angularjs-rails 1.4.7 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.4.7
2
+ * @license AngularJS v1.4.8
3
3
  * (c) 2010-2015 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.4.7
2
+ * @license AngularJS v1.4.8
3
3
  * (c) 2010-2015 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) {
57
57
  return match;
58
58
  });
59
59
 
60
- message += '\nhttp://errors.angularjs.org/1.4.7/' +
60
+ message += '\nhttp://errors.angularjs.org/1.4.8/' +
61
61
  (module ? module + '/' : '') + code;
62
62
 
63
63
  for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -267,20 +267,24 @@ msie = document.documentMode;
267
267
  * String ...)
268
268
  */
269
269
  function isArrayLike(obj) {
270
- if (obj == null || isWindow(obj)) {
271
- return false;
272
- }
270
+
271
+ // `null`, `undefined` and `window` are not array-like
272
+ if (obj == null || isWindow(obj)) return false;
273
+
274
+ // arrays, strings and jQuery/jqLite objects are array like
275
+ // * jqLite is either the jQuery or jqLite constructor function
276
+ // * we have to check the existance of jqLite first as this method is called
277
+ // via the forEach method when constructing the jqLite object in the first place
278
+ if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
273
279
 
274
280
  // Support: iOS 8.2 (not reproducible in simulator)
275
281
  // "length" in obj used to prevent JIT error (gh-11508)
276
282
  var length = "length" in Object(obj) && obj.length;
277
283
 
278
- if (obj.nodeType === NODE_TYPE_ELEMENT && length) {
279
- return true;
280
- }
281
-
282
- return isString(obj) || isArray(obj) || length === 0 ||
283
- typeof length === 'number' && length > 0 && (length - 1) in obj;
284
+ // NodeList objects (with `item` method) and
285
+ // other objects with suitable length characteristics are array-like
286
+ return isNumber(length) &&
287
+ (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
284
288
  }
285
289
 
286
290
  /**
@@ -425,6 +429,10 @@ function baseExtend(dst, objs, deep) {
425
429
  dst[key] = new Date(src.valueOf());
426
430
  } else if (isRegExp(src)) {
427
431
  dst[key] = new RegExp(src);
432
+ } else if (src.nodeName) {
433
+ dst[key] = src.cloneNode(true);
434
+ } else if (isElement(src)) {
435
+ dst[key] = src.clone();
428
436
  } else {
429
437
  if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
430
438
  baseExtend(dst[key], [src], true);
@@ -540,7 +548,7 @@ identity.$inject = [];
540
548
  function valueFn(value) {return function() {return value;};}
541
549
 
542
550
  function hasCustomToString(obj) {
543
- return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
551
+ return isFunction(obj.toString) && obj.toString !== toString;
544
552
  }
545
553
 
546
554
 
@@ -739,9 +747,9 @@ function isPromiseLike(obj) {
739
747
  }
740
748
 
741
749
 
742
- var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/;
750
+ var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
743
751
  function isTypedArray(value) {
744
- return TYPED_ARRAY_REGEXP.test(toString.call(value));
752
+ return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
745
753
  }
746
754
 
747
755
 
@@ -863,100 +871,111 @@ function arrayRemove(array, value) {
863
871
  </file>
864
872
  </example>
865
873
  */
866
- function copy(source, destination, stackSource, stackDest) {
867
- if (isWindow(source) || isScope(source)) {
868
- throw ngMinErr('cpws',
869
- "Can't copy! Making copies of Window or Scope instances is not supported.");
870
- }
871
- if (isTypedArray(destination)) {
872
- throw ngMinErr('cpta',
873
- "Can't copy! TypedArray destination cannot be mutated.");
874
- }
874
+ function copy(source, destination) {
875
+ var stackSource = [];
876
+ var stackDest = [];
875
877
 
876
- if (!destination) {
877
- destination = source;
878
- if (isObject(source)) {
879
- var index;
880
- if (stackSource && (index = stackSource.indexOf(source)) !== -1) {
881
- return stackDest[index];
882
- }
883
-
884
- // TypedArray, Date and RegExp have specific copy functionality and must be
885
- // pushed onto the stack before returning.
886
- // Array and other objects create the base object and recurse to copy child
887
- // objects. The array/object will be pushed onto the stack when recursed.
888
- if (isArray(source)) {
889
- return copy(source, [], stackSource, stackDest);
890
- } else if (isTypedArray(source)) {
891
- destination = new source.constructor(source);
892
- } else if (isDate(source)) {
893
- destination = new Date(source.getTime());
894
- } else if (isRegExp(source)) {
895
- destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
896
- destination.lastIndex = source.lastIndex;
897
- } else if (isFunction(source.cloneNode)) {
898
- destination = source.cloneNode(true);
899
- } else {
900
- var emptyObject = Object.create(getPrototypeOf(source));
901
- return copy(source, emptyObject, stackSource, stackDest);
902
- }
878
+ if (destination) {
879
+ if (isTypedArray(destination)) {
880
+ throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
881
+ }
882
+ if (source === destination) {
883
+ throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
884
+ }
903
885
 
904
- if (stackDest) {
905
- stackSource.push(source);
906
- stackDest.push(destination);
907
- }
886
+ // Empty the destination object
887
+ if (isArray(destination)) {
888
+ destination.length = 0;
889
+ } else {
890
+ forEach(destination, function(value, key) {
891
+ if (key !== '$$hashKey') {
892
+ delete destination[key];
893
+ }
894
+ });
908
895
  }
909
- } else {
910
- if (source === destination) throw ngMinErr('cpi',
911
- "Can't copy! Source and destination are identical.");
912
896
 
913
- stackSource = stackSource || [];
914
- stackDest = stackDest || [];
897
+ stackSource.push(source);
898
+ stackDest.push(destination);
899
+ return copyRecurse(source, destination);
900
+ }
915
901
 
916
- if (isObject(source)) {
917
- stackSource.push(source);
918
- stackDest.push(destination);
919
- }
902
+ return copyElement(source);
920
903
 
904
+ function copyRecurse(source, destination) {
905
+ var h = destination.$$hashKey;
921
906
  var result, key;
922
907
  if (isArray(source)) {
923
- destination.length = 0;
924
- for (var i = 0; i < source.length; i++) {
925
- destination.push(copy(source[i], null, stackSource, stackDest));
908
+ for (var i = 0, ii = source.length; i < ii; i++) {
909
+ destination.push(copyElement(source[i]));
926
910
  }
927
- } else {
928
- var h = destination.$$hashKey;
929
- if (isArray(destination)) {
930
- destination.length = 0;
931
- } else {
932
- forEach(destination, function(value, key) {
933
- delete destination[key];
934
- });
935
- }
936
- if (isBlankObject(source)) {
937
- // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
938
- for (key in source) {
939
- destination[key] = copy(source[key], null, stackSource, stackDest);
940
- }
941
- } else if (source && typeof source.hasOwnProperty === 'function') {
942
- // Slow path, which must rely on hasOwnProperty
943
- for (key in source) {
944
- if (source.hasOwnProperty(key)) {
945
- destination[key] = copy(source[key], null, stackSource, stackDest);
946
- }
911
+ } else if (isBlankObject(source)) {
912
+ // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
913
+ for (key in source) {
914
+ destination[key] = copyElement(source[key]);
915
+ }
916
+ } else if (source && typeof source.hasOwnProperty === 'function') {
917
+ // Slow path, which must rely on hasOwnProperty
918
+ for (key in source) {
919
+ if (source.hasOwnProperty(key)) {
920
+ destination[key] = copyElement(source[key]);
947
921
  }
948
- } else {
949
- // Slowest path --- hasOwnProperty can't be called as a method
950
- for (key in source) {
951
- if (hasOwnProperty.call(source, key)) {
952
- destination[key] = copy(source[key], null, stackSource, stackDest);
953
- }
922
+ }
923
+ } else {
924
+ // Slowest path --- hasOwnProperty can't be called as a method
925
+ for (key in source) {
926
+ if (hasOwnProperty.call(source, key)) {
927
+ destination[key] = copyElement(source[key]);
954
928
  }
955
929
  }
956
- setHashKey(destination,h);
957
930
  }
931
+ setHashKey(destination, h);
932
+ return destination;
933
+ }
934
+
935
+ function copyElement(source) {
936
+ // Simple values
937
+ if (!isObject(source)) {
938
+ return source;
939
+ }
940
+
941
+ // Already copied values
942
+ var index = stackSource.indexOf(source);
943
+ if (index !== -1) {
944
+ return stackDest[index];
945
+ }
946
+
947
+ if (isWindow(source) || isScope(source)) {
948
+ throw ngMinErr('cpws',
949
+ "Can't copy! Making copies of Window or Scope instances is not supported.");
950
+ }
951
+
952
+ var needsRecurse = false;
953
+ var destination;
954
+
955
+ if (isArray(source)) {
956
+ destination = [];
957
+ needsRecurse = true;
958
+ } else if (isTypedArray(source)) {
959
+ destination = new source.constructor(source);
960
+ } else if (isDate(source)) {
961
+ destination = new Date(source.getTime());
962
+ } else if (isRegExp(source)) {
963
+ destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
964
+ destination.lastIndex = source.lastIndex;
965
+ } else if (isFunction(source.cloneNode)) {
966
+ destination = source.cloneNode(true);
967
+ } else {
968
+ destination = Object.create(getPrototypeOf(source));
969
+ needsRecurse = true;
970
+ }
971
+
972
+ stackSource.push(source);
973
+ stackDest.push(destination);
974
+
975
+ return needsRecurse
976
+ ? copyRecurse(source, destination)
977
+ : destination;
958
978
  }
959
- return destination;
960
979
  }
961
980
 
962
981
  /**
@@ -2080,7 +2099,7 @@ function setupModuleLoader(window) {
2080
2099
  * @param {string} name constant name
2081
2100
  * @param {*} object Constant value.
2082
2101
  * @description
2083
- * Because the constant are fixed, they get applied before other provide methods.
2102
+ * Because the constants are fixed, they get applied before other provide methods.
2084
2103
  * See {@link auto.$provide#constant $provide.constant()}.
2085
2104
  */
2086
2105
  constant: invokeLater('$provide', 'constant', 'unshift'),
@@ -2379,11 +2398,11 @@ function toDebugString(obj) {
2379
2398
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2380
2399
  */
2381
2400
  var version = {
2382
- full: '1.4.7', // all of these placeholder strings will be replaced by grunt's
2401
+ full: '1.4.8', // all of these placeholder strings will be replaced by grunt's
2383
2402
  major: 1, // package task
2384
2403
  minor: 4,
2385
- dot: 7,
2386
- codeName: 'dark-luminescence'
2404
+ dot: 8,
2405
+ codeName: 'ice-manipulation'
2387
2406
  };
2388
2407
 
2389
2408
 
@@ -2765,6 +2784,14 @@ function jqLiteParseHTML(html, context) {
2765
2784
  return [];
2766
2785
  }
2767
2786
 
2787
+
2788
+ // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2789
+ var jqLiteContains = Node.prototype.contains || function(arg) {
2790
+ // jshint bitwise: false
2791
+ return !!(this.compareDocumentPosition(arg) & 16);
2792
+ // jshint bitwise: true
2793
+ };
2794
+
2768
2795
  /////////////////////////////////////////////
2769
2796
  function JQLite(element) {
2770
2797
  if (element instanceof JQLite) {
@@ -2823,17 +2850,23 @@ function jqLiteOff(element, type, fn, unsupported) {
2823
2850
  delete events[type];
2824
2851
  }
2825
2852
  } else {
2826
- forEach(type.split(' '), function(type) {
2853
+
2854
+ var removeHandler = function(type) {
2855
+ var listenerFns = events[type];
2827
2856
  if (isDefined(fn)) {
2828
- var listenerFns = events[type];
2829
2857
  arrayRemove(listenerFns || [], fn);
2830
- if (listenerFns && listenerFns.length > 0) {
2831
- return;
2832
- }
2833
2858
  }
2859
+ if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
2860
+ removeEventListenerFn(element, type, handle);
2861
+ delete events[type];
2862
+ }
2863
+ };
2834
2864
 
2835
- removeEventListenerFn(element, type, handle);
2836
- delete events[type];
2865
+ forEach(type.split(' '), function(type) {
2866
+ removeHandler(type);
2867
+ if (MOUSE_EVENT_MAP[type]) {
2868
+ removeHandler(MOUSE_EVENT_MAP[type]);
2869
+ }
2837
2870
  });
2838
2871
  }
2839
2872
  }
@@ -3288,6 +3321,9 @@ function createEventHandler(element, events) {
3288
3321
  return event.immediatePropagationStopped === true;
3289
3322
  };
3290
3323
 
3324
+ // Some events have special handlers that wrap the real handler
3325
+ var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3326
+
3291
3327
  // Copy event handlers in case event handlers array is modified during execution.
3292
3328
  if ((eventFnsLength > 1)) {
3293
3329
  eventFns = shallowCopy(eventFns);
@@ -3295,7 +3331,7 @@ function createEventHandler(element, events) {
3295
3331
 
3296
3332
  for (var i = 0; i < eventFnsLength; i++) {
3297
3333
  if (!event.isImmediatePropagationStopped()) {
3298
- eventFns[i].call(element, event);
3334
+ handlerWrapper(element, event, eventFns[i]);
3299
3335
  }
3300
3336
  }
3301
3337
  };
@@ -3306,6 +3342,22 @@ function createEventHandler(element, events) {
3306
3342
  return eventHandler;
3307
3343
  }
3308
3344
 
3345
+ function defaultHandlerWrapper(element, event, handler) {
3346
+ handler.call(element, event);
3347
+ }
3348
+
3349
+ function specialMouseHandlerWrapper(target, event, handler) {
3350
+ // Refer to jQuery's implementation of mouseenter & mouseleave
3351
+ // Read about mouseenter and mouseleave:
3352
+ // http://www.quirksmode.org/js/events_mouse.html#link8
3353
+ var related = event.relatedTarget;
3354
+ // For mousenter/leave call the handler if related is outside the target.
3355
+ // NB: No relatedTarget if the mouse left/entered the browser window
3356
+ if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3357
+ handler.call(target, event);
3358
+ }
3359
+ }
3360
+
3309
3361
  //////////////////////////////////////////
3310
3362
  // Functions iterating traversal.
3311
3363
  // These functions chain results into a single
@@ -3334,35 +3386,28 @@ forEach({
3334
3386
  var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3335
3387
  var i = types.length;
3336
3388
 
3337
- while (i--) {
3338
- type = types[i];
3389
+ var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3339
3390
  var eventFns = events[type];
3340
3391
 
3341
3392
  if (!eventFns) {
3342
- events[type] = [];
3343
-
3344
- if (type === 'mouseenter' || type === 'mouseleave') {
3345
- // Refer to jQuery's implementation of mouseenter & mouseleave
3346
- // Read about mouseenter and mouseleave:
3347
- // http://www.quirksmode.org/js/events_mouse.html#link8
3348
-
3349
- jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) {
3350
- var target = this, related = event.relatedTarget;
3351
- // For mousenter/leave call the handler if related is outside the target.
3352
- // NB: No relatedTarget if the mouse left/entered the browser window
3353
- if (!related || (related !== target && !target.contains(related))) {
3354
- handle(event, type);
3355
- }
3356
- });
3357
-
3358
- } else {
3359
- if (type !== '$destroy') {
3360
- addEventListenerFn(element, type, handle);
3361
- }
3393
+ eventFns = events[type] = [];
3394
+ eventFns.specialHandlerWrapper = specialHandlerWrapper;
3395
+ if (type !== '$destroy' && !noEventListener) {
3396
+ addEventListenerFn(element, type, handle);
3362
3397
  }
3363
- eventFns = events[type];
3364
3398
  }
3399
+
3365
3400
  eventFns.push(fn);
3401
+ };
3402
+
3403
+ while (i--) {
3404
+ type = types[i];
3405
+ if (MOUSE_EVENT_MAP[type]) {
3406
+ addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3407
+ addHandler(type, undefined, true);
3408
+ } else {
3409
+ addHandler(type);
3410
+ }
3366
3411
  }
3367
3412
  },
3368
3413
 
@@ -4543,7 +4588,7 @@ function $AnchorScrollProvider() {
4543
4588
  * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4544
4589
  * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4545
4590
  * in the
4546
- * [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document).
4591
+ * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
4547
4592
  *
4548
4593
  * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4549
4594
  * match any anchor whenever it changes. This can be disabled by calling
@@ -5058,7 +5103,7 @@ var $AnimateProvider = ['$provide', function($provide) {
5058
5103
  * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
5059
5104
  * to ensure that animation runs with the triggered DOM operation.
5060
5105
  *
5061
- * By default $animate doesn't trigger an animations. This is because the `ngAnimate` module isn't
5106
+ * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
5062
5107
  * included and only when it is active then the animation hooks that `$animate` triggers will be
5063
5108
  * functional. Once active then all structural `ng-` directives will trigger animations as they perform
5064
5109
  * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
@@ -5910,9 +5955,9 @@ function $CacheFactoryProvider() {
5910
5955
 
5911
5956
  var size = 0,
5912
5957
  stats = extend({}, options, {id: cacheId}),
5913
- data = {},
5958
+ data = createMap(),
5914
5959
  capacity = (options && options.capacity) || Number.MAX_VALUE,
5915
- lruHash = {},
5960
+ lruHash = createMap(),
5916
5961
  freshEnd = null,
5917
5962
  staleEnd = null;
5918
5963
 
@@ -6040,6 +6085,8 @@ function $CacheFactoryProvider() {
6040
6085
  delete lruHash[key];
6041
6086
  }
6042
6087
 
6088
+ if (!(key in data)) return;
6089
+
6043
6090
  delete data[key];
6044
6091
  size--;
6045
6092
  },
@@ -6054,9 +6101,9 @@ function $CacheFactoryProvider() {
6054
6101
  * Clears the cache object of any entries.
6055
6102
  */
6056
6103
  removeAll: function() {
6057
- data = {};
6104
+ data = createMap();
6058
6105
  size = 0;
6059
- lruHash = {};
6106
+ lruHash = createMap();
6060
6107
  freshEnd = staleEnd = null;
6061
6108
  },
6062
6109
 
@@ -7457,6 +7504,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7457
7504
  return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
7458
7505
  },
7459
7506
  NG_ATTR_BINDING = /^ngAttr[A-Z]/;
7507
+ var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
7460
7508
 
7461
7509
  compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
7462
7510
  var bindings = $element.data('$binding') || [];
@@ -7509,6 +7557,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7509
7557
  return function publicLinkFn(scope, cloneConnectFn, options) {
7510
7558
  assertArg(scope, 'scope');
7511
7559
 
7560
+ if (previousCompileContext && previousCompileContext.needsNewScope) {
7561
+ // A parent directive did a replace and a directive on this element asked
7562
+ // for transclusion, which caused us to lose a layer of element on which
7563
+ // we could hold the new transclusion scope, so we will create it manually
7564
+ // here.
7565
+ scope = scope.$parent.$new();
7566
+ }
7567
+
7512
7568
  options = options || {};
7513
7569
  var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
7514
7570
  transcludeControllers = options.transcludeControllers,
@@ -7654,11 +7710,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7654
7710
  if (nodeLinkFn.scope) {
7655
7711
  childScope = scope.$new();
7656
7712
  compile.$$addScopeInfo(jqLite(node), childScope);
7657
- var destroyBindings = nodeLinkFn.$$destroyBindings;
7658
- if (destroyBindings) {
7659
- nodeLinkFn.$$destroyBindings = null;
7660
- childScope.$on('$destroyed', destroyBindings);
7661
- }
7662
7713
  } else {
7663
7714
  childScope = scope;
7664
7715
  }
@@ -7677,8 +7728,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7677
7728
  childBoundTranscludeFn = null;
7678
7729
  }
7679
7730
 
7680
- nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn,
7681
- nodeLinkFn);
7731
+ nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
7682
7732
 
7683
7733
  } else if (childLinkFn) {
7684
7734
  childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
@@ -7747,13 +7797,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7747
7797
  });
7748
7798
  }
7749
7799
 
7750
- var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
7751
- if (directiveIsMultiElement(directiveNName)) {
7752
- if (ngAttrName === directiveNName + 'Start') {
7753
- attrStartName = name;
7754
- attrEndName = name.substr(0, name.length - 5) + 'end';
7755
- name = name.substr(0, name.length - 6);
7756
- }
7800
+ var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
7801
+ if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
7802
+ attrStartName = name;
7803
+ attrEndName = name.substr(0, name.length - 5) + 'end';
7804
+ name = name.substr(0, name.length - 6);
7757
7805
  }
7758
7806
 
7759
7807
  nName = directiveNormalize(name.toLowerCase());
@@ -7992,7 +8040,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
7992
8040
  } else {
7993
8041
  $template = jqLite(jqLiteClone(compileNode)).contents();
7994
8042
  $compileNode.empty(); // clear contents
7995
- childTranscludeFn = compile($template, transcludeFn);
8043
+ childTranscludeFn = compile($template, transcludeFn, undefined,
8044
+ undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
7996
8045
  }
7997
8046
  }
7998
8047
 
@@ -8034,8 +8083,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8034
8083
  var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
8035
8084
  var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
8036
8085
 
8037
- if (newIsolateScopeDirective) {
8038
- markDirectivesAsIsolate(templateDirectives);
8086
+ if (newIsolateScopeDirective || newScopeDirective) {
8087
+ // The original directive caused the current element to be replaced but this element
8088
+ // also needs to have a new scope, so we need to tell the template directives
8089
+ // that they would need to get their scope from further up, if they require transclusion
8090
+ markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
8039
8091
  }
8040
8092
  directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
8041
8093
  mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
@@ -8188,10 +8240,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8188
8240
  return elementControllers;
8189
8241
  }
8190
8242
 
8191
- function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn,
8192
- thisLinkFn) {
8193
- var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element,
8194
- attrs;
8243
+ function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
8244
+ var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
8245
+ attrs, removeScopeBindingWatches, removeControllerBindingWatches;
8195
8246
 
8196
8247
  if (compileNode === linkNode) {
8197
8248
  attrs = templateAttrs;
@@ -8201,8 +8252,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8201
8252
  attrs = new Attributes($element, templateAttrs);
8202
8253
  }
8203
8254
 
8255
+ controllerScope = scope;
8204
8256
  if (newIsolateScopeDirective) {
8205
8257
  isolateScope = scope.$new(true);
8258
+ } else if (newScopeDirective) {
8259
+ controllerScope = scope.$parent;
8206
8260
  }
8207
8261
 
8208
8262
  if (boundTranscludeFn) {
@@ -8223,42 +8277,34 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8223
8277
  compile.$$addScopeClass($element, true);
8224
8278
  isolateScope.$$isolateBindings =
8225
8279
  newIsolateScopeDirective.$$isolateBindings;
8226
- initializeDirectiveBindings(scope, attrs, isolateScope,
8227
- isolateScope.$$isolateBindings,
8228
- newIsolateScopeDirective, isolateScope);
8280
+ removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
8281
+ isolateScope.$$isolateBindings,
8282
+ newIsolateScopeDirective);
8283
+ if (removeScopeBindingWatches) {
8284
+ isolateScope.$on('$destroy', removeScopeBindingWatches);
8285
+ }
8229
8286
  }
8230
- if (elementControllers) {
8231
- // Initialize bindToController bindings for new/isolate scopes
8232
- var scopeDirective = newIsolateScopeDirective || newScopeDirective;
8233
- var bindings;
8234
- var controllerForBindings;
8235
- if (scopeDirective && elementControllers[scopeDirective.name]) {
8236
- bindings = scopeDirective.$$bindings.bindToController;
8237
- controller = elementControllers[scopeDirective.name];
8238
-
8239
- if (controller && controller.identifier && bindings) {
8240
- controllerForBindings = controller;
8241
- thisLinkFn.$$destroyBindings =
8242
- initializeDirectiveBindings(scope, attrs, controller.instance,
8243
- bindings, scopeDirective);
8244
- }
8287
+
8288
+ // Initialize bindToController bindings
8289
+ for (var name in elementControllers) {
8290
+ var controllerDirective = controllerDirectives[name];
8291
+ var controller = elementControllers[name];
8292
+ var bindings = controllerDirective.$$bindings.bindToController;
8293
+
8294
+ if (controller.identifier && bindings) {
8295
+ removeControllerBindingWatches =
8296
+ initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8245
8297
  }
8246
- for (i in elementControllers) {
8247
- controller = elementControllers[i];
8248
- var controllerResult = controller();
8249
-
8250
- if (controllerResult !== controller.instance) {
8251
- // If the controller constructor has a return value, overwrite the instance
8252
- // from setupControllers and update the element data
8253
- controller.instance = controllerResult;
8254
- $element.data('$' + i + 'Controller', controllerResult);
8255
- if (controller === controllerForBindings) {
8256
- // Remove and re-install bindToController bindings
8257
- thisLinkFn.$$destroyBindings();
8258
- thisLinkFn.$$destroyBindings =
8259
- initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective);
8260
- }
8261
- }
8298
+
8299
+ var controllerResult = controller();
8300
+ if (controllerResult !== controller.instance) {
8301
+ // If the controller constructor has a return value, overwrite the instance
8302
+ // from setupControllers
8303
+ controller.instance = controllerResult;
8304
+ $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
8305
+ removeControllerBindingWatches && removeControllerBindingWatches();
8306
+ removeControllerBindingWatches =
8307
+ initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
8262
8308
  }
8263
8309
  }
8264
8310
 
@@ -8318,10 +8364,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8318
8364
  }
8319
8365
  }
8320
8366
 
8321
- function markDirectivesAsIsolate(directives) {
8322
- // mark all directives as needing isolate scope.
8367
+ // Depending upon the context in which a directive finds itself it might need to have a new isolated
8368
+ // or child scope created. For instance:
8369
+ // * if the directive has been pulled into a template because another directive with a higher priority
8370
+ // asked for element transclusion
8371
+ // * if the directive itself asks for transclusion but it is at the root of a template and the original
8372
+ // element was replaced. See https://github.com/angular/angular.js/issues/12936
8373
+ function markDirectiveScope(directives, isolateScope, newScope) {
8323
8374
  for (var j = 0, jj = directives.length; j < jj; j++) {
8324
- directives[j] = inherit(directives[j], {$$isolateScope: true});
8375
+ directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
8325
8376
  }
8326
8377
  }
8327
8378
 
@@ -8468,7 +8519,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8468
8519
  var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
8469
8520
 
8470
8521
  if (isObject(origAsyncDirective.scope)) {
8471
- markDirectivesAsIsolate(templateDirectives);
8522
+ // the original directive that caused the template to be loaded async required
8523
+ // an isolate scope
8524
+ markDirectiveScope(templateDirectives, true);
8472
8525
  }
8473
8526
  directives = templateDirectives.concat(directives);
8474
8527
  mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
@@ -8517,7 +8570,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8517
8570
  childBoundTranscludeFn = boundTranscludeFn;
8518
8571
  }
8519
8572
  afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
8520
- childBoundTranscludeFn, afterTemplateNodeLinkFn);
8573
+ childBoundTranscludeFn);
8521
8574
  }
8522
8575
  linkQueue = null;
8523
8576
  });
@@ -8534,8 +8587,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8534
8587
  if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
8535
8588
  childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
8536
8589
  }
8537
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn,
8538
- afterTemplateNodeLinkFn);
8590
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
8539
8591
  }
