angularjs-rails 1.4.8 → 1.5.0

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.
@@ -9190,8 +9190,8 @@ return jQuery;
9190
9190
  }));
9191
9191
 
9192
9192
  /**
9193
- * @license AngularJS v1.4.8
9194
- * (c) 2010-2015 Google, Inc. http://angularjs.org
9193
+ * @license AngularJS v1.5.0
9194
+ * (c) 2010-2016 Google, Inc. http://angularjs.org
9195
9195
  * License: MIT
9196
9196
  */
9197
9197
  (function(window, document){
@@ -9249,7 +9249,7 @@ function minErr(module, ErrorConstructor) {
9249
9249
  return match;
9250
9250
  });
9251
9251
 
9252
- message += '\nhttp://errors.angularjs.org/1.4.8/' +
9252
+ message += '\nhttp://errors.angularjs.org/1.5.0/' +
9253
9253
  (module ? module + '/' : '') + code;
9254
9254
 
9255
9255
  for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -9380,29 +9380,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
9380
9380
  // This is used so that it's possible for internal tests to create mock ValidityStates.
9381
9381
  var VALIDITY_STATE_PROPERTY = 'validity';
9382
9382
 
9383
- /**
9384
- * @ngdoc function
9385
- * @name angular.lowercase
9386
- * @module ng
9387
- * @kind function
9388
- *
9389
- * @description Converts the specified string to lowercase.
9390
- * @param {string} string String to be converted to lowercase.
9391
- * @returns {string} Lowercased string.
9392
- */
9393
- var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
9394
9383
  var hasOwnProperty = Object.prototype.hasOwnProperty;
9395
9384
 
9396
- /**
9397
- * @ngdoc function
9398
- * @name angular.uppercase
9399
- * @module ng
9400
- * @kind function
9401
- *
9402
- * @description Converts the specified string to uppercase.
9403
- * @param {string} string String to be converted to uppercase.
9404
- * @returns {string} Uppercased string.
9405
- */
9385
+ var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
9406
9386
  var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
9407
9387
 
9408
9388
 
@@ -9422,7 +9402,7 @@ var manualUppercase = function(s) {
9422
9402
 
9423
9403
  // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
9424
9404
  // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
9425
- // with correct but slower alternatives.
9405
+ // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
9426
9406
  if ('i' !== 'I'.toLowerCase()) {
9427
9407
  lowercase = manualLowercase;
9428
9408
  uppercase = manualUppercase;
@@ -9465,7 +9445,7 @@ function isArrayLike(obj) {
9465
9445
 
9466
9446
  // arrays, strings and jQuery/jqLite objects are array like
9467
9447
  // * jqLite is either the jQuery or jqLite constructor function
9468
- // * we have to check the existance of jqLite first as this method is called
9448
+ // * we have to check the existence of jqLite first as this method is called
9469
9449
  // via the forEach method when constructing the jqLite object in the first place
9470
9450
  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
9471
9451
 
@@ -9476,7 +9456,8 @@ function isArrayLike(obj) {
9476
9456
  // NodeList objects (with `item` method) and
9477
9457
  // other objects with suitable length characteristics are array-like
9478
9458
  return isNumber(length) &&
9479
- (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
9459
+ (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
9460
+
9480
9461
  }
9481
9462
 
9482
9463
  /**
@@ -9573,7 +9554,7 @@ function forEachSorted(obj, iterator, context) {
9573
9554
  * @returns {function(*, string)}
9574
9555
  */
9575
9556
  function reverseParams(iteratorFn) {
9576
- return function(value, key) { iteratorFn(key, value); };
9557
+ return function(value, key) {iteratorFn(key, value);};
9577
9558
  }
9578
9559
 
9579
9560
  /**
@@ -9944,6 +9925,10 @@ function isTypedArray(value) {
9944
9925
  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
9945
9926
  }
9946
9927
 
9928
+ function isArrayBuffer(obj) {
9929
+ return toString.call(obj) === '[object ArrayBuffer]';
9930
+ }
9931
+
9947
9932
 
9948
9933
  var trim = function(value) {
9949
9934
  return isString(value) ? value.trim() : value;
@@ -9981,7 +9966,7 @@ function isElement(node) {
9981
9966
  * @returns {object} in the form of {key1:true, key2:true, ...}
9982
9967
  */
9983
9968
  function makeMap(str) {
9984
- var obj = {}, items = str.split(","), i;
9969
+ var obj = {}, items = str.split(','), i;
9985
9970
  for (i = 0; i < items.length; i++) {
9986
9971
  obj[items[i]] = true;
9987
9972
  }
@@ -10068,7 +10053,7 @@ function copy(source, destination) {
10068
10053
  var stackDest = [];
10069
10054
 
10070
10055
  if (destination) {
10071
- if (isTypedArray(destination)) {
10056
+ if (isTypedArray(destination) || isArrayBuffer(destination)) {
10072
10057
  throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
10073
10058
  }
10074
10059
  if (source === destination) {
@@ -10142,22 +10127,10 @@ function copy(source, destination) {
10142
10127
  }
10143
10128
 
10144
10129
  var needsRecurse = false;
10145
- var destination;
10130
+ var destination = copyType(source);
10146
10131
 
10147
- if (isArray(source)) {
10148
- destination = [];
10149
- needsRecurse = true;
10150
- } else if (isTypedArray(source)) {
10151
- destination = new source.constructor(source);
10152
- } else if (isDate(source)) {
10153
- destination = new Date(source.getTime());
10154
- } else if (isRegExp(source)) {
10155
- destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10156
- destination.lastIndex = source.lastIndex;
10157
- } else if (isFunction(source.cloneNode)) {
10158
- destination = source.cloneNode(true);
10159
- } else {
10160
- destination = Object.create(getPrototypeOf(source));
10132
+ if (destination === undefined) {
10133
+ destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
10161
10134
  needsRecurse = true;
10162
10135
  }
10163
10136
 
@@ -10168,6 +10141,45 @@ function copy(source, destination) {
10168
10141
  ? copyRecurse(source, destination)
10169
10142
  : destination;
10170
10143
  }
10144
+
10145
+ function copyType(source) {
10146
+ switch (toString.call(source)) {
10147
+ case '[object Int8Array]':
10148
+ case '[object Int16Array]':
10149
+ case '[object Int32Array]':
10150
+ case '[object Float32Array]':
10151
+ case '[object Float64Array]':
10152
+ case '[object Uint8Array]':
10153
+ case '[object Uint8ClampedArray]':
10154
+ case '[object Uint16Array]':
10155
+ case '[object Uint32Array]':
10156
+ return new source.constructor(copyElement(source.buffer));
10157
+
10158
+ case '[object ArrayBuffer]':
10159
+ //Support: IE10
10160
+ if (!source.slice) {
10161
+ var copied = new ArrayBuffer(source.byteLength);
10162
+ new Uint8Array(copied).set(new Uint8Array(source));
10163
+ return copied;
10164
+ }
10165
+ return source.slice(0);
10166
+
10167
+ case '[object Boolean]':
10168
+ case '[object Number]':
10169
+ case '[object String]':
10170
+ case '[object Date]':
10171
+ return new source.constructor(source.valueOf());
10172
+
10173
+ case '[object RegExp]':
10174
+ var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10175
+ re.lastIndex = source.lastIndex;
10176
+ return re;
10177
+ }
10178
+
10179
+ if (isFunction(source.cloneNode)) {
10180
+ return source.cloneNode(true);
10181
+ }
10182
+ }
10171
10183
  }
10172
10184
 
10173
10185
  /**
@@ -10230,38 +10242,37 @@ function equals(o1, o2) {
10230
10242
  if (o1 === null || o2 === null) return false;
10231
10243
  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
10232
10244
  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
10233
- if (t1 == t2) {
10234
- if (t1 == 'object') {
10235
- if (isArray(o1)) {
10236
- if (!isArray(o2)) return false;
10237
- if ((length = o1.length) == o2.length) {
10238
- for (key = 0; key < length; key++) {
10239
- if (!equals(o1[key], o2[key])) return false;
10240
- }
10241
- return true;
10242
- }
10243
- } else if (isDate(o1)) {
10244
- if (!isDate(o2)) return false;
10245
- return equals(o1.getTime(), o2.getTime());
10246
- } else if (isRegExp(o1)) {
10247
- return isRegExp(o2) ? o1.toString() == o2.toString() : false;
10248
- } else {
10249
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
10250
- isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
10251
- keySet = createMap();
10252
- for (key in o1) {
10253
- if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10245
+ if (t1 == t2 && t1 == 'object') {
10246
+ if (isArray(o1)) {
10247
+ if (!isArray(o2)) return false;
10248
+ if ((length = o1.length) == o2.length) {
10249
+ for (key = 0; key < length; key++) {
10254
10250
  if (!equals(o1[key], o2[key])) return false;
10255
- keySet[key] = true;
10256
- }
10257
- for (key in o2) {
10258
- if (!(key in keySet) &&
10259
- key.charAt(0) !== '$' &&
10260
- isDefined(o2[key]) &&
10261
- !isFunction(o2[key])) return false;
10262
10251
  }
10263
10252
  return true;
10264
10253
  }
10254
+ } else if (isDate(o1)) {
10255
+ if (!isDate(o2)) return false;
10256
+ return equals(o1.getTime(), o2.getTime());
10257
+ } else if (isRegExp(o1)) {
10258
+ if (!isRegExp(o2)) return false;
10259
+ return o1.toString() == o2.toString();
10260
+ } else {
10261
+ if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
10262
+ isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
10263
+ keySet = createMap();
10264
+ for (key in o1) {
10265
+ if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10266
+ if (!equals(o1[key], o2[key])) return false;
10267
+ keySet[key] = true;
10268
+ }
10269
+ for (key in o2) {
10270
+ if (!(key in keySet) &&
10271
+ key.charAt(0) !== '$' &&
10272
+ isDefined(o2[key]) &&
10273
+ !isFunction(o2[key])) return false;
10274
+ }
10275
+ return true;
10265
10276
  }
10266
10277
  }
10267
10278
  return false;
@@ -10438,7 +10449,7 @@ function toJsonReplacer(key, value) {
10438
10449
  * @returns {string|undefined} JSON-ified string representing `obj`.
10439
10450
  */
10440
10451
  function toJson(obj, pretty) {
10441
- if (typeof obj === 'undefined') return undefined;
10452
+ if (isUndefined(obj)) return undefined;
10442
10453
  if (!isNumber(pretty)) {
10443
10454
  pretty = pretty ? 2 : null;
10444
10455
  }
@@ -10465,7 +10476,10 @@ function fromJson(json) {
10465
10476
  }
10466
10477
 
10467
10478
 
10479
+ var ALL_COLONS = /:/g;
10468
10480
  function timezoneToOffset(timezone, fallback) {
10481
+ // IE/Edge do not "understand" colon (`:`) in timezone
10482
+ timezone = timezone.replace(ALL_COLONS, '');
10469
10483
  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
10470
10484
  return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
10471
10485
  }
@@ -10480,8 +10494,9 @@ function addDateMinutes(date, minutes) {
10480
10494
 
10481
10495
  function convertTimezoneToLocal(date, timezone, reverse) {
10482
10496
  reverse = reverse ? -1 : 1;
10483
- var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
10484
- return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
10497
+ var dateTimezoneOffset = date.getTimezoneOffset();
10498
+ var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
10499
+ return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
10485
10500
  }
10486
10501
 
10487
10502
 
@@ -10500,7 +10515,7 @@ function startingTag(element) {
10500
10515
  return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
10501
10516
  elemHtml.
10502
10517
  match(/^(<[^>]+>)/)[1].
10503
- replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
10518
+ replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
10504
10519
  } catch (e) {
10505
10520
  return lowercase(elemHtml);
10506
10521
  }
@@ -10943,7 +10958,6 @@ function snake_case(name, separator) {
10943
10958
  }
10944
10959
 
10945
10960
  var bindJQueryFired = false;
10946
- var skipDestroyOnNextJQueryCleanData;
10947
10961
  function bindJQuery() {
10948
10962
  var originalCleanData;
10949
10963
 
@@ -10977,15 +10991,11 @@ function bindJQuery() {
10977
10991
  originalCleanData = jQuery.cleanData;
10978
10992
  jQuery.cleanData = function(elems) {
10979
10993
  var events;
10980
- if (!skipDestroyOnNextJQueryCleanData) {
10981
- for (var i = 0, elem; (elem = elems[i]) != null; i++) {
10982
- events = jQuery._data(elem, "events");
10983
- if (events && events.$destroy) {
10984
- jQuery(elem).triggerHandler('$destroy');
10985
- }
10994
+ for (var i = 0, elem; (elem = elems[i]) != null; i++) {
10995
+ events = jQuery._data(elem, "events");
10996
+ if (events && events.$destroy) {
10997
+ jQuery(elem).triggerHandler('$destroy');
10986
10998
  }
10987
- } else {
10988
- skipDestroyOnNextJQueryCleanData = false;
10989
10999
  }
10990
11000
  originalCleanData(elems);
10991
11001
  };
@@ -11179,7 +11189,7 @@ function setupModuleLoader(window) {
11179
11189
  * unspecified then the module is being retrieved for further configuration.
11180
11190
  * @param {Function=} configFn Optional configuration function for the module. Same as
11181
11191
  * {@link angular.Module#config Module#config()}.
11182
- * @returns {module} new module with the {@link angular.Module} api.
11192
+ * @returns {angular.Module} new module with the {@link angular.Module} api.
11183
11193
  */
11184
11194
  return function module(name, requires, configFn) {
11185
11195
  var assertNotHasOwnProperty = function(name, context) {
@@ -11385,6 +11395,19 @@ function setupModuleLoader(window) {
11385
11395
  */
11386
11396
  directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
11387
11397
 
11398
+ /**
11399
+ * @ngdoc method
11400
+ * @name angular.Module#component
11401
+ * @module ng
11402
+ * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
11403
+ * @param {Object} options Component definition object (a simplified
11404
+ * {@link ng.$compile#directive-definition-object directive definition object})
11405
+ *
11406
+ * @description
11407
+ * See {@link ng.$compileProvider#component $compileProvider.component()}.
11408
+ */
11409
+ component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
11410
+
11388
11411
  /**
11389
11412
  * @ngdoc method
11390
11413
  * @name angular.Module#config
@@ -11536,11 +11559,14 @@ function toDebugString(obj) {
11536
11559
  $AnchorScrollProvider,
11537
11560
  $AnimateProvider,
11538
11561
  $CoreAnimateCssProvider,
11562
+ $$CoreAnimateJsProvider,
11539
11563
  $$CoreAnimateQueueProvider,
11540
- $$CoreAnimateRunnerProvider,
11564
+ $$AnimateRunnerFactoryProvider,
11565
+ $$AnimateAsyncRunFactoryProvider,
11541
11566
  $BrowserProvider,
11542
11567
  $CacheFactoryProvider,
11543
11568
  $ControllerProvider,
11569
+ $DateProvider,
11544
11570
  $DocumentProvider,
11545
11571
  $ExceptionHandlerProvider,
11546
11572
  $FilterProvider,
@@ -11590,11 +11616,11 @@ function toDebugString(obj) {
11590
11616
  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11591
11617
  */
11592
11618
  var version = {
11593
- full: '1.4.8', // all of these placeholder strings will be replaced by grunt's
11619
+ full: '1.5.0', // all of these placeholder strings will be replaced by grunt's
11594
11620
  major: 1, // package task
11595
- minor: 4,
11596
- dot: 8,
11597
- codeName: 'ice-manipulation'
11621
+ minor: 5,
11622
+ dot: 0,
11623
+ codeName: 'ennoblement-facilitation'
11598
11624
  };
11599
11625
 
11600
11626
 
@@ -11696,8 +11722,10 @@ function publishExternalAPI(angular) {
11696
11722
  $anchorScroll: $AnchorScrollProvider,
11697
11723
  $animate: $AnimateProvider,
11698
11724
  $animateCss: $CoreAnimateCssProvider,
11725
+ $$animateJs: $$CoreAnimateJsProvider,
11699
11726
  $$animateQueue: $$CoreAnimateQueueProvider,
11700
- $$AnimateRunner: $$CoreAnimateRunnerProvider,
11727
+ $$AnimateRunner: $$AnimateRunnerFactoryProvider,
11728
+ $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
11701
11729
  $browser: $BrowserProvider,
11702
11730
  $cacheFactory: $CacheFactoryProvider,
11703
11731
  $controller: $ControllerProvider,
@@ -11768,16 +11796,22 @@ function publishExternalAPI(angular) {
11768
11796
  *
11769
11797
  * If jQuery is available, `angular.element` is an alias for the
11770
11798
  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
11771
- * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
11799
+ * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
11772
11800
  *
11773
- * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
11774
- * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
11775
- * commonly needed functionality with the goal of having a very small footprint.</div>
11801
+ * jqLite is a tiny, API-compatible subset of jQuery that allows
11802
+ * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
11803
+ * commonly needed functionality with the goal of having a very small footprint.
11776
11804
  *
11777
- * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
11805
+ * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
11806
+ * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
11807
+ * specific version of jQuery if multiple versions exist on the page.
11778
11808
  *
11779
- * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
11780
- * jqLite; they are never raw DOM references.</div>
11809
+ * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
11810
+ * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
11811
+ *
11812
+ * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
11813
+ * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
11814
+ * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
11781
11815
  *
11782
11816
  * ## Angular's jqLite
11783
11817
  * jqLite provides only the following jQuery methods:
@@ -11790,7 +11824,8 @@ function publishExternalAPI(angular) {
11790
11824
  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
11791
11825
  * - [`clone()`](http://api.jquery.com/clone/)
11792
11826
  * - [`contents()`](http://api.jquery.com/contents/)
11793
- * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
11827
+ * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
11828
+ * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
11794
11829
  * - [`data()`](http://api.jquery.com/data/)
11795
11830
  * - [`detach()`](http://api.jquery.com/detach/)
11796
11831
  * - [`empty()`](http://api.jquery.com/empty/)
@@ -11924,6 +11959,12 @@ function jqLiteHasData(node) {
11924
11959
  return false;
11925
11960
  }
11926
11961
 
11962
+ function jqLiteCleanData(nodes) {
11963
+ for (var i = 0, ii = nodes.length; i < ii; i++) {
11964
+ jqLiteRemoveData(nodes[i]);
11965
+ }
11966
+ }
11967
+
11927
11968
  function jqLiteBuildFragment(html, context) {
11928
11969
  var tmp, tag, wrap,
11929
11970
  fragment = context.createDocumentFragment(),
@@ -11976,6 +12017,16 @@ function jqLiteParseHTML(html, context) {
11976
12017
  return [];
11977
12018
  }
11978
12019
 
12020
+ function jqLiteWrapNode(node, wrapper) {
12021
+ var parent = node.parentNode;
12022
+
12023
+ if (parent) {
12024
+ parent.replaceChild(wrapper, node);
12025
+ }
12026
+
12027
+ wrapper.appendChild(node);
12028
+ }
12029
+
11979
12030
 
11980
12031
  // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
11981
12032
  var jqLiteContains = Node.prototype.contains || function(arg) {
@@ -12226,7 +12277,7 @@ function jqLiteRemove(element, keepData) {
12226
12277
  function jqLiteDocumentLoaded(action, win) {
12227
12278
  win = win || window;
12228
12279
  if (win.document.readyState === 'complete') {
12229
- // Force the action to be run async for consistent behaviour
12280
+ // Force the action to be run async for consistent behavior
12230
12281
  // from the action's point of view
12231
12282
  // i.e. it will definitely not be in a $apply
12232
12283
  win.setTimeout(action);
@@ -12312,7 +12363,8 @@ function getAliasedAttrName(name) {
12312
12363
  forEach({
12313
12364
  data: jqLiteData,
12314
12365
  removeData: jqLiteRemoveData,
12315
- hasData: jqLiteHasData
12366
+ hasData: jqLiteHasData,
12367
+ cleanData: jqLiteCleanData
12316
12368
  }, function(fn, name) {
12317
12369
  JQLite[name] = fn;
12318
12370
  });
@@ -12667,12 +12719,7 @@ forEach({
12667
12719
  },
12668
12720
 
12669
12721
  wrap: function(element, wrapNode) {
12670
- wrapNode = jqLite(wrapNode).eq(0).clone()[0];
12671
- var parent = element.parentNode;
12672
- if (parent) {
12673
- parent.replaceChild(wrapNode, element);
12674
- }
12675
- wrapNode.appendChild(element);
12722
+ jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
12676
12723
  },
12677
12724
 
12678
12725
  remove: jqLiteRemove,
@@ -12950,17 +12997,23 @@ var $$HashMapProvider = [function() {
12950
12997
  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
12951
12998
  */
12952
12999
 
13000
+ var ARROW_ARG = /^([^\(]+?)=>/;
12953
13001
  var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
12954
13002
  var FN_ARG_SPLIT = /,/;
12955
13003
  var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
12956
13004
  var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
12957
13005
  var $injectorMinErr = minErr('$injector');
12958
13006
 
13007
+ function extractArgs(fn) {
13008
+ var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
13009
+ args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
13010
+ return args;
13011
+ }
13012
+
12959
13013
  function anonFn(fn) {
12960
13014
  // For anonymous functions, showing at the very least the function signature can help in
12961
13015
  // debugging.
12962
- var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
12963
- args = fnText.match(FN_ARGS);
13016
+ var args = extractArgs(fn);
12964
13017
  if (args) {
12965
13018
  return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
12966
13019
  }
@@ -12969,7 +13022,6 @@ function anonFn(fn) {
12969
13022
 
12970
13023
  function annotate(fn, strictDi, name) {
12971
13024
  var $inject,
12972
- fnText,
12973
13025
  argDecl,
12974
13026
  last;
12975
13027
 
@@ -12984,8 +13036,7 @@ function annotate(fn, strictDi, name) {
12984
13036
  throw $injectorMinErr('strictdi',
12985
13037
  '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
12986
13038
  }
12987
- fnText = fn.toString().replace(STRIP_COMMENTS, '');
12988
- argDecl = fnText.match(FN_ARGS);
13039
+ argDecl = extractArgs(fn);
12989
13040
  forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
12990
13041
  arg.replace(FN_ARG, function(all, underscore, name) {
12991
13042
  $inject.push(name);
@@ -13375,8 +13426,20 @@ function annotate(fn, strictDi, name) {
13375
13426
  *
13376
13427
  * Register a **service constructor**, which will be invoked with `new` to create the service
13377
13428
  * instance.
13378
- * This is short for registering a service where its provider's `$get` property is the service
13379
- * constructor function that will be used to instantiate the service instance.
13429
+ * This is short for registering a service where its provider's `$get` property is a factory
13430
+ * function that returns an instance instantiated by the injector from the service constructor
13431
+ * function.
13432
+ *
13433
+ * Internally it looks a bit like this:
13434
+ *
13435
+ * ```
13436
+ * {
13437
+ * $get: function() {
13438
+ * return $injector.instantiate(constructor);
13439
+ * }
13440
+ * }
13441
+ * ```
13442
+ *
13380
13443
  *
13381
13444
  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
13382
13445
  * as a type/class.
@@ -13477,7 +13540,7 @@ function annotate(fn, strictDi, name) {
13477
13540
  * @description
13478
13541
  *
13479
13542
  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
13480
- * intercepts the creation of a service, allowing it to override or modify the behaviour of the
13543
+ * intercepts the creation of a service, allowing it to override or modify the behavior of the
13481
13544
  * service. The object returned by the decorator may be the original service, or a new service
13482
13545
  * object which replaces or wraps and delegates to the original service.
13483
13546
  *
@@ -13526,14 +13589,19 @@ function createInjector(modulesToLoad, strictDi) {
13526
13589
  throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
13527
13590
  })),
13528
13591
  instanceCache = {},
13529
- instanceInjector = (instanceCache.$injector =
13592
+ protoInstanceInjector =
13530
13593
  createInternalInjector(instanceCache, function(serviceName, caller) {
13531
13594
  var provider = providerInjector.get(serviceName + providerSuffix, caller);
13532
- return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
13533
- }));
13534
-
13595
+ return instanceInjector.invoke(
13596
+ provider.$get, provider, undefined, serviceName);
13597
+ }),
13598
+ instanceInjector = protoInstanceInjector;
13535
13599
 
13536
- forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
13600
+ providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
13601
+ var runBlocks = loadModules(modulesToLoad);
13602
+ instanceInjector = protoInstanceInjector.get('$injector');
13603
+ instanceInjector.strictDi = strictDi;
13604
+ forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
13537
13605
 
13538
13606
  return instanceInjector;
13539
13607
 
@@ -13683,48 +13751,67 @@ function createInjector(modulesToLoad, strictDi) {
13683
13751
  }
13684
13752
  }
13685
13753
 
13686
- function invoke(fn, self, locals, serviceName) {
13687
- if (typeof locals === 'string') {
13688
- serviceName = locals;
13689
- locals = null;
13690
- }
13691
13754
 
13755
+ function injectionArgs(fn, locals, serviceName) {
13692
13756
  var args = [],
13693
- $inject = createInjector.$$annotate(fn, strictDi, serviceName),
13694
- length, i,
13695
- key;
13757
+ $inject = createInjector.$$annotate(fn, strictDi, serviceName);
13696
13758
 
13697
- for (i = 0, length = $inject.length; i < length; i++) {
13698
- key = $inject[i];
13759
+ for (var i = 0, length = $inject.length; i < length; i++) {
13760
+ var key = $inject[i];
13699
13761
  if (typeof key !== 'string') {
13700
13762
  throw $injectorMinErr('itkn',
13701
13763
  'Incorrect injection token! Expected service name as string, got {0}', key);
13702
13764
  }
13703
- args.push(
13704
- locals && locals.hasOwnProperty(key)
13705
- ? locals[key]
13706
- : getService(key, serviceName)
13707
- );
13765
+ args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
13766
+ getService(key, serviceName));
13767
+ }
13768
+ return args;
13769
+ }
13770
+
13771
+ function isClass(func) {
13772
+ // IE 9-11 do not support classes and IE9 leaks with the code below.
13773
+ if (msie <= 11) {
13774
+ return false;
13775
+ }
13776
+ // Workaround for MS Edge.
13777
+ // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
13778
+ return typeof func === 'function'
13779
+ && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
13780
+ }
13781
+
13782
+ function invoke(fn, self, locals, serviceName) {
13783
+ if (typeof locals === 'string') {
13784
+ serviceName = locals;
13785
+ locals = null;
13708
13786
  }
13787
+
13788
+ var args = injectionArgs(fn, locals, serviceName);
13709
13789
  if (isArray(fn)) {
13710
- fn = fn[length];
13790
+ fn = fn[fn.length - 1];
13711
13791
  }
13712
13792
 
13713
- // http://jsperf.com/angularjs-invoke-apply-vs-switch
13714
- // #5388
13715
- return fn.apply(self, args);
13793
+ if (!isClass(fn)) {
13794
+ // http://jsperf.com/angularjs-invoke-apply-vs-switch
13795
+ // #5388
13796
+ return fn.apply(self, args);
13797
+ } else {
13798
+ args.unshift(null);
13799
+ return new (Function.prototype.bind.apply(fn, args))();
13800
+ }
13716
13801
  }
13717
13802
 
13803
+
13718
13804
  function instantiate(Type, locals, serviceName) {
13719
13805
  // Check if Type is annotated and use just the given function at n-1 as parameter
13720
13806
  // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
13721
- // Object creation: http://jsperf.com/create-constructor/2
13722
- var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
13723
- var returnedValue = invoke(Type, instance, locals, serviceName);
13724
-
13725
- return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
13807
+ var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
13808
+ var args = injectionArgs(Type, locals, serviceName);
13809
+ // Empty object at position 0 is ignored for invocation with `new`, but required.
13810
+ args.unshift(null);
13811
+ return new (Function.prototype.bind.apply(ctor, args))();
13726
13812
  }
13727
13813
 
13814
+
13728
13815
  return {
13729
13816
  invoke: invoke,
13730
13817
  instantiate: instantiate,
@@ -14063,27 +14150,8 @@ function prepareAnimateOptions(options) {
14063
14150
  : {};
14064
14151
  }
14065
14152
 
14066
- var $$CoreAnimateRunnerProvider = function() {
14067
- this.$get = ['$q', '$$rAF', function($q, $$rAF) {
14068
- function AnimateRunner() {}
14069
- AnimateRunner.all = noop;
14070
- AnimateRunner.chain = noop;
14071
- AnimateRunner.prototype = {
14072
- end: noop,
14073
- cancel: noop,
14074
- resume: noop,
14075
- pause: noop,
14076
- complete: noop,
14077
- then: function(pass, fail) {
14078
- return $q(function(resolve) {
14079
- $$rAF(function() {
14080
- resolve();
14081
- });
14082
- }).then(pass, fail);
14083
- }
14084
- };
14085
- return AnimateRunner;
14086
- }];
14153
+ var $$CoreAnimateJsProvider = function() {
14154
+ this.$get = function() {};
14087
14155
  };
14088
14156
 
14089
14157
  // this is prefixed with Core since it conflicts with
@@ -14111,7 +14179,12 @@ var $$CoreAnimateQueueProvider = function() {
14111
14179
  addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
14112
14180
  }
14113
14181
 
14114
- return new $$AnimateRunner(); // jshint ignore:line
14182
+ var runner = new $$AnimateRunner(); // jshint ignore:line
14183
+
14184
+ // since there are no animations to run the runner needs to be
14185
+ // notified that the animation call is complete.
14186
+ runner.complete();
14187
+ return runner;
14115
14188
  }
14116
14189
  };
14117
14190
 
@@ -14353,8 +14426,8 @@ var $AnimateProvider = ['$provide', function($provide) {
14353
14426
  * // remove all the animation event listeners listening for `enter` on the given element and its children
14354
14427
  * $animate.off('enter', container);
14355
14428
  *
14356
- * // remove the event listener function provided by `listenerFn` that is set
14357
- * // to listen for `enter` on the given `element` as well as its children
14429
+ * // remove the event listener function provided by `callback` that is set
14430
+ * // to listen for `enter` on the given `container` as well as its children
14358
14431
  * $animate.off('enter', container, callback);
14359
14432
  * ```
14360
14433
  *
@@ -14576,17 +14649,30 @@ var $AnimateProvider = ['$provide', function($provide) {
14576
14649
  * @kind function
14577
14650
  *
14578
14651
  * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
14579
- * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
14580
- * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
14581
- * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
14582
- * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
14652
+ * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
14653
+ * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
14654
+ * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
14655
+ * style in `to`, the style in `from` is applied immediately, and no animation is run.
14656
+ * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
14657
+ * method (or as part of the `options` parameter):
14658
+ *
14659
+ * ```js
14660
+ * ngModule.animation('.my-inline-animation', function() {
14661
+ * return {
14662
+ * animate : function(element, from, to, done, options) {
14663
+ * //animation
14664
+ * done();
14665
+ * }
14666
+ * }
14667
+ * });
14668
+ * ```
14583
14669
  *
14584
14670
  * @param {DOMElement} element the element which the CSS styles will be applied to
14585
14671
  * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
14586
14672
  * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
14587
14673
  * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
14588
14674
  * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
14589
- * (Note that if no animation is detected then this value will not be appplied to the element.)
14675
+ * (Note that if no animation is detected then this value will not be applied to the element.)
14590
14676
  * @param {object=} options an optional collection of options/styles that will be applied to the element
14591
14677
  *
14592
14678
  * @return {Promise} the animation callback promise
@@ -14604,6 +14690,190 @@ var $AnimateProvider = ['$provide', function($provide) {
14604
14690
  }];
14605
14691
  }];
14606
14692
 
14693
+ var $$AnimateAsyncRunFactoryProvider = function() {
14694
+ this.$get = ['$$rAF', function($$rAF) {
14695
+ var waitQueue = [];
14696
+
14697
+ function waitForTick(fn) {
14698
+ waitQueue.push(fn);
14699
+ if (waitQueue.length > 1) return;
14700
+ $$rAF(function() {
14701
+ for (var i = 0; i < waitQueue.length; i++) {
14702
+ waitQueue[i]();
14703
+ }
14704
+ waitQueue = [];
14705
+ });
14706
+ }
14707
+
14708
+ return function() {
14709
+ var passed = false;
14710
+ waitForTick(function() {
14711
+ passed = true;
14712
+ });
14713
+ return function(callback) {
14714
+ passed ? callback() : waitForTick(callback);
14715
+ };
14716
+ };
14717
+ }];
14718
+ };
14719
+
14720
+ var $$AnimateRunnerFactoryProvider = function() {
14721
+ this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
14722
+ function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
14723
+
14724
+ var INITIAL_STATE = 0;
14725
+ var DONE_PENDING_STATE = 1;
14726
+ var DONE_COMPLETE_STATE = 2;
14727
+
14728
+ AnimateRunner.chain = function(chain, callback) {
14729
+ var index = 0;
14730
+
14731
+ next();
14732
+ function next() {
14733
+ if (index === chain.length) {
14734
+ callback(true);
14735
+ return;
14736
+ }
14737
+
14738
+ chain[index](function(response) {
14739
+ if (response === false) {
14740
+ callback(false);
14741
+ return;
14742
+ }
14743
+ index++;
14744
+ next();
14745
+ });
14746
+ }
14747
+ };
14748
+
14749
+ AnimateRunner.all = function(runners, callback) {
14750
+ var count = 0;
14751
+ var status = true;
14752
+ forEach(runners, function(runner) {
14753
+ runner.done(onProgress);
14754
+ });
14755
+
14756
+ function onProgress(response) {
14757
+ status = status && response;
14758
+ if (++count === runners.length) {
14759
+ callback(status);
14760
+ }
14761
+ }
14762
+ };
14763
+
14764
+ function AnimateRunner(host) {
14765
+ this.setHost(host);
14766
+
14767
+ var rafTick = $$animateAsyncRun();
14768
+ var timeoutTick = function(fn) {
14769
+ $timeout(fn, 0, false);
14770
+ };
14771
+
14772
+ this._doneCallbacks = [];
14773
+ this._tick = function(fn) {
14774
+ var doc = $document[0];
14775
+
14776
+ // the document may not be ready or attached
14777
+ // to the module for some internal tests
14778
+ if (doc && doc.hidden) {
14779
+ timeoutTick(fn);
14780
+ } else {
14781
+ rafTick(fn);
14782
+ }
14783
+ };
14784
+ this._state = 0;
14785
+ }
14786
+
14787
+ AnimateRunner.prototype = {
14788
+ setHost: function(host) {
14789
+ this.host = host || {};
14790
+ },
14791
+
14792
+ done: function(fn) {
14793
+ if (this._state === DONE_COMPLETE_STATE) {
14794
+ fn();
14795
+ } else {
14796
+ this._doneCallbacks.push(fn);
14797
+ }
14798
+ },
14799
+
14800
+ progress: noop,
14801
+
14802
+ getPromise: function() {
14803
+ if (!this.promise) {
14804
+ var self = this;
14805
+ this.promise = $q(function(resolve, reject) {
14806
+ self.done(function(status) {
14807
+ status === false ? reject() : resolve();
14808
+ });
14809
+ });
14810
+ }
14811
+ return this.promise;
14812
+ },
14813
+
14814
+ then: function(resolveHandler, rejectHandler) {
14815
+ return this.getPromise().then(resolveHandler, rejectHandler);
14816
+ },
14817
+
14818
+ 'catch': function(handler) {
14819
+ return this.getPromise()['catch'](handler);
14820
+ },
14821
+
14822
+ 'finally': function(handler) {
14823
+ return this.getPromise()['finally'](handler);
14824
+ },
14825
+
14826
+ pause: function() {
14827
+ if (this.host.pause) {
14828
+ this.host.pause();
14829
+ }
14830
+ },
14831
+
14832
+ resume: function() {
14833
+ if (this.host.resume) {
14834
+ this.host.resume();
14835
+ }
14836
+ },
14837
+
14838
+ end: function() {
14839
+ if (this.host.end) {
14840
+ this.host.end();
14841
+ }
14842
+ this._resolve(true);
14843
+ },
14844
+
14845
+ cancel: function() {
14846
+ if (this.host.cancel) {
14847
+ this.host.cancel();
14848
+ }
14849
+ this._resolve(false);
14850
+ },
14851
+
14852
+ complete: function(response) {
14853
+ var self = this;
14854
+ if (self._state === INITIAL_STATE) {
14855
+ self._state = DONE_PENDING_STATE;
14856
+ self._tick(function() {
14857
+ self._resolve(response);
14858
+ });
14859
+ }
14860
+ },
14861
+
14862
+ _resolve: function(response) {
14863
+ if (this._state !== DONE_COMPLETE_STATE) {
14864
+ forEach(this._doneCallbacks, function(fn) {
14865
+ fn(response);
14866
+ });
14867
+ this._doneCallbacks.length = 0;
14868
+ this._state = DONE_COMPLETE_STATE;
14869
+ }
14870
+ }
14871
+ };
14872
+
14873
+ return AnimateRunner;
14874
+ }];
14875
+ };
14876
+
14607
14877
  /**
14608
14878
  * @ngdoc service
14609
14879
  * @name $animateCss
@@ -14616,37 +14886,18 @@ var $AnimateProvider = ['$provide', function($provide) {
14616
14886
  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
14617
14887
  */
14618
14888
  var $CoreAnimateCssProvider = function() {
14619
- this.$get = ['$$rAF', '$q', function($$rAF, $q) {
14889
+ this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
14620
14890
 
14621
- var RAFPromise = function() {};
14622
- RAFPromise.prototype = {
14623
- done: function(cancel) {
14624
- this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
14625
- },
14626
- end: function() {
14627
- this.done();
14628
- },
14629
- cancel: function() {
14630
- this.done(true);
14631
- },
14632
- getPromise: function() {
14633
- if (!this.defer) {
14634
- this.defer = $q.defer();
14635
- }
14636
- return this.defer.promise;
14637
- },
14638
- then: function(f1,f2) {
14639
- return this.getPromise().then(f1,f2);
14640
- },
14641
- 'catch': function(f1) {
14642
- return this.getPromise()['catch'](f1);
14643
- },
14644
- 'finally': function(f1) {
14645
- return this.getPromise()['finally'](f1);
14891
+ return function(element, initialOptions) {
14892
+ // all of the animation functions should create
14893
+ // a copy of the options data, however, if a
14894
+ // parent service has already created a copy then
14895
+ // we should stick to using that
14896
+ var options = initialOptions || {};
14897
+ if (!options.$$prepared) {
14898
+ options = copy(options);
14646
14899
  }
14647
- };
14648
14900
 
14649
- return function(element, options) {
14650
14901
  // there is no point in applying the styles since
14651
14902
  // there is no animation that goes on at all in
14652
14903
  // this version of $animateCss.
@@ -14659,7 +14910,8 @@ var $CoreAnimateCssProvider = function() {
14659
14910
  options.from = null;
14660
14911
  }
14661
14912
 
14662
- var closed, runner = new RAFPromise();
14913
+ /* jshint newcap: false */
14914
+ var closed, runner = new $$AnimateRunner();
14663
14915
  return {
14664
14916
  start: run,
14665
14917
  end: run
@@ -14667,16 +14919,16 @@ var $CoreAnimateCssProvider = function() {
14667
14919
 
14668
14920
  function run() {
14669
14921
  $$rAF(function() {
14670
- close();
14922
+ applyAnimationContents();
14671
14923
  if (!closed) {
14672
- runner.done();
14924
+ runner.complete();
14673
14925
  }
14674
14926
  closed = true;
14675
14927
  });
14676
14928
  return runner;
14677
14929
  }
14678
14930
 
14679
- function close() {
14931
+ function applyAnimationContents() {
14680
14932
  if (options.addClass) {
14681
14933
  element.addClass(options.addClass);
14682
14934
  options.addClass = null;
@@ -15584,7 +15836,7 @@ function $TemplateCacheProvider() {
15584
15836
  * When this property is set to true, the HTML compiler will collect DOM nodes between
15585
15837
  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
15586
15838
  * together as the directive elements. It is recommended that this feature be used on directives
15587
- * which are not strictly behavioural (such as {@link ngClick}), and which
15839
+ * which are not strictly behavioral (such as {@link ngClick}), and which
15588
15840
  * do not manipulate or replace child nodes (such as {@link ngInclude}).
15589
15841
  *
15590
15842
  * #### `priority`
@@ -15622,35 +15874,62 @@ function $TemplateCacheProvider() {
15622
15874
  * is bound to the parent scope, via matching attributes on the directive's element:
15623
15875
  *
15624
15876
  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
15625
- * always a string since DOM attributes are strings. If no `attr` name is specified then the
15626
- * attribute name is assumed to be the same as the local name.
15627
- * Given `<widget my-attr="hello {{name}}">` and widget definition
15628
- * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
15629
- * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
15630
- * `localName` property on the widget scope. The `name` is read from the parent scope (not
15631
- * component scope).
15632
- *
15633
- * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
15634
- * parent scope property of name defined via the value of the `attr` attribute. If no `attr`
15635
- * name is specified then the attribute name is assumed to be the same as the local name.
15636
- * Given `<widget my-attr="parentModel">` and widget definition of
15637
- * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
15877
+ * always a string since DOM attributes are strings. If no `attr` name is specified then the
15878
+ * attribute name is assumed to be the same as the local name. Given `<my-component
15879
+ * my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
15880
+ * the directive's scope property `localName` will reflect the interpolated value of `hello
15881
+ * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
15882
+ * scope. The `name` is read from the parent scope (not the directive's scope).
15883
+ *
15884
+ * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
15885
+ * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
15886
+ * If no `attr` name is specified then the attribute name is assumed to be the same as the local
15887
+ * name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
15888
+ * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
15889
+ * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
15890
+ * `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
15891
+ * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
15892
+ * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
15893
+ * will be thrown upon discovering changes to the local value, since it will be impossible to sync
15894
+ * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
15895
+ * method is used for tracking changes, and the equality check is based on object identity.
15896
+ * However, if an object literal or an array literal is passed as the binding expression, the
15897
+ * equality check is done by value (using the {@link angular.equals} function). It's also possible
15898
+ * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
15899
+ * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
15900
+ *
15901
+ * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
15902
+ * expression passed via the attribute `attr`. The expression is evaluated in the context of the
15903
+ * parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
15904
+ * local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
15905
+ *
15906
+ * For example, given `<my-component my-attr="parentModel">` and directive definition of
15907
+ * `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
15638
15908
  * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
15639
- * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
15640
- * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
15641
- * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
15642
- * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
15643
- * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
15644
- *
15645
- * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
15646
- * If no `attr` name is specified then the attribute name is assumed to be the same as the
15647
- * local name. Given `<widget my-attr="count = count + value">` and widget definition of
15648
- * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
15649
- * a function wrapper for the `count = count + value` expression. Often it's desirable to
15650
- * pass data from the isolated scope via an expression to the parent scope, this can be
15651
- * done by passing a map of local variable names and values into the expression wrapper fn.
15652
- * For example, if the expression is `increment(amount)` then we can specify the amount value
15653
- * by calling the `localFn` as `localFn({amount: 22})`.
15909
+ * in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
15910
+ * two caveats:
15911
+ * 1. one-way binding does not copy the value from the parent to the isolate scope, it simply
15912
+ * sets the same value. That means if your bound value is an object, changes to its properties
15913
+ * in the isolated scope will be reflected in the parent scope (because both reference the same object).
15914
+ * 2. one-way binding watches changes to the **identity** of the parent value. That means the
15915
+ * {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
15916
+ * to the value has changed. In most cases, this should not be of concern, but can be important
15917
+ * to know if you one-way bind to an object, and then replace that object in the isolated scope.
15918
+ * If you now change a property of the object in your parent scope, the change will not be
15919
+ * propagated to the isolated scope, because the identity of the object on the parent scope
15920
+ * has not changed. Instead you must assign a new object.
15921
+ *
15922
+ * One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
15923
+ * back to the parent. However, it does not make this completely impossible.
15924
+ *
15925
+ * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
15926
+ * no `attr` name is specified then the attribute name is assumed to be the same as the local name.
15927
+ * Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
15928
+ * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
15929
+ * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
15930
+ * via an expression to the parent scope. This can be done by passing a map of local variable names
15931
+ * and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
15932
+ * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
15654
15933
  *
15655
15934
  * In general it's possible to apply more than one directive to one element, but there might be limitations
15656
15935
  * depending on the type of scope required by the directives. The following points will help explain these limitations.
@@ -15668,9 +15947,32 @@ function $TemplateCacheProvider() {
15668
15947
  *
15669
15948
  *
15670
15949
  * #### `bindToController`
15671
- * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
15672
- * allow a component to have its properties bound to the controller, rather than to scope. When the controller
15673
- * is instantiated, the initial values of the isolate scope bindings are already available.
15950
+ * This property is used to bind scope properties directly to the controller. It can be either
15951
+ * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
15952
+ * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
15953
+ * definition: `controller: 'myCtrl as myAlias'`.
15954
+ *
15955
+ * When an isolate scope is used for a directive (see above), `bindToController: true` will
15956
+ * allow a component to have its properties bound to the controller, rather than to scope.
15957
+ *
15958
+ * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
15959
+ * properties. You can access these bindings once they have been initialized by providing a controller method called
15960
+ * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
15961
+ * initialized.
15962
+ *
15963
+ * <div class="alert alert-warning">
15964
+ * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
15965
+ * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
15966
+ * code that relies upon bindings inside a `$onInit` method on the controller, instead.
15967
+ * </div>
15968
+ *
15969
+ * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
15970
+ * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
15971
+ * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
15972
+ * scope (useful for component directives).
15973
+ *
15974
+ * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
15975
+ *
15674
15976
  *
15675
15977
  * #### `controller`
15676
15978
  * Controller constructor function. The controller is instantiated before the
@@ -15682,10 +15984,10 @@ function $TemplateCacheProvider() {
15682
15984
  * * `$element` - Current element
15683
15985
  * * `$attrs` - Current attributes object for the element
15684
15986
  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
15685
- * `function([scope], cloneLinkingFn, futureParentElement)`.
15686
- * * `scope`: optional argument to override the scope.
15687
- * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
15688
- * * `futureParentElement`:
15987
+ * `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
15988
+ * * `scope`: (optional) override the scope.
15989
+ * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
15990
+ * * `futureParentElement` (optional):
15689
15991
  * * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
15690
15992
  * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
15691
15993
  * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
@@ -15693,14 +15995,34 @@ function $TemplateCacheProvider() {
15693
15995
  * as those elements need to created and cloned in a special way when they are defined outside their
15694
15996
  * usual containers (e.g. like `<svg>`).
15695
15997
  * * See also the `directive.templateNamespace` property.
15998
+ * * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
15999
+ * then the default translusion is provided.
16000
+ * The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
16001
+ * `true` if the specified slot contains content (i.e. one or more DOM nodes).
15696
16002
  *
16003
+ * The controller can provide the following methods that act as life-cycle hooks:
16004
+ * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
16005
+ * had their bindings initialized (and before the pre &amp; post linking functions for the directives on
16006
+ * this element). This is a good place to put initialization code for your controller.
15697
16007
  *
15698
16008
  * #### `require`
15699
16009
  * Require another directive and inject its controller as the fourth argument to the linking function. The
15700
- * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
15701
- * injected argument will be an array in corresponding order. If no such directive can be
15702
- * found, or if the directive does not have a controller, then an error is raised (unless no link function
15703
- * is specified, in which case error checking is skipped). The name can be prefixed with:
16010
+ * `require` property can be a string, an array or an object:
16011
+ * * a **string** containing the name of the directive to pass to the linking function
16012
+ * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
16013
+ * linking function will be an array of controllers in the same order as the names in the `require` property
16014
+ * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
16015
+ * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
16016
+ * controllers.
16017
+ *
16018
+ * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
16019
+ * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
16020
+ * have been constructed but before `$onInit` is called.
16021
+ * See the {@link $compileProvider#component} helper for an example of how this can be used.
16022
+ *
16023
+ * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
16024
+ * raised (unless no link function is specified and the required controllers are not being bound to the directive
16025
+ * controller, in which case error checking is skipped). The name can be prefixed with:
15704
16026
  *
15705
16027
  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
15706
16028
  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
@@ -15793,14 +16115,6 @@ function $TemplateCacheProvider() {
15793
16115
  * The contents are compiled and provided to the directive as a **transclusion function**. See the
15794
16116
  * {@link $compile#transclusion Transclusion} section below.
15795
16117
  *
15796
- * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
15797
- * directive's element or the entire element:
15798
- *
15799
- * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
15800
- * * `'element'` - transclude the whole of the directive's element including any directives on this
15801
- * element that defined at a lower priority than this directive. When used, the `template`
15802
- * property is ignored.
15803
- *
15804
16118
  *
15805
16119
  * #### `compile`
15806
16120
  *
@@ -15828,7 +16142,7 @@ function $TemplateCacheProvider() {
15828
16142
 
15829
16143
  * <div class="alert alert-warning">
15830
16144
  * **Note:** The compile function cannot handle directives that recursively use themselves in their
15831
- * own templates or compile functions. Compiling these directives results in an infinite loop and a
16145
+ * own templates or compile functions. Compiling these directives results in an infinite loop and
15832
16146
  * stack overflow errors.
15833
16147
  *
15834
16148
  * This can be avoided by manually using $compile in the postLink function to imperatively compile
@@ -15930,6 +16244,34 @@ function $TemplateCacheProvider() {
15930
16244
  * Testing Transclusion Directives}.
15931
16245
  * </div>
15932
16246
  *
16247
+ * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
16248
+ * directive's element, the entire element or multiple parts of the element contents:
16249
+ *
16250
+ * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
16251
+ * * `'element'` - transclude the whole of the directive's element including any directives on this
16252
+ * element that defined at a lower priority than this directive. When used, the `template`
16253
+ * property is ignored.
16254
+ * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
16255
+ *
16256
+ * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
16257
+ *
16258
+ * This object is a map where the keys are the name of the slot to fill and the value is an element selector
16259
+ * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
16260
+ * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
16261
+ *
16262
+ * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
16263
+ *
16264
+ * If the element selector is prefixed with a `?` then that slot is optional.
16265
+ *
16266
+ * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
16267
+ * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
16268
+ *
16269
+ * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
16270
+ * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
16271
+ * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
16272
+ * injectable into the directive's controller.
16273
+ *
16274
+ *
15933
16275
  * #### Transclusion Functions
15934
16276
  *
15935
16277
  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
@@ -15950,7 +16292,7 @@ function $TemplateCacheProvider() {
15950
16292
  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
15951
16293
  *
15952
16294
  * <div class="alert alert-info">
15953
- * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
16295
+ * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
15954
16296
  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
15955
16297
  * </div>
15956
16298
  *
@@ -15982,7 +16324,7 @@ function $TemplateCacheProvider() {
15982
16324
  * </div>
15983
16325
  *
15984
16326
  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
15985
- * automatically destroy their transluded clones as necessary so you do not need to worry about this if
16327
+ * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
15986
16328
  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
15987
16329
  *
15988
16330
  *
@@ -16007,19 +16349,19 @@ function $TemplateCacheProvider() {
16007
16349
  *
16008
16350
  * The `$parent` scope hierarchy will look like this:
16009
16351
  *
16010
- * ```
16011
- * - $rootScope
16012
- * - isolate
16013
- * - transclusion
16014
- * ```
16352
+ ```
16353
+ - $rootScope
16354
+ - isolate
16355
+ - transclusion
16356
+ ```
16015
16357
  *
16016
16358
  * but the scopes will inherit prototypically from different scopes to their `$parent`.
16017
16359
  *
16018
- * ```
16019
- * - $rootScope
16020
- * - transclusion
16021
- * - isolate
16022
- * ```
16360
+ ```
16361
+ - $rootScope
16362
+ - transclusion
16363
+ - isolate
16364
+ ```
16023
16365
  *
16024
16366
  *
16025
16367
  * ### Attributes
@@ -16027,10 +16369,9 @@ function $TemplateCacheProvider() {
16027
16369
  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
16028
16370
  * `link()` or `compile()` functions. It has a variety of uses.
16029
16371
  *
16030
- * accessing *Normalized attribute names:*
16031
- * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
16032
- * the attributes object allows for normalized access to
16033
- * the attributes.
16372
+ * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
16373
+ * 'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
16374
+ * to the attributes.
16034
16375
  *
16035
16376
  * * *Directive inter-communication:* All directives share the same instance of the attributes
16036
16377
  * object which allows the directives to use the attributes object as inter directive
@@ -16151,8 +16492,15 @@ function $TemplateCacheProvider() {
16151
16492
  * directives; if given, it will be passed through to the link functions of
16152
16493
  * directives found in `element` during compilation.
16153
16494
  * * `transcludeControllers` - an object hash with keys that map controller names
16154
- * to controller instances; if given, it will make the controllers
16155
- * available to directives.
16495
+ * to a hash with the key `instance`, which maps to the controller instance;
16496
+ * if given, it will make the controllers available to directives on the compileNode:
16497
+ * ```
16498
+ * {
16499
+ * parent: {
16500
+ * instance: parentControllerInstance
16501
+ * }
16502
+ * }
16503
+ * ```
16156
16504
  * * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
16157
16505
  * the cloned elements; only needed for transcludes that are allowed to contain non html
16158
16506
  * elements (e.g. SVG elements). See also the directive.controller property.
@@ -16213,7 +16561,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16213
16561
  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
16214
16562
 
16215
16563
  function parseIsolateBindings(scope, directiveName, isController) {
16216
- var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
16564
+ var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
16217
16565
 
16218
16566
  var bindings = {};
16219
16567
 
@@ -16300,8 +16648,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16300
16648
  * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
16301
16649
  * will match as <code>ng-bind</code>), or an object map of directives where the keys are the
16302
16650
  * names and the values are the factories.
16303
- * @param {Function|Array} directiveFactory An injectable directive factory function. See
16304
- * {@link guide/directive} for more info.
16651
+ * @param {Function|Array} directiveFactory An injectable directive factory function. See the
16652
+ * {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
16305
16653
  * @returns {ng.$compileProvider} Self for chaining.
16306
16654
  */
16307
16655
  this.directive = function registerDirective(name, directiveFactory) {
@@ -16348,6 +16696,128 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16348
16696
  return this;
16349
16697
  };
16350
16698
 
16699
+ /**
16700
+ * @ngdoc method
16701
+ * @name $compileProvider#component
16702
+ * @module ng
16703
+ * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
16704
+ * @param {Object} options Component definition object (a simplified
16705
+ * {@link ng.$compile#directive-definition-object directive definition object}),
16706
+ * with the following properties (all optional):
16707
+ *
16708
+ * - `controller` – `{(string|function()=}` – controller constructor function that should be
16709
+ * associated with newly created scope or the name of a {@link ng.$compile#-controller-
16710
+ * registered controller} if passed as a string. An empty `noop` function by default.
16711
+ * - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
16712
+ * If present, the controller will be published to scope under the `controllerAs` name.
16713
+ * If not present, this will default to be `$ctrl`.
16714
+ * - `template` – `{string=|function()=}` – html template as a string or a function that
16715
+ * returns an html template as a string which should be used as the contents of this component.
16716
+ * Empty string by default.
16717
+ *
16718
+ * If `template` is a function, then it is {@link auto.$injector#invoke injected} with
16719
+ * the following locals:
16720
+ *
16721
+ * - `$element` - Current element
16722
+ * - `$attrs` - Current attributes object for the element
16723
+ *
16724
+ * - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
16725
+ * template that should be used as the contents of this component.
16726
+ *
16727
+ * If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
16728
+ * the following locals:
16729
+ *
16730
+ * - `$element` - Current element
16731
+ * - `$attrs` - Current attributes object for the element
16732
+ *
16733
+ * - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
16734
+ * Component properties are always bound to the component controller and not to the scope.
16735
+ * See {@link ng.$compile#-bindtocontroller- `bindToController`}.
16736
+ * - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
16737
+ * Disabled by default.
16738
+ * - `$...` – `{function()=}` – additional annotations to provide to the directive factory function.
16739
+ *
16740
+ * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
16741
+ * @description
16742
+ * Register a **component definition** with the compiler. This is a shorthand for registering a special
16743
+ * type of directive, which represents a self-contained UI component in your application. Such components
16744
+ * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
16745
+ *
16746
+ * Component definitions are very simple and do not require as much configuration as defining general
16747
+ * directives. Component definitions usually consist only of a template and a controller backing it.
16748
+ *
16749
+ * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
16750
+ * `bindToController`. They always have **isolate scope** and are restricted to elements.
16751
+ *
16752
+ * Here are a few examples of how you would usually define components:
16753
+ *
16754
+ * ```js
16755
+ * var myMod = angular.module(...);
16756
+ * myMod.component('myComp', {
16757
+ * template: '<div>My name is {{$ctrl.name}}</div>',
16758
+ * controller: function() {
16759
+ * this.name = 'shahar';
16760
+ * }
16761
+ * });
16762
+ *
16763
+ * myMod.component('myComp', {
16764
+ * template: '<div>My name is {{$ctrl.name}}</div>',
16765
+ * bindings: {name: '@'}
16766
+ * });
16767
+ *
16768
+ * myMod.component('myComp', {
16769
+ * templateUrl: 'views/my-comp.html',
16770
+ * controller: 'MyCtrl as ctrl',
16771
+ * bindings: {name: '@'}
16772
+ * });
16773
+ *
16774
+ * ```
16775
+ * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
16776
+ *
16777
+ * <br />
16778
+ * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
16779
+ */
16780
+ this.component = function registerComponent(name, options) {
16781
+ var controller = options.controller || function() {};
16782
+
16783
+ function factory($injector) {
16784
+ function makeInjectable(fn) {
16785
+ if (isFunction(fn) || isArray(fn)) {
16786
+ return function(tElement, tAttrs) {
16787
+ return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
16788
+ };
16789
+ } else {
16790
+ return fn;
16791
+ }
16792
+ }
16793
+
16794
+ var template = (!options.template && !options.templateUrl ? '' : options.template);
16795
+ return {
16796
+ controller: controller,
16797
+ controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
16798
+ template: makeInjectable(template),
16799
+ templateUrl: makeInjectable(options.templateUrl),
16800
+ transclude: options.transclude,
16801
+ scope: {},
16802
+ bindToController: options.bindings || {},
16803
+ restrict: 'E',
16804
+ require: options.require
16805
+ };
16806
+ }
16807
+
16808
+ // Copy any annotation properties (starting with $) over to the factory function
16809
+ // These could be used by libraries such as the new component router
16810
+ forEach(options, function(val, key) {
16811
+ if (key.charAt(0) === '$') {
16812
+ factory[key] = val;
16813
+ }
16814
+ });
16815
+
16816
+ factory.$inject = ['$injector'];
16817
+
16818
+ return this.directive(name, factory);
16819
+ };
16820
+
16351
16821
 
16352
16822
  /**
16353
16823
  * @ngdoc method
@@ -16441,10 +16911,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16441
16911
 
16442
16912
  this.$get = [
16443
16913
  '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
16444
- '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
16914
+ '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
16445
16915
  function($injector, $interpolate, $exceptionHandler, $templateRequest, $parse,
16446
- $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
16916
+ $controller, $rootScope, $sce, $animate, $$sanitizeUri) {
16447
16917
 
16918
+ var SIMPLE_ATTR_NAME = /^\w/;
16919
+ var specialAttrHolder = document.createElement('div');
16448
16920
  var Attributes = function(element, attributesToCopy) {
16449
16921
  if (attributesToCopy) {
16450
16922
  var keys = Object.keys(attributesToCopy);
@@ -16580,7 +17052,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16580
17052
 
16581
17053
  nodeName = nodeName_(this.$$element);
16582
17054
 
16583
- if ((nodeName === 'a' && key === 'href') ||
17055
+ if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
16584
17056
  (nodeName === 'img' && key === 'src')) {
16585
17057
  // sanitize a[href] and img[src] values
16586
17058
  this[key] = value = $$sanitizeUri(value, key === 'src');
@@ -16624,7 +17096,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16624
17096
  if (value === null || isUndefined(value)) {
16625
17097
  this.$$element.removeAttr(attrName);
16626
17098
  } else {
16627
- this.$$element.attr(attrName, value);
17099
+ if (SIMPLE_ATTR_NAME.test(attrName)) {
17100
+ this.$$element.attr(attrName, value);
17101
+ } else {
17102
+ setSpecialAttr(this.$$element[0], attrName, value);
17103
+ }
16628
17104
  }
16629
17105
  }
16630
17106
 
@@ -16655,7 +17131,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16655
17131
  * @param {string} key Normalized key. (ie ngAttribute) .
16656
17132
  * @param {function(interpolatedValue)} fn Function that will be called whenever
16657
17133
  the interpolated value of the attribute changes.
16658
- * See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
17134
+ * See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
17135
+ * guide} for more info.
16659
17136
  * @returns {function()} Returns a deregistration function for this observer.
16660
17137
  */
16661
17138
  $observe: function(key, fn) {
@@ -16677,6 +17154,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16677
17154
  }
16678
17155
  };
16679
17156
 
17157
+ function setSpecialAttr(element, attrName, value) {
17158
+ // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
17159
+ // so we have to jump through some hoops to get such an attribute
17160
+ // https://github.com/angular/angular.js/pull/13318
17161
+ specialAttrHolder.innerHTML = "<span " + attrName + ">";
17162
+ var attributes = specialAttrHolder.firstChild.attributes;
17163
+ var attribute = attributes[0];
17164
+ // We have to remove the attribute from its container element before we can add it to the destination element
17165
+ attributes.removeNamedItem(attribute.name);
17166
+ attribute.value = value;
17167
+ element.attributes.setNamedItem(attribute);
17168
+ }
16680
17169
 
16681
17170
  function safeAddClass($element, className) {
16682
17171
  try {
@@ -16690,7 +17179,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16690
17179
 
16691
17180
  var startSymbol = $interpolate.startSymbol(),
16692
17181
  endSymbol = $interpolate.endSymbol(),
16693
- denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
17182
+ denormalizeTemplate = (startSymbol == '{{' && endSymbol == '}}')
16694
17183
  ? identity
16695
17184
  : function denormalizeTemplate(template) {
16696
17185
  return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
@@ -16734,13 +17223,19 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16734
17223
  // modify it.
16735
17224
  $compileNodes = jqLite($compileNodes);
16736
17225
  }
17226
+
17227
+ var NOT_EMPTY = /\S+/;
17228
+
16737
17229
  // We can not compile top level text elements since text nodes can be merged and we will
16738
17230
  // not be able to attach scope data to them, so we will wrap them in <span>
16739
- forEach($compileNodes, function(node, index) {
16740
- if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
16741
- $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
17231
+ for (var i = 0, len = $compileNodes.length; i < len; i++) {
17232
+ var domNode = $compileNodes[i];
17233
+
17234
+ if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
17235
+ jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
16742
17236
  }
16743
- });
17237
+ }
17238
+
16744
17239
  var compositeLinkFn =
16745
17240
  compileNodes($compileNodes, transcludeFn, $compileNodes,
16746
17241
  maxPriority, ignoreDirective, previousCompileContext);
@@ -16811,7 +17306,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16811
17306
  if (!node) {
16812
17307
  return 'html';
16813
17308
  } else {
16814
- return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
17309
+ return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
16815
17310
  }
16816
17311
  }
16817
17312
 
@@ -16945,6 +17440,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16945
17440
  });
16946
17441
  };
16947
17442
 
17443
+ // We need to attach the transclusion slots onto the `boundTranscludeFn`
17444
+ // so that they are available inside the `controllersBoundTransclude` function
17445
+ var boundSlots = boundTranscludeFn.$$slots = createMap();
17446
+ for (var slotName in transcludeFn.$$slots) {
17447
+ if (transcludeFn.$$slots[slotName]) {
17448
+ boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
17449
+ } else {
17450
+ boundSlots[slotName] = null;
17451
+ }
17452
+ }
17453
+
16948
17454
  return boundTranscludeFn;
16949
17455
  }
16950
17456
 
@@ -17103,6 +17609,37 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17103
17609
  };
17104
17610
  }
17105
17611
 
17612
+ /**
17613
+ * A function generator that is used to support both eager and lazy compilation
17614
+ * linking function.
17615
+ * @param eager
17616
+ * @param $compileNodes
17617
+ * @param transcludeFn
17618
+ * @param maxPriority
17619
+ * @param ignoreDirective
17620
+ * @param previousCompileContext
17621
+ * @returns {Function}
17622
+ */
17623
+ function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
17624
+ if (eager) {
17625
+ return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17626
+ }
17627
+
17628
+ var compiled;
17629
+
17630
+ return function() {
17631
+ if (!compiled) {
17632
+ compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17633
+
17634
+ // Null out all of these references in order to make them eligible for garbage collection
17635
+ // since this is a potentially long lived closure
17636
+ $compileNodes = transcludeFn = previousCompileContext = null;
17637
+ }
17638
+
17639
+ return compiled.apply(this, arguments);
17640
+ };
17641
+ }
17642
+
17106
17643
  /**
17107
17644
  * Once the directives have been collected, their compile functions are executed. This method
17108
17645
  * is responsible for inlining directive templates as well as terminating the application
@@ -17147,6 +17684,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17147
17684
  replaceDirective = originalReplaceDirective,
17148
17685
  childTranscludeFn = transcludeFn,
17149
17686
  linkFn,
17687
+ didScanForMultipleTransclusion = false,
17688
+ mightHaveMultipleTransclusionError = false,
17150
17689
  directiveValue;
17151
17690
 
17152
17691
  // executes all directives on the current element
@@ -17189,6 +17728,27 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17189
17728
 
17190
17729
  directiveName = directive.name;
17191
17730
 
17731
+ // If we encounter a condition that can result in transclusion on the directive,
17732
+ // then scan ahead in the remaining directives for others that may cause a multiple
17733
+ // transclusion error to be thrown during the compilation process. If a matching directive
17734
+ // is found, then we know that when we encounter a transcluded directive, we need to eagerly
17735
+ // compile the `transclude` function rather than doing it lazily in order to throw
17736
+ // exceptions at the correct time
17737
+ if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
17738
+ || (directive.transclude && !directive.$$tlb))) {
17739
+ var candidateDirective;
17740
+
17741
+ for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
17742
+ if ((candidateDirective.transclude && !candidateDirective.$$tlb)
17743
+ || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
17744
+ mightHaveMultipleTransclusionError = true;
17745
+ break;
17746
+ }
17747
+ }
17748
+
17749
+ didScanForMultipleTransclusion = true;
17750
+ }
17751
+
17192
17752
  if (!directive.templateUrl && directive.controller) {
17193
17753
  directiveValue = directive.controller;
17194
17754
  controllerDirectives = controllerDirectives || createMap();
@@ -17218,7 +17778,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17218
17778
  compileNode = $compileNode[0];
17219
17779
  replaceWith(jqCollection, sliceArgs($template), compileNode);
17220
17780
 
17221
- childTranscludeFn = compile($template, transcludeFn, terminalPriority,
17781
+ childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
17222
17782
  replaceDirective && replaceDirective.name, {
17223
17783
  // Don't pass in:
17224
17784
  // - controllerDirectives - otherwise we'll create duplicates controllers
@@ -17230,10 +17790,69 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17230
17790
  nonTlbTranscludeDirective: nonTlbTranscludeDirective
17231
17791
  });
17232
17792
  } else {
17793
+
17794
+ var slots = createMap();
17795
+
17233
17796
  $template = jqLite(jqLiteClone(compileNode)).contents();
17797
+
17798
+ if (isObject(directiveValue)) {
17799
+
17800
+ // We have transclusion slots,
17801
+ // collect them up, compile them and store their transclusion functions
17802
+ $template = [];
17803
+
17804
+ var slotMap = createMap();
17805
+ var filledSlots = createMap();
17806
+
17807
+ // Parse the element selectors
17808
+ forEach(directiveValue, function(elementSelector, slotName) {
17809
+ // If an element selector starts with a ? then it is optional
17810
+ var optional = (elementSelector.charAt(0) === '?');
17811
+ elementSelector = optional ? elementSelector.substring(1) : elementSelector;
17812
+
17813
+ slotMap[elementSelector] = slotName;
17814
+
17815
+ // We explicitly assign `null` since this implies that a slot was defined but not filled.
17816
+ // Later when calling boundTransclusion functions with a slot name we only error if the
17817
+ // slot is `undefined`
17818
+ slots[slotName] = null;
17819
+
17820
+ // filledSlots contains `true` for all slots that are either optional or have been
17821
+ // filled. This is used to check that we have not missed any required slots
17822
+ filledSlots[slotName] = optional;
17823
+ });
17824
+
17825
+ // Add the matching elements into their slot
17826
+ forEach($compileNode.contents(), function(node) {
17827
+ var slotName = slotMap[directiveNormalize(nodeName_(node))];
17828
+ if (slotName) {
17829
+ filledSlots[slotName] = true;
17830
+ slots[slotName] = slots[slotName] || [];
17831
+ slots[slotName].push(node);
17832
+ } else {
17833
+ $template.push(node);
17834
+ }
17835
+ });
17836
+
17837
+ // Check for required slots that were not filled
17838
+ forEach(filledSlots, function(filled, slotName) {
17839
+ if (!filled) {
17840
+ throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
17841
+ }
17842
+ });
17843
+
17844
+ for (var slotName in slots) {
17845
+ if (slots[slotName]) {
17846
+ // Only define a transclusion function if the slot was filled
17847
+ slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
17848
+ }
17849
+ }
17850
+ }
17851
+
17234
17852
  $compileNode.empty(); // clear contents
17235
- childTranscludeFn = compile($template, transcludeFn, undefined,
17853
+ childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
17236
17854
  undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
17855
+ childTranscludeFn.$$slots = slots;
17237
17856
  }
17238
17857
  }
17239
17858
 
@@ -17396,6 +18015,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17396
18015
  for (var i = 0, ii = require.length; i < ii; i++) {
17397
18016
  value[i] = getControllers(directiveName, require[i], $element, elementControllers);
17398
18017
  }
18018
+ } else if (isObject(require)) {
18019
+ value = {};
18020
+ forEach(require, function(controller, property) {
18021
+ value[property] = getControllers(directiveName, controller, $element, elementControllers);
18022
+ });
17399
18023
  }
17400
18024
 
17401
18025
  return value || null;
@@ -17433,7 +18057,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17433
18057
  }
17434
18058
 
17435
18059
  function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
17436
- var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
18060
+ var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
17437
18061
  attrs, removeScopeBindingWatches, removeControllerBindingWatches;
17438
18062
 
17439
18063
  if (compileNode === linkNode) {
@@ -17456,6 +18080,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17456
18080
  // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
17457
18081
  transcludeFn = controllersBoundTransclude;
17458
18082
  transcludeFn.$$boundTransclude = boundTranscludeFn;
18083
+ // expose the slots on the `$transclude` function
18084
+ transcludeFn.isSlotFilled = function(slotName) {
18085
+ return !!boundTranscludeFn.$$slots[slotName];
18086
+ };
17459
18087
  }
17460
18088
 
17461
18089
  if (controllerDirectives) {
@@ -17500,6 +18128,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17500
18128
  }
17501
18129
  }
17502
18130
 
18131
+ // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
18132
+ forEach(controllerDirectives, function(controllerDirective, name) {
18133
+ var require = controllerDirective.require;
18134
+ if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
18135
+ extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
18136
+ }
18137
+ });
18138
+
18139
+ // Trigger the `$onInit` method on all controllers that have one
18140
+ forEach(elementControllers, function(controller) {
18141
+ if (isFunction(controller.instance.$onInit)) {
18142
+ controller.instance.$onInit();
18143
+ }
18144
+ });
18145
+
17503
18146
  // PRELINKING
17504
18147
  for (i = 0, ii = preLinkFns.length; i < ii; i++) {
17505
18148
  linkFn = preLinkFns[i];
@@ -17535,11 +18178,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17535
18178
 
17536
18179
  // This is the function that is injected as `$transclude`.
17537
18180
  // Note: all arguments are optional!
17538
- function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
18181
+ function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
17539
18182
  var transcludeControllers;
17540
-
17541
18183
  // No scope passed in:
17542
18184
  if (!isScope(scope)) {
18185
+ slotName = futureParentElement;
17543
18186
  futureParentElement = cloneAttachFn;
17544
18187
  cloneAttachFn = scope;
17545
18188
  scope = undefined;
@@ -17551,7 +18194,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17551
18194
  if (!futureParentElement) {
17552
18195
  futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
17553
18196
  }
17554
- return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18197
+ if (slotName) {
18198
+ // slotTranscludeFn can be one of three things:
18199
+ // * a transclude function - a filled slot
18200
+ // * `null` - an optional slot that was not filled
18201
+ // * `undefined` - a slot that was not declared (i.e. invalid)
18202
+ var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
18203
+ if (slotTranscludeFn) {
18204
+ return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18205
+ } else if (isUndefined(slotTranscludeFn)) {
18206
+ throw $compileMinErr('noslot',
18207
+ 'No parent directive that requires a transclusion with slot name "{0}". ' +
18208
+ 'Element: {1}',
18209
+ slotName, startingTag($element));
18210
+ }
18211
+ } else {
18212
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18213
+ }
17555
18214
  }
17556
18215
  }
17557
18216
  }
@@ -17983,9 +18642,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17983
18642
  parent.replaceChild(newNode, firstElementToRemove);
17984
18643
  }
17985
18644
 
17986
- // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
18645
+ // Append all the `elementsToRemove` to a fragment. This will...
18646
+ // - remove them from the DOM
18647
+ // - allow them to still be traversed with .nextSibling
18648
+ // - allow a single fragment.qSA to fetch all elements being removed
17987
18649
  var fragment = document.createDocumentFragment();
17988
- fragment.appendChild(firstElementToRemove);
18650
+ for (i = 0; i < removeCount; i++) {
18651
+ fragment.appendChild(elementsToRemove[i]);
18652
+ }
17989
18653
 
17990
18654
  if (jqLite.hasData(firstElementToRemove)) {
17991
18655
  // Copy over user data (that includes Angular's $scope etc.). Don't copy private
@@ -17993,31 +18657,18 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
17993
18657
  // event listeners (which is the main use of private data) wouldn't work anyway.
17994
18658
  jqLite.data(newNode, jqLite.data(firstElementToRemove));
17995
18659
 
17996
- // Remove data of the replaced element. We cannot just call .remove()
17997
- // on the element it since that would deallocate scope that is needed
17998
- // for the new node. Instead, remove the data "manually".
17999
- if (!jQuery) {
18000
- delete jqLite.cache[firstElementToRemove[jqLite.expando]];
18001
- } else {
18002
- // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
18003
- // the replaced element. The cleanData version monkey-patched by Angular would cause
18004
- // the scope to be trashed and we do need the very same scope to work with the new
18005
- // element. However, we cannot just cache the non-patched version and use it here as
18006
- // that would break if another library patches the method after Angular does (one
18007
- // example is jQuery UI). Instead, set a flag indicating scope destroying should be
18008
- // skipped this one time.
18009
- skipDestroyOnNextJQueryCleanData = true;
18010
- jQuery.cleanData([firstElementToRemove]);
18011
- }
18660
+ // Remove $destroy event listeners from `firstElementToRemove`
18661
+ jqLite(firstElementToRemove).off('$destroy');
18012
18662
  }
18013
18663
 
18014
- for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
18015
- var element = elementsToRemove[k];
18016
- jqLite(element).remove(); // must do this way to clean up expando
18017
- fragment.appendChild(element);
18018
- delete elementsToRemove[k];
18019
- }
18664
+ // Cleanup any data/listeners on the elements and children.
18665
+ // This includes invoking the $destroy event on any elements with listeners.
18666
+ jqLite.cleanData(fragment.querySelectorAll('*'));
18020
18667
 
18668
+ // Update the jqLite collection to only contain the `newNode`
18669
+ for (i = 1; i < removeCount; i++) {
18670
+ delete elementsToRemove[i];
18671
+ }
18021
18672
  elementsToRemove[0] = newNode;
18022
18673
  elementsToRemove.length = 1;
18023
18674
  }
@@ -18046,7 +18697,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18046
18697
  optional = definition.optional,
18047
18698
  mode = definition.mode, // @, =, or &
18048
18699
  lastValue,
18049
- parentGet, parentSet, compare;
18700
+ parentGet, parentSet, compare, removeWatch;
18050
18701
 
18051
18702
  switch (mode) {
18052
18703
 
@@ -18060,10 +18711,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18060
18711
  }
18061
18712
  });
18062
18713
  attrs.$$observers[attrName].$$scope = scope;
18063
- if (isString(attrs[attrName])) {
18714
+ lastValue = attrs[attrName];
18715
+ if (isString(lastValue)) {
18064
18716
  // If the attribute has been provided then we trigger an interpolation to ensure
18065
18717
  // the value is there for use in the link fn
18066
- destination[scopeName] = $interpolate(attrs[attrName])(scope);
18718
+ destination[scopeName] = $interpolate(lastValue)(scope);
18719
+ } else if (isBoolean(lastValue)) {
18720
+ // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
18721
+ // the value to boolean rather than a string, so we special case this situation
18722
+ destination[scopeName] = lastValue;
18067
18723
  }
18068
18724
  break;
18069
18725
 
@@ -18084,8 +18740,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18084
18740
  // reset the change, or we will throw this exception on every $digest
18085
18741
  lastValue = destination[scopeName] = parentGet(scope);
18086
18742
  throw $compileMinErr('nonassign',
18087
- "Expression '{0}' used with directive '{1}' is non-assignable!",
18088
- attrs[attrName], directive.name);
18743
+ "Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
18744
+ attrs[attrName], attrName, directive.name);
18089
18745
  };
18090
18746
  lastValue = destination[scopeName] = parentGet(scope);
18091
18747
  var parentValueWatch = function parentValueWatch(parentValue) {
@@ -18102,7 +18758,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18102
18758
  return lastValue = parentValue;
18103
18759
  };
18104
18760
  parentValueWatch.$stateful = true;
18105
- var removeWatch;
18106
18761
  if (definition.collection) {
18107
18762
  removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
18108
18763
  } else {
@@ -18111,6 +18766,24 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
18111
18766
  removeWatchCollection.push(removeWatch);
18112
18767
  break;
18113
18768
 
18769
+ case '<':
18770
+ if (!hasOwnProperty.call(attrs, attrName)) {
18771
+ if (optional) break;
18772
+ attrs[attrName] = void 0;
18773
+ }
18774
+ if (optional && !attrs[attrName]) break;
18775
+
18776
+ parentGet = $parse(attrs[attrName]);
18777
+
18778
+ destination[scopeName] = parentGet(scope);
18779
+
18780
+ removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
18781
+ destination[scopeName] = newParentValue;
18782
+ }, parentGet.literal);
18783
+
18784
+ removeWatchCollection.push(removeWatch);
18785
+ break;
18786
+
18114
18787
  case '&':
18115
18788
  // Don't assign Object.prototype method to scope
18116
18789
  parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
@@ -18239,7 +18912,7 @@ function removeComments(jqNodes) {
18239
18912
  var $controllerMinErr = minErr('$controller');
18240
18913
 
18241
18914
 
18242
- var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
18915
+ var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
18243
18916
  function identifierForController(controller, ident) {
18244
18917
  if (ident && isString(ident)) return ident;
18245
18918
  if (isString(controller)) {
@@ -19030,7 +19703,7 @@ function $HttpProvider() {
19030
19703
  *
19031
19704
  * ```
19032
19705
  * module.run(function($http) {
19033
- * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
19706
+ * $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
19034
19707
  * });
19035
19708
  * ```
19036
19709
  *
@@ -19258,13 +19931,13 @@ function $HttpProvider() {
19258
19931
  *
19259
19932
  * ### Cross Site Request Forgery (XSRF) Protection
19260
19933
  *
19261
- * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
19262
- * an unauthorized site can gain your user's private data. Angular provides a mechanism
19263
- * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
19264
- * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
19265
- * JavaScript that runs on your domain could read the cookie, your server can be assured that
19266
- * the XHR came from JavaScript running on your domain. The header will not be set for
19267
- * cross-domain requests.
19934
+ * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
19935
+ * which the attacker can trick an authenticated user into unknowingly executing actions on your
19936
+ * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
19937
+ * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
19938
+ * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
19939
+ * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
19940
+ * The header will not be set for cross-domain requests.
19268
19941
  *
19269
19942
  * To take advantage of this, your server needs to set a token in a JavaScript readable session
19270
19943
  * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
@@ -19423,10 +20096,14 @@ function $HttpProvider() {
19423
20096
  */
19424
20097
  function $http(requestConfig) {
19425
20098
 
19426
- if (!angular.isObject(requestConfig)) {
20099
+ if (!isObject(requestConfig)) {
19427
20100
  throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
19428
20101
  }
19429
20102
 
20103
+ if (!isString(requestConfig.url)) {
20104
+ throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);
20105
+ }
20106
+
19430
20107
  var config = extend({
19431
20108
  method: 'get',
19432
20109
  transformRequest: defaults.transformRequest,
@@ -19539,7 +20216,7 @@ function $HttpProvider() {
19539
20216
 
19540
20217
  defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
19541
20218
 
19542
- // using for-in instead of forEach to avoid unecessary iteration after header has been found
20219
+ // using for-in instead of forEach to avoid unnecessary iteration after header has been found
19543
20220
  defaultHeadersIteration:
19544
20221
  for (defHeaderName in defHeaders) {
19545
20222
  lowercaseDefHeaderName = lowercase(defHeaderName);
@@ -20038,8 +20715,16 @@ $interpolateMinErr.interr = function(text, err) {
20038
20715
  *
20039
20716
  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
20040
20717
  *
20718
+ * <div class="alert alert-danger">
20719
+ * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
20720
+ * template within a Python Jinja template (or any other template language). Mixing templating
20721
+ * languages is **very dangerous**. The embedding template language will not safely escape Angular
20722
+ * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
20723
+ * security bugs!
20724
+ * </div>
20725
+ *
20041
20726
  * @example
20042
- <example module="customInterpolationApp">
20727
+ <example name="custom-interpolation-markup" module="customInterpolationApp">
20043
20728
  <file name="index.html">
20044
20729
  <script>
20045
20730
  var customInterpolationApp = angular.module('customInterpolationApp', []);
@@ -20054,7 +20739,7 @@ $interpolateMinErr.interr = function(text, err) {
20054
20739
  this.label = "This binding is brought you by // interpolation symbols.";
20055
20740
  });
20056
20741
  </script>
20057
- <div ng-app="App" ng-controller="DemoController as demo">
20742
+ <div ng-controller="DemoController as demo">
20058
20743
  //demo.label//
20059
20744
  </div>
20060
20745
  </file>
@@ -20138,6 +20823,15 @@ function $InterpolateProvider() {
20138
20823
  return value;
20139
20824
  }
20140
20825
 
20826
+ //TODO: this is the same as the constantWatchDelegate in parse.js
20827
+ function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
20828
+ var unwatch;
20829
+ return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
20830
+ unwatch();
20831
+ return constantInterp(scope);
20832
+ }, listener, objectEquality);
20833
+ }
20834
+
20141
20835
  /**
20142
20836
  * @ngdoc service
20143
20837
  * @name $interpolate
@@ -20233,6 +20927,19 @@ function $InterpolateProvider() {
20233
20927
  * - `context`: evaluation context for all expressions embedded in the interpolated text
20234
20928
  */
20235
20929
  function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
20930
+ // Provide a quick exit and simplified result function for text with no interpolation
20931
+ if (!text.length || text.indexOf(startSymbol) === -1) {
20932
+ var constantInterp;
20933
+ if (!mustHaveExpression) {
20934
+ var unescapedText = unescapeText(text);
20935
+ constantInterp = valueFn(unescapedText);
20936
+ constantInterp.exp = text;
20937
+ constantInterp.expressions = [];
20938
+ constantInterp.$$watchDelegate = constantWatchDelegate;
20939
+ }
20940
+ return constantInterp;
20941
+ }
20942
+
20236
20943
  allOrNothing = !!allOrNothing;
20237
20944
  var startIndex,
20238
20945
  endIndex,
@@ -20369,8 +21076,8 @@ function $InterpolateProvider() {
20369
21076
  }
20370
21077
 
20371
21078
  function $IntervalProvider() {
20372
- this.$get = ['$rootScope', '$window', '$q', '$$q',
20373
- function($rootScope, $window, $q, $$q) {
21079
+ this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
21080
+ function($rootScope, $window, $q, $$q, $browser) {
20374
21081
  var intervals = {};
20375
21082
 
20376
21083
 
@@ -20511,11 +21218,12 @@ function $IntervalProvider() {
20511
21218
 
20512
21219
  count = isDefined(count) ? count : 0;
20513
21220
 
20514
- promise.then(null, null, (!hasParams) ? fn : function() {
20515
- fn.apply(null, args);
20516
- });
20517
-
20518
21221
  promise.$$intervalId = setInterval(function tick() {
21222
+ if (skipApply) {
21223
+ $browser.defer(callback);
21224
+ } else {
21225
+ $rootScope.$evalAsync(callback);
21226
+ }
20519
21227
  deferred.notify(iteration++);
20520
21228
 
20521
21229
  if (count > 0 && iteration >= count) {
@@ -20531,6 +21239,14 @@ function $IntervalProvider() {
20531
21239
  intervals[promise.$$intervalId] = deferred;
20532
21240
 
20533
21241
  return promise;
21242
+
21243
+ function callback() {
21244
+ if (!hasParams) {
21245
+ fn(iteration);
21246
+ } else {
21247
+ fn.apply(null, args);
21248
+ }
21249
+ }
20534
21250
  }
20535
21251
 
20536
21252
 
@@ -21770,23 +22486,22 @@ function ensureSafeMemberName(name, fullExpression) {
21770
22486
  return name;
21771
22487
  }
21772
22488
 
21773
- function getStringValue(name, fullExpression) {
21774
- // From the JavaScript docs:
22489
+ function getStringValue(name) {
21775
22490
  // Property names must be strings. This means that non-string objects cannot be used
21776
22491
  // as keys in an object. Any non-string object, including a number, is typecasted
21777
22492
  // into a string via the toString method.
22493
+ // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
21778
22494
  //
21779
- // So, to ensure that we are checking the same `name` that JavaScript would use,
21780
- // we cast it to a string, if possible.
21781
- // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
21782
- // this is, this will handle objects that misbehave.
21783
- name = name + '';
21784
- if (!isString(name)) {
21785
- throw $parseMinErr('iseccst',
21786
- 'Cannot convert object to primitive value! '
21787
- + 'Expression: {0}', fullExpression);
21788
- }
21789
- return name;
22495
+ // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
22496
+ // to a string. It's not always possible. If `name` is an object and its `toString` method is
22497
+ // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
22498
+ //
22499
+ // TypeError: Cannot convert object to primitive value
22500
+ //
22501
+ // For performance reasons, we don't catch this error here and allow it to propagate up the call
22502
+ // stack. Note that you'll get the same error in JavaScript if you try to access a property using
22503
+ // such a 'broken' object as a key.
22504
+ return name + '';
21790
22505
  }
21791
22506
 
21792
22507
  function ensureSafeObject(obj, fullExpression) {
@@ -22047,6 +22762,7 @@ AST.ArrayExpression = 'ArrayExpression';
22047
22762
  AST.Property = 'Property';
22048
22763
  AST.ObjectExpression = 'ObjectExpression';
22049
22764
  AST.ThisExpression = 'ThisExpression';
22765
+ AST.LocalsExpression = 'LocalsExpression';
22050
22766
 
22051
22767
  // Internal use only
22052
22768
  AST.NGValueParameter = 'NGValueParameter';
@@ -22347,7 +23063,8 @@ AST.prototype = {
22347
23063
  'false': { type: AST.Literal, value: false },
22348
23064
  'null': { type: AST.Literal, value: null },
22349
23065
  'undefined': {type: AST.Literal, value: undefined },
22350
- 'this': {type: AST.ThisExpression }
23066
+ 'this': {type: AST.ThisExpression },
23067
+ '$locals': {type: AST.LocalsExpression }
22351
23068
  }
22352
23069
  };
22353
23070
 
@@ -22467,6 +23184,10 @@ function findConstantAndWatchExpressions(ast, $filter) {
22467
23184
  ast.constant = false;
22468
23185
  ast.toWatch = [];
22469
23186
  break;
23187
+ case AST.LocalsExpression:
23188
+ ast.constant = false;
23189
+ ast.toWatch = [];
23190
+ break;
22470
23191
  }
22471
23192
  }
22472
23193
 
@@ -22710,6 +23431,9 @@ ASTCompiler.prototype = {
22710
23431
  intoId = intoId || this.nextId();
22711
23432
  self.recurse(ast.object, left, undefined, function() {
22712
23433
  self.if_(self.notNull(left), function() {
23434
+ if (create && create !== 1) {
23435
+ self.addEnsureSafeAssignContext(left);
23436
+ }
22713
23437
  if (ast.computed) {
22714
23438
  right = self.nextId();
22715
23439
  self.recurse(ast.property, right);
@@ -22791,7 +23515,7 @@ ASTCompiler.prototype = {
22791
23515
  right = this.nextId();
22792
23516
  left = {};
22793
23517
  if (!isAssignable(ast.left)) {
22794
- throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
23518
+ throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
22795
23519
  }
22796
23520
  this.recurse(ast.left, undefined, left, function() {
22797
23521
  self.if_(self.notNull(left.context), function() {
@@ -22833,6 +23557,10 @@ ASTCompiler.prototype = {
22833
23557
  this.assign(intoId, 's');
22834
23558
  recursionFn('s');
22835
23559
  break;
23560
+ case AST.LocalsExpression:
23561
+ this.assign(intoId, 'l');
23562
+ recursionFn('l');
23563
+ break;
22836
23564
  case AST.NGValueParameter:
22837
23565
  this.assign(intoId, 'v');
22838
23566
  recursionFn('v');
@@ -22940,7 +23668,7 @@ ASTCompiler.prototype = {
22940
23668
  },
22941
23669
 
22942
23670
  getStringValue: function(item) {
22943
- this.assign(item, 'getStringValue(' + item + ',text)');
23671
+ this.assign(item, 'getStringValue(' + item + ')');
22944
23672
  },
22945
23673
 
22946
23674
  ensureSafeAssignContext: function(item) {
@@ -23160,6 +23888,10 @@ ASTInterpreter.prototype = {
23160
23888
  return function(scope) {
23161
23889
  return context ? {value: scope} : scope;
23162
23890
  };
23891
+ case AST.LocalsExpression:
23892
+ return function(scope, locals) {
23893
+ return context ? {value: locals} : locals;
23894
+ };
23163
23895
  case AST.NGValueParameter:
23164
23896
  return function(scope, locals, assign, inputs) {
23165
23897
  return context ? {value: assign} : assign;
@@ -23324,8 +24056,11 @@ ASTInterpreter.prototype = {
23324
24056
  rhs = right(scope, locals, assign, inputs);
23325
24057
  rhs = getStringValue(rhs);
23326
24058
  ensureSafeMemberName(rhs, expression);
23327
- if (create && create !== 1 && lhs && !(lhs[rhs])) {
23328
- lhs[rhs] = {};
24059
+ if (create && create !== 1) {
24060
+ ensureSafeAssignContext(lhs);
24061
+ if (lhs && !(lhs[rhs])) {
24062
+ lhs[rhs] = {};
24063
+ }
23329
24064
  }
23330
24065
  value = lhs[rhs];
23331
24066
  ensureSafeObject(value, expression);
@@ -23340,8 +24075,11 @@ ASTInterpreter.prototype = {
23340
24075
  nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
23341
24076
  return function(scope, locals, assign, inputs) {
23342
24077
  var lhs = left(scope, locals, assign, inputs);
23343
- if (create && create !== 1 && lhs && !(lhs[right])) {
23344
- lhs[right] = {};
24078
+ if (create && create !== 1) {
24079
+ ensureSafeAssignContext(lhs);
24080
+ if (lhs && !(lhs[right])) {
24081
+ lhs[right] = {};
24082
+ }
23345
24083
  }
23346
24084
  var value = lhs != null ? lhs[right] : undefined;
23347
24085
  if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
@@ -23382,9 +24120,6 @@ Parser.prototype = {
23382
24120
  }
23383
24121
  };
23384
24122
 
23385
- var getterFnCacheDefault = createMap();
23386
- var getterFnCacheExpensive = createMap();
23387
-
23388
24123
  function isPossiblyDangerousMemberName(name) {
23389
24124
  return name == 'constructor';
23390
24125
  }
@@ -23460,10 +24195,19 @@ function $ParseProvider() {
23460
24195
  csp: noUnsafeEval,
23461
24196
  expensiveChecks: true
23462
24197
  };
24198
+ var runningChecksEnabled = false;
24199
+
24200
+ $parse.$$runningExpensiveChecks = function() {
24201
+ return runningChecksEnabled;
24202
+ };
24203
+
24204
+ return $parse;
23463
24205
 
23464
- return function $parse(exp, interceptorFn, expensiveChecks) {
24206
+ function $parse(exp, interceptorFn, expensiveChecks) {
23465
24207
  var parsedExpression, oneTime, cacheKey;
23466
24208
 
24209
+ expensiveChecks = expensiveChecks || runningChecksEnabled;
24210
+
23467
24211
  switch (typeof exp) {
23468
24212
  case 'string':
23469
24213
  exp = exp.trim();
@@ -23489,6 +24233,9 @@ function $ParseProvider() {
23489
24233
  } else if (parsedExpression.inputs) {
23490
24234
  parsedExpression.$$watchDelegate = inputsWatchDelegate;
23491
24235
  }
24236
+ if (expensiveChecks) {
24237
+ parsedExpression = expensiveChecksInterceptor(parsedExpression);
24238
+ }
23492
24239
  cache[cacheKey] = parsedExpression;
23493
24240
  }
23494
24241
  return addInterceptor(parsedExpression, interceptorFn);
@@ -23497,9 +24244,33 @@ function $ParseProvider() {
23497
24244
  return addInterceptor(exp, interceptorFn);
23498
24245
 
23499
24246
  default:
23500
- return noop;
24247
+ return addInterceptor(noop, interceptorFn);
23501
24248
  }
23502
- };
24249
+ }
24250
+
24251
+ function expensiveChecksInterceptor(fn) {
24252
+ if (!fn) return fn;
24253
+ expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
24254
+ expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
24255
+ expensiveCheckFn.constant = fn.constant;
24256
+ expensiveCheckFn.literal = fn.literal;
24257
+ for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
24258
+ fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
24259
+ }
24260
+ expensiveCheckFn.inputs = fn.inputs;
24261
+
24262
+ return expensiveCheckFn;
24263
+
24264
+ function expensiveCheckFn(scope, locals, assign, inputs) {
24265
+ var expensiveCheckOldValue = runningChecksEnabled;
24266
+ runningChecksEnabled = true;
24267
+ try {
24268
+ return fn(scope, locals, assign, inputs);
24269
+ } finally {
24270
+ runningChecksEnabled = expensiveCheckOldValue;
24271
+ }
24272
+ }
24273
+ }
23503
24274
 
23504
24275
  function expressionInputDirtyCheck(newValue, oldValueOfValue) {
23505
24276
 
@@ -23616,13 +24387,9 @@ function $ParseProvider() {
23616
24387
  function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
23617
24388
  var unwatch;
23618
24389
  return unwatch = scope.$watch(function constantWatch(scope) {
23619
- return parsedExpression(scope);
23620
- }, function constantListener(value, old, scope) {
23621
- if (isFunction(listener)) {
23622
- listener.apply(this, arguments);
23623
- }
23624
24390
  unwatch();
23625
- }, objectEquality);
24391
+ return parsedExpression(scope);
24392
+ }, listener, objectEquality);
23626
24393
  }
23627
24394
 
23628
24395
  function addInterceptor(parsedExpression, interceptorFn) {
@@ -23715,7 +24482,7 @@ function $ParseProvider() {
23715
24482
  *
23716
24483
  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
23717
24484
  *
23718
- * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
24485
+ * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
23719
24486
  *
23720
24487
  * However, the more traditional CommonJS-style usage is still available, and documented below.
23721
24488
  *
@@ -23905,18 +24672,6 @@ function $$QProvider() {
23905
24672
  */
23906
24673
  function qFactory(nextTick, exceptionHandler) {
23907
24674
  var $qMinErr = minErr('$q', TypeError);
23908
- function callOnce(self, resolveFn, rejectFn) {
23909
- var called = false;
23910
- function wrap(fn) {
23911
- return function(value) {
23912
- if (called) return;
23913
- called = true;
23914
- fn.call(self, value);
23915
- };
23916
- }
23917
-
23918
- return [wrap(resolveFn), wrap(rejectFn)];
23919
- }
23920
24675
 
23921
24676
  /**
23922
24677
  * @ngdoc method
@@ -23929,7 +24684,12 @@ function qFactory(nextTick, exceptionHandler) {
23929
24684
  * @returns {Deferred} Returns a new instance of deferred.
23930
24685
  */
23931
24686
  var defer = function() {
23932
- return new Deferred();
24687
+ var d = new Deferred();
24688
+ //Necessary to support unbound execution :/
24689
+ d.resolve = simpleBind(d, d.resolve);
24690
+ d.reject = simpleBind(d, d.reject);
24691
+ d.notify = simpleBind(d, d.notify);
24692
+ return d;
23933
24693
  };
23934
24694
 
23935
24695
  function Promise() {
@@ -24002,10 +24762,6 @@ function qFactory(nextTick, exceptionHandler) {
24002
24762
 
24003
24763
  function Deferred() {
24004
24764
  this.promise = new Promise();
24005
- //Necessary to support unbound execution :/
24006
- this.resolve = simpleBind(this, this.resolve);
24007
- this.reject = simpleBind(this, this.reject);
24008
- this.notify = simpleBind(this, this.notify);
24009
24765
  }
24010
24766
 
24011
24767
  extend(Deferred.prototype, {
@@ -24023,23 +24779,34 @@ function qFactory(nextTick, exceptionHandler) {
24023
24779
  },
24024
24780
 
24025
24781
  $$resolve: function(val) {
24026
- var then, fns;
24027
-
24028
- fns = callOnce(this, this.$$resolve, this.$$reject);
24782
+ var then;
24783
+ var that = this;
24784
+ var done = false;
24029
24785
  try {
24030
24786
  if ((isObject(val) || isFunction(val))) then = val && val.then;
24031
24787
  if (isFunction(then)) {
24032
24788
  this.promise.$$state.status = -1;
24033
- then.call(val, fns[0], fns[1], this.notify);
24789
+ then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
24034
24790
  } else {
24035
24791
  this.promise.$$state.value = val;
24036
24792
  this.promise.$$state.status = 1;
24037
24793
  scheduleProcessQueue(this.promise.$$state);
24038
24794
  }
24039
24795
  } catch (e) {
24040
- fns[1](e);
24796
+ rejectPromise(e);
24041
24797
  exceptionHandler(e);
24042
24798
  }
24799
+
24800
+ function resolvePromise(val) {
24801
+ if (done) return;
24802
+ done = true;
24803
+ that.$$resolve(val);
24804
+ }
24805
+ function rejectPromise(val) {
24806
+ if (done) return;
24807
+ done = true;
24808
+ that.$$reject(val);
24809
+ }
24043
24810
  },
24044
24811
 
24045
24812
  reject: function(reason) {
@@ -24228,11 +24995,6 @@ function qFactory(nextTick, exceptionHandler) {
24228
24995
  throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
24229
24996
  }
24230
24997
 
24231
- if (!(this instanceof Q)) {
24232
- // More useful when $Q is the Promise itself.
24233
- return new Q(resolver);
24234
- }
24235
-
24236
24998
  var deferred = new Deferred();
24237
24999
 
24238
25000
  function resolveFn(value) {
@@ -24248,6 +25010,10 @@ function qFactory(nextTick, exceptionHandler) {
24248
25010
  return deferred.promise;
24249
25011
  };
24250
25012
 
25013
+ // Let's make the instanceof operator work for promises, so that
25014
+ // `new $q(fn) instanceof $q` would evaluate to true.
25015
+ $Q.prototype = Promise.prototype;
25016
+
24251
25017
  $Q.defer = defer;
24252
25018
  $Q.reject = reject;
24253
25019
  $Q.when = when;
@@ -24381,8 +25147,8 @@ function $RootScopeProvider() {
24381
25147
  return ChildScope;
24382
25148
  }
24383
25149
 
24384
- this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
24385
- function($injector, $exceptionHandler, $parse, $browser) {
25150
+ this.$get = ['$exceptionHandler', '$parse', '$browser',
25151
+ function($exceptionHandler, $parse, $browser) {
24386
25152
 
24387
25153
  function destroyChildScope($event) {
24388
25154
  $event.currentScope.$$destroyed = true;
@@ -24666,7 +25432,7 @@ function $RootScopeProvider() {
24666
25432
  * - `newVal` contains the current value of the `watchExpression`
24667
25433
  * - `oldVal` contains the previous value of the `watchExpression`
24668
25434
  * - `scope` refers to the current scope
24669
- * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
25435
+ * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
24670
25436
  * comparing for reference equality.
24671
25437
  * @returns {function()} Returns a deregistration function for this listener.
24672
25438
  */
@@ -25031,7 +25797,7 @@ function $RootScopeProvider() {
25031
25797
  *
25032
25798
  */
25033
25799
  $digest: function() {
25034
- var watch, value, last,
25800
+ var watch, value, last, fn, get,
25035
25801
  watchers,
25036
25802
  length,
25037
25803
  dirty, ttl = TTL,
@@ -25077,7 +25843,8 @@ function $RootScopeProvider() {
25077
25843
  // Most common watches are on primitives, in which case we can short
25078
25844
  // circuit it with === operator, only when === fails do we use .equals
25079
25845
  if (watch) {
25080
- if ((value = watch.get(current)) !== (last = watch.last) &&
25846
+ get = watch.get;
25847
+ if ((value = get(current)) !== (last = watch.last) &&
25081
25848
  !(watch.eq
25082
25849
  ? equals(value, last)
25083
25850
  : (typeof value === 'number' && typeof last === 'number'
@@ -25085,7 +25852,8 @@ function $RootScopeProvider() {
25085
25852
  dirty = true;
25086
25853
  lastDirtyWatch = watch;
25087
25854
  watch.last = watch.eq ? copy(value, null) : value;
25088
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
25855
+ fn = watch.fn;
25856
+ fn(value, ((last === initWatchVal) ? value : last), current);
25089
25857
  if (ttl < 5) {
25090
25858
  logIdx = 4 - ttl;
25091
25859
  if (!watchLog[logIdx]) watchLog[logIdx] = [];
@@ -25285,7 +26053,7 @@ function $RootScopeProvider() {
25285
26053
  });
25286
26054
  }
25287
26055
 
25288
- asyncQueue.push({scope: this, expression: expr, locals: locals});
26056
+ asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
25289
26057
  },
25290
26058
 
25291
26059
  $$postDigest: function(fn) {
@@ -25377,6 +26145,7 @@ function $RootScopeProvider() {
25377
26145
  $applyAsync: function(expr) {
25378
26146
  var scope = this;
25379
26147
  expr && applyAsyncQueue.push($applyAsyncExpression);
26148
+ expr = $parse(expr);
25380
26149
  scheduleApplyAsync();
25381
26150
 
25382
26151
  function $applyAsyncExpression() {
@@ -25651,6 +26420,21 @@ function $RootScopeProvider() {
25651
26420
  }];
25652
26421
  }
25653
26422
 
26423
+ /**
26424
+ * @ngdoc service
26425
+ * @name $rootElement
26426
+ *
26427
+ * @description
26428
+ * The root element of Angular application. This is either the element where {@link
26429
+ * ng.directive:ngApp ngApp} was declared or the element passed into
26430
+ * {@link angular.bootstrap}. The element represents the root element of application. It is also the
26431
+ * location where the application's {@link auto.$injector $injector} service gets
26432
+ * published, and can be retrieved using `$rootElement.injector()`.
26433
+ */
26434
+
26435
+
26436
+ // the implementation is in angular.bootstrap
26437
+
25654
26438
  /**
25655
26439
  * @description
25656
26440
  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
@@ -25865,13 +26649,15 @@ function $SceDelegateProvider() {
25865
26649
  * @kind function
25866
26650
  *
25867
26651
  * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
25868
- * provided. This must be an array or null. A snapshot of this array is used so further
25869
- * changes to the array are ignored.
26652
+ * provided. This must be an array or null. A snapshot of this array is used so further
26653
+ * changes to the array are ignored.
25870
26654
  *
25871
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
25872
- * allowed in this array.
26655
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
26656
+ * allowed in this array.
25873
26657
  *
25874
- * Note: **an empty whitelist array will block all URLs**!
26658
+ * <div class="alert alert-warning">
26659
+ * **Note:** an empty whitelist array will block all URLs!
26660
+ * </div>
25875
26661
  *
25876
26662
  * @return {Array} the currently set whitelist array.
25877
26663
  *
@@ -25894,17 +26680,17 @@ function $SceDelegateProvider() {
25894
26680
  * @kind function
25895
26681
  *
25896
26682
  * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
25897
- * provided. This must be an array or null. A snapshot of this array is used so further
25898
- * changes to the array are ignored.
26683
+ * provided. This must be an array or null. A snapshot of this array is used so further
26684
+ * changes to the array are ignored.
25899
26685
  *
25900
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
25901
- * allowed in this array.
26686
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
26687
+ * allowed in this array.
25902
26688
  *
25903
- * The typical usage for the blacklist is to **block
25904
- * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
25905
- * these would otherwise be trusted but actually return content from the redirected domain.
26689
+ * The typical usage for the blacklist is to **block
26690
+ * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
26691
+ * these would otherwise be trusted but actually return content from the redirected domain.
25906
26692
  *
25907
- * Finally, **the blacklist overrides the whitelist** and has the final say.
26693
+ * Finally, **the blacklist overrides the whitelist** and has the final say.
25908
26694
  *
25909
26695
  * @return {Array} the currently set blacklist array.
25910
26696
  *
@@ -26063,6 +26849,11 @@ function $SceDelegateProvider() {
26063
26849
  * returns the originally supplied value if the queried context type is a supertype of the
26064
26850
  * created type. If this condition isn't satisfied, throws an exception.
26065
26851
  *
26852
+ * <div class="alert alert-danger">
26853
+ * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
26854
+ * (XSS) vulnerability in your application.
26855
+ * </div>
26856
+ *
26066
26857
  * @param {string} type The kind of context in which this value is to be used.
26067
26858
  * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
26068
26859
  * `$sceDelegate.trustAs`} call.
@@ -26870,26 +27661,63 @@ function $SnifferProvider() {
26870
27661
  var $compileMinErr = minErr('$compile');
26871
27662
 
26872
27663
  /**
26873
- * @ngdoc service
26874
- * @name $templateRequest
26875
- *
27664
+ * @ngdoc provider
27665
+ * @name $templateRequestProvider
26876
27666
  * @description
26877
- * The `$templateRequest` service runs security checks then downloads the provided template using
26878
- * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
26879
- * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
26880
- * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
26881
- * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
26882
- * when `tpl` is of type string and `$templateCache` has the matching entry.
26883
- *
26884
- * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
26885
- * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
27667
+ * Used to configure the options passed to the {@link $http} service when making a template request.
26886
27668
  *
26887
- * @return {Promise} a promise for the HTTP response data of the given URL.
26888
- *
26889
- * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
27669
+ * For example, it can be used for specifying the "Accept" header that is sent to the server, when
27670
+ * requesting a template.
26890
27671
  */
26891
27672
  function $TemplateRequestProvider() {
27673
+
27674
+ var httpOptions;
27675
+
27676
+ /**
27677
+ * @ngdoc method
27678
+ * @name $templateRequestProvider#httpOptions
27679
+ * @description
27680
+ * The options to be passed to the {@link $http} service when making the request.
27681
+ * You can use this to override options such as the "Accept" header for template requests.
27682
+ *
27683
+ * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
27684
+ * options if not overridden here.
27685
+ *
27686
+ * @param {string=} value new value for the {@link $http} options.
27687
+ * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
27688
+ */
27689
+ this.httpOptions = function(val) {
27690
+ if (val) {
27691
+ httpOptions = val;
27692
+ return this;
27693
+ }
27694
+ return httpOptions;
27695
+ };
27696
+
27697
+ /**
27698
+ * @ngdoc service
27699
+ * @name $templateRequest
27700
+ *
27701
+ * @description
27702
+ * The `$templateRequest` service runs security checks then downloads the provided template using
27703
+ * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
27704
+ * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
27705
+ * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
27706
+ * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
27707
+ * when `tpl` is of type string and `$templateCache` has the matching entry.
27708
+ *
27709
+ * If you want to pass custom options to the `$http` service, such as setting the Accept header you
27710
+ * can configure this via {@link $templateRequestProvider#httpOptions}.
27711
+ *
27712
+ * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
27713
+ * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
27714
+ *
27715
+ * @return {Promise} a promise for the HTTP response data of the given URL.
27716
+ *
27717
+ * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
27718
+ */
26892
27719
  this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
27720
+
26893
27721
  function handleRequestFn(tpl, ignoreRequestError) {
26894
27722
  handleRequestFn.totalPendingRequests++;
26895
27723
 
@@ -26912,12 +27740,10 @@ function $TemplateRequestProvider() {
26912
27740
  transformResponse = null;
26913
27741
  }
26914
27742
 
26915
- var httpOptions = {
26916
- cache: $templateCache,
26917
- transformResponse: transformResponse
26918
- };
26919
-
26920
- return $http.get(tpl, httpOptions)
27743
+ return $http.get(tpl, extend({
27744
+ cache: $templateCache,
27745
+ transformResponse: transformResponse
27746
+ }, httpOptions))
26921
27747
  ['finally'](function() {
26922
27748
  handleRequestFn.totalPendingRequests--;
26923
27749
  })
@@ -27088,8 +27914,8 @@ function $TimeoutProvider() {
27088
27914
  * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
27089
27915
  * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
27090
27916
  * @param {...*=} Pass additional parameters to the executed function.
27091
- * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
27092
- * promise will be resolved with is the return value of the `fn` function.
27917
+ * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
27918
+ * will be resolved with the return value of the `fn` function.
27093
27919
  *
27094
27920
  */
27095
27921
  function timeout(fn, delay, invokeApply) {
@@ -27765,6 +28591,10 @@ function getTypeForFilter(val) {
27765
28591
  return (val === null) ? 'null' : typeof val;
27766
28592
  }
27767
28593
 
28594
+ var MAX_DIGITS = 22;
28595
+ var DECIMAL_SEP = '.';
28596
+ var ZERO_CHAR = '0';
28597
+
27768
28598
  /**
27769
28599
  * @ngdoc filter
27770
28600
  * @name currency
@@ -27854,7 +28684,7 @@ function currencyFilter($locale) {
27854
28684
  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
27855
28685
  * If this is not provided then the fraction size is computed from the current locale's number
27856
28686
  * formatting pattern. In the case of the default locale, it will be 3.
27857
- * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
28687
+ * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
27858
28688
  *
27859
28689
  * @example
27860
28690
  <example module="numberFilterExample">
@@ -27889,8 +28719,6 @@ function currencyFilter($locale) {
27889
28719
  </file>
27890
28720
  </example>
27891
28721
  */
27892
-
27893
-
27894
28722
  numberFilter.$inject = ['$locale'];
27895
28723
  function numberFilter($locale) {
27896
28724
  var formats = $locale.NUMBER_FORMATS;
@@ -27904,93 +28732,194 @@ function numberFilter($locale) {
27904
28732
  };
27905
28733
  }
27906
28734
 
27907
- var DECIMAL_SEP = '.';
27908
- function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
27909
- if (isObject(number)) return '';
28735
+ /**
28736
+ * Parse a number (as a string) into three components that can be used
28737
+ * for formatting the number.
28738
+ *
28739
+ * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
28740
+ *
28741
+ * @param {string} numStr The number to parse
28742
+ * @return {object} An object describing this number, containing the following keys:
28743
+ * - d : an array of digits containing leading zeros as necessary
28744
+ * - i : the number of the digits in `d` that are to the left of the decimal point
28745
+ * - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
28746
+ *
28747
+ */
28748
+ function parse(numStr) {
28749
+ var exponent = 0, digits, numberOfIntegerDigits;
28750
+ var i, j, zeros;
27910
28751
 
27911
- var isNegative = number < 0;
27912
- number = Math.abs(number);
28752
+ // Decimal point?
28753
+ if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
28754
+ numStr = numStr.replace(DECIMAL_SEP, '');
28755
+ }
27913
28756
 
27914
- var isInfinity = number === Infinity;
27915
- if (!isInfinity && !isFinite(number)) return '';
28757
+ // Exponential form?
28758
+ if ((i = numStr.search(/e/i)) > 0) {
28759
+ // Work out the exponent.
28760
+ if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
28761
+ numberOfIntegerDigits += +numStr.slice(i + 1);
28762
+ numStr = numStr.substring(0, i);
28763
+ } else if (numberOfIntegerDigits < 0) {
28764
+ // There was no decimal point or exponent so it is an integer.
28765
+ numberOfIntegerDigits = numStr.length;
28766
+ }
27916
28767
 
27917
- var numStr = number + '',
27918
- formatedText = '',
27919
- hasExponent = false,
27920
- parts = [];
28768
+ // Count the number of leading zeros.
28769
+ for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++);
27921
28770
 
27922
- if (isInfinity) formatedText = '\u221e';
28771
+ if (i == (zeros = numStr.length)) {
28772
+ // The digits are all zero.
28773
+ digits = [0];
28774
+ numberOfIntegerDigits = 1;
28775
+ } else {
28776
+ // Count the number of trailing zeros
28777
+ zeros--;
28778
+ while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
27923
28779
 
27924
- if (!isInfinity && numStr.indexOf('e') !== -1) {
27925
- var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
27926
- if (match && match[2] == '-' && match[3] > fractionSize + 1) {
27927
- number = 0;
27928
- } else {
27929
- formatedText = numStr;
27930
- hasExponent = true;
28780
+ // Trailing zeros are insignificant so ignore them
28781
+ numberOfIntegerDigits -= i;
28782
+ digits = [];
28783
+ // Convert string to array of digits without leading/trailing zeros.
28784
+ for (j = 0; i <= zeros; i++, j++) {
28785
+ digits[j] = +numStr.charAt(i);
27931
28786
  }
27932
28787
  }
27933
28788
 
27934
- if (!isInfinity && !hasExponent) {
27935
- var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
28789
+ // If the number overflows the maximum allowed digits then use an exponent.
28790
+ if (numberOfIntegerDigits > MAX_DIGITS) {
28791
+ digits = digits.splice(0, MAX_DIGITS - 1);
28792
+ exponent = numberOfIntegerDigits - 1;
28793
+ numberOfIntegerDigits = 1;
28794
+ }
27936
28795
 
27937
- // determine fractionSize if it is not specified
27938
- if (isUndefined(fractionSize)) {
27939
- fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
28796
+ return { d: digits, e: exponent, i: numberOfIntegerDigits };
28797
+ }
28798
+
28799
+ /**
28800
+ * Round the parsed number to the specified number of decimal places
28801
+ * This function changed the parsedNumber in-place
28802
+ */
28803
+ function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
28804
+ var digits = parsedNumber.d;
28805
+ var fractionLen = digits.length - parsedNumber.i;
28806
+
28807
+ // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
28808
+ fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
28809
+
28810
+ // The index of the digit to where rounding is to occur
28811
+ var roundAt = fractionSize + parsedNumber.i;
28812
+ var digit = digits[roundAt];
28813
+
28814
+ if (roundAt > 0) {
28815
+ digits.splice(roundAt);
28816
+ } else {
28817
+ // We rounded to zero so reset the parsedNumber
28818
+ parsedNumber.i = 1;
28819
+ digits.length = roundAt = fractionSize + 1;
28820
+ for (var i=0; i < roundAt; i++) digits[i] = 0;
27940
28821
  }
27941
28822
 
27942
- // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
27943
- // inspired by:
27944
- // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
27945
- number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
28823
+ if (digit >= 5) digits[roundAt - 1]++;
27946
28824
 
27947
- var fraction = ('' + number).split(DECIMAL_SEP);
27948
- var whole = fraction[0];
27949
- fraction = fraction[1] || '';
28825
+ // Pad out with zeros to get the required fraction length
28826
+ for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
27950
28827
 
27951
- var i, pos = 0,
27952
- lgroup = pattern.lgSize,
27953
- group = pattern.gSize;
27954
28828
 
27955
- if (whole.length >= (lgroup + group)) {
27956
- pos = whole.length - lgroup;
27957
- for (i = 0; i < pos; i++) {
27958
- if ((pos - i) % group === 0 && i !== 0) {
27959
- formatedText += groupSep;
27960
- }
27961
- formatedText += whole.charAt(i);
27962
- }
28829
+ // Do any carrying, e.g. a digit was rounded up to 10
28830
+ var carry = digits.reduceRight(function(carry, d, i, digits) {
28831
+ d = d + carry;
28832
+ digits[i] = d % 10;
28833
+ return Math.floor(d / 10);
28834
+ }, 0);
28835
+ if (carry) {
28836
+ digits.unshift(carry);
28837
+ parsedNumber.i++;
27963
28838
  }
28839
+ }
27964
28840
 
27965
- for (i = pos; i < whole.length; i++) {
27966
- if ((whole.length - i) % lgroup === 0 && i !== 0) {
27967
- formatedText += groupSep;
27968
- }
27969
- formatedText += whole.charAt(i);
28841
+ /**
28842
+ * Format a number into a string
28843
+ * @param {number} number The number to format
28844
+ * @param {{
28845
+ * minFrac, // the minimum number of digits required in the fraction part of the number
28846
+ * maxFrac, // the maximum number of digits required in the fraction part of the number
28847
+ * gSize, // number of digits in each group of separated digits
28848
+ * lgSize, // number of digits in the last group of digits before the decimal separator
28849
+ * negPre, // the string to go in front of a negative number (e.g. `-` or `(`))
28850
+ * posPre, // the string to go in front of a positive number
28851
+ * negSuf, // the string to go after a negative number (e.g. `)`)
28852
+ * posSuf // the string to go after a positive number
28853
+ * }} pattern
28854
+ * @param {string} groupSep The string to separate groups of number (e.g. `,`)
28855
+ * @param {string} decimalSep The string to act as the decimal separator (e.g. `.`)
28856
+ * @param {[type]} fractionSize The size of the fractional part of the number
28857
+ * @return {string} The number formatted as a string
28858
+ */
28859
+ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
28860
+
28861
+ if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
28862
+
28863
+ var isInfinity = !isFinite(number);
28864
+ var isZero = false;
28865
+ var numStr = Math.abs(number) + '',
28866
+ formattedText = '',
28867
+ parsedNumber;
28868
+
28869
+ if (isInfinity) {
28870
+ formattedText = '\u221e';
28871
+ } else {
28872
+ parsedNumber = parse(numStr);
28873
+
28874
+ roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
28875
+
28876
+ var digits = parsedNumber.d;
28877
+ var integerLen = parsedNumber.i;
28878
+ var exponent = parsedNumber.e;
28879
+ var decimals = [];
28880
+ isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
28881
+
28882
+ // pad zeros for small numbers
28883
+ while (integerLen < 0) {
28884
+ digits.unshift(0);
28885
+ integerLen++;
27970
28886
  }
27971
28887
 
27972
- // format fraction part.
27973
- while (fraction.length < fractionSize) {
27974
- fraction += '0';
28888
+ // extract decimals digits
28889
+ if (integerLen > 0) {
28890
+ decimals = digits.splice(integerLen);
28891
+ } else {
28892
+ decimals = digits;
28893
+ digits = [0];
27975
28894
  }
27976
28895
 
27977
- if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
27978
- } else {
27979
- if (fractionSize > 0 && number < 1) {
27980
- formatedText = number.toFixed(fractionSize);
27981
- number = parseFloat(formatedText);
27982
- formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
28896
+ // format the integer digits with grouping separators
28897
+ var groups = [];
28898
+ if (digits.length > pattern.lgSize) {
28899
+ groups.unshift(digits.splice(-pattern.lgSize).join(''));
27983
28900
  }
27984
- }
28901
+ while (digits.length > pattern.gSize) {
28902
+ groups.unshift(digits.splice(-pattern.gSize).join(''));
28903
+ }
28904
+ if (digits.length) {
28905
+ groups.unshift(digits.join(''));
28906
+ }
28907
+ formattedText = groups.join(groupSep);
27985
28908
 
27986
- if (number === 0) {
27987
- isNegative = false;
27988
- }
28909
+ // append the decimal digits
28910
+ if (decimals.length) {
28911
+ formattedText += decimalSep + decimals.join('');
28912
+ }
27989
28913
 
27990
- parts.push(isNegative ? pattern.negPre : pattern.posPre,
27991
- formatedText,
27992
- isNegative ? pattern.negSuf : pattern.posSuf);
27993
- return parts.join('');
28914
+ if (exponent) {
28915
+ formattedText += 'e+' + exponent;
28916
+ }
28917
+ }
28918
+ if (number < 0 && !isZero) {
28919
+ return pattern.negPre + formattedText + pattern.negSuf;
28920
+ } else {
28921
+ return pattern.posPre + formattedText + pattern.posSuf;
28922
+ }
27994
28923
  }
27995
28924
 
27996
28925
  function padNumber(num, digits, trim) {
@@ -28000,7 +28929,7 @@ function padNumber(num, digits, trim) {
28000
28929
  num = -num;
28001
28930
  }
28002
28931
  num = '' + num;
28003
- while (num.length < digits) num = '0' + num;
28932
+ while (num.length < digits) num = ZERO_CHAR + num;
28004
28933
  if (trim) {
28005
28934
  num = num.substr(num.length - digits);
28006
28935
  }
@@ -28269,13 +29198,13 @@ function dateFilter($locale) {
28269
29198
 
28270
29199
  var dateTimezoneOffset = date.getTimezoneOffset();
28271
29200
  if (timezone) {
28272
- dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
29201
+ dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
28273
29202
  date = convertTimezoneToLocal(date, timezone, true);
28274
29203
  }
28275
29204
  forEach(parts, function(value) {
28276
29205
  fn = DATE_FORMATS[value];
28277
29206
  text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
28278
- : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
29207
+ : value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
28279
29208
  });
28280
29209
 
28281
29210
  return text;
@@ -28479,8 +29408,9 @@ function limitToFilter() {
28479
29408
  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
28480
29409
  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
28481
29410
  * as expected, make sure they are actually being saved as numbers and not strings.
29411
+ * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
28482
29412
  *
28483
- * @param {Array} array The array to sort.
29413
+ * @param {Array} array The array (or array-like object) to sort.
28484
29414
  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
28485
29415
  * used by the comparator to determine the order of elements.
28486
29416
  *
@@ -28511,17 +29441,6 @@ function limitToFilter() {
28511
29441
  * `reverse` is not set, which means it defaults to `false`.
28512
29442
  <example module="orderByExample">
28513
29443
  <file name="index.html">
28514
- <script>
28515
- angular.module('orderByExample', [])
28516
- .controller('ExampleController', ['$scope', function($scope) {
28517
- $scope.friends =
28518
- [{name:'John', phone:'555-1212', age:10},
28519
- {name:'Mary', phone:'555-9876', age:19},
28520
- {name:'Mike', phone:'555-4321', age:21},
28521
- {name:'Adam', phone:'555-5678', age:35},
28522
- {name:'Julie', phone:'555-8765', age:29}];
28523
- }]);
28524
- </script>
28525
29444
  <div ng-controller="ExampleController">
28526
29445
  <table class="friend">
28527
29446
  <tr>
@@ -28537,6 +29456,17 @@ function limitToFilter() {
28537
29456
  </table>
28538
29457
  </div>
28539
29458
  </file>
29459
+ <file name="script.js">
29460
+ angular.module('orderByExample', [])
29461
+ .controller('ExampleController', ['$scope', function($scope) {
29462
+ $scope.friends =
29463
+ [{name:'John', phone:'555-1212', age:10},
29464
+ {name:'Mary', phone:'555-9876', age:19},
29465
+ {name:'Mike', phone:'555-4321', age:21},
29466
+ {name:'Adam', phone:'555-5678', age:35},
29467
+ {name:'Julie', phone:'555-8765', age:29}];
29468
+ }]);
29469
+ </file>
28540
29470
  </example>
28541
29471
  *
28542
29472
  * The predicate and reverse parameters can be controlled dynamically through scope properties,
@@ -28544,49 +29474,24 @@ function limitToFilter() {
28544
29474
  * @example
28545
29475
  <example module="orderByExample">
28546
29476
  <file name="index.html">
28547
- <script>
28548
- angular.module('orderByExample', [])
28549
- .controller('ExampleController', ['$scope', function($scope) {
28550
- $scope.friends =
28551
- [{name:'John', phone:'555-1212', age:10},
28552
- {name:'Mary', phone:'555-9876', age:19},
28553
- {name:'Mike', phone:'555-4321', age:21},
28554
- {name:'Adam', phone:'555-5678', age:35},
28555
- {name:'Julie', phone:'555-8765', age:29}];
28556
- $scope.predicate = 'age';
28557
- $scope.reverse = true;
28558
- $scope.order = function(predicate) {
28559
- $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
28560
- $scope.predicate = predicate;
28561
- };
28562
- }]);
28563
- </script>
28564
- <style type="text/css">
28565
- .sortorder:after {
28566
- content: '\25b2';
28567
- }
28568
- .sortorder.reverse:after {
28569
- content: '\25bc';
28570
- }
28571
- </style>
28572
29477
  <div ng-controller="ExampleController">
28573
29478
  <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
28574
29479
  <hr/>
28575
- [ <a href="" ng-click="predicate=''">unsorted</a> ]
29480
+ <button ng-click="predicate=''">Set to unsorted</button>
28576
29481
  <table class="friend">
28577
29482
  <tr>
28578
- <th>
28579
- <a href="" ng-click="order('name')">Name</a>
28580
- <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
28581
- </th>
28582
- <th>
28583
- <a href="" ng-click="order('phone')">Phone Number</a>
28584
- <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
28585
- </th>
28586
- <th>
28587
- <a href="" ng-click="order('age')">Age</a>
28588
- <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
28589
- </th>
29483
+ <th>
29484
+ <button ng-click="order('name')">Name</button>
29485
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29486
+ </th>
29487
+ <th>
29488
+ <button ng-click="order('phone')">Phone Number</button>
29489
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29490
+ </th>
29491
+ <th>
29492
+ <button ng-click="order('age')">Age</button>
29493
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29494
+ </th>
28590
29495
  </tr>
28591
29496
  <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
28592
29497
  <td>{{friend.name}}</td>
@@ -28596,6 +29501,31 @@ function limitToFilter() {
28596
29501
  </table>
28597
29502
  </div>
28598
29503
  </file>
29504
+ <file name="script.js">
29505
+ angular.module('orderByExample', [])
29506
+ .controller('ExampleController', ['$scope', function($scope) {
29507
+ $scope.friends =
29508
+ [{name:'John', phone:'555-1212', age:10},
29509
+ {name:'Mary', phone:'555-9876', age:19},
29510
+ {name:'Mike', phone:'555-4321', age:21},
29511
+ {name:'Adam', phone:'555-5678', age:35},
29512
+ {name:'Julie', phone:'555-8765', age:29}];
29513
+ $scope.predicate = 'age';
29514
+ $scope.reverse = true;
29515
+ $scope.order = function(predicate) {
29516
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
29517
+ $scope.predicate = predicate;
29518
+ };
29519
+ }]);
29520
+ </file>
29521
+ <file name="style.css">
29522
+ .sortorder:after {
29523
+ content: '\25b2';
29524
+ }
29525
+ .sortorder.reverse:after {
29526
+ content: '\25bc';
29527
+ }
29528
+ </file>
28599
29529
  </example>
28600
29530
  *
28601
29531
  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
@@ -28607,21 +29537,30 @@ function limitToFilter() {
28607
29537
  * @example
28608
29538
  <example module="orderByExample">
28609
29539
  <file name="index.html">
28610
- <div ng-controller="ExampleController">
28611
- <table class="friend">
28612
- <tr>
28613
- <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
28614
- (<a href="" ng-click="order('-name',false)">^</a>)</th>
28615
- <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
28616
- <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
28617
- </tr>
28618
- <tr ng-repeat="friend in friends">
28619
- <td>{{friend.name}}</td>
28620
- <td>{{friend.phone}}</td>
28621
- <td>{{friend.age}}</td>
28622
- </tr>
28623
- </table>
28624
- </div>
29540
+ <div ng-controller="ExampleController">
29541
+ <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
29542
+ <table class="friend">
29543
+ <tr>
29544
+ <th>
29545
+ <button ng-click="order('name')">Name</button>
29546
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29547
+ </th>
29548
+ <th>
29549
+ <button ng-click="order('phone')">Phone Number</button>
29550
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29551
+ </th>
29552
+ <th>
29553
+ <button ng-click="order('age')">Age</button>
29554
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29555
+ </th>
29556
+ </tr>
29557
+ <tr ng-repeat="friend in friends">
29558
+ <td>{{friend.name}}</td>
29559
+ <td>{{friend.phone}}</td>
29560
+ <td>{{friend.age}}</td>
29561
+ </tr>
29562
+ </table>
29563
+ </div>
28625
29564
  </file>
28626
29565
 
28627
29566
  <file name="script.js">
@@ -28635,19 +29574,33 @@ function limitToFilter() {
28635
29574
  { name: 'Adam', phone: '555-5678', age: 35 },
28636
29575
  { name: 'Julie', phone: '555-8765', age: 29 }
28637
29576
  ];
28638
- $scope.order = function(predicate, reverse) {
28639
- $scope.friends = orderBy($scope.friends, predicate, reverse);
29577
+ $scope.order = function(predicate) {
29578
+ $scope.predicate = predicate;
29579
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
29580
+ $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
28640
29581
  };
28641
- $scope.order('-age',false);
29582
+ $scope.order('age', true);
28642
29583
  }]);
28643
29584
  </file>
29585
+
29586
+ <file name="style.css">
29587
+ .sortorder:after {
29588
+ content: '\25b2';
29589
+ }
29590
+ .sortorder.reverse:after {
29591
+ content: '\25bc';
29592
+ }
29593
+ </file>
28644
29594
  </example>
28645
29595
  */
28646
29596
  orderByFilter.$inject = ['$parse'];
28647
29597
  function orderByFilter($parse) {
28648
29598
  return function(array, sortPredicate, reverseOrder) {
28649
29599
 
28650
- if (!(isArrayLike(array))) return array;
29600
+ if (array == null) return array;
29601
+ if (!isArrayLike(array)) {
29602
+ throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
29603
+ }
28651
29604
 
28652
29605
  if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
28653
29606
  if (sortPredicate.length === 0) { sortPredicate = ['+']; }
@@ -28970,20 +29923,7 @@ var htmlAnchorDirective = valueFn({
28970
29923
  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
28971
29924
  *
28972
29925
  * A special directive is necessary because we cannot use interpolation inside the `disabled`
28973
- * attribute. The following example would make the button enabled on Chrome/Firefox
28974
- * but not on older IEs:
28975
- *
28976
- * ```html
28977
- * <!-- See below for an example of ng-disabled being used correctly -->
28978
- * <div ng-init="isDisabled = false">
28979
- * <button disabled="{{isDisabled}}">Disabled</button>
28980
- * </div>
28981
- * ```
28982
- *
28983
- * This is because the HTML specification does not require browsers to preserve the values of
28984
- * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
28985
- * If we put an Angular interpolation expression into such an attribute then the
28986
- * binding information would be lost when the browser removes the attribute.
29926
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
28987
29927
  *
28988
29928
  * @example
28989
29929
  <example>
@@ -29018,15 +29958,9 @@ var htmlAnchorDirective = valueFn({
29018
29958
  * Note that this directive should not be used together with {@link ngModel `ngModel`},
29019
29959
  * as this can lead to unexpected behavior.
29020
29960
  *
29021
- * ### Why do we need `ngChecked`?
29961
+ * A special directive is necessary because we cannot use interpolation inside the `checked`
29962
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29022
29963
  *
29023
- * The HTML specification does not require browsers to preserve the values of boolean attributes
29024
- * such as checked. (Their presence means true and their absence means false.)
29025
- * If we put an Angular interpolation expression into such an attribute then the
29026
- * binding information would be lost when the browser removes the attribute.
29027
- * The `ngChecked` directive solves this problem for the `checked` attribute.
29028
- * This complementary directive is not removed by the browser and so provides
29029
- * a permanent reliable place to store the binding information.
29030
29964
  * @example
29031
29965
  <example>
29032
29966
  <file name="index.html">
@@ -29055,13 +29989,12 @@ var htmlAnchorDirective = valueFn({
29055
29989
  * @priority 100
29056
29990
  *
29057
29991
  * @description
29058
- * The HTML specification does not require browsers to preserve the values of boolean attributes
29059
- * such as readonly. (Their presence means true and their absence means false.)
29060
- * If we put an Angular interpolation expression into such an attribute then the
29061
- * binding information would be lost when the browser removes the attribute.
29062
- * The `ngReadonly` directive solves this problem for the `readonly` attribute.
29063
- * This complementary directive is not removed by the browser and so provides
29064
- * a permanent reliable place to store the binding information.
29992
+ *
29993
+ * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
29994
+ *
29995
+ * A special directive is necessary because we cannot use interpolation inside the `readOnly`
29996
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29997
+ *
29065
29998
  * @example
29066
29999
  <example>
29067
30000
  <file name="index.html">
@@ -29090,13 +30023,11 @@ var htmlAnchorDirective = valueFn({
29090
30023
  * @priority 100
29091
30024
  *
29092
30025
  * @description
29093
- * The HTML specification does not require browsers to preserve the values of boolean attributes
29094
- * such as selected. (Their presence means true and their absence means false.)
29095
- * If we put an Angular interpolation expression into such an attribute then the
29096
- * binding information would be lost when the browser removes the attribute.
29097
- * The `ngSelected` directive solves this problem for the `selected` attribute.
29098
- * This complementary directive is not removed by the browser and so provides
29099
- * a permanent reliable place to store the binding information.
30026
+ *
30027
+ * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
30028
+ *
30029
+ * A special directive is necessary because we cannot use interpolation inside the `selected`
30030
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29100
30031
  *
29101
30032
  * @example
29102
30033
  <example>
@@ -29128,13 +30059,12 @@ var htmlAnchorDirective = valueFn({
29128
30059
  * @priority 100
29129
30060
  *
29130
30061
  * @description
29131
- * The HTML specification does not require browsers to preserve the values of boolean attributes
29132
- * such as open. (Their presence means true and their absence means false.)
29133
- * If we put an Angular interpolation expression into such an attribute then the
29134
- * binding information would be lost when the browser removes the attribute.
29135
- * The `ngOpen` directive solves this problem for the `open` attribute.
29136
- * This complementary directive is not removed by the browser and so provides
29137
- * a permanent reliable place to store the binding information.
30062
+ *
30063
+ * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
30064
+ *
30065
+ * A special directive is necessary because we cannot use interpolation inside the `open`
30066
+ * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30067
+ *
29138
30068
  * @example
29139
30069
  <example>
29140
30070
  <file name="index.html">
@@ -29380,7 +30310,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29380
30310
  *
29381
30311
  * However, if the method is used programmatically, for example by adding dynamically created controls,
29382
30312
  * or controls that have been previously removed without destroying their corresponding DOM element,
29383
- * it's the developers responsiblity to make sure the current state propagates to the parent form.
30313
+ * it's the developers responsibility to make sure the current state propagates to the parent form.
29384
30314
  *
29385
30315
  * For example, if an input control is added that is already `$dirty` and has `$error` properties,
29386
30316
  * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
@@ -29590,13 +30520,9 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
29590
30520
  *
29591
30521
  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
29592
30522
  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
29593
- * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
29594
- * `<form>` but can be nested. This allows you to have nested forms, which is very useful when
29595
- * using Angular validation directives in forms that are dynamically generated using the
29596
- * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
29597
- * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
29598
- * `ngForm` directive and nest these in an outer `form` element.
29599
- *
30523
+ * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
30524
+ * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
30525
+ * of controls needs to be determined.
29600
30526
  *
29601
30527
  * # CSS classes
29602
30528
  * - `ng-valid` is set if the form is valid.
@@ -29817,7 +30743,18 @@ var ngFormDirective = formDirectiveFactory(true);
29817
30743
  // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
29818
30744
  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)/;
29819
30745
  // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
29820
- var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
30746
+ // Note: We are being more lenient, because browsers are too.
30747
+ // 1. Scheme
30748
+ // 2. Slashes
30749
+ // 3. Username
30750
+ // 4. Password
30751
+ // 5. Hostname
30752
+ // 6. Port
30753
+ // 7. Path
30754
+ // 8. Query
30755
+ // 9. Fragment
30756
+ // 1111111111111111 222 333333 44444 555555555555555555555555 666 77777777 8888888 999
30757
+ var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
29821
30758
  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;
29822
30759
  var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
29823
30760
  var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
@@ -29850,8 +30787,8 @@ var inputType = {
29850
30787
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
29851
30788
  * that contains the regular expression body that will be converted to a regular expression
29852
30789
  * as in the ngPattern directive.
29853
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
29854
- * a RegExp found by evaluating the Angular expression given in the attribute value.
30790
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
30791
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
29855
30792
  * If the expression evaluates to a RegExp object, then this is used directly.
29856
30793
  * If the expression evaluates to a string, then it will be converted to a RegExp
29857
30794
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -30138,7 +31075,7 @@ var inputType = {
30138
31075
  *
30139
31076
  * @description
30140
31077
  * Input with time validation and transformation. In browsers that do not yet support
30141
- * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31078
+ * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30142
31079
  * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
30143
31080
  * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
30144
31081
  *
@@ -30485,8 +31422,8 @@ var inputType = {
30485
31422
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30486
31423
  * that contains the regular expression body that will be converted to a regular expression
30487
31424
  * as in the ngPattern directive.
30488
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30489
- * a RegExp found by evaluating the Angular expression given in the attribute value.
31425
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31426
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
30490
31427
  * If the expression evaluates to a RegExp object, then this is used directly.
30491
31428
  * If the expression evaluates to a string, then it will be converted to a RegExp
30492
31429
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -30583,8 +31520,8 @@ var inputType = {
30583
31520
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30584
31521
  * that contains the regular expression body that will be converted to a regular expression
30585
31522
  * as in the ngPattern directive.
30586
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30587
- * a RegExp found by evaluating the Angular expression given in the attribute value.
31523
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31524
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
30588
31525
  * If the expression evaluates to a RegExp object, then this is used directly.
30589
31526
  * If the expression evaluates to a string, then it will be converted to a RegExp
30590
31527
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -30682,8 +31619,8 @@ var inputType = {
30682
31619
  * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30683
31620
  * that contains the regular expression body that will be converted to a regular expression
30684
31621
  * as in the ngPattern directive.
30685
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30686
- * a RegExp found by evaluating the Angular expression given in the attribute value.
31622
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31623
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
30687
31624
  * If the expression evaluates to a RegExp object, then this is used directly.
30688
31625
  * If the expression evaluates to a string, then it will be converted to a RegExp
30689
31626
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -31143,11 +32080,7 @@ function badInputChecker(scope, element, attr, ctrl) {
31143
32080
  if (nativeValidation) {
31144
32081
  ctrl.$parsers.push(function(value) {
31145
32082
  var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
31146
- // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
31147
- // - also sets validity.badInput (should only be validity.typeMismatch).
31148
- // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
31149
- // - can ignore this case as we can still read out the erroneous email...
31150
- return validity.badInput && !validity.typeMismatch ? undefined : value;
32083
+ return validity.badInput || validity.typeMismatch ? undefined : value;
31151
32084
  });
31152
32085
  }
31153
32086
  }
@@ -31319,8 +32252,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
31319
32252
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31320
32253
  * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
31321
32254
  * length.
31322
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
31323
- * a RegExp found by evaluating the Angular expression given in the attribute value.
32255
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32256
+ * does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31324
32257
  * If the expression evaluates to a RegExp object, then this is used directly.
31325
32258
  * If the expression evaluates to a string, then it will be converted to a RegExp
31326
32259
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -31358,8 +32291,8 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt
31358
32291
  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31359
32292
  * maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
31360
32293
  * length.
31361
- * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
31362
- * a RegExp found by evaluating the Angular expression given in the attribute value.
32294
+ * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32295
+ * value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31363
32296
  * If the expression evaluates to a RegExp object, then this is used directly.
31364
32297
  * If the expression evaluates to a string, then it will be converted to a RegExp
31365
32298
  * after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
@@ -32585,7 +33518,7 @@ var ngControllerDirective = [function() {
32585
33518
  *
32586
33519
  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
32587
33520
  *
32588
- * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
33521
+ * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
32589
33522
  *
32590
33523
  * You can use these values in the following combinations:
32591
33524
  *
@@ -32602,7 +33535,7 @@ var ngControllerDirective = [function() {
32602
33535
  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
32603
33536
  *
32604
33537
  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
32605
- * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
33538
+ * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
32606
33539
  *
32607
33540
  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
32608
33541
  * styles nor use eval, which is the same as an empty: ng-csp.
@@ -33581,6 +34514,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
33581
34514
  //set the 2nd param to true to ignore the template request error so that the inner
33582
34515
  //contents and scope can be cleaned up.
33583
34516
  $templateRequest(src, true).then(function(response) {
34517
+ if (scope.$$destroyed) return;
34518
+
33584
34519
  if (thisChangeId !== changeCounter) return;
33585
34520
  var newScope = scope.$new();
33586
34521
  ctrl.template = response;
@@ -33602,6 +34537,8 @@ var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
33602
34537
  currentScope.$emit('$includeContentLoaded', src);
33603
34538
  scope.$eval(onloadExp);
33604
34539
  }, function() {
34540
+ if (scope.$$destroyed) return;
34541
+
33605
34542
  if (thisChangeId === changeCounter) {
33606
34543
  cleanupLastIncludeContent();
33607
34544
  scope.$emit('$includeContentError', src);
@@ -33630,7 +34567,7 @@ var ngIncludeFillContentDirective = ['$compile',
33630
34567
  priority: -400,
33631
34568
  require: 'ngInclude',
33632
34569
  link: function(scope, $element, $attr, ctrl) {
33633
- if (/SVG/.test($element[0].toString())) {
34570
+ if (toString.call($element[0]).match(/SVG/)) {
33634
34571
  // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
33635
34572
  // support innerHTML, so detect this here and try to generate the contents
33636
34573
  // specially.
@@ -33859,7 +34796,9 @@ var VALID_CLASS = 'ng-valid',
33859
34796
  DIRTY_CLASS = 'ng-dirty',
33860
34797
  UNTOUCHED_CLASS = 'ng-untouched',
33861
34798
  TOUCHED_CLASS = 'ng-touched',
33862
- PENDING_CLASS = 'ng-pending';
34799
+ PENDING_CLASS = 'ng-pending',
34800
+ EMPTY_CLASS = 'ng-empty',
34801
+ NOT_EMPTY_CLASS = 'ng-not-empty';
33863
34802
 
33864
34803
  var ngModelMinErr = minErr('ngModel');
33865
34804
 
@@ -34163,6 +35102,17 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34163
35102
  return isUndefined(value) || value === '' || value === null || value !== value;
34164
35103
  };
34165
35104
 
35105
+ this.$$updateEmptyClasses = function(value) {
35106
+ if (ctrl.$isEmpty(value)) {
35107
+ $animate.removeClass($element, NOT_EMPTY_CLASS);
35108
+ $animate.addClass($element, EMPTY_CLASS);
35109
+ } else {
35110
+ $animate.removeClass($element, EMPTY_CLASS);
35111
+ $animate.addClass($element, NOT_EMPTY_CLASS);
35112
+ }
35113
+ };
35114
+
35115
+
34166
35116
  var currentValidationRunId = 0;
34167
35117
 
34168
35118
  /**
@@ -34280,11 +35230,14 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34280
35230
  * which may be caused by a pending debounced event or because the input is waiting for a some
34281
35231
  * future event.
34282
35232
  *
34283
- * If you have an input that uses `ng-model-options` to set up debounced events or events such
34284
- * as blur you can have a situation where there is a period when the `$viewValue`
34285
- * is out of synch with the ngModel's `$modelValue`.
35233
+ * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
35234
+ * depend on special events such as blur, you can have a situation where there is a period when
35235
+ * the `$viewValue` is out of sync with the ngModel's `$modelValue`.
35236
+ *
35237
+ * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
35238
+ * and reset the input to the last committed view value.
34286
35239
  *
34287
- * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
35240
+ * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
34288
35241
  * programmatically before these debounced/future events have resolved/occurred, because Angular's
34289
35242
  * dirty checking mechanism is not able to tell whether the model has actually changed or not.
34290
35243
  *
@@ -34297,39 +35250,63 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34297
35250
  * angular.module('cancel-update-example', [])
34298
35251
  *
34299
35252
  * .controller('CancelUpdateController', ['$scope', function($scope) {
34300
- * $scope.resetWithCancel = function(e) {
34301
- * if (e.keyCode == 27) {
34302
- * $scope.myForm.myInput1.$rollbackViewValue();
34303
- * $scope.myValue = '';
34304
- * }
34305
- * };
34306
- * $scope.resetWithoutCancel = function(e) {
35253
+ * $scope.model = {};
35254
+ *
35255
+ * $scope.setEmpty = function(e, value, rollback) {
34307
35256
  * if (e.keyCode == 27) {
34308
- * $scope.myValue = '';
35257
+ * e.preventDefault();
35258
+ * if (rollback) {
35259
+ * $scope.myForm[value].$rollbackViewValue();
35260
+ * }
35261
+ * $scope.model[value] = '';
34309
35262
  * }
34310
35263
  * };
34311
35264
  * }]);
34312
35265
  * </file>
34313
35266
  * <file name="index.html">
34314
35267
  * <div ng-controller="CancelUpdateController">
34315
- * <p>Try typing something in each input. See that the model only updates when you
34316
- * blur off the input.
34317
- * </p>
34318
- * <p>Now see what happens if you start typing then press the Escape key</p>
35268
+ * <p>Both of these inputs are only updated if they are blurred. Hitting escape should
35269
+ * empty them. Follow these steps and observe the difference:</p>
35270
+ * <ol>
35271
+ * <li>Type something in the input. You will see that the model is not yet updated</li>
35272
+ * <li>Press the Escape key.
35273
+ * <ol>
35274
+ * <li> In the first example, nothing happens, because the model is already '', and no
35275
+ * update is detected. If you blur the input, the model will be set to the current view.
35276
+ * </li>
35277
+ * <li> In the second example, the pending update is cancelled, and the input is set back
35278
+ * to the last committed view value (''). Blurring the input does nothing.
35279
+ * </li>
35280
+ * </ol>
35281
+ * </li>
35282
+ * </ol>
34319
35283
  *
34320
35284
  * <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
34321
- * <p id="inputDescription1">With $rollbackViewValue()</p>
34322
- * <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
34323
- * ng-keydown="resetWithCancel($event)"><br/>
34324
- * myValue: "{{ myValue }}"
34325
- *
34326
- * <p id="inputDescription2">Without $rollbackViewValue()</p>
34327
- * <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
34328
- * ng-keydown="resetWithoutCancel($event)"><br/>
34329
- * myValue: "{{ myValue }}"
35285
+ * <div>
35286
+ * <p id="inputDescription1">Without $rollbackViewValue():</p>
35287
+ * <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
35288
+ * ng-keydown="setEmpty($event, 'value1')">
35289
+ * value1: "{{ model.value1 }}"
35290
+ * </div>
35291
+ *
35292
+ * <div>
35293
+ * <p id="inputDescription2">With $rollbackViewValue():</p>
35294
+ * <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
35295
+ * ng-keydown="setEmpty($event, 'value2', true)">
35296
+ * value2: "{{ model.value2 }}"
35297
+ * </div>
34330
35298
  * </form>
34331
35299
  * </div>
34332
35300
  * </file>
35301
+ <file name="style.css">
35302
+ div {
35303
+ display: table-cell;
35304
+ }
35305
+ div:nth-child(1) {
35306
+ padding-right: 30px;
35307
+ }
35308
+
35309
+ </file>
34333
35310
  * </example>
34334
35311
  */
34335
35312
  this.$rollbackViewValue = function() {
@@ -34443,7 +35420,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34443
35420
  forEach(ctrl.$asyncValidators, function(validator, name) {
34444
35421
  var promise = validator(modelValue, viewValue);
34445
35422
  if (!isPromiseLike(promise)) {
34446
- throw ngModelMinErr("$asyncValidators",
35423
+ throw ngModelMinErr('nopromise',
34447
35424
  "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
34448
35425
  }
34449
35426
  setValidity(name, undefined);
@@ -34499,6 +35476,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34499
35476
  if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
34500
35477
  return;
34501
35478
  }
35479
+ ctrl.$$updateEmptyClasses(viewValue);
34502
35480
  ctrl.$$lastCommittedViewValue = viewValue;
34503
35481
 
34504
35482
  // change to dirty
@@ -34597,7 +35575,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34597
35575
  * However, custom controls might also pass objects to this method. In this case, we should make
34598
35576
  * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
34599
35577
  * perform a deep watch of objects, it only looks for a change of identity. If you only change
34600
- * the property of the object then ngModel will not realise that the object has changed and
35578
+ * the property of the object then ngModel will not realize that the object has changed and
34601
35579
  * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
34602
35580
  * not change properties of the copy once it has been passed to `$setViewValue`.
34603
35581
  * Otherwise you may cause the model value on the scope to change incorrectly.
@@ -34681,6 +35659,7 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34681
35659
  viewValue = formatters[idx](viewValue);
34682
35660
  }
34683
35661
  if (ctrl.$viewValue !== viewValue) {
35662
+ ctrl.$$updateEmptyClasses(viewValue);
34684
35663
  ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
34685
35664
  ctrl.$render();
34686
35665
 
@@ -34711,7 +35690,8 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34711
35690
  * require.
34712
35691
  * - Providing validation behavior (i.e. required, number, email, url).
34713
35692
  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
34714
- * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
35693
+ * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
35694
+ * `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
34715
35695
  * - Registering the control with its parent {@link ng.directive:form form}.
34716
35696
  *
34717
35697
  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
@@ -34739,6 +35719,22 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34739
35719
  * - {@link ng.directive:select select}
34740
35720
  * - {@link ng.directive:textarea textarea}
34741
35721
  *
35722
+ * # Complex Models (objects or collections)
35723
+ *
35724
+ * By default, `ngModel` watches the model by reference, not value. This is important to know when
35725
+ * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
35726
+ * object or collection change, `ngModel` will not be notified and so the input will not be re-rendered.
35727
+ *
35728
+ * The model must be assigned an entirely new object or collection before a re-rendering will occur.
35729
+ *
35730
+ * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
35731
+ * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
35732
+ * if the select is given the `multiple` attribute.
35733
+ *
35734
+ * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
35735
+ * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
35736
+ * not trigger a re-rendering of the model.
35737
+ *
34742
35738
  * # CSS classes
34743
35739
  * The following CSS classes are added and removed on the associated input/select/textarea element
34744
35740
  * depending on the validity of the model.
@@ -34752,13 +35748,16 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
34752
35748
  * - `ng-touched`: the control has been blurred
34753
35749
  * - `ng-untouched`: the control hasn't been blurred
34754
35750
  * - `ng-pending`: any `$asyncValidators` are unfulfilled
35751
+ * - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
35752
+ * by the {@link ngModel.NgModelController#$isEmpty} method
35753
+ * - `ng-not-empty`: the view contains a non-empty value
34755
35754
  *
34756
35755
  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
34757
35756
  *
34758
35757
  * ## Animation Hooks
34759
35758
  *
34760
35759
  * Animations within models are triggered when any of the associated CSS classes are added and removed
34761
- * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
35760
+ * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
34762
35761
  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
34763
35762
  * The animations that are triggered within ngModel are similar to how they work in ngClass and
34764
35763
  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
@@ -35651,14 +36650,10 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35651
36650
  var optionTemplate = document.createElement('option'),
35652
36651
  optGroupTemplate = document.createElement('optgroup');
35653
36652
 
35654
-
35655
36653
  function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
35656
36654
 
35657
- // if ngModel is not defined, we don't need to do anything
35658
- var ngModelCtrl = ctrls[1];
35659
- if (!ngModelCtrl) return;
35660
-
35661
36655
  var selectCtrl = ctrls[0];
36656
+ var ngModelCtrl = ctrls[1];
35662
36657
  var multiple = attr.multiple;
35663
36658
 
35664
36659
  // The emptyOption allows the application developer to provide their own custom "empty"
@@ -35889,7 +36884,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35889
36884
  (current === emptyOption_ ||
35890
36885
  current === unknownOption_ ||
35891
36886
  current.nodeType === NODE_TYPE_COMMENT ||
35892
- current.value === '')) {
36887
+ (nodeName_(current) === 'option' && current.value === ''))) {
35893
36888
  current = current.nextSibling;
35894
36889
  }
35895
36890
  }
@@ -35918,7 +36913,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35918
36913
  var groupElement;
35919
36914
  var optionElement;
35920
36915
 
35921
- if (option.group) {
36916
+ if (isDefined(option.group)) {
35922
36917
 
35923
36918
  // This option is to live in a group
35924
36919
  // See if we have already created this group
@@ -35979,7 +36974,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35979
36974
  // Check to see if the value has changed due to the update to the options
35980
36975
  if (!ngModelCtrl.$isEmpty(previousValue)) {
35981
36976
  var nextValue = selectCtrl.readValue();
35982
- if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
36977
+ var isNotPrimitive = ngOptions.trackBy || multiple;
36978
+ if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
35983
36979
  ngModelCtrl.$setViewValue(nextValue);
35984
36980
  ngModelCtrl.$render();
35985
36981
  }
@@ -35991,7 +36987,7 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35991
36987
  return {
35992
36988
  restrict: 'A',
35993
36989
  terminal: true,
35994
- require: ['select', '?ngModel'],
36990
+ require: ['select', 'ngModel'],
35995
36991
  link: {
35996
36992
  pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
35997
36993
  // Deactivate the SelectController.register method to prevent
@@ -36219,7 +37215,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36219
37215
  }
36220
37216
 
36221
37217
  // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
36222
- // In JS `NaN !== NaN`, so we have to exlicitly check.
37218
+ // In JS `NaN !== NaN`, so we have to explicitly check.
36223
37219
  if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
36224
37220
  watchRemover();
36225
37221
  var whenExpFn = whensExpFns[count];
@@ -36336,7 +37332,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36336
37332
  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
36337
37333
  * will not have to rebuild the DOM elements for items it has already rendered, even if the
36338
37334
  * JavaScript objects in the collection have been substituted for new ones. For large collections,
36339
- * this signifincantly improves rendering performance. If you don't have a unique identifier,
37335
+ * this significantly improves rendering performance. If you don't have a unique identifier,
36340
37336
  * `track by $index` can also provide a performance boost.
36341
37337
  * </div>
36342
37338
  * ```html
@@ -36413,6 +37409,8 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36413
37409
  *
36414
37410
  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
36415
37411
  *
37412
+ * See the example below for defining CSS animations with ngRepeat.
37413
+ *
36416
37414
  * @element ANY
36417
37415
  * @scope
36418
37416
  * @priority 1000
@@ -36465,22 +37463,11 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36465
37463
  * For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
36466
37464
  *
36467
37465
  * @example
36468
- * This example initializes the scope to a list of names and
36469
- * then uses `ngRepeat` to display every person:
36470
- <example module="ngAnimate" deps="angular-animate.js" animations="true">
37466
+ * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
37467
+ * results by name. New (entering) and removed (leaving) items are animated.
37468
+ <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
36471
37469
  <file name="index.html">
36472
- <div ng-init="friends = [
36473
- {name:'John', age:25, gender:'boy'},
36474
- {name:'Jessie', age:30, gender:'girl'},
36475
- {name:'Johanna', age:28, gender:'girl'},
36476
- {name:'Joy', age:15, gender:'girl'},
36477
- {name:'Mary', age:28, gender:'girl'},
36478
- {name:'Peter', age:95, gender:'boy'},
36479
- {name:'Sebastian', age:50, gender:'boy'},
36480
- {name:'Erika', age:27, gender:'girl'},
36481
- {name:'Patrick', age:40, gender:'boy'},
36482
- {name:'Samantha', age:60, gender:'girl'}
36483
- ]">
37470
+ <div ng-controller="repeatController">
36484
37471
  I have {{friends.length}} friends. They are:
36485
37472
  <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
36486
37473
  <ul class="example-animate-container">
@@ -36493,6 +37480,22 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36493
37480
  </ul>
36494
37481
  </div>
36495
37482
  </file>
37483
+ <file name="script.js">
37484
+ angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
37485
+ $scope.friends = [
37486
+ {name:'John', age:25, gender:'boy'},
37487
+ {name:'Jessie', age:30, gender:'girl'},
37488
+ {name:'Johanna', age:28, gender:'girl'},
37489
+ {name:'Joy', age:15, gender:'girl'},
37490
+ {name:'Mary', age:28, gender:'girl'},
37491
+ {name:'Peter', age:95, gender:'boy'},
37492
+ {name:'Sebastian', age:50, gender:'boy'},
37493
+ {name:'Erika', age:27, gender:'girl'},
37494
+ {name:'Patrick', age:40, gender:'boy'},
37495
+ {name:'Samantha', age:60, gender:'girl'}
37496
+ ];
37497
+ });
37498
+ </file>
36496
37499
  <file name="animations.css">
36497
37500
  .example-animate-container {
36498
37501
  background:white;
@@ -36503,7 +37506,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36503
37506
  }
36504
37507
 
36505
37508
  .animate-repeat {
36506
- line-height:40px;
37509
+ line-height:30px;
36507
37510
  list-style:none;
36508
37511
  box-sizing:border-box;
36509
37512
  }
@@ -36525,7 +37528,7 @@ var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale,
36525
37528
  .animate-repeat.ng-move.ng-move-active,
36526
37529
  .animate-repeat.ng-enter.ng-enter-active {
36527
37530
  opacity:1;
36528
- max-height:40px;
37531
+ max-height:30px;
36529
37532
  }
36530
37533
  </file>
36531
37534
  <file name="protractor.js" type="protractor">
@@ -37382,67 +38385,186 @@ var ngSwitchDefaultDirective = ngDirective({
37382
38385
  * @description
37383
38386
  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
37384
38387
  *
37385
- * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
38388
+ * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
38389
+ * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
38390
+ *
38391
+ * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
38392
+ * content of this element will be removed before the transcluded content is inserted.
38393
+ * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
38394
+ * that no transcluded content is provided.
37386
38395
  *
37387
38396
  * @element ANY
37388
38397
  *
38398
+ * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
38399
+ * or its value is the same as the name of the attribute then the default slot is used.
38400
+ *
37389
38401
  * @example
37390
- <example module="transcludeExample">
37391
- <file name="index.html">
37392
- <script>
37393
- angular.module('transcludeExample', [])
37394
- .directive('pane', function(){
37395
- return {
37396
- restrict: 'E',
37397
- transclude: true,
37398
- scope: { title:'@' },
37399
- template: '<div style="border: 1px solid black;">' +
37400
- '<div style="background-color: gray">{{title}}</div>' +
37401
- '<ng-transclude></ng-transclude>' +
37402
- '</div>'
37403
- };
37404
- })
37405
- .controller('ExampleController', ['$scope', function($scope) {
37406
- $scope.title = 'Lorem Ipsum';
37407
- $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
37408
- }]);
37409
- </script>
37410
- <div ng-controller="ExampleController">
37411
- <input ng-model="title" aria-label="title"> <br/>
37412
- <textarea ng-model="text" aria-label="text"></textarea> <br/>
37413
- <pane title="{{title}}">{{text}}</pane>
37414
- </div>
37415
- </file>
37416
- <file name="protractor.js" type="protractor">
37417
- it('should have transcluded', function() {
37418
- var titleElement = element(by.model('title'));
37419
- titleElement.clear();
37420
- titleElement.sendKeys('TITLE');
37421
- var textElement = element(by.model('text'));
37422
- textElement.clear();
37423
- textElement.sendKeys('TEXT');
37424
- expect(element(by.binding('title')).getText()).toEqual('TITLE');
37425
- expect(element(by.binding('text')).getText()).toEqual('TEXT');
37426
- });
37427
- </file>
37428
- </example>
38402
+ * ### Basic transclusion
38403
+ * This example demonstrates basic transclusion of content into a component directive.
38404
+ * <example name="simpleTranscludeExample" module="transcludeExample">
38405
+ * <file name="index.html">
38406
+ * <script>
38407
+ * angular.module('transcludeExample', [])
38408
+ * .directive('pane', function(){
38409
+ * return {
38410
+ * restrict: 'E',
38411
+ * transclude: true,
38412
+ * scope: { title:'@' },
38413
+ * template: '<div style="border: 1px solid black;">' +
38414
+ * '<div style="background-color: gray">{{title}}</div>' +
38415
+ * '<ng-transclude></ng-transclude>' +
38416
+ * '</div>'
38417
+ * };
38418
+ * })
38419
+ * .controller('ExampleController', ['$scope', function($scope) {
38420
+ * $scope.title = 'Lorem Ipsum';
38421
+ * $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38422
+ * }]);
38423
+ * </script>
38424
+ * <div ng-controller="ExampleController">
38425
+ * <input ng-model="title" aria-label="title"> <br/>
38426
+ * <textarea ng-model="text" aria-label="text"></textarea> <br/>
38427
+ * <pane title="{{title}}">{{text}}</pane>
38428
+ * </div>
38429
+ * </file>
38430
+ * <file name="protractor.js" type="protractor">
38431
+ * it('should have transcluded', function() {
38432
+ * var titleElement = element(by.model('title'));
38433
+ * titleElement.clear();
38434
+ * titleElement.sendKeys('TITLE');
38435
+ * var textElement = element(by.model('text'));
38436
+ * textElement.clear();
38437
+ * textElement.sendKeys('TEXT');
38438
+ * expect(element(by.binding('title')).getText()).toEqual('TITLE');
38439
+ * expect(element(by.binding('text')).getText()).toEqual('TEXT');
38440
+ * });
38441
+ * </file>
38442
+ * </example>
38443
+ *
38444
+ * @example
38445
+ * ### Transclude fallback content
38446
+ * This example shows how to use `NgTransclude` with fallback content, that
38447
+ * is displayed if no transcluded content is provided.
38448
+ *
38449
+ * <example module="transcludeFallbackContentExample">
38450
+ * <file name="index.html">
38451
+ * <script>
38452
+ * angular.module('transcludeFallbackContentExample', [])
38453
+ * .directive('myButton', function(){
38454
+ * return {
38455
+ * restrict: 'E',
38456
+ * transclude: true,
38457
+ * scope: true,
38458
+ * template: '<button style="cursor: pointer;">' +
38459
+ * '<ng-transclude>' +
38460
+ * '<b style="color: red;">Button1</b>' +
38461
+ * '</ng-transclude>' +
38462
+ * '</button>'
38463
+ * };
38464
+ * });
38465
+ * </script>
38466
+ * <!-- fallback button content -->
38467
+ * <my-button id="fallback"></my-button>
38468
+ * <!-- modified button content -->
38469
+ * <my-button id="modified">
38470
+ * <i style="color: green;">Button2</i>
38471
+ * </my-button>
38472
+ * </file>
38473
+ * <file name="protractor.js" type="protractor">
38474
+ * it('should have different transclude element content', function() {
38475
+ * expect(element(by.id('fallback')).getText()).toBe('Button1');
38476
+ * expect(element(by.id('modified')).getText()).toBe('Button2');
38477
+ * });
38478
+ * </file>
38479
+ * </example>
37429
38480
  *
38481
+ * @example
38482
+ * ### Multi-slot transclusion
38483
+ * This example demonstrates using multi-slot transclusion in a component directive.
38484
+ * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
38485
+ * <file name="index.html">
38486
+ * <style>
38487
+ * .title, .footer {
38488
+ * background-color: gray
38489
+ * }
38490
+ * </style>
38491
+ * <div ng-controller="ExampleController">
38492
+ * <input ng-model="title" aria-label="title"> <br/>
38493
+ * <textarea ng-model="text" aria-label="text"></textarea> <br/>
38494
+ * <pane>
38495
+ * <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
38496
+ * <pane-body><p>{{text}}</p></pane-body>
38497
+ * </pane>
38498
+ * </div>
38499
+ * </file>
38500
+ * <file name="app.js">
38501
+ * angular.module('multiSlotTranscludeExample', [])
38502
+ * .directive('pane', function(){
38503
+ * return {
38504
+ * restrict: 'E',
38505
+ * transclude: {
38506
+ * 'title': '?paneTitle',
38507
+ * 'body': 'paneBody',
38508
+ * 'footer': '?paneFooter'
38509
+ * },
38510
+ * template: '<div style="border: 1px solid black;">' +
38511
+ * '<div class="title" ng-transclude="title">Fallback Title</div>' +
38512
+ * '<div ng-transclude="body"></div>' +
38513
+ * '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
38514
+ * '</div>'
38515
+ * };
38516
+ * })
38517
+ * .controller('ExampleController', ['$scope', function($scope) {
38518
+ * $scope.title = 'Lorem Ipsum';
38519
+ * $scope.link = "https://google.com";
38520
+ * $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38521
+ * }]);
38522
+ * </file>
38523
+ * <file name="protractor.js" type="protractor">
38524
+ * it('should have transcluded the title and the body', function() {
38525
+ * var titleElement = element(by.model('title'));
38526
+ * titleElement.clear();
38527
+ * titleElement.sendKeys('TITLE');
38528
+ * var textElement = element(by.model('text'));
38529
+ * textElement.clear();
38530
+ * textElement.sendKeys('TEXT');
38531
+ * expect(element(by.css('.title')).getText()).toEqual('TITLE');
38532
+ * expect(element(by.binding('text')).getText()).toEqual('TEXT');
38533
+ * expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
38534
+ * });
38535
+ * </file>
38536
+ * </example>
37430
38537
  */
38538
+ var ngTranscludeMinErr = minErr('ngTransclude');
37431
38539
  var ngTranscludeDirective = ngDirective({
37432
38540
  restrict: 'EAC',
37433
38541
  link: function($scope, $element, $attrs, controller, $transclude) {
38542
+
38543
+ if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
38544
+ // If the attribute is of the form: `ng-transclude="ng-transclude"`
38545
+ // then treat it like the default
38546
+ $attrs.ngTransclude = '';
38547
+ }
38548
+
38549
+ function ngTranscludeCloneAttachFn(clone) {
38550
+ if (clone.length) {
38551
+ $element.empty();
38552
+ $element.append(clone);
38553
+ }
38554
+ }
38555
+
37434
38556
  if (!$transclude) {
37435
- throw minErr('ngTransclude')('orphan',
38557
+ throw ngTranscludeMinErr('orphan',
37436
38558
  'Illegal use of ngTransclude directive in the template! ' +
37437
38559
  'No parent directive that requires a transclusion found. ' +
37438
38560
  'Element: {0}',
37439
38561
  startingTag($element));
37440
38562
  }
37441
38563
 
37442
- $transclude(function(clone) {
37443
- $element.empty();
37444
- $element.append(clone);
37445
- });
38564
+ // If there is no slot name defined or the slot name is not optional
38565
+ // then transclude the slot
38566
+ var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
38567
+ $transclude(ngTranscludeCloneAttachFn, null, slotName);
37446
38568
  }
37447
38569
  });
37448
38570
 
@@ -37574,6 +38696,9 @@ var SelectController =
37574
38696
 
37575
38697
  // Tell the select control that an option, with the given value, has been added
37576
38698
  self.addOption = function(value, element) {
38699
+ // Skip comment nodes, as they only pollute the `optionsMap`
38700
+ if (element[0].nodeType === NODE_TYPE_COMMENT) return;
38701
+
37577
38702
  assertNotHasOwnProperty(value, '"option value"');
37578
38703
  if (value === '') {
37579
38704
  self.emptyOption = element;
@@ -37648,7 +38773,7 @@ var SelectController =
37648
38773
  *
37649
38774
  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
37650
38775
  * between the scope and the `<select>` control (including setting default values).
37651
- * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
38776
+ * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
37652
38777
  * {@link ngOptions `ngOptions`} directives.
37653
38778
  *
37654
38779
  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
@@ -37658,7 +38783,7 @@ var SelectController =
37658
38783
  *
37659
38784
  * <div class="alert alert-warning">
37660
38785
  * Note that the value of a `select` directive used without `ngOptions` is always a string.
37661
- * When the model needs to be bound to a non-string value, you must either explictly convert it
38786
+ * When the model needs to be bound to a non-string value, you must either explicitly convert it
37662
38787
  * using a directive (see example below) or use `ngOptions` to specify the set of options.
37663
38788
  * This is because an option element can only be bound to string values at present.
37664
38789
  * </div>
@@ -37850,7 +38975,8 @@ var selectDirective = function() {
37850
38975
  controller: SelectController,
37851
38976
  priority: 1,
37852
38977
  link: {
37853
- pre: selectPreLink
38978
+ pre: selectPreLink,
38979
+ post: selectPostLink
37854
38980
  }
37855
38981
  };
37856
38982
 
@@ -37864,13 +38990,6 @@ var selectDirective = function() {
37864
38990
 
37865
38991
  selectCtrl.ngModelCtrl = ngModelCtrl;
37866
38992
 
37867
- // We delegate rendering to the `writeValue` method, which can be changed
37868
- // if the select can have multiple selected values or if the options are being
37869
- // generated by `ngOptions`
37870
- ngModelCtrl.$render = function() {
37871
- selectCtrl.writeValue(ngModelCtrl.$viewValue);
37872
- };
37873
-
37874
38993
  // When the selected item(s) changes we delegate getting the value of the select control
37875
38994
  // to the `readValue` method, which can be changed if the select can have multiple
37876
38995
  // selected values or if the options are being generated by `ngOptions`
@@ -37924,6 +39043,23 @@ var selectDirective = function() {
37924
39043
 
37925
39044
  }
37926
39045
  }
39046
+
39047
+ function selectPostLink(scope, element, attrs, ctrls) {
39048
+ // if ngModel is not defined, we don't need to do anything
39049
+ var ngModelCtrl = ctrls[1];
39050
+ if (!ngModelCtrl) return;
39051
+
39052
+ var selectCtrl = ctrls[0];
39053
+
39054
+ // We delegate rendering to the `writeValue` method, which can be changed
39055
+ // if the select can have multiple selected values or if the options are being
39056
+ // generated by `ngOptions`.
39057
+ // This must be done in the postLink fn to prevent $render to be called before
39058
+ // all nodes have been linked correctly.
39059
+ ngModelCtrl.$render = function() {
39060
+ selectCtrl.writeValue(ngModelCtrl.$viewValue);
39061
+ };
39062
+ }
37927
39063
  };
37928
39064
 
37929
39065
 
@@ -37935,7 +39071,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
37935
39071
  restrict: 'E',
37936
39072
  priority: 100,
37937
39073
  compile: function(element, attr) {
37938
-
37939
39074
  if (isDefined(attr.value)) {
37940
39075
  // If the value attribute is defined, check if it contains an interpolation
37941
39076
  var interpolateValueFn = $interpolate(attr.value, true);
@@ -37949,7 +39084,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
37949
39084
  }
37950
39085
 
37951
39086
  return function(scope, element, attr) {
37952
-
37953
39087
  // This is an optimization over using ^^ since we don't want to have to search
37954
39088
  // all the way to the root of the DOM for every single option element
37955
39089
  var selectCtrlName = '$selectController',
@@ -37970,6 +39104,64 @@ var styleDirective = valueFn({
37970
39104
  terminal: false
37971
39105
  });
37972
39106
 
39107
+ /**
39108
+ * @ngdoc directive
39109
+ * @name ngRequired
39110
+ *
39111
+ * @description
39112
+ *
39113
+ * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39114
+ * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
39115
+ * applied to custom controls.
39116
+ *
39117
+ * The directive sets the `required` attribute on the element if the Angular expression inside
39118
+ * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
39119
+ * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
39120
+ * for more info.
39121
+ *
39122
+ * The validator will set the `required` error key to true if the `required` attribute is set and
39123
+ * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
39124
+ * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
39125
+ * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
39126
+ * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
39127
+ *
39128
+ * @example
39129
+ * <example name="ngRequiredDirective" module="ngRequiredExample">
39130
+ * <file name="index.html">
39131
+ * <script>
39132
+ * angular.module('ngRequiredExample', [])
39133
+ * .controller('ExampleController', ['$scope', function($scope) {
39134
+ * $scope.required = true;
39135
+ * }]);
39136
+ * </script>
39137
+ * <div ng-controller="ExampleController">
39138
+ * <form name="form">
39139
+ * <label for="required">Toggle required: </label>
39140
+ * <input type="checkbox" ng-model="required" id="required" />
39141
+ * <br>
39142
+ * <label for="input">This input must be filled if `required` is true: </label>
39143
+ * <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
39144
+ * <hr>
39145
+ * required error set? = <code>{{form.input.$error.required}}</code><br>
39146
+ * model = <code>{{model}}</code>
39147
+ * </form>
39148
+ * </div>
39149
+ * </file>
39150
+ * <file name="protractor.js" type="protractor">
39151
+ var required = element(by.binding('form.input.$error.required'));
39152
+ var model = element(by.binding('model'));
39153
+ var input = element(by.id('input'));
39154
+
39155
+ it('should set the required error', function() {
39156
+ expect(required.getText()).toContain('true');
39157
+
39158
+ input.sendKeys('123');
39159
+ expect(required.getText()).not.toContain('true');
39160
+ expect(model.getText()).toContain('123');
39161
+ });
39162
+ * </file>
39163
+ * </example>
39164
+ */
37973
39165
  var requiredDirective = function() {
37974
39166
  return {
37975
39167
  restrict: 'A',
@@ -37989,7 +39181,81 @@ var requiredDirective = function() {
37989
39181
  };
37990
39182
  };
37991
39183
 
39184
+ /**
39185
+ * @ngdoc directive
39186
+ * @name ngPattern
39187
+ *
39188
+ * @description
39189
+ *
39190
+ * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39191
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39192
+ *
39193
+ * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39194
+ * does not match a RegExp which is obtained by evaluating the Angular expression given in the
39195
+ * `ngPattern` attribute value:
39196
+ * * If the expression evaluates to a RegExp object, then this is used directly.
39197
+ * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
39198
+ * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
39199
+ *
39200
+ * <div class="alert alert-info">
39201
+ * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
39202
+ * start at the index of the last search's match, thus not taking the whole input value into
39203
+ * account.
39204
+ * </div>
39205
+ *
39206
+ * <div class="alert alert-info">
39207
+ * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
39208
+ * differences:
39209
+ * <ol>
39210
+ * <li>
39211
+ * `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
39212
+ * not available.
39213
+ * </li>
39214
+ * <li>
39215
+ * The `ngPattern` attribute must be an expression, while the `pattern` value must be
39216
+ * interpolated.
39217
+ * </li>
39218
+ * </ol>
39219
+ * </div>
39220
+ *
39221
+ * @example
39222
+ * <example name="ngPatternDirective" module="ngPatternExample">
39223
+ * <file name="index.html">
39224
+ * <script>
39225
+ * angular.module('ngPatternExample', [])
39226
+ * .controller('ExampleController', ['$scope', function($scope) {
39227
+ * $scope.regex = '\\d+';
39228
+ * }]);
39229
+ * </script>
39230
+ * <div ng-controller="ExampleController">
39231
+ * <form name="form">
39232
+ * <label for="regex">Set a pattern (regex string): </label>
39233
+ * <input type="text" ng-model="regex" id="regex" />
39234
+ * <br>
39235
+ * <label for="input">This input is restricted by the current pattern: </label>
39236
+ * <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
39237
+ * <hr>
39238
+ * input valid? = <code>{{form.input.$valid}}</code><br>
39239
+ * model = <code>{{model}}</code>
39240
+ * </form>
39241
+ * </div>
39242
+ * </file>
39243
+ * <file name="protractor.js" type="protractor">
39244
+ var model = element(by.binding('model'));
39245
+ var input = element(by.id('input'));
39246
+
39247
+ it('should validate the input with the default pattern', function() {
39248
+ input.sendKeys('aaa');
39249
+ expect(model.getText()).not.toContain('aaa');
37992
39250
 
39251
+ input.clear().then(function() {
39252
+ input.sendKeys('123');
39253
+ expect(model.getText()).toContain('123');
39254
+ });
39255
+ });
39256
+ * </file>
39257
+ * </example>
39258
+ */
37993
39259
  var patternDirective = function() {
37994
39260
  return {
37995
39261
  restrict: 'A',
@@ -38021,7 +39287,72 @@ var patternDirective = function() {
38021
39287
  };
38022
39288
  };
38023
39289
 
39290
+ /**
39291
+ * @ngdoc directive
39292
+ * @name ngMaxlength
39293
+ *
39294
+ * @description
39295
+ *
39296
+ * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39297
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39298
+ *
39299
+ * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39300
+ * is longer than the integer obtained by evaluating the Angular expression given in the
39301
+ * `ngMaxlength` attribute value.
39302
+ *
39303
+ * <div class="alert alert-info">
39304
+ * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
39305
+ * differences:
39306
+ * <ol>
39307
+ * <li>
39308
+ * `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
39309
+ * validation is not available.
39310
+ * </li>
39311
+ * <li>
39312
+ * The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
39313
+ * interpolated.
39314
+ * </li>
39315
+ * </ol>
39316
+ * </div>
39317
+ *
39318
+ * @example
39319
+ * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
39320
+ * <file name="index.html">
39321
+ * <script>
39322
+ * angular.module('ngMaxlengthExample', [])
39323
+ * .controller('ExampleController', ['$scope', function($scope) {
39324
+ * $scope.maxlength = 5;
39325
+ * }]);
39326
+ * </script>
39327
+ * <div ng-controller="ExampleController">
39328
+ * <form name="form">
39329
+ * <label for="maxlength">Set a maxlength: </label>
39330
+ * <input type="number" ng-model="maxlength" id="maxlength" />
39331
+ * <br>
39332
+ * <label for="input">This input is restricted by the current maxlength: </label>
39333
+ * <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
39334
+ * <hr>
39335
+ * input valid? = <code>{{form.input.$valid}}</code><br>
39336
+ * model = <code>{{model}}</code>
39337
+ * </form>
39338
+ * </div>
39339
+ * </file>
39340
+ * <file name="protractor.js" type="protractor">
39341
+ var model = element(by.binding('model'));
39342
+ var input = element(by.id('input'));
39343
+
39344
+ it('should validate the input with the default maxlength', function() {
39345
+ input.sendKeys('abcdef');
39346
+ expect(model.getText()).not.toContain('abcdef');
38024
39347
 
39348
+ input.clear().then(function() {
39349
+ input.sendKeys('abcde');
39350
+ expect(model.getText()).toContain('abcde');
39351
+ });
39352
+ });
39353
+ * </file>
39354
+ * </example>
39355
+ */
38025
39356
  var maxlengthDirective = function() {
38026
39357
  return {
38027
39358
  restrict: 'A',
@@ -38042,6 +39373,70 @@ var maxlengthDirective = function() {
38042
39373
  };
38043
39374
  };
38044
39375
 
39376
+ /**
39377
+ * @ngdoc directive
39378
+ * @name ngMinlength
39379
+ *
39380
+ * @description
39381
+ *
39382
+ * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39383
+ * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39384
+ *
39385
+ * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39386
+ * is shorter than the integer obtained by evaluating the Angular expression given in the
39387
+ * `ngMinlength` attribute value.
39388
+ *
39389
+ * <div class="alert alert-info">
39390
+ * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
39391
+ * differences:
39392
+ * <ol>
39393
+ * <li>
39394
+ * `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
39395
+ * validation is not available.
39396
+ * </li>
39397
+ * <li>
39398
+ * The `ngMinlength` value must be an expression, while the `minlength` value must be
39399
+ * interpolated.
39400
+ * </li>
39401
+ * </ol>
39402
+ * </div>
39403
+ *
39404
+ * @example
39405
+ * <example name="ngMinlengthDirective" module="ngMinlengthExample">
39406
+ * <file name="index.html">
39407
+ * <script>
39408
+ * angular.module('ngMinlengthExample', [])
39409
+ * .controller('ExampleController', ['$scope', function($scope) {
39410
+ * $scope.minlength = 3;
39411
+ * }]);
39412
+ * </script>
39413
+ * <div ng-controller="ExampleController">
39414
+ * <form name="form">
39415
+ * <label for="minlength">Set a minlength: </label>
39416
+ * <input type="number" ng-model="minlength" id="minlength" />
39417
+ * <br>
39418
+ * <label for="input">This input is restricted by the current minlength: </label>
39419
+ * <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
39420
+ * <hr>
39421
+ * input valid? = <code>{{form.input.$valid}}</code><br>
39422
+ * model = <code>{{model}}</code>
39423
+ * </form>
39424
+ * </div>
39425
+ * </file>
39426
+ * <file name="protractor.js" type="protractor">
39427
+ var model = element(by.binding('model'));
39428
+ var input = element(by.id('input'));
39429
+
39430
+ it('should validate the input with the default minlength', function() {
39431
+ input.sendKeys('ab');
39432
+ expect(model.getText()).not.toContain('ab');
39433
+
39434
+ input.sendKeys('abc');
39435
+ expect(model.getText()).toContain('abc');
39436
+ });
39437
+ * </file>
39438
+ * </example>
39439
+ */
38045
39440
  var minlengthDirective = function() {
38046
39441
  return {
38047
39442
  restrict: 'A',
@@ -38154,6 +39549,20 @@ $provide.value("$locale", {
38154
39549
  "Nov",
38155
39550
  "Dec"
38156
39551
  ],
39552
+ "STANDALONEMONTH": [
39553
+ "January",
39554
+ "February",
39555
+ "March",
39556
+ "April",
39557
+ "May",
39558
+ "June",
39559
+ "July",
39560
+ "August",
39561
+ "September",
39562
+ "October",
39563
+ "November",
39564
+ "December"
39565
+ ],
38157
39566
  "WEEKENDRANGE": [
38158
39567
  5,
38159
39568
  6
@@ -38197,6 +39606,7 @@ $provide.value("$locale", {
38197
39606
  ]
38198
39607
  },
38199
39608
  "id": "en-us",
39609
+ "localeID": "en_US",
38200
39610
  "pluralCat": function(n, opt_precision) { var i = n | 0; var vf = getVF(n, opt_precision); if (i == 1 && vf.v == 0) { return PLURAL_CATEGORY.ONE; } return PLURAL_CATEGORY.OTHER;}
38201
39611
  });
38202
39612
  }]);