angularjs-rails 1.4.8 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }]);