8540
8592
  };
8541
8593
  }
@@ -8747,7 +8799,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8747
8799
  // Copy over user data (that includes Angular's $scope etc.). Don't copy private
8748
8800
  // data here because there's no public interface in jQuery to do that and copying over
8749
8801
  // event listeners (which is the main use of private data) wouldn't work anyway.
8750
- jqLite(newNode).data(jqLite(firstElementToRemove).data());
8802
+ jqLite.data(newNode, jqLite.data(firstElementToRemove));
8751
8803
 
8752
8804
  // Remove data of the replaced element. We cannot just call .remove()
8753
8805
  // on the element it since that would deallocate scope that is needed
@@ -8795,9 +8847,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8795
8847
 
8796
8848
  // Set up $watches for isolate scope and controller bindings. This process
8797
8849
  // only occurs for isolate scopes and new scopes with controllerAs.
8798
- function initializeDirectiveBindings(scope, attrs, destination, bindings,
8799
- directive, newScope) {
8800
- var onNewScopeDestroyed;
8850
+ function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
8851
+ var removeWatchCollection = [];
8801
8852
  forEach(bindings, function(definition, scopeName) {
8802
8853
  var attrName = definition.attrName,
8803
8854
  optional = definition.optional,
@@ -8859,14 +8910,13 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8859
8910
  return lastValue = parentValue;
8860
8911
  };
8861
8912
  parentValueWatch.$stateful = true;
8862
- var unwatch;
8913
+ var removeWatch;
8863
8914
  if (definition.collection) {
8864
- unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8915
+ removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
8865
8916
  } else {
8866
- unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8917
+ removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
8867
8918
  }
8868
- onNewScopeDestroyed = (onNewScopeDestroyed || []);
8869
- onNewScopeDestroyed.push(unwatch);
8919
+ removeWatchCollection.push(removeWatch);
8870
8920
  break;
8871
8921
 
8872
8922
  case '&':
@@ -8882,16 +8932,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
8882
8932
  break;
8883
8933
  }
8884
8934
  });
