http://git-wip-us.apache.org/repos/asf/struts-examples/blob/558c6b0f/rest-angular/src/main/webapp/js/lib/angular/angular-scenario.js ---------------------------------------------------------------------- diff --git a/rest-angular/src/main/webapp/js/lib/angular/angular-scenario.js b/rest-angular/src/main/webapp/js/lib/angular/angular-scenario.js index ce24ace..20af805 100644 --- a/rest-angular/src/main/webapp/js/lib/angular/angular-scenario.js +++ b/rest-angular/src/main/webapp/js/lib/angular/angular-scenario.js @@ -9190,8 +9190,8 @@ return jQuery; })); /** - * @license AngularJS v1.4.5 - * (c) 2010-2015 Google, Inc. http://angularjs.org + * @license AngularJS v1.5.0 + * (c) 2010-2016 Google, Inc. http://angularjs.org * License: MIT */ (function(window, document){ @@ -9249,7 +9249,7 @@ function minErr(module, ErrorConstructor) { return match; }); - message += '\nhttp://errors.angularjs.org/1.4.5/' + + message += '\nhttp://errors.angularjs.org/1.5.0/' + (module ? module + '/' : '') + code; for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { @@ -9380,29 +9380,9 @@ var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/; // This is used so that it's possible for internal tests to create mock ValidityStates. var VALIDITY_STATE_PROPERTY = 'validity'; -/** - * @ngdoc function - * @name angular.lowercase - * @module ng - * @kind function - * - * @description Converts the specified string to lowercase. - * @param {string} string String to be converted to lowercase. - * @returns {string} Lowercased string. - */ -var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; var hasOwnProperty = Object.prototype.hasOwnProperty; -/** - * @ngdoc function - * @name angular.uppercase - * @module ng - * @kind function - * - * @description Converts the specified string to uppercase. - * @param {string} string String to be converted to uppercase. - * @returns {string} Uppercased string. - */ +var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;}; var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;}; @@ -9422,7 +9402,7 @@ var manualUppercase = function(s) { // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods -// with correct but slower alternatives. +// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387 if ('i' !== 'I'.toLowerCase()) { lowercase = manualLowercase; uppercase = manualUppercase; @@ -9459,20 +9439,25 @@ msie = document.documentMode; * String ...) */ function isArrayLike(obj) { - if (obj == null || isWindow(obj)) { - return false; - } + + // `null`, `undefined` and `window` are not array-like + if (obj == null || isWindow(obj)) return false; + + // arrays, strings and jQuery/jqLite objects are array like + // * jqLite is either the jQuery or jqLite constructor function + // * we have to check the existence of jqLite first as this method is called + // via the forEach method when constructing the jqLite object in the first place + if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true; // Support: iOS 8.2 (not reproducible in simulator) // "length" in obj used to prevent JIT error (gh-11508) var length = "length" in Object(obj) && obj.length; - if (obj.nodeType === NODE_TYPE_ELEMENT && length) { - return true; - } + // NodeList objects (with `item` method) and + // other objects with suitable length characteristics are array-like + return isNumber(length) && + (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function'); - return isString(obj) || isArray(obj) || length === 0 || - typeof length === 'number' && length > 0 && (length - 1) in obj; } /** @@ -9569,7 +9554,7 @@ function forEachSorted(obj, iterator, context) { * @returns {function(*, string)} */ function reverseParams(iteratorFn) { - return function(value, key) { iteratorFn(key, value); }; + return function(value, key) {iteratorFn(key, value);}; } /** @@ -9617,6 +9602,10 @@ function baseExtend(dst, objs, deep) { dst[key] = new Date(src.valueOf()); } else if (isRegExp(src)) { dst[key] = new RegExp(src); + } else if (src.nodeName) { + dst[key] = src.cloneNode(true); + } else if (isElement(src)) { + dst[key] = src.clone(); } else { if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {}; baseExtend(dst[key], [src], true); @@ -9732,7 +9721,7 @@ identity.$inject = []; function valueFn(value) {return function() {return value;};} function hasCustomToString(obj) { - return isFunction(obj.toString) && obj.toString !== Object.prototype.toString; + return isFunction(obj.toString) && obj.toString !== toString; } @@ -9931,9 +9920,13 @@ function isPromiseLike(obj) { } -var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/; +var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/; function isTypedArray(value) { - return TYPED_ARRAY_REGEXP.test(toString.call(value)); + return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value)); +} + +function isArrayBuffer(obj) { + return toString.call(obj) === '[object ArrayBuffer]'; } @@ -9973,7 +9966,7 @@ function isElement(node) { * @returns {object} in the form of {key1:true, key2:true, ...} */ function makeMap(str) { - var obj = {}, items = str.split(","), i; + var obj = {}, items = str.split(','), i; for (i = 0; i < items.length; i++) { obj[items[i]] = true; } @@ -10055,98 +10048,138 @@ function arrayRemove(array, value) { </file> </example> */ -function copy(source, destination, stackSource, stackDest) { - if (isWindow(source) || isScope(source)) { - throw ngMinErr('cpws', - "Can't copy! Making copies of Window or Scope instances is not supported."); - } - if (isTypedArray(destination)) { - throw ngMinErr('cpta', - "Can't copy! TypedArray destination cannot be mutated."); - } +function copy(source, destination) { + var stackSource = []; + var stackDest = []; - if (!destination) { - destination = source; - if (isObject(source)) { - var index; - if (stackSource && (index = stackSource.indexOf(source)) !== -1) { - return stackDest[index]; - } - - // TypedArray, Date and RegExp have specific copy functionality and must be - // pushed onto the stack before returning. - // Array and other objects create the base object and recurse to copy child - // objects. The array/object will be pushed onto the stack when recursed. - if (isArray(source)) { - return copy(source, [], stackSource, stackDest); - } else if (isTypedArray(source)) { - destination = new source.constructor(source); - } else if (isDate(source)) { - destination = new Date(source.getTime()); - } else if (isRegExp(source)) { - destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); - destination.lastIndex = source.lastIndex; - } else { - var emptyObject = Object.create(getPrototypeOf(source)); - return copy(source, emptyObject, stackSource, stackDest); - } + if (destination) { + if (isTypedArray(destination) || isArrayBuffer(destination)) { + throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated."); + } + if (source === destination) { + throw ngMinErr('cpi', "Can't copy! Source and destination are identical."); + } - if (stackDest) { - stackSource.push(source); - stackDest.push(destination); - } + // Empty the destination object + if (isArray(destination)) { + destination.length = 0; + } else { + forEach(destination, function(value, key) { + if (key !== '$$hashKey') { + delete destination[key]; + } + }); } - } else { - if (source === destination) throw ngMinErr('cpi', - "Can't copy! Source and destination are identical."); - stackSource = stackSource || []; - stackDest = stackDest || []; + stackSource.push(source); + stackDest.push(destination); + return copyRecurse(source, destination); + } - if (isObject(source)) { - stackSource.push(source); - stackDest.push(destination); - } + return copyElement(source); + function copyRecurse(source, destination) { + var h = destination.$$hashKey; var result, key; if (isArray(source)) { - destination.length = 0; - for (var i = 0; i < source.length; i++) { - destination.push(copy(source[i], null, stackSource, stackDest)); + for (var i = 0, ii = source.length; i < ii; i++) { + destination.push(copyElement(source[i])); } - } else { - var h = destination.$$hashKey; - if (isArray(destination)) { - destination.length = 0; - } else { - forEach(destination, function(value, key) { - delete destination[key]; - }); + } else if (isBlankObject(source)) { + // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty + for (key in source) { + destination[key] = copyElement(source[key]); } - if (isBlankObject(source)) { - // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty - for (key in source) { - destination[key] = copy(source[key], null, stackSource, stackDest); - } - } else if (source && typeof source.hasOwnProperty === 'function') { - // Slow path, which must rely on hasOwnProperty - for (key in source) { - if (source.hasOwnProperty(key)) { - destination[key] = copy(source[key], null, stackSource, stackDest); - } + } else if (source && typeof source.hasOwnProperty === 'function') { + // Slow path, which must rely on hasOwnProperty + for (key in source) { + if (source.hasOwnProperty(key)) { + destination[key] = copyElement(source[key]); } - } else { - // Slowest path --- hasOwnProperty can't be called as a method - for (key in source) { - if (hasOwnProperty.call(source, key)) { - destination[key] = copy(source[key], null, stackSource, stackDest); - } + } + } else { + // Slowest path --- hasOwnProperty can't be called as a method + for (key in source) { + if (hasOwnProperty.call(source, key)) { + destination[key] = copyElement(source[key]); } } - setHashKey(destination,h); + } + setHashKey(destination, h); + return destination; + } + + function copyElement(source) { + // Simple values + if (!isObject(source)) { + return source; + } + + // Already copied values + var index = stackSource.indexOf(source); + if (index !== -1) { + return stackDest[index]; + } + + if (isWindow(source) || isScope(source)) { + throw ngMinErr('cpws', + "Can't copy! Making copies of Window or Scope instances is not supported."); + } + + var needsRecurse = false; + var destination = copyType(source); + + if (destination === undefined) { + destination = isArray(source) ? [] : Object.create(getPrototypeOf(source)); + needsRecurse = true; + } + + stackSource.push(source); + stackDest.push(destination); + + return needsRecurse + ? copyRecurse(source, destination) + : destination; + } + + function copyType(source) { + switch (toString.call(source)) { + case '[object Int8Array]': + case '[object Int16Array]': + case '[object Int32Array]': + case '[object Float32Array]': + case '[object Float64Array]': + case '[object Uint8Array]': + case '[object Uint8ClampedArray]': + case '[object Uint16Array]': + case '[object Uint32Array]': + return new source.constructor(copyElement(source.buffer)); + + case '[object ArrayBuffer]': + //Support: IE10 + if (!source.slice) { + var copied = new ArrayBuffer(source.byteLength); + new Uint8Array(copied).set(new Uint8Array(source)); + return copied; + } + return source.slice(0); + + case '[object Boolean]': + case '[object Number]': + case '[object String]': + case '[object Date]': + return new source.constructor(source.valueOf()); + + case '[object RegExp]': + var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]); + re.lastIndex = source.lastIndex; + return re; + } + + if (isFunction(source.cloneNode)) { + return source.cloneNode(true); } } - return destination; } /** @@ -10209,38 +10242,37 @@ function equals(o1, o2) { if (o1 === null || o2 === null) return false; if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN var t1 = typeof o1, t2 = typeof o2, length, key, keySet; - if (t1 == t2) { - if (t1 == 'object') { - if (isArray(o1)) { - if (!isArray(o2)) return false; - if ((length = o1.length) == o2.length) { - for (key = 0; key < length; key++) { - if (!equals(o1[key], o2[key])) return false; - } - return true; - } - } else if (isDate(o1)) { - if (!isDate(o2)) return false; - return equals(o1.getTime(), o2.getTime()); - } else if (isRegExp(o1)) { - return isRegExp(o2) ? o1.toString() == o2.toString() : false; - } else { - if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || - isArray(o2) || isDate(o2) || isRegExp(o2)) return false; - keySet = createMap(); - for (key in o1) { - if (key.charAt(0) === '$' || isFunction(o1[key])) continue; + if (t1 == t2 && t1 == 'object') { + if (isArray(o1)) { + if (!isArray(o2)) return false; + if ((length = o1.length) == o2.length) { + for (key = 0; key < length; key++) { if (!equals(o1[key], o2[key])) return false; - keySet[key] = true; - } - for (key in o2) { - if (!(key in keySet) && - key.charAt(0) !== '$' && - o2[key] !== undefined && - !isFunction(o2[key])) return false; } return true; } + } else if (isDate(o1)) { + if (!isDate(o2)) return false; + return equals(o1.getTime(), o2.getTime()); + } else if (isRegExp(o1)) { + if (!isRegExp(o2)) return false; + return o1.toString() == o2.toString(); + } else { + if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || + isArray(o2) || isDate(o2) || isRegExp(o2)) return false; + keySet = createMap(); + for (key in o1) { + if (key.charAt(0) === '$' || isFunction(o1[key])) continue; + if (!equals(o1[key], o2[key])) return false; + keySet[key] = true; + } + for (key in o2) { + if (!(key in keySet) && + key.charAt(0) !== '$' && + isDefined(o2[key]) && + !isFunction(o2[key])) return false; + } + return true; } } return false; @@ -10417,7 +10449,7 @@ function toJsonReplacer(key, value) { * @returns {string|undefined} JSON-ified string representing `obj`. */ function toJson(obj, pretty) { - if (typeof obj === 'undefined') return undefined; + if (isUndefined(obj)) return undefined; if (!isNumber(pretty)) { pretty = pretty ? 2 : null; } @@ -10444,7 +10476,10 @@ function fromJson(json) { } +var ALL_COLONS = /:/g; function timezoneToOffset(timezone, fallback) { + // IE/Edge do not "understand" colon (`:`) in timezone + timezone = timezone.replace(ALL_COLONS, ''); var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000; return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset; } @@ -10459,8 +10494,9 @@ function addDateMinutes(date, minutes) { function convertTimezoneToLocal(date, timezone, reverse) { reverse = reverse ? -1 : 1; - var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset()); - return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset())); + var dateTimezoneOffset = date.getTimezoneOffset(); + var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); + return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset)); } @@ -10479,7 +10515,7 @@ function startingTag(element) { return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) : elemHtml. match(/^(<[^>]+>)/)[1]. - replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); }); + replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);}); } catch (e) { return lowercase(elemHtml); } @@ -10922,7 +10958,6 @@ function snake_case(name, separator) { } var bindJQueryFired = false; -var skipDestroyOnNextJQueryCleanData; function bindJQuery() { var originalCleanData; @@ -10932,10 +10967,9 @@ function bindJQuery() { // bind to jQuery if present; var jqName = jq(); - jQuery = window.jQuery; // use default jQuery. - if (isDefined(jqName)) { // `ngJq` present - jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`. - } + jQuery = isUndefined(jqName) ? window.jQuery : // use jQuery (if present) + !jqName ? undefined : // use jqLite + window[jqName]; // use jQuery specified by `ngJq` // Use jQuery if it exists with proper functionality, otherwise default to us. // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. @@ -10957,15 +10991,11 @@ function bindJQuery() { originalCleanData = jQuery.cleanData; jQuery.cleanData = function(elems) { var events; - if (!skipDestroyOnNextJQueryCleanData) { - for (var i = 0, elem; (elem = elems[i]) != null; i++) { - events = jQuery._data(elem, "events"); - if (events && events.$destroy) { - jQuery(elem).triggerHandler('$destroy'); - } + for (var i = 0, elem; (elem = elems[i]) != null; i++) { + events = jQuery._data(elem, "events"); + if (events && events.$destroy) { + jQuery(elem).triggerHandler('$destroy'); } - } else { - skipDestroyOnNextJQueryCleanData = false; } originalCleanData(elems); }; @@ -11040,22 +11070,24 @@ function getter(obj, path, bindFnToScope) { /** * Return the DOM siblings between the first and last node in the given array. * @param {Array} array like object - * @returns {jqLite} jqLite collection containing the nodes + * @returns {Array} the inputted object or a jqLite collection containing the nodes */ function getBlockNodes(nodes) { - // TODO(perf): just check if all items in `nodes` are siblings and if they are return the original - // collection, otherwise update the original collection. + // TODO(perf): update `nodes` instead of creating a new object? var node = nodes[0]; var endNode = nodes[nodes.length - 1]; - var blockNodes = [node]; + var blockNodes; - do { - node = node.nextSibling; - if (!node) break; - blockNodes.push(node); - } while (node !== endNode); + for (var i = 1; node !== endNode && (node = node.nextSibling); i++) { + if (blockNodes || nodes[i] !== node) { + if (!blockNodes) { + blockNodes = jqLite(slice.call(nodes, 0, i)); + } + blockNodes.push(node); + } + } - return jqLite(blockNodes); + return blockNodes || nodes; } @@ -11157,7 +11189,7 @@ function setupModuleLoader(window) { * unspecified then the module is being retrieved for further configuration. * @param {Function=} configFn Optional configuration function for the module. Same as * {@link angular.Module#config Module#config()}. - * @returns {module} new module with the {@link angular.Module} api. + * @returns {angular.Module} new module with the {@link angular.Module} api. */ return function module(name, requires, configFn) { var assertNotHasOwnProperty = function(name, context) { @@ -11269,7 +11301,7 @@ function setupModuleLoader(window) { * @param {string} name constant name * @param {*} object Constant value. * @description - * Because the constant are fixed, they get applied before other provide methods. + * Because the constants are fixed, they get applied before other provide methods. * See {@link auto.$provide#constant $provide.constant()}. */ constant: invokeLater('$provide', 'constant', 'unshift'), @@ -11365,6 +11397,19 @@ function setupModuleLoader(window) { /** * @ngdoc method + * @name angular.Module#component + * @module ng + * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp) + * @param {Object} options Component definition object (a simplified + * {@link ng.$compile#directive-definition-object directive definition object}) + * + * @description + * See {@link ng.$compileProvider#component $compileProvider.component()}. + */ + component: invokeLaterAndSetModuleName('$compileProvider', 'component'), + + /** + * @ngdoc method * @name angular.Module#config * @module ng * @param {Function} configFn Execute this function on module load. Useful for service @@ -11439,7 +11484,7 @@ function serializeObject(obj) { val = toJsonReplacer(key, val); if (isObject(val)) { - if (seen.indexOf(val) >= 0) return '<<already seen>>'; + if (seen.indexOf(val) >= 0) return '...'; seen.push(val); } @@ -11450,7 +11495,7 @@ function serializeObject(obj) { function toDebugString(obj) { if (typeof obj === 'function') { return obj.toString().replace(/ \{[\s\S]*$/, ''); - } else if (typeof obj === 'undefined') { + } else if (isUndefined(obj)) { return 'undefined'; } else if (typeof obj !== 'string') { return serializeObject(obj); @@ -11514,11 +11559,14 @@ function toDebugString(obj) { $AnchorScrollProvider, $AnimateProvider, $CoreAnimateCssProvider, + $$CoreAnimateJsProvider, $$CoreAnimateQueueProvider, - $$CoreAnimateRunnerProvider, + $$AnimateRunnerFactoryProvider, + $$AnimateAsyncRunFactoryProvider, $BrowserProvider, $CacheFactoryProvider, $ControllerProvider, + $DateProvider, $DocumentProvider, $ExceptionHandlerProvider, $FilterProvider, @@ -11530,6 +11578,7 @@ function toDebugString(obj) { $HttpParamSerializerProvider, $HttpParamSerializerJQLikeProvider, $HttpBackendProvider, + $xhrFactoryProvider, $LocationProvider, $LogProvider, $ParseProvider, @@ -11556,8 +11605,9 @@ function toDebugString(obj) { * @name angular.version * @module ng * @description - * An object that contains information about the current AngularJS version. This object has the - * following properties: + * An object that contains information about the current AngularJS version. + * + * This object has the following properties: * * - `full` â `{string}` â Full version string, such as "0.9.18". * - `major` â `{number}` â Major version number, such as "0". @@ -11566,11 +11616,11 @@ function toDebugString(obj) { * - `codeName` â `{string}` â Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.4.5', // all of these placeholder strings will be replaced by grunt's + full: '1.5.0', // all of these placeholder strings will be replaced by grunt's major: 1, // package task - minor: 4, - dot: 5, - codeName: 'permanent-internship' + minor: 5, + dot: 0, + codeName: 'ennoblement-facilitation' }; @@ -11672,8 +11722,10 @@ function publishExternalAPI(angular) { $anchorScroll: $AnchorScrollProvider, $animate: $AnimateProvider, $animateCss: $CoreAnimateCssProvider, + $$animateJs: $$CoreAnimateJsProvider, $$animateQueue: $$CoreAnimateQueueProvider, - $$AnimateRunner: $$CoreAnimateRunnerProvider, + $$AnimateRunner: $$AnimateRunnerFactoryProvider, + $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider, $browser: $BrowserProvider, $cacheFactory: $CacheFactoryProvider, $controller: $ControllerProvider, @@ -11687,6 +11739,7 @@ function publishExternalAPI(angular) { $httpParamSerializer: $HttpParamSerializerProvider, $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider, $httpBackend: $HttpBackendProvider, + $xhrFactory: $xhrFactoryProvider, $location: $LocationProvider, $log: $LogProvider, $parse: $ParseProvider, @@ -11743,16 +11796,22 @@ function publishExternalAPI(angular) { * * If jQuery is available, `angular.element` is an alias for the * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element` - * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite." + * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**. * - * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows - * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most - * commonly needed functionality with the goal of having a very small footprint.</div> + * jqLite is a tiny, API-compatible subset of jQuery that allows + * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most + * commonly needed functionality with the goal of having a very small footprint. * - * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. + * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the + * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a + * specific version of jQuery if multiple versions exist on the page. * - * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or - * jqLite; they are never raw DOM references.</div> + * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or + * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div> + * + * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements + * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)` + * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div> * * ## Angular's jqLite * jqLite provides only the following jQuery methods: @@ -11765,7 +11824,8 @@ function publishExternalAPI(angular) { * - [`children()`](http://api.jquery.com/children/) - Does not support selectors * - [`clone()`](http://api.jquery.com/clone/) * - [`contents()`](http://api.jquery.com/contents/) - * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'. + * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. + * As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing. * - [`data()`](http://api.jquery.com/data/) * - [`detach()`](http://api.jquery.com/detach/) * - [`empty()`](http://api.jquery.com/empty/) @@ -11861,10 +11921,10 @@ function camelCase(name) { replace(MOZ_HACK_REGEXP, 'Moz$1'); } -var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/; +var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/; var HTML_REGEXP = /<|&#?\w+;/; -var TAG_NAME_REGEXP = /<([\w:]+)/; -var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi; +var TAG_NAME_REGEXP = /<([\w:-]+)/; +var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi; var wrapMap = { 'option': [1, '<select multiple="multiple">', '</select>'], @@ -11899,6 +11959,12 @@ function jqLiteHasData(node) { return false; } +function jqLiteCleanData(nodes) { + for (var i = 0, ii = nodes.length; i < ii; i++) { + jqLiteRemoveData(nodes[i]); + } +} + function jqLiteBuildFragment(html, context) { var tmp, tag, wrap, fragment = context.createDocumentFragment(), @@ -11951,6 +12017,24 @@ function jqLiteParseHTML(html, context) { return []; } +function jqLiteWrapNode(node, wrapper) { + var parent = node.parentNode; + + if (parent) { + parent.replaceChild(wrapper, node); + } + + wrapper.appendChild(node); +} + + +// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259. +var jqLiteContains = Node.prototype.contains || function(arg) { + // jshint bitwise: false + return !!(this.compareDocumentPosition(arg) & 16); + // jshint bitwise: true +}; + ///////////////////////////////////////////// function JQLite(element) { if (element instanceof JQLite) { @@ -12009,17 +12093,23 @@ function jqLiteOff(element, type, fn, unsupported) { delete events[type]; } } else { - forEach(type.split(' '), function(type) { + + var removeHandler = function(type) { + var listenerFns = events[type]; if (isDefined(fn)) { - var listenerFns = events[type]; arrayRemove(listenerFns || [], fn); - if (listenerFns && listenerFns.length > 0) { - return; - } } + if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) { + removeEventListenerFn(element, type, handle); + delete events[type]; + } + }; - removeEventListenerFn(element, type, handle); - delete events[type]; + forEach(type.split(' '), function(type) { + removeHandler(type); + if (MOUSE_EVENT_MAP[type]) { + removeHandler(MOUSE_EVENT_MAP[type]); + } }); } } @@ -12160,7 +12250,7 @@ function jqLiteInheritedData(element, name, value) { while (element) { for (var i = 0, ii = names.length; i < ii; i++) { - if ((value = jqLite.data(element, names[i])) !== undefined) return value; + if (isDefined(value = jqLite.data(element, names[i]))) return value; } // If dealing with a document fragment node with a host element, and no parent, use the host @@ -12187,7 +12277,7 @@ function jqLiteRemove(element, keepData) { function jqLiteDocumentLoaded(action, win) { win = win || window; if (win.document.readyState === 'complete') { - // Force the action to be run async for consistent behaviour + // Force the action to be run async for consistent behavior // from the action's point of view // i.e. it will definitely not be in a $apply win.setTimeout(action); @@ -12266,15 +12356,15 @@ function getBooleanAttrName(element, name) { return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr; } -function getAliasedAttrName(element, name) { - var nodeName = element.nodeName; - return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name]; +function getAliasedAttrName(name) { + return ALIASED_ATTR[name]; } forEach({ data: jqLiteData, removeData: jqLiteRemoveData, - hasData: jqLiteHasData + hasData: jqLiteHasData, + cleanData: jqLiteCleanData }, function(fn, name) { JQLite[name] = fn; }); @@ -12405,7 +12495,7 @@ forEach({ // in a way that survives minification. // jqLiteEmpty takes no arguments but is a setter. if (fn !== jqLiteEmpty && - (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) { + (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) { if (isObject(arg1)) { // we are a write, but the object properties are the key/values @@ -12426,7 +12516,7 @@ forEach({ // TODO: do we still need this? var value = fn.$dv; // Only if we have $dv do we iterate over all, otherwise it is just the first element. - var jj = (value === undefined) ? Math.min(nodeCount, 1) : nodeCount; + var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount; for (var j = 0; j < jj; j++) { var nodeValue = fn(this[j], arg1, arg2); value = value ? value + nodeValue : nodeValue; @@ -12475,6 +12565,9 @@ function createEventHandler(element, events) { return event.immediatePropagationStopped === true; }; + // Some events have special handlers that wrap the real handler + var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper; + // Copy event handlers in case event handlers array is modified during execution. if ((eventFnsLength > 1)) { eventFns = shallowCopy(eventFns); @@ -12482,7 +12575,7 @@ function createEventHandler(element, events) { for (var i = 0; i < eventFnsLength; i++) { if (!event.isImmediatePropagationStopped()) { - eventFns[i].call(element, event); + handlerWrapper(element, event, eventFns[i]); } } }; @@ -12493,6 +12586,22 @@ function createEventHandler(element, events) { return eventHandler; } +function defaultHandlerWrapper(element, event, handler) { + handler.call(element, event); +} + +function specialMouseHandlerWrapper(target, event, handler) { + // Refer to jQuery's implementation of mouseenter & mouseleave + // Read about mouseenter and mouseleave: + // http://www.quirksmode.org/js/events_mouse.html#link8 + var related = event.relatedTarget; + // For mousenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if (!related || (related !== target && !jqLiteContains.call(target, related))) { + handler.call(target, event); + } +} + ////////////////////////////////////////// // Functions iterating traversal. // These functions chain results into a single @@ -12521,35 +12630,28 @@ forEach({ var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type]; var i = types.length; - while (i--) { - type = types[i]; + var addHandler = function(type, specialHandlerWrapper, noEventListener) { var eventFns = events[type]; if (!eventFns) { - events[type] = []; - - if (type === 'mouseenter' || type === 'mouseleave') { - // Refer to jQuery's implementation of mouseenter & mouseleave - // Read about mouseenter and mouseleave: - // http://www.quirksmode.org/js/events_mouse.html#link8 - - jqLiteOn(element, MOUSE_EVENT_MAP[type], function(event) { - var target = this, related = event.relatedTarget; - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if (!related || (related !== target && !target.contains(related))) { - handle(event, type); - } - }); - - } else { - if (type !== '$destroy') { - addEventListenerFn(element, type, handle); - } + eventFns = events[type] = []; + eventFns.specialHandlerWrapper = specialHandlerWrapper; + if (type !== '$destroy' && !noEventListener) { + addEventListenerFn(element, type, handle); } - eventFns = events[type]; } + eventFns.push(fn); + }; + + while (i--) { + type = types[i]; + if (MOUSE_EVENT_MAP[type]) { + addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper); + addHandler(type, undefined, true); + } else { + addHandler(type); + } } }, @@ -12617,12 +12719,7 @@ forEach({ }, wrap: function(element, wrapNode) { - wrapNode = jqLite(wrapNode).eq(0).clone()[0]; - var parent = element.parentNode; - if (parent) { - parent.replaceChild(wrapNode, element); - } - wrapNode.appendChild(element); + jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]); }, remove: jqLiteRemove, @@ -12900,17 +12997,23 @@ var $$HashMapProvider = [function() { * Implicit module which gets automatically added to each {@link auto.$injector $injector}. */ +var ARROW_ARG = /^([^\(]+?)=>/; var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m; var FN_ARG_SPLIT = /,/; var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var $injectorMinErr = minErr('$injector'); +function extractArgs(fn) { + var fnText = fn.toString().replace(STRIP_COMMENTS, ''), + args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS); + return args; +} + function anonFn(fn) { // For anonymous functions, showing at the very least the function signature can help in // debugging. - var fnText = fn.toString().replace(STRIP_COMMENTS, ''), - args = fnText.match(FN_ARGS); + var args = extractArgs(fn); if (args) { return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')'; } @@ -12919,7 +13022,6 @@ function anonFn(fn) { function annotate(fn, strictDi, name) { var $inject, - fnText, argDecl, last; @@ -12934,8 +13036,7 @@ function annotate(fn, strictDi, name) { throw $injectorMinErr('strictdi', '{0} is not using explicit annotation and cannot be invoked in strict mode', name); } - fnText = fn.toString().replace(STRIP_COMMENTS, ''); - argDecl = fnText.match(FN_ARGS); + argDecl = extractArgs(fn); forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) { arg.replace(FN_ARG, function(all, underscore, name) { $inject.push(name); @@ -13325,8 +13426,20 @@ function annotate(fn, strictDi, name) { * * Register a **service constructor**, which will be invoked with `new` to create the service * instance. - * This is short for registering a service where its provider's `$get` property is the service - * constructor function that will be used to instantiate the service instance. + * This is short for registering a service where its provider's `$get` property is a factory + * function that returns an instance instantiated by the injector from the service constructor + * function. + * + * Internally it looks a bit like this: + * + * ``` + * { + * $get: function() { + * return $injector.instantiate(constructor); + * } + * } + * ``` + * * * You should use {@link auto.$provide#service $provide.service(class)} if you define your service * as a type/class. @@ -13427,7 +13540,7 @@ function annotate(fn, strictDi, name) { * @description * * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator - * intercepts the creation of a service, allowing it to override or modify the behaviour of the + * intercepts the creation of a service, allowing it to override or modify the behavior of the * service. The object returned by the decorator may be the original service, or a new service * object which replaces or wraps and delegates to the original service. * @@ -13476,14 +13589,19 @@ function createInjector(modulesToLoad, strictDi) { throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); })), instanceCache = {}, - instanceInjector = (instanceCache.$injector = + protoInstanceInjector = createInternalInjector(instanceCache, function(serviceName, caller) { var provider = providerInjector.get(serviceName + providerSuffix, caller); - return instanceInjector.invoke(provider.$get, provider, undefined, serviceName); - })); - + return instanceInjector.invoke( + provider.$get, provider, undefined, serviceName); + }), + instanceInjector = protoInstanceInjector; - forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); }); + providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) }; + var runBlocks = loadModules(modulesToLoad); + instanceInjector = protoInstanceInjector.get('$injector'); + instanceInjector.strictDi = strictDi; + forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); }); return instanceInjector; @@ -13633,48 +13751,67 @@ function createInjector(modulesToLoad, strictDi) { } } - function invoke(fn, self, locals, serviceName) { - if (typeof locals === 'string') { - serviceName = locals; - locals = null; - } + function injectionArgs(fn, locals, serviceName) { var args = [], - $inject = createInjector.$$annotate(fn, strictDi, serviceName), - length, i, - key; + $inject = createInjector.$$annotate(fn, strictDi, serviceName); - for (i = 0, length = $inject.length; i < length; i++) { - key = $inject[i]; + for (var i = 0, length = $inject.length; i < length; i++) { + var key = $inject[i]; if (typeof key !== 'string') { throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key); } - args.push( - locals && locals.hasOwnProperty(key) - ? locals[key] - : getService(key, serviceName) - ); + args.push(locals && locals.hasOwnProperty(key) ? locals[key] : + getService(key, serviceName)); + } + return args; + } + + function isClass(func) { + // IE 9-11 do not support classes and IE9 leaks with the code below. + if (msie <= 11) { + return false; + } + // Workaround for MS Edge. + // Check https://connect.microsoft.com/IE/Feedback/Details/2211653 + return typeof func === 'function' + && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func)); + } + + function invoke(fn, self, locals, serviceName) { + if (typeof locals === 'string') { + serviceName = locals; + locals = null; } + + var args = injectionArgs(fn, locals, serviceName); if (isArray(fn)) { - fn = fn[length]; + fn = fn[fn.length - 1]; } - // http://jsperf.com/angularjs-invoke-apply-vs-switch - // #5388 - return fn.apply(self, args); + if (!isClass(fn)) { + // http://jsperf.com/angularjs-invoke-apply-vs-switch + // #5388 + return fn.apply(self, args); + } else { + args.unshift(null); + return new (Function.prototype.bind.apply(fn, args))(); + } } + function instantiate(Type, locals, serviceName) { // Check if Type is annotated and use just the given function at n-1 as parameter // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]); - // Object creation: http://jsperf.com/create-constructor/2 - var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null); - var returnedValue = invoke(Type, instance, locals, serviceName); - - return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance; + var ctor = (isArray(Type) ? Type[Type.length - 1] : Type); + var args = injectionArgs(Type, locals, serviceName); + // Empty object at position 0 is ignored for invocation with `new`, but required. + args.unshift(null); + return new (Function.prototype.bind.apply(ctor, args))(); } + return { invoke: invoke, instantiate: instantiate, @@ -13730,7 +13867,7 @@ function $AnchorScrollProvider() { * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified * in the - * [HTML5 spec](http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document). + * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document). * * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to * match any anchor whenever it changes. This can be disabled by calling @@ -14013,27 +14150,8 @@ function prepareAnimateOptions(options) { : {}; } -var $$CoreAnimateRunnerProvider = function() { - this.$get = ['$q', '$$rAF', function($q, $$rAF) { - function AnimateRunner() {} - AnimateRunner.all = noop; - AnimateRunner.chain = noop; - AnimateRunner.prototype = { - end: noop, - cancel: noop, - resume: noop, - pause: noop, - complete: noop, - then: function(pass, fail) { - return $q(function(resolve) { - $$rAF(function() { - resolve(); - }); - }).then(pass, fail); - } - }; - return AnimateRunner; - }]; +var $$CoreAnimateJsProvider = function() { + this.$get = function() {}; }; // this is prefixed with Core since it conflicts with @@ -14061,65 +14179,75 @@ var $$CoreAnimateQueueProvider = function() { addRemoveClassesPostDigest(element, options.addClass, options.removeClass); } - return new $$AnimateRunner(); // jshint ignore:line + var runner = new $$AnimateRunner(); // jshint ignore:line + + // since there are no animations to run the runner needs to be + // notified that the animation call is complete. + runner.complete(); + return runner; } }; - function addRemoveClassesPostDigest(element, add, remove) { - var classVal, data = postDigestQueue.get(element); - if (!data) { - postDigestQueue.put(element, data = {}); - postDigestElements.push(element); + function updateData(data, classes, value) { + var changed = false; + if (classes) { + classes = isString(classes) ? classes.split(' ') : + isArray(classes) ? classes : []; + forEach(classes, function(className) { + if (className) { + changed = true; + data[className] = value; + } + }); } - - var updateData = function(classes, value) { - var changed = false; - if (classes) { - classes = isString(classes) ? classes.split(' ') : - isArray(classes) ? classes : []; - forEach(classes, function(className) { - if (className) { - changed = true; - data[className] = value; + return changed; + } + + function handleCSSClassChanges() { + forEach(postDigestElements, function(element) { + var data = postDigestQueue.get(element); + if (data) { + var existing = splitClasses(element.attr('class')); + var toAdd = ''; + var toRemove = ''; + forEach(data, function(status, className) { + var hasClass = !!existing[className]; + if (status !== hasClass) { + if (status) { + toAdd += (toAdd.length ? ' ' : '') + className; + } else { + toRemove += (toRemove.length ? ' ' : '') + className; + } } }); + + forEach(element, function(elm) { + toAdd && jqLiteAddClass(elm, toAdd); + toRemove && jqLiteRemoveClass(elm, toRemove); + }); + postDigestQueue.remove(element); } - return changed; - }; + }); + postDigestElements.length = 0; + } - var classesAdded = updateData(add, true); - var classesRemoved = updateData(remove, false); - if ((!classesAdded && !classesRemoved) || postDigestElements.length > 1) return; - - $rootScope.$$postDigest(function() { - forEach(postDigestElements, function(element) { - var data = postDigestQueue.get(element); - if (data) { - var existing = splitClasses(element.attr('class')); - var toAdd = ''; - var toRemove = ''; - forEach(data, function(status, className) { - var hasClass = !!existing[className]; - if (status !== hasClass) { - if (status) { - toAdd += (toAdd.length ? ' ' : '') + className; - } else { - toRemove += (toRemove.length ? ' ' : '') + className; - } - } - }); - forEach(element, function(elm) { - toAdd && jqLiteAddClass(elm, toAdd); - toRemove && jqLiteRemoveClass(elm, toRemove); - }); - postDigestQueue.remove(element); - } - }); + function addRemoveClassesPostDigest(element, add, remove) { + var data = postDigestQueue.get(element) || {}; - postDigestElements.length = 0; - }); + var classesAdded = updateData(data, add, true); + var classesRemoved = updateData(data, remove, false); + + if (classesAdded || classesRemoved) { + + postDigestQueue.put(element, data); + postDigestElements.push(element); + + if (postDigestElements.length === 1) { + $rootScope.$$postDigest(handleCSSClassChanges); + } + } } }]; }; @@ -14240,7 +14368,7 @@ var $AnimateProvider = ['$provide', function($provide) { * when an animation is detected (and animations are enabled), $animate will do the heavy lifting * to ensure that animation runs with the triggered DOM operation. * - * By default $animate doesn't trigger an animations. This is because the `ngAnimate` module isn't + * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't * included and only when it is active then the animation hooks that `$animate` triggers will be * functional. Once active then all structural `ng-` directives will trigger animations as they perform * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`, @@ -14298,8 +14426,8 @@ var $AnimateProvider = ['$provide', function($provide) { * // remove all the animation event listeners listening for `enter` on the given element and its children * $animate.off('enter', container); * - * // remove the event listener function provided by `listenerFn` that is set - * // to listen for `enter` on the given `element` as well as its children + * // remove the event listener function provided by `callback` that is set + * // to listen for `enter` on the given `container` as well as its children * $animate.off('enter', container, callback); * ``` * @@ -14521,17 +14649,30 @@ var $AnimateProvider = ['$provide', function($provide) { * @kind function * * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element. - * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take - * on the provided styles. For example, if a transition animation is set for the given className then the provided from and - * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles - * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter). + * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take + * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and + * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding + * style in `to`, the style in `from` is applied immediately, and no animation is run. + * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate` + * method (or as part of the `options` parameter): + * + * ```js + * ngModule.animation('.my-inline-animation', function() { + * return { + * animate : function(element, from, to, done, options) { + * //animation + * done(); + * } + * } + * }); + * ``` * * @param {DOMElement} element the element which the CSS styles will be applied to * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation. * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation. * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If * this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element. - * (Note that if no animation is detected then this value will not be appplied to the element.) + * (Note that if no animation is detected then this value will not be applied to the element.) * @param {object=} options an optional collection of options/styles that will be applied to the element * * @return {Promise} the animation callback promise @@ -14549,72 +14690,245 @@ var $AnimateProvider = ['$provide', function($provide) { }]; }]; -/** - * @ngdoc service - * @name $animateCss - * @kind object - * - * @description - * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included, - * then the `$animateCss` service will actually perform animations. - * - * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}. - */ -var $CoreAnimateCssProvider = function() { - this.$get = ['$$rAF', '$q', function($$rAF, $q) { +var $$AnimateAsyncRunFactoryProvider = function() { + this.$get = ['$$rAF', function($$rAF) { + var waitQueue = []; - var RAFPromise = function() {}; - RAFPromise.prototype = { - done: function(cancel) { - this.defer && this.defer[cancel === true ? 'reject' : 'resolve'](); - }, - end: function() { - this.done(); - }, - cancel: function() { - this.done(true); - }, - getPromise: function() { - if (!this.defer) { - this.defer = $q.defer(); + function waitForTick(fn) { + waitQueue.push(fn); + if (waitQueue.length > 1) return; + $$rAF(function() { + for (var i = 0; i < waitQueue.length; i++) { + waitQueue[i](); } - return this.defer.promise; - }, - then: function(f1,f2) { - return this.getPromise().then(f1,f2); - }, - 'catch': function(f1) { - return this.getPromise()['catch'](f1); - }, - 'finally': function(f1) { - return this.getPromise()['finally'](f1); - } + waitQueue = []; + }); + } + + return function() { + var passed = false; + waitForTick(function() { + passed = true; + }); + return function(callback) { + passed ? callback() : waitForTick(callback); + }; }; + }]; +}; - return function(element, options) { - if (options.from) { - element.css(options.from); - options.from = null; - } +var $$AnimateRunnerFactoryProvider = function() { + this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout', + function($q, $sniffer, $$animateAsyncRun, $document, $timeout) { - var closed, runner = new RAFPromise(); - return { - start: run, - end: run - }; + var INITIAL_STATE = 0; + var DONE_PENDING_STATE = 1; + var DONE_COMPLETE_STATE = 2; - function run() { - $$rAF(function() { - close(); - if (!closed) { - runner.done(); + AnimateRunner.chain = function(chain, callback) { + var index = 0; + + next(); + function next() { + if (index === chain.length) { + callback(true); + return; + } + + chain[index](function(response) { + if (response === false) { + callback(false); + return; } - closed = true; + index++; + next(); }); - return runner; } + }; - function close() { + AnimateRunner.all = function(runners, callback) { + var count = 0; + var status = true; + forEach(runners, function(runner) { + runner.done(onProgress); + }); + + function onProgress(response) { + status = status && response; + if (++count === runners.length) { + callback(status); + } + } + }; + + function AnimateRunner(host) { + this.setHost(host); + + var rafTick = $$animateAsyncRun(); + var timeoutTick = function(fn) { + $timeout(fn, 0, false); + }; + + this._doneCallbacks = []; + this._tick = function(fn) { + var doc = $document[0]; + + // the document may not be ready or attached + // to the module for some internal tests + if (doc && doc.hidden) { + timeoutTick(fn); + } else { + rafTick(fn); + } + }; + this._state = 0; + } + + AnimateRunner.prototype = { + setHost: function(host) { + this.host = host || {}; + }, + + done: function(fn) { + if (this._state === DONE_COMPLETE_STATE) { + fn(); + } else { + this._doneCallbacks.push(fn); + } + }, + + progress: noop, + + getPromise: function() { + if (!this.promise) { + var self = this; + this.promise = $q(function(resolve, reject) { + self.done(function(status) { + status === false ? reject() : resolve(); + }); + }); + } + return this.promise; + }, + + then: function(resolveHandler, rejectHandler) { + return this.getPromise().then(resolveHandler, rejectHandler); + }, + + 'catch': function(handler) { + return this.getPromise()['catch'](handler); + }, + + 'finally': function(handler) { + return this.getPromise()['finally'](handler); + }, + + pause: function() { + if (this.host.pause) { + this.host.pause(); + } + }, + + resume: function() { + if (this.host.resume) { + this.host.resume(); + } + }, + + end: function() { + if (this.host.end) { + this.host.end(); + } + this._resolve(true); + }, + + cancel: function() { + if (this.host.cancel) { + this.host.cancel(); + } + this._resolve(false); + }, + + complete: function(response) { + var self = this; + if (self._state === INITIAL_STATE) { + self._state = DONE_PENDING_STATE; + self._tick(function() { + self._resolve(response); + }); + } + }, + + _resolve: function(response) { + if (this._state !== DONE_COMPLETE_STATE) { + forEach(this._doneCallbacks, function(fn) { + fn(response); + }); + this._doneCallbacks.length = 0; + this._state = DONE_COMPLETE_STATE; + } + } + }; + + return AnimateRunner; + }]; +}; + +/** + * @ngdoc service + * @name $animateCss + * @kind object + * + * @description + * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included, + * then the `$animateCss` service will actually perform animations. + * + * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}. + */ +var $CoreAnimateCssProvider = function() { + this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) { + + return function(element, initialOptions) { + // all of the animation functions should create + // a copy of the options data, however, if a + // parent service has already created a copy then + // we should stick to using that + var options = initialOptions || {}; + if (!options.$$prepared) { + options = copy(options); + } + + // there is no point in applying the styles since + // there is no animation that goes on at all in + // this version of $animateCss. + if (options.cleanupStyles) { + options.from = options.to = null; + } + + if (options.from) { + element.css(options.from); + options.from = null; + } + + /* jshint newcap: false */ + var closed, runner = new $$AnimateRunner(); + return { + start: run, + end: run + }; + + function run() { + $$rAF(function() { + applyAnimationContents(); + if (!closed) { + runner.complete(); + } + closed = true; + }); + return runner; + } + + function applyAnimationContents() { if (options.addClass) { element.addClass(options.addClass); options.addClass = null; @@ -14720,7 +15034,7 @@ function Browser(window, document, $log, $sniffer) { var cachedState, lastHistoryState, lastBrowserUrl = location.href, baseElement = document.find('base'), - reloadLocation = null; + pendingLocation = null; cacheState(); lastHistoryState = cachedState; @@ -14780,8 +15094,8 @@ function Browser(window, document, $log, $sniffer) { // Do the assignment again so that those two variables are referentially identical. lastHistoryState = cachedState; } else { - if (!sameBase || reloadLocation) { - reloadLocation = url; + if (!sameBase || pendingLocation) { + pendingLocation = url; } if (replace) { location.replace(url); @@ -14790,14 +15104,18 @@ function Browser(window, document, $log, $sniffer) { } else { location.hash = getHash(url); } + if (location.href !== url) { + pendingLocation = url; + } } return self; // getter } else { - // - reloadLocation is needed as browsers don't allow to read out - // the new location.href if a reload happened. + // - pendingLocation is needed as browsers don't allow to read out + // the new location.href if a reload happened or if there is a bug like in iOS 9 (see + // https://openradar.appspot.com/22186109). // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172 - return reloadLocation || location.href.replace(/%27/g,"'"); + return pendingLocation || location.href.replace(/%27/g,"'"); } }; @@ -14819,6 +15137,7 @@ function Browser(window, document, $log, $sniffer) { urlChangeInit = false; function cacheStateAndFireUrlChange() { + pendingLocation = null; cacheState(); fireUrlChange(); } @@ -15054,10 +15373,10 @@ function $BrowserProvider() { $scope.keys = []; $scope.cache = $cacheFactory('cacheId'); $scope.put = function(key, value) { - if ($scope.cache.get(key) === undefined) { + if (angular.isUndefined($scope.cache.get(key))) { $scope.keys.push(key); } - $scope.cache.put(key, value === undefined ? null : value); + $scope.cache.put(key, angular.isUndefined(value) ? null : value); }; }]); </file> @@ -15080,9 +15399,9 @@ function $CacheFactoryProvider() { var size = 0, stats = extend({}, options, {id: cacheId}), - data = {}, + data = createMap(), capacity = (options && options.capacity) || Number.MAX_VALUE, - lruHash = {}, + lruHash = createMap(), freshEnd = null, staleEnd = null; @@ -15210,6 +15529,8 @@ function $CacheFactoryProvider() { delete lruHash[key]; } + if (!(key in data)) return; + delete data[key]; size--; }, @@ -15224,9 +15545,9 @@ function $CacheFactoryProvider() { * Clears the cache object of any entries. */ removeAll: function() { - data = {}; + data = createMap(); size = 0; - lruHash = {}; + lruHash = createMap(); freshEnd = staleEnd = null; }, @@ -15515,7 +15836,7 @@ function $TemplateCacheProvider() { * When this property is set to true, the HTML compiler will collect DOM nodes between * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them * together as the directive elements. It is recommended that this feature be used on directives - * which are not strictly behavioural (such as {@link ngClick}), and which + * which are not strictly behavioral (such as {@link ngClick}), and which * do not manipulate or replace child nodes (such as {@link ngInclude}). * * #### `priority` @@ -15533,59 +15854,129 @@ function $TemplateCacheProvider() { * and other directives used in the directive's template will also be excluded from execution. * * #### `scope` - * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the - * same element request a new scope, only one new scope is created. The new scope rule does not - * apply for the root of the template since the root of the template always gets a new scope. + * The scope property can be `true`, an object or a falsy value: + * + * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope. * - * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from - * normal scope in that it does not prototypically inherit from the parent scope. This is useful - * when creating reusable components, which should not accidentally read or modify data in the - * parent scope. + * * **`true`:** A new child scope that prototypically inherits from its parent will be created for + * the directive's element. If multiple directives on the same element request a new scope, + * only one new scope is created. The new scope rule does not apply for the root of the template + * since the root of the template always gets a new scope. * - * The 'isolate' scope takes an object hash which defines a set of local scope properties - * derived from the parent scope. These local properties are useful for aliasing values for - * templates. Locals definition is a hash of local scope property to its source: + * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The + * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent + * scope. This is useful when creating reusable components, which should not accidentally read or modify + * data in the parent scope. + * + * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the + * directive's element. These local properties are useful for aliasing values for templates. The keys in + * the object hash map to the name of the property on the isolate scope; the values define how the property + * is bound to the parent scope, via matching attributes on the directive's element: * * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is - * always a string since DOM attributes are strings. If no `attr` name is specified then the - * attribute name is assumed to be the same as the local name. - * Given `<widget my-attr="hello {{name}}">` and widget definition - * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect - * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the - * `localName` property on the widget scope. The `name` is read from the parent scope (not - * component scope). - * - * * `=` or `=attr` - set up bi-directional binding between a local scope property and the - * parent scope property of name defined via the value of the `attr` attribute. If no `attr` - * name is specified then the attribute name is assumed to be the same as the local name. - * Given `<widget my-attr="parentModel">` and widget definition of - * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the + * always a string since DOM attributes are strings. If no `attr` name is specified then the + * attribute name is assumed to be the same as the local name. Given `<my-component + * my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`, + * the directive's scope property `localName` will reflect the interpolated value of `hello + * {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's + * scope. The `name` is read from the parent scope (not the directive's scope). + * + * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression + * passed via the attribute `attr`. The expression is evaluated in the context of the parent scope. + * If no `attr` name is specified then the attribute name is assumed to be the same as the local + * name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: { + * localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the + * value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in + * `localModel` and vice versa. Optional attributes should be marked as such with a question mark: + * `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't + * optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`}) + * will be thrown upon discovering changes to the local value, since it will be impossible to sync + * them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`} + * method is used for tracking changes, and the equality check is based on object identity. + * However, if an object literal or an array literal is passed as the binding expression, the + * equality check is done by value (using the {@link angular.equals} function). It's also possible + * to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection + * `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional). + * + * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an + * expression passed via the attribute `attr`. The expression is evaluated in the context of the + * parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the + * local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`. + * + * For example, given `<my-component my-attr="parentModel">` and directive definition of + * `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected - * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent - * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You - * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If - * you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use - * `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional). - * - * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. - * If no `attr` name is specified then the attribute name is assumed to be the same as the - * local name. Given `<widget my-attr="count = count + value">` and widget definition of - * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to - * a function wrapper for the `count = count + value` expression. Often it's desirable to - * pass data from the isolated scope via an expression to the parent scope, this can be - * done by passing a map of local variable names and values into the expression wrapper fn. - * For example, if the expression is `increment(amount)` then we can specify the amount value - * by calling the `localFn` as `localFn({amount: 22})`. + * in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however + * two caveats: + * 1. one-way binding does not copy the value from the parent to the isolate scope, it simply + * sets the same value. That means if your bound value is an object, changes to its properties + * in the isolated scope will be reflected in the parent scope (because both reference the same object). + * 2. one-way binding watches changes to the **identity** of the parent value. That means the + * {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference + * to the value has changed. In most cases, this should not be of concern, but can be important + * to know if you one-way bind to an object, and then replace that object in the isolated scope. + * If you now change a property of the object in your parent scope, the change will not be + * propagated to the isolated scope, because the identity of the object on the parent scope + * has not changed. Instead you must assign a new object. + * + * One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings + * back to the parent. However, it does not make this completely impossible. + * + * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If + * no `attr` name is specified then the attribute name is assumed to be the same as the local name. + * Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: { + * localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for + * the `count = count + value` expression. Often it's desirable to pass data from the isolated scope + * via an expression to the parent scope. This can be done by passing a map of local variable names + * and values into the expression wrapper fn. For example, if the expression is `increment(amount)` + * then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`. + * + * In general it's possible to apply more than one directive to one element, but there might be limitations + * depending on the type of scope required by the directives. The following points will help explain these limitations. + * For simplicity only two directives are taken into account, but it is also applicable for several directives: + * + * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope + * * **child scope** + **no scope** => Both directives will share one single child scope + * * **child scope** + **child scope** => Both directives will share one single child scope + * * **isolated scope** + **no scope** => The isolated directive will use it's own created isolated scope. The other directive will use + * its parent's scope + * * **isolated scope** + **child scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives cannot + * be applied to the same element. + * * **isolated scope** + **isolated scope** => **Won't work!** Only one scope can be related to one element. Therefore these directives + * cannot be applied to the same element. * * * #### `bindToController` - * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will - * allow a component to have its properties bound to the controller, rather than to scope. When the controller - * is instantiated, the initial values of the isolate scope bindings are already available. + * This property is used to bind scope properties directly to the controller. It can be either + * `true` or an object hash with the same format as the `scope` property. Additionally, a controller + * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller + * definition: `controller: 'myCtrl as myAlias'`. + * + * When an isolate scope is used for a directive (see above), `bindToController: true` will + * allow a component to have its properties bound to the controller, rather than to scope. + * + * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller + * properties. You can access these bindings once they have been initialized by providing a controller method called + * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings + * initialized. + * + * <div class="alert alert-warning"> + * **Deprecation warning:** although bindings for non-ES6 class controllers are currently + * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization + * code that relies upon bindings inside a `$onInit` method on the controller, instead. + * </div> + * + * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property. + * This will set up the scope bindings to the controller directly. Note that `scope` can still be used + * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate + * scope (useful for component directives). + * + * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`. + * * * #### `controller` * Controller constructor function. The controller is instantiated before the - * pre-linking phase and it is shared with other directives (see + * pre-linking phase and can be accessed by other directives (see * `require` attribute). This allows the directives to communicate with each other and augment * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals: * @@ -15593,10 +15984,10 @@ function $TemplateCacheProvider() { * * `$element` - Current element * * `$attrs` - Current attributes object for the element * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope: - * `function([scope], cloneLinkingFn, futureParentElement)`. - * * `scope`: optional argument to override the scope. - * * `cloneLinkingFn`: optional argument to create clones of the original transcluded content. - * * `futureParentElement`: + * `function([scope], cloneLinkingFn, futureParentElement, slotName)`: + * * `scope`: (optional) override the scope. + * * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content. + * * `futureParentElement` (optional): * * defines the parent to which the `cloneLinkingFn` will add the cloned elements. * * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`. * * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements) @@ -15604,14 +15995,34 @@ function $TemplateCacheProvider() { * as those elements need to created and cloned in a special way when they are defined outside their * usual containers (e.g. like `<svg>`). * * See also the `directive.templateNamespace` property. + * * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`) + * then the default translusion is provided. + * The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns + * `true` if the specified slot contains content (i.e. one or more DOM nodes). * + * The controller can provide the following methods that act as life-cycle hooks: + * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and + * had their bindings initialized (and before the pre & post linking functions for the directives on + * this element). This is a good place to put initialization code for your controller. * * #### `require` * Require another directive and inject its controller as the fourth argument to the linking function. The - * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the - * injected argument will be an array in corresponding order. If no such directive can be - * found, or if the directive does not have a controller, then an error is raised (unless no link function - * is specified, in which case error checking is skipped). The name can be prefixed with: + * `require` property can be a string, an array or an object: + * * a **string** containing the name of the directive to pass to the linking function + * * an **array** containing the names of directives to pass to the linking function. The argument passed to the + * linking function will be an array of controllers in the same order as the names in the `require` property + * * an **object** whose property values are the names of the directives to pass to the linking function. The argument + * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding + * controllers. + * + * If the `require` property is an object and `bindToController` is truthy, then the required controllers are + * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers + * have been constructed but before `$onInit` is called. + * See the {@link $compileProvider#component} helper for an example of how this can be used. + * + * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is + * raised (unless no link function is specified and the required controllers are not being bound to the directive + * controller, in which case error checking is skipped). The name can be prefixed with: * * * (no prefix) - Locate the required controller on the current element. Throw an error if not found. * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found. @@ -15625,9 +16036,10 @@ function $TemplateCacheProvider() { * * #### `controllerAs` * Identifier name for a reference to the controller in the directive's scope. - * This allows the controller to be referenced from the directive template. The directive - * needs to define a scope for this configuration to be used. Useful in the case when - * directive is used as component. + * This allows the controller to be referenced from the directive template. This is especially + * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible + * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the + * `controllerAs` reference might overwrite a property that already exists on the parent scope. * * * #### `restrict` @@ -15703,14 +16115,6 @@ function $TemplateCacheProvider() { * The contents are compiled and provided to the directive as a **transclusion function**. See the * {@link $compile#transclusion Transclusion} section below. * - * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the - * directive's element or the entire element: - * - * * `true` - transclude the content (i.e. the child nodes) of the directive's element. - * * `'element'` - transclude the whole of the directive's element including any directives on this - * element that defined at a lower priority than this directive. When used, the `template` - * property is ignored. - * * * #### `compile` * @@ -15738,7 +16142,7 @@ function $TemplateCacheProvider() { * <div class="alert alert-warning"> * **Note:** The compile function cannot handle directives that recursively use themselves in their - * own templates or compile functions. Compiling these directives results in an infinite loop and a + * own templates or compile functions. Compiling these directives results in an infinite loop and * stack overflow errors. * * This can be avoided by manually using $compile in the postLink function to imperatively compile @@ -15840,6 +16244,34 @@ function $TemplateCacheProvider() { * Testing Transclusion Directives}. * </div> * + * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the + * directive's element, the entire element or multiple parts of the element contents: + * + * * `true` - transclude the content (i.e. the child nodes) of the directive's element. + * * `'element'` - transclude the whole of the directive's element including any directives on this + * element that defined at a lower priority than this directive. When used, the `template` + * property is ignored. + * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template. + * + * **Mult-slot transclusion** is declared by providing an object for the `transclude` property. + * + * This object is a map where the keys are the name of the slot to fill and the value is an element selector + * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`) + * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc). + * + * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives} + * + * If the element selector is prefixed with a `?` then that slot is optional. + * + * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to + * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive. + * + * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements + * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call + * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and + * injectable into the directive's controller. + * + * * #### Transclusion Functions * * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion @@ -15860,7 +16292,7 @@ function $TemplateCacheProvider() { * content and the `scope` is the newly created transclusion scope, to which the clone is bound. * * <div class="alert alert-info"> - * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function + * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope. * </div> * @@ -15892,7 +16324,7 @@ function $TemplateCacheProvider() { * </div> * * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat} - * automatically destroy their transluded clones as necessary so you do not need to worry about this if + * automatically destroy their transcluded clones as necessary so you do not need to worry about this if * you are simply using {@link ngTransclude} to inject the transclusion into your directive. * * @@ -15917,19 +16349,19 @@ function $TemplateCacheProvider() { * * The `$parent` scope hierarchy will look like this: * - * ``` - * - $rootScope - * - isolate - * - transclusion - * ``` + ``` + - $rootScope + - isolate + - transclusion + ``` * * but the scopes will inherit prototypically from differ
<TRUNCATED>