History

ModbusAdapters: Fixed security issues in Modbus configuration screen GSF.Web: Cleaned up new embedded resources

J. Ritchie Carroll committed 9 years ago

Commit 970956d1 parent 230686d36 files · +72369 −1648Browse files

Showing the changes to Source/Libraries/GSF.Web/Shared/Scripts/angular.js (1 of 36 files). Show all

Unified · Split

Source/Libraries/GSF.Web/Shared/Scripts/angular.js+31768−0
@@ -0,0 +1,31768 @@
1/**
2 * @license AngularJS v1.5.8
3 * (c) 2010-2016 Google, Inc. http://angularjs.org
4 * License: MIT
5 */
6(function(window) {'use strict';
7
8/**
9 * @description
10 *
11 * This object provides a utility for producing rich Error messages within
12 * Angular. It can be called as follows:
13 *
14 * var exampleMinErr = minErr('example');
15 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
16 *
17 * The above creates an instance of minErr in the example namespace. The
18 * resulting error will have a namespaced error code of example.one. The
19 * resulting error will replace {0} with the value of foo, and {1} with the
20 * value of bar. The object is not restricted in the number of arguments it can
21 * take.
22 *
23 * If fewer arguments are specified than necessary for interpolation, the extra
24 * interpolation markers will be preserved in the final string.
25 *
26 * Since data will be parsed statically during a build step, some restrictions
27 * are applied with respect to how minErr instances are created and called.
28 * Instances should have names of the form namespaceMinErr for a minErr created
29 * using minErr('namespace') . Error codes, namespaces and template strings
30 * should all be static strings, not variables or general expressions.
31 *
32 * @param {string} module The namespace to use for the new minErr instance.
33 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
34 * error from returned function, for cases when a particular type of error is useful.
35 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
36 */
37
38function minErr(module, ErrorConstructor) {
39 ErrorConstructor = ErrorConstructor || Error;
40 return function() {
41 var SKIP_INDEXES = 2;
42
43 var templateArgs = arguments,
44 code = templateArgs[0],
45 message = '[' + (module ? module + ':' : '') + code + '] ',
46 template = templateArgs[1],
47 paramPrefix, i;
48
49 message += template.replace(/\{\d+\}/g, function(match) {
50 var index = +match.slice(1, -1),
51 shiftedIndex = index + SKIP_INDEXES;
52
53 if (shiftedIndex < templateArgs.length) {
54 return toDebugString(templateArgs[shiftedIndex]);
55 }
56
57 return match;
58 });
59
60 message += '\nhttp://errors.angularjs.org/1.5.8/' +
61 (module ? module + '/' : '') + code;
62
63 for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
64 message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
65 encodeURIComponent(toDebugString(templateArgs[i]));
66 }
67
68 return new ErrorConstructor(message);
69 };
70}
71
72/* We need to tell jshint what variables are being exported */
73/* global angular: true,
74 msie: true,
75 jqLite: true,
76 jQuery: true,
77 slice: true,
78 splice: true,
79 push: true,
80 toString: true,
81 ngMinErr: true,
82 angularModule: true,
83 uid: true,
84 REGEX_STRING_REGEXP: true,
85 VALIDITY_STATE_PROPERTY: true,
86
87 lowercase: true,
88 uppercase: true,
89 manualLowercase: true,
90 manualUppercase: true,
91 nodeName_: true,
92 isArrayLike: true,
93 forEach: true,
94 forEachSorted: true,
95 reverseParams: true,
96 nextUid: true,
97 setHashKey: true,
98 extend: true,
99 toInt: true,
100 inherit: true,
101 merge: true,
102 noop: true,
103 identity: true,
104 valueFn: true,
105 isUndefined: true,
106 isDefined: true,
107 isObject: true,
108 isBlankObject: true,
109 isString: true,
110 isNumber: true,
111 isDate: true,
112 isArray: true,
113 isFunction: true,
114 isRegExp: true,
115 isWindow: true,
116 isScope: true,
117 isFile: true,
118 isFormData: true,
119 isBlob: true,
120 isBoolean: true,
121 isPromiseLike: true,
122 trim: true,
123 escapeForRegexp: true,
124 isElement: true,
125 makeMap: true,
126 includes: true,
127 arrayRemove: true,
128 copy: true,
129 equals: true,
130 csp: true,
131 jq: true,
132 concat: true,
133 sliceArgs: true,
134 bind: true,
135 toJsonReplacer: true,
136 toJson: true,
137 fromJson: true,
138 convertTimezoneToLocal: true,
139 timezoneToOffset: true,
140 startingTag: true,
141 tryDecodeURIComponent: true,
142 parseKeyValue: true,
143 toKeyValue: true,
144 encodeUriSegment: true,
145 encodeUriQuery: true,
146 angularInit: true,
147 bootstrap: true,
148 getTestability: true,
149 snake_case: true,
150 bindJQuery: true,
151 assertArg: true,
152 assertArgFn: true,
153 assertNotHasOwnProperty: true,
154 getter: true,
155 getBlockNodes: true,
156 hasOwnProperty: true,
157 createMap: true,
158
159 NODE_TYPE_ELEMENT: true,
160 NODE_TYPE_ATTRIBUTE: true,
161 NODE_TYPE_TEXT: true,
162 NODE_TYPE_COMMENT: true,
163 NODE_TYPE_DOCUMENT: true,
164 NODE_TYPE_DOCUMENT_FRAGMENT: true,
165*/
166
167////////////////////////////////////
168
169/**
170 * @ngdoc module
171 * @name ng
172 * @module ng
173 * @installation
174 * @description
175 *
176 * # ng (core module)
177 * The ng module is loaded by default when an AngularJS application is started. The module itself
178 * contains the essential components for an AngularJS application to function. The table below
179 * lists a high level breakdown of each of the services/factories, filters, directives and testing
180 * components available within this core module.
181 *
182 * <div doc-module-components="ng"></div>
183 */
184
185var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
186
187// The name of a form control's ValidityState property.
188// This is used so that it's possible for internal tests to create mock ValidityStates.
189var VALIDITY_STATE_PROPERTY = 'validity';
190
191var hasOwnProperty = Object.prototype.hasOwnProperty;
192
193var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
194var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
195
196
197var manualLowercase = function(s) {
198 /* jshint bitwise: false */
199 return isString(s)
200 ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
201 : s;
202};
203var manualUppercase = function(s) {
204 /* jshint bitwise: false */
205 return isString(s)
206 ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
207 : s;
208};
209
210
211// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
212// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
213// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
214if ('i' !== 'I'.toLowerCase()) {
215 lowercase = manualLowercase;
216 uppercase = manualUppercase;
217}
218
219
220var
221 msie, // holds major version number for IE, or NaN if UA is not IE.
222 jqLite, // delay binding since jQuery could be loaded after us.
223 jQuery, // delay binding
224 slice = [].slice,
225 splice = [].splice,
226 push = [].push,
227 toString = Object.prototype.toString,
228 getPrototypeOf = Object.getPrototypeOf,
229 ngMinErr = minErr('ng'),
230
231 /** @name angular */
232 angular = window.angular || (window.angular = {}),
233 angularModule,
234 uid = 0;
235
236/**
237 * documentMode is an IE-only property
238 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
239 */
240msie = window.document.documentMode;
241
242
243/**
244 * @private
245 * @param {*} obj
246 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
247 * String ...)
248 */
249function isArrayLike(obj) {
250
251 // `null`, `undefined` and `window` are not array-like
252 if (obj == null || isWindow(obj)) return false;
253
254 // arrays, strings and jQuery/jqLite objects are array like
255 // * jqLite is either the jQuery or jqLite constructor function
256 // * we have to check the existence of jqLite first as this method is called
257 // via the forEach method when constructing the jqLite object in the first place
258 if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
259
260 // Support: iOS 8.2 (not reproducible in simulator)
261 // "length" in obj used to prevent JIT error (gh-11508)
262 var length = "length" in Object(obj) && obj.length;
263
264 // NodeList objects (with `item` method) and
265 // other objects with suitable length characteristics are array-like
266 return isNumber(length) &&
267 (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
268
269}
270
271/**
272 * @ngdoc function
273 * @name angular.forEach
274 * @module ng
275 * @kind function
276 *
277 * @description
278 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
279 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
280 * is the value of an object property or an array element, `key` is the object property key or
281 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
282 *
283 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
284 * using the `hasOwnProperty` method.
285 *
286 * Unlike ES262's
287 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
288 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
289 * return the value provided.
290 *
291 ```js
292 var values = {name: 'misko', gender: 'male'};
293 var log = [];
294 angular.forEach(values, function(value, key) {
295 this.push(key + ': ' + value);
296 }, log);
297 expect(log).toEqual(['name: misko', 'gender: male']);
298 ```
299 *
300 * @param {Object|Array} obj Object to iterate over.
301 * @param {Function} iterator Iterator function.
302 * @param {Object=} context Object to become context (`this`) for the iterator function.
303 * @returns {Object|Array} Reference to `obj`.
304 */
305
306function forEach(obj, iterator, context) {
307 var key, length;
308 if (obj) {
309 if (isFunction(obj)) {
310 for (key in obj) {
311 // Need to check if hasOwnProperty exists,
312 // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
313 if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
314 iterator.call(context, obj[key], key, obj);
315 }
316 }
317 } else if (isArray(obj) || isArrayLike(obj)) {
318 var isPrimitive = typeof obj !== 'object';
319 for (key = 0, length = obj.length; key < length; key++) {
320 if (isPrimitive || key in obj) {
321 iterator.call(context, obj[key], key, obj);
322 }
323 }
324 } else if (obj.forEach && obj.forEach !== forEach) {
325 obj.forEach(iterator, context, obj);
326 } else if (isBlankObject(obj)) {
327 // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
328 for (key in obj) {
329 iterator.call(context, obj[key], key, obj);
330 }
331 } else if (typeof obj.hasOwnProperty === 'function') {
332 // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
333 for (key in obj) {
334 if (obj.hasOwnProperty(key)) {
335 iterator.call(context, obj[key], key, obj);
336 }
337 }
338 } else {
339 // Slow path for objects which do not have a method `hasOwnProperty`
340 for (key in obj) {
341 if (hasOwnProperty.call(obj, key)) {
342 iterator.call(context, obj[key], key, obj);
343 }
344 }
345 }
346 }
347 return obj;
348}
349
350function forEachSorted(obj, iterator, context) {
351 var keys = Object.keys(obj).sort();
352 for (var i = 0; i < keys.length; i++) {
353 iterator.call(context, obj[keys[i]], keys[i]);
354 }
355 return keys;
356}
357
358
359/**
360 * when using forEach the params are value, key, but it is often useful to have key, value.
361 * @param {function(string, *)} iteratorFn
362 * @returns {function(*, string)}
363 */
364function reverseParams(iteratorFn) {
365 return function(value, key) {iteratorFn(key, value);};
366}
367
368/**
369 * A consistent way of creating unique IDs in angular.
370 *
371 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
372 * we hit number precision issues in JavaScript.
373 *
374 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
375 *
376 * @returns {number} an unique alpha-numeric string
377 */
378function nextUid() {
379 return ++uid;
380}
381
382
383/**
384 * Set or clear the hashkey for an object.
385 * @param obj object
386 * @param h the hashkey (!truthy to delete the hashkey)
387 */
388function setHashKey(obj, h) {
389 if (h) {
390 obj.$$hashKey = h;
391 } else {
392 delete obj.$$hashKey;
393 }
394}
395
396
397function baseExtend(dst, objs, deep) {
398 var h = dst.$$hashKey;
399
400 for (var i = 0, ii = objs.length; i < ii; ++i) {
401 var obj = objs[i];
402 if (!isObject(obj) && !isFunction(obj)) continue;
403 var keys = Object.keys(obj);
404 for (var j = 0, jj = keys.length; j < jj; j++) {
405 var key = keys[j];
406 var src = obj[key];
407
408 if (deep && isObject(src)) {
409 if (isDate(src)) {
410 dst[key] = new Date(src.valueOf());
411 } else if (isRegExp(src)) {
412 dst[key] = new RegExp(src);
413 } else if (src.nodeName) {
414 dst[key] = src.cloneNode(true);
415 } else if (isElement(src)) {
416 dst[key] = src.clone();
417 } else {
418 if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
419 baseExtend(dst[key], [src], true);
420 }
421 } else {
422 dst[key] = src;
423 }
424 }
425 }
426
427 setHashKey(dst, h);
428 return dst;
429}
430
431/**
432 * @ngdoc function
433 * @name angular.extend
434 * @module ng
435 * @kind function
436 *
437 * @description
438 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
439 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
440 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
441 *
442 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
443 * {@link angular.merge} for this.
444 *
445 * @param {Object} dst Destination object.
446 * @param {...Object} src Source object(s).
447 * @returns {Object} Reference to `dst`.
448 */
449function extend(dst) {
450 return baseExtend(dst, slice.call(arguments, 1), false);
451}
452
453
454/**
455* @ngdoc function
456* @name angular.merge
457* @module ng
458* @kind function
459*
460* @description
461* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
462* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
463* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
464*
465* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
466* objects, performing a deep copy.
467*
468* @param {Object} dst Destination object.
469* @param {...Object} src Source object(s).
470* @returns {Object} Reference to `dst`.
471*/
472function merge(dst) {
473 return baseExtend(dst, slice.call(arguments, 1), true);
474}
475
476
477
478function toInt(str) {
479 return parseInt(str, 10);
480}
481
482
483function inherit(parent, extra) {
484 return extend(Object.create(parent), extra);
485}
486
487/**
488 * @ngdoc function
489 * @name angular.noop
490 * @module ng
491 * @kind function
492 *
493 * @description
494 * A function that performs no operations. This function can be useful when writing code in the
495 * functional style.
496 ```js
497 function foo(callback) {
498 var result = calculateResult();
499 (callback || angular.noop)(result);
500 }
501 ```
502 */
503function noop() {}
504noop.$inject = [];
505
506
507/**
508 * @ngdoc function
509 * @name angular.identity
510 * @module ng
511 * @kind function
512 *
513 * @description
514 * A function that returns its first argument. This function is useful when writing code in the
515 * functional style.
516 *
517 ```js
518 function transformer(transformationFn, value) {
519 return (transformationFn || angular.identity)(value);
520 };
521
522 // E.g.
523 function getResult(fn, input) {
524 return (fn || angular.identity)(input);
525 };
526
527 getResult(function(n) { return n * 2; }, 21); // returns 42
528 getResult(null, 21); // returns 21
529 getResult(undefined, 21); // returns 21
530 ```
531 *
532 * @param {*} value to be returned.
533 * @returns {*} the value passed in.
534 */
535function identity($) {return $;}
536identity.$inject = [];
537
538
539function valueFn(value) {return function valueRef() {return value;};}
540
541function hasCustomToString(obj) {
542 return isFunction(obj.toString) && obj.toString !== toString;
543}
544
545
546/**
547 * @ngdoc function
548 * @name angular.isUndefined
549 * @module ng
550 * @kind function
551 *
552 * @description
553 * Determines if a reference is undefined.
554 *
555 * @param {*} value Reference to check.
556 * @returns {boolean} True if `value` is undefined.
557 */
558function isUndefined(value) {return typeof value === 'undefined';}
559
560
561/**
562 * @ngdoc function
563 * @name angular.isDefined
564 * @module ng
565 * @kind function
566 *
567 * @description
568 * Determines if a reference is defined.
569 *
570 * @param {*} value Reference to check.
571 * @returns {boolean} True if `value` is defined.
572 */
573function isDefined(value) {return typeof value !== 'undefined';}
574
575
576/**
577 * @ngdoc function
578 * @name angular.isObject
579 * @module ng
580 * @kind function
581 *
582 * @description
583 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
584 * considered to be objects. Note that JavaScript arrays are objects.
585 *
586 * @param {*} value Reference to check.
587 * @returns {boolean} True if `value` is an `Object` but not `null`.
588 */
589function isObject(value) {
590 // http://jsperf.com/isobject4
591 return value !== null && typeof value === 'object';
592}
593
594
595/**
596 * Determine if a value is an object with a null prototype
597 *
598 * @returns {boolean} True if `value` is an `Object` with a null prototype
599 */
600function isBlankObject(value) {
601 return value !== null && typeof value === 'object' && !getPrototypeOf(value);
602}
603
604
605/**
606 * @ngdoc function
607 * @name angular.isString
608 * @module ng
609 * @kind function
610 *
611 * @description
612 * Determines if a reference is a `String`.
613 *
614 * @param {*} value Reference to check.
615 * @returns {boolean} True if `value` is a `String`.
616 */
617function isString(value) {return typeof value === 'string';}
618
619
620/**
621 * @ngdoc function
622 * @name angular.isNumber
623 * @module ng
624 * @kind function
625 *
626 * @description
627 * Determines if a reference is a `Number`.
628 *
629 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
630 *
631 * If you wish to exclude these then you can use the native
632 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
633 * method.
634 *
635 * @param {*} value Reference to check.
636 * @returns {boolean} True if `value` is a `Number`.
637 */
638function isNumber(value) {return typeof value === 'number';}
639
640
641/**
642 * @ngdoc function
643 * @name angular.isDate
644 * @module ng
645 * @kind function
646 *
647 * @description
648 * Determines if a value is a date.
649 *
650 * @param {*} value Reference to check.
651 * @returns {boolean} True if `value` is a `Date`.
652 */
653function isDate(value) {
654 return toString.call(value) === '[object Date]';
655}
656
657
658/**
659 * @ngdoc function
660 * @name angular.isArray
661 * @module ng
662 * @kind function
663 *
664 * @description
665 * Determines if a reference is an `Array`.
666 *
667 * @param {*} value Reference to check.
668 * @returns {boolean} True if `value` is an `Array`.
669 */
670var isArray = Array.isArray;
671
672/**
673 * @ngdoc function
674 * @name angular.isFunction
675 * @module ng
676 * @kind function
677 *
678 * @description
679 * Determines if a reference is a `Function`.
680 *
681 * @param {*} value Reference to check.
682 * @returns {boolean} True if `value` is a `Function`.
683 */
684function isFunction(value) {return typeof value === 'function';}
685
686
687/**
688 * Determines if a value is a regular expression object.
689 *
690 * @private
691 * @param {*} value Reference to check.
692 * @returns {boolean} True if `value` is a `RegExp`.
693 */
694function isRegExp(value) {
695 return toString.call(value) === '[object RegExp]';
696}
697
698
699/**
700 * Checks if `obj` is a window object.
701 *
702 * @private
703 * @param {*} obj Object to check
704 * @returns {boolean} True if `obj` is a window obj.
705 */
706function isWindow(obj) {
707 return obj && obj.window === obj;
708}
709
710
711function isScope(obj) {
712 return obj && obj.$evalAsync && obj.$watch;
713}
714
715
716function isFile(obj) {
717 return toString.call(obj) === '[object File]';
718}
719
720
721function isFormData(obj) {
722 return toString.call(obj) === '[object FormData]';
723}
724
725
726function isBlob(obj) {
727 return toString.call(obj) === '[object Blob]';
728}
729
730
731function isBoolean(value) {
732 return typeof value === 'boolean';
733}
734
735
736function isPromiseLike(obj) {
737 return obj && isFunction(obj.then);
738}
739
740
741var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
742function isTypedArray(value) {
743 return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
744}
745
746function isArrayBuffer(obj) {
747 return toString.call(obj) === '[object ArrayBuffer]';
748}
749
750
751var trim = function(value) {
752 return isString(value) ? value.trim() : value;
753};
754
755// Copied from:
756// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
757// Prereq: s is a string.
758var escapeForRegexp = function(s) {
759 return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
760 replace(/\x08/g, '\\x08');
761};
762
763
764/**
765 * @ngdoc function
766 * @name angular.isElement
767 * @module ng
768 * @kind function
769 *
770 * @description
771 * Determines if a reference is a DOM element (or wrapped jQuery element).
772 *
773 * @param {*} value Reference to check.
774 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
775 */
776function isElement(node) {
777 return !!(node &&
778 (node.nodeName // We are a direct element.
779 || (node.prop && node.attr && node.find))); // We have an on and find method part of jQuery API.
780}
781
782/**
783 * @param str 'key1,key2,...'
784 * @returns {object} in the form of {key1:true, key2:true, ...}
785 */
786function makeMap(str) {
787 var obj = {}, items = str.split(','), i;
788 for (i = 0; i < items.length; i++) {
789 obj[items[i]] = true;
790 }
791 return obj;
792}
793
794
795function nodeName_(element) {
796 return lowercase(element.nodeName || (element[0] && element[0].nodeName));
797}
798
799function includes(array, obj) {
800 return Array.prototype.indexOf.call(array, obj) != -1;
801}
802
803function arrayRemove(array, value) {
804 var index = array.indexOf(value);
805 if (index >= 0) {
806 array.splice(index, 1);
807 }
808 return index;
809}
810
811/**
812 * @ngdoc function
813 * @name angular.copy
814 * @module ng
815 * @kind function
816 *
817 * @description
818 * Creates a deep copy of `source`, which should be an object or an array.
819 *
820 * * If no destination is supplied, a copy of the object or array is created.
821 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
822 * are deleted and then all elements/properties from the source are copied to it.
823 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
824 * * If `source` is identical to `destination` an exception will be thrown.
825 *
826 * <br />
827 * <div class="alert alert-warning">
828 * Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
829 * and on `destination`) will be ignored.
830 * </div>
831 *
832 * @param {*} source The source that will be used to make a copy.
833 * Can be any type, including primitives, `null`, and `undefined`.
834 * @param {(Object|Array)=} destination Destination into which the source is copied. If
835 * provided, must be of the same type as `source`.
836 * @returns {*} The copy or updated `destination`, if `destination` was specified.
837 *
838 * @example
839 <example module="copyExample">
840 <file name="index.html">
841 <div ng-controller="ExampleController">
842 <form novalidate class="simple-form">
843 <label>Name: <input type="text" ng-model="user.name" /></label><br />
844 <label>Age: <input type="number" ng-model="user.age" /></label><br />
845 Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
846 <label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
847 <button ng-click="reset()">RESET</button>
848 <button ng-click="update(user)">SAVE</button>
849 </form>
850 <pre>form = {{user | json}}</pre>
851 <pre>master = {{master | json}}</pre>
852 </div>
853 </file>
854 <file name="script.js">
855 // Module: copyExample
856 angular.
857 module('copyExample', []).
858 controller('ExampleController', ['$scope', function($scope) {
859 $scope.master = {};
860
861 $scope.reset = function() {
862 // Example with 1 argument
863 $scope.user = angular.copy($scope.master);
864 };
865
866 $scope.update = function(user) {
867 // Example with 2 arguments
868 angular.copy(user, $scope.master);
869 };
870
871 $scope.reset();
872 }]);
873 </file>
874 </example>
875 */
876function copy(source, destination) {
877 var stackSource = [];
878 var stackDest = [];
879
880 if (destination) {
881 if (isTypedArray(destination) || isArrayBuffer(destination)) {
882 throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
883 }
884 if (source === destination) {
885 throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
886 }
887
888 // Empty the destination object
889 if (isArray(destination)) {
890 destination.length = 0;
891 } else {
892 forEach(destination, function(value, key) {
893 if (key !== '$$hashKey') {
894 delete destination[key];
895 }
896 });
897 }
898
899 stackSource.push(source);
900 stackDest.push(destination);
901 return copyRecurse(source, destination);
902 }
903
904 return copyElement(source);
905
906 function copyRecurse(source, destination) {
907 var h = destination.$$hashKey;
908 var key;
909 if (isArray(source)) {
910 for (var i = 0, ii = source.length; i < ii; i++) {
911 destination.push(copyElement(source[i]));
912 }
913 } else if (isBlankObject(source)) {
914 // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
915 for (key in source) {
916 destination[key] = copyElement(source[key]);
917 }
918 } else if (source && typeof source.hasOwnProperty === 'function') {
919 // Slow path, which must rely on hasOwnProperty
920 for (key in source) {
921 if (source.hasOwnProperty(key)) {
922 destination[key] = copyElement(source[key]);
923 }
924 }
925 } else {
926 // Slowest path --- hasOwnProperty can't be called as a method
927 for (key in source) {
928 if (hasOwnProperty.call(source, key)) {
929 destination[key] = copyElement(source[key]);
930 }
931 }
932 }
933 setHashKey(destination, h);
934 return destination;
935 }
936
937 function copyElement(source) {
938 // Simple values
939 if (!isObject(source)) {
940 return source;
941 }
942
943 // Already copied values
944 var index = stackSource.indexOf(source);
945 if (index !== -1) {
946 return stackDest[index];
947 }
948
949 if (isWindow(source) || isScope(source)) {
950 throw ngMinErr('cpws',
951 "Can't copy! Making copies of Window or Scope instances is not supported.");
952 }
953
954 var needsRecurse = false;
955 var destination = copyType(source);
956
957 if (destination === undefined) {
958 destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
959 needsRecurse = true;
960 }
961
962 stackSource.push(source);
963 stackDest.push(destination);
964
965 return needsRecurse
966 ? copyRecurse(source, destination)
967 : destination;
968 }
969
970 function copyType(source) {
971 switch (toString.call(source)) {
972 case '[object Int8Array]':
973 case '[object Int16Array]':
974 case '[object Int32Array]':
975 case '[object Float32Array]':
976 case '[object Float64Array]':
977 case '[object Uint8Array]':
978 case '[object Uint8ClampedArray]':
979 case '[object Uint16Array]':
980 case '[object Uint32Array]':
981 return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
982
983 case '[object ArrayBuffer]':
984 //Support: IE10
985 if (!source.slice) {
986 var copied = new ArrayBuffer(source.byteLength);
987 new Uint8Array(copied).set(new Uint8Array(source));
988 return copied;
989 }
990 return source.slice(0);
991
992 case '[object Boolean]':
993 case '[object Number]':
994 case '[object String]':
995 case '[object Date]':
996 return new source.constructor(source.valueOf());
997
998 case '[object RegExp]':
999 var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
1000 re.lastIndex = source.lastIndex;
1001 return re;
1002
1003 case '[object Blob]':
1004 return new source.constructor([source], {type: source.type});
1005 }
1006
1007 if (isFunction(source.cloneNode)) {
1008 return source.cloneNode(true);
1009 }
1010 }
1011}
1012
1013
1014/**
1015 * @ngdoc function
1016 * @name angular.equals
1017 * @module ng
1018 * @kind function
1019 *
1020 * @description
1021 * Determines if two objects or two values are equivalent. Supports value types, regular
1022 * expressions, arrays and objects.
1023 *
1024 * Two objects or values are considered equivalent if at least one of the following is true:
1025 *
1026 * * Both objects or values pass `===` comparison.
1027 * * Both objects or values are of the same type and all of their properties are equal by
1028 * comparing them with `angular.equals`.
1029 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
1030 * * Both values represent the same regular expression (In JavaScript,
1031 * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
1032 * representation matches).
1033 *
1034 * During a property comparison, properties of `function` type and properties with names
1035 * that begin with `$` are ignored.
1036 *
1037 * Scope and DOMWindow objects are being compared only by identify (`===`).
1038 *
1039 * @param {*} o1 Object or value to compare.
1040 * @param {*} o2 Object or value to compare.
1041 * @returns {boolean} True if arguments are equal.
1042 *
1043 * @example
1044 <example module="equalsExample" name="equalsExample">
1045 <file name="index.html">
1046 <div ng-controller="ExampleController">
1047 <form novalidate>
1048 <h3>User 1</h3>
1049 Name: <input type="text" ng-model="user1.name">
1050 Age: <input type="number" ng-model="user1.age">
1051
1052 <h3>User 2</h3>
1053 Name: <input type="text" ng-model="user2.name">
1054 Age: <input type="number" ng-model="user2.age">
1055
1056 <div>
1057 <br/>
1058 <input type="button" value="Compare" ng-click="compare()">
1059 </div>
1060 User 1: <pre>{{user1 | json}}</pre>
1061 User 2: <pre>{{user2 | json}}</pre>
1062 Equal: <pre>{{result}}</pre>
1063 </form>
1064 </div>
1065 </file>
1066 <file name="script.js">
1067 angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
1068 $scope.user1 = {};
1069 $scope.user2 = {};
1070 $scope.result;
1071 $scope.compare = function() {
1072 $scope.result = angular.equals($scope.user1, $scope.user2);
1073 };
1074 }]);
1075 </file>
1076 </example>
1077 */
1078function equals(o1, o2) {
1079 if (o1 === o2) return true;
1080 if (o1 === null || o2 === null) return false;
1081 if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
1082 var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
1083 if (t1 == t2 && t1 == 'object') {
1084 if (isArray(o1)) {
1085 if (!isArray(o2)) return false;
1086 if ((length = o1.length) == o2.length) {
1087 for (key = 0; key < length; key++) {
1088 if (!equals(o1[key], o2[key])) return false;
1089 }
1090 return true;
1091 }
1092 } else if (isDate(o1)) {
1093 if (!isDate(o2)) return false;
1094 return equals(o1.getTime(), o2.getTime());
1095 } else if (isRegExp(o1)) {
1096 if (!isRegExp(o2)) return false;
1097 return o1.toString() == o2.toString();
1098 } else {
1099 if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
1100 isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
1101 keySet = createMap();
1102 for (key in o1) {
1103 if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
1104 if (!equals(o1[key], o2[key])) return false;
1105 keySet[key] = true;
1106 }
1107 for (key in o2) {
1108 if (!(key in keySet) &&
1109 key.charAt(0) !== '$' &&
1110 isDefined(o2[key]) &&
1111 !isFunction(o2[key])) return false;
1112 }
1113 return true;
1114 }
1115 }
1116 return false;
1117}
1118
1119var csp = function() {
1120 if (!isDefined(csp.rules)) {
1121
1122
1123 var ngCspElement = (window.document.querySelector('[ng-csp]') ||
1124 window.document.querySelector('[data-ng-csp]'));
1125
1126 if (ngCspElement) {
1127 var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
1128 ngCspElement.getAttribute('data-ng-csp');
1129 csp.rules = {
1130 noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
1131 noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
1132 };
1133 } else {
1134 csp.rules = {
1135 noUnsafeEval: noUnsafeEval(),
1136 noInlineStyle: false
1137 };
1138 }
1139 }
1140
1141 return csp.rules;
1142
1143 function noUnsafeEval() {
1144 try {
1145 /* jshint -W031, -W054 */
1146 new Function('');
1147 /* jshint +W031, +W054 */
1148 return false;
1149 } catch (e) {
1150 return true;
1151 }
1152 }
1153};
1154
1155/**
1156 * @ngdoc directive
1157 * @module ng
1158 * @name ngJq
1159 *
1160 * @element ANY
1161 * @param {string=} ngJq the name of the library available under `window`
1162 * to be used for angular.element
1163 * @description
1164 * Use this directive to force the angular.element library. This should be
1165 * used to force either jqLite by leaving ng-jq blank or setting the name of
1166 * the jquery variable under window (eg. jQuery).
1167 *
1168 * Since angular looks for this directive when it is loaded (doesn't wait for the
1169 * DOMContentLoaded event), it must be placed on an element that comes before the script
1170 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
1171 * others ignored.
1172 *
1173 * @example
1174 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
1175 ```html
1176 <!doctype html>
1177 <html ng-app ng-jq>
1178 ...
1179 ...
1180 </html>
1181 ```
1182 * @example
1183 * This example shows how to use a jQuery based library of a different name.
1184 * The library name must be available at the top most 'window'.
1185 ```html
1186 <!doctype html>
1187 <html ng-app ng-jq="jQueryLib">
1188 ...
1189 ...
1190 </html>
1191 ```
1192 */
1193var jq = function() {
1194 if (isDefined(jq.name_)) return jq.name_;
1195 var el;
1196 var i, ii = ngAttrPrefixes.length, prefix, name;
1197 for (i = 0; i < ii; ++i) {
1198 prefix = ngAttrPrefixes[i];
1199 if (el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
1200 name = el.getAttribute(prefix + 'jq');
1201 break;
1202 }
1203 }
1204
1205 return (jq.name_ = name);
1206};
1207
1208function concat(array1, array2, index) {
1209 return array1.concat(slice.call(array2, index));
1210}
1211
1212function sliceArgs(args, startIndex) {
1213 return slice.call(args, startIndex || 0);
1214}
1215
1216
1217/* jshint -W101 */
1218/**
1219 * @ngdoc function
1220 * @name angular.bind
1221 * @module ng
1222 * @kind function
1223 *
1224 * @description
1225 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
1226 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
1227 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
1228 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
1229 *
1230 * @param {Object} self Context which `fn` should be evaluated in.
1231 * @param {function()} fn Function to be bound.
1232 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
1233 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
1234 */
1235/* jshint +W101 */
1236function bind(self, fn) {
1237 var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
1238 if (isFunction(fn) && !(fn instanceof RegExp)) {
1239 return curryArgs.length
1240 ? function() {
1241 return arguments.length
1242 ? fn.apply(self, concat(curryArgs, arguments, 0))
1243 : fn.apply(self, curryArgs);
1244 }
1245 : function() {
1246 return arguments.length
1247 ? fn.apply(self, arguments)
1248 : fn.call(self);
1249 };
1250 } else {
1251 // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
1252 return fn;
1253 }
1254}
1255
1256
1257function toJsonReplacer(key, value) {
1258 var val = value;
1259
1260 if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
1261 val = undefined;
1262 } else if (isWindow(value)) {
1263 val = '$WINDOW';
1264 } else if (value && window.document === value) {
1265 val = '$DOCUMENT';
1266 } else if (isScope(value)) {
1267 val = '$SCOPE';
1268 }
1269
1270 return val;
1271}
1272
1273
1274/**
1275 * @ngdoc function
1276 * @name angular.toJson
1277 * @module ng
1278 * @kind function
1279 *
1280 * @description
1281 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
1282 * stripped since angular uses this notation internally.
1283 *
1284 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
1285 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
1286 * If set to an integer, the JSON output will contain that many spaces per indentation.
1287 * @returns {string|undefined} JSON-ified string representing `obj`.
1288 * @knownIssue
1289 *
1290 * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
1291 * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
1292 * `Date.prototype.toJSON` method as follows:
1293 *
1294 * ```
1295 * var _DatetoJSON = Date.prototype.toJSON;
1296 * Date.prototype.toJSON = function() {
1297 * try {
1298 * return _DatetoJSON.call(this);
1299 * } catch(e) {
1300 * if (e instanceof RangeError) {
1301 * return null;
1302 * }
1303 * throw e;
1304 * }
1305 * };
1306 * ```
1307 *
1308 * See https://github.com/angular/angular.js/pull/14221 for more information.
1309 */
1310function toJson(obj, pretty) {
1311 if (isUndefined(obj)) return undefined;
1312 if (!isNumber(pretty)) {
1313 pretty = pretty ? 2 : null;
1314 }
1315 return JSON.stringify(obj, toJsonReplacer, pretty);
1316}
1317
1318
1319/**
1320 * @ngdoc function
1321 * @name angular.fromJson
1322 * @module ng
1323 * @kind function
1324 *
1325 * @description
1326 * Deserializes a JSON string.
1327 *
1328 * @param {string} json JSON string to deserialize.
1329 * @returns {Object|Array|string|number} Deserialized JSON string.
1330 */
1331function fromJson(json) {
1332 return isString(json)
1333 ? JSON.parse(json)
1334 : json;
1335}
1336
1337
1338var ALL_COLONS = /:/g;
1339function timezoneToOffset(timezone, fallback) {
1340 // IE/Edge do not "understand" colon (`:`) in timezone
1341 timezone = timezone.replace(ALL_COLONS, '');
1342 var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
1343 return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
1344}
1345
1346
1347function addDateMinutes(date, minutes) {
1348 date = new Date(date.getTime());
1349 date.setMinutes(date.getMinutes() + minutes);
1350 return date;
1351}
1352
1353
1354function convertTimezoneToLocal(date, timezone, reverse) {
1355 reverse = reverse ? -1 : 1;
1356 var dateTimezoneOffset = date.getTimezoneOffset();
1357 var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
1358 return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
1359}
1360
1361
1362/**
1363 * @returns {string} Returns the string representation of the element.
1364 */
1365function startingTag(element) {
1366 element = jqLite(element).clone();
1367 try {
1368 // turns out IE does not let you set .html() on elements which
1369 // are not allowed to have children. So we just ignore it.
1370 element.empty();
1371 } catch (e) {}
1372 var elemHtml = jqLite('<div>').append(element).html();
1373 try {
1374 return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
1375 elemHtml.
1376 match(/^(<[^>]+>)/)[1].
1377 replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
1378 } catch (e) {
1379 return lowercase(elemHtml);
1380 }
1381
1382}
1383
1384
1385/////////////////////////////////////////////////
1386
1387/**
1388 * Tries to decode the URI component without throwing an exception.
1389 *
1390 * @private
1391 * @param str value potential URI component to check.
1392 * @returns {boolean} True if `value` can be decoded
1393 * with the decodeURIComponent function.
1394 */
1395function tryDecodeURIComponent(value) {
1396 try {
1397 return decodeURIComponent(value);
1398 } catch (e) {
1399 // Ignore any invalid uri component.
1400 }
1401}
1402
1403
1404/**
1405 * Parses an escaped url query string into key-value pairs.
1406 * @returns {Object.<string,boolean|Array>}
1407 */
1408function parseKeyValue(/**string*/keyValue) {
1409 var obj = {};
1410 forEach((keyValue || "").split('&'), function(keyValue) {
1411 var splitPoint, key, val;
1412 if (keyValue) {
1413 key = keyValue = keyValue.replace(/\+/g,'%20');
1414 splitPoint = keyValue.indexOf('=');
1415 if (splitPoint !== -1) {
1416 key = keyValue.substring(0, splitPoint);
1417 val = keyValue.substring(splitPoint + 1);
1418 }
1419 key = tryDecodeURIComponent(key);
1420 if (isDefined(key)) {
1421 val = isDefined(val) ? tryDecodeURIComponent(val) : true;
1422 if (!hasOwnProperty.call(obj, key)) {
1423 obj[key] = val;
1424 } else if (isArray(obj[key])) {
1425 obj[key].push(val);
1426 } else {
1427 obj[key] = [obj[key],val];
1428 }
1429 }
1430 }
1431 });
1432 return obj;
1433}
1434
1435function toKeyValue(obj) {
1436 var parts = [];
1437 forEach(obj, function(value, key) {
1438 if (isArray(value)) {
1439 forEach(value, function(arrayValue) {
1440 parts.push(encodeUriQuery(key, true) +
1441 (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
1442 });
1443 } else {
1444 parts.push(encodeUriQuery(key, true) +
1445 (value === true ? '' : '=' + encodeUriQuery(value, true)));
1446 }
1447 });
1448 return parts.length ? parts.join('&') : '';
1449}
1450
1451
1452/**
1453 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
1454 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
1455 * segments:
1456 * segment = *pchar
1457 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
1458 * pct-encoded = "%" HEXDIG HEXDIG
1459 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1460 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1461 * / "*" / "+" / "," / ";" / "="
1462 */
1463function encodeUriSegment(val) {
1464 return encodeUriQuery(val, true).
1465 replace(/%26/gi, '&').
1466 replace(/%3D/gi, '=').
1467 replace(/%2B/gi, '+');
1468}
1469
1470
1471/**
1472 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
1473 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
1474 * encoded per http://tools.ietf.org/html/rfc3986:
1475 * query = *( pchar / "/" / "?" )
1476 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
1477 * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1478 * pct-encoded = "%" HEXDIG HEXDIG
1479 * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
1480 * / "*" / "+" / "," / ";" / "="
1481 */
1482function encodeUriQuery(val, pctEncodeSpaces) {
1483 return encodeURIComponent(val).
1484 replace(/%40/gi, '@').
1485 replace(/%3A/gi, ':').
1486 replace(/%24/g, '$').
1487 replace(/%2C/gi, ',').
1488 replace(/%3B/gi, ';').
1489 replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
1490}
1491
1492var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
1493
1494function getNgAttribute(element, ngAttr) {
1495 var attr, i, ii = ngAttrPrefixes.length;
1496 for (i = 0; i < ii; ++i) {
1497 attr = ngAttrPrefixes[i] + ngAttr;
1498 if (isString(attr = element.getAttribute(attr))) {
1499 return attr;
1500 }
1501 }
1502 return null;
1503}
1504
1505/**
1506 * @ngdoc directive
1507 * @name ngApp
1508 * @module ng
1509 *
1510 * @element ANY
1511 * @param {angular.Module} ngApp an optional application
1512 * {@link angular.module module} name to load.
1513 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
1514 * created in "strict-di" mode. This means that the application will fail to invoke functions which
1515 * do not use explicit function annotation (and are thus unsuitable for minification), as described
1516 * in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
1517 * tracking down the root of these bugs.
1518 *
1519 * @description
1520 *
1521 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
1522 * designates the **root element** of the application and is typically placed near the root element
1523 * of the page - e.g. on the `<body>` or `<html>` tags.
1524 *
1525 * There are a few things to keep in mind when using `ngApp`:
1526 * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
1527 * found in the document will be used to define the root element to auto-bootstrap as an
1528 * application. To run multiple applications in an HTML document you must manually bootstrap them using
1529 * {@link angular.bootstrap} instead.
1530 * - AngularJS applications cannot be nested within each other.
1531 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
1532 * This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
1533 * {@link ngRoute.ngView `ngView`}.
1534 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1535 * causing animations to stop working and making the injector inaccessible from outside the app.
1536 *
1537 * You can specify an **AngularJS module** to be used as the root module for the application. This
1538 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
1539 * should contain the application code needed or have dependencies on other modules that will
1540 * contain the code. See {@link angular.module} for more information.
1541 *
1542 * In the example below if the `ngApp` directive were not placed on the `html` element then the
1543 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
1544 * would not be resolved to `3`.
1545 *
1546 * `ngApp` is the easiest, and most common way to bootstrap an application.
1547 *
1548 <example module="ngAppDemo">
1549 <file name="index.html">
1550 <div ng-controller="ngAppDemoController">
1551 I can add: {{a}} + {{b}} = {{ a+b }}
1552 </div>
1553 </file>
1554 <file name="script.js">
1555 angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
1556 $scope.a = 1;
1557 $scope.b = 2;
1558 });
1559 </file>
1560 </example>
1561 *
1562 * Using `ngStrictDi`, you would see something like this:
1563 *
1564 <example ng-app-included="true">
1565 <file name="index.html">
1566 <div ng-app="ngAppStrictDemo" ng-strict-di>
1567 <div ng-controller="GoodController1">
1568 I can add: {{a}} + {{b}} = {{ a+b }}
1569
1570 <p>This renders because the controller does not fail to
1571 instantiate, by using explicit annotation style (see
1572 script.js for details)
1573 </p>
1574 </div>
1575
1576 <div ng-controller="GoodController2">
1577 Name: <input ng-model="name"><br />
1578 Hello, {{name}}!
1579
1580 <p>This renders because the controller does not fail to
1581 instantiate, by using explicit annotation style
1582 (see script.js for details)
1583 </p>
1584 </div>
1585
1586 <div ng-controller="BadController">
1587 I can add: {{a}} + {{b}} = {{ a+b }}
1588
1589 <p>The controller could not be instantiated, due to relying
1590 on automatic function annotations (which are disabled in
1591 strict mode). As such, the content of this section is not
1592 interpolated, and there should be an error in your web console.
1593 </p>
1594 </div>
1595 </div>
1596 </file>
1597 <file name="script.js">
1598 angular.module('ngAppStrictDemo', [])
1599 // BadController will fail to instantiate, due to relying on automatic function annotation,
1600 // rather than an explicit annotation
1601 .controller('BadController', function($scope) {
1602 $scope.a = 1;
1603 $scope.b = 2;
1604 })
1605 // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
1606 // due to using explicit annotations using the array style and $inject property, respectively.
1607 .controller('GoodController1', ['$scope', function($scope) {
1608 $scope.a = 1;
1609 $scope.b = 2;
1610 }])
1611 .controller('GoodController2', GoodController2);
1612 function GoodController2($scope) {
1613 $scope.name = "World";
1614 }
1615 GoodController2.$inject = ['$scope'];
1616 </file>
1617 <file name="style.css">
1618 div[ng-controller] {
1619 margin-bottom: 1em;
1620 -webkit-border-radius: 4px;
1621 border-radius: 4px;
1622 border: 1px solid;
1623 padding: .5em;
1624 }
1625 div[ng-controller^=Good] {
1626 border-color: #d6e9c6;
1627 background-color: #dff0d8;
1628 color: #3c763d;
1629 }
1630 div[ng-controller^=Bad] {
1631 border-color: #ebccd1;
1632 background-color: #f2dede;
1633 color: #a94442;
1634 margin-bottom: 0;
1635 }
1636 </file>
1637 </example>
1638 */
1639function angularInit(element, bootstrap) {
1640 var appElement,
1641 module,
1642 config = {};
1643
1644 // The element `element` has priority over any other element.
1645 forEach(ngAttrPrefixes, function(prefix) {
1646 var name = prefix + 'app';
1647
1648 if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
1649 appElement = element;
1650 module = element.getAttribute(name);
1651 }
1652 });
1653 forEach(ngAttrPrefixes, function(prefix) {
1654 var name = prefix + 'app';
1655 var candidate;
1656
1657 if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
1658 appElement = candidate;
1659 module = candidate.getAttribute(name);
1660 }
1661 });
1662 if (appElement) {
1663 config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
1664 bootstrap(appElement, module ? [module] : [], config);
1665 }
1666}
1667
1668/**
1669 * @ngdoc function
1670 * @name angular.bootstrap
1671 * @module ng
1672 * @description
1673 * Use this function to manually start up angular application.
1674 *
1675 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
1676 *
1677 * Angular will detect if it has been loaded into the browser more than once and only allow the
1678 * first loaded script to be bootstrapped and will report a warning to the browser console for
1679 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
1680 * multiple instances of Angular try to work on the DOM.
1681 *
1682 * <div class="alert alert-warning">
1683 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
1684 * They must use {@link ng.directive:ngApp ngApp}.
1685 * </div>
1686 *
1687 * <div class="alert alert-warning">
1688 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
1689 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
1690 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
1691 * causing animations to stop working and making the injector inaccessible from outside the app.
1692 * </div>
1693 *
1694 * ```html
1695 * <!doctype html>
1696 * <html>
1697 * <body>
1698 * <div ng-controller="WelcomeController">
1699 * {{greeting}}
1700 * </div>
1701 *
1702 * <script src="angular.js"></script>
1703 * <script>
1704 * var app = angular.module('demo', [])
1705 * .controller('WelcomeController', function($scope) {
1706 * $scope.greeting = 'Welcome!';
1707 * });
1708 * angular.bootstrap(document, ['demo']);
1709 * </script>
1710 * </body>
1711 * </html>
1712 * ```
1713 *
1714 * @param {DOMElement} element DOM element which is the root of angular application.
1715 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
1716 * Each item in the array should be the name of a predefined module or a (DI annotated)
1717 * function that will be invoked by the injector as a `config` block.
1718 * See: {@link angular.module modules}
1719 * @param {Object=} config an object for defining configuration options for the application. The
1720 * following keys are supported:
1721 *
1722 * * `strictDi` - disable automatic function annotation for the application. This is meant to
1723 * assist in finding bugs which break minified code. Defaults to `false`.
1724 *
1725 * @returns {auto.$injector} Returns the newly created injector for this app.
1726 */
1727function bootstrap(element, modules, config) {
1728 if (!isObject(config)) config = {};
1729 var defaultConfig = {
1730 strictDi: false
1731 };
1732 config = extend(defaultConfig, config);
1733 var doBootstrap = function() {
1734 element = jqLite(element);
1735
1736 if (element.injector()) {
1737 var tag = (element[0] === window.document) ? 'document' : startingTag(element);
1738 // Encode angle brackets to prevent input from being sanitized to empty string #8683.
1739 throw ngMinErr(
1740 'btstrpd',
1741 "App already bootstrapped with this element '{0}'",
1742 tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
1743 }
1744
1745 modules = modules || [];
1746 modules.unshift(['$provide', function($provide) {
1747 $provide.value('$rootElement', element);
1748 }]);
1749
1750 if (config.debugInfoEnabled) {
1751 // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
1752 modules.push(['$compileProvider', function($compileProvider) {
1753 $compileProvider.debugInfoEnabled(true);
1754 }]);
1755 }
1756
1757 modules.unshift('ng');
1758 var injector = createInjector(modules, config.strictDi);
1759 injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
1760 function bootstrapApply(scope, element, compile, injector) {
1761 scope.$apply(function() {
1762 element.data('$injector', injector);
1763 compile(element)(scope);
1764 });
1765 }]
1766 );
1767 return injector;
1768 };
1769
1770 var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
1771 var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
1772
1773 if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
1774 config.debugInfoEnabled = true;
1775 window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
1776 }
1777
1778 if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
1779 return doBootstrap();
1780 }
1781
1782 window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
1783 angular.resumeBootstrap = function(extraModules) {
1784 forEach(extraModules, function(module) {
1785 modules.push(module);
1786 });
1787 return doBootstrap();
1788 };
1789
1790 if (isFunction(angular.resumeDeferredBootstrap)) {
1791 angular.resumeDeferredBootstrap();
1792 }
1793}
1794
1795/**
1796 * @ngdoc function
1797 * @name angular.reloadWithDebugInfo
1798 * @module ng
1799 * @description
1800 * Use this function to reload the current application with debug information turned on.
1801 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
1802 *
1803 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
1804 */
1805function reloadWithDebugInfo() {
1806 window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
1807 window.location.reload();
1808}
1809
1810/**
1811 * @name angular.getTestability
1812 * @module ng
1813 * @description
1814 * Get the testability service for the instance of Angular on the given
1815 * element.
1816 * @param {DOMElement} element DOM element which is the root of angular application.
1817 */
1818function getTestability(rootElement) {
1819 var injector = angular.element(rootElement).injector();
1820 if (!injector) {
1821 throw ngMinErr('test',
1822 'no injector found for element argument to getTestability');
1823 }
1824 return injector.get('$$testability');
1825}
1826
1827var SNAKE_CASE_REGEXP = /[A-Z]/g;
1828function snake_case(name, separator) {
1829 separator = separator || '_';
1830 return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
1831 return (pos ? separator : '') + letter.toLowerCase();
1832 });
1833}
1834
1835var bindJQueryFired = false;
1836function bindJQuery() {
1837 var originalCleanData;
1838
1839 if (bindJQueryFired) {
1840 return;
1841 }
1842
1843 // bind to jQuery if present;
1844 var jqName = jq();
1845 jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present)
1846 !jqName ? undefined : // use jqLite
1847 window[jqName]; // use jQuery specified by `ngJq`
1848
1849 // Use jQuery if it exists with proper functionality, otherwise default to us.
1850 // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
1851 // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
1852 // versions. It will not work for sure with jQuery <1.7, though.
1853 if (jQuery && jQuery.fn.on) {
1854 jqLite = jQuery;
1855 extend(jQuery.fn, {
1856 scope: JQLitePrototype.scope,
1857 isolateScope: JQLitePrototype.isolateScope,
1858 controller: JQLitePrototype.controller,
1859 injector: JQLitePrototype.injector,
1860 inheritedData: JQLitePrototype.inheritedData
1861 });
1862
1863 // All nodes removed from the DOM via various jQuery APIs like .remove()
1864 // are passed through jQuery.cleanData. Monkey-patch this method to fire
1865 // the $destroy event on all removed nodes.
1866 originalCleanData = jQuery.cleanData;
1867 jQuery.cleanData = function(elems) {
1868 var events;
1869 for (var i = 0, elem; (elem = elems[i]) != null; i++) {
1870 events = jQuery._data(elem, "events");
1871 if (events && events.$destroy) {
1872 jQuery(elem).triggerHandler('$destroy');
1873 }
1874 }
1875 originalCleanData(elems);
1876 };
1877 } else {
1878 jqLite = JQLite;
1879 }
1880
1881 angular.element = jqLite;
1882
1883 // Prevent double-proxying.
1884 bindJQueryFired = true;
1885}
1886
1887/**
1888 * throw error if the argument is falsy.
1889 */
1890function assertArg(arg, name, reason) {
1891 if (!arg) {
1892 throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
1893 }
1894 return arg;
1895}
1896
1897function assertArgFn(arg, name, acceptArrayAnnotation) {
1898 if (acceptArrayAnnotation && isArray(arg)) {
1899 arg = arg[arg.length - 1];
1900 }
1901
1902 assertArg(isFunction(arg), name, 'not a function, got ' +
1903 (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
1904 return arg;
1905}
1906
1907/**
1908 * throw error if the name given is hasOwnProperty
1909 * @param {String} name the name to test
1910 * @param {String} context the context in which the name is used, such as module or directive
1911 */
1912function assertNotHasOwnProperty(name, context) {
1913 if (name === 'hasOwnProperty') {
1914 throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
1915 }
1916}
1917
1918/**
1919 * Return the value accessible from the object by path. Any undefined traversals are ignored
1920 * @param {Object} obj starting object
1921 * @param {String} path path to traverse
1922 * @param {boolean} [bindFnToScope=true]
1923 * @returns {Object} value as accessible by path
1924 */
1925//TODO(misko): this function needs to be removed
1926function getter(obj, path, bindFnToScope) {
1927 if (!path) return obj;
1928 var keys = path.split('.');
1929 var key;
1930 var lastInstance = obj;
1931 var len = keys.length;
1932
1933 for (var i = 0; i < len; i++) {
1934 key = keys[i];
1935 if (obj) {
1936 obj = (lastInstance = obj)[key];
1937 }
1938 }
1939 if (!bindFnToScope && isFunction(obj)) {
1940 return bind(lastInstance, obj);
1941 }
1942 return obj;
1943}
1944
1945/**
1946 * Return the DOM siblings between the first and last node in the given array.
1947 * @param {Array} array like object
1948 * @returns {Array} the inputted object or a jqLite collection containing the nodes
1949 */
1950function getBlockNodes(nodes) {
1951 // TODO(perf): update `nodes` instead of creating a new object?
1952 var node = nodes[0];
1953 var endNode = nodes[nodes.length - 1];
1954 var blockNodes;
1955
1956 for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
1957 if (blockNodes || nodes[i] !== node) {
1958 if (!blockNodes) {
1959 blockNodes = jqLite(slice.call(nodes, 0, i));
1960 }
1961 blockNodes.push(node);
1962 }
1963 }
1964
1965 return blockNodes || nodes;
1966}
1967
1968
1969/**
1970 * Creates a new object without a prototype. This object is useful for lookup without having to
1971 * guard against prototypically inherited properties via hasOwnProperty.
1972 *
1973 * Related micro-benchmarks:
1974 * - http://jsperf.com/object-create2
1975 * - http://jsperf.com/proto-map-lookup/2
1976 * - http://jsperf.com/for-in-vs-object-keys2
1977 *
1978 * @returns {Object}
1979 */
1980function createMap() {
1981 return Object.create(null);
1982}
1983
1984var NODE_TYPE_ELEMENT = 1;
1985var NODE_TYPE_ATTRIBUTE = 2;
1986var NODE_TYPE_TEXT = 3;
1987var NODE_TYPE_COMMENT = 8;
1988var NODE_TYPE_DOCUMENT = 9;
1989var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
1990
1991/**
1992 * @ngdoc type
1993 * @name angular.Module
1994 * @module ng
1995 * @description
1996 *
1997 * Interface for configuring angular {@link angular.module modules}.
1998 */
1999
2000function setupModuleLoader(window) {
2001
2002 var $injectorMinErr = minErr('$injector');
2003 var ngMinErr = minErr('ng');
2004
2005 function ensure(obj, name, factory) {
2006 return obj[name] || (obj[name] = factory());
2007 }
2008
2009 var angular = ensure(window, 'angular', Object);
2010
2011 // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
2012 angular.$$minErr = angular.$$minErr || minErr;
2013
2014 return ensure(angular, 'module', function() {
2015 /** @type {Object.<string, angular.Module>} */
2016 var modules = {};
2017
2018 /**
2019 * @ngdoc function
2020 * @name angular.module
2021 * @module ng
2022 * @description
2023 *
2024 * The `angular.module` is a global place for creating, registering and retrieving Angular
2025 * modules.
2026 * All modules (angular core or 3rd party) that should be available to an application must be
2027 * registered using this mechanism.
2028 *
2029 * Passing one argument retrieves an existing {@link angular.Module},
2030 * whereas passing more than one argument creates a new {@link angular.Module}
2031 *
2032 *
2033 * # Module
2034 *
2035 * A module is a collection of services, directives, controllers, filters, and configuration information.
2036 * `angular.module` is used to configure the {@link auto.$injector $injector}.
2037 *
2038 * ```js
2039 * // Create a new module
2040 * var myModule = angular.module('myModule', []);
2041 *
2042 * // register a new service
2043 * myModule.value('appName', 'MyCoolApp');
2044 *
2045 * // configure existing services inside initialization blocks.
2046 * myModule.config(['$locationProvider', function($locationProvider) {
2047 * // Configure existing providers
2048 * $locationProvider.hashPrefix('!');
2049 * }]);
2050 * ```
2051 *
2052 * Then you can create an injector and load your modules like this:
2053 *
2054 * ```js
2055 * var injector = angular.injector(['ng', 'myModule'])
2056 * ```
2057 *
2058 * However it's more likely that you'll just use
2059 * {@link ng.directive:ngApp ngApp} or
2060 * {@link angular.bootstrap} to simplify this process for you.
2061 *
2062 * @param {!string} name The name of the module to create or retrieve.
2063 * @param {!Array.<string>=} requires If specified then new module is being created. If
2064 * unspecified then the module is being retrieved for further configuration.
2065 * @param {Function=} configFn Optional configuration function for the module. Same as
2066 * {@link angular.Module#config Module#config()}.
2067 * @returns {angular.Module} new module with the {@link angular.Module} api.
2068 */
2069 return function module(name, requires, configFn) {
2070 var assertNotHasOwnProperty = function(name, context) {
2071 if (name === 'hasOwnProperty') {
2072 throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
2073 }
2074 };
2075
2076 assertNotHasOwnProperty(name, 'module');
2077 if (requires && modules.hasOwnProperty(name)) {
2078 modules[name] = null;
2079 }
2080 return ensure(modules, name, function() {
2081 if (!requires) {
2082 throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
2083 "the module name or forgot to load it. If registering a module ensure that you " +
2084 "specify the dependencies as the second argument.", name);
2085 }
2086
2087 /** @type {!Array.<Array.<*>>} */
2088 var invokeQueue = [];
2089
2090 /** @type {!Array.<Function>} */
2091 var configBlocks = [];
2092
2093 /** @type {!Array.<Function>} */
2094 var runBlocks = [];
2095
2096 var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
2097
2098 /** @type {angular.Module} */
2099 var moduleInstance = {
2100 // Private state
2101 _invokeQueue: invokeQueue,
2102 _configBlocks: configBlocks,
2103 _runBlocks: runBlocks,
2104
2105 /**
2106 * @ngdoc property
2107 * @name angular.Module#requires
2108 * @module ng
2109 *
2110 * @description
2111 * Holds the list of modules which the injector will load before the current module is
2112 * loaded.
2113 */
2114 requires: requires,
2115
2116 /**
2117 * @ngdoc property
2118 * @name angular.Module#name
2119 * @module ng
2120 *
2121 * @description
2122 * Name of the module.
2123 */
2124 name: name,
2125
2126
2127 /**
2128 * @ngdoc method
2129 * @name angular.Module#provider
2130 * @module ng
2131 * @param {string} name service name
2132 * @param {Function} providerType Construction function for creating new instance of the
2133 * service.
2134 * @description
2135 * See {@link auto.$provide#provider $provide.provider()}.
2136 */
2137 provider: invokeLaterAndSetModuleName('$provide', 'provider'),
2138
2139 /**
2140 * @ngdoc method
2141 * @name angular.Module#factory
2142 * @module ng
2143 * @param {string} name service name
2144 * @param {Function} providerFunction Function for creating new instance of the service.
2145 * @description
2146 * See {@link auto.$provide#factory $provide.factory()}.
2147 */
2148 factory: invokeLaterAndSetModuleName('$provide', 'factory'),
2149
2150 /**
2151 * @ngdoc method
2152 * @name angular.Module#service
2153 * @module ng
2154 * @param {string} name service name
2155 * @param {Function} constructor A constructor function that will be instantiated.
2156 * @description
2157 * See {@link auto.$provide#service $provide.service()}.
2158 */
2159 service: invokeLaterAndSetModuleName('$provide', 'service'),
2160
2161 /**
2162 * @ngdoc method
2163 * @name angular.Module#value
2164 * @module ng
2165 * @param {string} name service name
2166 * @param {*} object Service instance object.
2167 * @description
2168 * See {@link auto.$provide#value $provide.value()}.
2169 */
2170 value: invokeLater('$provide', 'value'),
2171
2172 /**
2173 * @ngdoc method
2174 * @name angular.Module#constant
2175 * @module ng
2176 * @param {string} name constant name
2177 * @param {*} object Constant value.
2178 * @description
2179 * Because the constants are fixed, they get applied before other provide methods.
2180 * See {@link auto.$provide#constant $provide.constant()}.
2181 */
2182 constant: invokeLater('$provide', 'constant', 'unshift'),
2183
2184 /**
2185 * @ngdoc method
2186 * @name angular.Module#decorator
2187 * @module ng
2188 * @param {string} name The name of the service to decorate.
2189 * @param {Function} decorFn This function will be invoked when the service needs to be
2190 * instantiated and should return the decorated service instance.
2191 * @description
2192 * See {@link auto.$provide#decorator $provide.decorator()}.
2193 */
2194 decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
2195
2196 /**
2197 * @ngdoc method
2198 * @name angular.Module#animation
2199 * @module ng
2200 * @param {string} name animation name
2201 * @param {Function} animationFactory Factory function for creating new instance of an
2202 * animation.
2203 * @description
2204 *
2205 * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
2206 *
2207 *
2208 * Defines an animation hook that can be later used with
2209 * {@link $animate $animate} service and directives that use this service.
2210 *
2211 * ```js
2212 * module.animation('.animation-name', function($inject1, $inject2) {
2213 * return {
2214 * eventName : function(element, done) {
2215 * //code to run the animation
2216 * //once complete, then run done()
2217 * return function cancellationFunction(element) {
2218 * //code to cancel the animation
2219 * }
2220 * }
2221 * }
2222 * })
2223 * ```
2224 *
2225 * See {@link ng.$animateProvider#register $animateProvider.register()} and
2226 * {@link ngAnimate ngAnimate module} for more information.
2227 */
2228 animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
2229
2230 /**
2231 * @ngdoc method
2232 * @name angular.Module#filter
2233 * @module ng
2234 * @param {string} name Filter name - this must be a valid angular expression identifier
2235 * @param {Function} filterFactory Factory function for creating new instance of filter.
2236 * @description
2237 * See {@link ng.$filterProvider#register $filterProvider.register()}.
2238 *
2239 * <div class="alert alert-warning">
2240 * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
2241 * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
2242 * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
2243 * (`myapp_subsection_filterx`).
2244 * </div>
2245 */
2246 filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
2247
2248 /**
2249 * @ngdoc method
2250 * @name angular.Module#controller
2251 * @module ng
2252 * @param {string|Object} name Controller name, or an object map of controllers where the
2253 * keys are the names and the values are the constructors.
2254 * @param {Function} constructor Controller constructor function.
2255 * @description
2256 * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
2257 */
2258 controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
2259
2260 /**
2261 * @ngdoc method
2262 * @name angular.Module#directive
2263 * @module ng
2264 * @param {string|Object} name Directive name, or an object map of directives where the
2265 * keys are the names and the values are the factories.
2266 * @param {Function} directiveFactory Factory function for creating new instance of
2267 * directives.
2268 * @description
2269 * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
2270 */
2271 directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
2272
2273 /**
2274 * @ngdoc method
2275 * @name angular.Module#component
2276 * @module ng
2277 * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
2278 * @param {Object} options Component definition object (a simplified
2279 * {@link ng.$compile#directive-definition-object directive definition object})
2280 *
2281 * @description
2282 * See {@link ng.$compileProvider#component $compileProvider.component()}.
2283 */
2284 component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
2285
2286 /**
2287 * @ngdoc method
2288 * @name angular.Module#config
2289 * @module ng
2290 * @param {Function} configFn Execute this function on module load. Useful for service
2291 * configuration.
2292 * @description
2293 * Use this method to register work which needs to be performed on module loading.
2294 * For more about how to configure services, see
2295 * {@link providers#provider-recipe Provider Recipe}.
2296 */
2297 config: config,
2298
2299 /**
2300 * @ngdoc method
2301 * @name angular.Module#run
2302 * @module ng
2303 * @param {Function} initializationFn Execute this function after injector creation.
2304 * Useful for application initialization.
2305 * @description
2306 * Use this method to register work which should be performed when the injector is done
2307 * loading all modules.
2308 */
2309 run: function(block) {
2310 runBlocks.push(block);
2311 return this;
2312 }
2313 };
2314
2315 if (configFn) {
2316 config(configFn);
2317 }
2318
2319 return moduleInstance;
2320
2321 /**
2322 * @param {string} provider
2323 * @param {string} method
2324 * @param {String=} insertMethod
2325 * @returns {angular.Module}
2326 */
2327 function invokeLater(provider, method, insertMethod, queue) {
2328 if (!queue) queue = invokeQueue;
2329 return function() {
2330 queue[insertMethod || 'push']([provider, method, arguments]);
2331 return moduleInstance;
2332 };
2333 }
2334
2335 /**
2336 * @param {string} provider
2337 * @param {string} method
2338 * @returns {angular.Module}
2339 */
2340 function invokeLaterAndSetModuleName(provider, method) {
2341 return function(recipeName, factoryFunction) {
2342 if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
2343 invokeQueue.push([provider, method, arguments]);
2344 return moduleInstance;
2345 };
2346 }
2347 });
2348 };
2349 });
2350
2351}
2352
2353/* global shallowCopy: true */
2354
2355/**
2356 * Creates a shallow copy of an object, an array or a primitive.
2357 *
2358 * Assumes that there are no proto properties for objects.
2359 */
2360function shallowCopy(src, dst) {
2361 if (isArray(src)) {
2362 dst = dst || [];
2363
2364 for (var i = 0, ii = src.length; i < ii; i++) {
2365 dst[i] = src[i];
2366 }
2367 } else if (isObject(src)) {
2368 dst = dst || {};
2369
2370 for (var key in src) {
2371 if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
2372 dst[key] = src[key];
2373 }
2374 }
2375 }
2376
2377 return dst || src;
2378}
2379
2380/* global toDebugString: true */
2381
2382function serializeObject(obj) {
2383 var seen = [];
2384
2385 return JSON.stringify(obj, function(key, val) {
2386 val = toJsonReplacer(key, val);
2387 if (isObject(val)) {
2388
2389 if (seen.indexOf(val) >= 0) return '...';
2390
2391 seen.push(val);
2392 }
2393 return val;
2394 });
2395}
2396
2397function toDebugString(obj) {
2398 if (typeof obj === 'function') {
2399 return obj.toString().replace(/ \{[\s\S]*$/, '');
2400 } else if (isUndefined(obj)) {
2401 return 'undefined';
2402 } else if (typeof obj !== 'string') {
2403 return serializeObject(obj);
2404 }
2405 return obj;
2406}
2407
2408/* global angularModule: true,
2409 version: true,
2410
2411 $CompileProvider,
2412
2413 htmlAnchorDirective,
2414 inputDirective,
2415 inputDirective,
2416 formDirective,
2417 scriptDirective,
2418 selectDirective,
2419 styleDirective,
2420 optionDirective,
2421 ngBindDirective,
2422 ngBindHtmlDirective,
2423 ngBindTemplateDirective,
2424 ngClassDirective,
2425 ngClassEvenDirective,
2426 ngClassOddDirective,
2427 ngCloakDirective,
2428 ngControllerDirective,
2429 ngFormDirective,
2430 ngHideDirective,
2431 ngIfDirective,
2432 ngIncludeDirective,
2433 ngIncludeFillContentDirective,
2434 ngInitDirective,
2435 ngNonBindableDirective,
2436 ngPluralizeDirective,
2437 ngRepeatDirective,
2438 ngShowDirective,
2439 ngStyleDirective,
2440 ngSwitchDirective,
2441 ngSwitchWhenDirective,
2442 ngSwitchDefaultDirective,
2443 ngOptionsDirective,
2444 ngTranscludeDirective,
2445 ngModelDirective,
2446 ngListDirective,
2447 ngChangeDirective,
2448 patternDirective,
2449 patternDirective,
2450 requiredDirective,
2451 requiredDirective,
2452 minlengthDirective,
2453 minlengthDirective,
2454 maxlengthDirective,
2455 maxlengthDirective,
2456 ngValueDirective,
2457 ngModelOptionsDirective,
2458 ngAttributeAliasDirectives,
2459 ngEventDirectives,
2460
2461 $AnchorScrollProvider,
2462 $AnimateProvider,
2463 $CoreAnimateCssProvider,
2464 $$CoreAnimateJsProvider,
2465 $$CoreAnimateQueueProvider,
2466 $$AnimateRunnerFactoryProvider,
2467 $$AnimateAsyncRunFactoryProvider,
2468 $BrowserProvider,
2469 $CacheFactoryProvider,
2470 $ControllerProvider,
2471 $DateProvider,
2472 $DocumentProvider,
2473 $ExceptionHandlerProvider,
2474 $FilterProvider,
2475 $$ForceReflowProvider,
2476 $InterpolateProvider,
2477 $IntervalProvider,
2478 $$HashMapProvider,
2479 $HttpProvider,
2480 $HttpParamSerializerProvider,
2481 $HttpParamSerializerJQLikeProvider,
2482 $HttpBackendProvider,
2483 $xhrFactoryProvider,
2484 $jsonpCallbacksProvider,
2485 $LocationProvider,
2486 $LogProvider,
2487 $ParseProvider,
2488 $RootScopeProvider,
2489 $QProvider,
2490 $$QProvider,
2491 $$SanitizeUriProvider,
2492 $SceProvider,
2493 $SceDelegateProvider,
2494 $SnifferProvider,
2495 $TemplateCacheProvider,
2496 $TemplateRequestProvider,
2497 $$TestabilityProvider,
2498 $TimeoutProvider,
2499 $$RAFProvider,
2500 $WindowProvider,
2501 $$jqLiteProvider,
2502 $$CookieReaderProvider
2503*/
2504
2505
2506/**
2507 * @ngdoc object
2508 * @name angular.version
2509 * @module ng
2510 * @description
2511 * An object that contains information about the current AngularJS version.
2512 *
2513 * This object has the following properties:
2514 *
2515 * - `full` – `{string}` – Full version string, such as "0.9.18".
2516 * - `major` – `{number}` – Major version number, such as "0".
2517 * - `minor` – `{number}` – Minor version number, such as "9".
2518 * - `dot` – `{number}` – Dot version number, such as "18".
2519 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
2520 */
2521var version = {
2522 full: '1.5.8', // all of these placeholder strings will be replaced by grunt's
2523 major: 1, // package task
2524 minor: 5,
2525 dot: 8,
2526 codeName: 'arbitrary-fallbacks'
2527};
2528
2529
2530function publishExternalAPI(angular) {
2531 extend(angular, {
2532 'bootstrap': bootstrap,
2533 'copy': copy,
2534 'extend': extend,
2535 'merge': merge,
2536 'equals': equals,
2537 'element': jqLite,
2538 'forEach': forEach,
2539 'injector': createInjector,
2540 'noop': noop,
2541 'bind': bind,
2542 'toJson': toJson,
2543 'fromJson': fromJson,
2544 'identity': identity,
2545 'isUndefined': isUndefined,
2546 'isDefined': isDefined,
2547 'isString': isString,
2548 'isFunction': isFunction,
2549 'isObject': isObject,
2550 'isNumber': isNumber,
2551 'isElement': isElement,
2552 'isArray': isArray,
2553 'version': version,
2554 'isDate': isDate,
2555 'lowercase': lowercase,
2556 'uppercase': uppercase,
2557 'callbacks': {$$counter: 0},
2558 'getTestability': getTestability,
2559 '$$minErr': minErr,
2560 '$$csp': csp,
2561 'reloadWithDebugInfo': reloadWithDebugInfo
2562 });
2563
2564 angularModule = setupModuleLoader(window);
2565
2566 angularModule('ng', ['ngLocale'], ['$provide',
2567 function ngModule($provide) {
2568 // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
2569 $provide.provider({
2570 $$sanitizeUri: $$SanitizeUriProvider
2571 });
2572 $provide.provider('$compile', $CompileProvider).
2573 directive({
2574 a: htmlAnchorDirective,
2575 input: inputDirective,
2576 textarea: inputDirective,
2577 form: formDirective,
2578 script: scriptDirective,
2579 select: selectDirective,
2580 style: styleDirective,
2581 option: optionDirective,
2582 ngBind: ngBindDirective,
2583 ngBindHtml: ngBindHtmlDirective,
2584 ngBindTemplate: ngBindTemplateDirective,
2585 ngClass: ngClassDirective,
2586 ngClassEven: ngClassEvenDirective,
2587 ngClassOdd: ngClassOddDirective,
2588 ngCloak: ngCloakDirective,
2589 ngController: ngControllerDirective,
2590 ngForm: ngFormDirective,
2591 ngHide: ngHideDirective,
2592 ngIf: ngIfDirective,
2593 ngInclude: ngIncludeDirective,
2594 ngInit: ngInitDirective,
2595 ngNonBindable: ngNonBindableDirective,
2596 ngPluralize: ngPluralizeDirective,
2597 ngRepeat: ngRepeatDirective,
2598 ngShow: ngShowDirective,
2599 ngStyle: ngStyleDirective,
2600 ngSwitch: ngSwitchDirective,
2601 ngSwitchWhen: ngSwitchWhenDirective,
2602 ngSwitchDefault: ngSwitchDefaultDirective,
2603 ngOptions: ngOptionsDirective,
2604 ngTransclude: ngTranscludeDirective,
2605 ngModel: ngModelDirective,
2606 ngList: ngListDirective,
2607 ngChange: ngChangeDirective,
2608 pattern: patternDirective,
2609 ngPattern: patternDirective,
2610 required: requiredDirective,
2611 ngRequired: requiredDirective,
2612 minlength: minlengthDirective,
2613 ngMinlength: minlengthDirective,
2614 maxlength: maxlengthDirective,
2615 ngMaxlength: maxlengthDirective,
2616 ngValue: ngValueDirective,
2617 ngModelOptions: ngModelOptionsDirective
2618 }).
2619 directive({
2620 ngInclude: ngIncludeFillContentDirective
2621 }).
2622 directive(ngAttributeAliasDirectives).
2623 directive(ngEventDirectives);
2624 $provide.provider({
2625 $anchorScroll: $AnchorScrollProvider,
2626 $animate: $AnimateProvider,
2627 $animateCss: $CoreAnimateCssProvider,
2628 $$animateJs: $$CoreAnimateJsProvider,
2629 $$animateQueue: $$CoreAnimateQueueProvider,
2630 $$AnimateRunner: $$AnimateRunnerFactoryProvider,
2631 $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
2632 $browser: $BrowserProvider,
2633 $cacheFactory: $CacheFactoryProvider,
2634 $controller: $ControllerProvider,
2635 $document: $DocumentProvider,
2636 $exceptionHandler: $ExceptionHandlerProvider,
2637 $filter: $FilterProvider,
2638 $$forceReflow: $$ForceReflowProvider,
2639 $interpolate: $InterpolateProvider,
2640 $interval: $IntervalProvider,
2641 $http: $HttpProvider,
2642 $httpParamSerializer: $HttpParamSerializerProvider,
2643 $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
2644 $httpBackend: $HttpBackendProvider,
2645 $xhrFactory: $xhrFactoryProvider,
2646 $jsonpCallbacks: $jsonpCallbacksProvider,
2647 $location: $LocationProvider,
2648 $log: $LogProvider,
2649 $parse: $ParseProvider,
2650 $rootScope: $RootScopeProvider,
2651 $q: $QProvider,
2652 $$q: $$QProvider,
2653 $sce: $SceProvider,
2654 $sceDelegate: $SceDelegateProvider,
2655 $sniffer: $SnifferProvider,
2656 $templateCache: $TemplateCacheProvider,
2657 $templateRequest: $TemplateRequestProvider,
2658 $$testability: $$TestabilityProvider,
2659 $timeout: $TimeoutProvider,
2660 $window: $WindowProvider,
2661 $$rAF: $$RAFProvider,
2662 $$jqLite: $$jqLiteProvider,
2663 $$HashMap: $$HashMapProvider,
2664 $$cookieReader: $$CookieReaderProvider
2665 });
2666 }
2667 ]);
2668}
2669
2670/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2671 * Any commits to this file should be reviewed with security in mind. *
2672 * Changes to this file can potentially create security vulnerabilities. *
2673 * An approval from 2 Core members with history of modifying *
2674 * this file is required. *
2675 * *
2676 * Does the change somehow allow for arbitrary javascript to be executed? *
2677 * Or allows for someone to change the prototype of built-in objects? *
2678 * Or gives undesired access to variables likes document or window? *
2679 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2680
2681/* global JQLitePrototype: true,
2682 addEventListenerFn: true,
2683 removeEventListenerFn: true,
2684 BOOLEAN_ATTR: true,
2685 ALIASED_ATTR: true,
2686*/
2687
2688//////////////////////////////////
2689//JQLite
2690//////////////////////////////////
2691
2692/**
2693 * @ngdoc function
2694 * @name angular.element
2695 * @module ng
2696 * @kind function
2697 *
2698 * @description
2699 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
2700 *
2701 * If jQuery is available, `angular.element` is an alias for the
2702 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
2703 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
2704 *
2705 * jqLite is a tiny, API-compatible subset of jQuery that allows
2706 * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
2707 * commonly needed functionality with the goal of having a very small footprint.
2708 *
2709 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
2710 * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
2711 * specific version of jQuery if multiple versions exist on the page.
2712 *
2713 * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
2714 * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
2715 *
2716 * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
2717 * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
2718 * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
2719 *
2720 * ## Angular's jqLite
2721 * jqLite provides only the following jQuery methods:
2722 *
2723 * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
2724 * - [`after()`](http://api.jquery.com/after/)
2725 * - [`append()`](http://api.jquery.com/append/)
2726 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
2727 * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
2728 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
2729 * - [`clone()`](http://api.jquery.com/clone/)
2730 * - [`contents()`](http://api.jquery.com/contents/)
2731 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
2732 * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
2733 * - [`data()`](http://api.jquery.com/data/)
2734 * - [`detach()`](http://api.jquery.com/detach/)
2735 * - [`empty()`](http://api.jquery.com/empty/)
2736 * - [`eq()`](http://api.jquery.com/eq/)
2737 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
2738 * - [`hasClass()`](http://api.jquery.com/hasClass/)
2739 * - [`html()`](http://api.jquery.com/html/)
2740 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
2741 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
2742 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
2743 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
2744 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
2745 * - [`prepend()`](http://api.jquery.com/prepend/)
2746 * - [`prop()`](http://api.jquery.com/prop/)
2747 * - [`ready()`](http://api.jquery.com/ready/)
2748 * - [`remove()`](http://api.jquery.com/remove/)
2749 * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
2750 * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
2751 * - [`removeData()`](http://api.jquery.com/removeData/)
2752 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
2753 * - [`text()`](http://api.jquery.com/text/)
2754 * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
2755 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
2756 * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
2757 * - [`val()`](http://api.jquery.com/val/)
2758 * - [`wrap()`](http://api.jquery.com/wrap/)
2759 *
2760 * ## jQuery/jqLite Extras
2761 * Angular also provides the following additional methods and events to both jQuery and jqLite:
2762 *
2763 * ### Events
2764 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
2765 * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
2766 * element before it is removed.
2767 *
2768 * ### Methods
2769 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
2770 * retrieves controller associated with the `ngController` directive. If `name` is provided as
2771 * camelCase directive name, then the controller for this directive will be retrieved (e.g.
2772 * `'ngModel'`).
2773 * - `injector()` - retrieves the injector of the current element or its parent.
2774 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
2775 * element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
2776 * be enabled.
2777 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
2778 * current element. This getter should be used only on elements that contain a directive which starts a new isolate
2779 * scope. Calling `scope()` on this element always returns the original non-isolate scope.
2780 * Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
2781 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
2782 * parent element is reached.
2783 *
2784 * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
2785 * https://github.com/angular/angular.js/issues/14251 for more information.
2786 *
2787 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
2788 * @returns {Object} jQuery object.
2789 */
2790
2791JQLite.expando = 'ng339';
2792
2793var jqCache = JQLite.cache = {},
2794 jqId = 1,
2795 addEventListenerFn = function(element, type, fn) {
2796 element.addEventListener(type, fn, false);
2797 },
2798 removeEventListenerFn = function(element, type, fn) {
2799 element.removeEventListener(type, fn, false);
2800 };
2801
2802/*
2803 * !!! This is an undocumented "private" function !!!
2804 */
2805JQLite._data = function(node) {
2806 //jQuery always returns an object on cache miss
2807 return this.cache[node[this.expando]] || {};
2808};
2809
2810function jqNextId() { return ++jqId; }
2811
2812
2813var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
2814var MOZ_HACK_REGEXP = /^moz([A-Z])/;
2815var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
2816var jqLiteMinErr = minErr('jqLite');
2817
2818/**
2819 * Converts snake_case to camelCase.
2820 * Also there is special case for Moz prefix starting with upper case letter.
2821 * @param name Name to normalize
2822 */
2823function camelCase(name) {
2824 return name.
2825 replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
2826 return offset ? letter.toUpperCase() : letter;
2827 }).
2828 replace(MOZ_HACK_REGEXP, 'Moz$1');
2829}
2830
2831var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
2832var HTML_REGEXP = /<|&#?\w+;/;
2833var TAG_NAME_REGEXP = /<([\w:-]+)/;
2834var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
2835
2836var wrapMap = {
2837 'option': [1, '<select multiple="multiple">', '</select>'],
2838
2839 'thead': [1, '<table>', '</table>'],
2840 'col': [2, '<table><colgroup>', '</colgroup></table>'],
2841 'tr': [2, '<table><tbody>', '</tbody></table>'],
2842 'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
2843 '_default': [0, "", ""]
2844};
2845
2846wrapMap.optgroup = wrapMap.option;
2847wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
2848wrapMap.th = wrapMap.td;
2849
2850
2851function jqLiteIsTextNode(html) {
2852 return !HTML_REGEXP.test(html);
2853}
2854
2855function jqLiteAcceptsData(node) {
2856 // The window object can accept data but has no nodeType
2857 // Otherwise we are only interested in elements (1) and documents (9)
2858 var nodeType = node.nodeType;
2859 return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
2860}
2861
2862function jqLiteHasData(node) {
2863 for (var key in jqCache[node.ng339]) {
2864 return true;
2865 }
2866 return false;
2867}
2868
2869function jqLiteCleanData(nodes) {
2870 for (var i = 0, ii = nodes.length; i < ii; i++) {
2871 jqLiteRemoveData(nodes[i]);
2872 }
2873}
2874
2875function jqLiteBuildFragment(html, context) {
2876 var tmp, tag, wrap,
2877 fragment = context.createDocumentFragment(),
2878 nodes = [], i;
2879
2880 if (jqLiteIsTextNode(html)) {
2881 // Convert non-html into a text node
2882 nodes.push(context.createTextNode(html));
2883 } else {
2884 // Convert html into DOM nodes
2885 tmp = fragment.appendChild(context.createElement("div"));
2886 tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
2887 wrap = wrapMap[tag] || wrapMap._default;
2888 tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
2889
2890 // Descend through wrappers to the right content
2891 i = wrap[0];
2892 while (i--) {
2893 tmp = tmp.lastChild;
2894 }
2895
2896 nodes = concat(nodes, tmp.childNodes);
2897
2898 tmp = fragment.firstChild;
2899 tmp.textContent = "";
2900 }
2901
2902 // Remove wrapper from fragment
2903 fragment.textContent = "";
2904 fragment.innerHTML = ""; // Clear inner HTML
2905 forEach(nodes, function(node) {
2906 fragment.appendChild(node);
2907 });
2908
2909 return fragment;
2910}
2911
2912function jqLiteParseHTML(html, context) {
2913 context = context || window.document;
2914 var parsed;
2915
2916 if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
2917 return [context.createElement(parsed[1])];
2918 }
2919
2920 if ((parsed = jqLiteBuildFragment(html, context))) {
2921 return parsed.childNodes;
2922 }
2923
2924 return [];
2925}
2926
2927function jqLiteWrapNode(node, wrapper) {
2928 var parent = node.parentNode;
2929
2930 if (parent) {
2931 parent.replaceChild(wrapper, node);
2932 }
2933
2934 wrapper.appendChild(node);
2935}
2936
2937
2938// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
2939var jqLiteContains = window.Node.prototype.contains || function(arg) {
2940 // jshint bitwise: false
2941 return !!(this.compareDocumentPosition(arg) & 16);
2942 // jshint bitwise: true
2943};
2944
2945/////////////////////////////////////////////
2946function JQLite(element) {
2947 if (element instanceof JQLite) {
2948 return element;
2949 }
2950
2951 var argIsString;
2952
2953 if (isString(element)) {
2954 element = trim(element);
2955 argIsString = true;
2956 }
2957 if (!(this instanceof JQLite)) {
2958 if (argIsString && element.charAt(0) != '<') {
2959 throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
2960 }
2961 return new JQLite(element);
2962 }
2963
2964 if (argIsString) {
2965 jqLiteAddNodes(this, jqLiteParseHTML(element));
2966 } else {
2967 jqLiteAddNodes(this, element);
2968 }
2969}
2970
2971function jqLiteClone(element) {
2972 return element.cloneNode(true);
2973}
2974
2975function jqLiteDealoc(element, onlyDescendants) {
2976 if (!onlyDescendants) jqLiteRemoveData(element);
2977
2978 if (element.querySelectorAll) {
2979 var descendants = element.querySelectorAll('*');
2980 for (var i = 0, l = descendants.length; i < l; i++) {
2981 jqLiteRemoveData(descendants[i]);
2982 }
2983 }
2984}
2985
2986function jqLiteOff(element, type, fn, unsupported) {
2987 if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
2988
2989 var expandoStore = jqLiteExpandoStore(element);
2990 var events = expandoStore && expandoStore.events;
2991 var handle = expandoStore && expandoStore.handle;
2992
2993 if (!handle) return; //no listeners registered
2994
2995 if (!type) {
2996 for (type in events) {
2997 if (type !== '$destroy') {
2998 removeEventListenerFn(element, type, handle);
2999 }
3000 delete events[type];
3001 }
3002 } else {
3003
3004 var removeHandler = function(type) {
3005 var listenerFns = events[type];
3006 if (isDefined(fn)) {
3007 arrayRemove(listenerFns || [], fn);
3008 }
3009 if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
3010 removeEventListenerFn(element, type, handle);
3011 delete events[type];
3012 }
3013 };
3014
3015 forEach(type.split(' '), function(type) {
3016 removeHandler(type);
3017 if (MOUSE_EVENT_MAP[type]) {
3018 removeHandler(MOUSE_EVENT_MAP[type]);
3019 }
3020 });
3021 }
3022}
3023
3024function jqLiteRemoveData(element, name) {
3025 var expandoId = element.ng339;
3026 var expandoStore = expandoId && jqCache[expandoId];
3027
3028 if (expandoStore) {
3029 if (name) {
3030 delete expandoStore.data[name];
3031 return;
3032 }
3033
3034 if (expandoStore.handle) {
3035 if (expandoStore.events.$destroy) {
3036 expandoStore.handle({}, '$destroy');
3037 }
3038 jqLiteOff(element);
3039 }
3040 delete jqCache[expandoId];
3041 element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
3042 }
3043}
3044
3045
3046function jqLiteExpandoStore(element, createIfNecessary) {
3047 var expandoId = element.ng339,
3048 expandoStore = expandoId && jqCache[expandoId];
3049
3050 if (createIfNecessary && !expandoStore) {
3051 element.ng339 = expandoId = jqNextId();
3052 expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
3053 }
3054
3055 return expandoStore;
3056}
3057
3058
3059function jqLiteData(element, key, value) {
3060 if (jqLiteAcceptsData(element)) {
3061
3062 var isSimpleSetter = isDefined(value);
3063 var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
3064 var massGetter = !key;
3065 var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
3066 var data = expandoStore && expandoStore.data;
3067
3068 if (isSimpleSetter) { // data('key', value)
3069 data[key] = value;
3070 } else {
3071 if (massGetter) { // data()
3072 return data;
3073 } else {
3074 if (isSimpleGetter) { // data('key')
3075 // don't force creation of expandoStore if it doesn't exist yet
3076 return data && data[key];
3077 } else { // mass-setter: data({key1: val1, key2: val2})
3078 extend(data, key);
3079 }
3080 }
3081 }
3082 }
3083}
3084
3085function jqLiteHasClass(element, selector) {
3086 if (!element.getAttribute) return false;
3087 return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
3088 indexOf(" " + selector + " ") > -1);
3089}
3090
3091function jqLiteRemoveClass(element, cssClasses) {
3092 if (cssClasses && element.setAttribute) {
3093 forEach(cssClasses.split(' '), function(cssClass) {
3094 element.setAttribute('class', trim(
3095 (" " + (element.getAttribute('class') || '') + " ")
3096 .replace(/[\n\t]/g, " ")
3097 .replace(" " + trim(cssClass) + " ", " "))
3098 );
3099 });
3100 }
3101}
3102
3103function jqLiteAddClass(element, cssClasses) {
3104 if (cssClasses && element.setAttribute) {
3105 var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
3106 .replace(/[\n\t]/g, " ");
3107
3108 forEach(cssClasses.split(' '), function(cssClass) {
3109 cssClass = trim(cssClass);
3110 if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
3111 existingClasses += cssClass + ' ';
3112 }
3113 });
3114
3115 element.setAttribute('class', trim(existingClasses));
3116 }
3117}
3118
3119
3120function jqLiteAddNodes(root, elements) {
3121 // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
3122
3123 if (elements) {
3124
3125 // if a Node (the most common case)
3126 if (elements.nodeType) {
3127 root[root.length++] = elements;
3128 } else {
3129 var length = elements.length;
3130
3131 // if an Array or NodeList and not a Window
3132 if (typeof length === 'number' && elements.window !== elements) {
3133 if (length) {
3134 for (var i = 0; i < length; i++) {
3135 root[root.length++] = elements[i];
3136 }
3137 }
3138 } else {
3139 root[root.length++] = elements;
3140 }
3141 }
3142 }
3143}
3144
3145
3146function jqLiteController(element, name) {
3147 return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
3148}
3149
3150function jqLiteInheritedData(element, name, value) {
3151 // if element is the document object work with the html element instead
3152 // this makes $(document).scope() possible
3153 if (element.nodeType == NODE_TYPE_DOCUMENT) {
3154 element = element.documentElement;
3155 }
3156 var names = isArray(name) ? name : [name];
3157
3158 while (element) {
3159 for (var i = 0, ii = names.length; i < ii; i++) {
3160 if (isDefined(value = jqLite.data(element, names[i]))) return value;
3161 }
3162
3163 // If dealing with a document fragment node with a host element, and no parent, use the host
3164 // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
3165 // to lookup parent controllers.
3166 element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
3167 }
3168}
3169
3170function jqLiteEmpty(element) {
3171 jqLiteDealoc(element, true);
3172 while (element.firstChild) {
3173 element.removeChild(element.firstChild);
3174 }
3175}
3176
3177function jqLiteRemove(element, keepData) {
3178 if (!keepData) jqLiteDealoc(element);
3179 var parent = element.parentNode;
3180 if (parent) parent.removeChild(element);
3181}
3182
3183
3184function jqLiteDocumentLoaded(action, win) {
3185 win = win || window;
3186 if (win.document.readyState === 'complete') {
3187 // Force the action to be run async for consistent behavior
3188 // from the action's point of view
3189 // i.e. it will definitely not be in a $apply
3190 win.setTimeout(action);
3191 } else {
3192 // No need to unbind this handler as load is only ever called once
3193 jqLite(win).on('load', action);
3194 }
3195}
3196
3197//////////////////////////////////////////
3198// Functions which are declared directly.
3199//////////////////////////////////////////
3200var JQLitePrototype = JQLite.prototype = {
3201 ready: function(fn) {
3202 var fired = false;
3203
3204 function trigger() {
3205 if (fired) return;
3206 fired = true;
3207 fn();
3208 }
3209
3210 // check if document is already loaded
3211 if (window.document.readyState === 'complete') {
3212 window.setTimeout(trigger);
3213 } else {
3214 this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
3215 // we can not use jqLite since we are not done loading and jQuery could be loaded later.
3216 // jshint -W064
3217 JQLite(window).on('load', trigger); // fallback to window.onload for others
3218 // jshint +W064
3219 }
3220 },
3221 toString: function() {
3222 var value = [];
3223 forEach(this, function(e) { value.push('' + e);});
3224 return '[' + value.join(', ') + ']';
3225 },
3226
3227 eq: function(index) {
3228 return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
3229 },
3230
3231 length: 0,
3232 push: push,
3233 sort: [].sort,
3234 splice: [].splice
3235};
3236
3237//////////////////////////////////////////
3238// Functions iterating getter/setters.
3239// these functions return self on setter and
3240// value on get.
3241//////////////////////////////////////////
3242var BOOLEAN_ATTR = {};
3243forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
3244 BOOLEAN_ATTR[lowercase(value)] = value;
3245});
3246var BOOLEAN_ELEMENTS = {};
3247forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
3248 BOOLEAN_ELEMENTS[value] = true;
3249});
3250var ALIASED_ATTR = {
3251 'ngMinlength': 'minlength',
3252 'ngMaxlength': 'maxlength',
3253 'ngMin': 'min',
3254 'ngMax': 'max',
3255 'ngPattern': 'pattern'
3256};
3257
3258function getBooleanAttrName(element, name) {
3259 // check dom last since we will most likely fail on name
3260 var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
3261
3262 // booleanAttr is here twice to minimize DOM access
3263 return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
3264}
3265
3266function getAliasedAttrName(name) {
3267 return ALIASED_ATTR[name];
3268}
3269
3270forEach({
3271 data: jqLiteData,
3272 removeData: jqLiteRemoveData,
3273 hasData: jqLiteHasData,
3274 cleanData: jqLiteCleanData
3275}, function(fn, name) {
3276 JQLite[name] = fn;
3277});
3278
3279forEach({
3280 data: jqLiteData,
3281 inheritedData: jqLiteInheritedData,
3282
3283 scope: function(element) {
3284 // Can't use jqLiteData here directly so we stay compatible with jQuery!
3285 return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
3286 },
3287
3288 isolateScope: function(element) {
3289 // Can't use jqLiteData here directly so we stay compatible with jQuery!
3290 return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
3291 },
3292
3293 controller: jqLiteController,
3294
3295 injector: function(element) {
3296 return jqLiteInheritedData(element, '$injector');
3297 },
3298
3299 removeAttr: function(element, name) {
3300 element.removeAttribute(name);
3301 },
3302
3303 hasClass: jqLiteHasClass,
3304
3305 css: function(element, name, value) {
3306 name = camelCase(name);
3307
3308 if (isDefined(value)) {
3309 element.style[name] = value;
3310 } else {
3311 return element.style[name];
3312 }
3313 },
3314
3315 attr: function(element, name, value) {
3316 var nodeType = element.nodeType;
3317 if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
3318 return;
3319 }
3320 var lowercasedName = lowercase(name);
3321 if (BOOLEAN_ATTR[lowercasedName]) {
3322 if (isDefined(value)) {
3323 if (!!value) {
3324 element[name] = true;
3325 element.setAttribute(name, lowercasedName);
3326 } else {
3327 element[name] = false;
3328 element.removeAttribute(lowercasedName);
3329 }
3330 } else {
3331 return (element[name] ||
3332 (element.attributes.getNamedItem(name) || noop).specified)
3333 ? lowercasedName
3334 : undefined;
3335 }
3336 } else if (isDefined(value)) {
3337 element.setAttribute(name, value);
3338 } else if (element.getAttribute) {
3339 // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
3340 // some elements (e.g. Document) don't have get attribute, so return undefined
3341 var ret = element.getAttribute(name, 2);
3342 // normalize non-existing attributes to undefined (as jQuery)
3343 return ret === null ? undefined : ret;
3344 }
3345 },
3346
3347 prop: function(element, name, value) {
3348 if (isDefined(value)) {
3349 element[name] = value;
3350 } else {
3351 return element[name];
3352 }
3353 },
3354
3355 text: (function() {
3356 getText.$dv = '';
3357 return getText;
3358
3359 function getText(element, value) {
3360 if (isUndefined(value)) {
3361 var nodeType = element.nodeType;
3362 return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
3363 }
3364 element.textContent = value;
3365 }
3366 })(),
3367
3368 val: function(element, value) {
3369 if (isUndefined(value)) {
3370 if (element.multiple && nodeName_(element) === 'select') {
3371 var result = [];
3372 forEach(element.options, function(option) {
3373 if (option.selected) {
3374 result.push(option.value || option.text);
3375 }
3376 });
3377 return result.length === 0 ? null : result;
3378 }
3379 return element.value;
3380 }
3381 element.value = value;
3382 },
3383
3384 html: function(element, value) {
3385 if (isUndefined(value)) {
3386 return element.innerHTML;
3387 }
3388 jqLiteDealoc(element, true);
3389 element.innerHTML = value;
3390 },
3391
3392 empty: jqLiteEmpty
3393}, function(fn, name) {
3394 /**
3395 * Properties: writes return selection, reads return first value
3396 */
3397 JQLite.prototype[name] = function(arg1, arg2) {
3398 var i, key;
3399 var nodeCount = this.length;
3400
3401 // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
3402 // in a way that survives minification.
3403 // jqLiteEmpty takes no arguments but is a setter.
3404 if (fn !== jqLiteEmpty &&
3405 (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
3406 if (isObject(arg1)) {
3407
3408 // we are a write, but the object properties are the key/values
3409 for (i = 0; i < nodeCount; i++) {
3410 if (fn === jqLiteData) {
3411 // data() takes the whole object in jQuery
3412 fn(this[i], arg1);
3413 } else {
3414 for (key in arg1) {
3415 fn(this[i], key, arg1[key]);
3416 }
3417 }
3418 }
3419 // return self for chaining
3420 return this;
3421 } else {
3422 // we are a read, so read the first child.
3423 // TODO: do we still need this?
3424 var value = fn.$dv;
3425 // Only if we have $dv do we iterate over all, otherwise it is just the first element.
3426 var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
3427 for (var j = 0; j < jj; j++) {
3428 var nodeValue = fn(this[j], arg1, arg2);
3429 value = value ? value + nodeValue : nodeValue;
3430 }
3431 return value;
3432 }
3433 } else {
3434 // we are a write, so apply to all children
3435 for (i = 0; i < nodeCount; i++) {
3436 fn(this[i], arg1, arg2);
3437 }
3438 // return self for chaining
3439 return this;
3440 }
3441 };
3442});
3443
3444function createEventHandler(element, events) {
3445 var eventHandler = function(event, type) {
3446 // jQuery specific api
3447 event.isDefaultPrevented = function() {
3448 return event.defaultPrevented;
3449 };
3450
3451 var eventFns = events[type || event.type];
3452 var eventFnsLength = eventFns ? eventFns.length : 0;
3453
3454 if (!eventFnsLength) return;
3455
3456 if (isUndefined(event.immediatePropagationStopped)) {
3457 var originalStopImmediatePropagation = event.stopImmediatePropagation;
3458 event.stopImmediatePropagation = function() {
3459 event.immediatePropagationStopped = true;
3460
3461 if (event.stopPropagation) {
3462 event.stopPropagation();
3463 }
3464
3465 if (originalStopImmediatePropagation) {
3466 originalStopImmediatePropagation.call(event);
3467 }
3468 };
3469 }
3470
3471 event.isImmediatePropagationStopped = function() {
3472 return event.immediatePropagationStopped === true;
3473 };
3474
3475 // Some events have special handlers that wrap the real handler
3476 var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
3477
3478 // Copy event handlers in case event handlers array is modified during execution.
3479 if ((eventFnsLength > 1)) {
3480 eventFns = shallowCopy(eventFns);
3481 }
3482
3483 for (var i = 0; i < eventFnsLength; i++) {
3484 if (!event.isImmediatePropagationStopped()) {
3485 handlerWrapper(element, event, eventFns[i]);
3486 }
3487 }
3488 };
3489
3490 // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
3491 // events on `element`
3492 eventHandler.elem = element;
3493 return eventHandler;
3494}
3495
3496function defaultHandlerWrapper(element, event, handler) {
3497 handler.call(element, event);
3498}
3499
3500function specialMouseHandlerWrapper(target, event, handler) {
3501 // Refer to jQuery's implementation of mouseenter & mouseleave
3502 // Read about mouseenter and mouseleave:
3503 // http://www.quirksmode.org/js/events_mouse.html#link8
3504 var related = event.relatedTarget;
3505 // For mousenter/leave call the handler if related is outside the target.
3506 // NB: No relatedTarget if the mouse left/entered the browser window
3507 if (!related || (related !== target && !jqLiteContains.call(target, related))) {
3508 handler.call(target, event);
3509 }
3510}
3511
3512//////////////////////////////////////////
3513// Functions iterating traversal.
3514// These functions chain results into a single
3515// selector.
3516//////////////////////////////////////////
3517forEach({
3518 removeData: jqLiteRemoveData,
3519
3520 on: function jqLiteOn(element, type, fn, unsupported) {
3521 if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
3522
3523 // Do not add event handlers to non-elements because they will not be cleaned up.
3524 if (!jqLiteAcceptsData(element)) {
3525 return;
3526 }
3527
3528 var expandoStore = jqLiteExpandoStore(element, true);
3529 var events = expandoStore.events;
3530 var handle = expandoStore.handle;
3531
3532 if (!handle) {
3533 handle = expandoStore.handle = createEventHandler(element, events);
3534 }
3535
3536 // http://jsperf.com/string-indexof-vs-split
3537 var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
3538 var i = types.length;
3539
3540 var addHandler = function(type, specialHandlerWrapper, noEventListener) {
3541 var eventFns = events[type];
3542
3543 if (!eventFns) {
3544 eventFns = events[type] = [];
3545 eventFns.specialHandlerWrapper = specialHandlerWrapper;
3546 if (type !== '$destroy' && !noEventListener) {
3547 addEventListenerFn(element, type, handle);
3548 }
3549 }
3550
3551 eventFns.push(fn);
3552 };
3553
3554 while (i--) {
3555 type = types[i];
3556 if (MOUSE_EVENT_MAP[type]) {
3557 addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
3558 addHandler(type, undefined, true);
3559 } else {
3560 addHandler(type);
3561 }
3562 }
3563 },
3564
3565 off: jqLiteOff,
3566
3567 one: function(element, type, fn) {
3568 element = jqLite(element);
3569
3570 //add the listener twice so that when it is called
3571 //you can remove the original function and still be
3572 //able to call element.off(ev, fn) normally
3573 element.on(type, function onFn() {
3574 element.off(type, fn);
3575 element.off(type, onFn);
3576 });
3577 element.on(type, fn);
3578 },
3579
3580 replaceWith: function(element, replaceNode) {
3581 var index, parent = element.parentNode;
3582 jqLiteDealoc(element);
3583 forEach(new JQLite(replaceNode), function(node) {
3584 if (index) {
3585 parent.insertBefore(node, index.nextSibling);
3586 } else {
3587 parent.replaceChild(node, element);
3588 }
3589 index = node;
3590 });
3591 },
3592
3593 children: function(element) {
3594 var children = [];
3595 forEach(element.childNodes, function(element) {
3596 if (element.nodeType === NODE_TYPE_ELEMENT) {
3597 children.push(element);
3598 }
3599 });
3600 return children;
3601 },
3602
3603 contents: function(element) {
3604 return element.contentDocument || element.childNodes || [];
3605 },
3606
3607 append: function(element, node) {
3608 var nodeType = element.nodeType;
3609 if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
3610
3611 node = new JQLite(node);
3612
3613 for (var i = 0, ii = node.length; i < ii; i++) {
3614 var child = node[i];
3615 element.appendChild(child);
3616 }
3617 },
3618
3619 prepend: function(element, node) {
3620 if (element.nodeType === NODE_TYPE_ELEMENT) {
3621 var index = element.firstChild;
3622 forEach(new JQLite(node), function(child) {
3623 element.insertBefore(child, index);
3624 });
3625 }
3626 },
3627
3628 wrap: function(element, wrapNode) {
3629 jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
3630 },
3631
3632 remove: jqLiteRemove,
3633
3634 detach: function(element) {
3635 jqLiteRemove(element, true);
3636 },
3637
3638 after: function(element, newElement) {
3639 var index = element, parent = element.parentNode;
3640 newElement = new JQLite(newElement);
3641
3642 for (var i = 0, ii = newElement.length; i < ii; i++) {
3643 var node = newElement[i];
3644 parent.insertBefore(node, index.nextSibling);
3645 index = node;
3646 }
3647 },
3648
3649 addClass: jqLiteAddClass,
3650 removeClass: jqLiteRemoveClass,
3651
3652 toggleClass: function(element, selector, condition) {
3653 if (selector) {
3654 forEach(selector.split(' '), function(className) {
3655 var classCondition = condition;
3656 if (isUndefined(classCondition)) {
3657 classCondition = !jqLiteHasClass(element, className);
3658 }
3659 (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
3660 });
3661 }
3662 },
3663
3664 parent: function(element) {
3665 var parent = element.parentNode;
3666 return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
3667 },
3668
3669 next: function(element) {
3670 return element.nextElementSibling;
3671 },
3672
3673 find: function(element, selector) {
3674 if (element.getElementsByTagName) {
3675 return element.getElementsByTagName(selector);
3676 } else {
3677 return [];
3678 }
3679 },
3680
3681 clone: jqLiteClone,
3682
3683 triggerHandler: function(element, event, extraParameters) {
3684
3685 var dummyEvent, eventFnsCopy, handlerArgs;
3686 var eventName = event.type || event;
3687 var expandoStore = jqLiteExpandoStore(element);
3688 var events = expandoStore && expandoStore.events;
3689 var eventFns = events && events[eventName];
3690
3691 if (eventFns) {
3692 // Create a dummy event to pass to the handlers
3693 dummyEvent = {
3694 preventDefault: function() { this.defaultPrevented = true; },
3695 isDefaultPrevented: function() { return this.defaultPrevented === true; },
3696 stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
3697 isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
3698 stopPropagation: noop,
3699 type: eventName,
3700 target: element
3701 };
3702
3703 // If a custom event was provided then extend our dummy event with it
3704 if (event.type) {
3705 dummyEvent = extend(dummyEvent, event);
3706 }
3707
3708 // Copy event handlers in case event handlers array is modified during execution.
3709 eventFnsCopy = shallowCopy(eventFns);
3710 handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
3711
3712 forEach(eventFnsCopy, function(fn) {
3713 if (!dummyEvent.isImmediatePropagationStopped()) {
3714 fn.apply(element, handlerArgs);
3715 }
3716 });
3717 }
3718 }
3719}, function(fn, name) {
3720 /**
3721 * chaining functions
3722 */
3723 JQLite.prototype[name] = function(arg1, arg2, arg3) {
3724 var value;
3725
3726 for (var i = 0, ii = this.length; i < ii; i++) {
3727 if (isUndefined(value)) {
3728 value = fn(this[i], arg1, arg2, arg3);
3729 if (isDefined(value)) {
3730 // any function which returns a value needs to be wrapped
3731 value = jqLite(value);
3732 }
3733 } else {
3734 jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
3735 }
3736 }
3737 return isDefined(value) ? value : this;
3738 };
3739
3740 // bind legacy bind/unbind to on/off
3741 JQLite.prototype.bind = JQLite.prototype.on;
3742 JQLite.prototype.unbind = JQLite.prototype.off;
3743});
3744
3745
3746// Provider for private $$jqLite service
3747function $$jqLiteProvider() {
3748 this.$get = function $$jqLite() {
3749 return extend(JQLite, {
3750 hasClass: function(node, classes) {
3751 if (node.attr) node = node[0];
3752 return jqLiteHasClass(node, classes);
3753 },
3754 addClass: function(node, classes) {
3755 if (node.attr) node = node[0];
3756 return jqLiteAddClass(node, classes);
3757 },
3758 removeClass: function(node, classes) {
3759 if (node.attr) node = node[0];
3760 return jqLiteRemoveClass(node, classes);
3761 }
3762 });
3763 };
3764}
3765
3766/**
3767 * Computes a hash of an 'obj'.
3768 * Hash of a:
3769 * string is string
3770 * number is number as string
3771 * object is either result of calling $$hashKey function on the object or uniquely generated id,
3772 * that is also assigned to the $$hashKey property of the object.
3773 *
3774 * @param obj
3775 * @returns {string} hash string such that the same input will have the same hash string.
3776 * The resulting string key is in 'type:hashKey' format.
3777 */
3778function hashKey(obj, nextUidFn) {
3779 var key = obj && obj.$$hashKey;
3780
3781 if (key) {
3782 if (typeof key === 'function') {
3783 key = obj.$$hashKey();
3784 }
3785 return key;
3786 }
3787
3788 var objType = typeof obj;
3789 if (objType == 'function' || (objType == 'object' && obj !== null)) {
3790 key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
3791 } else {
3792 key = objType + ':' + obj;
3793 }
3794
3795 return key;
3796}
3797
3798/**
3799 * HashMap which can use objects as keys
3800 */
3801function HashMap(array, isolatedUid) {
3802 if (isolatedUid) {
3803 var uid = 0;
3804 this.nextUid = function() {
3805 return ++uid;
3806 };
3807 }
3808 forEach(array, this.put, this);
3809}
3810HashMap.prototype = {
3811 /**
3812 * Store key value pair
3813 * @param key key to store can be any type
3814 * @param value value to store can be any type
3815 */
3816 put: function(key, value) {
3817 this[hashKey(key, this.nextUid)] = value;
3818 },
3819
3820 /**
3821 * @param key
3822 * @returns {Object} the value for the key
3823 */
3824 get: function(key) {
3825 return this[hashKey(key, this.nextUid)];
3826 },
3827
3828 /**
3829 * Remove the key/value pair
3830 * @param key
3831 */
3832 remove: function(key) {
3833 var value = this[key = hashKey(key, this.nextUid)];
3834 delete this[key];
3835 return value;
3836 }
3837};
3838
3839var $$HashMapProvider = [function() {
3840 this.$get = [function() {
3841 return HashMap;
3842 }];
3843}];
3844
3845/**
3846 * @ngdoc function
3847 * @module ng
3848 * @name angular.injector
3849 * @kind function
3850 *
3851 * @description
3852 * Creates an injector object that can be used for retrieving services as well as for
3853 * dependency injection (see {@link guide/di dependency injection}).
3854 *
3855 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
3856 * {@link angular.module}. The `ng` module must be explicitly added.
3857 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
3858 * disallows argument name annotation inference.
3859 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
3860 *
3861 * @example
3862 * Typical usage
3863 * ```js
3864 * // create an injector
3865 * var $injector = angular.injector(['ng']);
3866 *
3867 * // use the injector to kick off your application
3868 * // use the type inference to auto inject arguments, or use implicit injection
3869 * $injector.invoke(function($rootScope, $compile, $document) {
3870 * $compile($document)($rootScope);
3871 * $rootScope.$digest();
3872 * });
3873 * ```
3874 *
3875 * Sometimes you want to get access to the injector of a currently running Angular app
3876 * from outside Angular. Perhaps, you want to inject and compile some markup after the
3877 * application has been bootstrapped. You can do this using the extra `injector()` added
3878 * to JQuery/jqLite elements. See {@link angular.element}.
3879 *
3880 * *This is fairly rare but could be the case if a third party library is injecting the
3881 * markup.*
3882 *
3883 * In the following example a new block of HTML containing a `ng-controller`
3884 * directive is added to the end of the document body by JQuery. We then compile and link
3885 * it into the current AngularJS scope.
3886 *
3887 * ```js
3888 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
3889 * $(document.body).append($div);
3890 *
3891 * angular.element(document).injector().invoke(function($compile) {
3892 * var scope = angular.element($div).scope();
3893 * $compile($div)(scope);
3894 * });
3895 * ```
3896 */
3897
3898
3899/**
3900 * @ngdoc module
3901 * @name auto
3902 * @installation
3903 * @description
3904 *
3905 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
3906 */
3907
3908var ARROW_ARG = /^([^\(]+?)=>/;
3909var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
3910var FN_ARG_SPLIT = /,/;
3911var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
3912var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
3913var $injectorMinErr = minErr('$injector');
3914
3915function stringifyFn(fn) {
3916 // Support: Chrome 50-51 only
3917 // Creating a new string by adding `' '` at the end, to hack around some bug in Chrome v50/51
3918 // (See https://github.com/angular/angular.js/issues/14487.)
3919 // TODO (gkalpak): Remove workaround when Chrome v52 is released
3920 return Function.prototype.toString.call(fn) + ' ';
3921}
3922
3923function extractArgs(fn) {
3924 var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
3925 args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
3926 return args;
3927}
3928
3929function anonFn(fn) {
3930 // For anonymous functions, showing at the very least the function signature can help in
3931 // debugging.
3932 var args = extractArgs(fn);
3933 if (args) {
3934 return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
3935 }
3936 return 'fn';
3937}
3938
3939function annotate(fn, strictDi, name) {
3940 var $inject,
3941 argDecl,
3942 last;
3943
3944 if (typeof fn === 'function') {
3945 if (!($inject = fn.$inject)) {
3946 $inject = [];
3947 if (fn.length) {
3948 if (strictDi) {
3949 if (!isString(name) || !name) {
3950 name = fn.name || anonFn(fn);
3951 }
3952 throw $injectorMinErr('strictdi',
3953 '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
3954 }
3955 argDecl = extractArgs(fn);
3956 forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
3957 arg.replace(FN_ARG, function(all, underscore, name) {
3958 $inject.push(name);
3959 });
3960 });
3961 }
3962 fn.$inject = $inject;
3963 }
3964 } else if (isArray(fn)) {
3965 last = fn.length - 1;
3966 assertArgFn(fn[last], 'fn');
3967 $inject = fn.slice(0, last);
3968 } else {
3969 assertArgFn(fn, 'fn', true);
3970 }
3971 return $inject;
3972}
3973
3974///////////////////////////////////////
3975
3976/**
3977 * @ngdoc service
3978 * @name $injector
3979 *
3980 * @description
3981 *
3982 * `$injector` is used to retrieve object instances as defined by
3983 * {@link auto.$provide provider}, instantiate types, invoke methods,
3984 * and load modules.
3985 *
3986 * The following always holds true:
3987 *
3988 * ```js
3989 * var $injector = angular.injector();
3990 * expect($injector.get('$injector')).toBe($injector);
3991 * expect($injector.invoke(function($injector) {
3992 * return $injector;
3993 * })).toBe($injector);
3994 * ```
3995 *
3996 * # Injection Function Annotation
3997 *
3998 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
3999 * following are all valid ways of annotating function with injection arguments and are equivalent.
4000 *
4001 * ```js
4002 * // inferred (only works if code not minified/obfuscated)
4003 * $injector.invoke(function(serviceA){});
4004 *
4005 * // annotated
4006 * function explicit(serviceA) {};
4007 * explicit.$inject = ['serviceA'];
4008 * $injector.invoke(explicit);
4009 *
4010 * // inline
4011 * $injector.invoke(['serviceA', function(serviceA){}]);
4012 * ```
4013 *
4014 * ## Inference
4015 *
4016 * In JavaScript calling `toString()` on a function returns the function definition. The definition
4017 * can then be parsed and the function arguments can be extracted. This method of discovering
4018 * annotations is disallowed when the injector is in strict mode.
4019 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
4020 * argument names.
4021 *
4022 * ## `$inject` Annotation
4023 * By adding an `$inject` property onto a function the injection parameters can be specified.
4024 *
4025 * ## Inline
4026 * As an array of injection names, where the last item in the array is the function to call.
4027 */
4028
4029/**
4030 * @ngdoc method
4031 * @name $injector#get
4032 *
4033 * @description
4034 * Return an instance of the service.
4035 *
4036 * @param {string} name The name of the instance to retrieve.
4037 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
4038 * @return {*} The instance.
4039 */
4040
4041/**
4042 * @ngdoc method
4043 * @name $injector#invoke
4044 *
4045 * @description
4046 * Invoke the method and supply the method arguments from the `$injector`.
4047 *
4048 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
4049 * injected according to the {@link guide/di $inject Annotation} rules.
4050 * @param {Object=} self The `this` for the invoked method.
4051 * @param {Object=} locals Optional object. If preset then any argument names are read from this
4052 * object first, before the `$injector` is consulted.
4053 * @returns {*} the value returned by the invoked `fn` function.
4054 */
4055
4056/**
4057 * @ngdoc method
4058 * @name $injector#has
4059 *
4060 * @description
4061 * Allows the user to query if the particular service exists.
4062 *
4063 * @param {string} name Name of the service to query.
4064 * @returns {boolean} `true` if injector has given service.
4065 */
4066
4067/**
4068 * @ngdoc method
4069 * @name $injector#instantiate
4070 * @description
4071 * Create a new instance of JS type. The method takes a constructor function, invokes the new
4072 * operator, and supplies all of the arguments to the constructor function as specified by the
4073 * constructor annotation.
4074 *
4075 * @param {Function} Type Annotated constructor function.
4076 * @param {Object=} locals Optional object. If preset then any argument names are read from this
4077 * object first, before the `$injector` is consulted.
4078 * @returns {Object} new instance of `Type`.
4079 */
4080
4081/**
4082 * @ngdoc method
4083 * @name $injector#annotate
4084 *
4085 * @description
4086 * Returns an array of service names which the function is requesting for injection. This API is
4087 * used by the injector to determine which services need to be injected into the function when the
4088 * function is invoked. There are three ways in which the function can be annotated with the needed
4089 * dependencies.
4090 *
4091 * # Argument names
4092 *
4093 * The simplest form is to extract the dependencies from the arguments of the function. This is done
4094 * by converting the function into a string using `toString()` method and extracting the argument
4095 * names.
4096 * ```js
4097 * // Given
4098 * function MyController($scope, $route) {
4099 * // ...
4100 * }
4101 *
4102 * // Then
4103 * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4104 * ```
4105 *
4106 * You can disallow this method by using strict injection mode.
4107 *
4108 * This method does not work with code minification / obfuscation. For this reason the following
4109 * annotation strategies are supported.
4110 *
4111 * # The `$inject` property
4112 *
4113 * If a function has an `$inject` property and its value is an array of strings, then the strings
4114 * represent names of services to be injected into the function.
4115 * ```js
4116 * // Given
4117 * var MyController = function(obfuscatedScope, obfuscatedRoute) {
4118 * // ...
4119 * }
4120 * // Define function dependencies
4121 * MyController['$inject'] = ['$scope', '$route'];
4122 *
4123 * // Then
4124 * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
4125 * ```
4126 *
4127 * # The array notation
4128 *
4129 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
4130 * is very inconvenient. In these situations using the array notation to specify the dependencies in
4131 * a way that survives minification is a better choice:
4132 *
4133 * ```js
4134 * // We wish to write this (not minification / obfuscation safe)
4135 * injector.invoke(function($compile, $rootScope) {
4136 * // ...
4137 * });
4138 *
4139 * // We are forced to write break inlining
4140 * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
4141 * // ...
4142 * };
4143 * tmpFn.$inject = ['$compile', '$rootScope'];
4144 * injector.invoke(tmpFn);
4145 *
4146 * // To better support inline function the inline annotation is supported
4147 * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
4148 * // ...
4149 * }]);
4150 *
4151 * // Therefore
4152 * expect(injector.annotate(
4153 * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
4154 * ).toEqual(['$compile', '$rootScope']);
4155 * ```
4156 *
4157 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
4158 * be retrieved as described above.
4159 *
4160 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
4161 *
4162 * @returns {Array.<string>} The names of the services which the function requires.
4163 */
4164
4165
4166
4167
4168/**
4169 * @ngdoc service
4170 * @name $provide
4171 *
4172 * @description
4173 *
4174 * The {@link auto.$provide $provide} service has a number of methods for registering components
4175 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
4176 * {@link angular.Module}.
4177 *
4178 * An Angular **service** is a singleton object created by a **service factory**. These **service
4179 * factories** are functions which, in turn, are created by a **service provider**.
4180 * The **service providers** are constructor functions. When instantiated they must contain a
4181 * property called `$get`, which holds the **service factory** function.
4182 *
4183 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
4184 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
4185 * function to get the instance of the **service**.
4186 *
4187 * Often services have no configuration options and there is no need to add methods to the service
4188 * provider. The provider will be no more than a constructor function with a `$get` property. For
4189 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
4190 * services without specifying a provider.
4191 *
4192 * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
4193 * {@link auto.$injector $injector}
4194 * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
4195 * providers and services.
4196 * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
4197 * services, not providers.
4198 * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
4199 * that will be wrapped in a **service provider** object, whose `$get` property will contain the
4200 * given factory function.
4201 * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
4202 * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
4203 * a new object using the given constructor function.
4204 * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
4205 * will be able to modify or replace the implementation of another service.
4206 *
4207 * See the individual methods for more information and examples.
4208 */
4209
4210/**
4211 * @ngdoc method
4212 * @name $provide#provider
4213 * @description
4214 *
4215 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
4216 * are constructor functions, whose instances are responsible for "providing" a factory for a
4217 * service.
4218 *
4219 * Service provider names start with the name of the service they provide followed by `Provider`.
4220 * For example, the {@link ng.$log $log} service has a provider called
4221 * {@link ng.$logProvider $logProvider}.
4222 *
4223 * Service provider objects can have additional methods which allow configuration of the provider
4224 * and its service. Importantly, you can configure what kind of service is created by the `$get`
4225 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
4226 * method {@link ng.$logProvider#debugEnabled debugEnabled}
4227 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
4228 * console or not.
4229 *
4230 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
4231 'Provider'` key.
4232 * @param {(Object|function())} provider If the provider is:
4233 *
4234 * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
4235 * {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
4236 * - `Constructor`: a new instance of the provider will be created using
4237 * {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
4238 *
4239 * @returns {Object} registered provider instance
4240
4241 * @example
4242 *
4243 * The following example shows how to create a simple event tracking service and register it using
4244 * {@link auto.$provide#provider $provide.provider()}.
4245 *
4246 * ```js
4247 * // Define the eventTracker provider
4248 * function EventTrackerProvider() {
4249 * var trackingUrl = '/track';
4250 *
4251 * // A provider method for configuring where the tracked events should been saved
4252 * this.setTrackingUrl = function(url) {
4253 * trackingUrl = url;
4254 * };
4255 *
4256 * // The service factory function
4257 * this.$get = ['$http', function($http) {
4258 * var trackedEvents = {};
4259 * return {
4260 * // Call this to track an event
4261 * event: function(event) {
4262 * var count = trackedEvents[event] || 0;
4263 * count += 1;
4264 * trackedEvents[event] = count;
4265 * return count;
4266 * },
4267 * // Call this to save the tracked events to the trackingUrl
4268 * save: function() {
4269 * $http.post(trackingUrl, trackedEvents);
4270 * }
4271 * };
4272 * }];
4273 * }
4274 *
4275 * describe('eventTracker', function() {
4276 * var postSpy;
4277 *
4278 * beforeEach(module(function($provide) {
4279 * // Register the eventTracker provider
4280 * $provide.provider('eventTracker', EventTrackerProvider);
4281 * }));
4282 *
4283 * beforeEach(module(function(eventTrackerProvider) {
4284 * // Configure eventTracker provider
4285 * eventTrackerProvider.setTrackingUrl('/custom-track');
4286 * }));
4287 *
4288 * it('tracks events', inject(function(eventTracker) {
4289 * expect(eventTracker.event('login')).toEqual(1);
4290 * expect(eventTracker.event('login')).toEqual(2);
4291 * }));
4292 *
4293 * it('saves to the tracking url', inject(function(eventTracker, $http) {
4294 * postSpy = spyOn($http, 'post');
4295 * eventTracker.event('login');
4296 * eventTracker.save();
4297 * expect(postSpy).toHaveBeenCalled();
4298 * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
4299 * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
4300 * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
4301 * }));
4302 * });
4303 * ```
4304 */
4305
4306/**
4307 * @ngdoc method
4308 * @name $provide#factory
4309 * @description
4310 *
4311 * Register a **service factory**, which will be called to return the service instance.
4312 * This is short for registering a service where its provider consists of only a `$get` property,
4313 * which is the given service factory function.
4314 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
4315 * configure your service in a provider.
4316 *
4317 * @param {string} name The name of the instance.
4318 * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
4319 * Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
4320 * @returns {Object} registered provider instance
4321 *
4322 * @example
4323 * Here is an example of registering a service
4324 * ```js
4325 * $provide.factory('ping', ['$http', function($http) {
4326 * return function ping() {
4327 * return $http.send('/ping');
4328 * };
4329 * }]);
4330 * ```
4331 * You would then inject and use this service like this:
4332 * ```js
4333 * someModule.controller('Ctrl', ['ping', function(ping) {
4334 * ping();
4335 * }]);
4336 * ```
4337 */
4338
4339
4340/**
4341 * @ngdoc method
4342 * @name $provide#service
4343 * @description
4344 *
4345 * Register a **service constructor**, which will be invoked with `new` to create the service
4346 * instance.
4347 * This is short for registering a service where its provider's `$get` property is a factory
4348 * function that returns an instance instantiated by the injector from the service constructor
4349 * function.
4350 *
4351 * Internally it looks a bit like this:
4352 *
4353 * ```
4354 * {
4355 * $get: function() {
4356 * return $injector.instantiate(constructor);
4357 * }
4358 * }
4359 * ```
4360 *
4361 *
4362 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
4363 * as a type/class.
4364 *
4365 * @param {string} name The name of the instance.
4366 * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
4367 * that will be instantiated.
4368 * @returns {Object} registered provider instance
4369 *
4370 * @example
4371 * Here is an example of registering a service using
4372 * {@link auto.$provide#service $provide.service(class)}.
4373 * ```js
4374 * var Ping = function($http) {
4375 * this.$http = $http;
4376 * };
4377 *
4378 * Ping.$inject = ['$http'];
4379 *
4380 * Ping.prototype.send = function() {
4381 * return this.$http.get('/ping');
4382 * };
4383 * $provide.service('ping', Ping);
4384 * ```
4385 * You would then inject and use this service like this:
4386 * ```js
4387 * someModule.controller('Ctrl', ['ping', function(ping) {
4388 * ping.send();
4389 * }]);
4390 * ```
4391 */
4392
4393
4394/**
4395 * @ngdoc method
4396 * @name $provide#value
4397 * @description
4398 *
4399 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
4400 * number, an array, an object or a function. This is short for registering a service where its
4401 * provider's `$get` property is a factory function that takes no arguments and returns the **value
4402 * service**. That also means it is not possible to inject other services into a value service.
4403 *
4404 * Value services are similar to constant services, except that they cannot be injected into a
4405 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
4406 * an Angular {@link auto.$provide#decorator decorator}.
4407 *
4408 * @param {string} name The name of the instance.
4409 * @param {*} value The value.
4410 * @returns {Object} registered provider instance
4411 *
4412 * @example
4413 * Here are some examples of creating value services.
4414 * ```js
4415 * $provide.value('ADMIN_USER', 'admin');
4416 *
4417 * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
4418 *
4419 * $provide.value('halfOf', function(value) {
4420 * return value / 2;
4421 * });
4422 * ```
4423 */
4424
4425
4426/**
4427 * @ngdoc method
4428 * @name $provide#constant
4429 * @description
4430 *
4431 * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
4432 * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
4433 * possible to inject other services into a constant.
4434 *
4435 * But unlike {@link auto.$provide#value value}, a constant can be
4436 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
4437 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
4438 *
4439 * @param {string} name The name of the constant.
4440 * @param {*} value The constant value.
4441 * @returns {Object} registered instance
4442 *
4443 * @example
4444 * Here a some examples of creating constants:
4445 * ```js
4446 * $provide.constant('SHARD_HEIGHT', 306);
4447 *
4448 * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
4449 *
4450 * $provide.constant('double', function(value) {
4451 * return value * 2;
4452 * });
4453 * ```
4454 */
4455
4456
4457/**
4458 * @ngdoc method
4459 * @name $provide#decorator
4460 * @description
4461 *
4462 * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
4463 * intercepts the creation of a service, allowing it to override or modify the behavior of the
4464 * service. The return value of the decorator function may be the original service, or a new service
4465 * that replaces (or wraps and delegates to) the original service.
4466 *
4467 * You can find out more about using decorators in the {@link guide/decorators} guide.
4468 *
4469 * @param {string} name The name of the service to decorate.
4470 * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
4471 * provided and should return the decorated service instance. The function is called using
4472 * the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
4473 * Local injection arguments:
4474 *
4475 * * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
4476 * decorated or delegated to.
4477 *
4478 * @example
4479 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
4480 * calls to {@link ng.$log#error $log.warn()}.
4481 * ```js
4482 * $provide.decorator('$log', ['$delegate', function($delegate) {
4483 * $delegate.warn = $delegate.error;
4484 * return $delegate;
4485 * }]);
4486 * ```
4487 */
4488
4489
4490function createInjector(modulesToLoad, strictDi) {
4491 strictDi = (strictDi === true);
4492 var INSTANTIATING = {},
4493 providerSuffix = 'Provider',
4494 path = [],
4495 loadedModules = new HashMap([], true),
4496 providerCache = {
4497 $provide: {
4498 provider: supportObject(provider),
4499 factory: supportObject(factory),
4500 service: supportObject(service),
4501 value: supportObject(value),
4502 constant: supportObject(constant),
4503 decorator: decorator
4504 }
4505 },
4506 providerInjector = (providerCache.$injector =
4507 createInternalInjector(providerCache, function(serviceName, caller) {
4508 if (angular.isString(caller)) {
4509 path.push(caller);
4510 }
4511 throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
4512 })),
4513 instanceCache = {},
4514 protoInstanceInjector =
4515 createInternalInjector(instanceCache, function(serviceName, caller) {
4516 var provider = providerInjector.get(serviceName + providerSuffix, caller);
4517 return instanceInjector.invoke(
4518 provider.$get, provider, undefined, serviceName);
4519 }),
4520 instanceInjector = protoInstanceInjector;
4521
4522 providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
4523 var runBlocks = loadModules(modulesToLoad);
4524 instanceInjector = protoInstanceInjector.get('$injector');
4525 instanceInjector.strictDi = strictDi;
4526 forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
4527
4528 return instanceInjector;
4529
4530 ////////////////////////////////////
4531 // $provider
4532 ////////////////////////////////////
4533
4534 function supportObject(delegate) {
4535 return function(key, value) {
4536 if (isObject(key)) {
4537 forEach(key, reverseParams(delegate));
4538 } else {
4539 return delegate(key, value);
4540 }
4541 };
4542 }
4543
4544 function provider(name, provider_) {
4545 assertNotHasOwnProperty(name, 'service');
4546 if (isFunction(provider_) || isArray(provider_)) {
4547 provider_ = providerInjector.instantiate(provider_);
4548 }
4549 if (!provider_.$get) {
4550 throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
4551 }
4552 return providerCache[name + providerSuffix] = provider_;
4553 }
4554
4555 function enforceReturnValue(name, factory) {
4556 return function enforcedReturnValue() {
4557 var result = instanceInjector.invoke(factory, this);
4558 if (isUndefined(result)) {
4559 throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
4560 }
4561 return result;
4562 };
4563 }
4564
4565 function factory(name, factoryFn, enforce) {
4566 return provider(name, {
4567 $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
4568 });
4569 }
4570
4571 function service(name, constructor) {
4572 return factory(name, ['$injector', function($injector) {
4573 return $injector.instantiate(constructor);
4574 }]);
4575 }
4576
4577 function value(name, val) { return factory(name, valueFn(val), false); }
4578
4579 function constant(name, value) {
4580 assertNotHasOwnProperty(name, 'constant');
4581 providerCache[name] = value;
4582 instanceCache[name] = value;
4583 }
4584
4585 function decorator(serviceName, decorFn) {
4586 var origProvider = providerInjector.get(serviceName + providerSuffix),
4587 orig$get = origProvider.$get;
4588
4589 origProvider.$get = function() {
4590 var origInstance = instanceInjector.invoke(orig$get, origProvider);
4591 return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
4592 };
4593 }
4594
4595 ////////////////////////////////////
4596 // Module Loading
4597 ////////////////////////////////////
4598 function loadModules(modulesToLoad) {
4599 assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
4600 var runBlocks = [], moduleFn;
4601 forEach(modulesToLoad, function(module) {
4602 if (loadedModules.get(module)) return;
4603 loadedModules.put(module, true);
4604
4605 function runInvokeQueue(queue) {
4606 var i, ii;
4607 for (i = 0, ii = queue.length; i < ii; i++) {
4608 var invokeArgs = queue[i],
4609 provider = providerInjector.get(invokeArgs[0]);
4610
4611 provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
4612 }
4613 }
4614
4615 try {
4616 if (isString(module)) {
4617 moduleFn = angularModule(module);
4618 runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
4619 runInvokeQueue(moduleFn._invokeQueue);
4620 runInvokeQueue(moduleFn._configBlocks);
4621 } else if (isFunction(module)) {
4622 runBlocks.push(providerInjector.invoke(module));
4623 } else if (isArray(module)) {
4624 runBlocks.push(providerInjector.invoke(module));
4625 } else {
4626 assertArgFn(module, 'module');
4627 }
4628 } catch (e) {
4629 if (isArray(module)) {
4630 module = module[module.length - 1];
4631 }
4632 if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
4633 // Safari & FF's stack traces don't contain error.message content
4634 // unlike those of Chrome and IE
4635 // So if stack doesn't contain message, we create a new string that contains both.
4636 // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
4637 /* jshint -W022 */
4638 e = e.message + '\n' + e.stack;
4639 }
4640 throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
4641 module, e.stack || e.message || e);
4642 }
4643 });
4644 return runBlocks;
4645 }
4646
4647 ////////////////////////////////////
4648 // internal Injector
4649 ////////////////////////////////////
4650
4651 function createInternalInjector(cache, factory) {
4652
4653 function getService(serviceName, caller) {
4654 if (cache.hasOwnProperty(serviceName)) {
4655 if (cache[serviceName] === INSTANTIATING) {
4656 throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
4657 serviceName + ' <- ' + path.join(' <- '));
4658 }
4659 return cache[serviceName];
4660 } else {
4661 try {
4662 path.unshift(serviceName);
4663 cache[serviceName] = INSTANTIATING;
4664 return cache[serviceName] = factory(serviceName, caller);
4665 } catch (err) {
4666 if (cache[serviceName] === INSTANTIATING) {
4667 delete cache[serviceName];
4668 }
4669 throw err;
4670 } finally {
4671 path.shift();
4672 }
4673 }
4674 }
4675
4676
4677 function injectionArgs(fn, locals, serviceName) {
4678 var args = [],
4679 $inject = createInjector.$$annotate(fn, strictDi, serviceName);
4680
4681 for (var i = 0, length = $inject.length; i < length; i++) {
4682 var key = $inject[i];
4683 if (typeof key !== 'string') {
4684 throw $injectorMinErr('itkn',
4685 'Incorrect injection token! Expected service name as string, got {0}', key);
4686 }
4687 args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
4688 getService(key, serviceName));
4689 }
4690 return args;
4691 }
4692
4693 function isClass(func) {
4694 // IE 9-11 do not support classes and IE9 leaks with the code below.
4695 if (msie <= 11) {
4696 return false;
4697 }
4698 // Support: Edge 12-13 only
4699 // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
4700 return typeof func === 'function'
4701 && /^(?:class\b|constructor\()/.test(stringifyFn(func));
4702 }
4703
4704 function invoke(fn, self, locals, serviceName) {
4705 if (typeof locals === 'string') {
4706 serviceName = locals;
4707 locals = null;
4708 }
4709
4710 var args = injectionArgs(fn, locals, serviceName);
4711 if (isArray(fn)) {
4712 fn = fn[fn.length - 1];
4713 }
4714
4715 if (!isClass(fn)) {
4716 // http://jsperf.com/angularjs-invoke-apply-vs-switch
4717 // #5388
4718 return fn.apply(self, args);
4719 } else {
4720 args.unshift(null);
4721 return new (Function.prototype.bind.apply(fn, args))();
4722 }
4723 }
4724
4725
4726 function instantiate(Type, locals, serviceName) {
4727 // Check if Type is annotated and use just the given function at n-1 as parameter
4728 // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
4729 var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
4730 var args = injectionArgs(Type, locals, serviceName);
4731 // Empty object at position 0 is ignored for invocation with `new`, but required.
4732 args.unshift(null);
4733 return new (Function.prototype.bind.apply(ctor, args))();
4734 }
4735
4736
4737 return {
4738 invoke: invoke,
4739 instantiate: instantiate,
4740 get: getService,
4741 annotate: createInjector.$$annotate,
4742 has: function(name) {
4743 return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
4744 }
4745 };
4746 }
4747}
4748
4749createInjector.$$annotate = annotate;
4750
4751/**
4752 * @ngdoc provider
4753 * @name $anchorScrollProvider
4754 *
4755 * @description
4756 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
4757 * {@link ng.$location#hash $location.hash()} changes.
4758 */
4759function $AnchorScrollProvider() {
4760
4761 var autoScrollingEnabled = true;
4762
4763 /**
4764 * @ngdoc method
4765 * @name $anchorScrollProvider#disableAutoScrolling
4766 *
4767 * @description
4768 * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
4769 * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
4770 * Use this method to disable automatic scrolling.
4771 *
4772 * If automatic scrolling is disabled, one must explicitly call
4773 * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
4774 * current hash.
4775 */
4776 this.disableAutoScrolling = function() {
4777 autoScrollingEnabled = false;
4778 };
4779
4780 /**
4781 * @ngdoc service
4782 * @name $anchorScroll
4783 * @kind function
4784 * @requires $window
4785 * @requires $location
4786 * @requires $rootScope
4787 *
4788 * @description
4789 * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
4790 * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
4791 * in the
4792 * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
4793 *
4794 * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
4795 * match any anchor whenever it changes. This can be disabled by calling
4796 * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
4797 *
4798 * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
4799 * vertical scroll-offset (either fixed or dynamic).
4800 *
4801 * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
4802 * {@link ng.$location#hash $location.hash()} will be used.
4803 *
4804 * @property {(number|function|jqLite)} yOffset
4805 * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
4806 * positioned elements at the top of the page, such as navbars, headers etc.
4807 *
4808 * `yOffset` can be specified in various ways:
4809 * - **number**: A fixed number of pixels to be used as offset.<br /><br />
4810 * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
4811 * a number representing the offset (in pixels).<br /><br />
4812 * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
4813 * the top of the page to the element's bottom will be used as offset.<br />
4814 * **Note**: The element will be taken into account only as long as its `position` is set to
4815 * `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
4816 * their height and/or positioning according to the viewport's size.
4817 *
4818 * <br />
4819 * <div class="alert alert-warning">
4820 * In order for `yOffset` to work properly, scrolling should take place on the document's root and
4821 * not some child element.
4822 * </div>
4823 *
4824 * @example
4825 <example module="anchorScrollExample">
4826 <file name="index.html">
4827 <div id="scrollArea" ng-controller="ScrollController">
4828 <a ng-click="gotoBottom()">Go to bottom</a>
4829 <a id="bottom"></a> You're at the bottom!
4830 </div>
4831 </file>
4832 <file name="script.js">
4833 angular.module('anchorScrollExample', [])
4834 .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
4835 function ($scope, $location, $anchorScroll) {
4836 $scope.gotoBottom = function() {
4837 // set the location.hash to the id of
4838 // the element you wish to scroll to.
4839 $location.hash('bottom');
4840
4841 // call $anchorScroll()
4842 $anchorScroll();
4843 };
4844 }]);
4845 </file>
4846 <file name="style.css">
4847 #scrollArea {
4848 height: 280px;
4849 overflow: auto;
4850 }
4851
4852 #bottom {
4853 display: block;
4854 margin-top: 2000px;
4855 }
4856 </file>
4857 </example>
4858 *
4859 * <hr />
4860 * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
4861 * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
4862 *
4863 * @example
4864 <example module="anchorScrollOffsetExample">
4865 <file name="index.html">
4866 <div class="fixed-header" ng-controller="headerCtrl">
4867 <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
4868 Go to anchor {{x}}
4869 </a>
4870 </div>
4871 <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
4872 Anchor {{x}} of 5
4873 </div>
4874 </file>
4875 <file name="script.js">
4876 angular.module('anchorScrollOffsetExample', [])
4877 .run(['$anchorScroll', function($anchorScroll) {
4878 $anchorScroll.yOffset = 50; // always scroll by 50 extra pixels
4879 }])
4880 .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
4881 function ($anchorScroll, $location, $scope) {
4882 $scope.gotoAnchor = function(x) {
4883 var newHash = 'anchor' + x;
4884 if ($location.hash() !== newHash) {
4885 // set the $location.hash to `newHash` and
4886 // $anchorScroll will automatically scroll to it
4887 $location.hash('anchor' + x);
4888 } else {
4889 // call $anchorScroll() explicitly,
4890 // since $location.hash hasn't changed
4891 $anchorScroll();
4892 }
4893 };
4894 }
4895 ]);
4896 </file>
4897 <file name="style.css">
4898 body {
4899 padding-top: 50px;
4900 }
4901
4902 .anchor {
4903 border: 2px dashed DarkOrchid;
4904 padding: 10px 10px 200px 10px;
4905 }
4906
4907 .fixed-header {
4908 background-color: rgba(0, 0, 0, 0.2);
4909 height: 50px;
4910 position: fixed;
4911 top: 0; left: 0; right: 0;
4912 }
4913
4914 .fixed-header > a {
4915 display: inline-block;
4916 margin: 5px 15px;
4917 }
4918 </file>
4919 </example>
4920 */
4921 this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
4922 var document = $window.document;
4923
4924 // Helper function to get first anchor from a NodeList
4925 // (using `Array#some()` instead of `angular#forEach()` since it's more performant
4926 // and working in all supported browsers.)
4927 function getFirstAnchor(list) {
4928 var result = null;
4929 Array.prototype.some.call(list, function(element) {
4930 if (nodeName_(element) === 'a') {
4931 result = element;
4932 return true;
4933 }
4934 });
4935 return result;
4936 }
4937
4938 function getYOffset() {
4939
4940 var offset = scroll.yOffset;
4941
4942 if (isFunction(offset)) {
4943 offset = offset();
4944 } else if (isElement(offset)) {
4945 var elem = offset[0];
4946 var style = $window.getComputedStyle(elem);
4947 if (style.position !== 'fixed') {
4948 offset = 0;
4949 } else {
4950 offset = elem.getBoundingClientRect().bottom;
4951 }
4952 } else if (!isNumber(offset)) {
4953 offset = 0;
4954 }
4955
4956 return offset;
4957 }
4958
4959 function scrollTo(elem) {
4960 if (elem) {
4961 elem.scrollIntoView();
4962
4963 var offset = getYOffset();
4964
4965 if (offset) {
4966 // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
4967 // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
4968 // top of the viewport.
4969 //
4970 // IF the number of pixels from the top of `elem` to the end of the page's content is less
4971 // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
4972 // way down the page.
4973 //
4974 // This is often the case for elements near the bottom of the page.
4975 //
4976 // In such cases we do not need to scroll the whole `offset` up, just the difference between
4977 // the top of the element and the offset, which is enough to align the top of `elem` at the
4978 // desired position.
4979 var elemTop = elem.getBoundingClientRect().top;
4980 $window.scrollBy(0, elemTop - offset);
4981 }
4982 } else {
4983 $window.scrollTo(0, 0);
4984 }
4985 }
4986
4987 function scroll(hash) {
4988 hash = isString(hash) ? hash : $location.hash();
4989 var elm;
4990
4991 // empty hash, scroll to the top of the page
4992 if (!hash) scrollTo(null);
4993
4994 // element with given id
4995 else if ((elm = document.getElementById(hash))) scrollTo(elm);
4996
4997 // first anchor with given name :-D
4998 else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
4999

26769 more lines aren’t shown here.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t