8885
- var destroyBindings = onNewScopeDestroyed ? function destroyBindings() {
8886
- for (var i = 0, ii = onNewScopeDestroyed.length; i < ii; ++i) {
8887
- onNewScopeDestroyed[i]();
8935
+
8936
+ return removeWatchCollection.length && function removeWatches() {
8937
+ for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
8938
+ removeWatchCollection[i]();
8888
8939
  }
8889
- } : noop;
8890
- if (newScope && destroyBindings !== noop) {
8891
- newScope.$on('$destroy', destroyBindings);
8892
- return noop;
8893
- }
8894
- return destroyBindings;
8940
+ };
8895
8941
  }
8896
8942
  }];
8897
8943
  }
@@ -9616,9 +9662,9 @@ function $HttpProvider() {
9616
9662
  * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
9617
9663
  * This should be used to make sure that applications work without these methods.
9618
9664
  *
9619
- * Defaults to false. If no value is specified, returns the current configured value.
9665
+ * Defaults to true. If no value is specified, returns the current configured value.
9620
9666
  *
9621
- * @param {boolean=} value If true, `$http` will return a normal promise without the `success` and `error` methods.
9667
+ * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
9622
9668
  *
9623
9669
  * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
9624
9670
  * otherwise, returns the current configured value.
@@ -10270,11 +10316,8 @@ function $HttpProvider() {
10270
10316
  function transformResponse(response) {
10271
10317
  // make a copy since the response must be cacheable
10272
10318
  var resp = extend({}, response);
10273
- if (!response.data) {
10274
- resp.data = response.data;
10275
- } else {
10276
- resp.data = transformData(response.data, response.headers, response.status, config.transformResponse);
10277
- }
10319
+ resp.data = transformData(response.data, response.headers, response.status,
10320
+ config.transformResponse);
10278
10321
  return (isSuccess(response.status))
10279
10322
  ? resp
10280
10323
  : $q.reject(resp);
@@ -11908,9 +11951,9 @@ var locationPrototype = {
11908
11951
  * @description
11909
11952
  * This method is getter / setter.
11910
11953
  *
11911
- * Return hash fragment when called without any parameter.
11954
+ * Returns the hash fragment when called without any parameters.
11912
11955
  *
11913
- * Change hash fragment when called with parameter and return `$location`.
11956
+ * Changes the hash fragment when called with a parameter and returns `$location`.
11914
11957
  *
11915
11958
  *
11916
11959
  * ```js
@@ -11931,8 +11974,8 @@ var locationPrototype = {
11931
11974
  * @name $location#replace
11932
11975
  *
11933
11976
  * @description
11934
- * If called, all changes to $location during current `$digest` will be replacing current history
11935
- * record, instead of adding new one.
11977
+ * If called, all changes to $location during the current `$digest` will replace the current history
11978
+ * record, instead of adding a new one.
11936
11979
  */
11937
11980
  replace: function() {
11938
11981
  this.$$replace = true;
@@ -12252,7 +12295,7 @@ function $LocationProvider() {
12252
12295
  var oldUrl = $location.absUrl();
12253
12296
  var oldState = $location.$$state;
12254
12297
  var defaultPrevented;
12255
-
12298
+ newUrl = trimEmptyHash(newUrl);
12256
12299
  $location.$$parse(newUrl);
12257
12300
  $location.$$state = newState;
12258
12301
 
@@ -14393,13 +14436,14 @@ function $ParseProvider() {
14393
14436
  function addInterceptor(parsedExpression, interceptorFn) {
14394
14437
  if (!interceptorFn) return parsedExpression;
14395
14438
  var watchDelegate = parsedExpression.$$watchDelegate;
14439
+ var useInputs = false;
14396
14440
 
14397
14441
  var regularWatch =
14398
14442
  watchDelegate !== oneTimeLiteralWatchDelegate &&
14399
14443
  watchDelegate !== oneTimeWatchDelegate;
14400
14444
 
14401
14445
  var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
14402
- var value = parsedExpression(scope, locals, assign, inputs);
14446
+ var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
14403
14447
  return interceptorFn(value, scope, locals);
14404
14448
  } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
14405
14449
  var value = parsedExpression(scope, locals, assign, inputs);
@@ -14417,6 +14461,7 @@ function $ParseProvider() {
14417
14461
  // If there is an interceptor, but no watchDelegate then treat the interceptor like
14418
14462
  // we treat filters - it is assumed to be a pure function unless flagged with $stateful
14419
14463
  fn.$$watchDelegate = inputsWatchDelegate;
14464
+ useInputs = !parsedExpression.inputs;
14420
14465
  fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
14421
14466
  }
14422
14467
 
@@ -14478,6 +14523,8 @@ function $ParseProvider() {
14478
14523
  *
14479
14524
  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
14480
14525
  *
14526
+ * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
14527
+ *
14481
14528
  * However, the more traditional CommonJS-style usage is still available, and documented below.
14482
14529
  *
14483
14530
  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
@@ -15062,15 +15109,15 @@ function $$RAFProvider() { //rAF
15062
15109
  * exposed as $$____ properties
15063
15110
  *
15064
15111
  * Loop operations are optimized by using while(count--) { ... }
15065
- * - this means that in order to keep the same order of execution as addition we have to add
15112
+ * - This means that in order to keep the same order of execution as addition we have to add
15066
15113
  * items to the array at the beginning (unshift) instead of at the end (push)
15067
15114
  *
15068
15115
  * Child scopes are created and removed often
15069
- * - Using an array would be slow since inserts in middle are expensive so we use linked list
15116
+ * - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
15070
15117
  *
15071
- * There are few watches then a lot of observers. This is why you don't want the observer to be
15072
- * implemented in the same way as watch. Watch requires return of initialization function which
15073
- * are expensive to construct.
15118
+ * There are fewer watches than observers. This is why you don't want the observer to be implemented
15119
+ * in the same way as watch. Watch requires return of the initialization function which is expensive
15120
+ * to construct.
15074
15121
  */
15075
15122
 
15076
15123
 
@@ -15112,7 +15159,7 @@ function $$RAFProvider() { //rAF
15112
15159
  * Every application has a single root {@link ng.$rootScope.Scope scope}.
15113
15160
  * All other scopes are descendant scopes of the root scope. Scopes provide separation
15114
15161
  * between the model and the view, via a mechanism for watching the model for changes.
15115
- * They also provide an event emission/broadcast and subscription facility. See the
15162
+ * They also provide event emission/broadcast and subscription facility. See the
15116
15163
  * {@link guide/scope developer guide on scopes}.
15117
15164
  */
15118
15165
  function $RootScopeProvider() {
@@ -15149,6 +15196,29 @@ function $RootScopeProvider() {
15149
15196
  $event.currentScope.$$destroyed = true;
15150
15197
  }
15151
15198
 
15199
+ function cleanUpScope($scope) {
15200
+
15201
+ if (msie === 9) {
15202
+ // There is a memory leak in IE9 if all child scopes are not disconnected
15203
+ // completely when a scope is destroyed. So this code will recurse up through
15204
+ // all this scopes children
15205
+ //
15206
+ // See issue https://github.com/angular/angular.js/issues/10706
15207
+ $scope.$$childHead && cleanUpScope($scope.$$childHead);
15208
+ $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
15209
+ }
15210
+
15211
+ // The code below works around IE9 and V8's memory leaks
15212
+ //
15213
+ // See:
15214
+ // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15215
+ // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15216
+ // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15217
+
15218
+ $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
15219
+ $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
15220
+ }
15221
+
15152
15222
  /**
15153
15223
  * @ngdoc type
15154
15224
  * @name $rootScope.Scope
@@ -15945,16 +16015,9 @@ function $RootScopeProvider() {
15945
16015
  this.$on = this.$watch = this.$watchGroup = function() { return noop; };
15946
16016
  this.$$listeners = {};
15947
16017
 
15948
- // All of the code below is bogus code that works around V8's memory leak via optimized code
15949
- // and inline caches.
15950
- //
15951
- // see:
15952
- // - https://code.google.com/p/v8/issues/detail?id=2073#c26
15953
- // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
15954
- // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
15955
-
15956
- this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
15957
- this.$$childTail = this.$root = this.$$watchers = null;
16018
+ // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
16019
+ this.$$nextSibling = null;
16020
+ cleanUpScope(this);
15958
16021
  },
15959
16022
 
15960
16023
  /**
@@ -16950,7 +17013,7 @@ function $SceDelegateProvider() {
16950
17013
  * By default, Angular only loads templates from the same domain and protocol as the application
16951
17014
  * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
16952
17015
  * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
16953
- * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
17016
+ * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
16954
17017
  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
16955
17018
  *
16956
17019
  * *Please note*:
@@ -19201,7 +19264,7 @@ function limitToFilter() {
19201
19264
  if (!isArray(input) && !isString(input)) return input;
19202
19265
 
19203
19266
  begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
19204
- begin = (begin < 0 && begin >= -input.length) ? input.length + begin : begin;
19267
+ begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
19205
19268
 
19206
19269
  if (limit >= 0) {
19207
19270
  return input.slice(begin, begin + limit);
@@ -20561,7 +20624,8 @@ var ngFormDirective = formDirectiveFactory(true);
20561
20624
 
20562
20625
  // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
20563
20626
  var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
20564
- var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
20627
+ // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
20628
+ var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
20565
20629
  var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
20566
20630
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
20567
20631
  var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
@@ -24127,7 +24191,13 @@ var ngIfDirective = ['$animate', function($animate) {
24127
24191
  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
24128
24192
  * make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
24129
24193
  * @param {string=} onload Expression to evaluate when a new partial is loaded.
24130
- *
24194
+ * <div class="alert alert-warning">
24195
+ * **Note:** When using onload on SVG elements in IE11, the browser will try to call
24196
+ * a function with the name on the window element, which will usually throw a
24197
+ * "function is undefined" error. To fix this, you can instead use `data-onload` or a
24198
+ * different form that {@link guide/directive#normalization matches} `onload`.
24199
+ * </div>
24200
+ *
24131
24201
  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
24132
24202
  * $anchorScroll} to scroll the viewport after the content is loaded.
24133
24203
  *
@@ -25720,12 +25790,13 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25720
25790
  </label><br />
25721
25791
  </form>
25722
25792
  <pre>user.name = <span ng-bind="user.name"></span></pre>
25793
+ <pre>user.data = <span ng-bind="user.data"></span></pre>
25723
25794
  </div>
25724
25795
  </file>
25725
25796
  <file name="app.js">
25726
25797
  angular.module('optionsExample', [])
25727
25798
  .controller('ExampleController', ['$scope', function($scope) {
25728
- $scope.user = { name: 'say', data: '' };
25799
+ $scope.user = { name: 'John', data: '' };
25729
25800
 
25730
25801
  $scope.cancel = function(e) {
25731
25802
  if (e.keyCode == 27) {
@@ -25740,20 +25811,20 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25740
25811
  var other = element(by.model('user.data'));
25741
25812
 
25742
25813
  it('should allow custom events', function() {
25743
- input.sendKeys(' hello');
25814
+ input.sendKeys(' Doe');
25744
25815
  input.click();
25745
- expect(model.getText()).toEqual('say');
25816
+ expect(model.getText()).toEqual('John');
25746
25817
  other.click();
25747
- expect(model.getText()).toEqual('say hello');
25818
+ expect(model.getText()).toEqual('John Doe');
25748
25819
  });
25749
25820
 
25750
25821
  it('should $rollbackViewValue when model changes', function() {
25751
- input.sendKeys(' hello');
25752
- expect(input.getAttribute('value')).toEqual('say hello');
25822
+ input.sendKeys(' Doe');
25823
+ expect(input.getAttribute('value')).toEqual('John Doe');
25753
25824
  input.sendKeys(protractor.Key.ESCAPE);
25754
- expect(input.getAttribute('value')).toEqual('say');
25825
+ expect(input.getAttribute('value')).toEqual('John');
25755
25826
  other.click();
25756
- expect(model.getText()).toEqual('say');
25827
+ expect(model.getText()).toEqual('John');
25757
25828
  });
25758
25829
  </file>
25759
25830
  </example>
@@ -25779,7 +25850,7 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
25779
25850
  <file name="app.js">
25780
25851
  angular.module('optionsExample', [])
25781
25852
  .controller('ExampleController', ['$scope', function($scope) {
25782
- $scope.user = { name: 'say' };
25853
+ $scope.user = { name: 'Igor' };
25783
25854
  }]);
25784
25855
  </file>
25785
25856
  </example>
@@ -26012,19 +26083,27 @@ var ngOptionsMinErr = minErr('ngOptions');
26012
26083
  *
26013
26084
  * ## Complex Models (objects or collections)
26014
26085
  *
26015
- * **Note:** By default, `ngModel` watches the model by reference, not value. This is important when
26016
- * binding any input directive to a model that is an object or a collection.
26086
+ * By default, `ngModel` watches the model by reference, not value. This is important to know when
26087
+ * binding the select to a model that is an object or a collection.
26017
26088
  *
26018
- * Since this is a common situation for `ngOptions` the directive additionally watches the model using
26019
- * `$watchCollection` when the select has the `multiple` attribute or when there is a `track by` clause in
26020
- * the options expression. This allows ngOptions to trigger a re-rendering of the options even if the actual
26021
- * object/collection has not changed identity but only a property on the object or an item in the collection
26022
- * changes.
26089
+ * One issue occurs if you want to preselect an option. For example, if you set
26090
+ * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
26091
+ * because the objects are not identical. So by default, you should always reference the item in your collection
26092
+ * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
26023
26093
  *
26024
- * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26025
- * if the model is an array). This means that changing a property deeper inside the object/collection that the
26026
- * first level will not trigger a re-rendering.
26094
+ * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
26095
+ * of the item not by reference, but by the result of the `track by` expression. For example, if your
26096
+ * collection items have an id property, you would `track by item.id`.
26097
+ *
26098
+ * A different issue with objects or collections is that ngModel won't detect if an object property or
26099
+ * a collection item changes. For that reason, `ngOptions` additionally watches the model using
26100
+ * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
26101
+ * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
26102
+ * has not changed identity, but only a property on the object or an item in the collection changes.
26027
26103
  *
26104
+ * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
26105
+ * if the model is an array). This means that changing a property deeper than the first level inside the
26106
+ * object/collection will not trigger a re-rendering.
26028
26107
  *
26029
26108
  * ## `select` **`as`**
26030
26109
  *
@@ -26037,17 +26116,13 @@ var ngOptionsMinErr = minErr('ngOptions');
26037
26116
  * ### `select` **`as`** and **`track by`**
26038
26117
  *
26039
26118
  * <div class="alert alert-warning">
26040
- * Do not use `select` **`as`** and **`track by`** in the same expression. They are not designed to work together.
26119
+ * Be careful when using `select` **`as`** and **`track by`** in the same expression.
26041
26120
  * </div>
26042
26121
  *
26043
- * Consider the following example:
26044
- *
26045
- * ```html
26046
- * <select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"></select>
26047
- * ```
26122
+ * Given this array of items on the $scope:
26048
26123
  *
26049
26124
  * ```js
26050
- * $scope.values = [{
26125
+ * $scope.items = [{
26051
26126
  * id: 1,
26052
26127
  * label: 'aLabel',
26053
26128
  * subItem: { name: 'aSubItem' }
@@ -26056,20 +26131,33 @@ var ngOptionsMinErr = minErr('ngOptions');
26056
26131
  * label: 'bLabel',
26057
26132
  * subItem: { name: 'bSubItem' }
26058
26133
  * }];
26134
+ * ```
26135
+ *
26136
+ * This will work:
26059
26137
  *
26060
- * $scope.selected = { name: 'aSubItem' };
26138
+ * ```html
26139
+ * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
26140
+ * ```
26141
+ * ```js
26142
+ * $scope.selected = $scope.items[0];
26061
26143
  * ```
26062
26144
  *
26063
- * With the purpose of preserving the selection, the **`track by`** expression is always applied to the element
26064
- * of the data source (to `item` in this example). To calculate whether an element is selected, we do the
26065
- * following:
26145
+ * but this will not work:
26066
26146
  *
26067
- * 1. Apply **`track by`** to the elements in the array. In the example: `[1, 2]`
26068
- * 2. Apply **`track by`** to the already selected value in `ngModel`.
26069
- * In the example: this is not possible as **`track by`** refers to `item.id`, but the selected
26070
- * value from `ngModel` is `{name: 'aSubItem'}`, so the **`track by`** expression is applied to
26071
- * a wrong object, the selected element can't be found, `<select>` is always reset to the "not
26072
- * selected" option.
26147
+ * ```html
26148
+ * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
26149
+ * ```
26150
+ * ```js
26151
+ * $scope.selected = $scope.items[0].subItem;
26152
+ * ```
26153
+ *
26154
+ * In both examples, the **`track by`** expression is applied successfully to each `item` in the
26155
+ * `items` array. Because the selected option has been set programmatically in the controller, the
26156
+ * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
26157
+ * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
26158
+ * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
26159
+ * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
26160
+ * is not matched against any `<option>` and the `<select>` appears as having no selected value.
26073
26161
  *
26074
26162
  *
26075
26163
  * @param {string} ngModel Assignable angular expression to data-bind to.
@@ -26371,11 +26459,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26371
26459
  var optionTemplate = document.createElement('option'),
26372
26460
  optGroupTemplate = document.createElement('optgroup');
26373
26461
 
26374
- return {
26375
- restrict: 'A',
26376
- terminal: true,
26377
- require: ['select', '?ngModel'],
26378
- link: function(scope, selectElement, attr, ctrls) {
26462
+
26463
+ function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
26379
26464
 
26380
26465
  // if ngModel is not defined, we don't need to do anything
26381
26466
  var ngModelCtrl = ctrls[1];
@@ -26430,7 +26515,6 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26430
26515
  unknownOption.remove();
26431
26516
  };
26432
26517
 
26433
-
26434
26518
  // Update the controller methods for multiple selectable options
26435
26519
  if (!multiple) {
26436
26520
 
@@ -26605,13 +26689,15 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26605
26689
  var emptyOption_ = emptyOption && emptyOption[0];
26606
26690
  var unknownOption_ = unknownOption && unknownOption[0];
26607
26691
 
26692
+ // We cannot rely on the extracted empty option being the same as the compiled empty option,
26693
+ // because the compiled empty option might have been replaced by a comment because
26694
+ // it had an "element" transclusion directive on it (such as ngIf)
26608
26695
  if (emptyOption_ || unknownOption_) {
26609
26696
  while (current &&
26610
26697
  (current === emptyOption_ ||
26611
26698
  current === unknownOption_ ||
26612
- emptyOption_ && emptyOption_.nodeType === NODE_TYPE_COMMENT)) {
26613
- // Empty options might have directives that transclude
26614
- // and insert comments (e.g. ngIf)
26699
+ current.nodeType === NODE_TYPE_COMMENT ||
26700
+ current.value === '')) {
26615
26701
  current = current.nextSibling;
26616
26702
  }
26617
26703
  }
@@ -26708,7 +26794,20 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
26708
26794
  }
26709
26795
 
26710
26796
  }
26797
+ }
26711
26798
 
26799
+ return {
26800
+ restrict: 'A',
26801
+ terminal: true,
26802
+ require: ['select', '?ngModel'],
26803
+ link: {
26804
+ pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
26805
+ // Deactivate the SelectController.register method to prevent
26806
+ // option directives from accidentally registering themselves
26807
+ // (and unwanted $destroy handlers etc.)
26808
+ ctrls[0].registerOption = noop;
26809
+ },
26810
+ post: ngOptionsPostLink
26712
26811
  }
26713
26812
  };
26714
26813
  }];
@@ -26995,7 +27094,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
26995
27094
  * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
26996
27095
  * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
26997
27096
  * keys in the order in which they were defined, although there are exceptions when keys are deleted
26998
- * and reinstated. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_issues
27097
+ * and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
26999
27098
  *
27000
27099
  * If this is not desired, the recommended workaround is to convert your object into an array
27001
27100
  * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
@@ -27005,15 +27104,21 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27005
27104
  *
27006
27105
  * # Tracking and Duplicates
27007
27106
  *
27008
- * When the contents of the collection change, `ngRepeat` makes the corresponding changes to the DOM:
27107
+ * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
27108
+ * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
27009
27109
  *
27010
27110
  * * When an item is added, a new instance of the template is added to the DOM.
27011
27111
  * * When an item is removed, its template instance is removed from the DOM.
27012
27112
  * * When items are reordered, their respective templates are reordered in the DOM.
27013
27113
  *
27014
- * By default, `ngRepeat` does not allow duplicate items in arrays. This is because when
27015
- * there are duplicates, it is not possible to maintain a one-to-one mapping between collection
27016
- * items and DOM elements.
27114
+ * To minimize creation of DOM elements, `ngRepeat` uses a function
27115
+ * to "keep track" of all items in the collection and their corresponding DOM elements.
27116
+ * For example, if an item is added to the collection, ngRepeat will know that all other items
27117
+ * already have DOM elements, and will not re-render them.
27118
+ *
27119
+ * The default tracking function (which tracks items by their identity) does not allow
27120
+ * duplicate items in arrays. This is because when there are duplicates, it is not possible
27121
+ * to maintain a one-to-one mapping between collection items and DOM elements.
27017
27122
  *
27018
27123
  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
27019
27124
  * with your own using the `track by` expression.
@@ -27026,7 +27131,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27026
27131
  * </div>
27027
27132
  * ```
27028
27133
  *
27029
- * You may use arbitrary expressions in `track by`, including references to custom functions
27134
+ * You may also use arbitrary expressions in `track by`, including references to custom functions
27030
27135
  * on the scope:
27031
27136
  * ```html
27032
27137
  * <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
@@ -27034,10 +27139,14 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
27034
27139
  * </div>
27035
27140
  * ```
27036
27141
  *
27037
- * If you are working with objects that have an identifier property, you can track
27142
+ * <div class="alert alert-success">
27143
+ * If you are working with objects that have an identifier property, you should track
27038
27144
  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
27039
27145
  * will not have to rebuild the DOM elements for items it has already rendered, even if the
27040
- * JavaScript objects in the collection have been substituted for new ones:
27146
+ * JavaScript objects in the collection have been substituted for new ones. For large collections,
27147
+ * this signifincantly improves rendering performance. If you don't have a unique identifier,
27148
+ * `track by $index` can also provide a performance boost.
27149
+ * </div>
27041
27150
  * ```html
27042
27151
  * <div ng-repeat="model in collection track by model.id">
27043
27152
  * {{model.name}}
@@ -28195,6 +28304,15 @@ var scriptDirective = ['$templateCache', function($templateCache) {
28195
28304
 
28196
28305
  var noopNgModelController = { $setViewValue: noop, $render: noop };
28197
28306
 
28307
+ function chromeHack(optionElement) {
28308
+ // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28309
+ // Adding an <option selected="selected"> element to a <select required="required"> should
28310
+ // automatically select the new element
28311
+ if (optionElement[0].hasAttribute('selected')) {
28312
+ optionElement[0].selected = true;
28313
+ }
28314
+ }
28315
+
28198
28316
  /**
28199
28317
  * @ngdoc type
28200
28318
  * @name select.SelectController
@@ -28270,6 +28388,8 @@ var SelectController =
28270
28388
  }
28271
28389
  var count = optionsMap.get(value) || 0;
28272
28390
  optionsMap.put(value, count + 1);
28391
+ self.ngModelCtrl.$render();
28392
+ chromeHack(element);
28273
28393
  };
28274
28394
 
28275
28395
  // Tell the select control that an option, with the given value, has been removed
@@ -28291,6 +28411,39 @@ var SelectController =
28291
28411
  self.hasOption = function(value) {
28292
28412
  return !!optionsMap.get(value);
28293
28413
  };
28414
+
28415
+
28416
+ self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
28417
+
28418
+ if (interpolateValueFn) {
28419
+ // The value attribute is interpolated
28420
+ var oldVal;
28421
+ optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
28422
+ if (isDefined(oldVal)) {
28423
+ self.removeOption(oldVal);
28424
+ }
28425
+ oldVal = newVal;
28426
+ self.addOption(newVal, optionElement);
28427
+ });
28428
+ } else if (interpolateTextFn) {
28429
+ // The text content is interpolated
28430
+ optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
28431
+ optionAttrs.$set('value', newVal);
28432
+ if (oldVal !== newVal) {
28433
+ self.removeOption(oldVal);
28434
+ }
28435
+ self.addOption(newVal, optionElement);
28436
+ });
28437
+ } else {
28438
+ // The value attribute is static
28439
+ self.addOption(optionAttrs.value, optionElement);
28440
+ }
28441
+
28442
+ optionElement.on('$destroy', function() {
28443
+ self.removeOption(optionAttrs.value);
28444
+ self.ngModelCtrl.$render();
28445
+ });
28446
+ };
28294
28447
  }];
28295
28448
 
28296
28449
  /**
@@ -28336,6 +28489,8 @@ var SelectController =
28336
28489
  *
28337
28490
  * @param {string} ngModel Assignable angular expression to data-bind to.
28338
28491
  * @param {string=} name Property name of the form under which the control is published.
28492
+ * @param {string=} multiple Allows multiple options to be selected. The selected values will be
28493
+ * bound to the model as an array.
28339
28494
  * @param {string=} required Sets `required` validation error key if the value is not entered.
28340
28495
  * @param {string=} ngRequired Adds required attribute and required validation constraint to
28341
28496
  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
@@ -28501,7 +28656,13 @@ var selectDirective = function() {
28501
28656
  restrict: 'E',
28502
28657
  require: ['select', '?ngModel'],
28503
28658
  controller: SelectController,
28504
- link: function(scope, element, attr, ctrls) {
28659
+ priority: 1,
28660
+ link: {
28661
+ pre: selectPreLink
28662
+ }
28663
+ };
28664
+
28665
+ function selectPreLink(scope, element, attr, ctrls) {
28505
28666
 
28506
28667
  // if ngModel is not defined, we don't need to do anything
28507
28668
  var ngModelCtrl = ctrls[1];
@@ -28571,7 +28732,6 @@ var selectDirective = function() {
28571
28732
 
28572
28733
  }
28573
28734
  }
28574
- };
28575
28735
  };
28576
28736
 
28577
28737
 
@@ -28579,16 +28739,6 @@ var selectDirective = function() {
28579
28739
  // of dynamically created (and destroyed) option elements to their containing select
28580
28740
  // directive via its controller.
28581
28741
  var optionDirective = ['$interpolate', function($interpolate) {
28582
-
28583
- function chromeHack(optionElement) {
28584
- // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
28585
- // Adding an <option selected="selected"> element to a <select required="required"> should
28586
- // automatically select the new element
28587
- if (optionElement[0].hasAttribute('selected')) {
28588
- optionElement[0].selected = true;
28589
- }
28590
- }
28591
-
28592
28742
  return {
28593
28743
  restrict: 'E',
28594
28744
  priority: 100,
@@ -28596,12 +28746,12 @@ var optionDirective = ['$interpolate', function($interpolate) {
28596
28746
 
28597
28747
  if (isDefined(attr.value)) {
28598
28748
  // If the value attribute is defined, check if it contains an interpolation
28599
- var valueInterpolated = $interpolate(attr.value, true);
28749
+ var interpolateValueFn = $interpolate(attr.value, true);
28600
28750
  } else {
28601
28751
  // If the value attribute is not defined then we fall back to the
28602
28752
  // text content of the option element, which may be interpolated
28603
- var interpolateFn = $interpolate(element.text(), true);
28604
- if (!interpolateFn) {
28753
+ var interpolateTextFn = $interpolate(element.text(), true);
28754
+ if (!interpolateTextFn) {
28605
28755
  attr.$set('value', element.text());
28606
28756
  }
28607
28757
  }
@@ -28615,44 +28765,8 @@ var optionDirective = ['$interpolate', function($interpolate) {
28615
28765
  selectCtrl = parent.data(selectCtrlName) ||
28616
28766
  parent.parent().data(selectCtrlName); // in case we are in optgroup
28617
28767
 
28618
- function addOption(optionValue) {
28619
- selectCtrl.addOption(optionValue, element);
28620
- selectCtrl.ngModelCtrl.$render();
28621
- chromeHack(element);
28622
- }
28623
-
28624
- // Only update trigger option updates if this is an option within a `select`
28625
- // that also has `ngModel` attached
28626
- if (selectCtrl && selectCtrl.ngModelCtrl) {
28627
-
28628
- if (valueInterpolated) {
28629
- // The value attribute is interpolated
28630
- var oldVal;
28631
- attr.$observe('value', function valueAttributeObserveAction(newVal) {
28632
- if (isDefined(oldVal)) {
28633
- selectCtrl.removeOption(oldVal);
28634
- }
28635
- oldVal = newVal;
28636
- addOption(newVal);
28637
- });
28638
- } else if (interpolateFn) {
28639
- // The text content is interpolated
28640
- scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
28641
- attr.$set('value', newVal);
28642
- if (oldVal !== newVal) {
28643
- selectCtrl.removeOption(oldVal);
28644
- }
28645
- addOption(newVal);
28646
- });
28647
- } else {
28648
- // The value attribute is static
28649
- addOption(attr.value);
28650
- }
28651
-
28652
- element.on('$destroy', function() {
28653
- selectCtrl.removeOption(attr.value);
28654
- selectCtrl.ngModelCtrl.$render();
28655
- });
28768
+ if (selectCtrl) {
28769
+ selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
28656
28770
  }
28657
28771
  };
28658
28772
  }