· 8 years ago · Jan 03, 2018, 01:44 PM
1'use strict';
2
3/* We need to tell ESLint what variables are being exported */
4/* exported
5 angular,
6 msie,
7 jqLite,
8 jQuery,
9 slice,
10 splice,
11 push,
12 toString,
13 minErrConfig,
14 errorHandlingConfig,
15 isValidObjectMaxDepth,
16 ngMinErr,
17 angularModule,
18 uid,
19 REGEX_STRING_REGEXP,
20 VALIDITY_STATE_PROPERTY,
21
22 lowercase,
23 uppercase,
24 manualLowercase,
25 manualUppercase,
26 nodeName_,
27 isArrayLike,
28 forEach,
29 forEachSorted,
30 reverseParams,
31 nextUid,
32 setHashKey,
33 extend,
34 toInt,
35 inherit,
36 merge,
37 noop,
38 identity,
39 valueFn,
40 isUndefined,
41 isDefined,
42 isObject,
43 isBlankObject,
44 isString,
45 isNumber,
46 isNumberNaN,
47 isDate,
48 isError,
49 isArray,
50 isFunction,
51 isRegExp,
52 isWindow,
53 isScope,
54 isFile,
55 isFormData,
56 isBlob,
57 isBoolean,
58 isPromiseLike,
59 trim,
60 escapeForRegexp,
61 isElement,
62 makeMap,
63 includes,
64 arrayRemove,
65 copy,
66 simpleCompare,
67 equals,
68 csp,
69 jq,
70 concat,
71 sliceArgs,
72 bind,
73 toJsonReplacer,
74 toJson,
75 fromJson,
76 convertTimezoneToLocal,
77 timezoneToOffset,
78 startingTag,
79 tryDecodeURIComponent,
80 parseKeyValue,
81 toKeyValue,
82 encodeUriSegment,
83 encodeUriQuery,
84 angularInit,
85 bootstrap,
86 getTestability,
87 snake_case,
88 bindJQuery,
89 assertArg,
90 assertArgFn,
91 assertNotHasOwnProperty,
92 getter,
93 getBlockNodes,
94 hasOwnProperty,
95 createMap,
96 stringify,
97
98 NODE_TYPE_ELEMENT,
99 NODE_TYPE_ATTRIBUTE,
100 NODE_TYPE_TEXT,
101 NODE_TYPE_COMMENT,
102 NODE_TYPE_DOCUMENT,
103 NODE_TYPE_DOCUMENT_FRAGMENT
104*/
105
106////////////////////////////////////
107
108/**
109 * @ngdoc module
110 * @name ng
111 * @module ng
112 * @installation
113 * @description
114 *
115 * The ng module is loaded by default when an AngularJS application is started. The module itself
116 * contains the essential components for an AngularJS application to function. The table below
117 * lists a high level breakdown of each of the services/factories, filters, directives and testing
118 * components available within this core module.
119 *
120 */
121
122var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
123
124// The name of a form control's ValidityState property.
125// This is used so that it's possible for internal tests to create mock ValidityStates.
126var VALIDITY_STATE_PROPERTY = 'validity';
127
128
129var hasOwnProperty = Object.prototype.hasOwnProperty;
130
131/**
132 * @private
133 *
134 * @description Converts the specified string to lowercase.
135 * @param {string} string String to be converted to lowercase.
136 * @returns {string} Lowercased string.
137 */
138var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
139
140/**
141 * @private
142 *
143 * @description Converts the specified string to uppercase.
144 * @param {string} string String to be converted to uppercase.
145 * @returns {string} Uppercased string.
146 */
147var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
148
149
150var manualLowercase = function(s) {
151 /* eslint-disable no-bitwise */
152 return isString(s)
153 ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
154 : s;
155 /* eslint-enable */
156};
157var manualUppercase = function(s) {
158 /* eslint-disable no-bitwise */
159 return isString(s)
160 ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
161 : s;
162 /* eslint-enable */
163};
164
165
166// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
167// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
168// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
169if ('i' !== 'I'.toLowerCase()) {
170 lowercase = manualLowercase;
171 uppercase = manualUppercase;
172}
173
174
175var
176 msie, // holds major version number for IE, or NaN if UA is not IE.
177 jqLite, // delay binding since jQuery could be loaded after us.
178 jQuery, // delay binding
179 slice = [].slice,
180 splice = [].splice,
181 push = [].push,
182 toString = Object.prototype.toString,
183 getPrototypeOf = Object.getPrototypeOf,
184 ngMinErr = minErr('ng'),
185
186 /** @name angular */
187 angular = window.angular || (window.angular = {}),
188 angularModule,
189 uid = 0;
190
191// Support: IE 9-11 only
192/**
193 * documentMode is an IE-only property
194 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
195 */
196msie = window.document.documentMode;
197
198
199/**
200 * @private
201 * @param {*} obj
202 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
203 * String ...)
204 */
205function isArrayLike(obj) {
206
207 // `null`, `undefined` and `window` are not array-like
208 if (obj == null || isWindow(obj)) return false;
209
210 // arrays, strings and jQuery/jqLite objects are array like
211 // * jqLite is either the jQuery or jqLite constructor function
212 // * we have to check the existence of jqLite first as this method is called
213 // via the forEach method when constructing the jqLite object in the first place
214 if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
215
216 // Support: iOS 8.2 (not reproducible in simulator)
217 // "length" in obj used to prevent JIT error (gh-11508)
218 var length = 'length' in Object(obj) && obj.length;
219
220 // NodeList objects (with `item` method) and
221 // other objects with suitable length characteristics are array-like
222 return isNumber(length) &&
223 (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item === 'function');
224
225}
226
227/**
228 * @ngdoc function
229 * @name angular.forEach
230 * @module ng
231 * @kind function
232 *
233 * @description
234 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
235 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
236 * is the value of an object property or an array element, `key` is the object property key or
237 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
238 *
239 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
240 * using the `hasOwnProperty` method.
241 *
242 * Unlike ES262's
243 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
244 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
245 * return the value provided.
246 *
247 ```js
248 var values = {name: 'misko', gender: 'male'};
249 var log = [];
250 angular.forEach(values, function(value, key) {
251 this.push(key + ': ' + value);
252 }, log);
253 expect(log).toEqual(['name: misko', 'gender: male']);
254 ```
255 *
256 * @param {Object|Array} obj Object to iterate over.
257 * @param {Function} iterator Iterator function.
258 * @param {Object=} context Object to become context (`this`) for the iterator function.
259 * @returns {Object|Array} Reference to `obj`.
260 */
261
262function forEach(obj, iterator, context) {
263 var key, length;
264 if (obj) {
265 if (isFunction(obj)) {
266 for (key in obj) {
267 if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
268 iterator.call(context, obj[key], key, obj);
269 }
270 }
271 } else if (isArray(obj) || isArrayLike(obj)) {
272 var isPrimitive = typeof obj !== 'object';
273 for (key = 0, length = obj.length; key < length; key++) {
274 if (isPrimitive || key in obj) {
275 iterator.call(context, obj[key], key, obj);
276 }
277 }
278 } else if (obj.forEach && obj.forEach !== forEach) {
279 obj.forEach(iterator, context, obj);
280 } else if (isBlankObject(obj)) {
281 // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
282 for (key in obj) {
283 iterator.call(context, obj[key], key, obj);
284 }
285 } else if (typeof obj.hasOwnProperty === 'function') {
286 // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
287 for (key in obj) {
288 if (obj.hasOwnProperty(key)) {
289 iterator.call(context, obj[key], key, obj);
290 }
291 }
292 } else {
293 // Slow path for objects which do not have a method `hasOwnProperty`
294 for (key in obj) {
295 if (hasOwnProperty.call(obj, key)) {
296 iterator.call(context, obj[key], key, obj);
297 }
298 }
299 }
300 }
301 return obj;
302}
303
304function forEachSorted(obj, iterator, context) {
305 var keys = Object.keys(obj).sort();
306 for (var i = 0; i < keys.length; i++) {
307 iterator.call(context, obj[keys[i]], keys[i]);
308 }
309 return keys;
310}
311
312
313/**
314 * when using forEach the params are value, key, but it is often useful to have key, value.
315 * @param {function(string, *)} iteratorFn
316 * @returns {function(*, string)}
317 */
318function reverseParams(iteratorFn) {
319 return function(value, key) {iteratorFn(key, value);};
320}
321
322/**
323 * A consistent way of creating unique IDs in angular.
324 *
325 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
326 * we hit number precision issues in JavaScript.
327 *
328 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
329 *
330 * @returns {number} an unique alpha-numeric string
331 */
332function nextUid() {
333 return ++uid;
334}
335
336
337/**
338 * Set or clear the hashkey for an object.
339 * @param obj object
340 * @param h the hashkey (!truthy to delete the hashkey)
341 */
342function setHashKey(obj, h) {
343 if (h) {
344 obj.$$hashKey = h;
345 } else {
346 delete obj.$$hashKey;
347 }
348}
349
350
351function baseExtend(dst, objs, deep) {
352 var h = dst.$$hashKey;
353
354 for (var i = 0, ii = objs.length; i < ii; ++i) {
355 var obj = objs[i];
356 if (!isObject(obj) && !isFunction(obj)) continue;
357 var keys = Object.keys(obj);
358 for (var j = 0, jj = keys.length; j < jj; j++) {
359 var key = keys[j];
360 var src = obj[key];
361
362 if (deep && isObject(src)) {
363 if (isDate(src)) {
364 dst[key] = new Date(src.valueOf());
365 } else if (isRegExp(src)) {
366 dst[key] = new RegExp(src);
367 } else if (src.nodeName) {
368 dst[key] = src.cloneNode(true);
369 } else if (isElement(src)) {
370 dst[key] = src.clone();
371 } else {
372 if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
373 baseExtend(dst[key], [src], true);
374 }
375 } else {
376 dst[key] = src;
377 }
378 }
379 }
380
381 setHashKey(dst, h);
382 return dst;
383}
384
385/**
386 * @ngdoc function
387 * @name angular.extend
388 * @module ng
389 * @kind function
390 *
391 * @description
392 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
393 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
394 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
395 *
396 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
397 * {@link angular.merge} for this.
398 *
399 * @param {Object} dst Destination object.
400 * @param {...Object} src Source object(s).
401 * @returns {Object} Reference to `dst`.
402 */
403function extend(dst) {
404 return baseExtend(dst, slice.call(arguments, 1), false);
405}
406
407
408/**
409* @ngdoc function
410* @name angular.merge
411* @module ng
412* @kind function
413*
414* @description
415* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
416* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
417* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
418*
419* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
420* objects, performing a deep copy.
421*
422* @deprecated
423* sinceVersion="1.6.5"
424* This function is deprecated, but will not be removed in the 1.x lifecycle.
425* There are edge cases (see {@link angular.merge#known-issues known issues}) that are not
426* supported by this function. We suggest
427* using [lodash's merge()](https://lodash.com/docs/4.17.4#merge) instead.
428*
429* @knownIssue
430* This is a list of (known) object types that are not handled correctly by this function:
431* - [`Blob`](https://developer.mozilla.org/docs/Web/API/Blob)
432* - [`MediaStream`](https://developer.mozilla.org/docs/Web/API/MediaStream)
433* - [`CanvasGradient`](https://developer.mozilla.org/docs/Web/API/CanvasGradient)
434* - AngularJS {@link $rootScope.Scope scopes};
435*
436* @param {Object} dst Destination object.
437* @param {...Object} src Source object(s).
438* @returns {Object} Reference to `dst`.
439*/
440function merge(dst) {
441 return baseExtend(dst, slice.call(arguments, 1), true);
442}
443
444
445
446function toInt(str) {
447 return parseInt(str, 10);
448}
449
450var isNumberNaN = Number.isNaN || function isNumberNaN(num) {
451 // eslint-disable-next-line no-self-compare
452 return num !== num;
453};
454
455
456function inherit(parent, extra) {
457 return extend(Object.create(parent), extra);
458}
459
460/**
461 * @ngdoc function
462 * @name angular.noop
463 * @module ng
464 * @kind function
465 *
466 * @description
467 * A function that performs no operations. This function can be useful when writing code in the
468 * functional style.
469 ```js
470 function foo(callback) {
471 var result = calculateResult();
472 (callback || angular.noop)(result);
473 }
474 ```
475 */
476function noop() {}
477noop.$inject = [];
478
479
480/**
481 * @ngdoc function
482 * @name angular.identity
483 * @module ng
484 * @kind function
485 *
486 * @description
487 * A function that returns its first argument. This function is useful when writing code in the
488 * functional style.
489 *
490 ```js
491 function transformer(transformationFn, value) {
492 return (transformationFn || angular.identity)(value);
493 };
494
495 // E.g.
496 function getResult(fn, input) {
497 return (fn || angular.identity)(input);
498 };
499
500 getResult(function(n) { return n * 2; }, 21); // returns 42
501 getResult(null, 21); // returns 21
502 getResult(undefined, 21); // returns 21
503 ```
504 *
505 * @param {*} value to be returned.
506 * @returns {*} the value passed in.
507 */
508function identity($) {return $;}
509identity.$inject = [];
510
511
512function valueFn(value) {return function valueRef() {return value;};}
513
514function hasCustomToString(obj) {
515 return isFunction(obj.toString) && obj.toString !== toString;
516}
517
518
519/**
520 * @ngdoc function
521 * @name angular.isUndefined
522 * @module ng
523 * @kind function
524 *
525 * @description
526 * Determines if a reference is undefined.
527 *
528 * @param {*} value Reference to check.
529 * @returns {boolean} True if `value` is undefined.
530 */
531function isUndefined(value) {return typeof value === 'undefined';}
532
533
534/**
535 * @ngdoc function
536 * @name angular.isDefined
537 * @module ng
538 * @kind function
539 *
540 * @description
541 * Determines if a reference is defined.
542 *
543 * @param {*} value Reference to check.
544 * @returns {boolean} True if `value` is defined.
545 */
546function isDefined(value) {return typeof value !== 'undefined';}
547
548
549/**
550 * @ngdoc function
551 * @name angular.isObject
552 * @module ng
553 * @kind function
554 *
555 * @description
556 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
557 * considered to be objects. Note that JavaScript arrays are objects.
558 *
559 * @param {*} value Reference to check.
560 * @returns {boolean} True if `value` is an `Object` but not `null`.
561 */
562function isObject(value) {
563 // http://jsperf.com/isobject4
564 return value !== null && typeof value === 'object';
565}
566
567
568/**
569 * Determine if a value is an object with a null prototype
570 *
571 * @returns {boolean} True if `value` is an `Object` with a null prototype
572 */
573function isBlankObject(value) {
574 return value !== null && typeof value === 'object' && !getPrototypeOf(value);
575}
576
577
578/**
579 * @ngdoc function
580 * @name angular.isString
581 * @module ng
582 * @kind function
583 *
584 * @description
585 * Determines if a reference is a `String`.
586 *
587 * @param {*} value Reference to check.
588 * @returns {boolean} True if `value` is a `String`.
589 */
590function isString(value) {return typeof value === 'string';}
591
592
593/**
594 * @ngdoc function
595 * @name angular.isNumber
596 * @module ng
597 * @kind function
598 *
599 * @description
600 * Determines if a reference is a `Number`.
601 *
602 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
603 *
604 * If you wish to exclude these then you can use the native
605 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
606 * method.
607 *
608 * @param {*} value Reference to check.
609 * @returns {boolean} True if `value` is a `Number`.
610 */
611function isNumber(value) {return typeof value === 'number';}
612
613
614/**
615 * @ngdoc function
616 * @name angular.isDate
617 * @module ng
618 * @kind function
619 *
620 * @description
621 * Determines if a value is a date.
622 *
623 * @param {*} value Reference to check.
624 * @returns {boolean} True if `value` is a `Date`.
625 */
626function isDate(value) {
627 return toString.call(value) === '[object Date]';
628}
629
630
631/**
632 * @ngdoc function
633 * @name angular.isArray
634 * @module ng
635 * @kind function
636 *
637 * @description
638 * Determines if a reference is an `Array`. Alias of Array.isArray.
639 *
640 * @param {*} value Reference to check.
641 * @returns {boolean} True if `value` is an `Array`.
642 */
643var isArray = Array.isArray;
644
645/**
646 * @description
647 * Determines if a reference is an `Error`.
648 * Loosely based on https://www.npmjs.com/package/iserror
649 *
650 * @param {*} value Reference to check.
651 * @returns {boolean} True if `value` is an `Error`.
652 */
653function isError(value) {
654 var tag = toString.call(value);
655 switch (tag) {
656 case '[object Error]': return true;
657 case '[object Exception]': return true;
658 case '[object DOMException]': return true;
659 default: return value instanceof Error;
660 }
661}
662
663/**
664 * @ngdoc function
665 * @name angular.isFunction
666 * @module ng
667 * @kind function
668 *
669 * @description
670 * Determines if a reference is a `Function`.
671 *
672 * @param {*} value Reference to check.
673 * @returns {boolean} True if `value` is a `Function`.
674 */
675function isFunction(value) {return typeof value === 'function';}
676
677
678/**
679 * Determines if a value is a regular expression object.
680 *
681 * @private
682 * @param {*} value Reference to check.
683 * @returns {boolean} True if `value` is a `RegExp`.
684 */
685function isRegExp(value) {
686 return toString.call(value) === '[object RegExp]';
687}
688
689
690/**
691 * Checks if `obj` is a window object.
692 *
693 * @private
694 * @param {*} obj Object to check
695 * @returns {boolean} True if `obj` is a window obj.
696 */
697function isWindow(obj) {
698 return obj && obj.window === obj;
699}
700
701
702function isScope(obj) {
703 return obj && obj.$evalAsync && obj.$watch;
704}
705
706
707function isFile(obj) {
708 return toString.call(obj) === '[object File]';
709}
710
711
712function isFormData(obj) {
713 return toString.call(obj) === '[object FormData]';
714}
715
716
717function isBlob(obj) {
718 return toString.call(obj) === '[object Blob]';
719}
720
721
722function isBoolean(value) {
723 return typeof value === 'boolean';
724}
725
726
727function isPromiseLike(obj) {
728 return obj && isFunction(obj.then);
729}
730
731
732var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
733function isTypedArray(value) {
734 return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
735}
736
737function isArrayBuffer(obj) {
738 return toString.call(obj) === '[object ArrayBuffer]';
739}
740
741
742var trim = function(value) {
743 return isString(value) ? value.trim() : value;
744};
745
746// Copied from:
747// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
748// Prereq: s is a string.
749var escapeForRegexp = function(s) {
750 return s
751 .replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
752 // eslint-disable-next-line no-control-regex
753 .replace(/\x08/g, '\\x08');
754};
755
756
757/**
758 * @ngdoc function
759 * @name angular.isElement
760 * @module ng
761 * @kind function
762 *
763 * @description
764 * Determines if a reference is a DOM element (or wrapped jQuery element).
765 *
766 * @param {*} value Reference to check.
767 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
768 */
769function isElement(node) {
770 return !!(node &&
771 (node.nodeName // We are a direct element.
772 || (node.prop && node.attr && node.find))); // We have an on and find method part of jQuery API.
773}
774
775/**
776 * @param str 'key1,key2,...'
777 * @returns {object} in the form of {key1:true, key2:true, ...}
778 */
779function makeMap(str) {
780 var obj = {}, items = str.split(','), i;
781 for (i = 0; i < items.length; i++) {
782 obj[items[i]] = true;
783 }
784 return obj;
785}
786
787
788function nodeName_(element) {
789 return lowercase(element.nodeName || (element[0] && element[0].nodeName));
790}
791
792function includes(array, obj) {
793 return Array.prototype.indexOf.call(array, obj) !== -1;
794}
795
796function arrayRemove(array, value) {
797 var index = array.indexOf(value);
798 if (index >= 0) {
799 array.splice(index, 1);
800 }
801 return index;
802}
803
804/**
805 * @ngdoc function
806 * @name angular.copy
807 * @module ng
808 * @kind function
809 *
810 * @description
811 * Creates a deep copy of `source`, which should be an object or an array.
812 *
813 * * If no destination is supplied, a copy of the object or array is created.
814 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
815 * are deleted and then all elements/properties from the source are copied to it.
816 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
817 * * If `source` is identical to `destination` an exception will be thrown.
818 *
819 * <br />
820 * <div class="alert alert-warning">
821 * Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
822 * and on `destination`) will be ignored.
823 * </div>
824 *
825 * @param {*} source The source that will be used to make a copy.
826 * Can be any type, including primitives, `null`, and `undefined`.
827 * @param {(Object|Array)=} destination Destination into which the source is copied. If
828 * provided, must be of the same type as `source`.
829 * @returns {*} The copy or updated `destination`, if `destination` was specified.
830 *
831 * @example
832 <example module="copyExample" name="angular-copy">
833 <file name="index.html">
834 <div ng-controller="ExampleController">
835 <form novalidate class="simple-form">
836 <label>Name: <input type="text" ng-model="user.name" /></label><br />
837 <label>Age: <input type="number" ng-model="user.age" /></label><br />
838 Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
839 <label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
840 <button ng-click="reset()">RESET</button>
841 <button ng-click="update(user)">SAVE</button>
842 </form>
843 <pre>form = {{user | json}}</pre>
844 <pre>leader = {{leader | json}}</pre>
845 </div>
846 </file>
847 <file name="script.js">
848 // Module: copyExample
849 angular.
850 module('copyExample', []).
851 controller('ExampleController', ['$scope', function($scope) {
852 $scope.leader = {};
853
854 $scope.reset = function() {
855 // Example with 1 argument
856 $scope.user = angular.copy($scope.leader);
857 };
858
859 $scope.update = function(user) {
860 // Example with 2 arguments
861 angular.copy(user, $scope.leader);
862 };
863
864 $scope.reset();
865 }]);
866 </file>
867 </example>
868 */
869function copy(source, destination, maxDepth) {
870 var stackSource = [];
871 var stackDest = [];
872 maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
873
874 if (destination) {
875 if (isTypedArray(destination) || isArrayBuffer(destination)) {
876 throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.');
877 }
878 if (source === destination) {
879 throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.');
880 }
881
882 // Empty the destination object
883 if (isArray(destination)) {
884 destination.length = 0;
885 } else {
886 forEach(destination, function(value, key) {
887 if (key !== '$$hashKey') {
888 delete destination[key];
889 }
890 });
891 }
892
893 stackSource.push(source);
894 stackDest.push(destination);
895 return copyRecurse(source, destination, maxDepth);
896 }
897
898 return copyElement(source, maxDepth);
899
900 function copyRecurse(source, destination, maxDepth) {
901 maxDepth--;
902 if (maxDepth < 0) {
903 return '...';
904 }
905 var h = destination.$$hashKey;
906 var key;
907 if (isArray(source)) {
908 for (var i = 0, ii = source.length; i < ii; i++) {
909 destination.push(copyElement(source[i], maxDepth));
910 }
911 } else if (isBlankObject(source)) {
912 // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
913 for (key in source) {
914 destination[key] = copyElement(source[key], maxDepth);
915 }
916 } else if (source && typeof source.hasOwnProperty === 'function') {
917 // Slow path, which must rely on hasOwnProperty
918 for (key in source) {
919 if (source.hasOwnProperty(key)) {
920 destination[key] = copyElement(source[key], maxDepth);
921 }
922 }
923 } else {
924 // Slowest path --- hasOwnProperty can't be called as a method
925 for (key in source) {
926 if (hasOwnProperty.call(source, key)) {
927 destination[key] = copyElement(source[key], maxDepth);
928 }
929 }
930 }
931 setHashKey(destination, h);
932 return destination;
933 }
934
935 function copyElement(source, maxDepth) {
936 // Simple values
937 if (!isObject(source)) {
938 return source;
939 }
940
941 // Already copied values
942 var index = stackSource.indexOf(source);
943 if (index !== -1) {
944 return stackDest[index];
945 }
946
947 if (isWindow(source) || isScope(source)) {
948 throw ngMinErr('cpws',
949 'Can\'t copy! Making copies of Window or Scope instances is not supported.');
950 }
951
952 var needsRecurse = false;
953 var destination = copyType(source);
954
955 if (destination === undefined) {
956 destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
957 needsRecurse = true;
958 }
959
960 stackSource.push(source);
961 stackDest.push(destination);
962
963 return needsRecurse
964 ? copyRecurse(source, destination, maxDepth)
965 : destination;
966 }
967
968 function copyType(source) {
969 switch (toString.call(source)) {
970 case '[object Int8Array]':
971 case '[object Int16Array]':
972 case '[object Int32Array]':
973 case '[object Float32Array]':
974 case '[object Float64Array]':
975 case '[object Uint8Array]':
976 case '[object Uint8ClampedArray]':
977 case '[object Uint16Array]':
978 case '[object Uint32Array]':
979 return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
980
981 case '[object ArrayBuffer]':
982 // Support: IE10
983 if (!source.slice) {
984 // If we're in this case we know the environment supports ArrayBuffer
985 /* eslint-disable no-undef */
986 var copied = new ArrayBuffer(source.byteLength);
987 new Uint8Array(copied).set(new Uint8Array(source));
988 /* eslint-enable */
989 return copied;
990 }
991 return source.slice(0);
992
993 case '[object Boolean]':
994 case '[object Number]':
995 case '[object String]':
996 case '[object Date]':
997 return new source.constructor(source.valueOf());
998
999 case '[object RegExp]':
1000 var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
1001 re.lastIndex = source.lastIndex;
1002 return re;
1003
1004 case '[object Blob]':
1005 return new source.constructor([source], {type: source.type});
1006 }
1007
1008 if (isFunction(source.cloneNode)) {
1009 return source.cloneNode(true);
1010 }
1011 }
1012}
1013
1014
1015// eslint-disable-next-line no-self-compare
1016function simpleCompare(a, b) { return a === b || (a !== a && b !== b); }
1017
1018
1019/**
1020 * @ngdoc function
1021 * @name angular.equals
1022 * @module ng
1023 * @kind function
1024 *
1025 * @description
1026 * Determines if two objects or two values are equivalent. Supports value types, regular
1027 * expressions, arrays and objects.
1028 *
1029 * Two objects or values are considered equivalent if at least one of the following is true:
1030 *
1031 * * Both objects or values pass `===` comparison.
1032 * * Both objects or values are of the same type and all of their properties are equal by
1033 * comparing them with `angular.equals`.
1034 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1035 * * Both values represent the same regular expression (In JavaScript,
1036 * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1037 * representation matches).
1038 *
1039 * During a property comparison, properties of `function` type and properties with names
1040 * that begin with `$` are ignored.
1041 *
1042 * Scope and DOMWindow objects are being compared only by identify (`===`).
1043 *
1044 * @param {*} o1 Object or value to compare.
1045 * @param {*} o2 Object or value to compare.
1046 * @returns {boolean} True if arguments are equal.
1047 *
1048 * @example
1049 <example module="equalsExample" name="equalsExample">
1050 <file name="index.html">
1051 <div ng-controller="ExampleController">
1052 <form novalidate>
1053 <h3>User 1</h3>
1054 Name: <input type="text" ng-model="user1.name">
1055 Age: <input type="number" ng-model="user1.age">
1056
1057 <h3>User 2</h3>
1058 Name: <input type="text" ng-model="user2.name">
1059 Age: <input type="number" ng-model="user2.age">
1060
1061 <div>
1062 <br/>
1063 <input type="button" value="Compare" ng-click="compare()">
1064 </div>
1065 User 1: <pre>{{user1 | json}}</pre>
1066 User 2: <pre>{{user2 | json}}</pre>
1067 Equal: <pre>{{result}}</pre>
1068 </form>
1069 </div>
1070 </file>
1071 <file name="script.js">
1072 angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
1073 $scope.user1 = {};
1074 $scope.user2 = {};
1075 $scope.compare = function() {
1076 $scope.result = angular.equals($scope.user1, $scope.user2);
1077 };
1078 }]);
1079 </file>
1080 </example>
1081 */
1082function equals(o1, o2) {
1083 if (o1 === o2) return true;
1084 if (o1 === null || o2 === null) return false;
1085 // eslint-disable-next-line no-self-compare
1086 if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1087 var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1088 if (t1 === t2 && t1 === 'object') {
1089 if (isArray(o1)) {
1090 if (!isArray(o2)) return false;
1091 if ((length = o1.length) === o2.length) {
1092 for (key = 0; key < length; key++) {
1093 if (!equals(o1[key], o2[key])) return false;
1094 }
1095 return true;
1096 }
1097 } else if (isDate(o1)) {
1098 if (!isDate(o2)) return false;
1099 return simpleCompare(o1.getTime(), o2.getTime());
1100 } else if (isRegExp(o1)) {
1101 if (!isRegExp(o2)) return false;
1102 return o1.toString() === o2.toString();
1103 } else {
1104 if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1105 isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1106 keySet = createMap();
1107 for (key in o1) {
1108 if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1109 if (!equals(o1[key], o2[key])) return false;
1110 keySet[key] = true;
1111 }
1112 for (key in o2) {
1113 if (!(key in keySet) &&
1114 key.charAt(0) !== '$' &&
1115 isDefined(o2[key]) &&
1116 !isFunction(o2[key])) return false;
1117 }
1118 return true;
1119 }
1120 }
1121 return false;
1122}
1123
1124var csp = function() {
1125 if (!isDefined(csp.rules)) {
1126
1127
1128 var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1129 window.document.querySelector('[data-ng-csp]'));
1130
1131 if (ngCspElement) {
1132 var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1133 ngCspElement.getAttribute('data-ng-csp');
1134 csp.rules = {
1135 noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1136 noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1137 };
1138 } else {
1139 csp.rules = {
1140 noUnsafeEval: noUnsafeEval(),
1141 noInlineStyle: false
1142 };
1143 }
1144 }
1145
1146 return csp.rules;
1147
1148 function noUnsafeEval() {
1149 try {
1150 // eslint-disable-next-line no-new, no-new-func
1151 new Function('');
1152 return false;
1153 } catch (e) {
1154 return true;
1155 }
1156 }
1157};
1158
1159/**
1160 * @ngdoc directive
1161 * @module ng
1162 * @name ngJq
1163 *
1164 * @element ANY
1165 * @param {string=} ngJq the name of the library available under `window`
1166 * to be used for angular.element
1167 * @description
1168 * Use this directive to force the angular.element library. This should be
1169 * used to force either jqLite by leaving ng-jq blank or setting the name of
1170 * the jquery variable under window (eg. jQuery).
1171 *
1172 * Since AngularJS looks for this directive when it is loaded (doesn't wait for the
1173 * DOMContentLoaded event), it must be placed on an element that comes before the script
1174 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1175 * others ignored.
1176 *
1177 * @example
1178 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1179 ```html
1180 <!doctype html>
1181 <html ng-app ng-jq>
1182 ...
1183 ...
1184 </html>
1185 ```
1186 * @example
1187 * This example shows how to use a jQuery based library of a different name.
1188 * The library name must be available at the top most 'window'.
1189 ```html
1190 <!doctype html>
1191 <html ng-app ng-jq="jQueryLib">
1192 ...
1193 ...
1194 </html>
1195 ```
1196 */
1197var jq = function() {
1198 if (isDefined(jq.name_)) return jq.name_;
1199 var el;
1200 var i, ii = ngAttrPrefixes.length, prefix, name;
1201 for (i = 0; i < ii; ++i) {
1202 prefix = ngAttrPrefixes[i];
1203 el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]');
1204 if (el) {
1205 name = el.getAttribute(prefix + 'jq');
1206 break;
1207 }
1208 }
1209
1210 return (jq.name_ = name);
1211};
1212
1213function concat(array1, array2, index) {
1214 return array1.concat(slice.call(array2, index));
1215}
1216
1217function sliceArgs(args, startIndex) {
1218 return slice.call(args, startIndex || 0);
1219}
1220
1221
1222/**
1223 * @ngdoc function
1224 * @name angular.bind
1225 * @module ng
1226 * @kind function
1227 *
1228 * @description
1229 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1230 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1231 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1232 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1233 *
1234 * @param {Object} self Context which `fn` should be evaluated in.
1235 * @param {function()} fn Function to be bound.
1236 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1237 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1238 */
1239function bind(self, fn) {
1240 var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1241 if (isFunction(fn) && !(fn instanceof RegExp)) {
1242 return curryArgs.length
1243 ? function() {
1244 return arguments.length
1245 ? fn.apply(self, concat(curryArgs, arguments, 0))
1246 : fn.apply(self, curryArgs);
1247 }
1248 : function() {
1249 return arguments.length
1250 ? fn.apply(self, arguments)
1251 : fn.call(self);
1252 };
1253 } else {
1254 // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
1255 return fn;
1256 }
1257}
1258
1259
1260function toJsonReplacer(key, value) {
1261 var val = value;
1262
1263 if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1264 val = undefined;
1265 } else if (isWindow(value)) {
1266 val = '$WINDOW';
1267 } else if (value && window.document === value) {
1268 val = '$DOCUMENT';
1269 } else if (isScope(value)) {
1270 val = '$SCOPE';
1271 }
1272
1273 return val;
1274}
1275
1276
1277/**
1278 * @ngdoc function
1279 * @name angular.toJson
1280 * @module ng
1281 * @kind function
1282 *
1283 * @description
1284 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1285 * stripped since AngularJS uses this notation internally.
1286 *
1287 * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON.
1288 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1289 * If set to an integer, the JSON output will contain that many spaces per indentation.
1290 * @returns {string|undefined} JSON-ified string representing `obj`.
1291 * @knownIssue
1292 *
1293 * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
1294 * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
1295 * `Date.prototype.toJSON` method as follows:
1296 *
1297 * ```
1298 * var _DatetoJSON = Date.prototype.toJSON;
1299 * Date.prototype.toJSON = function() {
1300 * try {
1301 * return _DatetoJSON.call(this);
1302 * } catch(e) {
1303 * if (e instanceof RangeError) {
1304 * return null;
1305 * }
1306 * throw e;
1307 * }
1308 * };
1309 * ```
1310 *
1311 * See https://github.com/angular/angular.js/pull/14221 for more information.
1312 */
1313function toJson(obj, pretty) {
1314 if (isUndefined(obj)) return undefined;
1315 if (!isNumber(pretty)) {
1316 pretty = pretty ? 2 : null;
1317 }
1318 return JSON.stringify(obj, toJsonReplacer, pretty);
1319}
1320
1321
1322/**
1323 * @ngdoc function
1324 * @name angular.fromJson
1325 * @module ng
1326 * @kind function
1327 *
1328 * @description
1329 * Deserializes a JSON string.
1330 *
1331 * @param {string} json JSON string to deserialize.
1332 * @returns {Object|Array|string|number} Deserialized JSON string.
1333 */
1334function fromJson(json) {
1335 return isString(json)
1336 ? JSON.parse(json)
1337 : json;
1338}
1339
1340
1341var ALL_COLONS = /:/g;
1342function timezoneToOffset(timezone, fallback) {
1343 // Support: IE 9-11 only, Edge 13-15+
1344 // IE/Edge do not "understand" colon (`:`) in timezone
1345 timezone = timezone.replace(ALL_COLONS, '');
1346 var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1347 return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1348}
1349
1350
1351function addDateMinutes(date, minutes) {
1352 date = new Date(date.getTime());
1353 date.setMinutes(date.getMinutes() + minutes);
1354 return date;
1355}
1356
1357
1358function convertTimezoneToLocal(date, timezone, reverse) {
1359 reverse = reverse ? -1 : 1;
1360 var dateTimezoneOffset = date.getTimezoneOffset();
1361 var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1362 return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
1363}
1364
1365
1366/**
1367 * @returns {string} Returns the string representation of the element.
1368 */
1369function startingTag(element) {
1370 element = jqLite(element).clone().empty();
1371 var elemHtml = jqLite('<div>').append(element).html();
1372 try {
1373 return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1374 elemHtml.
1375 match(/^(<[^>]+>)/)[1].
1376 replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
1377 } catch (e) {
1378 return lowercase(elemHtml);
1379 }
1380
1381}
1382
1383
1384/////////////////////////////////////////////////
1385
1386/**
1387 * Tries to decode the URI component without throwing an exception.
1388 *
1389 * @private
1390 * @param str value potential URI component to check.
1391 * @returns {boolean} True if `value` can be decoded
1392 * with the decodeURIComponent function.
1393 */
1394function tryDecodeURIComponent(value) {
1395 try {
1396 return decodeURIComponent(value);
1397 } catch (e) {
1398 // Ignore any invalid uri component.
1399 }
1400}
1401
1402
1403/**
1404 * Parses an escaped url query string into key-value pairs.
1405 * @returns {Object.<string,boolean|Array>}
1406 */
1407function parseKeyValue(/**string*/keyValue) {
1408 var obj = {};
1409 forEach((keyValue || '').split('&'), function(keyValue) {
1410 var splitPoint, key, val;
1411 if (keyValue) {
1412 key = keyValue = keyValue.replace(/\+/g,'%20');
1413 splitPoint = keyValue.indexOf('=');
1414 if (splitPoint !== -1) {
1415 key = keyValue.substring(0, splitPoint);
1416 val = keyValue.substring(splitPoint + 1);
1417 }
1418 key = tryDecodeURIComponent(key);
1419 if (isDefined(key)) {
1420 val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1421 if (!hasOwnProperty.call(obj, key)) {
1422 obj[key] = val;
1423 } else if (isArray(obj[key])) {
1424 obj[key].push(val);
1425 } else {
1426 obj[key] = [obj[key],val];
1427 }
1428 }
1429 }
1430 });
1431 return obj;
1432}
1433
1434function toKeyValue(obj) {
1435 var parts = [];
1436 forEach(obj, function(value, key) {
1437 if (isArray(value)) {
1438 forEach(value, function(arrayValue) {
1439 parts.push(encodeUriQuery(key, true) +
1440 (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1441 });
1442 } else {
1443 parts.push(encodeUriQuery(key, true) +
1444 (value === true ? '' : '=' + encodeUriQuery(value, true)));
1445 }
1446 });
1447 return parts.length ? parts.join('&') : '';
1448}
1449
1450
1451/**
1452 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1453 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1454 * segments:
1455 * segment = *pchar
1456 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
1457 * pct-encoded = "%" HEXDIG HEXDIG
1458 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1459 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1460 * / "*" / "+" / "," / ";" / "="
1461 */
1462function encodeUriSegment(val) {
1463 return encodeUriQuery(val, true).
1464 replace(/%26/gi, '&').
1465 replace(/%3D/gi, '=').
1466 replace(/%2B/gi, '+');
1467}
1468
1469
1470/**
1471 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1472 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1473 * encoded per http://tools.ietf.org/html/rfc3986:
1474 * query = *( pchar / "/" / "?" )
1475 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
1476 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1477 * pct-encoded = "%" HEXDIG HEXDIG
1478 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1479 * / "*" / "+" / "," / ";" / "="
1480 */
1481function encodeUriQuery(val, pctEncodeSpaces) {
1482 return encodeURIComponent(val).
1483 replace(/%40/gi, '@').
1484 replace(/%3A/gi, ':').
1485 replace(/%24/g, '$').
1486 replace(/%2C/gi, ',').
1487 replace(/%3B/gi, ';').
1488 replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1489}
1490
1491var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1492
1493function getNgAttribute(element, ngAttr) {
1494 var attr, i, ii = ngAttrPrefixes.length;
1495 for (i = 0; i < ii; ++i) {
1496 attr = ngAttrPrefixes[i] + ngAttr;
1497 if (isString(attr = element.getAttribute(attr))) {
1498 return attr;
1499 }
1500 }
1501 return null;
1502}
1503
1504function allowAutoBootstrap(document) {
1505 var script = document.currentScript;
1506
1507 if (!script) {
1508 // Support: IE 9-11 only
1509 // IE does not have `document.currentScript`
1510 return true;
1511 }
1512
1513 // If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
1514 if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
1515 return false;
1516 }
1517
1518 var attributes = script.attributes;
1519 var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
1520
1521 return srcs.every(function(src) {
1522 if (!src) {
1523 return true;
1524 }
1525 if (!src.value) {
1526 return false;
1527 }
1528
1529 var link = document.createElement('a');
1530 link.href = src.value;
1531
1532 if (document.location.origin === link.origin) {
1533 // Same-origin resources are always allowed, even for non-whitelisted schemes.
1534 return true;
1535 }
1536 // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
1537 // This is to prevent angular.js bundled with browser extensions from being used to bypass the
1538 // content security policy in web pages and other browser extensions.
1539 switch (link.protocol) {
1540 case 'http:':
1541 case 'https:':
1542 case 'ftp:':
1543 case 'blob:':
1544 case 'file:':
1545 case 'data:':
1546 return true;
1547 default:
1548 return false;
1549 }
1550 });
1551}
1552
1553// Cached as it has to run during loading so that document.currentScript is available.
1554var isAutoBootstrapAllowed = allowAutoBootstrap(window.document);
1555
1556/**
1557 * @ngdoc directive
1558 * @name ngApp
1559 * @module ng
1560 *
1561 * @element ANY
1562 * @param {angular.Module} ngApp an optional application
1563 * {@link angular.module module} name to load.
1564 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1565 * created in "strict-di" mode. This means that the application will fail to invoke functions which
1566 * do not use explicit function annotation (and are thus unsuitable for minification), as described
1567 * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1568 * tracking down the root of these bugs.
1569 *
1570 * @description
1571 *
1572 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1573 * designates the **root element** of the application and is typically placed near the root element
1574 * of the page - e.g. on the `<body>` or `<html>` tags.
1575 *
1576 * There are a few things to keep in mind when using `ngApp`:
1577 * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1578 * found in the document will be used to define the root element to auto-bootstrap as an
1579 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1580 * {@link angular.bootstrap} instead.
1581 * - AngularJS applications cannot be nested within each other.
1582 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
1583 * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
1584 * {@link ngRoute.ngView `ngView`}.
1585 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1586 * causing animations to stop working and making the injector inaccessible from outside the app.
1587 *
1588 * You can specify an **AngularJS module** to be used as the root module for the application. This
1589 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1590 * should contain the application code needed or have dependencies on other modules that will
1591 * contain the code. See {@link angular.module} for more information.
1592 *
1593 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1594 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1595 * would not be resolved to `3`.
1596 *
1597 * @example
1598 *
1599 * ### Simple Usage
1600 *
1601 * `ngApp` is the easiest, and most common way to bootstrap an application.
1602 *
1603 <example module="ngAppDemo" name="ng-app">
1604 <file name="index.html">
1605 <div ng-controller="ngAppDemoController">
1606 I can add: {{a}} + {{b}} = {{ a+b }}
1607 </div>
1608 </file>
1609 <file name="script.js">
1610 angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1611 $scope.a = 1;
1612 $scope.b = 2;
1613 });
1614 </file>
1615 </example>
1616 *
1617 * @example
1618 *
1619 * ### With `ngStrictDi`
1620 *
1621 * Using `ngStrictDi`, you would see something like this:
1622 *
1623 <example ng-app-included="true" name="strict-di">
1624 <file name="index.html">
1625 <div ng-app="ngAppStrictDemo" ng-strict-di>
1626 <div ng-controller="GoodController1">
1627 I can add: {{a}} + {{b}} = {{ a+b }}
1628
1629 <p>This renders because the controller does not fail to
1630 instantiate, by using explicit annotation style (see
1631 script.js for details)
1632 </p>
1633 </div>
1634
1635 <div ng-controller="GoodController2">
1636 Name: <input ng-model="name"><br />
1637 Hello, {{name}}!
1638
1639 <p>This renders because the controller does not fail to
1640 instantiate, by using explicit annotation style
1641 (see script.js for details)
1642 </p>
1643 </div>
1644
1645 <div ng-controller="BadController">
1646 I can add: {{a}} + {{b}} = {{ a+b }}
1647
1648 <p>The controller could not be instantiated, due to relying
1649 on automatic function annotations (which are disabled in
1650 strict mode). As such, the content of this section is not
1651 interpolated, and there should be an error in your web console.
1652 </p>
1653 </div>
1654 </div>
1655 </file>
1656 <file name="script.js">
1657 angular.module('ngAppStrictDemo', [])
1658 // BadController will fail to instantiate, due to relying on automatic function annotation,
1659 // rather than an explicit annotation
1660 .controller('BadController', function($scope) {
1661 $scope.a = 1;
1662 $scope.b = 2;
1663 })
1664 // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1665 // due to using explicit annotations using the array style and $inject property, respectively.
1666 .controller('GoodController1', ['$scope', function($scope) {
1667 $scope.a = 1;
1668 $scope.b = 2;
1669 }])
1670 .controller('GoodController2', GoodController2);
1671 function GoodController2($scope) {
1672 $scope.name = 'World';
1673 }
1674 GoodController2.$inject = ['$scope'];
1675 </file>
1676 <file name="style.css">
1677 div[ng-controller] {
1678 margin-bottom: 1em;
1679 -webkit-border-radius: 4px;
1680 border-radius: 4px;
1681 border: 1px solid;
1682 padding: .5em;
1683 }
1684 div[ng-controller^=Good] {
1685 border-color: #d6e9c6;
1686 background-color: #dff0d8;
1687 color: #3c763d;
1688 }
1689 div[ng-controller^=Bad] {
1690 border-color: #ebccd1;
1691 background-color: #f2dede;
1692 color: #a94442;
1693 margin-bottom: 0;
1694 }
1695 </file>
1696 </example>
1697 */
1698function angularInit(element, bootstrap) {
1699 var appElement,
1700 module,
1701 config = {};
1702
1703 // The element `element` has priority over any other element.
1704 forEach(ngAttrPrefixes, function(prefix) {
1705 var name = prefix + 'app';
1706
1707 if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1708 appElement = element;
1709 module = element.getAttribute(name);
1710 }
1711 });
1712 forEach(ngAttrPrefixes, function(prefix) {
1713 var name = prefix + 'app';
1714 var candidate;
1715
1716 if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1717 appElement = candidate;
1718 module = candidate.getAttribute(name);
1719 }
1720 });
1721 if (appElement) {
1722 if (!isAutoBootstrapAllowed) {
1723 window.console.error('AngularJS: disabling automatic bootstrap. <script> protocol indicates ' +
1724 'an extension, document.location.href does not match.');
1725 return;
1726 }
1727 config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
1728 bootstrap(appElement, module ? [module] : [], config);
1729 }
1730}
1731
1732/**
1733 * @ngdoc function
1734 * @name angular.bootstrap
1735 * @module ng
1736 * @description
1737 * Use this function to manually start up AngularJS application.
1738 *
1739 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
1740 *
1741 * AngularJS will detect if it has been loaded into the browser more than once and only allow the
1742 * first loaded script to be bootstrapped and will report a warning to the browser console for
1743 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1744 * multiple instances of AngularJS try to work on the DOM.
1745 *
1746 * <div class="alert alert-warning">
1747 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
1748 * They must use {@link ng.directive:ngApp ngApp}.
1749 * </div>
1750 *
1751 * <div class="alert alert-warning">
1752 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
1753 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
1754 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1755 * causing animations to stop working and making the injector inaccessible from outside the app.
1756 * </div>
1757 *
1758 * ```html
1759 * <!doctype html>
1760 * <html>
1761 * <body>
1762 * <div ng-controller="WelcomeController">
1763 * {{greeting}}
1764 * </div>
1765 *
1766 * <script src="angular.js"></script>
1767 * <script>
1768 * var app = angular.module('demo', [])
1769 * .controller('WelcomeController', function($scope) {
1770 * $scope.greeting = 'Welcome!';
1771 * });
1772 * angular.bootstrap(document, ['demo']);
1773 * </script>
1774 * </body>
1775 * </html>
1776 * ```
1777 *
1778 * @param {DOMElement} element DOM element which is the root of AngularJS application.
1779 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1780 * Each item in the array should be the name of a predefined module or a (DI annotated)
1781 * function that will be invoked by the injector as a `config` block.
1782 * See: {@link angular.module modules}
1783 * @param {Object=} config an object for defining configuration options for the application. The
1784 * following keys are supported:
1785 *
1786 * * `strictDi` - disable automatic function annotation for the application. This is meant to
1787 * assist in finding bugs which break minified code. Defaults to `false`.
1788 *
1789 * @returns {auto.$injector} Returns the newly created injector for this app.
1790 */
1791function bootstrap(element, modules, config) {
1792 if (!isObject(config)) config = {};
1793 var defaultConfig = {
1794 strictDi: false
1795 };
1796 config = extend(defaultConfig, config);
1797 var doBootstrap = function() {
1798 element = jqLite(element);
1799
1800 if (element.injector()) {
1801 var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1802 // Encode angle brackets to prevent input from being sanitized to empty string #8683.
1803 throw ngMinErr(
1804 'btstrpd',
1805 'App already bootstrapped with this element \'{0}\'',
1806 tag.replace(/</,'<').replace(/>/,'>'));
1807 }
1808
1809 modules = modules || [];
1810 modules.unshift(['$provide', function($provide) {
1811 $provide.value('$rootElement', element);
1812 }]);
1813
1814 if (config.debugInfoEnabled) {
1815 // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1816 modules.push(['$compileProvider', function($compileProvider) {
1817 $compileProvider.debugInfoEnabled(true);
1818 }]);
1819 }
1820
1821 modules.unshift('ng');
1822 var injector = createInjector(modules, config.strictDi);
1823 injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1824 function bootstrapApply(scope, element, compile, injector) {
1825 scope.$apply(function() {
1826 element.data('$injector', injector);
1827 compile(element)(scope);
1828 });
1829 }]
1830 );
1831 return injector;
1832 };
1833
1834 var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1835 var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1836
1837 if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1838 config.debugInfoEnabled = true;
1839 window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1840 }
1841
1842 if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1843 return doBootstrap();
1844 }
1845
1846 window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1847 angular.resumeBootstrap = function(extraModules) {
1848 forEach(extraModules, function(module) {
1849 modules.push(module);
1850 });
1851 return doBootstrap();
1852 };
1853
1854 if (isFunction(angular.resumeDeferredBootstrap)) {
1855 angular.resumeDeferredBootstrap();
1856 }
1857}
1858
1859/**
1860 * @ngdoc function
1861 * @name angular.reloadWithDebugInfo
1862 * @module ng
1863 * @description
1864 * Use this function to reload the current application with debug information turned on.
1865 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1866 *
1867 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1868 */
1869function reloadWithDebugInfo() {
1870 window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1871 window.location.reload();
1872}
1873
1874/**
1875 * @name angular.getTestability
1876 * @module ng
1877 * @description
1878 * Get the testability service for the instance of AngularJS on the given
1879 * element.
1880 * @param {DOMElement} element DOM element which is the root of AngularJS application.
1881 */
1882function getTestability(rootElement) {
1883 var injector = angular.element(rootElement).injector();
1884 if (!injector) {
1885 throw ngMinErr('test',
1886 'no injector found for element argument to getTestability');
1887 }
1888 return injector.get('$$testability');
1889}
1890
1891var SNAKE_CASE_REGEXP = /[A-Z]/g;
1892function snake_case(name, separator) {
1893 separator = separator || '_';
1894 return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1895 return (pos ? separator : '') + letter.toLowerCase();
1896 });
1897}
1898
1899var bindJQueryFired = false;
1900function bindJQuery() {
1901 var originalCleanData;
1902
1903 if (bindJQueryFired) {
1904 return;
1905 }
1906
1907 // bind to jQuery if present;
1908 var jqName = jq();
1909 jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)
1910 !jqName ? undefined : // use jqLite
1911 window[jqName]; // use jQuery specified by `ngJq`
1912
1913 // Use jQuery if it exists with proper functionality, otherwise default to us.
1914 // AngularJS 1.2+ requires jQuery 1.7+ for on()/off() support.
1915 // AngularJS 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1916 // versions. It will not work for sure with jQuery <1.7, though.
1917 if (jQuery && jQuery.fn.on) {
1918 jqLite = jQuery;
1919 extend(jQuery.fn, {
1920 scope: JQLitePrototype.scope,
1921 isolateScope: JQLitePrototype.isolateScope,
1922 controller: /** @type {?} */ (JQLitePrototype).controller,
1923 injector: JQLitePrototype.injector,
1924 inheritedData: JQLitePrototype.inheritedData
1925 });
1926
1927 // All nodes removed from the DOM via various jQuery APIs like .remove()
1928 // are passed through jQuery.cleanData. Monkey-patch this method to fire
1929 // the $destroy event on all removed nodes.
1930 originalCleanData = jQuery.cleanData;
1931 jQuery.cleanData = function(elems) {
1932 var events;
1933 for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1934 events = jQuery._data(elem, 'events');
1935 if (events && events.$destroy) {
1936 jQuery(elem).triggerHandler('$destroy');
1937 }
1938 }
1939 originalCleanData(elems);
1940 };
1941 } else {
1942 jqLite = JQLite;
1943 }
1944
1945 angular.element = jqLite;
1946
1947 // Prevent double-proxying.
1948 bindJQueryFired = true;
1949}
1950
1951/**
1952 * throw error if the argument is falsy.
1953 */
1954function assertArg(arg, name, reason) {
1955 if (!arg) {
1956 throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
1957 }
1958 return arg;
1959}
1960
1961function assertArgFn(arg, name, acceptArrayAnnotation) {
1962 if (acceptArrayAnnotation && isArray(arg)) {
1963 arg = arg[arg.length - 1];
1964 }
1965
1966 assertArg(isFunction(arg), name, 'not a function, got ' +
1967 (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1968 return arg;
1969}
1970
1971/**
1972 * throw error if the name given is hasOwnProperty
1973 * @param {String} name the name to test
1974 * @param {String} context the context in which the name is used, such as module or directive
1975 */
1976function assertNotHasOwnProperty(name, context) {
1977 if (name === 'hasOwnProperty') {
1978 throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
1979 }
1980}
1981
1982/**
1983 * Return the value accessible from the object by path. Any undefined traversals are ignored
1984 * @param {Object} obj starting object
1985 * @param {String} path path to traverse
1986 * @param {boolean} [bindFnToScope=true]
1987 * @returns {Object} value as accessible by path
1988 */
1989//TODO(misko): this function needs to be removed
1990function getter(obj, path, bindFnToScope) {
1991 if (!path) return obj;
1992 var keys = path.split('.');
1993 var key;
1994 var lastInstance = obj;
1995 var len = keys.length;
1996
1997 for (var i = 0; i < len; i++) {
1998 key = keys[i];
1999 if (obj) {
2000 obj = (lastInstance = obj)[key];
2001 }
2002 }
2003 if (!bindFnToScope && isFunction(obj)) {
2004 return bind(lastInstance, obj);
2005 }
2006 return obj;
2007}
2008
2009/**
2010 * Return the DOM siblings between the first and last node in the given array.
2011 * @param {Array} array like object
2012 * @returns {Array} the inputted object or a jqLite collection containing the nodes
2013 */
2014function getBlockNodes(nodes) {
2015 // TODO(perf): update `nodes` instead of creating a new object?
2016 var node = nodes[0];
2017 var endNode = nodes[nodes.length - 1];
2018 var blockNodes;
2019
2020 for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
2021 if (blockNodes || nodes[i] !== node) {
2022 if (!blockNodes) {
2023 blockNodes = jqLite(slice.call(nodes, 0, i));
2024 }
2025 blockNodes.push(node);
2026 }
2027 }
2028
2029 return blockNodes || nodes;
2030}
2031
2032
2033/**
2034 * Creates a new object without a prototype. This object is useful for lookup without having to
2035 * guard against prototypically inherited properties via hasOwnProperty.
2036 *
2037 * Related micro-benchmarks:
2038 * - http://jsperf.com/object-create2
2039 * - http://jsperf.com/proto-map-lookup/2
2040 * - http://jsperf.com/for-in-vs-object-keys2
2041 *
2042 * @returns {Object}
2043 */
2044function createMap() {
2045 return Object.create(null);
2046}
2047
2048function stringify(value) {
2049 if (value == null) { // null || undefined
2050 return '';
2051 }
2052 switch (typeof value) {
2053 case 'string':
2054 break;
2055 case 'number':
2056 value = '' + value;
2057 break;
2058 default:
2059 if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
2060 value = value.toString();
2061 } else {
2062 value = toJson(value);
2063 }
2064 }
2065
2066 return value;
2067}
2068
2069var NODE_TYPE_ELEMENT = 1;
2070var NODE_TYPE_ATTRIBUTE = 2;
2071var NODE_TYPE_TEXT = 3;
2072var NODE_TYPE_COMMENT = 8;
2073var NODE_TYPE_DOCUMENT = 9;
2074var NODE_TYPE_DOCUMENT_FRAGMENT = 11;