vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.0.rc3 vs vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.0
- old
+ new
@@ -9788,11 +9788,11 @@
}
})( window );
/**
- * @license AngularJS v1.2.0-rc.3
+ * @license AngularJS v1.2.0
* (c) 2010-2012 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document){
var _jQuery = window.jQuery.noConflict(true);
@@ -9869,10 +9869,94 @@
return new Error(message);
};
}
+/* We need to tell jshint what variables are being exported */
+/* global
+ -angular,
+ -msie,
+ -jqLite,
+ -jQuery,
+ -slice,
+ -push,
+ -toString,
+ -ngMinErr,
+ -_angular,
+ -angularModule,
+ -nodeName_,
+ -uid,
+
+ -lowercase,
+ -uppercase,
+ -manualLowercase,
+ -manualUppercase,
+ -nodeName_,
+ -isArrayLike,
+ -forEach,
+ -sortedKeys,
+ -forEachSorted,
+ -reverseParams,
+ -nextUid,
+ -setHashKey,
+ -extend,
+ -int,
+ -inherit,
+ -noop,
+ -identity,
+ -valueFn,
+ -isUndefined,
+ -isDefined,
+ -isObject,
+ -isString,
+ -isNumber,
+ -isDate,
+ -isArray,
+ -isFunction,
+ -isRegExp,
+ -isWindow,
+ -isScope,
+ -isFile,
+ -isBoolean,
+ -trim,
+ -isElement,
+ -makeMap,
+ -map,
+ -size,
+ -includes,
+ -indexOf,
+ -arrayRemove,
+ -isLeafNode,
+ -copy,
+ -shallowCopy,
+ -equals,
+ -csp,
+ -concat,
+ -sliceArgs,
+ -bind,
+ -toJsonReplacer,
+ -toJson,
+ -fromJson,
+ -toBoolean,
+ -startingTag,
+ -tryDecodeURIComponent,
+ -parseKeyValue,
+ -toKeyValue,
+ -encodeUriSegment,
+ -encodeUriQuery,
+ -angularInit,
+ -bootstrap,
+ -snake_case,
+ -bindJQuery,
+ -assertArg,
+ -assertArgFn,
+ -assertNotHasOwnProperty,
+ -getter,
+ -getBlockElements
+
+*/
+
////////////////////////////////////
/**
* @ngdoc function
* @name angular.lowercase
@@ -9896,15 +9980,17 @@
*/
var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
var manualLowercase = function(s) {
+ /* jshint bitwise: false */
return isString(s)
? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
: s;
};
var manualUppercase = function(s) {
+ /* jshint bitwise: false */
return isString(s)
? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
: s;
};
@@ -9946,11 +10032,12 @@
/**
* @private
* @param {*} obj
- * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, String ...)
+ * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
+ * String ...)
*/
function isArrayLike(obj) {
if (obj == null || isWindow(obj)) {
return false;
}
@@ -10040,11 +10127,11 @@
* when using forEach the params are value, key, but it is often useful to have key, value.
* @param {function(string, *)} iteratorFn
* @returns {function(*, string)}
*/
function reverseParams(iteratorFn) {
- return function(value, key) { iteratorFn(key, value) };
+ return function(value, key) { iteratorFn(key, value); };
}
/**
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
@@ -10399,21 +10486,21 @@
* @param {Object|Array|string} obj Object, array, or string to inspect.
* @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
* @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
*/
function size(obj, ownPropsOnly) {
- var size = 0, key;
+ var count = 0, key;
if (isArray(obj) || isString(obj)) {
return obj.length;
} else if (isObject(obj)){
for (key in obj)
if (!ownPropsOnly || obj.hasOwnProperty(key))
- size++;
+ count++;
}
- return size;
+ return count;
}
function includes(array, obj) {
return indexOf(array, obj) != -1;
@@ -10459,13 +10546,10 @@
* * If a destination is provided, all of its elements (for array) or properties (for objects)
* are deleted and then all elements/properties from the source are copied to it.
* * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
* * If `source` is identical to 'destination' an exception will be thrown.
*
- * Note: this function is used to augment the Object type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
* @param {*} source The source that will be used to make a copy.
* Can be any type, including primitives, `null`, and `undefined`.
* @param {(Object|Array)=} destination Destination into which the source is copied. If
* provided, must be of the same type as `source`.
* @returns {*} The copy or updated `destination`, if `destination` was specified.
@@ -10506,11 +10590,12 @@
</doc:source>
</doc:example>
*/
function copy(source, destination){
if (isWindow(source) || isScope(source)) {
- throw ngMinErr('cpws', "Can't copy! Making copies of Window or Scope instances is not supported.");
+ throw ngMinErr('cpws',
+ "Can't copy! Making copies of Window or Scope instances is not supported.");
}
if (!destination) {
destination = source;
if (source) {
@@ -10523,11 +10608,12 @@
} else if (isObject(source)) {
destination = copy(source, {});
}
}
} else {
- if (source === destination) throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
+ if (source === destination) throw ngMinErr('cpi',
+ "Can't copy! Source and destination are identical.");
if (isArray(source)) {
destination.length = 0;
for ( var i = 0; i < source.length; i++) {
destination.push(copy(source[i]));
}
@@ -10567,17 +10653,18 @@
* @ngdoc function
* @name angular.equals
* @function
*
* @description
- * Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and
- * objects.
+ * Determines if two objects or two values are equivalent. Supports value types, regular
+ * expressions, arrays and objects.
*
* Two objects or values are considered equivalent if at least one of the following is true:
*
* * Both objects or values pass `===` comparison.
- * * Both objects or values are of the same type and all of their properties pass `===` comparison.
+ * * Both objects or values are of the same type and all of their properties are equal by
+ * comparing them with `angular.equals`.
* * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
* * Both values represent the same regular expression (In JavasScript,
* /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
* representation matches).
*
@@ -10629,35 +10716,44 @@
}
return false;
}
+function csp() {
+ return (document.securityPolicy && document.securityPolicy.isActive) ||
+ (document.querySelector &&
+ !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
+}
+
+
function concat(array1, array2, index) {
return array1.concat(slice.call(array2, index));
}
function sliceArgs(args, startIndex) {
return slice.call(args, startIndex || 0);
}
+/* jshint -W101 */
/**
* @ngdoc function
* @name angular.bind
* @function
*
* @description
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
* `fn`). You can supply optional `args` that are prebound to the function. This feature is also
- * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as distinguished
- * from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
+ * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
+ * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
*
* @param {Object} self Context which `fn` should be evaluated in.
* @param {function()} fn Function to be bound.
* @param {...*} args Optional arguments to be prebound to the `fn` function call.
* @returns {function()} Function that wraps the `fn` with all the specified bindings.
*/
+/* jshint +W101 */
function bind(self, fn) {
var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
if (isFunction(fn) && !(fn instanceof RegExp)) {
return curryArgs.length
? function() {
@@ -10813,14 +10909,16 @@
function toKeyValue(obj) {
var parts = [];
forEach(obj, function(value, key) {
if (isArray(value)) {
forEach(value, function(arrayValue) {
- parts.push(encodeUriQuery(key, true) + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
+ parts.push(encodeUriQuery(key, true) +
+ (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
});
} else {
- parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
+ parts.push(encodeUriQuery(key, true) +
+ (value === true ? '' : '=' + encodeUriQuery(value, true)));
}
});
return parts.length ? parts.join('&') : '';
}
@@ -10878,12 +10976,12 @@
* Use this directive to auto-bootstrap an application. Only
* one ngApp directive can be used per HTML document. The directive
* designates the root of the application and is typically placed
* at the root of the page.
*
- * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an
- * HTML document you must manually bootstrap them using {@link angular.bootstrap}.
+ * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in
+ * an HTML document you must manually bootstrap them using {@link angular.bootstrap}.
* Applications cannot be nested.
*
* In the example below if the `ngApp` directive were not placed
* on the `html` element then the document would not be compiled
* and the `{{ 1+2 }}` would not be resolved to `3`.
@@ -10953,11 +11051,12 @@
* They must use {@link api/ng.directive:ngApp ngApp}.
*
* @param {Element} element DOM element which is the root of angular application.
* @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
* Each item in the array should be the name of a predefined module or a (DI annotated)
- * function that will be invoked by the injector as a run block. See: {@link angular.module modules}
+ * function that will be invoked by the injector as a run block.
+ * See: {@link angular.module modules}
* @returns {AUTO.$injector} Returns the newly created injector for this app.
*/
function bootstrap(element, modules) {
var doBootstrap = function() {
element = jqLite(element);
@@ -10977,11 +11076,10 @@
function(scope, element, compile, injector, animate) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
- animate.enabled(true);
}]
);
return injector;
};
@@ -11014,18 +11112,20 @@
// reset to jQuery or default to us.
if (jQuery) {
jqLite = jQuery;
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
+ isolateScope: JQLitePrototype.isolateScope,
controller: JQLitePrototype.controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
- // Method signature: JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
- JQLitePatchJQueryRemove('remove', true, true, false);
- JQLitePatchJQueryRemove('empty', false, false, false);
- JQLitePatchJQueryRemove('html', false, false, true);
+ // Method signature:
+ // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
+ jqLitePatchJQueryRemove('remove', true, true, false);
+ jqLitePatchJQueryRemove('empty', false, false, false);
+ jqLitePatchJQueryRemove('html', false, false, true);
} else {
jqLite = JQLite;
}
angular.element = jqLite;
}
@@ -11087,10 +11187,32 @@
}
return obj;
}
/**
+ * Return the siblings between `startNode` and `endNode`, inclusive
+ * @param {Object} object with `startNode` and `endNode` properties
+ * @returns jQlite object containing the elements
+ */
+function getBlockElements(block) {
+ if (block.startNode === block.endNode) {
+ return jqLite(block.startNode);
+ }
+
+ var element = block.startNode;
+ var elements = [element];
+
+ do {
+ element = element.nextSibling;
+ if (!element) break;
+ elements.push(element);
+ } while (element !== block.endNode);
+
+ return jqLite(elements);
+}
+
+/**
* @ngdoc interface
* @name angular.Module
* @description
*
* Interface for configuring angular {@link angular.module modules}.
@@ -11111,11 +11233,12 @@
/**
* @ngdoc function
* @name angular.module
* @description
*
- * The `angular.module` is a global place for creating, registering and retrieving Angular modules.
+ * The `angular.module` is a global place for creating, registering and retrieving Angular
+ * modules.
* All modules (angular core or 3rd party) that should be available to an application must be
* registered using this mechanism.
*
* When passed two or more arguments, a new module is created. If passed only one argument, an
* existing module (the name passed as the first argument to `module`) is retrieved.
@@ -11149,26 +11272,26 @@
* However it's more likely that you'll just use
* {@link ng.directive:ngApp ngApp} or
* {@link angular.bootstrap} to simplify this process for you.
*
* @param {!string} name The name of the module to create or retrieve.
- * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
- * the module is being retrieved for further configuration.
+ * @param {Array.<string>=} requires If specified then new module is being created. If
+ * unspecified then the 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()}.
+ * {@link angular.Module#methods_config Module#config()}.
* @returns {module} new module with the {@link angular.Module} api.
*/
return function module(name, requires, configFn) {
assertNotHasOwnProperty(name, 'module');
if (requires && modules.hasOwnProperty(name)) {
modules[name] = null;
}
return ensure(modules, name, function() {
if (!requires) {
- throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled the module name " +
- "or forgot to load it. If registering a module ensure that you specify the dependencies as the second " +
- "argument.", name);
+ throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
+ "the module name or forgot to load it. If registering a module ensure that you " +
+ "specify the dependencies as the second argument.", name);
}
/** @type {!Array.<Array.<*>>} */
var invokeQueue = [];
@@ -11187,11 +11310,12 @@
* @ngdoc property
* @name angular.Module#requires
* @propertyOf angular.Module
* @returns {Array.<string>} List of module names which must be loaded before this module.
* @description
- * Holds the list of modules which the injector will load before the current module is loaded.
+ * Holds the list of modules which the injector will load before the current module is
+ * loaded.
*/
requires: requires,
/**
* @ngdoc property
@@ -11206,11 +11330,12 @@
/**
* @ngdoc method
* @name angular.Module#provider
* @methodOf angular.Module
* @param {string} name service name
- * @param {Function} providerType Construction function for creating new instance of the service.
+ * @param {Function} providerType Construction function for creating new instance of the
+ * service.
* @description
* See {@link AUTO.$provide#provider $provide.provider()}.
*/
provider: invokeLater('$provide', 'provider'),
@@ -11262,18 +11387,19 @@
/**
* @ngdoc method
* @name angular.Module#animation
* @methodOf angular.Module
* @param {string} name animation name
- * @param {Function} animationFactory Factory function for creating new instance of an animation.
+ * @param {Function} animationFactory Factory function for creating new instance of an
+ * animation.
* @description
*
* **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
*
*
- * Defines an animation hook that can be later used with {@link ngAnimate.$animate $animate} service and
- * directives that use this service.
+ * Defines an animation hook that can be later used with
+ * {@link ngAnimate.$animate $animate} service and directives that use this service.
*
* <pre>
* module.animation('.animation-name', function($inject1, $inject2) {
* return {
* eventName : function(element, done) {
@@ -11322,11 +11448,11 @@
* @param {string|Object} name Directive name, or an object map of directives where the
* keys are the names and the values are the factories.
* @param {Function} directiveFactory Factory function for creating new instance of
* directives.
* @description
- * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
+ * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
*/
directive: invokeLater('$compileProvider', 'directive'),
/**
* @ngdoc method
@@ -11369,18 +11495,92 @@
*/
function invokeLater(provider, method, insertMethod) {
return function() {
invokeQueue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
- }
+ };
}
});
};
});
}
+/* global
+ angularModule: true,
+ version: true,
+
+ $LocaleProvider,
+ $CompileProvider,
+
+ htmlAnchorDirective,
+ inputDirective,
+ inputDirective,
+ formDirective,
+ scriptDirective,
+ selectDirective,
+ styleDirective,
+ optionDirective,
+ ngBindDirective,
+ ngBindHtmlDirective,
+ ngBindTemplateDirective,
+ ngClassDirective,
+ ngClassEvenDirective,
+ ngClassOddDirective,
+ ngCspDirective,
+ ngCloakDirective,
+ ngControllerDirective,
+ ngFormDirective,
+ ngHideDirective,
+ ngIfDirective,
+ ngIncludeDirective,
+ ngInitDirective,
+ ngNonBindableDirective,
+ ngPluralizeDirective,
+ ngRepeatDirective,
+ ngShowDirective,
+ ngStyleDirective,
+ ngSwitchDirective,
+ ngSwitchWhenDirective,
+ ngSwitchDefaultDirective,
+ ngOptionsDirective,
+ ngTranscludeDirective,
+ ngModelDirective,
+ ngListDirective,
+ ngChangeDirective,
+ requiredDirective,
+ requiredDirective,
+ ngValueDirective,
+ ngAttributeAliasDirectives,
+ ngEventDirectives,
+
+ $AnchorScrollProvider,
+ $AnimateProvider,
+ $BrowserProvider,
+ $CacheFactoryProvider,
+ $ControllerProvider,
+ $DocumentProvider,
+ $ExceptionHandlerProvider,
+ $FilterProvider,
+ $InterpolateProvider,
+ $IntervalProvider,
+ $HttpProvider,
+ $HttpBackendProvider,
+ $LocationProvider,
+ $LogProvider,
+ $ParseProvider,
+ $RootScopeProvider,
+ $QProvider,
+ $SceProvider,
+ $SceDelegateProvider,
+ $SnifferProvider,
+ $TemplateCacheProvider,
+ $TimeoutProvider,
+ $WindowProvider
+*/
+
+
/**
* @ngdoc property
* @name angular.version
* @description
* An object that contains information about the current AngularJS version. This object has the
@@ -11391,15 +11591,15 @@
* - `minor` – `{number}` – Minor version number, such as "9".
* - `dot` – `{number}` – Dot version number, such as "18".
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.2.0-rc.3', // all of these placeholder strings will be replaced by grunt's
+ full: '1.2.0', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
- minor: 2,
+ minor: "NG_VERSION_MINOR",
dot: 0,
- codeName: 'ferocious-twitch'
+ codeName: 'timely-delivery'
};
function publishExternalAPI(angular){
extend(angular, {
@@ -11421,16 +11621,17 @@
'isFunction': isFunction,
'isObject': isObject,
'isNumber': isNumber,
'isElement': isElement,
'isArray': isArray,
- '$$minErr': minErr,
'version': version,
'isDate': isDate,
'lowercase': lowercase,
'uppercase': uppercase,
- 'callbacks': {counter: 0}
+ 'callbacks': {counter: 0},
+ '$$minErr': minErr,
+ '$$csp': csp
});
angularModule = setupModuleLoader(window);
try {
angularModule('ngLocale');
@@ -11454,11 +11655,10 @@
ngBindHtml: ngBindHtmlDirective,
ngBindTemplate: ngBindTemplateDirective,
ngClass: ngClassDirective,
ngClassEven: ngClassEvenDirective,
ngClassOdd: ngClassOddDirective,
- ngCsp: ngCspDirective,
ngCloak: ngCloakDirective,
ngController: ngControllerDirective,
ngForm: ngFormDirective,
ngHide: ngHideDirective,
ngIf: ngIfDirective,
@@ -11510,10 +11710,18 @@
});
}
]);
}
+/* global
+
+ -JQLitePrototype,
+ -addEventListenerFn,
+ -removeEventListenerFn,
+ -BOOLEAN_ATTR
+*/
+
//////////////////////////////////
//JQLite
//////////////////////////////////
/**
@@ -11587,10 +11795,13 @@
* camelCase directive name, then the controller for this directive will be retrieved (e.g.
* `'ngModel'`).
* - `injector()` - retrieves the injector of the current element or its parent.
* - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
* element or its parent.
+ * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the
+ * current element. This getter should be used only on elements that contain a directive which starts a new isolate
+ * scope. Calling `scope()` on this element always returns the original non-isolate scope.
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
* parent element is reached.
*
* @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
* @returns {Object} jQuery object.
@@ -11632,17 +11843,18 @@
// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
// $destroy event on all DOM nodes being removed.
//
/////////////////////////////////////////////
-function JQLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
+function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
var originalJqFn = jQuery.fn[name];
originalJqFn = originalJqFn.$original || originalJqFn;
removePatch.$original = originalJqFn;
jQuery.fn[name] = removePatch;
function removePatch(param) {
+ // jshint -W040
var list = filterElems && param ? [this.filter(param)] : [this],
fireEvent = dispatchThis,
set, setIndex, setLength,
element, childIndex, childLength, children;
@@ -11684,34 +11896,34 @@
var div = document.createElement('div');
// Read about the NoScope elements here:
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
div.innerHTML = '<div> </div>' + element; // IE insanity to make NoScope elements work!
div.removeChild(div.firstChild); // remove the superfluous div
- JQLiteAddNodes(this, div.childNodes);
+ jqLiteAddNodes(this, div.childNodes);
var fragment = jqLite(document.createDocumentFragment());
fragment.append(this); // detach the elements from the temporary DOM div.
} else {
- JQLiteAddNodes(this, element);
+ jqLiteAddNodes(this, element);
}
}
-function JQLiteClone(element) {
+function jqLiteClone(element) {
return element.cloneNode(true);
}
-function JQLiteDealoc(element){
- JQLiteRemoveData(element);
+function jqLiteDealoc(element){
+ jqLiteRemoveData(element);
for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
- JQLiteDealoc(children[i]);
+ jqLiteDealoc(children[i]);
}
}
-function JQLiteOff(element, type, fn, unsupported) {
+function jqLiteOff(element, type, fn, unsupported) {
if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
- var events = JQLiteExpandoStore(element, 'events'),
- handle = JQLiteExpandoStore(element, 'handle');
+ var events = jqLiteExpandoStore(element, 'events'),
+ handle = jqLiteExpandoStore(element, 'handle');
if (!handle) return; //no listeners registered
if (isUndefined(type)) {
forEach(events, function(eventHandler, type) {
@@ -11728,11 +11940,11 @@
}
});
}
}
-function JQLiteRemoveData(element, name) {
+function jqLiteRemoveData(element, name) {
var expandoId = element[jqName],
expandoStore = jqCache[expandoId];
if (expandoStore) {
if (name) {
@@ -11740,18 +11952,18 @@
return;
}
if (expandoStore.handle) {
expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
- JQLiteOff(element);
+ jqLiteOff(element);
}
delete jqCache[expandoId];
element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
}
}
-function JQLiteExpandoStore(element, key, value) {
+function jqLiteExpandoStore(element, key, value) {
var expandoId = element[jqName],
expandoStore = jqCache[expandoId || -1];
if (isDefined(value)) {
if (!expandoStore) {
@@ -11762,18 +11974,18 @@
} else {
return expandoStore && expandoStore[key];
}
}
-function JQLiteData(element, key, value) {
- var data = JQLiteExpandoStore(element, 'data'),
+function jqLiteData(element, key, value) {
+ var data = jqLiteExpandoStore(element, 'data'),
isSetter = isDefined(value),
keyDefined = !isSetter && isDefined(key),
isSimpleGetter = keyDefined && !isObject(key);
if (!data && !isSimpleGetter) {
- JQLiteExpandoStore(element, 'data', data = {});
+ jqLiteExpandoStore(element, 'data', data = {});
}
if (isSetter) {
data[key] = value;
} else {
@@ -11788,17 +12000,17 @@
return data;
}
}
}
-function JQLiteHasClass(element, selector) {
+function jqLiteHasClass(element, selector) {
if (!element.getAttribute) return false;
return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
indexOf( " " + selector + " " ) > -1);
}
-function JQLiteRemoveClass(element, cssClasses) {
+function jqLiteRemoveClass(element, cssClasses) {
if (cssClasses && element.setAttribute) {
forEach(cssClasses.split(' '), function(cssClass) {
element.setAttribute('class', trim(
(" " + (element.getAttribute('class') || '') + " ")
.replace(/[\n\t]/g, " ")
@@ -11806,11 +12018,11 @@
);
});
}
}
-function JQLiteAddClass(element, cssClasses) {
+function jqLiteAddClass(element, cssClasses) {
if (cssClasses && element.setAttribute) {
var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
.replace(/[\n\t]/g, " ");
forEach(cssClasses.split(' '), function(cssClass) {
@@ -11822,36 +12034,40 @@
element.setAttribute('class', trim(existingClasses));
}
}
-function JQLiteAddNodes(root, elements) {
+function jqLiteAddNodes(root, elements) {
if (elements) {
elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
? elements
: [ elements ];
for(var i=0; i < elements.length; i++) {
root.push(elements[i]);
}
}
}
-function JQLiteController(element, name) {
- return JQLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
+function jqLiteController(element, name) {
+ return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
}
-function JQLiteInheritedData(element, name, value) {
+function jqLiteInheritedData(element, name, value) {
element = jqLite(element);
// if element is the document object work with the html element instead
// this makes $(document).scope() possible
if(element[0].nodeType == 9) {
element = element.find('html');
}
+ var names = isArray(name) ? name : [name];
while (element.length) {
- if ((value = element.data(name)) !== undefined) return value;
+
+ for (var i = 0, ii = names.length; i < ii; i++) {
+ if ((value = element.data(names[i])) !== undefined) return value;
+ }
element = element.parent();
}
}
//////////////////////////////////////////
@@ -11871,11 +12087,13 @@
if (document.readyState === 'complete'){
setTimeout(trigger);
} else {
this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
// we can not use jqLite since we are not done loading and jQuery could be loaded later.
+ // jshint -W064
JQLite(window).on('load', trigger); // fallback to window.onload for others
+ // jshint +W064
}
},
toString: function() {
var value = [];
forEach(this, function(e){ value.push('' + e);});
@@ -11913,28 +12131,34 @@
// booleanAttr is here twice to minimize DOM access
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
}
forEach({
- data: JQLiteData,
- inheritedData: JQLiteInheritedData,
+ data: jqLiteData,
+ inheritedData: jqLiteInheritedData,
scope: function(element) {
- return JQLiteInheritedData(element, '$scope');
+ // Can't use jqLiteData here directly so we stay compatible with jQuery!
+ return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
},
- controller: JQLiteController ,
+ isolateScope: function(element) {
+ // Can't use jqLiteData here directly so we stay compatible with jQuery!
+ return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
+ },
+ controller: jqLiteController ,
+
injector: function(element) {
- return JQLiteInheritedData(element, '$injector');
+ return jqLiteInheritedData(element, '$injector');
},
removeAttr: function(element,name) {
element.removeAttribute(name);
},
- hasClass: JQLiteHasClass,
+ hasClass: jqLiteHasClass,
css: function(element, name, value) {
name = camelCase(name);
if (isDefined(value)) {
@@ -12006,11 +12230,11 @@
}
getText.$dv = '';
return getText;
function getText(element, value) {
- var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType]
+ var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
if (isUndefined(value)) {
return textProp ? element[textProp] : '';
}
element[textProp] = value;
}
@@ -12035,29 +12259,29 @@
html: function(element, value) {
if (isUndefined(value)) {
return element.innerHTML;
}
for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
- JQLiteDealoc(childNodes[i]);
+ jqLiteDealoc(childNodes[i]);
}
element.innerHTML = value;
}
}, function(fn, name){
/**
* Properties: writes return selection, reads return first value
*/
JQLite.prototype[name] = function(arg1, arg2) {
var i, key;
- // JQLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
+ // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
// in a way that survives minification.
- if (((fn.length == 2 && (fn !== JQLiteHasClass && fn !== JQLiteController)) ? arg1 : arg2) === undefined) {
+ if (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined) {
if (isObject(arg1)) {
// we are a write, but the object properties are the key/values
for(i=0; i < this.length; i++) {
- if (fn === JQLiteData) {
+ if (fn === jqLiteData) {
// data() takes the whole object in jQuery
fn(this[i], arg1);
} else {
for (key in arg1) {
fn(this[i], key, arg1[key]);
@@ -12068,11 +12292,11 @@
return this;
} else {
// we are a read, so read the first child.
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(this.length, 1) : this.length;
+ var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
for (var j = 0; j < jj; j++) {
var nodeValue = fn(this[j], arg1, arg2);
value = value ? value + nodeValue : nodeValue;
}
return value;
@@ -12114,11 +12338,11 @@
};
event.defaultPrevented = false;
}
event.isDefaultPrevented = function() {
- return event.defaultPrevented || event.returnValue == false;
+ return event.defaultPrevented || event.returnValue === false;
};
forEach(events[type || event.type], function(fn) {
fn.call(element, event);
});
@@ -12145,30 +12369,31 @@
// Functions iterating traversal.
// These functions chain results into a single
// selector.
//////////////////////////////////////////
forEach({
- removeData: JQLiteRemoveData,
+ removeData: jqLiteRemoveData,
- dealoc: JQLiteDealoc,
+ dealoc: jqLiteDealoc,
on: function onFn(element, type, fn, unsupported){
if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
- var events = JQLiteExpandoStore(element, 'events'),
- handle = JQLiteExpandoStore(element, 'handle');
+ var events = jqLiteExpandoStore(element, 'events'),
+ handle = jqLiteExpandoStore(element, 'handle');
- if (!events) JQLiteExpandoStore(element, 'events', events = {});
- if (!handle) JQLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
+ if (!events) jqLiteExpandoStore(element, 'events', events = {});
+ if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
forEach(type.split(' '), function(type){
var eventFns = events[type];
if (!eventFns) {
if (type == 'mouseenter' || type == 'mouseleave') {
var contains = document.body.contains || document.body.compareDocumentPosition ?
function( a, b ) {
+ // jshint bitwise: false
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && (
adown.contains ?
adown.contains( bup ) :
@@ -12204,21 +12429,21 @@
} else {
addEventListenerFn(element, type, handle);
events[type] = [];
}
- eventFns = events[type]
+ eventFns = events[type];
}
eventFns.push(fn);
});
},
- off: JQLiteOff,
+ off: jqLiteOff,
replaceWith: function(element, replaceNode) {
var index, parent = element.parentNode;
- JQLiteDealoc(element);
+ jqLiteDealoc(element);
forEach(new JQLite(replaceNode), function(node){
if (index) {
parent.insertBefore(node, index.nextSibling);
} else {
parent.replaceChild(node, element);
@@ -12265,11 +12490,11 @@
}
wrapNode.appendChild(element);
},
remove: function(element) {
- JQLiteDealoc(element);
+ jqLiteDealoc(element);
var parent = element.parentNode;
if (parent) parent.removeChild(element);
},
after: function(element, newElement) {
@@ -12278,18 +12503,18 @@
parent.insertBefore(node, index.nextSibling);
index = node;
});
},
- addClass: JQLiteAddClass,
- removeClass: JQLiteRemoveClass,
+ addClass: jqLiteAddClass,
+ removeClass: jqLiteRemoveClass,
toggleClass: function(element, selector, condition) {
if (isUndefined(condition)) {
- condition = !JQLiteHasClass(element, selector);
+ condition = !jqLiteHasClass(element, selector);
}
- (condition ? JQLiteAddClass : JQLiteRemoveClass)(element, selector);
+ (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector);
},
parent: function(element) {
var parent = element.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
@@ -12310,15 +12535,15 @@
find: function(element, selector) {
return element.getElementsByTagName(selector);
},
- clone: JQLiteClone,
+ clone: jqLiteClone,
triggerHandler: function(element, eventName, eventData) {
- var eventFns = (JQLiteExpandoStore(element, 'events') || {})[eventName];
-
+ var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
+
eventData = eventData || [];
var event = [{
preventDefault: noop,
stopPropagation: noop
@@ -12333,21 +12558,21 @@
* chaining functions
*/
JQLite.prototype[name] = function(arg1, arg2, arg3) {
var value;
for(var i=0; i < this.length; i++) {
- if (value == undefined) {
+ if (isUndefined(value)) {
value = fn(this[i], arg1, arg2, arg3);
- if (value !== undefined) {
+ if (isDefined(value)) {
// any function which returns a value needs to be wrapped
value = jqLite(value);
}
} else {
- JQLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
+ jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
}
}
- return value == undefined ? this : value;
+ return isDefined(value) ? value : this;
};
// bind legacy bind/unbind to on/off
JQLite.prototype.bind = JQLite.prototype.on;
JQLite.prototype.unbind = JQLite.prototype.off;
@@ -12532,13 +12757,13 @@
* $injector.invoke(['serviceA', function(serviceA){}]);
* </pre>
*
* ## Inference
*
- * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
- * parsed and the function arguments can be extracted. *NOTE:* This does not work with minification, and obfuscation
- * tools since these tools change the argument names.
+ * In JavaScript calling `toString()` on a function returns the function definition. The definition
+ * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
+ * minification, and obfuscation tools since these tools change the argument names.
*
* ## `$inject` Annotation
* By adding a `$inject` property onto a function the injection parameters can be specified.
*
* ## Inline
@@ -12566,12 +12791,12 @@
* Invoke the method and supply the method arguments from the `$injector`.
*
* @param {!function} fn The function to invoke. Function parameters are injected according to the
* {@link guide/di $inject Annotation} rules.
* @param {Object=} self The `this` for the invoked method.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
- * the `$injector` is consulted.
+ * @param {Object=} locals Optional object. If preset then any argument names are read from this
+ * object first, before the `$injector` is consulted.
* @returns {*} the value returned by the invoked `fn` function.
*/
/**
* @ngdoc method
@@ -12588,50 +12813,53 @@
/**
* @ngdoc method
* @name AUTO.$injector#instantiate
* @methodOf AUTO.$injector
* @description
- * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
- * all of the arguments to the constructor function as specified by the constructor annotation.
+ * Create a new instance of JS type. The method takes a constructor function invokes the new
+ * operator and supplies all of the arguments to the constructor function as specified by the
+ * constructor annotation.
*
* @param {function} Type Annotated constructor function.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
- * the `$injector` is consulted.
+ * @param {Object=} locals Optional object. If preset then any argument names are read from this
+ * object first, before the `$injector` is consulted.
* @returns {Object} new instance of `Type`.
*/
/**
* @ngdoc method
* @name AUTO.$injector#annotate
* @methodOf AUTO.$injector
*
* @description
- * Returns an array of service names which the function is requesting for injection. This API is used by the injector
- * to determine which services need to be injected into the function when the function is invoked. There are three
- * ways in which the function can be annotated with the needed dependencies.
+ * Returns an array of service names which the function is requesting for injection. This API is
+ * used by the injector to determine which services need to be injected into the function when the
+ * function is invoked. There are three ways in which the function can be annotated with the needed
+ * dependencies.
*
* # Argument names
*
- * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
- * the function into a string using `toString()` method and extracting the argument names.
+ * The simplest form is to extract the dependencies from the arguments of the function. This is done
+ * by converting the function into a string using `toString()` method and extracting the argument
+ * names.
* <pre>
* // Given
* function MyController($scope, $route) {
* // ...
* }
*
* // Then
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
* </pre>
*
- * This method does not work with code minification / obfuscation. For this reason the following annotation strategies
- * are supported.
+ * This method does not work with code minification / obfuscation. For this reason the following
+ * annotation strategies are supported.
*
* # The `$inject` property
*
- * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
- * services to be injected into the function.
+ * If a function has an `$inject` property and its value is an array of strings, then the strings
+ * represent names of services to be injected into the function.
* <pre>
* // Given
* var MyController = function(obfuscatedScope, obfuscatedRoute) {
* // ...
* }
@@ -12642,13 +12870,13 @@
* expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
* </pre>
*
* # The array notation
*
- * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
- * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
- * minification is a better choice:
+ * It is often desirable to inline Injected functions and that's when setting the `$inject` property
+ * is very inconvenient. In these situations using the array notation to specify the dependencies in
+ * a way that survives minification is a better choice:
*
* <pre>
* // We wish to write this (not minification / obfuscation safe)
* injector.invoke(function($compile, $rootScope) {
* // ...
@@ -12670,12 +12898,12 @@
* expect(injector.annotate(
* ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
* ).toEqual(['$compile', '$rootScope']);
* </pre>
*
- * @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
- * above.
+ * @param {function|Array.<string|Function>} fn Function for which dependent service names need to
+ * be retrieved as described above.
*
* @returns {Array.<string>} The names of the services which the function requires.
*/
@@ -12685,76 +12913,82 @@
* @ngdoc object
* @name AUTO.$provide
*
* @description
*
- * The {@link AUTO.$provide $provide} service has a number of methods for registering components with
- * the {@link AUTO.$injector $injector}. Many of these functions are also exposed on {@link angular.Module}.
+ * The {@link AUTO.$provide $provide} service has a number of methods for registering components
+ * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on
+ * {@link angular.Module}.
*
* An Angular **service** is a singleton object created by a **service factory**. These **service
* factories** are functions which, in turn, are created by a **service provider**.
- * The **service providers** are constructor functions. When instantiated they must contain a property
- * called `$get`, which holds the **service factory** function.
- *
+ * The **service providers** are constructor functions. When instantiated they must contain a
+ * property called `$get`, which holds the **service factory** function.
+ *
* When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
* correct **service provider**, instantiating it and then calling its `$get` **service factory**
* function to get the instance of the **service**.
- *
+ *
* Often services have no configuration options and there is no need to add methods to the service
* provider. The provider will be no more than a constructor function with a `$get` property. For
* these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
* services without specifying a provider.
*
- * * {@link AUTO.$provide#provider provider(provider)} - registers a **service provider** with the
+ * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the
* {@link AUTO.$injector $injector}
- * * {@link AUTO.$provide#constant constant(obj)} - registers a value/object that can be accessed by
+ * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by
* providers and services.
- * * {@link AUTO.$provide#value value(obj)} - registers a value/object that can only be accessed by
+ * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by
* services, not providers.
- * * {@link AUTO.$provide#factory factory(fn)} - registers a service **factory function**, `fn`, that
- * will be wrapped in a **service provider** object, whose `$get` property will contain the given
- * factory function.
- * * {@link AUTO.$provide#service service(class)} - registers a **constructor function**, `class` that
- * will be wrapped in a **service provider** object, whose `$get` property will instantiate a new
- * object using the given constructor function.
+ * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`,
+ * that will be wrapped in a **service provider** object, whose `$get` property will contain the
+ * given factory function.
+ * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that
+ * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
+ * a new object using the given constructor function.
*
* See the individual methods for more information and examples.
*/
/**
* @ngdoc method
* @name AUTO.$provide#provider
* @methodOf AUTO.$provide
* @description
*
- * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions are
- * constructor functions, whose instances are responsible for "providing" a factory for a service.
- *
+ * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions
+ * are constructor functions, whose instances are responsible for "providing" a factory for a
+ * service.
+ *
* Service provider names start with the name of the service they provide followed by `Provider`.
- * For example, the {@link ng.$log $log} service has a provider called {@link ng.$logProvider $logProvider}.
+ * For example, the {@link ng.$log $log} service has a provider called
+ * {@link ng.$logProvider $logProvider}.
*
- * Service provider objects can have additional methods which allow configuration of the provider and
- * its service. Importantly, you can configure what kind of service is created by the `$get` method,
- * or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a method
- * {@link ng.$logProvider#debugEnabled debugEnabled}
+ * Service provider objects can have additional methods which allow configuration of the provider
+ * and its service. Importantly, you can configure what kind of service is created by the `$get`
+ * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
+ * method {@link ng.$logProvider#debugEnabled debugEnabled}
* which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
* console or not.
*
- * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
+ * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
+ 'Provider'` key.
* @param {(Object|function())} provider If the provider is:
*
* - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
- * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
+ * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be
+ * created.
* - `Constructor`: a new instance of the provider will be created using
- * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
+ * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
+ * `object`.
*
* @returns {Object} registered provider instance
* @example
*
* The following example shows how to create a simple event tracking service and register it using
- * {@link AUTO.$provide#provider $provide.provider()}.
+ * {@link AUTO.$provide#methods_provider $provide.provider()}.
*
* <pre>
* // Define the eventTracker provider
* function EventTrackerProvider() {
* var trackingUrl = '/track';
@@ -12821,20 +13055,20 @@
* @description
*
* Register a **service factory**, which will be called to return the service instance.
* This is short for registering a service where its provider consists of only a `$get` property,
* which is the given service factory function.
- * You should use {@link AUTO.$provide#factory $provide.factor(getFn)} if you do not need to configure
- * your service in a provider.
+ * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to
+ * configure your service in a provider.
*
* @param {string} name The name of the instance.
- * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
- * `$provide.provider(name, {$get: $getFn})`.
+ * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
+ * for `$provide.provider(name, {$get: $getFn})`.
* @returns {Object} registered provider instance
*
* @example
- * Here is an example of registering a service
+ * Here is an example of registering a service
* <pre>
* $provide.factory('ping', ['$http', function($http) {
* return function ping() {
* return $http.send('/ping');
* };
@@ -12853,30 +13087,31 @@
* @ngdoc method
* @name AUTO.$provide#service
* @methodOf AUTO.$provide
* @description
*
- * Register a **service constructor**, which will be invoked with `new` to create the service instance.
+ * 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.
*
- * You should use {@link AUTO.$provide#service $provide.service(class)} if you define your service
+ * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
* as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}.
*
* @param {string} name The name of the instance.
* @param {Function} constructor A class (constructor function) that will be instantiated.
* @returns {Object} registered provider instance
*
* @example
- * Here is an example of registering a service using {@link AUTO.$provide#service $provide.service(class)}
- * that is defined as a CoffeeScript class.
+ * Here is an example of registering a service using
+ * {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
* <pre>
* class Ping
* constructor: (@$http)->
* send: ()=>
* @$http.get('/ping')
- *
+ *
* $provide.service('ping', ['$http', Ping])
* </pre>
* You would then inject and use this service like this:
* <pre>
* someModule.controller 'Ctrl', ['ping', (ping)->
@@ -12890,29 +13125,31 @@
* @ngdoc method
* @name AUTO.$provide#value
* @methodOf AUTO.$provide
* @description
*
- * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a number,
- * an array, an object or a function. This is short for registering a service where its provider's
- * `$get` property is a factory function that takes no arguments and returns the **value service**.
+ * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a
+ * number, an array, an object or a function. This is short for registering a service where its
+ * provider's `$get` property is a factory function that takes no arguments and returns the **value
+ * service**.
*
- * Value services are similar to constant services, except that they cannot be injected into a module
- * configuration function (see {@link angular.Module#config}) but they can be overridden by an Angular
+ * Value services are similar to constant services, except that they cannot be injected into a
+ * module configuration function (see {@link angular.Module#config}) but they can be overridden by
+ * an Angular
* {@link AUTO.$provide#decorator decorator}.
- *
+ *
* @param {string} name The name of the instance.
* @param {*} value The value.
* @returns {Object} registered provider instance
*
* @example
* Here are some examples of creating value services.
* <pre>
* $provide.constant('ADMIN_USER', 'admin');
- *
+ *
* $provide.constant('RoleLookup', { admin: 0, writer: 1, reader: 2 });
- *
+ *
* $provide.constant('halfOf', function(value) {
* return value / 2;
* });
* </pre>
*/
@@ -12922,26 +13159,26 @@
* @ngdoc method
* @name AUTO.$provide#constant
* @methodOf AUTO.$provide
* @description
*
- * Register a **constant service**, such as a string, a number, an array, an object or a function, with
- * the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be injected
- * into a module configuration function (see {@link angular.Module#config}) and it cannot be
- * overridden by an Angular {@link AUTO.$provide#decorator decorator}.
+ * Register a **constant service**, such as a string, a number, an array, an object or a function,
+ * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be
+ * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
+ * be overridden by an Angular {@link AUTO.$provide#decorator decorator}.
*
* @param {string} name The name of the constant.
* @param {*} value The constant value.
* @returns {Object} registered instance
*
* @example
* Here a some examples of creating constants:
* <pre>
* $provide.constant('SHARD_HEIGHT', 306);
- *
+ *
* $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
- *
+ *
* $provide.constant('double', function(value) {
* return value * 2;
* });
* </pre>
*/
@@ -12953,12 +13190,12 @@
* @methodOf AUTO.$provide
* @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
- * 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.
+ * 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.
*
* @param {string} name The name of the service to decorate.
* @param {function()} decorator This function will be invoked when the service needs to be
* instantiated and should return the decorated service instance. The function is called using
* the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
@@ -13019,11 +13256,11 @@
if (isObject(key)) {
forEach(key, reverseParams(delegate));
} else {
return delegate(key, value);
}
- }
+ };
}
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
@@ -13041,11 +13278,11 @@
return factory(name, ['$injector', function($injector) {
return $injector.instantiate(constructor);
}]);
}
- function value(name, value) { return factory(name, valueFn(value)); }
+ function value(name, val) { return factory(name, valueFn(val)); }
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
@@ -13063,21 +13300,21 @@
////////////////////////////////////
// Module Loading
////////////////////////////////////
function loadModules(modulesToLoad){
- var runBlocks = [];
+ var runBlocks = [], moduleFn, invokeQueue, i, ii;
forEach(modulesToLoad, function(module) {
if (loadedModules.get(module)) return;
loadedModules.put(module, true);
try {
if (isString(module)) {
- var moduleFn = angularModule(module);
+ moduleFn = angularModule(module);
runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
- for(var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
+ for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
var invokeArgs = invokeQueue[i],
provider = providerInjector.get(invokeArgs[0]);
provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
}
@@ -13091,16 +13328,19 @@
} catch (e) {
if (isArray(module)) {
module = module[module.length - 1];
}
if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
- // Safari & FF's stack traces don't contain error.message content unlike those of Chrome and IE
+ // Safari & FF's stack traces don't contain error.message content
+ // unlike those of Chrome and IE
// So if stack doesn't contain message, we create a new string that contains both.
// Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
+ /* jshint -W022 */
e = e.message + '\n' + e.stack;
}
- throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}", module, e.stack || e.message || e);
+ throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
+ module, e.stack || e.message || e);
}
});
return runBlocks;
}
@@ -13134,11 +13374,12 @@
key;
for(i = 0, length = $inject.length; i < length; i++) {
key = $inject[i];
if (typeof key !== 'string') {
- throw $injectorMinErr('itkn', 'Incorrect injection token! Expected service name as string, got {0}', key);
+ throw $injectorMinErr('itkn',
+ 'Incorrect injection token! Expected service name as string, got {0}', key);
}
args.push(
locals && locals.hasOwnProperty(key)
? locals[key]
: getService(key)
@@ -13159,12 +13400,14 @@
case 4: return fn(args[0], args[1], args[2], args[3]);
case 5: return fn(args[0], args[1], args[2], args[3], args[4]);
case 6: return fn(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
- case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
- case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
+ case 9: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
+ args[8]);
+ case 10: return fn(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7],
+ args[8], args[9]);
default: return fn.apply(self, args);
}
}
function instantiate(Type, locals) {
@@ -13175,11 +13418,11 @@
// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
instance = new Constructor();
returnedValue = invoke(Type, instance, locals);
- return isObject(returnedValue) ? returnedValue : instance;
+ return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
}
return {
invoke: invoke,
instantiate: instantiate,
@@ -13190,11 +13433,10 @@
}
};
}
}
-
/**
* @ngdoc function
* @name ng.$anchorScroll
* @requires $window
* @requires $location
@@ -13298,34 +13540,38 @@
/**
* @ngdoc object
* @name ng.$animateProvider
*
* @description
- * Default implementation of $animate that doesn't perform any animations, instead just synchronously performs DOM
+ * Default implementation of $animate that doesn't perform any animations, instead just
+ * synchronously performs DOM
* updates and calls done() callbacks.
*
* In order to enable animations the ngAnimate module has to be loaded.
*
* To see the functional implementation check out src/ngAnimate/animate.js
*/
var $AnimateProvider = ['$provide', function($provide) {
+
this.$$selectors = {};
/**
* @ngdoc function
* @name ng.$animateProvider#register
* @methodOf ng.$animateProvider
*
* @description
- * Registers a new injectable animation factory function. The factory function produces the animation object which
- * contains callback functions for each event that is expected to be animated.
+ * Registers a new injectable animation factory function. The factory function produces the
+ * animation object which contains callback functions for each event that is expected to be
+ * animated.
*
- * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction` must be called once the
- * element animation is complete. If a function is returned then the animation service will use this function to
- * cancel the animation whenever a cancel event is triggered.
+ * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
+ * must be called once the element animation is complete. If a function is returned then the
+ * animation service will use this function to cancel the animation whenever a cancel event is
+ * triggered.
*
*
*<pre>
* return {
* eventFn : function(element, done) {
@@ -13337,11 +13583,12 @@
* }
* }
*</pre>
*
* @param {string} name The name of the animation.
- * @param {function} factory The factory function that will be executed to return the animation object.
+ * @param {function} factory The factory function that will be executed to return the animation
+ * object.
*/
this.register = function(name, factory) {
var key = name + '-animation';
if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
"Expecting class selector starting with '.' got '{0}'.", name);
@@ -13350,40 +13597,43 @@
};
this.$get = ['$timeout', function($timeout) {
/**
+ *
* @ngdoc object
* @name ng.$animate
+ * @description The $animate service provides rudimentary DOM manipulation functions to
+ * insert, remove and move elements within the DOM, as well as adding and removing classes.
+ * This service is the core service used by the ngAnimate $animator service which provides
+ * high-level animation hooks for CSS and JavaScript.
*
- * @description
- * The $animate service provides rudimentary DOM manipulation functions to insert, remove and move elements within
- * the DOM, as well as adding and removing classes. This service is the core service used by the ngAnimate $animator
- * service which provides high-level animation hooks for CSS and JavaScript.
+ * $animate is available in the AngularJS core, however, the ngAnimate module must be included
+ * to enable full out animation support. Otherwise, $animate will only perform simple DOM
+ * manipulation operations.
*
- * $animate is available in the AngularJS core, however, the ngAnimate module must be included to enable full out
- * animation support. Otherwise, $animate will only perform simple DOM manipulation operations.
- *
- * To learn more about enabling animation support, click here to visit the {@link ngAnimate ngAnimate module page}
- * as well as the {@link ngAnimate.$animate ngAnimate $animate service page}.
+ * To learn more about enabling animation support, click here to visit the {@link ngAnimate
+ * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
+ * page}.
*/
return {
/**
+ *
* @ngdoc function
* @name ng.$animate#enter
* @methodOf ng.$animate
* @function
- *
- * @description
- * Inserts the element into the DOM either after the `after` element or within the `parent` element. Once complete,
- * the done() callback will be fired (if provided).
- *
+ * @description Inserts the element into the DOM either after the `after` element or within
+ * the `parent` element. Once complete, the done() callback will be fired (if provided).
* @param {jQuery/jqLite element} element the element which will be inserted into the DOM
- * @param {jQuery/jqLite element} parent the parent element which will append the element as a child (if the after element is not present)
- * @param {jQuery/jqLite element} after the sibling element which will append the element after itself
- * @param {function=} done callback function that will be called after the element has been inserted into the DOM
+ * @param {jQuery/jqLite element} parent the parent element which will append the element as
+ * a child (if the after element is not present)
+ * @param {jQuery/jqLite element} after the sibling element which will append the element
+ * after itself
+ * @param {function=} done callback function that will be called after the element has been
+ * inserted into the DOM
*/
enter : function(element, parent, after, done) {
var afterNode = after && after[after.length - 1];
var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
// IE does not like undefined so we have to pass null.
@@ -13393,89 +13643,95 @@
});
done && $timeout(done, 0, false);
},
/**
+ *
* @ngdoc function
* @name ng.$animate#leave
* @methodOf ng.$animate
* @function
- *
- * @description
- * Removes the element from the DOM. Once complete, the done() callback will be fired (if provided).
- *
+ * @description Removes the element from the DOM. Once complete, the done() callback will be
+ * fired (if provided).
* @param {jQuery/jqLite element} element the element which will be removed from the DOM
- * @param {function=} done callback function that will be called after the element has been removed from the DOM
+ * @param {function=} done callback function that will be called after the element has been
+ * removed from the DOM
*/
leave : function(element, done) {
element.remove();
done && $timeout(done, 0, false);
},
/**
+ *
* @ngdoc function
* @name ng.$animate#move
* @methodOf ng.$animate
* @function
- *
- * @description
- * Moves the position of the provided element within the DOM to be placed either after the `after` element or inside of the `parent` element.
- * Once complete, the done() callback will be fired (if provided).
- *
- * @param {jQuery/jqLite element} element the element which will be moved around within the DOM
- * @param {jQuery/jqLite element} parent the parent element where the element will be inserted into (if the after element is not present)
- * @param {jQuery/jqLite element} after the sibling element where the element will be positioned next to
- * @param {function=} done the callback function (if provided) that will be fired after the element has been moved to its new position
+ * @description Moves the position of the provided element within the DOM to be placed
+ * either after the `after` element or inside of the `parent` element. Once complete, the
+ * done() callback will be fired (if provided).
+ *
+ * @param {jQuery/jqLite element} element the element which will be moved around within the
+ * DOM
+ * @param {jQuery/jqLite element} parent the parent element where the element will be
+ * inserted into (if the after element is not present)
+ * @param {jQuery/jqLite element} after the sibling element where the element will be
+ * positioned next to
+ * @param {function=} done the callback function (if provided) that will be fired after the
+ * element has been moved to its new position
*/
move : function(element, parent, after, done) {
// Do not remove element before insert. Removing will cause data associated with the
// element to be dropped. Insert will implicitly do the remove.
this.enter(element, parent, after, done);
},
/**
+ *
* @ngdoc function
* @name ng.$animate#addClass
* @methodOf ng.$animate
* @function
- *
- * @description
- * Adds the provided className CSS class value to the provided element. Once complete, the done() callback will be fired (if provided).
- *
- * @param {jQuery/jqLite element} element the element which will have the className value added to it
+ * @description Adds the provided className CSS class value to the provided element. Once
+ * complete, the done() callback will be fired (if provided).
+ * @param {jQuery/jqLite element} element the element which will have the className value
+ * added to it
* @param {string} className the CSS class which will be added to the element
- * @param {function=} done the callback function (if provided) that will be fired after the className value has been added to the element
+ * @param {function=} done the callback function (if provided) that will be fired after the
+ * className value has been added to the element
*/
addClass : function(element, className, done) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
forEach(element, function (element) {
- JQLiteAddClass(element, className);
+ jqLiteAddClass(element, className);
});
done && $timeout(done, 0, false);
},
/**
+ *
* @ngdoc function
* @name ng.$animate#removeClass
* @methodOf ng.$animate
* @function
- *
- * @description
- * Removes the provided className CSS class value from the provided element. Once complete, the done() callback will be fired (if provided).
- *
- * @param {jQuery/jqLite element} element the element which will have the className value removed from it
+ * @description Removes the provided className CSS class value from the provided element.
+ * Once complete, the done() callback will be fired (if provided).
+ * @param {jQuery/jqLite element} element the element which will have the className value
+ * removed from it
* @param {string} className the CSS class which will be removed from the element
- * @param {function=} done the callback function (if provided) that will be fired after the className value has been removed from the element
+ * @param {function=} done the callback function (if provided) that will be fired after the
+ * className value has been removed from the element
*/
removeClass : function(element, className, done) {
className = isString(className) ?
className :
isArray(className) ? className.join(' ') : '';
forEach(element, function (element) {
- JQLiteRemoveClass(element, className);
+ jqLiteRemoveClass(element, className);
});
done && $timeout(done, 0, false);
},
enabled : noop
@@ -13755,34 +14011,39 @@
* @description
* The cookies method provides a 'private' low level access to browser cookies.
* It is not meant to be used directly, use the $cookie service instead.
*
* The return values vary depending on the arguments that the method was called with as follows:
- * <ul>
- * <li>cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify it</li>
- * <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
- * <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
- * </ul>
- *
+ *
+ * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
+ * it
+ * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
+ * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
+ * way)
+ *
* @returns {Object} Hash of all cookies (if called without any parameter)
*/
self.cookies = function(name, value) {
+ /* global escape: false, unescape: false */
var cookieLength, cookieArray, cookie, i, index;
if (name) {
if (value === undefined) {
- rawDocument.cookie = escape(name) + "=;path=" + cookiePath + ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
+ ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
} else {
if (isString(value)) {
- cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) + ';path=' + cookiePath).length + 1;
+ cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(value) +
+ ';path=' + cookiePath).length + 1;
// per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
// - 300 cookies
// - 20 cookies per unique domain
// - 4096 bytes per cookie
if (cookieLength > 4096) {
- $log.warn("Cookie '"+ name +"' possibly not set or overflowed because it was too large ("+
+ $log.warn("Cookie '"+ name +
+ "' possibly not set or overflowed because it was too large ("+
cookieLength + " > 4096 bytes)!");
}
}
}
} else {
@@ -13793,11 +14054,11 @@
for (i = 0; i < cookieArray.length; i++) {
cookie = cookieArray[i];
index = cookie.indexOf('=');
if (index > 0) { //ignore nameless cookies
- var name = unescape(cookie.substring(0, index));
+ name = unescape(cookie.substring(0, index));
// the first value that is seen for a cookie is the most
// specific one. values for the same cookie name that
// follow are for less specific paths.
if (lastCookies[name] === undefined) {
lastCookies[name] = unescape(cookie.substring(index + 1));
@@ -13843,11 +14104,12 @@
*
* @description
* Cancels a deferred task identified with `deferId`.
*
* @param {*} deferId Token returned by the `$browser.defer` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully canceled.
+ * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
+ * canceled.
*/
self.defer.cancel = function(deferId) {
if (pendingDeferIds[deferId]) {
delete pendingDeferIds[deferId];
clearTimeout(deferId);
@@ -13879,13 +14141,14 @@
* expect($cacheFactory.get('cacheId')).toBe(cache);
* expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
*
* cache.put("key", "value");
* cache.put("another key", "another value");
+ *
+ * // We've specified no options on creation
+ * expect(cache.info()).toEqual({id: 'cacheId', size: 2});
*
- * expect(cache.info()).toEqual({id: 'cacheId', size: 2}); // Since we've specified no options on creation
- *
* </pre>
*
*
* @param {string} cacheId Name or id of the newly created cache.
* @param {object=} options Options object that specifies the cache behavior. Properties:
@@ -13893,11 +14156,12 @@
* - `{number=}` `capacity` — turns the cache into LRU cache.
*
* @returns {object} Newly created cache object with the following set of methods:
*
* - `{object}` `info()` — Returns id, size, and options of cache.
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns it.
+ * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
+ * it.
* - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
* - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
* - `{void}` `removeAll()` — Removes all cached values.
* - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
*
@@ -14060,13 +14324,13 @@
/**
* @ngdoc object
* @name ng.$templateCache
*
* @description
- * The first time a template is used, it is loaded in the template cache for quick retrieval. You can
- * load templates directly into the cache in a `script` tag, or by consuming the `$templateCache`
- * service directly.
+ * The first time a template is used, it is loaded in the template cache for quick retrieval. You
+ * can load templates directly into the cache in a `script` tag, or by consuming the
+ * `$templateCache` service directly.
*
* Adding via the `script` tag:
* <pre>
* <html ng-app>
* <head>
@@ -14076,12 +14340,12 @@
* </head>
* ...
* </html>
* </pre>
*
- * **Note:** the `script` tag containing the template does not need to be included in the `head` of the document, but
- * it must be below the `ng-app` definition.
+ * **Note:** the `script` tag containing the template does not need to be included in the `head` of
+ * the document, but it must be below the `ng-app` definition.
*
* Adding via the $templateCache service:
*
* <pre>
* var myApp = angular.module('myApp', []);
@@ -14132,25 +14396,359 @@
* @name ng.$compile
* @function
*
* @description
* Compiles a piece of HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
+ * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
*
- * The compilation is a process of walking the DOM tree and trying to match DOM elements to
- * {@link ng.$compileProvider#directive directives}. For each match it
- * executes corresponding template function and collects the
- * instance functions into a single template function which is then returned.
+ * The compilation is a process of walking the DOM tree and matching DOM elements to
+ * {@link ng.$compileProvider#methods_directive directives}.
*
- * The template function can then be used once to produce the view or as it is the case with
- * {@link ng.directive:ngRepeat repeater} many-times, in which
- * case each call results in a view that is a DOM clone of the original template.
+ * <div class="alert alert-warning">
+ * **Note:** This document is an in-depth reference of all directive options.
+ * For a gentle introduction to directives with examples of common use cases,
+ * see the {@link guide/directive directive guide}.
+ * </div>
*
+ * ## Comprehensive Directive API
+ *
+ * There are many different options for a directive.
+ *
+ * The difference resides in the return value of the factory function.
+ * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
+ * or just the `postLink` function (all other properties will have the default values).
+ *
+ * <div class="alert alert-success">
+ * **Best Practice:** It's recommended to use the "directive definition object" form.
+ * </div>
+ *
+ * Here's an example directive declared with a Directive Definition Object:
+ *
+ * <pre>
+ * var myModule = angular.module(...);
+ *
+ * myModule.directive('directiveName', function factory(injectables) {
+ * var directiveDefinitionObject = {
+ * priority: 0,
+ * template: '<div></div>', // or // function(tElement, tAttrs) { ... },
+ * // or
+ * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
+ * replace: false,
+ * transclude: false,
+ * restrict: 'A',
+ * scope: false,
+ * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
+ * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
+ * compile: function compile(tElement, tAttrs, transclude) {
+ * return {
+ * pre: function preLink(scope, iElement, iAttrs, controller) { ... },
+ * post: function postLink(scope, iElement, iAttrs, controller) { ... }
+ * }
+ * // or
+ * // return function postLink( ... ) { ... }
+ * },
+ * // or
+ * // link: {
+ * // pre: function preLink(scope, iElement, iAttrs, controller) { ... },
+ * // post: function postLink(scope, iElement, iAttrs, controller) { ... }
+ * // }
+ * // or
+ * // link: function postLink( ... ) { ... }
+ * };
+ * return directiveDefinitionObject;
+ * });
+ * </pre>
+ *
+ * <div class="alert alert-warning">
+ * **Note:** Any unspecified options will use the default value. You can see the default values below.
+ * </div>
+ *
+ * Therefore the above can be simplified as:
+ *
+ * <pre>
+ * var myModule = angular.module(...);
+ *
+ * myModule.directive('directiveName', function factory(injectables) {
+ * var directiveDefinitionObject = {
+ * link: function postLink(scope, iElement, iAttrs) { ... }
+ * };
+ * return directiveDefinitionObject;
+ * // or
+ * // return function postLink(scope, iElement, iAttrs) { ... }
+ * });
+ * </pre>
+ *
+ *
+ *
+ * ### Directive Definition Object
+ *
+ * The directive definition object provides instructions to the {@link api/ng.$compile
+ * compiler}. The attributes are:
+ *
+ * #### `priority`
+ * When there are multiple directives defined on a single DOM element, sometimes it
+ * is necessary to specify the order in which the directives are applied. The `priority` is used
+ * to sort the directives before their `compile` functions get called. Priority is defined as a
+ * number. Directives with greater numerical `priority` are compiled first. The order of directives with
+ * the same priority is undefined. The default priority is `0`.
+ *
+ * #### `terminal`
+ * If set to true then the current `priority` will be the last set of directives
+ * which will execute (any directives at the current priority will still execute
+ * as the order of execution on same `priority` is undefined).
+ *
+ * #### `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.
+ *
+ * **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.
+ *
+ * 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:
+ *
+ * * `@` 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
+ * 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.
+ *
+ * * `&` 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 and 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})`.
+ *
+ *
+ *
+ * #### `controller`
+ * Controller constructor function. The controller is instantiated before the
+ * pre-linking phase and it is shared with 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:
+ *
+ * * `$scope` - Current scope associated with the element
+ * * `$element` - Current element
+ * * `$attrs` - Current attributes object for the element
+ * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
+ * `function(cloneLinkingFn)`.
+ *
+ *
+ * #### `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. 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.
+ * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
+ * * `?^` - Attempt to locate the required controller by searching the element's parentsor pass `null` to the
+ * `link` fn if not found.
+ *
+ *
+ * #### `controllerAs`
+ * Controller alias at the directive scope. An alias for the controller so it
+ * can be referenced at 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.
+ *
+ *
+ * #### `restrict`
+ * String of subset of `EACM` which restricts the directive to a specific directive
+ * declaration style. If omitted, the default (attributes only) is used.
+ *
+ * * `E` - Element name: `<my-directive></my-directive>`
+ * * `A` - Attribute (default): `<div my-directive="exp"></div>`
+ * * `C` - Class: `<div class="my-directive: exp;"></div>`
+ * * `M` - Comment: `<!-- directive: my-directive exp -->`
+ *
+ *
+ * #### `template`
+ * replace the current element with the contents of the HTML. The replacement process
+ * migrates all of the attributes / classes from the old element to the new one. See the
+ * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
+ * Directives Guide} for an example.
+ *
+ * You can specify `template` as a string representing the template or as a function which takes
+ * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
+ * returns a string value representing the template.
+ *
+ *
+ * #### `templateUrl`
+ * Same as `template` but the template is loaded from the specified URL. Because
+ * the template loading is asynchronous the compilation/linking is suspended until the template
+ * is loaded.
+ *
+ * You can specify `templateUrl` as a string representing the URL or as a function which takes two
+ * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
+ * a string value representing the url. In either case, the template URL is passed through {@link
+ * api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}.
+ *
+ *
+ * #### `replace`
+ * specify where the template should be inserted. Defaults to `false`.
+ *
+ * * `true` - the template will replace the current element.
+ * * `false` - the template will replace the contents of the current element.
+ *
+ *
+ * #### `transclude`
+ * compile the content of the element and make it available to the directive.
+ * Typically used with {@link api/ng.directive:ngTransclude
+ * ngTransclude}. The advantage of transclusion is that the linking function receives a
+ * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
+ * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
+ * scope. This makes it possible for the widget to have private state, and the transclusion to
+ * be bound to the parent (pre-`isolate`) scope.
+ *
+ * * `true` - transclude the content of the directive.
+ * * `'element'` - transclude the whole element including any directives defined at lower priority.
+ *
+ *
+ * #### `compile`
+ *
+ * <pre>
+ * function compile(tElement, tAttrs, transclude) { ... }
+ * </pre>
+ *
+ * The compile function deals with transforming the template DOM. Since most directives do not do
+ * template transformation, it is not used often. Examples that require compile functions are
+ * directives that transform template DOM, such as {@link
+ * api/ng.directive:ngRepeat ngRepeat}, or load the contents
+ * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The
+ * compile function takes the following arguments.
+ *
+ * * `tElement` - template element - The element where the directive has been declared. It is
+ * safe to do template transformation on the element and child elements only.
+ *
+ * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
+ * between all directive compile functions.
+ *
+ * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
+ *
+ * <div class="alert alert-warning">
+ * **Note:** The template instance and the link instance may be different objects if the template has
+ * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
+ * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
+ * should be done in a linking function rather than in a compile function.
+ * </div>
+ *
+ * A compile function can have a return value which can be either a function or an object.
+ *
+ * * returning a (post-link) function - is equivalent to registering the linking function via the
+ * `link` property of the config object when the compile function is empty.
+ *
+ * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
+ * control when a linking function should be called during the linking phase. See info about
+ * pre-linking and post-linking functions below.
+ *
+ *
+ * #### `link`
+ * This property is used only if the `compile` property is not defined.
+ *
+ * <pre>
+ * function link(scope, iElement, iAttrs, controller) { ... }
+ * </pre>
+ *
+ * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
+ * executed after the template has been cloned. This is where most of the directive logic will be
+ * put.
+ *
+ * * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
+ * directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}.
+ *
+ * * `iElement` - instance element - The element where the directive is to be used. It is safe to
+ * manipulate the children of the element only in `postLink` function since the children have
+ * already been linked.
+ *
+ * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
+ * between all directive linking functions.
+ *
+ * * `controller` - a controller instance - A controller instance if at least one directive on the
+ * element defines a controller. The controller is shared among all the directives, which allows
+ * the directives to use the controllers as a communication channel.
+ *
+ *
+ *
+ * #### Pre-linking function
+ *
+ * Executed before the child elements are linked. Not safe to do DOM transformation since the
+ * compiler linking function will fail to locate the correct elements for linking.
+ *
+ * #### Post-linking function
+ *
+ * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
+ *
+ * <a name="Attributes"></a>
+ * ### Attributes
+ *
+ * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
+ * `link()` or `compile()` functions. It has a variety of uses.
+ *
+ * accessing *Normalized attribute names:*
+ * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
+ * the attributes object allows for normalized access to
+ * the attributes.
+ *
+ * * *Directive inter-communication:* All directives share the same instance of the attributes
+ * object which allows the directives to use the attributes object as inter directive
+ * communication.
+ *
+ * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
+ * allowing other directives to read the interpolated value.
+ *
+ * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
+ * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
+ * the only way to easily get the actual value because during the linking phase the interpolation
+ * hasn't been evaluated yet and so the value is at this time set to `undefined`.
+ *
+ * <pre>
+ * function linkingFn(scope, elm, attrs, ctrl) {
+ * // get the attribute value
+ * console.log(attrs.ngModel);
+ *
+ * // change the attribute
+ * attrs.$set('ngModel', 'new value');
+ *
+ * // observe changes to interpolated attribute
+ * attrs.$observe('ngModel', function(value) {
+ * console.log('ngModel has changed value to ' + value);
+ * });
+ * }
+ * </pre>
+ *
+ * Below is an example using `$compileProvider`.
+ *
+ * <div class="alert alert-warning">
+ * **Note**: Typically directives are registered with `module.directive`. The example below is
+ * to illustrate how `$compile` works.
+ * </div>
+ *
<doc:example module="compile">
<doc:source>
<script>
- // declare a new module, and inject the $compileProvider
angular.module('compile', [], function($compileProvider) {
// configure new 'compile' directive by passing a directive
// factory function. The factory function injects the '$compile'
$compileProvider.directive('compile', function($compile) {
// directive factory creates a link function
@@ -14204,20 +14802,20 @@
* root element(s), not their children)
* @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
* (a DOM element/tree) to a scope. Where:
*
* * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
- * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the `template`
- * and call the `cloneAttachFn` function allowing the caller to attach the
+ * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
+ * `template` and call the `cloneAttachFn` function allowing the caller to attach the
* cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
* called as: <br> `cloneAttachFn(clonedElement, scope)` where:
*
* * `clonedElement` - is a clone of the original `element` passed into the compiler.
* * `scope` - is the current scope with which the linking function is working with.
*
- * Calling the linking function returns the element of the template. It is either the original element
- * passed in, or the clone of the element if the `cloneAttachFn` is provided.
+ * Calling the linking function returns the element of the template. It is either the original
+ * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
*
* After linking the view is not updated until after a call to $digest which typically is done by
* Angular automatically.
*
* If you need access to the bound view, there are two ways to do it:
@@ -14364,14 +14962,14 @@
* Retrieves or overrides the default regular expression that is used for whitelisting of safe
* urls during img[src] sanitization.
*
* The sanitization is a security measure aimed at prevent XSS attacks via html links.
*
- * Any url about to be assigned to img[src] via data-binding is first normalized and turned into an
- * absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist` regular
- * expression. If a match is found, the original url is written into the dom. Otherwise, the
- * absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
+ * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
+ * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
+ * regular expression. If a match is found, the original url is written into the dom. Otherwise,
+ * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
*
* @param {RegExp=} regexp New regexp to whitelist urls with.
* @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
* chaining otherwise.
*/
@@ -14422,12 +15020,12 @@
* @name ng.$compile.directive.Attributes#$removeClass
* @methodOf ng.$compile.directive.Attributes
* @function
*
* @description
- * Removes the CSS class value specified by the classVal parameter from the element. If animations
- * are enabled then an animation will be triggered for the class removal.
+ * Removes the CSS class value specified by the classVal parameter from the element. If
+ * animations are enabled then an animation will be triggered for the class removal.
*
* @param {string} classVal The className value that will be removed from the element
*/
$removeClass : function(classVal) {
if(classVal && classVal.length > 0) {
@@ -14523,11 +15121,11 @@
if(token == tokens2[j]) continue outer;
}
values.push(token);
}
return values;
- };
+ }
},
/**
* @ngdoc function
@@ -14576,23 +15174,27 @@
return compile;
//================================
- function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
+ function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
+ previousCompileContext) {
if (!($compileNodes instanceof jqLite)) {
- // jquery always rewraps, whereas we need to preserve the original selector so that we can modify it.
+ // jquery always rewraps, whereas we need to preserve the original selector so that we can
+ // modify it.
$compileNodes = jqLite($compileNodes);
}
// We can not compile top level text elements since text nodes can be merged and we will
// not be able to attach scope data to them, so we will wrap them in <span>
forEach($compileNodes, function(node, index){
if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
$compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
}
});
- var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority, ignoreDirective, previousCompileContext);
+ var compositeLinkFn =
+ compileNodes($compileNodes, transcludeFn, $compileNodes,
+ maxPriority, ignoreDirective, previousCompileContext);
return function publicLinkFn(scope, cloneConnectFn){
assertArg(scope, 'scope');
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
var $linkNode = cloneConnectFn
@@ -14629,46 +15231,52 @@
* function, which is the a linking function for the node.
*
* @param {NodeList} nodeList an array of nodes or NodeList to compile
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
* scope argument is auto-generated to the new child of the transcluded parent scope.
- * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then the
- * rootElement must be set the jqLite collection of the compile root. This is
+ * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
+ * the rootElement must be set the jqLite collection of the compile root. This is
* needed so that the jqLite collection items can be replaced with widgets.
* @param {number=} max directive priority
* @returns {?function} A composite linking function of all of the matched directives or null.
*/
- function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, previousCompileContext) {
+ function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
+ previousCompileContext) {
var linkFns = [],
nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
for(var i = 0; i < nodeList.length; i++) {
attrs = new Attributes();
// we must always refer to nodeList[i] since the nodes can be replaced underneath us.
- directives = collectDirectives(nodeList[i], [], attrs, i == 0 ? maxPriority : undefined, ignoreDirective);
+ directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
+ ignoreDirective);
nodeLinkFn = (directives.length)
- ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement, null, [], [], previousCompileContext)
+ ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
+ null, [], [], previousCompileContext)
: null;
- childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !nodeList[i].childNodes || !nodeList[i].childNodes.length)
+ childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
+ !nodeList[i].childNodes ||
+ !nodeList[i].childNodes.length)
? null
: compileNodes(nodeList[i].childNodes,
nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
linkFns.push(nodeLinkFn);
linkFns.push(childLinkFn);
linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
- previousCompileContext = null; //use the previous context only for the first element in the virtual group
+ //use the previous context only for the first element in the virtual group
+ previousCompileContext = null;
}
// return a linking function if we have found anything, null otherwise
return linkFnFound ? compositeLinkFn : null;
function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
- var nodeLinkFn, childLinkFn, node, childScope, childTranscludeFn, i, ii, n;
+ var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
// copy nodeList so that linking doesn't break due to live list updates.
var stableNodeList = [];
for (i = 0, ii = nodeList.length; i < ii; i++) {
stableNodeList.push(nodeList[i]);
@@ -14676,15 +15284,17 @@
for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
node = stableNodeList[n];
nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++];
+ $node = jqLite(node);
if (nodeLinkFn) {
if (nodeLinkFn.scope) {
- childScope = scope.$new(isObject(nodeLinkFn.scope));
- jqLite(node).data('$scope', childScope);
+ childScope = scope.$new();
+ $node.data('$scope', childScope);
+ safeAddClass($node, 'ng-scope');
} else {
childScope = scope;
}
childTranscludeFn = nodeLinkFn.transclude;
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
@@ -14761,11 +15371,12 @@
: attr.value);
if (getBooleanAttrName(node, nName)) {
attrs[nName] = true; // presence means true
}
addAttrInterpolateDirective(node, directives, value, nName);
- addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName, attrEndName);
+ addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
+ attrEndName);
}
}
// use class as directive
className = node.className;
@@ -14790,22 +15401,24 @@
if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
attrs[nName] = trim(match[2]);
}
}
} catch (e) {
- // turns out that under some circumstances IE9 throws errors when one attempts to read comment's node value.
+ // turns out that under some circumstances IE9 throws errors when one attempts to read
+ // comment's node value.
// Just ignore it and continue. (Can't seem to reproduce in test case.)
}
break;
}
directives.sort(byPriority);
return directives;
}
/**
- * Given a node with an directive-start it collects all of the siblings until it find directive-end.
+ * Given a node with an directive-start it collects all of the siblings until it finds
+ * directive-end.
* @param node
* @param attrStart
* @param attrEnd
* @returns {*}
*/
@@ -14814,11 +15427,13 @@
var depth = 0;
if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
var startNode = node;
do {
if (!node) {
- throw $compileMinErr('uterdir', "Unterminated attribute, found '{0}' but no matching '{1}' found.", attrStart, attrEnd);
+ throw $compileMinErr('uterdir',
+ "Unterminated attribute, found '{0}' but no matching '{1}' found.",
+ attrStart, attrEnd);
}
if (node.nodeType == 1 /** Element **/) {
if (node.hasAttribute(attrStart)) depth++;
if (node.hasAttribute(attrEnd)) depth--;
}
@@ -14842,11 +15457,11 @@
*/
function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
return function(scope, element, attrs, controllers) {
element = groupScan(element[0], attrStart, attrEnd);
return linkFn(scope, element, attrs, controllers);
- }
+ };
}
/**
* Once the directives have been collected, their compile functions are executed. This method
* is responsible for inlining directive templates as well as terminating the application
@@ -14855,36 +15470,40 @@
* @param {Array} directives Array of collected directives to execute their compile function.
* this needs to be pre-sorted by priority order.
* @param {Node} compileNode The raw DOM node to apply the compile functions to
* @param {Object} templateAttrs The shared attribute function
* @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
- * scope argument is auto-generated to the new child of the transcluded parent scope.
+ * scope argument is auto-generated to the new
+ * child of the transcluded parent scope.
* @param {JQLite} jqCollection If we are working on the root of the compile tree then this
- * argument has the root jqLite array so that we can replace nodes on it.
- * @param {Object=} originalReplaceDirective An optional directive that will be ignored when compiling
- * the transclusion.
+ * argument has the root jqLite array so that we can replace nodes
+ * on it.
+ * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
+ * compiling the transclusion.
* @param {Array.<Function>} preLinkFns
* @param {Array.<Function>} postLinkFns
- * @param {Object} previousCompileContext Context used for previous compilation of the current node
+ * @param {Object} previousCompileContext Context used for previous compilation of the current
+ * node
* @returns linkFn
*/
- function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection,
- originalReplaceDirective, preLinkFns, postLinkFns, previousCompileContext) {
+ function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
+ jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
+ previousCompileContext) {
previousCompileContext = previousCompileContext || {};
var terminalPriority = -Number.MAX_VALUE,
newScopeDirective,
+ controllerDirectives = previousCompileContext.controllerDirectives,
newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
templateDirective = previousCompileContext.templateDirective,
+ transcludeDirective = previousCompileContext.transcludeDirective,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
directiveName,
$template,
- transcludeDirective = previousCompileContext.transcludeDirective,
replaceDirective = originalReplaceDirective,
childTranscludeFn = transcludeFn,
- controllerDirectives,
linkFn,
directiveValue;
// executes all directives on the current element
for(var i = 0, ii = directives.length; i < ii; i++) {
@@ -14892,30 +15511,29 @@
var attrStart = directive.$$start;
var attrEnd = directive.$$end;
// collect multiblock sections
if (attrStart) {
- $compileNode = groupScan(compileNode, attrStart, attrEnd)
+ $compileNode = groupScan(compileNode, attrStart, attrEnd);
}
$template = undefined;
if (terminalPriority > directive.priority) {
break; // prevent further processing of directives
}
if (directiveValue = directive.scope) {
newScopeDirective = newScopeDirective || directive;
- // skip the check for directives with async templates, we'll check the derived sync directive when
- // the template arrives
+ // skip the check for directives with async templates, we'll check the derived sync
+ // directive when the template arrives
if (!directive.templateUrl) {
- assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive, $compileNode);
+ assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
+ $compileNode);
if (isObject(directiveValue)) {
- safeAddClass($compileNode, 'ng-isolate-scope');
newIsolateScopeDirective = directive;
}
- safeAddClass($compileNode, 'ng-scope');
}
}
directiveName = directive.name;
@@ -14926,33 +15544,40 @@
controllerDirectives[directiveName], directive, $compileNode);
controllerDirectives[directiveName] = directive;
}
if (directiveValue = directive.transclude) {
- // Special case ngRepeat so that we don't complain about duplicate transclusion, ngRepeat knows how to handle
- // this on its own.
- if (directiveName !== 'ngRepeat') {
+ // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
+ // This option should only be used by directives that know how to how to safely handle element transclusion,
+ // where the transcluded nodes are added or replaced after linking.
+ if (!directive.$$tlb) {
assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
transcludeDirective = directive;
}
if (directiveValue == 'element') {
terminalPriority = directive.priority;
$template = groupScan(compileNode, attrStart, attrEnd);
$compileNode = templateAttrs.$$element =
- jqLite(document.createComment(' ' + directiveName + ': ' + templateAttrs[directiveName] + ' '));
+ jqLite(document.createComment(' ' + directiveName + ': ' +
+ templateAttrs[directiveName] + ' '));
compileNode = $compileNode[0];
replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
childTranscludeFn = compile($template, transcludeFn, terminalPriority,
replaceDirective && replaceDirective.name, {
- newIsolateScopeDirective: newIsolateScopeDirective,
- transcludeDirective: transcludeDirective,
- templateDirective: templateDirective
+ // Don't pass in:
+ // - controllerDirectives - otherwise we'll create duplicates controllers
+ // - newIsolateScopeDirective or templateDirective - combining templates with
+ // element transclusion doesn't make sense.
+ //
+ // We need only transcludeDirective so that we prevent putting transclusion
+ // on the same element more than once.
+ transcludeDirective: transcludeDirective
});
} else {
- $template = jqLite(JQLiteClone(compileNode)).contents();
+ $template = jqLite(jqLiteClone(compileNode)).contents();
$compileNode.html(''); // clear contents
childTranscludeFn = compile($template, transcludeFn);
}
}
@@ -14972,29 +15597,31 @@
trim(directiveValue) +
'</div>').contents();
compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}", directiveName, '');
+ throw $compileMinErr('tplrt',
+ "Template for directive '{0}' must have exactly one root element. {1}",
+ directiveName, '');
}
replaceWith(jqCollection, $compileNode, compileNode);
var newTemplateAttrs = {$attr: {}};
// combine directives from the original node and from the template:
// - take the array of directives for this element
- // - split it into two parts, those that were already applied and those that weren't
- // - collect directives from the template, add them to the second group and sort them
- // - append the second group with new directives to the first group
- directives = directives.concat(
- collectDirectives(
- compileNode,
- directives.splice(i + 1, directives.length - (i + 1)),
- newTemplateAttrs
- )
- );
+ // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
+ // - collect directives from the template and sort them by priority
+ // - combine directives as: processed + template + unprocessed
+ var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
+ var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
+
+ if (newIsolateScopeDirective) {
+ markDirectivesAsIsolate(templateDirectives);
+ }
+ directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
ii = directives.length;
} else {
$compileNode.html(directiveValue);
@@ -15009,13 +15636,14 @@
replaceDirective = directive;
}
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
+ controllerDirectives: controllerDirectives,
newIsolateScopeDirective: newIsolateScopeDirective,
- transcludeDirective: transcludeDirective,
- templateDirective: templateDirective
+ templateDirective: templateDirective,
+ transcludeDirective: transcludeDirective
});
ii = directives.length;
} else if (directive.compile) {
try {
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
@@ -15034,11 +15662,11 @@
terminalPriority = Math.max(terminalPriority, directive.priority);
}
}
- nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope;
+ nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
// might be normal or delayed nodeLinkFn depending on if templateUrl is present
return nodeLinkFn;
@@ -15046,15 +15674,21 @@
function addLinkFns(pre, post, attrStart, attrEnd) {
if (pre) {
if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
pre.require = directive.require;
+ if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
+ pre = cloneAndAnnotateFn(pre, {isolateScope: true});
+ }
preLinkFns.push(pre);
}
if (post) {
if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
post.require = directive.require;
+ if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
+ post = cloneAndAnnotateFn(post, {isolateScope: true});
+ }
postLinkFns.push(post);
}
}
@@ -15075,11 +15709,13 @@
value = value || $element[0].$$controller;
$element[0].$$controller = null;
}
if (!value && !optional) {
- throw $compileMinErr('ctreq', "Controller '{0}', required by directive '{1}', can't be found!", require, directiveName);
+ throw $compileMinErr('ctreq',
+ "Controller '{0}', required by directive '{1}', can't be found!",
+ require, directiveName);
}
return value;
} else if (isArray(require)) {
value = [];
forEach(require, function(require) {
@@ -15089,98 +15725,109 @@
return value;
}
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller;
+ var attrs, $element, i, ii, linkFn, controller, isolateScope;
if (compileNode === linkNode) {
attrs = templateAttrs;
} else {
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
}
$element = attrs.$$element;
if (newIsolateScopeDirective) {
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
+ var $linkNode = jqLite(linkNode);
- var parentScope = scope.$parent || scope;
+ isolateScope = scope.$new(true);
+ if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
+ $linkNode.data('$isolateScope', isolateScope) ;
+ } else {
+ $linkNode.data('$isolateScopeNoTemplate', isolateScope);
+ }
+
+
+
+ safeAddClass($linkNode, 'ng-isolate-scope');
+
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
var match = definition.match(LOCAL_REGEXP) || [],
attrName = match[3] || scopeName,
optional = (match[2] == '?'),
mode = match[1], // @, =, or &
lastValue,
parentGet, parentSet;
- scope.$$isolateBindings[scopeName] = mode + attrName;
+ isolateScope.$$isolateBindings[scopeName] = mode + attrName;
switch (mode) {
- case '@': {
+ case '@':
attrs.$observe(attrName, function(value) {
- scope[scopeName] = value;
+ isolateScope[scopeName] = value;
});
- attrs.$$observers[attrName].$$scope = parentScope;
+ attrs.$$observers[attrName].$$scope = scope;
if( attrs[attrName] ) {
- // If the attribute has been provided then we trigger an interpolation to ensure the value is there for use in the link fn
- scope[scopeName] = $interpolate(attrs[attrName])(parentScope);
+ // If the attribute has been provided then we trigger an interpolation to ensure
+ // the value is there for use in the link fn
+ isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
}
break;
- }
- case '=': {
+ case '=':
if (optional && !attrs[attrName]) {
return;
}
parentGet = $parse(attrs[attrName]);
parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest
- lastValue = scope[scopeName] = parentGet(parentScope);
- throw $compileMinErr('nonassign', "Expression '{0}' used with directive '{1}' is non-assignable!",
+ lastValue = isolateScope[scopeName] = parentGet(scope);
+ throw $compileMinErr('nonassign',
+ "Expression '{0}' used with directive '{1}' is non-assignable!",
attrs[attrName], newIsolateScopeDirective.name);
};
- lastValue = scope[scopeName] = parentGet(parentScope);
- scope.$watch(function parentValueWatch() {
- var parentValue = parentGet(parentScope);
+ lastValue = isolateScope[scopeName] = parentGet(scope);
+ isolateScope.$watch(function parentValueWatch() {
+ var parentValue = parentGet(scope);
- if (parentValue !== scope[scopeName]) {
+ if (parentValue !== isolateScope[scopeName]) {
// we are out of sync and need to copy
if (parentValue !== lastValue) {
// parent changed and it has precedence
- lastValue = scope[scopeName] = parentValue;
+ lastValue = isolateScope[scopeName] = parentValue;
} else {
// if the parent can be assigned then do so
- parentSet(parentScope, parentValue = lastValue = scope[scopeName]);
+ parentSet(scope, parentValue = lastValue = isolateScope[scopeName]);
}
}
return parentValue;
});
break;
- }
- case '&': {
+ case '&':
parentGet = $parse(attrs[attrName]);
- scope[scopeName] = function(locals) {
- return parentGet(parentScope, locals);
+ isolateScope[scopeName] = function(locals) {
+ return parentGet(scope, locals);
};
break;
- }
- default: {
- throw $compileMinErr('iscp', "Invalid isolate scope definition for directive '{0}'. Definition: {... {1}: '{2}' ...}",
+ default:
+ throw $compileMinErr('iscp',
+ "Invalid isolate scope definition for directive '{0}'." +
+ " Definition: {... {1}: '{2}' ...}",
newIsolateScopeDirective.name, scopeName, definition);
- }
}
});
}
if (controllerDirectives) {
forEach(controllerDirectives, function(directive) {
var locals = {
- $scope: scope,
+ $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
$transclude: boundTranscludeFn
}, controllerInstance;
@@ -15208,33 +15855,45 @@
// PRELINKING
for(i = 0, ii = preLinkFns.length; i < ii; i++) {
try {
linkFn = preLinkFns[i];
- linkFn(scope, $element, attrs,
+ linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.require, $element));
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
// RECURSION
- childLinkFn && childLinkFn(scope, linkNode.childNodes, undefined, boundTranscludeFn);
+ // We only pass the isolate scope, if the isolate directive has a template,
+ // otherwise the child elements do not belong to the isolate directive.
+ var scopeToChild = scope;
+ if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
+ scopeToChild = isolateScope;
+ }
+ childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
// POSTLINKING
for(i = postLinkFns.length - 1; i >= 0; i--) {
try {
linkFn = postLinkFns[i];
- linkFn(scope, $element, attrs,
+ linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
linkFn.require && getControllers(linkFn.require, $element));
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
}
}
+ function markDirectivesAsIsolate(directives) {
+ // mark all directives as needing isolate scope.
+ for (var j = 0, jj = directives.length; j < jj; j++) {
+ directives[j] = inherit(directives[j], {$$isolateScope: true});
+ }
+ }
/**
* looks up the directive and decorates it with exception handling and proper parameters. We
* call this the boundDirective.
*
@@ -15246,11 +15905,12 @@
* * `A': attribute
* * `C`: class
* * `M`: comment
* @returns true if directive was added.
*/
- function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName) {
+ function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
+ endAttrName) {
if (name === ignoreDirective) return null;
var match = null;
if (hasDirectives.hasOwnProperty(name)) {
for(var directive, directives = $injector.get(name + Suffix),
i = 0, ii = directives.length; i<ii; i++) {
@@ -15319,11 +15979,11 @@
afterTemplateChildLinkFn,
beforeTemplateCompileNode = $compileNode[0],
origAsyncDirective = directives.shift(),
// The fact that we have to copy and patch the directive seems wrong!
derivedSyncDirective = extend({}, origAsyncDirective, {
- templateUrl: null, transclude: null, replace: null
+ templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
}),
templateUrl = (isFunction(origAsyncDirective.templateUrl))
? origAsyncDirective.templateUrl($compileNode, tAttrs)
: origAsyncDirective.templateUrl;
@@ -15338,27 +15998,34 @@
if (origAsyncDirective.replace) {
$template = jqLite('<div>' + trim(content) + '</div>').contents();
compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw $compileMinErr('tplrt', "Template for directive '{0}' must have exactly one root element. {1}",
+ throw $compileMinErr('tplrt',
+ "Template for directive '{0}' must have exactly one root element. {1}",
origAsyncDirective.name, templateUrl);
}
tempTemplateAttrs = {$attr: {}};
replaceWith($rootElement, $compileNode, compileNode);
- collectDirectives(compileNode, directives, tempTemplateAttrs);
+ var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
+
+ if (isObject(origAsyncDirective.scope)) {
+ markDirectivesAsIsolate(templateDirectives);
+ }
+ directives = templateDirectives.concat(directives);
mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
} else {
compileNode = beforeTemplateCompileNode;
$compileNode.html(content);
}
directives.unshift(derivedSyncDirective);
afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
- childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns, previousCompileContext);
+ childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
+ previousCompileContext);
forEach($rootElement, function(node, i) {
if (node == compileNode) {
$rootElement[i] = $compileNode[0];
}
});
@@ -15372,15 +16039,16 @@
controller = linkQueue.shift(),
linkNode = $compileNode[0];
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
// it was cloned therefore we have to clone as well.
- linkNode = JQLiteClone(compileNode);
+ linkNode = jqLiteClone(compileNode);
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
}
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, controller);
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
+ controller);
}
linkQueue = null;
}).
error(function(response, code, headers, config) {
throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
@@ -15453,53 +16121,59 @@
// no interpolation found -> ignore
if (!interpolateFn) return;
if (name === "multiple" && nodeName_(node) === "SELECT") {
- throw $compileMinErr("selmulti", "Binding to the 'multiple' attribute is not supported. Element: {0}",
+ throw $compileMinErr("selmulti",
+ "Binding to the 'multiple' attribute is not supported. Element: {0}",
startingTag(node));
}
directives.push({
- priority: -100,
- compile: valueFn(function attrInterpolateLinkFn(scope, element, attr) {
- var $$observers = (attr.$$observers || (attr.$$observers = {}));
+ priority: 100,
+ compile: function() {
+ return {
+ pre: function attrInterpolatePreLinkFn(scope, element, attr) {
+ var $$observers = (attr.$$observers || (attr.$$observers = {}));
- if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
- throw $compileMinErr('nodomevents',
- "Interpolations for HTML DOM event attributes are disallowed. Please use the ng- " +
- "versions (such as ng-click instead of onclick) instead.");
- }
+ if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
+ throw $compileMinErr('nodomevents',
+ "Interpolations for HTML DOM event attributes are disallowed. Please use the " +
+ "ng- versions (such as ng-click instead of onclick) instead.");
+ }
- // we need to interpolate again, in case the attribute value has been updated
- // (e.g. by another directive's compile function)
- interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
+ // we need to interpolate again, in case the attribute value has been updated
+ // (e.g. by another directive's compile function)
+ interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
- // if attribute was updated so that there is no interpolation going on we don't want to
- // register any observers
- if (!interpolateFn) return;
+ // if attribute was updated so that there is no interpolation going on we don't want to
+ // register any observers
+ if (!interpolateFn) return;
- // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the actual attr value
- attr[name] = interpolateFn(scope);
- ($$observers[name] || ($$observers[name] = [])).$$inter = true;
- (attr.$$observers && attr.$$observers[name].$$scope || scope).
- $watch(interpolateFn, function interpolateFnWatchAction(value) {
- attr.$set(name, value);
- });
- })
+ // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
+ // actual attr value
+ attr[name] = interpolateFn(scope);
+ ($$observers[name] || ($$observers[name] = [])).$$inter = true;
+ (attr.$$observers && attr.$$observers[name].$$scope || scope).
+ $watch(interpolateFn, function interpolateFnWatchAction(value) {
+ attr.$set(name, value);
+ });
+ }
+ };
+ }
});
}
/**
* This is a special jqLite.replaceWith, which can replace items which
* have no parents, provided that the containing jqLite collection is provided.
*
* @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
- * in the root of the tree.
- * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep the shell,
- * but replace its DOM node reference.
+ * in the root of the tree.
+ * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
+ * the shell, but replace its DOM node reference.
* @param {Node} newNode The new DOM node.
*/
function replaceWith($rootElement, elementsToRemove, newNode) {
var firstElementToRemove = elementsToRemove[0],
removeCount = elementsToRemove.length,
@@ -15537,12 +16211,17 @@
fragment.appendChild(element);
delete elementsToRemove[k];
}
elementsToRemove[0] = newNode;
- elementsToRemove.length = 1
+ elementsToRemove.length = 1;
}
+
+
+ function cloneAndAnnotateFn(fn, annotation) {
+ return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
+ }
}];
}
var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
/**
@@ -15561,25 +16240,25 @@
}
/**
* @ngdoc object
* @name ng.$compile.directive.Attributes
+ *
* @description
+ * A shared object between directive compile / linking functions which contains normalized DOM
+ * element attributes. The values reflect current binding state `{{ }}`. The normalization is
+ * needed since all of these are treated as equivalent in Angular:
*
- * A shared object between directive compile / linking functions which contains normalized DOM element
- * attributes. The the values reflect current binding state `{{ }}`. The normalization is needed
- * since all of these are treated as equivalent in Angular:
- *
- * <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
+ * <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
*/
/**
* @ngdoc property
* @name ng.$compile.directive.Attributes#$attr
* @propertyOf ng.$compile.directive.Attributes
* @returns {object} A map of DOM element attribute names to the normalized name. This is
- * needed to do reverse lookup from normalized name back to actual name.
+ * needed to do reverse lookup from normalized name back to actual name.
*/
/**
* @ngdoc function
@@ -15624,11 +16303,11 @@
* @description
* The {@link ng.$controller $controller service} is used by Angular to create new
* controllers.
*
* This provider allows controller registration via the
- * {@link ng.$controllerProvider#register register} method.
+ * {@link ng.$controllerProvider#methods_register register} method.
*/
function $ControllerProvider() {
var controllers = {},
CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
@@ -15643,11 +16322,11 @@
* annotations in the array notation).
*/
this.register = function(name, constructor) {
assertNotHasOwnProperty(name, 'controller');
if (isObject(name)) {
- extend(controllers, name)
+ extend(controllers, name);
} else {
controllers[name] = constructor;
}
};
@@ -15693,11 +16372,13 @@
instance = $injector.instantiate(expression, locals);
if (identifier) {
if (!(locals && typeof locals.$scope == 'object')) {
- throw minErr('$controller')('noscp', "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.", constructor || expression.name, identifier);
+ throw minErr('$controller')('noscp',
+ "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
+ constructor || expression.name, identifier);
}
locals.$scope[identifier] = instance;
}
@@ -15983,27 +16664,28 @@
* will result in the success callback being called. Note that if the response is a redirect,
* XMLHttpRequest will transparently follow it, meaning that the error callback will not be
* called for such responses.
*
* # Calling $http from outside AngularJS
- * The `$http` service will not actually send the request until the next `$digest()` is executed.
- * Normally this is not an issue, since almost all the time your call to `$http` will be from within
- * a `$apply()` block.
- * If you are calling `$http` from outside Angular, then you should wrap it in a call to `$apply`
- * to cause a $digest to occur and also to handle errors in the block correctly.
+ * The `$http` service will not actually send the request until the next `$digest()` is
+ * executed. Normally this is not an issue, since almost all the time your call to `$http` will
+ * be from within a `$apply()` block.
+ * If you are calling `$http` from outside Angular, then you should wrap it in a call to
+ * `$apply` to cause a $digest to occur and also to handle errors in the block correctly.
*
* ```
* $scope.$apply(function() {
* $http(...);
* });
* ```
*
* # Writing Unit Tests that use $http
- * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do not
- * trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have been
- * made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the code
- * that calls the `$http()` method inside a $apply block as explained in the previous section.
+ * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do
+ * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have
+ * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the
+ * code that calls the `$http()` method inside a $apply block as explained in the previous
+ * section.
*
* ```
* $httpBackend.expectGET(...);
* $scope.$apply(function() {
* $http.get(...);
@@ -16022,16 +16704,16 @@
* $http.post('/someUrl', data).success(successCallback);
* </pre>
*
* Complete list of shortcut methods:
*
- * - {@link ng.$http#get $http.get}
- * - {@link ng.$http#head $http.head}
- * - {@link ng.$http#post $http.post}
- * - {@link ng.$http#put $http.put}
- * - {@link ng.$http#delete $http.delete}
- * - {@link ng.$http#jsonp $http.jsonp}
+ * - {@link ng.$http#methods_get $http.get}
+ * - {@link ng.$http#methods_head $http.head}
+ * - {@link ng.$http#methods_post $http.post}
+ * - {@link ng.$http#methods_put $http.put}
+ * - {@link ng.$http#methods_delete $http.delete}
+ * - {@link ng.$http#methods_jsonp $http.jsonp}
*
*
* # Setting HTTP Headers
*
* The $http service will automatically add certain HTTP headers to all requests. These defaults
@@ -16048,37 +16730,40 @@
* To add or overwrite these defaults, simply add or remove a property from these configuration
* objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
* with the lowercased HTTP method name as the key, e.g.
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
*
- * Additionally, the defaults can be set at runtime via the `$http.defaults` object in the same
- * fashion.
+ * The defaults can also be set at runtime via the `$http.defaults` object in the same
+ * fashion. In addition, you can supply a `headers` property in the config object passed when
+ * calling `$http(config)`, which overrides the defaults without changing them globally.
*
*
* # Transforming Requests and Responses
*
* Both requests and responses can be transformed using transform functions. By default, Angular
* applies these transformations:
*
* Request transformations:
*
- * - If the `data` property of the request configuration object contains an object, serialize it into
- * JSON format.
+ * - If the `data` property of the request configuration object contains an object, serialize it
+ * into JSON format.
*
* Response transformations:
*
* - If XSRF prefix is detected, strip it (see Security Considerations section below).
* - If JSON response is detected, deserialize it using a JSON parser.
*
- * To globally augment or override the default transforms, modify the `$httpProvider.defaults.transformRequest` and
- * `$httpProvider.defaults.transformResponse` properties. These properties are by default an
- * array of transform functions, which allows you to `push` or `unshift` a new transformation function into the
- * transformation chain. You can also decide to completely override any default transformations by assigning your
+ * To globally augment or override the default transforms, modify the
+ * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
+ * properties. These properties are by default an array of transform functions, which allows you
+ * to `push` or `unshift` a new transformation function into the transformation chain. You can
+ * also decide to completely override any default transformations by assigning your
* transformation functions to these properties directly without the array wrapper.
*
- * Similarly, to locally override the request/response transforms, augment the `transformRequest` and/or
- * `transformResponse` properties of the configuration object passed into `$http`.
+ * Similarly, to locally override the request/response transforms, augment the
+ * `transformRequest` and/or `transformResponse` properties of the configuration object passed
+ * into `$http`.
*
*
* # Caching
*
* To enable caching, set the configuration property `cache` to `true`. When the cache is
@@ -16112,20 +16797,20 @@
* adding them to the `$httpProvider.interceptors` array. The factory is called and
* injected with dependencies (if specified) and returns the interceptor.
*
* There are two kinds of interceptors (and two kinds of rejection interceptors):
*
- * * `request`: interceptors get called with http `config` object. The function is free to modify
- * the `config` or create a new one. The function needs to return the `config` directly or as a
- * promise.
- * * `requestError`: interceptor gets called when a previous interceptor threw an error or resolved
- * with a rejection.
- * * `response`: interceptors get called with http `response` object. The function is free to modify
- * the `response` or create a new one. The function needs to return the `response` directly or as a
- * promise.
- * * `responseError`: interceptor gets called when a previous interceptor threw an error or resolved
- * with a rejection.
+ * * `request`: interceptors get called with http `config` object. The function is free to
+ * modify the `config` or create a new one. The function needs to return the `config`
+ * directly or as a promise.
+ * * `requestError`: interceptor gets called when a previous interceptor threw an error or
+ * resolved with a rejection.
+ * * `response`: interceptors get called with http `response` object. The function is free to
+ * modify the `response` or create a new one. The function needs to return the `response`
+ * directly or as a promise.
+ * * `responseError`: interceptor gets called when a previous interceptor threw an error or
+ * resolved with a rejection.
*
*
* <pre>
* // register the interceptor as a service
* $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
@@ -16174,10 +16859,11 @@
* // same as above
* },
* 'response': function(response) {
* // same as above
* }
+ * };
* });
* </pre>
*
* # Response interceptors (DEPRECATED)
*
@@ -16270,35 +16956,39 @@
*
* To take advantage of this, your server needs to set a token in a JavaScript readable session
* cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
* server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
* that only JavaScript running on your domain could have sent the request. The token must be
- * unique for each user and must be verifiable by the server (to prevent the JavaScript from making
- * up its own tokens). We recommend that the token is a digest of your site's authentication
- * cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt} for added security.
+ * unique for each user and must be verifiable by the server (to prevent the JavaScript from
+ * making up its own tokens). We recommend that the token is a digest of your site's
+ * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt}
+ * for added security.
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
* properties of either $httpProvider.defaults, or the per-request config object.
*
*
* @param {object} config Object describing the request to be made and how it should be
* processed. The object has following properties:
*
* - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
* - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
- * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned to
- * `?key1=value1&key2=value2` after the url. If the value is not a string, it will be JSONified.
+ * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
+ * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
+ * JSONified.
* - **data** – `{string|Object}` – Data to be sent as the request message data.
* - **headers** – `{Object}` – Map of strings or functions which return strings representing
- * HTTP headers to send to the server. If the return value of a function is null, the header will
- * not be sent.
+ * HTTP headers to send to the server. If the return value of a function is null, the
+ * header will not be sent.
* - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
* - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
- * - **transformRequest** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * - **transformRequest** –
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
* transform function or an array of such functions. The transform function takes the http
* request body and headers and returns its transformed (typically serialized) version.
- * - **transformResponse** – `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
+ * - **transformResponse** –
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
* transform function or an array of such functions. The transform function takes the http
* response body and headers and returns its transformed (typically deserialized) version.
* - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
* GET request, otherwise if a cache instance built with
* {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
@@ -16317,89 +17007,97 @@
* response object. The `success` and `error` methods take a single argument - a function that
* will be called when the request succeeds or fails respectively. The arguments passed into
* these functions are destructured representation of the response object passed into the
* `then` method. The response object has these properties:
*
- * - **data** – `{string|Object}` – The response body transformed with the transform functions.
+ * - **data** – `{string|Object}` – The response body transformed with the transform
+ * functions.
* - **status** – `{number}` – HTTP status code of the response.
* - **headers** – `{function([headerName])}` – Header getter function.
* - **config** – `{Object}` – The configuration object that was used to generate the request.
*
* @property {Array.<Object>} pendingRequests Array of config objects for currently pending
* requests. This is primarily meant to be used for debugging purposes.
*
*
* @example
- <example>
- <file name="index.html">
- <div ng-controller="FetchCtrl">
- <select ng-model="method">
- <option>GET</option>
- <option>JSONP</option>
- </select>
- <input type="text" ng-model="url" size="80"/>
- <button ng-click="fetch()">fetch</button><br>
- <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
- <button ng-click="updateModel('JSONP', 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">Sample JSONP</button>
- <button ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">Invalid JSONP</button>
- <pre>http status code: {{status}}</pre>
- <pre>http response data: {{data}}</pre>
- </div>
- </file>
- <file name="script.js">
- function FetchCtrl($scope, $http, $templateCache) {
- $scope.method = 'GET';
- $scope.url = 'http-hello.html';
+<example>
+<file name="index.html">
+ <div ng-controller="FetchCtrl">
+ <select ng-model="method">
+ <option>GET</option>
+ <option>JSONP</option>
+ </select>
+ <input type="text" ng-model="url" size="80"/>
+ <button ng-click="fetch()">fetch</button><br>
+ <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
+ <button
+ ng-click="updateModel('JSONP',
+ 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
+ Sample JSONP
+ </button>
+ <button
+ ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
+ Invalid JSONP
+ </button>
+ <pre>http status code: {{status}}</pre>
+ <pre>http response data: {{data}}</pre>
+ </div>
+</file>
+<file name="script.js">
+ function FetchCtrl($scope, $http, $templateCache) {
+ $scope.method = 'GET';
+ $scope.url = 'http-hello.html';
- $scope.fetch = function() {
- $scope.code = null;
- $scope.response = null;
+ $scope.fetch = function() {
+ $scope.code = null;
+ $scope.response = null;
- $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
- success(function(data, status) {
- $scope.status = status;
- $scope.data = data;
- }).
- error(function(data, status) {
- $scope.data = data || "Request failed";
- $scope.status = status;
- });
- };
+ $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
+ success(function(data, status) {
+ $scope.status = status;
+ $scope.data = data;
+ }).
+ error(function(data, status) {
+ $scope.data = data || "Request failed";
+ $scope.status = status;
+ });
+ };
- $scope.updateModel = function(method, url) {
- $scope.method = method;
- $scope.url = url;
- };
- }
- </file>
- <file name="http-hello.html">
- Hello, $http!
- </file>
- <file name="scenario.js">
- it('should make an xhr GET request', function() {
- element(':button:contains("Sample GET")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Hello, \$http!/);
- });
+ $scope.updateModel = function(method, url) {
+ $scope.method = method;
+ $scope.url = url;
+ };
+ }
+</file>
+<file name="http-hello.html">
+ Hello, $http!
+</file>
+<file name="scenario.js">
+ it('should make an xhr GET request', function() {
+ element(':button:contains("Sample GET")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('200');
+ expect(binding('data')).toMatch(/Hello, \$http!/);
+ });
- it('should make a JSONP request to angularjs.org', function() {
- element(':button:contains("Sample JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Super Hero!/);
- });
+ it('should make a JSONP request to angularjs.org', function() {
+ element(':button:contains("Sample JSONP")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('200');
+ expect(binding('data')).toMatch(/Super Hero!/);
+ });
- it('should make JSONP request to invalid URL and invoke the error handler',
- function() {
- element(':button:contains("Invalid JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('0');
- expect(binding('data')).toBe('Request failed');
- });
- </file>
- </example>
+ it('should make JSONP request to invalid URL and invoke the error handler',
+ function() {
+ element(':button:contains("Invalid JSONP")').click();
+ element(':button:contains("fetch")').click();
+ expect(binding('status')).toBe('0');
+ expect(binding('data')).toBe('Request failed');
+ });
+</file>
+</example>
*/
function $http(requestConfig) {
var config = {
transformRequest: defaults.transformRequest,
transformResponse: defaults.transformResponse
@@ -16755,11 +17453,11 @@
function buildUrl(url, params) {
if (!params) return url;
var parts = [];
forEachSorted(params, function(value, key) {
- if (value == null || value == undefined) return;
+ if (value === null || isUndefined(value)) return;
if (!isArray(value)) value = [value];
forEach(value, function(v) {
if (isObject(v)) {
v = toJson(v);
@@ -16774,10 +17472,11 @@
}];
}
var XHR = window.XMLHttpRequest || function() {
+ /* global ActiveXObject */
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
};
@@ -16844,11 +17543,11 @@
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var responseHeaders = xhr.getAllResponseHeaders();
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
- // response and responseType properties were introduced in XHR Level2 spec (supported by IE10)
+ // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
completeRequest(callback,
status || xhr.status,
(xhr.responseType ? xhr.response : xhr.responseText),
responseHeaders);
}
@@ -16932,35 +17631,35 @@
* @description
*
* Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
*
* @example
- <doc:example module="customInterpolationApp">
- <doc:source>
- <script>
- var customInterpolationApp = angular.module('customInterpolationApp', []);
+<doc:example module="customInterpolationApp">
+<doc:source>
+<script>
+ var customInterpolationApp = angular.module('customInterpolationApp', []);
- customInterpolationApp.config(function($interpolateProvider) {
- $interpolateProvider.startSymbol('//');
- $interpolateProvider.endSymbol('//');
- });
+ customInterpolationApp.config(function($interpolateProvider) {
+ $interpolateProvider.startSymbol('//');
+ $interpolateProvider.endSymbol('//');
+ });
- customInterpolationApp.controller('DemoController', function DemoController() {
- this.label = "This bindings is brought you you by // interpolation symbols.";
- });
- </script>
- <div ng-app="App" ng-controller="DemoController as demo">
- //demo.label//
- </div>
- </doc:source>
- <doc:scenario>
- it('should interpolate binding with custom symbols', function() {
- expect(binding('demo.label')).toBe('This bindings is brought you you by // interpolation symbols.');
- });
- </doc:scenario>
- </doc:example>
+ customInterpolationApp.controller('DemoController', function DemoController() {
+ this.label = "This binding is brought you by // interpolation symbols.";
+ });
+</script>
+<div ng-app="App" ng-controller="DemoController as demo">
+ //demo.label//
+</div>
+</doc:source>
+<doc:scenario>
+ it('should interpolate binding with custom symbols', function() {
+ expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
+ });
+</doc:scenario>
+</doc:example>
*/
function $InterpolateProvider() {
var startSymbol = '{{';
var endSymbol = '}}';
@@ -17033,15 +17732,15 @@
* @param {string} text The text with markup to interpolate.
* @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
* embedded expression in order to return an interpolation function. Strings with no
* embedded expression will return null for the interpolation function.
* @param {string=} trustedContext when provided, the returned function passes the interpolated
- * result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
+ * result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
* trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
* provides Strict Contextual Escaping for details.
- * @returns {function(context)} an interpolation function which is used to compute the interpolated
- * string. The function has these parameters:
+ * @returns {function(context)} an interpolation function which is used to compute the
+ * interpolated string. The function has these parameters:
*
* * `context`: an object against which any expressions embedded in the strings are evaluated
* against.
*
*/
@@ -17075,16 +17774,16 @@
// we added, nothing, must have been an empty string.
parts.push('');
length = 1;
}
- // Concatenating expressions makes it hard to reason about whether some combination of concatenated
- // values are unsafe to use and could easily lead to XSS. By requiring that a single
- // expression be used for iframe[src], object[src], etc., we ensure that the value that's used
- // is assigned or constructed by some JS code somewhere that is more testable or make it
- // obvious that you bound the value to some user controlled value. This helps reduce the load
- // when auditing for XSS issues.
+ // Concatenating expressions makes it hard to reason about whether some combination of
+ // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a
+ // single expression be used for iframe[src], object[src], etc., we ensure that the value
+ // that's used is assigned or constructed by some JS code somewhere that is more testable or
+ // make it obvious that you bound the value to some user controlled value. This helps reduce
+ // the load when auditing for XSS issues.
if (trustedContext && parts.length > 1) {
throw $interpolateMinErr('noconcat',
"Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
"interpolations that concatenate multiple expressions when a trusted value is " +
"required. See http://docs.angularjs.org/api/ng.$sce", text);
@@ -17100,22 +17799,23 @@
if (trustedContext) {
part = $sce.getTrusted(trustedContext, part);
} else {
part = $sce.valueOf(part);
}
- if (part == null || part == undefined) {
+ if (part === null || isUndefined(part)) {
part = '';
} else if (typeof part != 'string') {
part = toJson(part);
}
}
concat[i] = part;
}
return concat.join('');
}
catch(err) {
- var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
+ var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
+ err.toString());
$exceptionHandler(newErr);
}
};
fn.exp = text;
fn.parts = parts;
@@ -17136,11 +17836,11 @@
*
* @returns {string} start symbol.
*/
$interpolate.startSymbol = function() {
return startSymbol;
- }
+ };
/**
* @ngdoc method
* @name ng.$interpolate#endSymbol
@@ -17153,11 +17853,11 @@
*
* @returns {string} start symbol.
*/
$interpolate.endSymbol = function() {
return endSymbol;
- }
+ };
return $interpolate;
}];
}
@@ -17179,31 +17879,31 @@
* notified upon each tick of the interval, and will be resolved after `count` iterations, or
* run indefinitely if `count` is not defined. The value of the notification will be the
* number of iterations that have run.
* To cancel an interval, call `$interval.cancel(promise)`.
*
- * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
+ * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
* move forward by `millis` milliseconds and trigger any functions scheduled to run in that
* time.
*
* @param {function()} fn A function that should be called repeatedly.
* @param {number} delay Number of milliseconds between each function call.
* @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
* indefinitely.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
* @returns {promise} A promise which will be notified on each iteration.
*/
function interval(fn, delay, count, invokeApply) {
var setInterval = $window.setInterval,
- clearInterval = $window.clearInterval;
-
- var deferred = $q.defer(),
+ clearInterval = $window.clearInterval,
+ deferred = $q.defer(),
promise = deferred.promise,
- count = (isDefined(count)) ? count : 0,
iteration = 0,
skipApply = (isDefined(invokeApply) && !invokeApply);
+
+ count = isDefined(count) ? count : 0,
promise.then(null, null, fn);
promise.$$intervalId = setInterval(function tick() {
deferred.notify(iteration++);
@@ -17292,12 +17992,13 @@
],
CURRENCY_SYM: '$'
},
DATETIME_FORMATS: {
- MONTH: 'January,February,March,April,May,June,July,August,September,October,November,December'
- .split(','),
+ MONTH:
+ 'January,February,March,April,May,June,July,August,September,October,November,December'
+ .split(','),
SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
AMPMS: ['AM','PM'],
medium: 'MMM d, y h:mm:ss a',
@@ -17355,27 +18056,31 @@
var prefixed = (relativeUrl.charAt(0) !== '/');
if (prefixed) {
relativeUrl = '/' + relativeUrl;
}
var match = urlResolve(relativeUrl);
- locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ? match.pathname.substring(1) : match.pathname);
+ locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
+ match.pathname.substring(1) : match.pathname);
locationObj.$$search = parseKeyValue(match.search);
locationObj.$$hash = decodeURIComponent(match.hash);
// make sure path starts with '/';
- if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') locationObj.$$path = '/' + locationObj.$$path;
+ if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
+ locationObj.$$path = '/' + locationObj.$$path;
+ }
}
/**
*
* @param {string} begin
* @param {string} whole
- * @returns {string} returns text from whole after begin or undefined if it does not begin with expected string.
+ * @returns {string} returns text from whole after begin or undefined if it does not begin with
+ * expected string.
*/
function beginsWith(begin, whole) {
- if (whole.indexOf(begin) == 0) {
+ if (whole.indexOf(begin) === 0) {
return whole.substr(begin.length);
}
}
@@ -17416,11 +18121,12 @@
* @private
*/
this.$$parse = function(url) {
var pathUrl = beginsWith(appBaseNoFile, url);
if (!isString(pathUrl)) {
- throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url, appBaseNoFile);
+ throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
+ appBaseNoFile);
}
parseAppUrl(pathUrl, this);
if (!this.$$path) {
@@ -17455,11 +18161,11 @@
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
return appBaseNoFile + appUrl;
} else if (appBaseNoFile == url + '/') {
return appBaseNoFile;
}
- }
+ };
}
/**
* LocationHashbangUrl represents url
@@ -17488,11 +18194,12 @@
: (this.$$html5)
? withoutBaseUrl
: '';
if (!isString(withoutHashUrl)) {
- throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, hashPrefix);
+ throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
+ hashPrefix);
}
parseAppUrl(withoutHashUrl, this);
this.$$compose();
};
@@ -17510,11 +18217,11 @@
this.$$rewrite = function(url) {
if(stripHash(appBase) == stripHash(url)) {
return url;
}
- }
+ };
}
/**
* LocationHashbangUrl represents url
@@ -17539,11 +18246,11 @@
} else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
return appBase + hashPrefix + appUrl;
} else if ( appBaseNoFile === url + '/') {
return appBaseNoFile;
}
- }
+ };
}
LocationHashbangInHtml5Url.prototype =
LocationHashbangUrl.prototype =
@@ -17678,15 +18385,18 @@
*
* Return search part (as object) of current url when called without any parameter.
*
* Change search part when called with parameter and return `$location`.
*
- * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or hash object. Hash object
- * may contain an array of values, which will be decoded as duplicates in the url.
- * @param {string=} paramValue If `search` is a string, then `paramValue` will override only a
- * single search parameter. If the value is `null`, the parameter will be deleted.
+ * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
+ * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
+ * the url.
*
+ * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
+ * single search parameter. If `paramValue` is an array, it will set the parameter as a
+ * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
+ *
* @return {string} search
*/
search: function(search, paramValue) {
switch (arguments.length) {
case 0:
@@ -17695,15 +18405,16 @@
if (isString(search)) {
this.$$search = parseKeyValue(search);
} else if (isObject(search)) {
this.$$search = search;
} else {
- throw $locationMinErr('isrcharg', 'The first argument of the `$location#search()` call must be a string or an object.');
+ throw $locationMinErr('isrcharg',
+ 'The first argument of the `$location#search()` call must be a string or an object.');
}
break;
default:
- if (paramValue == undefined || paramValue == null) {
+ if (isUndefined(paramValue) || paramValue === null) {
delete this.$$search[search];
} else {
this.$$search[search] = paramValue;
}
}
@@ -17835,10 +18546,39 @@
} else {
return html5Mode;
}
};
+ /**
+ * @ngdoc event
+ * @name ng.$location#$locationChangeStart
+ * @eventOf ng.$location
+ * @eventType broadcast on root scope
+ * @description
+ * Broadcasted before a URL will change. This change can be prevented by calling
+ * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
+ * details about event object. Upon successful change
+ * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
+ *
+ * @param {Object} angularEvent Synthetic event object.
+ * @param {string} newUrl New URL
+ * @param {string=} oldUrl URL that was before it was changed.
+ */
+
+ /**
+ * @ngdoc event
+ * @name ng.$location#$locationChangeSuccess
+ * @eventOf ng.$location
+ * @eventType broadcast on root scope
+ * @description
+ * Broadcasted after a URL was changed.
+ *
+ * @param {Object} angularEvent Synthetic event object.
+ * @param {string} newUrl New URL
+ * @param {string=} oldUrl URL that was before it was changed.
+ */
+
this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
function( $rootScope, $browser, $sniffer, $rootElement) {
var $location,
LocationMode,
baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
@@ -17891,11 +18631,12 @@
}
// update $location when $browser url changes
$browser.onUrlChange(function(newUrl) {
if ($location.absUrl() != newUrl) {
- if ($rootScope.$broadcast('$locationChangeStart', newUrl, $location.absUrl()).defaultPrevented) {
+ if ($rootScope.$broadcast('$locationChangeStart', newUrl,
+ $location.absUrl()).defaultPrevented) {
$browser.url($location.absUrl());
return;
}
$rootScope.$evalAsync(function() {
var oldUrl = $location.absUrl();
@@ -17942,11 +18683,11 @@
* @ngdoc object
* @name ng.$log
* @requires $window
*
* @description
- * Simple service for logging. Default implementation writes the message
+ * Simple service for logging. Default implementation safely writes the message
* into the browser's console (if present).
*
* The main purpose of this service is to simplify debugging and troubleshooting.
*
* The default is not to log `debug` messages. You can use
@@ -17991,16 +18732,16 @@
* @description
* @param {string=} flag enable or disable debug level messages
* @returns {*} current value if used as getter or itself (chaining) if used as setter
*/
this.debugEnabled = function(flag) {
- if (isDefined(flag)) {
- debug = flag;
- return this;
- } else {
- return debug;
- }
+ if (isDefined(flag)) {
+ debug = flag;
+ return this;
+ } else {
+ return debug;
+ }
};
this.$get = ['$window', function($window){
return {
/**
@@ -18050,17 +18791,17 @@
*
* @description
* Write a debug message
*/
debug: (function () {
- var fn = consoleLog('debug');
-
- return function() {
- if (debug) {
- fn.apply(self, arguments);
- }
- }
+ var fn = consoleLog('debug');
+
+ return function() {
+ if (debug) {
+ fn.apply(self, arguments);
+ }
+ };
}())
};
function formatError(arg) {
if (arg instanceof Error) {
@@ -18091,73 +18832,93 @@
// we are IE which either doesn't have window.console => this is noop and we do nothing,
// or we are IE where console.log doesn't have apply so we log at least first 2 args
return function(arg1, arg2) {
logFn(arg1, arg2 == null ? '' : arg2);
- }
+ };
}
}];
}
var $parseMinErr = minErr('$parse');
var promiseWarningCache = {};
var promiseWarning;
// Sandboxing Angular Expressions
// ------------------------------
-// Angular expressions are generally considered safe because these expressions only have direct access to $scope and
-// locals. However, one can obtain the ability to execute arbitrary JS code by obtaining a reference to native JS
-// functions such as the Function constructor.
+// Angular expressions are generally considered safe because these expressions only have direct
+// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
+// obtaining a reference to native JS functions such as the Function constructor, the global Window
+// or Document object. In addition, many powerful functions for use by JavaScript code are
+// published on scope that shouldn't be available from within an Angular expression.
//
// As an example, consider the following Angular expression:
//
// {}.toString.constructor(alert("evil JS code"))
//
-// We want to prevent this type of access. For the sake of performance, during the lexing phase we disallow any "dotted"
-// access to any member named "constructor".
+// We want to prevent this type of access. For the sake of performance, during the lexing phase we
+// disallow any "dotted" access to any member named "constructor" or to any member whose name begins
+// or ends with an underscore. The latter allows one to exclude the private / JavaScript only API
+// available on the scope and controllers from the context of an Angular expression.
//
-// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor while evaluating
-// the expression, which is a stronger but more expensive test. Since reflective calls are expensive anyway, this is not
-// such a big deal compared to static dereferencing.
+// For reflective calls (a[b]), we check that the value of the lookup is not the Function
+// constructor, Window or DOM node while evaluating the expression, which is a stronger but more
+// expensive test. Since reflective calls are expensive anyway, this is not such a big deal compared
+// to static dereferencing.
//
-// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits against the
-// expression language, but not to prevent exploits that were enabled by exposing sensitive JavaScript or browser apis
-// on Scope. Exposing such objects on a Scope is never a good practice and therefore we are not even trying to protect
-// against interaction with an object explicitly exposed in this way.
+// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
+// against the expression language, but not to prevent exploits that were enabled by exposing
+// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
+// practice and therefore we are not even trying to protect against interaction with an object
+// explicitly exposed in this way.
//
-// A developer could foil the name check by aliasing the Function constructor under a different name on the scope.
+// A developer could foil the name check by aliasing the Function constructor under a different
+// name on the scope.
//
-// In general, it is not possible to access a Window object from an angular expression unless a window or some DOM
-// object that has a reference to window is published onto a Scope.
+// In general, it is not possible to access a Window object from an angular expression unless a
+// window or some DOM object that has a reference to window is published onto a Scope.
-function ensureSafeMemberName(name, fullExpression) {
- if (name === "constructor") {
+function ensureSafeMemberName(name, fullExpression, allowConstructor) {
+ if (typeof name !== 'string' && toString.apply(name) !== "[object String]") {
+ return name;
+ }
+ if (name === "constructor" && !allowConstructor) {
throw $parseMinErr('isecfld',
- 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}', fullExpression);
+ 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
}
+ if (name.charAt(0) === '_' || name.charAt(name.length-1) === '_') {
+ throw $parseMinErr('isecprv',
+ 'Referencing private fields in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
+ }
return name;
-};
+}
function ensureSafeObject(obj, fullExpression) {
// nifty check if obj is Function that is fast and works across iframes and other contexts
if (obj && obj.constructor === obj) {
throw $parseMinErr('isecfn',
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}', fullExpression);
+ 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
} else if (// isWindow(obj)
obj && obj.document && obj.location && obj.alert && obj.setInterval) {
throw $parseMinErr('isecwindow',
- 'Referencing the Window in Angular expressions is disallowed! Expression: {0}', fullExpression);
+ 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
} else if (// isElement(obj)
obj && (obj.nodeName || (obj.on && obj.find))) {
throw $parseMinErr('isecdom',
- 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}', fullExpression);
+ 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
+ fullExpression);
} else {
return obj;
}
}
var OPERATORS = {
+ /* jshint bitwise : false */
'null':function(){return null;},
'true':function(){return true;},
'false':function(){return false;},
undefined:noop,
'+':function(self, locals, a,b){
@@ -18167,11 +18928,14 @@
return a + b;
}
return a;
}
return isDefined(b)?b:undefined;},
- '-':function(self, locals, a,b){a=a(self, locals); b=b(self, locals); return (isDefined(a)?a:0)-(isDefined(b)?b:0);},
+ '-':function(self, locals, a,b){
+ a=a(self, locals); b=b(self, locals);
+ return (isDefined(a)?a:0)-(isDefined(b)?b:0);
+ },
'*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
'/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
'%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
'^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
'=':noop,
@@ -18188,10 +18952,11 @@
'&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
// '|':function(self, locals, a,b){return a|b;},
'|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
'!':function(self, locals, a){return !a(self, locals);}
};
+/* jshint bitwise: true */
var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
/////////////////////////////////////////
@@ -18288,12 +19053,13 @@
isNumber: function(ch) {
return ('0' <= ch && ch <= '9');
},
isWhitespace: function(ch) {
+ // IE treats non-breaking space as \u00A0
return (ch === ' ' || ch === '\r' || ch === '\t' ||
- ch === '\n' || ch === '\v' || ch === '\u00A0'); // IE treats non-breaking space as \u00A0
+ ch === '\n' || ch === '\v' || ch === '\u00A0');
},
isIdent: function(ch) {
return ('a' <= ch && ch <= 'z' ||
'A' <= ch && ch <= 'Z' ||
@@ -18806,11 +19572,14 @@
var indexFn = this.expression();
this.consume(']');
return extend(function(self, locals) {
var o = obj(self, locals),
- i = indexFn(self, locals),
+ // In the getter, we will not block looking up "constructor" by name in order to support user defined
+ // constructors. However, if value looked up is the Function constructor, we will still block it in the
+ // ensureSafeObject call right after we look up o[i] (a few lines below.)
+ i = ensureSafeMemberName(indexFn(self, locals), parser.text, true /* allowConstructor */),
v, p;
if (!o) return undefined;
v = ensureSafeObject(o[i], parser.text);
if (v && v.then && parser.options.unwrapPromises) {
@@ -18822,11 +19591,11 @@
v = v.$$v;
}
return v;
}, {
assign: function(self, value, locals) {
- var key = indexFn(self, locals);
+ var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
// prevent overwriting of Function.constructor which would break ensureSafeObject check
var safe = ensureSafeObject(obj(self, locals), parser.text);
return safe[key] = value;
}
});
@@ -18850,10 +19619,11 @@
for (var i = 0; i < argsFn.length; i++) {
args.push(argsFn[i](scope, locals));
}
var fnPtr = fn(scope, locals, context) || noop;
+ ensureSafeObject(context, parser.text);
ensureSafeObject(fnPtr, parser.text);
// IE stupidity! (IE doesn't have apply for some native functions)
var v = fnPtr.apply
? fnPtr.apply(context, args)
@@ -19055,11 +19825,11 @@
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
return pathVal;
- }
+ };
}
function getterFn(path, options, fullExp) {
// Check whether the cache has this getter already.
// We can use hasOwnProperty directly on the cache because we ensure,
@@ -19071,24 +19841,26 @@
var pathKeys = path.split('.'),
pathKeysLength = pathKeys.length,
fn;
if (options.csp) {
- fn = (pathKeysLength < 6)
- ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, options)
- : function(scope, locals) {
- var i = 0, val;
- do {
- val = cspSafeGetterFn(
- pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], fullExp, options
- )(scope, locals);
+ if (pathKeysLength < 6) {
+ fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
+ options);
+ } else {
+ fn = function(scope, locals) {
+ var i = 0, val;
+ do {
+ val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
+ pathKeys[i++], fullExp, options)(scope, locals);
- locals = undefined; // clear after first iteration
- scope = val;
- } while (i < pathKeysLength);
- return val;
- }
+ locals = undefined; // clear after first iteration
+ scope = val;
+ } while (i < pathKeysLength);
+ return val;
+ };
+ }
} else {
var code = 'var l, fn, p;\n';
forEach(pathKeys, function(key, index) {
ensureSafeMemberName(key, fullExp);
code += 'if(s === null || s === undefined) return s;\n' +
@@ -19110,11 +19882,13 @@
'}\n'
: '');
});
code += 'return s;';
- var evaledFnGetter = Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
+ /* jshint -W054 */
+ var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
+ /* jshint +W054 */
evaledFnGetter.toString = function() { return code; };
fn = function(scope, locals) {
return evaledFnGetter(scope, locals, promiseWarning);
};
}
@@ -19174,11 +19948,12 @@
* @ngdoc object
* @name ng.$parseProvider
* @function
*
* @description
- * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse} service.
+ * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
+ * service.
*/
function $ParseProvider() {
var cache = {};
var $parseOptions = {
@@ -19196,39 +19971,44 @@
* @methodOf ng.$parseProvider
* @description
*
* **This feature is deprecated, see deprecation notes below for more info**
*
- * If set to true (default is false), $parse will unwrap promises automatically when a promise is found at any part of
- * the expression. In other words, if set to true, the expression will always result in a non-promise value.
+ * If set to true (default is false), $parse will unwrap promises automatically when a promise is
+ * found at any part of the expression. In other words, if set to true, the expression will always
+ * result in a non-promise value.
*
- * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled, the fulfillment value
- * is used in place of the promise while evaluating the expression.
+ * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
+ * the fulfillment value is used in place of the promise while evaluating the expression.
*
* **Deprecation notice**
*
- * This is a feature that didn't prove to be wildly useful or popular, primarily because of the dichotomy between data
- * access in templates (accessed as raw values) and controller code (accessed as promises).
+ * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
+ * dichotomy between data access in templates (accessed as raw values) and controller code
+ * (accessed as promises).
*
- * In most code we ended up resolving promises manually in controllers anyway and thus unifying the model access there.
+ * In most code we ended up resolving promises manually in controllers anyway and thus unifying
+ * the model access there.
*
* Other downsides of automatic promise unwrapping:
*
* - when building components it's often desirable to receive the raw promises
* - adds complexity and slows down expression evaluation
- * - makes expression code pre-generation unattractive due to the amount of code that needs to be generated
+ * - makes expression code pre-generation unattractive due to the amount of code that needs to be
+ * generated
* - makes IDE auto-completion and tool support hard
*
* **Warning Logs**
*
- * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a promise (to reduce
- * the noise, each expression is logged only once). To disable this logging use
+ * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
+ * promise (to reduce the noise, each expression is logged only once). To disable this logging use
* `$parseProvider.logPromiseWarnings(false)` api.
*
*
* @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as setter.
+ * @returns {boolean|self} Returns the current setting when used as getter and self if used as
+ * setter.
*/
this.unwrapPromises = function(value) {
if (isDefined(value)) {
$parseOptions.unwrapPromises = !!value;
return this;
@@ -19251,11 +20031,12 @@
* The default is set to `true`.
*
* This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
*
* @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as setter.
+ * @returns {boolean|self} Returns the current setting when used as getter and self if used as
+ * setter.
*/
this.logPromiseWarnings = function(value) {
if (isDefined(value)) {
$parseOptions.logPromiseWarnings = value;
return this;
@@ -19355,12 +20136,12 @@
* alert('Got notification: ' + update);
* });
* </pre>
*
* At first it might not be obvious why this extra complexity is worth the trouble. The payoff
- * comes in the way of
- * [guarantees that promise and deferred APIs make](https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md).
+ * comes in the way of guarantees that promise and deferred APIs make, see
+ * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
*
* Additionally the promise api allows for composition that is very hard to do with the
* traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
* For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
* section on serial or parallel joining of promises.
@@ -19403,12 +20184,13 @@
* as soon as the result is available. The callbacks are called with a single argument: the result
* or rejection reason. Additionally, the notify callback may be called zero or more times to
* provide a progress indication, before the promise is resolved or rejected.
*
* This method *returns a new promise* which is resolved or rejected via the return value of the
- * `successCallback`, `errorCallback`. It also notifies via the return value of the `notifyCallback`
- * method. The promise can not be resolved or rejected from the notifyCallback method.
+ * `successCallback`, `errorCallback`. It also notifies via the return value of the
+ * `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
+ * method.
*
* - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
*
* - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
* but to do so without modifying the final value. This is useful to release resources or do some
@@ -19420,12 +20202,12 @@
* property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
* make your code IE8 compatible.
*
* # Chaining promises
*
- * Because calling the `then` method of a promise returns a new derived promise, it is easily possible
- * to create a chain of promises:
+ * Because calling the `then` method of a promise returns a new derived promise, it is easily
+ * possible to create a chain of promises:
*
* <pre>
* promiseB = promiseA.then(function(result) {
* return result + 1;
* });
@@ -19445,12 +20227,10 @@
* There are three main differences:
*
* - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
* mechanism in angular, which means faster propagation of resolution or rejection into your
* models and avoiding unnecessary browser repaints, which would result in flickering UI.
- * - $q promises are recognized by the templating engine in angular, which means that in templates
- * you can treat promises attached to a scope as if they were the resulting values.
* - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
* all the important functionality needed for common async tasks.
*
* # Testing
*
@@ -19784,13 +20564,13 @@
* Combines multiple promises into a single promise that is resolved when all of the input
* promises are resolved.
*
* @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
* @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
- * each value corresponding to the promise at the same index/key in the `promises` array/hash. If any of
- * the promises is resolved with a rejection, this resulting promise will be rejected with the
- * same rejection value.
+ * each value corresponding to the promise at the same index/key in the `promises` array/hash.
+ * If any of the promises is resolved with a rejection, this resulting promise will be rejected
+ * with the same rejection value.
*/
function all(promises) {
var deferred = defer(),
counter = 0,
results = isArray(promises) ? [] : {};
@@ -19860,15 +20640,23 @@
* @ngdoc function
* @name ng.$rootScopeProvider#digestTtl
* @methodOf ng.$rootScopeProvider
* @description
*
- * Sets the number of digest iterations the scope should attempt to execute before giving up and
+ * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
* assuming that the model is unstable.
*
* The current default is 10 iterations.
*
+ * In complex applications it's possible that the dependencies between `$watch`s will result in
+ * several digest iterations. However if an application needs more than the default 10 digest
+ * iterations for its model to stabilize then you should investigate what is causing the model to
+ * continuously change during the digest.
+ *
+ * Increasing the TTL could have performance implications, so you should not change it without
+ * proper justification.
+ *
* @param {number} limit The number of digest iterations.
*/
/**
@@ -19901,11 +20689,11 @@
* @name ng.$rootScope.Scope
*
* @description
* A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
* {@link AUTO.$injector $injector}. Child scopes are created using the
- * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
+ * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when
* compiled HTML template is executed.)
*
* Here is a simple scope snippet to show how you can interact with the scope.
* <pre>
* <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
@@ -19925,15 +20713,16 @@
expect(child.salutation).toEqual('Welcome');
expect(parent.salutation).toEqual('Hello');
* </pre>
*
*
- * @param {Object.<string, function()>=} providers Map of service factory which need to be provided
- * for the current scope. Defaults to {@link ng}.
+ * @param {Object.<string, function()>=} providers Map of service factory which need to be
+ * provided for the current scope. Defaults to {@link ng}.
* @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
- * append/override services provided by `providers`. This is handy when unit-testing and having
- * the need to override a default service.
+ * append/override services provided by `providers`. This is handy
+ * when unit-testing and having the need to override a default
+ * service.
* @returns {Object} Newly created scope.
*
*/
function Scope() {
this.$id = nextUid();
@@ -19967,16 +20756,16 @@
*
* @description
* Creates a new child {@link ng.$rootScope.Scope scope}.
*
* The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} and
- * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the scope
- * hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
+ * {@link ng.$rootScope.Scope#$digest $digest()} events. The scope can be removed from the
+ * scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
*
- * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is desired for
- * the scope and its child scopes to be permanently detached from the parent and thus stop
- * participating in model change detection and listener notification by invoking.
+ * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
+ * desired for the scope and its child scopes to be permanently detached from the parent and
+ * thus stop participating in model change detection and listener notification by invoking.
*
* @param {boolean} isolate If true, then the scope does not prototypically inherit from the
* parent scope. The scope is isolated, as it can not see parent scope properties.
* When creating widgets, it is useful for the widget to not accidentally read parent
* state.
@@ -20023,71 +20812,107 @@
* @function
*
* @description
* Registers a `listener` callback to be executed whenever the `watchExpression` changes.
*
- * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest $digest()} and
- * should return the value that will be watched. (Since {@link ng.$rootScope.Scope#$digest $digest()}
- * reruns when it detects changes the `watchExpression` can execute multiple times per
+ * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
+ * $digest()} and should return the value that will be watched. (Since
+ * {@link ng.$rootScope.Scope#$digest $digest()} reruns when it detects changes the
+ * `watchExpression` can execute multiple times per
* {@link ng.$rootScope.Scope#$digest $digest()} and should be idempotent.)
* - The `listener` is called only when the value from the current `watchExpression` and the
* previous call to `watchExpression` are not equal (with the exception of the initial run,
* see below). The inequality is determined according to
- * {@link angular.equals} function. To save the value of the object for later comparison, the
- * {@link angular.copy} function is used. It also means that watching complex options will
- * have adverse memory and performance implications.
- * - The watch `listener` may change the model, which may trigger other `listener`s to fire. This
- * is achieved by rerunning the watchers until no changes are detected. The rerun iteration
- * limit is 10 to prevent an infinite loop deadlock.
+ * {@link angular.equals} function. To save the value of the object for later comparison,
+ * the {@link angular.copy} function is used. It also means that watching complex options
+ * will have adverse memory and performance implications.
+ * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
+ * This is achieved by rerunning the watchers until no changes are detected. The rerun
+ * iteration limit is 10 to prevent an infinite loop deadlock.
*
*
* If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
* you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
- * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a change is
- * detected, be prepared for multiple calls to your listener.)
+ * can execute multiple times per {@link ng.$rootScope.Scope#$digest $digest} cycle when a
+ * change is detected, be prepared for multiple calls to your listener.)
*
* After a watcher is registered with the scope, the `listener` fn is called asynchronously
* (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
* watcher. In rare cases, this is undesirable because the listener is called when the result
* of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
* can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
* listener was called due to initialization.
*
+ * The example below contains an illustration of using a function as your $watch listener
*
+ *
* # Example
* <pre>
// let's assume that scope was dependency injected as the $rootScope
var scope = $rootScope;
scope.name = 'misko';
scope.counter = 0;
expect(scope.counter).toEqual(0);
- scope.$watch('name', function(newValue, oldValue) { scope.counter = scope.counter + 1; });
+ scope.$watch('name', function(newValue, oldValue) {
+ scope.counter = scope.counter + 1;
+ });
expect(scope.counter).toEqual(0);
scope.$digest();
// no variable change
expect(scope.counter).toEqual(0);
scope.name = 'adam';
scope.$digest();
expect(scope.counter).toEqual(1);
+
+
+
+ // Using a listener function
+ var food;
+ scope.foodCounter = 0;
+ expect(scope.foodCounter).toEqual(0);
+ scope.$watch(
+ // This is the listener function
+ function() { return food; },
+ // This is the change handler
+ function(newValue, oldValue) {
+ if ( newValue !== oldValue ) {
+ // Only increment the counter if the value changed
+ scope.foodCounter = scope.foodCounter + 1;
+ }
+ }
+ );
+ // No digest has been run so the counter will be zero
+ expect(scope.foodCounter).toEqual(0);
+
+ // Run the digest but since food has not changed cout will still be zero
+ scope.$digest();
+ expect(scope.foodCounter).toEqual(0);
+
+ // Update food and run digest. Now the counter will increment
+ food = 'cheeseburger';
+ scope.$digest();
+ expect(scope.foodCounter).toEqual(1);
+
* </pre>
*
*
*
* @param {(function()|string)} watchExpression Expression that is evaluated on each
- * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers a
- * call to the `listener`.
+ * {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
+ * a call to the `listener`.
*
* - `string`: Evaluated as {@link guide/expression expression}
* - `function(scope)`: called with current `scope` as a parameter.
* @param {(function()|string)=} listener Callback called whenever the return value of
* the `watchExpression` changes.
*
* - `string`: Evaluated as {@link guide/expression expression}
- * - `function(newValue, oldValue, scope)`: called with current and previous values as parameters.
+ * - `function(newValue, oldValue, scope)`: called with current and previous values as
+ * parameters.
*
* @param {boolean=} objectEquality Compare object for equality rather than for reference.
* @returns {function()} Returns a deregistration function for this listener.
*/
$watch: function(watchExp, listener, objectEquality) {
@@ -20135,17 +20960,17 @@
* @methodOf ng.$rootScope.Scope
* @function
*
* @description
* Shallow watches the properties of an object and fires whenever any of the properties change
- * (for arrays, this implies watching the array items; for object maps, this implies watching the properties).
- * If a change is detected, the `listener` callback is fired.
+ * (for arrays, this implies watching the array items; for object maps, this implies watching
+ * the properties). If a change is detected, the `listener` callback is fired.
*
- * - The `obj` collection is observed via standard $watch operation and is examined on every call to $digest() to
- * see if any items have been added, removed, or moved.
- * - The `listener` is called whenever anything within the `obj` has changed. Examples include adding, removing,
- * and moving items belonging to an object or array.
+ * - The `obj` collection is observed via standard $watch operation and is examined on every
+ * call to $digest() to see if any items have been added, removed, or moved.
+ * - The `listener` is called whenever anything within the `obj` has changed. Examples include
+ * adding, removing, and moving items belonging to an object or array.
*
*
* # Example
* <pre>
$scope.names = ['igor', 'matias', 'misko', 'james'];
@@ -20167,23 +20992,23 @@
//now there's been a change
expect($scope.dataCount).toEqual(3);
* </pre>
*
*
- * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The expression value
- * should evaluate to an object or an array which is observed on each
- * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the collection will trigger
- * a call to the `listener`.
+ * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
+ * expression value should evaluate to an object or an array which is observed on each
+ * {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
+ * collection will trigger a call to the `listener`.
*
- * @param {function(newCollection, oldCollection, scope)} listener a callback function that is fired with both
- * the `newCollection` and `oldCollection` as parameters.
- * The `newCollection` object is the newly modified data obtained from the `obj` expression and the
- * `oldCollection` object is a copy of the former collection data.
+ * @param {function(newCollection, oldCollection, scope)} listener a callback function that is
+ * fired with both the `newCollection` and `oldCollection` as parameters.
+ * The `newCollection` object is the newly modified data obtained from the `obj` expression
+ * and the `oldCollection` object is a copy of the former collection data.
* The `scope` refers to the current scope.
*
- * @returns {function()} Returns a de-registration function for this listener. When the de-registration function
- * is executed, the internal watch operation is terminated.
+ * @returns {function()} Returns a de-registration function for this listener. When the
+ * de-registration function is executed, the internal watch operation is terminated.
*/
$watchCollection: function(obj, listener) {
var self = this;
var oldValue;
var newValue;
@@ -20274,25 +21099,26 @@
* @name ng.$rootScope.Scope#$digest
* @methodOf ng.$rootScope.Scope
* @function
*
* @description
- * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and its children.
- * Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change the model, the
- * `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers} until no more listeners are
- * firing. This means that it is possible to get into an infinite loop. This function will throw
- * `'Maximum iteration limit exceeded.'` if the number of iterations exceeds 10.
+ * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
+ * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
+ * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
+ * until no more listeners are firing. This means that it is possible to get into an infinite
+ * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
+ * iterations exceeds 10.
*
* Usually, you don't call `$digest()` directly in
* {@link ng.directive:ngController controllers} or in
- * {@link ng.$compileProvider#directive directives}.
- * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
- * {@link ng.$compileProvider#directive directives}), which will force a `$digest()`.
+ * {@link ng.$compileProvider#methods_directive directives}.
+ * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
+ * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
*
* If you want to be notified whenever `$digest()` is called,
- * you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
- * with no `listener`.
+ * you can register a `watchExpression` function with
+ * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
*
* In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
*
* # Example
* <pre>
@@ -20386,11 +21212,12 @@
} while ((current = next));
if(dirty && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
- '{0} $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: {1}',
+ '{0} $digest() iterations reached. Aborting!\n' +
+ 'Watchers fired in the last 5 iterations: {1}',
TTL, toJson(watchLog));
}
} while (dirty || asyncQueue.length);
clearPhase();
@@ -20465,12 +21292,13 @@
* @name ng.$rootScope.Scope#$eval
* @methodOf ng.$rootScope.Scope
* @function
*
* @description
- * Executes the `expression` on the current scope and returns the result. Any exceptions in the
- * expression are propagated (uncaught). This is useful when evaluating Angular expressions.
+ * Executes the `expression` on the current scope and returns the result. Any exceptions in
+ * the expression are propagated (uncaught). This is useful when evaluating Angular
+ * expressions.
*
* # Example
* <pre>
var scope = ng.$rootScope.Scope();
scope.a = 1;
@@ -20482,11 +21310,12 @@
*
* @param {(string|function())=} expression An angular expression to be executed.
*
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
* - `function(scope)`: execute the function with the current `scope` parameter.
- *
+ *
+ * @param {(object)=} locals Local variables object, useful for overriding values in scope.
* @returns {*} The result of evaluating the expression.
*/
$eval: function(expr, locals) {
return $parse(expr)(this, locals);
},
@@ -20498,31 +21327,34 @@
* @function
*
* @description
* Executes the expression on the current scope at a later point in time.
*
- * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only that:
+ * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
+ * that:
*
- * - it will execute after the function that scheduled the evaluation (preferably before DOM rendering).
- * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after `expression` execution.
+ * - it will execute after the function that scheduled the evaluation (preferably before DOM
+ * rendering).
+ * - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
+ * `expression` execution.
*
* Any exceptions from the execution of the expression are forwarded to the
* {@link ng.$exceptionHandler $exceptionHandler} service.
*
- * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle will be scheduled.
- * However, it is encouraged to always call code that changes the model from within an `$apply` call.
- * That includes code evaluated via `$evalAsync`.
+ * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
+ * will be scheduled. However, it is encouraged to always call code that changes the model
+ * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
*
* @param {(string|function())=} expression An angular expression to be executed.
*
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
* - `function(scope)`: execute the function with the current `scope` parameter.
*
*/
$evalAsync: function(expr) {
- // if we are outside of an $digest loop and this is the first time we are scheduling async task also schedule
- // async auto-flush
+ // if we are outside of an $digest loop and this is the first time we are scheduling async
+ // task also schedule async auto-flush
if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
$browser.defer(function() {
if ($rootScope.$$asyncQueue.length) {
$rootScope.$digest();
}
@@ -20541,14 +21373,14 @@
* @name ng.$rootScope.Scope#$apply
* @methodOf ng.$rootScope.Scope
* @function
*
* @description
- * `$apply()` is used to execute an expression in angular from outside of the angular framework.
- * (For example from browser DOM events, setTimeout, XHR or third party libraries).
- * Because we are calling into the angular framework we need to perform proper scope life cycle
- * of {@link ng.$exceptionHandler exception handling},
+ * `$apply()` is used to execute an expression in angular from outside of the angular
+ * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
+ * Because we are calling into the angular framework we need to perform proper scope life
+ * cycle of {@link ng.$exceptionHandler exception handling},
* {@link ng.$rootScope.Scope#$digest executing watches}.
*
* ## Life cycle
*
* # Pseudo-Code of `$apply()`
@@ -20569,12 +21401,12 @@
*
* 1. The {@link guide/expression expression} is executed using the
* {@link ng.$rootScope.Scope#$eval $eval()} method.
* 2. Any exceptions from the execution of the expression are forwarded to the
* {@link ng.$exceptionHandler $exceptionHandler} service.
- * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the expression
- * was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
+ * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
+ * expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
*
*
* @param {(string|function())=} exp An angular expression to be executed.
*
* - `string`: execute using the rules as defined in {@link guide/expression expression}.
@@ -20604,22 +21436,24 @@
* @name ng.$rootScope.Scope#$on
* @methodOf ng.$rootScope.Scope
* @function
*
* @description
- * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for discussion of
- * event life cycle.
+ * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
+ * discussion of event life cycle.
*
* The event listener function format is: `function(event, args...)`. The `event` object
* passed into the listener has the following attributes:
*
- * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
+ * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
+ * `$broadcast`-ed.
* - `currentScope` - `{Scope}`: the current scope which is handling the event.
* - `name` - `{string}`: name of the event.
- * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel further event
- * propagation (available only for events that were `$emit`-ed).
- * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag to true.
+ * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
+ * further event propagation (available only for events that were `$emit`-ed).
+ * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
+ * to true.
* - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
*
* @param {string} name Event name to listen on.
* @param {function(event, args...)} listener Function to call when the event is emitted.
* @returns {function()} Returns a deregistration function for this listener.
@@ -20646,13 +21480,14 @@
* @description
* Dispatches an event `name` upwards through the scope hierarchy notifying the
* registered {@link ng.$rootScope.Scope#$on} listeners.
*
* The event life cycle starts at the scope on which `$emit` was called. All
- * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
- * Afterwards, the event traverses upwards toward the root scope and calls all registered
- * listeners along the way. The event will stop propagating if one of the listeners cancels it.
+ * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
+ * notified. Afterwards, the event traverses upwards toward the root scope and calls all
+ * registered listeners along the way. The event will stop propagating if one of the listeners
+ * cancels it.
*
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
*
* @param {string} name Event name to emit.
@@ -20714,13 +21549,13 @@
* @description
* Dispatches an event `name` downwards to all child scopes (and their children) notifying the
* registered {@link ng.$rootScope.Scope#$on} listeners.
*
* The event life cycle starts at the scope on which `$broadcast` was called. All
- * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get notified.
- * Afterwards, the event propagates to all direct and indirect scopes of the current scope and
- * calls all registered listeners along the way. The event cannot be canceled.
+ * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
+ * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
+ * scope and calls all registered listeners along the way. The event cannot be canceled.
*
* Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
* onto the {@link ng.$exceptionHandler $exceptionHandler} service.
*
* @param {string} name Event name to broadcast.
@@ -20826,11 +21661,11 @@
// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
// Prereq: s is a string.
function escapeForRegexp(s) {
return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
replace(/\x08/g, '\\x08');
-};
+}
function adjustMatcher(matcher) {
if (matcher === 'self') {
return matcher;
@@ -20890,25 +21725,25 @@
*
* The default instance of `$sceDelegate` should work out of the box with little pain. While you
* can override it completely to change the behavior of `$sce`, the common case would
* involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
* your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
- * templates. Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
+ * templates. Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist
* $sceDelegateProvider.resourceUrlWhitelist} and {@link
- * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
+ * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
*/
/**
* @ngdoc object
* @name ng.$sceDelegateProvider
* @description
*
* The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
* $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure
* that the URLs used for sourcing Angular templates are safe. Refer {@link
- * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
- * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
+ * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
+ * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
*
* For the general details about this service in Angular, read the main page for {@link ng.$sce
* Strict Contextual Escaping (SCE)}.
*
* **Example**: Consider the following case. <a name="example"></a>
@@ -20950,12 +21785,12 @@
*
* @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
* provided. This must be an array or null. A snapshot of this array is used so further
* changes to the array are ignored.
*
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items allowed in
- * this array.
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
+ * allowed in this array.
*
* Note: **an empty whitelist array will block all URLs**!
*
* @return {Array} the currently set whitelist array.
*
@@ -20980,23 +21815,23 @@
*
* @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
* provided. This must be an array or null. A snapshot of this array is used so further
* changes to the array are ignored.
*
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items allowed in
- * this array.
+ * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
+ * allowed in this array.
*
- * The typical usage for the blacklist is to **block [open redirects](http://cwe.mitre.org/data/definitions/601.html)**
- * served by your domain as these would otherwise be trusted but actually return content from the redirected
- * domain.
+ * The typical usage for the blacklist is to **block
+ * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
+ * these would otherwise be trusted but actually return content from the redirected domain.
*
* Finally, **the blacklist overrides the whitelist** and has the final say.
*
* @return {Array} the currently set blacklist array.
*
- * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there is
- * no blacklist.)
+ * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
+ * is no blacklist.)
*
* @description
* Sets/Gets the blacklist of trusted resource URLs.
*/
@@ -21048,25 +21883,25 @@
}
}
return allowed;
}
- function generateHolderType(base) {
+ function generateHolderType(Base) {
var holderType = function TrustedValueHolderType(trustedValue) {
this.$$unwrapTrustedValue = function() {
return trustedValue;
};
};
- if (base) {
- holderType.prototype = new base();
+ if (Base) {
+ holderType.prototype = new Base();
}
holderType.prototype.valueOf = function sceValueOf() {
return this.$$unwrapTrustedValue();
- }
+ };
holderType.prototype.toString = function sceToString() {
return this.$$unwrapTrustedValue().toString();
- }
+ };
return holderType;
}
var trustedValueHolderBase = generateHolderType(),
byType = {};
@@ -21094,13 +21929,14 @@
* @param {*} value The value that that should be considered trusted/safe.
* @returns {*} A value that can be used to stand in for the provided `value` in places
* where Angular expects a $sce.trustAs() return value.
*/
function trustAs(type, trustedValue) {
- var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
- if (!constructor) {
- throw $sceMinErr('icontext', 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
+ var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
+ if (!Constructor) {
+ throw $sceMinErr('icontext',
+ 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
type, trustedValue);
}
if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
return trustedValue;
}
@@ -21109,31 +21945,31 @@
if (typeof trustedValue !== 'string') {
throw $sceMinErr('itype',
'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
type);
}
- return new constructor(trustedValue);
+ return new Constructor(trustedValue);
}
/**
* @ngdoc method
* @name ng.$sceDelegate#valueOf
* @methodOf ng.$sceDelegate
*
* @description
- * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
+ * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs
* `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
- * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
+ * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.
*
* If the passed parameter is not a value that had been returned by {@link
- * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
+ * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is.
*
- * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
+ * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
* call or anything else.
- * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
- * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns `value`
- * unchanged.
+ * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
+ * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns
+ * `value` unchanged.
*/
function valueOf(maybeTrusted) {
if (maybeTrusted instanceof trustedValueHolderBase) {
return maybeTrusted.$$unwrapTrustedValue();
} else {
@@ -21145,18 +21981,18 @@
* @ngdoc method
* @name ng.$sceDelegate#getTrusted
* @methodOf ng.$sceDelegate
*
* @description
- * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and returns the
- * originally supplied value if the queried context type is a supertype of the created type. If
- * this condition isn't satisfied, throws an exception.
+ * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and
+ * returns the originally supplied value if the queried context type is a supertype of the
+ * created type. If this condition isn't satisfied, throws an exception.
*
* @param {string} type The kind of context in which this value is to be used.
- * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
- * `$sceDelegate.trustAs`} call.
- * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
+ * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs
+ * `$sceDelegate.trustAs`} call.
+ * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
* `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception.
*/
function getTrusted(type, maybeTrusted) {
if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
return maybeTrusted;
@@ -21171,11 +22007,12 @@
if (type === SCE_CONTEXTS.RESOURCE_URL) {
if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
return maybeTrusted;
} else {
throw $sceMinErr('insecurl',
- 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}', maybeTrusted.toString());
+ 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}',
+ maybeTrusted.toString());
}
} else if (type === SCE_CONTEXTS.HTML) {
return htmlSanitizer(maybeTrusted);
}
throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
@@ -21198,10 +22035,12 @@
* - override the default implementation with a custom delegate
*
* Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
*/
+/* jshint maxlen: false*/
+
/**
* @ngdoc service
* @name ng.$sce
* @function
*
@@ -21254,24 +22093,24 @@
* for those values that you can easily tell are safe - because they were received from your server,
* sanitized by your library, etc. You can organize your codebase to help with this - perhaps
* allowing only the files in a specific directory to do this. Ensuring that the internal API
* exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
*
- * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs} (and shorthand
- * methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to obtain values that will be
- * accepted by SCE / privileged contexts.
+ * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs}
+ * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to
+ * obtain values that will be accepted by SCE / privileged contexts.
*
*
* ## How does it work?
*
- * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
+ * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted
* $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
- * ng.$sce#parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
- * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
+ * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
+ * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
*
* As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
- * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
+ * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
* simplified):
*
* <pre class="prettyprint">
* var ngBindHtmlDirective = ['$sce', function($sce) {
* return function(scope, element, attr) {
@@ -21286,14 +22125,14 @@
*
* This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
* `templateUrl`'s specified by {@link guide/directive directives}.
*
* By default, Angular only loads templates from the same domain and protocol as the application
- * document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
+ * document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
* $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
- * protocols, you may either either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
- * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
+ * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist
+ * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value.
*
* *Please note*:
* The browser's
* {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
* Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
@@ -21309,34 +22148,35 @@
* If your expressions are constant literals, they're automatically trusted and you don't need to
* call `$sce.trustAs` on them. (e.g.
* `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
*
* Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
- * through {@link ng.$sce#getTrusted $sce.getTrusted}. SCE doesn't play a role here.
+ * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
*
* The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
* templates in `ng-include` from your application's domain without having to even know about SCE.
* It blocks loading templates from other domains or loading templates over http from an https
* served document. You can change these by setting your own custom {@link
- * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
- * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
+ * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link
+ * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs.
*
* This significantly reduces the overhead. It is far easier to pay the small overhead and have an
* application that's secure and can be audited to verify that with much more ease than bolting
* security onto an application later.
*
- * ## What trusted context types are supported?<a name="contexts"></a>
+ * <a name="contexts"></a>
+ * ## What trusted context types are supported?
*
* | Context | Notes |
* |---------------------|----------------|
* | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
* | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
* | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
* | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
* | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
*
- * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
+ * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
*
* Each element in these arrays must be one of the following:
*
* - **'self'**
* - The special **string**, `'self'`, can be used to match against all URLs of the **same
@@ -21377,69 +22217,72 @@
* and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
* Javascript lacks a similar built in function for escaping. Take a look at Google
* Closure library's [goog.string.regExpEscape(s)](
* http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
*
- * Refer {@link ng.$sceDelegateProvider#example $sceDelegateProvider} for an example.
+ * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
*
* ## Show me an example using SCE.
*
* @example
- <example module="mySceApp">
- <file name="index.html">
- <div ng-controller="myAppController as myCtrl">
- <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
- <b>User comments</b><br>
- By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when $sanitize is available. If $sanitize isn't available, this results in an error instead of an exploit.
- <div class="well">
- <div ng-repeat="userComment in myCtrl.userComments">
- <b>{{userComment.name}}</b>:
- <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
- <br>
- </div>
+<example module="mySceApp">
+<file name="index.html">
+ <div ng-controller="myAppController as myCtrl">
+ <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
+ <b>User comments</b><br>
+ By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
+ $sanitize is available. If $sanitize isn't available, this results in an error instead of an
+ exploit.
+ <div class="well">
+ <div ng-repeat="userComment in myCtrl.userComments">
+ <b>{{userComment.name}}</b>:
+ <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
+ <br>
</div>
</div>
- </file>
+ </div>
+</file>
- <file name="script.js">
- var mySceApp = angular.module('mySceApp', ['ngSanitize']);
+<file name="script.js">
+ var mySceApp = angular.module('mySceApp', ['ngSanitize']);
- mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
- var self = this;
- $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
- self.userComments = userComments;
- });
- self.explicitlyTrustedHtml = $sce.trustAsHtml(
- '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
- 'sanitization."">Hover over this text.</span>');
+ mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
+ var self = this;
+ $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
+ self.userComments = userComments;
});
- </file>
+ self.explicitlyTrustedHtml = $sce.trustAsHtml(
+ '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
+ 'sanitization."">Hover over this text.</span>');
+ });
+</file>
- <file name="test_data.json">
- [
- { "name": "Alice",
- "htmlComment": "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
- },
- { "name": "Bob",
- "htmlComment": "<i>Yes!</i> Am I the only other one?"
- }
- ]
- </file>
+<file name="test_data.json">
+[
+ { "name": "Alice",
+ "htmlComment":
+ "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
+ },
+ { "name": "Bob",
+ "htmlComment": "<i>Yes!</i> Am I the only other one?"
+ }
+]
+</file>
- <file name="scenario.js">
- describe('SCE doc demo', function() {
- it('should sanitize untrusted values', function() {
- expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
- });
- it('should NOT sanitize explicitly trusted values', function() {
- expect(element('#explicitlyTrustedHtml').html()).toBe(
- '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
- 'sanitization."">Hover over this text.</span>');
- });
+<file name="scenario.js">
+ describe('SCE doc demo', function() {
+ it('should sanitize untrusted values', function() {
+ expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
});
- </file>
- </example>
+ it('should NOT sanitize explicitly trusted values', function() {
+ expect(element('#explicitlyTrustedHtml').html()).toBe(
+ '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
+ 'sanitization."">Hover over this text.</span>');
+ });
+ });
+</file>
+</example>
*
*
*
* ## Can I disable SCE completely?
*
@@ -21458,10 +22301,11 @@
* $sceProvider.enabled(false);
* });
* </pre>
*
*/
+/* jshint maxlen: 100 */
function $SceProvider() {
var enabled = true;
/**
@@ -21503,17 +22347,17 @@
*
* - getTrusted(contextEnum, value)
* This function should return the a value that is safe to use in the context specified by
* contextEnum or throw and exception otherwise.
*
- * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be opaque
- * or wrapped in some holder object. That happens to be an implementation detail. For instance,
- * an implementation could maintain a registry of all trusted objects by context. In such a case,
- * trustAs() would return the same object that was passed in. getTrusted() would return the same
- * object passed in if it was found in the registry under a compatible context or throw an
- * exception otherwise. An implementation might only wrap values some of the time based on
- * some criteria. getTrusted() might return a value and not throw an exception for special
+ * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
+ * opaque or wrapped in some holder object. That happens to be an implementation detail. For
+ * instance, an implementation could maintain a registry of all trusted objects by context. In
+ * such a case, trustAs() would return the same object that was passed in. getTrusted() would
+ * return the same object passed in if it was found in the registry under a compatible context or
+ * throw an exception otherwise. An implementation might only wrap values some of the time based
+ * on some criteria. getTrusted() might return a value and not throw an exception for special
* constants or objects even if not wrapped. All such implementations fulfill this contract.
*
*
* A note on the inheritance model for SCE contexts
* ------------------------------------------------
@@ -21564,23 +22408,23 @@
sce.trustAs = $sceDelegate.trustAs;
sce.getTrusted = $sceDelegate.getTrusted;
sce.valueOf = $sceDelegate.valueOf;
if (!enabled) {
- sce.trustAs = sce.getTrusted = function(type, value) { return value; },
- sce.valueOf = identity
+ sce.trustAs = sce.getTrusted = function(type, value) { return value; };
+ sce.valueOf = identity;
}
/**
* @ngdoc method
* @name ng.$sce#parse
* @methodOf ng.$sce
*
* @description
* Converts Angular {@link guide/expression expression} into a function. This is like {@link
* ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it
- * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
+ * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*,
* *result*)}
*
* @param {string} type The kind of SCE context in which this result will be used.
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
@@ -21595,25 +22439,26 @@
if (parsed.literal && parsed.constant) {
return parsed;
} else {
return function sceParseAsTrusted(self, locals) {
return sce.getTrusted(type, parsed(self, locals));
- }
+ };
}
};
/**
* @ngdoc method
* @name ng.$sce#trustAs
* @methodOf ng.$sce
*
* @description
- * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}. As such, returns an object
- * that is trusted by angular for use in specified strict contextual escaping contexts (such as
- * ng-html-bind-unsafe, ng-include, any src attribute interpolation, any dom event binding
- * attribute interpolation such as for onclick, etc.) that uses the provided value. See *
- * {@link ng.$sce $sce} for enabling strict contextual escaping.
+ * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
+ * returns an objectthat is trusted by angular for use in specified strict contextual
+ * escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute
+ * interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
+ * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
+ * escaping.
*
* @param {string} type The kind of context in which this value is safe for use. e.g. url,
* resource_url, html, js and css.
* @param {*} value The value that that should be considered trusted/safe.
* @returns {*} A value that can be used to stand in for the provided `value` in places
@@ -21624,88 +22469,95 @@
* @ngdoc method
* @name ng.$sce#trustAsHtml
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.trustAsHtml(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
+ * Shorthand method. `$sce.trustAsHtml(value)` →
+ * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
*
* @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
+ * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml
* $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives
* only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
*/
/**
* @ngdoc method
* @name ng.$sce#trustAsUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.trustAsUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
+ * Shorthand method. `$sce.trustAsUrl(value)` →
+ * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`}
*
* @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
+ * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl
* $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives
* only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
*/
/**
* @ngdoc method
* @name ng.$sce#trustAsResourceUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.trustAsResourceUrl(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
+ * Shorthand method. `$sce.trustAsResourceUrl(value)` →
+ * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
*
* @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
+ * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl
* $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives
* only accept expressions that are either literal constants or are the return
- * value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ * value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
*/
/**
* @ngdoc method
* @name ng.$sce#trustAsJs
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.trustAsJs(value)` → {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
+ * Shorthand method. `$sce.trustAsJs(value)` →
+ * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`}
*
* @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
+ * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs
* $sce.getTrustedJs(value)} to obtain the original value. (privileged directives
* only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#trustAs $sce.trustAs}.)
+ * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
*/
/**
* @ngdoc method
* @name ng.$sce#getTrusted
* @methodOf ng.$sce
*
* @description
- * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}. As such, takes
- * the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the originally supplied
- * value if the queried context type is a supertype of the created type. If this condition
- * isn't satisfied, throws an exception.
+ * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}. As such,
+ * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the
+ * originally supplied value if the queried context type is a supertype of the created type.
+ * If this condition isn't satisfied, throws an exception.
*
* @param {string} type The kind of context in which this value is to be used.
- * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`} call.
- * @returns {*} The value the was originally provided to {@link ng.$sce#trustAs `$sce.trustAs`} if
- * valid in this context. Otherwise, throws an exception.
+ * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`}
+ * call.
+ * @returns {*} The value the was originally provided to
+ * {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context.
+ * Otherwise, throws an exception.
*/
/**
* @ngdoc method
* @name ng.$sce#getTrustedHtml
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.getTrustedHtml(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
+ * Shorthand method. `$sce.getTrustedHtml(value)` →
+ * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
*
* @param {*} value The value to pass to `$sce.getTrusted`.
* @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
*/
@@ -21713,11 +22565,12 @@
* @ngdoc method
* @name ng.$sce#getTrustedCss
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.getTrustedCss(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
+ * Shorthand method. `$sce.getTrustedCss(value)` →
+ * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
*
* @param {*} value The value to pass to `$sce.getTrusted`.
* @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
*/
@@ -21725,11 +22578,12 @@
* @ngdoc method
* @name ng.$sce#getTrustedUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.getTrustedUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
+ * Shorthand method. `$sce.getTrustedUrl(value)` →
+ * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
*
* @param {*} value The value to pass to `$sce.getTrusted`.
* @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
*/
@@ -21737,11 +22591,12 @@
* @ngdoc method
* @name ng.$sce#getTrustedResourceUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.getTrustedResourceUrl(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
+ * Shorthand method. `$sce.getTrustedResourceUrl(value)` →
+ * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
*
* @param {*} value The value to pass to `$sceDelegate.getTrusted`.
* @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
*/
@@ -21749,11 +22604,12 @@
* @ngdoc method
* @name ng.$sce#getTrustedJs
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.getTrustedJs(value)` → {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
+ * Shorthand method. `$sce.getTrustedJs(value)` →
+ * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
*
* @param {*} value The value to pass to `$sce.getTrusted`.
* @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
*/
@@ -21761,11 +22617,12 @@
* @ngdoc method
* @name ng.$sce#parseAsHtml
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.parseAsHtml(expression string)` → {@link ng.$sce#parse `$sce.parseAs($sce.HTML, value)`}
+ * Shorthand method. `$sce.parseAsHtml(expression string)` →
+ * {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
* * `context` – `{object}` – an object against which any expressions embedded in the strings
@@ -21778,11 +22635,12 @@
* @ngdoc method
* @name ng.$sce#parseAsCss
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.parseAsCss(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.CSS, value)`}
+ * Shorthand method. `$sce.parseAsCss(value)` →
+ * {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
* * `context` – `{object}` – an object against which any expressions embedded in the strings
@@ -21795,11 +22653,12 @@
* @ngdoc method
* @name ng.$sce#parseAsUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.parseAsUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.URL, value)`}
+ * Shorthand method. `$sce.parseAsUrl(value)` →
+ * {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
* * `context` – `{object}` – an object against which any expressions embedded in the strings
@@ -21812,11 +22671,12 @@
* @ngdoc method
* @name ng.$sce#parseAsResourceUrl
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.parseAsResourceUrl(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
+ * Shorthand method. `$sce.parseAsResourceUrl(value)` →
+ * {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
* * `context` – `{object}` – an object against which any expressions embedded in the strings
@@ -21829,11 +22689,12 @@
* @ngdoc method
* @name ng.$sce#parseAsJs
* @methodOf ng.$sce
*
* @description
- * Shorthand method. `$sce.parseAsJs(value)` → {@link ng.$sce#parse `$sce.parseAs($sce.JS, value)`}
+ * Shorthand method. `$sce.parseAsJs(value)` →
+ * {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`}
*
* @param {string} expression String expression to compile.
* @returns {function(context, locals)} a function which represents the compiled expression:
*
* * `context` – `{object}` – an object against which any expressions embedded in the strings
@@ -21849,17 +22710,17 @@
forEach(SCE_CONTEXTS, function (enumValue, name) {
var lName = lowercase(name);
sce[camelCase("parse_as_" + lName)] = function (expr) {
return parse(enumValue, expr);
- }
+ };
sce[camelCase("get_trusted_" + lName)] = function (value) {
return getTrusted(enumValue, value);
- }
+ };
sce[camelCase("trust_as_" + lName)] = function (value) {
return trustAs(enumValue, value);
- }
+ };
});
return sce;
}];
}
@@ -21880,11 +22741,12 @@
* This is very simple implementation of testing browser's features.
*/
function $SnifferProvider() {
this.$get = ['$window', '$document', function($window, $document) {
var eventSupport = {},
- android = int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
+ android =
+ int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
document = $document[0] || {},
vendorPrefix,
vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
bodyStyle = document.body && document.body.style,
@@ -21921,11 +22783,14 @@
// http://code.google.com/p/android/issues/detail?id=17471
// https://github.com/angular/angular.js/issues/904
// older webit browser (533.9) on Boxee box has exactly the same problem as Android has
// so let's not use the history API also
+ // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
+ // jshint -W018
history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
+ // jshint +W018
hashchange: 'onhashchange' in $window &&
// IE8 compatible mode lies
(!document.documentMode || document.documentMode > 7),
hasEvent: function(event) {
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
@@ -21938,14 +22803,15 @@
eventSupport[event] = 'on' + event in divElm;
}
return eventSupport[event];
},
- csp: document.securityPolicy ? document.securityPolicy.isActive : false,
+ csp: csp(),
vendorPrefix: vendorPrefix,
transitions : transitions,
- animations : animations
+ animations : animations,
+ msie : msie
};
}];
}
function $TimeoutProvider() {
@@ -21973,11 +22839,11 @@
* synchronously flush the queue of deferred functions.
*
* @param {function()} fn A function, whose execution should be delayed.
* @param {number=} [delay=0] Delay in milliseconds.
* @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
+ * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
* @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
* promise will be resolved with is the return value of the `fn` function.
*
* @example
<doc:example module="time">
@@ -22200,11 +23066,12 @@
host: urlParsingNode.host,
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
hostname: urlParsingNode.hostname,
port: urlParsingNode.port,
- pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ? urlParsingNode.pathname : '/' + urlParsingNode.pathname
+ pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ?
+ urlParsingNode.pathname : '/' + urlParsingNode.pathname
};
}
/**
@@ -22265,13 +23132,13 @@
/**
* @ngdoc object
* @name ng.$filterProvider
* @description
*
- * Filters are just functions which transform input to an output. However filters need to be Dependency Injected. To
- * achieve this a filter definition consists of a factory function which is annotated with dependencies and is
- * responsible for creating a filter function.
+ * Filters are just functions which transform input to an output. However filters need to be
+ * Dependency Injected. To achieve this a filter definition consists of a factory function which is
+ * annotated with dependencies and is responsible for creating a filter function.
*
* <pre>
* // Filter registration
* function MyModule($provide, $filterProvider) {
* // create a service to demonstrate injection (not always needed)
@@ -22290,11 +23157,13 @@
* };
* });
* }
* </pre>
*
- * The filter function is registered with the `$injector` under the filter name suffix with `Filter`.
+ * The filter function is registered with the `$injector` under the filter name suffix with
+ * `Filter`.
+ *
* <pre>
* it('should be the same instance', inject(
* function($filterProvider) {
* $filterProvider.register('reverse', function(){
* return ...;
@@ -22305,12 +23174,11 @@
* });
* </pre>
*
*
* For more information about how angular filters work, and how to create your own filters, see
- * {@link guide/dev_guide.templates.filters Understanding Angular Filters} in the angular Developer
- * Guide.
+ * {@link guide/filter Filters} in the Angular Developer Guide.
*/
/**
* @ngdoc method
* @name ng.$filterProvider#register
* @methodOf ng.$filterProvider
@@ -22367,10 +23235,22 @@
return $injector.get(name + suffix);
};
}];
////////////////////////////////////////
+
+ /* global
+ currencyFilter: false,
+ dateFilter: false,
+ filterFilter: false,
+ jsonFilter: false,
+ limitToFilter: false,
+ lowercaseFilter: false,
+ numberFilter: false,
+ orderByFilter: false,
+ uppercaseFilter: false,
+ */
register('currency', currencyFilter);
register('date', dateFilter);
register('filter', filterFilter);
register('json', jsonFilter);
@@ -22387,13 +23267,10 @@
* @function
*
* @description
* Selects a subset of items from `array` and returns it as a new array.
*
- * Note: This function is used to augment the `Array` type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
* @param {Array} array The source array.
* @param {string|Object|function()} expression The predicate to be used for selecting items from
* `array`.
*
* Can be one of:
@@ -22484,51 +23361,51 @@
});
</doc:scenario>
</doc:example>
*/
function filterFilter() {
- return function(array, expression, comperator) {
+ return function(array, expression, comparator) {
if (!isArray(array)) return array;
- var predicates = [];
+
+ var comparatorType = typeof(comparator),
+ predicates = [];
+
predicates.check = function(value) {
for (var j = 0; j < predicates.length; j++) {
if(!predicates[j](value)) {
return false;
}
}
return true;
};
- switch(typeof comperator) {
- case "function":
- break;
- case "boolean":
- if(comperator == true) {
- comperator = function(obj, text) {
- return angular.equals(obj, text);
- }
- break;
- }
- default:
- comperator = function(obj, text) {
+
+ if (comparatorType !== 'function') {
+ if (comparatorType === 'boolean' && comparator) {
+ comparator = function(obj, text) {
+ return angular.equals(obj, text);
+ };
+ } else {
+ comparator = function(obj, text) {
text = (''+text).toLowerCase();
return (''+obj).toLowerCase().indexOf(text) > -1;
};
+ }
}
+
var search = function(obj, text){
if (typeof text == 'string' && text.charAt(0) === '!') {
return !search(obj, text.substr(1));
}
switch (typeof obj) {
case "boolean":
case "number":
case "string":
- return comperator(obj, text);
+ return comparator(obj, text);
case "object":
switch (typeof text) {
case "object":
- return comperator(obj, text);
- break;
+ return comparator(obj, text);
default:
for ( var objKey in obj) {
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
return true;
}
@@ -22549,17 +23426,20 @@
};
switch (typeof expression) {
case "boolean":
case "number":
case "string":
+ // Set up expression object and fall through
expression = {$:expression};
+ // jshint -W086
case "object":
+ // jshint +W086
for (var key in expression) {
if (key == '$') {
(function() {
if (!expression[key]) return;
- var path = key
+ var path = key;
predicates.push(function(value) {
return search(value, expression[path]);
});
})();
} else {
@@ -22585,11 +23465,11 @@
if (predicates.check(value)) {
filtered.push(value);
}
}
return filtered;
- }
+ };
}
/**
* @ngdoc filter
* @name ng.filter:currency
@@ -22732,17 +23612,17 @@
number = Math.round(number * pow) / pow;
var fraction = ('' + number).split(DECIMAL_SEP);
var whole = fraction[0];
fraction = fraction[1] || '';
- var pos = 0,
+ var i, pos = 0,
lgroup = pattern.lgSize,
group = pattern.gSize;
if (whole.length >= (lgroup + group)) {
pos = whole.length - lgroup;
- for (var i = 0; i < pos; i++) {
+ for (i = 0; i < pos; i++) {
if ((pos - i)%group === 0 && i !== 0) {
formatedText += groupSep;
}
formatedText += whole.charAt(i);
}
@@ -22952,11 +23832,11 @@
tzHour = int(match[9] + match[10]);
tzMin = int(match[9] + match[11]);
}
dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
var h = int(match[4]||0) - tzHour;
- var m = int(match[5]||0) - tzMin
+ var m = int(match[5]||0) - tzMin;
var s = int(match[6]||0);
var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
timeSetter.call(date, h, m, s, ms);
return date;
}
@@ -23073,13 +23953,10 @@
* @description
* Creates a new array or string containing only a specified number of elements. The elements
* are taken from either the beginning or the end of the source array or string, as specified by
* the value and sign (positive or negative) of `limit`.
*
- * Note: This function is used to augment the `Array` type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
* @param {Array|string} input Source array or string to be limited.
* @param {string|number} limit The length of the returned array or string. If the `limit` number
* is positive, `limit` number of items from the beginning of the source array/string are copied.
* If the number is negative, `limit` number of items from the end of the source array/string
* are copied. The `limit` will be trimmed if it exceeds `array.length`
@@ -23163,24 +24040,21 @@
for (; i<n; i++) {
out.push(input[i]);
}
return out;
- }
+ };
}
/**
* @ngdoc function
* @name ng.filter:orderBy
* @function
*
* @description
* Orders a specified `array` by the `expression` predicate.
*
- * Note: this function is used to augment the `Array` type in Angular expressions. See
- * {@link ng.$filter} for more information about Angular arrays.
- *
* @param {Array} array The array to sort.
* @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
* used by the comparator to determine the order of elements.
*
* Can be one of:
@@ -23301,18 +24175,18 @@
return v1 < v2 ? -1 : 1;
} else {
return t1 < t2 ? -1 : 1;
}
}
- }
+ };
}
function ngDirective(directive) {
if (isFunction(directive)) {
directive = {
link: directive
- }
+ };
}
directive.restrict = directive.restrict || 'AC';
return valueFn(directive);
}
@@ -23353,11 +24227,11 @@
// if we have no href url, then don't navigate anywhere.
if (!element.attr('href')) {
event.preventDefault();
}
});
- }
+ };
}
});
/**
* @ngdoc directive
@@ -23706,10 +24580,11 @@
}
};
};
});
+/* global -nullFormCtrl */
var nullFormCtrl = {
$addControl: noop,
$removeControl: noop,
$setValidity: noop,
$setDirty: noop,
@@ -23911,11 +24786,11 @@
* @description
* Nestable alias of {@link ng.directive:form `form`} directive. HTML
* does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
* sub-group of controls needs to be determined.
*
- * @param {string=} name|ngForm Name of the form. If specified, the form controller will be published into
+ * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
* related scope, under this name.
*
*/
/**
@@ -23970,11 +24845,11 @@
* or {@link ng.directive:ngClick ngClick} directives.
* This is because of the following form submission rules in the HTML specification:
*
* - If a form has only one input field then hitting enter in this field triggers form submit
* (`ngSubmit`)
- * - if a form has has 2+ input fields and no buttons or input[type=submit] then hitting enter
+ * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
* doesn't trigger submit
* - if a form has one or more input fields and one or more buttons or input[type=submit] then
* hitting enter in any of the input fields will trigger the click handler on the *first* button or
* input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
*
@@ -24071,10 +24946,18 @@
};
var formDirective = formDirectiveFactory();
var ngFormDirective = formDirectiveFactory(true);
+/* global
+
+ -VALID_CLASS,
+ -INVALID_CLASS,
+ -PRISTINE_CLASS,
+ -DIRTY_CLASS
+*/
+
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
var inputType = {
@@ -24099,12 +24982,11 @@
* @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
* RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
* patterns defined as scope expressions.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
- * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trimming the
- * input.
+ * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
*
* @example
<doc:example>
<doc:source>
<script>
@@ -24607,12 +25489,12 @@
ctrl.$formatters.push(function(value) {
return ctrl.$isEmpty(value) ? '' : '' + value;
});
if (attr.min) {
- var min = parseFloat(attr.min);
var minValidator = function(value) {
+ var min = parseFloat(attr.min);
if (!ctrl.$isEmpty(value) && value < min) {
ctrl.$setValidity('min', false);
return undefined;
} else {
ctrl.$setValidity('min', true);
@@ -24623,12 +25505,12 @@
ctrl.$parsers.push(minValidator);
ctrl.$formatters.push(minValidator);
}
if (attr.max) {
- var max = parseFloat(attr.max);
var maxValidator = function(value) {
+ var max = parseFloat(attr.max);
if (!ctrl.$isEmpty(value) && value > max) {
ctrl.$setValidity('max', false);
return undefined;
} else {
ctrl.$setValidity('max', true);
@@ -24889,11 +25771,11 @@
* @property {*} $modelValue The value in the model, that the control is bound to.
* @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
the control reads value from the DOM. Each function is called, in turn, passing the value
through to the next. Used to sanitize / convert the value as well as validation.
For validation, the parsers should update the validity state using
- {@link ng.directive:ngModel.NgModelController#$setValidity $setValidity()},
+ {@link ng.directive:ngModel.NgModelController#methods_$setValidity $setValidity()},
and return `undefined` for invalid values.
*
* @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
the model value changes. Each function is called, in turn, passing the value through to the
@@ -25002,34 +25884,35 @@
* ## Isolated Scope Pitfall
*
* Note that if you have a directive with an isolated scope, you cannot require `ngModel`
* since the model value will be looked up on the isolated scope rather than the outer scope.
* When the directive updates the model value, calling `ngModel.$setViewValue()` the property
- * on the outer scope will not be updated.
+ * on the outer scope will not be updated. However you can get around this by using $parent.
*
- * Here is an example of this situation. You'll notice that even though both 'input' and 'div'
- * seem to be attached to the same model, they are not kept in synch.
+ * Here is an example of this situation. You'll notice that the first div is not updating the input.
+ * However the second div can update the input properly.
*
* <example module="badIsolatedDirective">
<file name="script.js">
- angular.module('badIsolatedDirective', []).directive('bad', function() {
- return {
- require: 'ngModel',
- scope: { },
- template: '<input ng-model="innerModel">',
- link: function(scope, element, attrs, ngModel) {
- scope.$watch('innerModel', function(value) {
- console.log(value);
- ngModel.$setViewValue(value);
- });
- }
- };
+ angular.module('badIsolatedDirective', []).directive('isolate', function() {
+ return {
+ require: 'ngModel',
+ scope: { },
+ template: '<input ng-model="innerModel">',
+ link: function(scope, element, attrs, ngModel) {
+ scope.$watch('innerModel', function(value) {
+ console.log(value);
+ ngModel.$setViewValue(value);
+ });
+ }
+ };
});
</file>
<file name="index.html">
- <input ng-model="someModel">
- <div bad ng-model="someModel"></div>
+ <input ng-model="someModel"/>
+ <div isolate ng-model="someModel"></div>
+ <div isolate ng-model="$parent.someModel"></div>
</file>
* </example>
*
*
*/
@@ -25070,14 +25953,14 @@
* @name { ng.directive:ngModel.NgModelController#$isEmpty
* @methodOf ng.directive:ngModel.NgModelController
*
* @description
* This is called when we need to determine if the value of the input is empty.
- *
+ *
* For instance, the required directive does this to work out if the input has data or not.
* The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
- *
+ *
* You can override this for input directives whose concept of being empty is different to the
* default. The `checkboxInputType` directive does this because in its case a value of `false`
* implies empty.
*/
this.$isEmpty = function(value) {
@@ -25118,11 +26001,14 @@
* for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
* class and can be bound to as `{{someForm.someControl.$error.myError}}` .
* @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
*/
this.$setValidity = function(validationErrorKey, isValid) {
+ // Purposeful use of ! here to cast isValid to boolean in case it is undefined
+ // jshint -W018
if ($error[validationErrorKey] === !isValid) return;
+ // jshint +W018
if (isValid) {
if ($error[validationErrorKey]) invalidCount--;
if (!invalidCount) {
toggleValidCss(true);
@@ -25198,11 +26084,11 @@
try {
listener();
} catch(e) {
$exceptionHandler(e);
}
- })
+ });
}
};
// model -> value
var ctrl = this;
@@ -25281,11 +26167,11 @@
var modelCtrl = ctrls[0],
formCtrl = ctrls[1] || nullFormCtrl;
formCtrl.$addControl(modelCtrl);
- element.on('$destroy', function() {
+ scope.$on('$destroy', function() {
formCtrl.$removeControl(modelCtrl);
});
}
};
};
@@ -25547,12 +26433,12 @@
* expression changes.
*
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
* `{{ expression }}` which is similar but less verbose.
*
- * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
- * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
+ * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
+ * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading.
*
* An alternative solution to this problem would be using the
* {@link ng.directive:ngCloak ngCloak} directive.
*
@@ -25584,10 +26470,13 @@
</doc:example>
*/
var ngBindDirective = ngDirective(function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBind);
scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
+ // We are purposefully using == here rather than === because we want to
+ // catch when value is "null or undefined"
+ // jshint -W041
element.text(value == undefined ? '' : value);
});
});
@@ -25645,11 +26534,11 @@
var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
element.addClass('ng-binding').data('$binding', interpolateFn);
attr.$observe('ngBindTemplate', function(value) {
element.text(value);
});
- }
+ };
}];
/**
* @ngdoc directive
@@ -25659,18 +26548,41 @@
* Creates a binding that will innerHTML the result of evaluating the `expression` into the current
* element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
* ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
* is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
* core Angular.) You may also bypass sanitization for values you know are safe. To do so, bind to
- * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}. See the example
+ * an explicitly trusted value via {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}. See the example
* under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
*
* Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
* will have an exception (instead of an exploit.)
*
* @element ANY
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
+ *
+ * @example
+ * Try it here: enter text in text box and watch the greeting change.
+ <doc:example module="ngBindHtmlExample" deps="angular-sanitize.js" >
+ <doc:source>
+ <script>
+ angular.module('ngBindHtmlExample', ['ngSanitize'])
+
+ .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
+ $scope.myHTML = 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
+ }]);
+ </script>
+ <div ng-controller="ngBindHtmlCtrl">
+ <p ng-bind-html="myHTML"></p>
+ </div>
+ </doc:source>
+ <doc:scenario>
+ it('should check ng-bind-html', function() {
+ expect(using('.doc-example-live').binding('myHTML')).
+ toBe('I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>');
+ });
+ </doc:scenario>
+ </doc:example>
*/
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
@@ -25687,21 +26599,22 @@
name = 'ngClass' + name;
return function() {
return {
restrict: 'AC',
link: function(scope, element, attr) {
- var oldVal = undefined;
+ var oldVal;
scope.$watch(attr[name], ngClassWatchAction, true);
attr.$observe('class', function(value) {
ngClassWatchAction(scope.$eval(attr[name]));
});
if (name !== 'ngClass') {
scope.$watch('$index', function($index, old$index) {
+ // jshint bitwise: false
var mod = $index & 1;
if (mod !== old$index & 1) {
if (mod === selector) {
addClass(scope.$eval(attr[name]));
} else {
@@ -25744,11 +26657,11 @@
});
return classes.join(' ');
}
return classVal;
- };
+ }
}
};
};
}
@@ -25775,11 +26688,11 @@
* of the evaluation can be a string representing space delimited class
* names, an array, or a map of class names to boolean values. In the case of a map, the
* names of the properties whose values are truthy will be added as css classes to the
* element.
*
- * @example Example that demostrates basic bindings via ngClass directive.
+ * @example Example that demonstrates basic bindings via ngClass directive.
<example>
<file name="index.html">
<p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
<input type="checkbox" ng-model="bold"> bold
<input type="checkbox" ng-model="strike"> strike
@@ -25840,30 +26753,22 @@
<example animations="true">
<file name="index.html">
<input type="button" value="set" ng-click="myVar='my-class'">
<input type="button" value="clear" ng-click="myVar=''">
<br>
- <span ng-class="myVar">Sample Text</span>
+ <span class="base-class" ng-class="myVar">Sample Text</span>
</file>
<file name="style.css">
- .my-class-add, .my-class-remove {
+ .base-class {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
- .my-class,
- .my-class-add.my-class-add-active {
+ .base-class.my-class {
color: red;
font-size:3em;
}
-
- .my-class-remove.my-class-remove-active {
- font-size:1.0em;
- color:black;
- }
</file>
<file name="scenario.js">
it('should check ng-class', function() {
expect(element('.doc-example-live span').prop('className')).not().
toMatch(/my-class/);
@@ -25882,14 +26787,14 @@
</example>
## ngClass and pre-existing CSS3 Transitions/Animations
The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
- Therefore, if any CSS3 Transition/Animation styles (outside of ngAnimate) are set on the element, then, if a ngClass animation
- is triggered, the ngClass animation will be skipped so that ngAnimate can allow for the pre-existing transition or animation to
- take over. This restriction allows for ngClass to still work with standard CSS3 Transitions/Animations that are defined
- outside of ngAnimate.
+ Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
+ any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
+ to view the step by step details of {@link ngAnimate.$animate#methods_addclass $animate.addClass} and
+ {@link ngAnimate.$animate#methods_removeclass $animate.removeClass}.
*/
var ngClassDirective = classDirective('', true);
/**
* @ngdoc directive
@@ -26000,11 +26905,12 @@
* The directive can be applied to the `<body>` element, but the preferred usage is to apply
* multiple `ngCloak` directives to small portions of the page to permit progressive rendering
* of the browser view.
*
* `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
- * `angular.min.js`:
+ * `angular.min.js`.
+ * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
*
* <pre>
* [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
* display: none !important;
* }
@@ -26063,11 +26969,14 @@
* are accessed through bindings.
* * View — The template (HTML with data bindings) that is rendered into the View.
* * Controller — The `ngController` directive specifies a Controller class; the class contains business
* logic behind the application to decorate the scope with functions and values
*
- * Note that an alternative way to define controllers is via the {@link ngRoute.$route $route} service.
+ * Note that you can also attach controllers to the DOM by declaring it in a route definition
+ * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
+ * again using `ng-controller` in the template itself. This will cause the controller to be attached
+ * and executed twice.
*
* @element ANY
* @scope
* @param {expression} ngController Name of a globally accessible constructor function or an
* {@link guide/expression expression} that on the current scope evaluates to a
@@ -26218,29 +27127,34 @@
}];
/**
* @ngdoc directive
* @name ng.directive:ngCsp
- * @priority 1000
*
* @element html
* @description
* Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
- *
+ *
* This is necessary when developing things like Google Chrome Extensions.
- *
+ *
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating
* any of these restrictions.
- *
+ *
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
* evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
* be raised.
- *
+ *
+ * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
+ * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
+ * To make those directives work in CSP mode, include the `angular-csp.css` manually.
+ *
* In order to use this feature put the `ngCsp` directive on the root element of the application.
- *
+ *
+ * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
+ *
* @example
* This example shows how to apply the `ngCsp` directive to the `html` tag.
<pre>
<!doctype html>
<html ng-app ng-csp>
@@ -26248,18 +27162,13 @@
...
</html>
</pre>
*/
-var ngCspDirective = ['$sniffer', function($sniffer) {
- return {
- priority: 1000,
- compile: function() {
- $sniffer.csp = true;
- }
- };
-}];
+// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
+// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
+// anywhere in the current doc
/**
* @ngdoc directive
* @name ng.directive:ngClick
*
@@ -26298,17 +27207,21 @@
forEach(
'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
function(name) {
var directiveName = directiveNormalize('ng-' + name);
ngEventDirectives[directiveName] = ['$parse', function($parse) {
- return function(scope, element, attr) {
- var fn = $parse(attr[directiveName]);
- element.on(lowercase(name), function(event) {
- scope.$apply(function() {
- fn(scope, {$event:event});
- });
- });
+ return {
+ compile: function($element, attr) {
+ var fn = $parse(attr[directiveName]);
+ return function(scope, element, attr) {
+ element.on(lowercase(name), function(event) {
+ scope.$apply(function() {
+ fn(scope, {$event:event});
+ });
+ });
+ };
+ }
};
}];
}
);
@@ -26638,11 +27551,11 @@
* @element ANY
* @scope
* @priority 600
* @param {expression} ngIf If the {@link guide/expression expression} is falsy then
* the element is removed from the DOM tree. If it is truthy a copy of the compiled
- * eleent is added to the DOM tree.
+ * element is added to the DOM tree.
*
* @example
<example animations="true">
<file name="index.html">
Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
@@ -26656,24 +27569,25 @@
background:white;
border:1px solid black;
padding:10px;
}
+ /*
+ The transition styles can also be placed on the CSS base class above
+ */
.animate-if.ng-enter, .animate-if.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
.animate-if.ng-enter,
.animate-if.ng-leave.ng-leave-active {
opacity:0;
}
- .animate-if.ng-enter.ng-enter-active,
- .animate-if.ng-leave {
+ .animate-if.ng-leave,
+ .animate-if.ng-enter.ng-enter-active {
opacity:1;
}
</file>
</example>
*/
@@ -26681,33 +27595,43 @@
return {
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
+ $$tlb: true,
compile: function (element, attr, transclude) {
return function ($scope, $element, $attr) {
- var childElement, childScope;
+ var block, childScope;
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
- if (childElement) {
- $animate.leave(childElement);
- childElement = undefined;
- }
- if (childScope) {
- childScope.$destroy();
- childScope = undefined;
- }
+
if (toBoolean(value)) {
+
childScope = $scope.$new();
transclude(childScope, function (clone) {
- childElement = clone;
+ block = {
+ startNode: clone[0],
+ endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
+ };
$animate.enter(clone, $element.parent(), $element);
});
+
+ } else {
+
+ if (childScope) {
+ childScope.$destroy();
+ childScope = null;
+ }
+
+ if (block) {
+ $animate.leave(getBlockElements(block));
+ block = null;
+ }
}
});
- }
+ };
}
- }
+ };
}];
/**
* @ngdoc directive
* @name ng.directive:ngInclude
@@ -26715,14 +27639,14 @@
*
* @description
* Fetches, compiles and includes an external HTML fragment.
*
* By default, the template URL is restricted to the same domain and protocol as the
- * application document. This is done by calling {@link ng.$sce#getTrustedResourceUrl
+ * application document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
* $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
- * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
- * {@link ng.$sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
+ * you may either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist them} or
+ * {@link ng.$sce#methods_trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
* ng.$sce Strict Contextual Escaping}.
*
* In addition, the browser's
* {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
* Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
@@ -26757,12 +27681,12 @@
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
url of the template: <tt>{{template.url}}</tt>
<hr/>
- <div class="example-animate-container">
- <div class="include-example" ng-include="template.url"></div>
+ <div class="slide-animate-container">
+ <div class="slide-animate" ng-include="template.url"></div>
</div>
</div>
</file>
<file name="script.js">
function Ctrl($scope) {
@@ -26777,26 +27701,24 @@
</file>
<file name="template2.html">
Content of template2.html
</file>
<file name="animations.css">
- .example-animate-container {
+ .slide-animate-container {
position:relative;
background:white;
border:1px solid black;
height:40px;
overflow:hidden;
}
- .example-animate-container > div {
+ .slide-animate {
padding:10px;
}
- .include-example.ng-enter, .include-example.ng-leave {
+ .slide-animate.ng-enter, .slide-animate.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
position:absolute;
top:0;
left:0;
@@ -26804,21 +27726,21 @@
bottom:0;
display:block;
padding:10px;
}
- .include-example.ng-enter {
+ .slide-animate.ng-enter {
top:-50px;
}
- .include-example.ng-enter.ng-enter-active {
+ .slide-animate.ng-enter.ng-enter-active {
top:0;
}
- .include-example.ng-leave {
+ .slide-animate.ng-leave {
top:0;
}
- .include-example.ng-leave.ng-leave-active {
+ .slide-animate.ng-leave.ng-leave-active {
top:50px;
}
</file>
<file name="scenario.js">
it('should load template1.html', function() {
@@ -26884,10 +27806,15 @@
currentElement = null;
}
};
scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
+ var afterAnimation = function() {
+ if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
+ $anchorScroll();
+ }
+ };
var thisChangeId = ++changeCounter;
if (src) {
$http.get(src, {cache: $templateCache}).success(function(response) {
if (thisChangeId !== changeCounter) return;
@@ -26898,17 +27825,12 @@
currentScope = newScope;
currentElement = clone;
currentElement.html(response);
- $animate.enter(currentElement, null, $element);
+ $animate.enter(currentElement, null, $element, afterAnimation);
$compile(currentElement.contents())(currentScope);
-
- if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
- $anchorScroll();
- }
-
currentScope.$emit('$includeContentLoaded');
scope.$eval(onloadExp);
});
}).error(function() {
if (thisChangeId === changeCounter) cleanupLastIncludeContent();
@@ -26933,11 +27855,11 @@
* current scope.
*
* <div class="alert alert-error">
* The only appropriate use of `ngInit` for aliasing special properties of
* {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
- * should use {@link guide/dev_guide.mvc.understanding_controller controllers} rather than `ngInit`
+ * should use {@link guide/controller controllers} rather than `ngInit`
* to initialize values on a scope.
* </div>
*
* @element ANY
* @param {expression} ngInit {@link guide/expression Expression} to eval.
@@ -26973,11 +27895,11 @@
compile: function() {
return {
pre: function(scope, element, attrs) {
scope.$eval(attrs.ngInit);
}
- }
+ };
}
});
/**
* @ngdoc directive
@@ -26987,11 +27909,11 @@
*
* @description
* The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
* DOM element. This is useful if the element contains what appears to be Angular directives and
* bindings but which should be ignored by Angular. This could be the case if you have a site that
- * displays snippets of code. for instance.
+ * displays snippets of code, for instance.
*
* @element ANY
*
* @example
* In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
@@ -27364,53 +28286,39 @@
.example-animate-container {
background:white;
border:1px solid black;
list-style:none;
margin:0;
- padding:0;
+ padding:0 10px;
}
- .example-animate-container > li {
- padding:10px;
+ .animate-repeat {
+ line-height:40px;
list-style:none;
+ box-sizing:border-box;
}
+ .animate-repeat.ng-move,
.animate-repeat.ng-enter,
- .animate-repeat.ng-leave,
- .animate-repeat.ng-move {
+ .animate-repeat.ng-leave {
-webkit-transition:all linear 0.5s;
- -moz-transition:all linear 0.5s;
- -o-transition:all linear 0.5s;
transition:all linear 0.5s;
}
+ .animate-repeat.ng-leave.ng-leave-active,
+ .animate-repeat.ng-move,
.animate-repeat.ng-enter {
- line-height:0;
opacity:0;
- padding-top:0;
- padding-bottom:0;
+ max-height:0;
}
+
+ .animate-repeat.ng-leave,
+ .animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
- line-height:20px;
opacity:1;
- padding:10px;
+ max-height:40px;
}
-
- .animate-repeat.ng-leave {
- opacity:1;
- line-height:20px;
- padding:10px;
- }
- .animate-repeat.ng-leave.ng-leave-active {
- opacity:0;
- line-height:0;
- padding-top:0;
- padding-bottom:0;
- }
-
- .animate-repeat.ng-move { }
- .animate-repeat.ng-move.ng-move-active { }
</file>
<file name="scenario.js">
it('should render initial data set', function() {
var r = using('.doc-example-live').repeater('ul li');
expect(r.count()).toBe(10);
@@ -27438,10 +28346,11 @@
var ngRepeatMinErr = minErr('ngRepeat');
return {
transclude: 'element',
priority: 1000,
terminal: true,
+ $$tlb: true,
compile: function(element, attr, linker) {
return function($scope, $element, $attr){
var expression = $attr.ngRepeat;
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
@@ -27467,14 +28376,14 @@
return trackByExpGetter($scope, hashFnLocals);
};
} else {
trackByIdArrayFn = function(key, value) {
return hashKey(value);
- }
+ };
trackByIdObjFn = function(key) {
return key;
- }
+ };
}
match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
if (!match) {
throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
@@ -27532,11 +28441,11 @@
key = (collection === collectionKeys) ? index : collectionKeys[index];
value = collection[key];
trackById = trackByIdFn(key, value, index);
assertNotHasOwnProperty(trackById, '`track by` id');
if(lastBlockMap.hasOwnProperty(trackById)) {
- block = lastBlockMap[trackById]
+ block = lastBlockMap[trackById];
delete lastBlockMap[trackById];
nextBlockMap[trackById] = block;
nextBlockOrder[index] = block;
} else if (nextBlockMap.hasOwnProperty(trackById)) {
// restore lastBlockMap
@@ -27580,13 +28489,11 @@
nextNode = previousNode;
do {
nextNode = nextNode.nextSibling;
} while(nextNode && nextNode[NG_REMOVED]);
- if (block.startNode == nextNode) {
- // do nothing
- } else {
+ if (block.startNode != nextNode) {
// existing item which got moved
$animate.move(getBlockElements(block), null, jqLite(previousNode));
}
previousNode = block.endNode;
} else {
@@ -27598,11 +28505,13 @@
if (keyIdentifier) childScope[keyIdentifier] = key;
childScope.$index = index;
childScope.$first = (index === 0);
childScope.$last = (index === (arrayLength - 1));
childScope.$middle = !(childScope.$first || childScope.$last);
- childScope.$odd = !(childScope.$even = index%2==0);
+ // jshint bitwise: false
+ childScope.$odd = !(childScope.$even = (index&1) === 0);
+ // jshint bitwise: true
if (!block.startNode) {
linker(childScope, function(clone) {
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
$animate.enter(clone, null, jqLite(previousNode));
@@ -27617,27 +28526,10 @@
lastBlockMap = nextBlockMap;
});
};
}
};
-
- function getBlockElements(block) {
- if (block.startNode === block.endNode) {
- return jqLite(block.startNode);
- }
-
- var element = block.startNode;
- var elements = [element];
-
- do {
- element = element.nextSibling;
- if (!element) break;
- elements.push(element);
- } while (element !== block.endNode);
-
- return jqLite(elements);
- }
}];
/**
* @ngdoc directive
* @name ng.directive:ngShow
@@ -27645,10 +28537,11 @@
* @description
* The `ngShow` directive shows or hides the given HTML element based on the expression
* provided to the ngShow attribute. The element is shown or hidden by removing or adding
* the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
* in AngularJS and sets the display style to none (using an !important flag).
+ * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
*
* <pre>
* <!-- when $scope.myValue is truthy (element is visible) -->
* <div ng-show="myValue"></div>
*
@@ -27735,35 +28628,31 @@
<span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
</div>
</div>
</file>
<file name="animations.css">
- .animate-show.ng-hide-add,
- .animate-show.ng-hide-remove {
+ .animate-show {
-webkit-transition:all linear 0.5s;
- -moz-transition:all linear 0.5s;
- -o-transition:all linear 0.5s;
transition:all linear 0.5s;
- display:block!important;
+ line-height:20px;
+ opacity:1;
+ padding:10px;
+ border:1px solid black;
+ background:white;
}
- .animate-show.ng-hide-add.ng-hide-add-active,
+ .animate-show.ng-hide-add,
.animate-show.ng-hide-remove {
+ display:block!important;
+ }
+
+ .animate-show.ng-hide {
line-height:0;
opacity:0;
padding:0 10px;
}
- .animate-show.ng-hide-add,
- .animate-show.ng-hide-remove.ng-hide-remove-active {
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
- }
-
.check-element {
padding:10px;
border:1px solid black;
background:white;
}
@@ -27797,10 +28686,11 @@
* @description
* The `ngHide` directive shows or hides the given HTML element based on the expression
* provided to the ngHide attribute. The element is shown or hidden by removing or adding
* the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
* in AngularJS and sets the display style to none (using an !important flag).
+ * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
*
* <pre>
* <!-- when $scope.myValue is truthy (element is hidden) -->
* <div ng-hide="myValue"></div>
*
@@ -27887,35 +28777,31 @@
<span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
</div>
</div>
</file>
<file name="animations.css">
- .animate-hide.ng-hide-add,
- .animate-hide.ng-hide-remove {
+ .animate-hide {
-webkit-transition:all linear 0.5s;
- -moz-transition:all linear 0.5s;
- -o-transition:all linear 0.5s;
transition:all linear 0.5s;
- display:block!important;
+ line-height:20px;
+ opacity:1;
+ padding:10px;
+ border:1px solid black;
+ background:white;
}
- .animate-hide.ng-hide-add.ng-hide-add-active,
+ .animate-hide.ng-hide-add,
.animate-hide.ng-hide-remove {
+ display:block!important;
+ }
+
+ .animate-hide.ng-hide {
line-height:0;
opacity:0;
padding:0 10px;
}
- .animate-hide.ng-hide-add,
- .animate-hide.ng-hide-remove.ng-hide-remove-active {
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
- }
-
.check-element {
padding:10px;
border:1px solid black;
background:white;
}
@@ -28040,13 +28926,13 @@
</select>
<tt>selection={{selection}}</tt>
<hr/>
<div class="animate-switch-container"
ng-switch on="selection">
- <div ng-switch-when="settings">Settings Div</div>
- <div ng-switch-when="home">Home Span</div>
- <div ng-switch-default>default</div>
+ <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
+ <div class="animate-switch" ng-switch-when="home">Home Span</div>
+ <div class="animate-switch" ng-switch-default>default</div>
</div>
</div>
</file>
<file name="script.js">
function Ctrl($scope) {
@@ -28061,41 +28947,33 @@
border:1px solid black;
height:40px;
overflow:hidden;
}
- .animate-switch-container > div {
+ .animate-switch {
padding:10px;
}
- .animate-switch-container > .ng-enter,
- .animate-switch-container > .ng-leave {
+ .animate-switch.ng-animate {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -moz-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- -o-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
}
- .animate-switch-container > .ng-enter {
+ .animate-switch.ng-leave.ng-leave-active,
+ .animate-switch.ng-enter {
top:-50px;
}
- .animate-switch-container > .ng-enter.ng-enter-active {
+ .animate-switch.ng-leave,
+ .animate-switch.ng-enter.ng-enter-active {
top:0;
}
-
- .animate-switch-container > .ng-leave {
- top:0;
- }
- .animate-switch-container > .ng-leave.ng-leave-active {
- top:50px;
- }
</file>
<file name="scenario.js">
it('should start in settings', function() {
expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
});
@@ -28147,11 +29025,11 @@
});
});
}
});
}
- }
+ };
}];
var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
priority: 800,
@@ -28390,11 +29268,11 @@
<select ng-model="color" ng-options="c.name for c in colors"></select><br>
Color (null allowed):
<span class="nullable">
<select ng-model="color" ng-options="c.name for c in colors">
- <option value="">-- chose color --</option>
+ <option value="">-- choose color --</option>
</select>
</span><br/>
Color grouped by shade:
<select ng-model="color" ng-options="c.name group by c.shade for c in colors">
@@ -28420,14 +29298,16 @@
</doc:scenario>
</doc:example>
*/
var ngOptionsDirective = valueFn({ terminal: true });
+// jshint maxlen: false
var selectDirective = ['$compile', '$parse', function($compile, $parse) {
//0000111110000000000022220000000000000000000000333300000000000000444444444444444000000000555555555555555000000066666666666666600000000000000007777000000000000000000088888
var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
nullModelCtrl = {$setViewValue: noop};
+// jshint maxlen: 100
return {
restrict: 'E',
require: ['select', '?ngModel'],
controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
@@ -28504,11 +29384,11 @@
optGroupTemplate =jqLite(document.createElement('optgroup')),
unknownOption = optionTemplate.clone();
// find "null" option
for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
- if (children[i].value == '') {
+ if (children[i].value === '') {
emptyOption = nullOption = children.eq(i);
break;
}
}
@@ -28527,20 +29407,20 @@
attr.$observe('required', function() {
requiredValidator(ngModelCtrl.$viewValue);
});
}
- if (optionsExp) Options(scope, element, ngModelCtrl);
- else if (multiple) Multiple(scope, element, ngModelCtrl);
- else Single(scope, element, ngModelCtrl, selectCtrl);
+ if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
+ else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
+ else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
////////////////////////////
- function Single(scope, selectElement, ngModelCtrl, selectCtrl) {
+ function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
ngModelCtrl.$render = function() {
var viewValue = ngModelCtrl.$viewValue;
if (selectCtrl.hasOption(viewValue)) {
if (unknownOption.parent()) unknownOption.remove();
@@ -28561,11 +29441,11 @@
ngModelCtrl.$setViewValue(selectElement.val());
});
});
}
- function Multiple(scope, selectElement, ctrl) {
+ function setupAsMultiple(scope, selectElement, ctrl) {
var lastView;
ctrl.$render = function() {
var items = new HashMap(ctrl.$viewValue);
forEach(selectElement.find('option'), function(option) {
option.selected = isDefined(items.get(option.value));
@@ -28592,16 +29472,18 @@
ctrl.$setViewValue(array);
});
});
}
- function Options(scope, selectElement, ctrl) {
+ function setupAsOptions(scope, selectElement, ctrl) {
var match;
if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
throw ngOptionsMinErr('iexp',
- "Expected expression in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '{0}'. Element: {1}",
+ "Expected expression in form of " +
+ "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
+ " but got '{0}'. Element: {1}",
optionsExp, startingTag(selectElement));
}
var displayFn = $parse(match[2] || match[1]),
valueName = match[4] || match[6],
@@ -28609,13 +29491,14 @@
groupByFn = $parse(match[3] || ''),
valueFn = $parse(match[2] ? match[1] : valueName),
valuesFn = $parse(match[7]),
track = match[8],
trackFn = track ? $parse(match[8]) : null,
- // This is an array of array of existing option groups in DOM. We try to reuse these if possible
- // optionGroupsCache[0] is the options with no option group
- // optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
+ // This is an array of array of existing option groups in DOM.
+ // We try to reuse these if possible
+ // - optionGroupsCache[0] is the options with no option group
+ // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
optionGroupsCache = [[{element: selectElement, label:''}]];
if (nullOption) {
// compile the element since there might be bindings in it
$compile(nullOption)(scope);
@@ -28665,11 +29548,11 @@
}
} else {
key = selectElement.val();
if (key == '?') {
value = undefined;
- } else if (key == ''){
+ } else if (key === ''){
value = null;
} else {
if (trackFn) {
for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
locals[valueName] = collection[trackIndex];
@@ -28693,11 +29576,12 @@
// TODO(vojta): can't we optimize this ?
scope.$watch(render);
function render() {
- var optionGroups = {'':[]}, // Temporary location for the option groups before we render them
+ // Temporary location for the option groups before we render them
+ var optionGroups = {'':[]},
optionGroupNames = [''],
optionGroupName,
optionGroup,
option,
existingParent, existingOptions, existingOption,
@@ -28742,11 +29626,13 @@
if (!(optionGroup = optionGroups[optionGroupName])) {
optionGroup = optionGroups[optionGroupName] = [];
optionGroupNames.push(optionGroupName);
}
if (multiple) {
- selected = selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals)) !== undefined;
+ selected = isDefined(
+ selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
+ );
} else {
if (trackFn) {
var modelCast = {};
modelCast[valueName] = modelValue;
selected = trackFn(scope, modelCast) === trackFn(scope, locals);
@@ -28754,13 +29640,16 @@
selected = modelValue === valueFn(scope, locals);
}
selectedSet = selectedSet || selected; // see if at least one item is selected
}
label = displayFn(scope, locals); // what will be seen by the user
- label = label === undefined ? '' : label; // doing displayFn(scope, locals) || '' overwrites zero values
+
+ // doing displayFn(scope, locals) || '' overwrites zero values
+ label = isDefined(label) ? label : '';
optionGroup.push({
- id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index), // either the index into array or key from object
+ // either the index into array or key from object
+ id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
label: label,
selected: selected // determine if we should be selected
});
}
if (!multiple) {
@@ -28955,10 +29844,11 @@
* @param {function()} fn Factory function(), return a function for
* the statement.
*/
angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
angular.scenario.dsl[name] = function() {
+ /* jshint -W040 *//* The dsl binds `this` for us when calling chained functions */
function executeStatement(statement, args) {
var result = statement.apply(this, args);
if (angular.isFunction(result) || result instanceof angular.scenario.Future)
return result;
var self = this;
@@ -29186,19 +30076,19 @@
bindExp = bindExp.replace(/\s/g, '');
match = function (actualExp) {
if (actualExp) {
actualExp = actualExp.replace(/\s/g, '');
if (actualExp == bindExp) return true;
- if (actualExp.indexOf(bindExp) == 0) {
+ if (actualExp.indexOf(bindExp) === 0) {
return actualExp.charAt(bindExp.length) == '|';
}
}
- }
+ };
} else if (bindExp) {
match = function(actualExp) {
return actualExp && bindExp.exec(actualExp);
- }
+ };
} else {
match = function(actualExp) {
return !!actualExp;
};
}
@@ -29206,11 +30096,11 @@
if (this.is(bindSelector)) {
selection = selection.add(this);
}
function push(value) {
- if (value == undefined) {
+ if (value === undefined) {
value = '';
} else if (typeof value != 'string') {
value = angular.toJson(value);
}
result.push('' + value);
@@ -29265,12 +30155,12 @@
* Triggers a browser event. Attempts to choose the right event if one is
* not specified.
*
* @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
* @param {string} eventType Optional event type
- * @param {Object=} eventData An optional object which contains additional event data (such as x,y coordinates, keys, etc...) that
- * are passed into the event when triggered
+ * @param {Object=} eventData An optional object which contains additional event data (such as x,y
+ * coordinates, keys, etc...) that are passed into the event when triggered
*/
window.browserTrigger = function browserTrigger(element, eventType, eventData) {
if (element && !element.nodeName) element = element[0];
if (!element) return;
@@ -29369,12 +30259,12 @@
}
else {
evnt = document.createEvent('MouseEvents');
x = x || 0;
y = y || 0;
- evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'), pressed('alt'),
- pressed('shift'), pressed('meta'), 0, element);
+ evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
+ pressed('alt'), pressed('shift'), pressed('meta'), 0, element);
}
/* we're unable to change the timeStamp value directly so this
* is only here to allow for testing where the timeStamp value is
* read */
@@ -29400,11 +30290,11 @@
delete angular['ff-684208-preventDefault'];
return finalProcessDefault;
}
- }
+ };
}());
/**
* Represents the application currently being tested and abstracts usage
* of iframes or separate windows.
@@ -29473,19 +30363,14 @@
try {
var $window = self.getWindow_();
if ($window.angular) {
// Disable animations
-
- // TODO(i): this doesn't disable javascript animations
- // we don't need that for our tests, but it should be done
$window.angular.resumeBootstrap([['$provide', function($provide) {
- $provide.decorator('$sniffer', function($delegate) {
- $delegate.transitions = false;
- $delegate.animations = false;
- return $delegate;
- });
+ return ['$animate', function($animate) {
+ $animate.enabled(false);
+ }];
}]]);
}
self.executeAction(loadFn);
} catch (e) {
@@ -29812,11 +30697,11 @@
self.emit('SpecEnd', it);
});
runner.on('StepBegin', function(spec, step) {
var it = self.getSpec(spec.id);
- var step = new angular.scenario.ObjectModel.Step(step.name);
+ step = new angular.scenario.ObjectModel.Step(step.name);
it.steps.push(step);
// forward the event
self.emit('StepBegin', it, step);
});
@@ -29886,12 +30771,13 @@
*
* @param {string} eventName Name of the event to fire.
*/
angular.scenario.ObjectModel.prototype.emit = function(eventName) {
var self = this,
- args = Array.prototype.slice.call(arguments, 1),
- eventName = eventName.toLowerCase();
+ args = Array.prototype.slice.call(arguments, 1);
+
+ eventName = eventName.toLowerCase();
if (this.listeners[eventName]) {
angular.forEach(this.listeners[eventName], function(listener) {
listener.apply(self, args);
});
@@ -30239,11 +31125,12 @@
/**
* Executes a spec which is an it block with associated before/after functions
* based on the describe nesting.
*
* @param {Object} spec A spec object
- * @param {function()} specDone function that is called when the spec finishes. Function(error, index)
+ * @param {function()} specDone function that is called when the spec finishes,
+ * of the form `Function(error, index)`
*/
angular.scenario.SpecRunner.prototype.run = function(spec, specDone) {
var self = this;
this.spec = spec;
@@ -30546,16 +31433,17 @@
* Usage:
* binding(name) returns the value of the first matching binding
*/
angular.scenario.dsl('binding', function() {
return function(name) {
- return this.addFutureAction("select binding '" + name + "'", function($window, $document, done) {
- var values = $document.elements().bindings($window.angular.element, name);
- if (!values.length) {
- return done("Binding selector '" + name + "' did not match.");
- }
- done(null, values[0]);
+ return this.addFutureAction("select binding '" + name + "'",
+ function($window, $document, done) {
+ var values = $document.elements().bindings($window.angular.element, name);
+ if (!values.length) {
+ return done("Binding selector '" + name + "' did not match.");
+ }
+ done(null, values[0]);
});
};
});
/**
@@ -30568,32 +31456,35 @@
angular.scenario.dsl('input', function() {
var chain = {};
var supportInputEvent = 'oninput' in document.createElement('div') && msie != 9;
chain.enter = function(value, event) {
- return this.addFutureAction("input '" + this.name + "' enter '" + value + "'", function($window, $document, done) {
- var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
- input.val(value);
- input.trigger(event || (supportInputEvent ? 'input' : 'change'));
- done();
+ return this.addFutureAction("input '" + this.name + "' enter '" + value + "'",
+ function($window, $document, done) {
+ var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
+ input.val(value);
+ input.trigger(event || (supportInputEvent ? 'input' : 'change'));
+ done();
});
};
chain.check = function() {
- return this.addFutureAction("checkbox '" + this.name + "' toggle", function($window, $document, done) {
- var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
- input.trigger('click');
- done();
+ return this.addFutureAction("checkbox '" + this.name + "' toggle",
+ function($window, $document, done) {
+ var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
+ input.trigger('click');
+ done();
});
};
chain.select = function(value) {
- return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'", function($window, $document, done) {
- var input = $document.
- elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
- input.trigger('click');
- done();
+ return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'",
+ function($window, $document, done) {
+ var input = $document.
+ elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
+ input.trigger('click');
+ done();
});
};
chain.val = function() {
return this.addFutureAction("return input val", function($window, $document, done) {
@@ -30611,37 +31502,41 @@
/**
* Usage:
* repeater('#products table', 'Product List').count() number of rows
* repeater('#products table', 'Product List').row(1) all bindings in row as an array
- * repeater('#products table', 'Product List').column('product.name') all values across all rows in an array
+ * repeater('#products table', 'Product List').column('product.name') all values across all rows
+ * in an array
*/
angular.scenario.dsl('repeater', function() {
var chain = {};
chain.count = function() {
- return this.addFutureAction("repeater '" + this.label + "' count", function($window, $document, done) {
- try {
- done(null, $document.elements().length);
- } catch (e) {
- done(null, 0);
- }
+ return this.addFutureAction("repeater '" + this.label + "' count",
+ function($window, $document, done) {
+ try {
+ done(null, $document.elements().length);
+ } catch (e) {
+ done(null, 0);
+ }
});
};
chain.column = function(binding) {
- return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'", function($window, $document, done) {
- done(null, $document.elements().bindings($window.angular.element, binding));
+ return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'",
+ function($window, $document, done) {
+ done(null, $document.elements().bindings($window.angular.element, binding));
});
};
chain.row = function(index) {
- return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'", function($window, $document, done) {
- var matches = $document.elements().slice(index, index + 1);
- if (!matches.length)
- return done('row ' + index + ' out of bounds');
- done(null, matches.bindings($window.angular.element));
+ return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'",
+ function($window, $document, done) {
+ var matches = $document.elements().slice(index, index + 1);
+ if (!matches.length)
+ return done('row ' + index + ' out of bounds');
+ done(null, matches.bindings($window.angular.element));
});
};
return function(selector, label) {
this.dsl.using(selector, label);
@@ -30656,40 +31551,42 @@
*/
angular.scenario.dsl('select', function() {
var chain = {};
chain.option = function(value) {
- return this.addFutureAction("select '" + this.name + "' option '" + value + "'", function($window, $document, done) {
- var select = $document.elements('select[ng\\:model="$1"]', this.name);
- var option = select.find('option[value="' + value + '"]');
- if (option.length) {
- select.val(value);
- } else {
- option = select.find('option').filter(function(){
- return _jQuery(this).text() === value;
- });
- if (!option.length) {
- option = select.find('option:contains("' + value + '")');
- }
+ return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
+ function($window, $document, done) {
+ var select = $document.elements('select[ng\\:model="$1"]', this.name);
+ var option = select.find('option[value="' + value + '"]');
if (option.length) {
- select.val(option.val());
+ select.val(value);
} else {
- return done("option '" + value + "' not found");
+ option = select.find('option').filter(function(){
+ return _jQuery(this).text() === value;
+ });
+ if (!option.length) {
+ option = select.find('option:contains("' + value + '")');
+ }
+ if (option.length) {
+ select.val(option.val());
+ } else {
+ return done("option '" + value + "' not found");
+ }
}
- }
- select.trigger('change');
- done();
+ select.trigger('change');
+ done();
});
};
chain.options = function() {
var values = arguments;
- return this.addFutureAction("select '" + this.name + "' options '" + values + "'", function($window, $document, done) {
- var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
- select.val(values);
- select.trigger('change');
- done();
+ return this.addFutureAction("select '" + this.name + "' options '" + values + "'",
+ function($window, $document, done) {
+ var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
+ select.val(values);
+ select.trigger('change');
+ done();
});
};
return function(name) {
this.name = name;
@@ -30717,87 +31614,95 @@
'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
];
var chain = {};
chain.count = function() {
- return this.addFutureAction("element '" + this.label + "' count", function($window, $document, done) {
- try {
- done(null, $document.elements().length);
- } catch (e) {
- done(null, 0);
- }
+ return this.addFutureAction("element '" + this.label + "' count",
+ function($window, $document, done) {
+ try {
+ done(null, $document.elements().length);
+ } catch (e) {
+ done(null, 0);
+ }
});
};
chain.click = function() {
- return this.addFutureAction("element '" + this.label + "' click", function($window, $document, done) {
- var elements = $document.elements();
- var href = elements.attr('href');
- var eventProcessDefault = elements.trigger('click')[0];
+ return this.addFutureAction("element '" + this.label + "' click",
+ function($window, $document, done) {
+ var elements = $document.elements();
+ var href = elements.attr('href');
+ var eventProcessDefault = elements.trigger('click')[0];
- if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
- this.application.navigateTo(href, function() {
+ if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
+ this.application.navigateTo(href, function() {
+ done();
+ }, done);
+ } else {
done();
- }, done);
- } else {
- done();
- }
+ }
});
};
chain.dblclick = function() {
- return this.addFutureAction("element '" + this.label + "' dblclick", function($window, $document, done) {
- var elements = $document.elements();
- var href = elements.attr('href');
- var eventProcessDefault = elements.trigger('dblclick')[0];
+ return this.addFutureAction("element '" + this.label + "' dblclick",
+ function($window, $document, done) {
+ var elements = $document.elements();
+ var href = elements.attr('href');
+ var eventProcessDefault = elements.trigger('dblclick')[0];
- if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
- this.application.navigateTo(href, function() {
+ if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
+ this.application.navigateTo(href, function() {
+ done();
+ }, done);
+ } else {
done();
- }, done);
- } else {
- done();
- }
+ }
});
};
chain.mouseover = function() {
- return this.addFutureAction("element '" + this.label + "' mouseover", function($window, $document, done) {
- var elements = $document.elements();
- elements.trigger('mouseover');
- done();
+ return this.addFutureAction("element '" + this.label + "' mouseover",
+ function($window, $document, done) {
+ var elements = $document.elements();
+ elements.trigger('mouseover');
+ done();
});
};
chain.mousedown = function() {
- return this.addFutureAction("element '" + this.label + "' mousedown", function($window, $document, done) {
- var elements = $document.elements();
- elements.trigger('mousedown');
- done();
+ return this.addFutureAction("element '" + this.label + "' mousedown",
+ function($window, $document, done) {
+ var elements = $document.elements();
+ elements.trigger('mousedown');
+ done();
});
};
chain.mouseup = function() {
- return this.addFutureAction("element '" + this.label + "' mouseup", function($window, $document, done) {
- var elements = $document.elements();
- elements.trigger('mouseup');
- done();
+ return this.addFutureAction("element '" + this.label + "' mouseup",
+ function($window, $document, done) {
+ var elements = $document.elements();
+ elements.trigger('mouseup');
+ done();
});
};
chain.query = function(fn) {
- return this.addFutureAction('element ' + this.label + ' custom query', function($window, $document, done) {
- fn.call(this, $document.elements(), done);
+ return this.addFutureAction('element ' + this.label + ' custom query',
+ function($window, $document, done) {
+ fn.call(this, $document.elements(), done);
});
};
angular.forEach(KEY_VALUE_METHODS, function(methodName) {
chain[methodName] = function(name, value) {
var args = arguments,
futureName = (args.length == 1)
? "element '" + this.label + "' get " + methodName + " '" + name + "'"
- : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" + value + "'";
+ : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" +
+ value + "'";
return this.addFutureAction(futureName, function($window, $document, done) {
var element = $document.elements();
done(null, element[methodName].apply(element, args));
});
@@ -30805,11 +31710,11 @@
});
angular.forEach(VALUE_METHODS, function(methodName) {
chain[methodName] = function(value) {
var args = arguments,
- futureName = (args.length == 0)
+ futureName = (args.length === 0)
? "element '" + this.label + "' " + methodName
: "element '" + this.label + "' set " + methodName + " to '" + value + "'";
return this.addFutureAction(futureName, function($window, $document, done) {
var element = $document.elements();
@@ -31124,7 +32029,8 @@
angular.scenario.setUpAndRun(config);
});
}
})(window, document);
-angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n</style>');
-angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');
+
+!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak],\n.ng-cloak, .x-ng-cloak,\n.ng-hide {\n display: none !important;\n}\n\nng\\:form {\n display: block;\n}\n\n/* The styles below ensure that the CSS transition will ALWAYS\n * animate and close. A nasty bug occurs with CSS transitions where\n * when the active class isn\'t set, or if the active class doesn\'t\n * contain any styles to transition to, then, if ngAnimate is used,\n * it will appear as if the webpage is broken due to the forever hanging\n * animations. The clip (!ie) and zoom (ie) CSS properties are used\n * since they trigger a transition without making the browser\n * animate anything and they\'re both highly underused CSS properties */\n.ng-animate-start { clip:rect(0, auto, auto, 0); -ms-zoom:1.0001; }\n.ng-animate-active { clip:rect(-1px, auto, auto, 0); -ms-zoom:1; }\n</style>');
+!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";\n/* CSS Document */\n\n/** Structure */\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n font-size: 14px;\n}\n\n#system-error {\n font-size: 1.5em;\n text-align: center;\n}\n\n#json, #xml {\n display: none;\n}\n\n#header {\n position: fixed;\n width: 100%;\n}\n\n#specs {\n padding-top: 50px;\n}\n\n#header .angular {\n font-family: Courier New, monospace;\n font-weight: bold;\n}\n\n#header h1 {\n font-weight: normal;\n float: left;\n font-size: 30px;\n line-height: 30px;\n margin: 0;\n padding: 10px 10px;\n height: 30px;\n}\n\n#application h2,\n#specs h2 {\n margin: 0;\n padding: 0.5em;\n font-size: 1.1em;\n}\n\n#status-legend {\n margin-top: 10px;\n margin-right: 10px;\n}\n\n#header,\n#application,\n.test-info,\n.test-actions li {\n overflow: hidden;\n}\n\n#application {\n margin: 10px;\n}\n\n#application iframe {\n width: 100%;\n height: 758px;\n}\n\n#application .popout {\n float: right;\n}\n\n#application iframe {\n border: none;\n}\n\n.tests li,\n.test-actions li,\n.test-it li,\n.test-it ol,\n.status-display {\n list-style-type: none;\n}\n\n.tests,\n.test-it ol,\n.status-display {\n margin: 0;\n padding: 0;\n}\n\n.test-info {\n margin-left: 1em;\n margin-top: 0.5em;\n border-radius: 8px 0 0 8px;\n -webkit-border-radius: 8px 0 0 8px;\n -moz-border-radius: 8px 0 0 8px;\n cursor: pointer;\n}\n\n.test-info:hover .test-name {\n text-decoration: underline;\n}\n\n.test-info .closed:before {\n content: \'\\25b8\\00A0\';\n}\n\n.test-info .open:before {\n content: \'\\25be\\00A0\';\n font-weight: bold;\n}\n\n.test-it ol {\n margin-left: 2.5em;\n}\n\n.status-display,\n.status-display li {\n float: right;\n}\n\n.status-display li {\n padding: 5px 10px;\n}\n\n.timer-result,\n.test-title {\n display: inline-block;\n margin: 0;\n padding: 4px;\n}\n\n.test-actions .test-title,\n.test-actions .test-result {\n display: table-cell;\n padding-left: 0.5em;\n padding-right: 0.5em;\n}\n\n.test-actions {\n display: table;\n}\n\n.test-actions li {\n display: table-row;\n}\n\n.timer-result {\n width: 4em;\n padding: 0 10px;\n text-align: right;\n font-family: monospace;\n}\n\n.test-it pre,\n.test-actions pre {\n clear: left;\n color: black;\n margin-left: 6em;\n}\n\n.test-describe {\n padding-bottom: 0.5em;\n}\n\n.test-describe .test-describe {\n margin: 5px 5px 10px 2em;\n}\n\n.test-actions .status-pending .test-title:before {\n content: \'\\00bb\\00A0\';\n}\n\n.scrollpane {\n max-height: 20em;\n overflow: auto;\n}\n\n/** Colors */\n\n#header {\n background-color: #F2C200;\n}\n\n#specs h2 {\n border-top: 2px solid #BABAD1;\n}\n\n#specs h2,\n#application h2 {\n background-color: #efefef;\n}\n\n#application {\n border: 1px solid #BABAD1;\n}\n\n.test-describe .test-describe {\n border-left: 1px solid #BABAD1;\n border-right: 1px solid #BABAD1;\n border-bottom: 1px solid #BABAD1;\n}\n\n.status-display {\n border: 1px solid #777;\n}\n\n.status-display .status-pending,\n.status-pending .test-info {\n background-color: #F9EEBC;\n}\n\n.status-display .status-success,\n.status-success .test-info {\n background-color: #B1D7A1;\n}\n\n.status-display .status-failure,\n.status-failure .test-info {\n background-color: #FF8286;\n}\n\n.status-display .status-error,\n.status-error .test-info {\n background-color: black;\n color: white;\n}\n\n.test-actions .status-success .test-title {\n color: #30B30A;\n}\n\n.test-actions .status-failure .test-title {\n color: #DF0000;\n}\n\n.test-actions .status-error .test-title {\n color: black;\n}\n\n.test-actions .timer-result {\n color: #888;\n}\n</style>');
\ No newline at end of file