vendor/assets/javascripts/angular.js in rails-angularjs-1.4.0 vs vendor/assets/javascripts/angular.js in rails-angularjs-1.4.1
- old
+ new
@@ -1,7 +1,7 @@
/**
- * @license AngularJS v1.4.0
+ * @license AngularJS v1.4.1
* (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document, undefined) {'use strict';
@@ -55,11 +55,11 @@
}
return match;
});
- message += '\nhttp://errors.angularjs.org/1.4.0/' +
+ message += '\nhttp://errors.angularjs.org/1.4.1/' +
(module ? module + '/' : '') + code;
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
encodeURIComponent(toDebugString(templateArgs[i]));
@@ -862,50 +862,56 @@
"Can't copy! TypedArray destination cannot be mutated.");
}
if (!destination) {
destination = source;
- if (source) {
+ if (isObject(source)) {
+ var index;
+ if (stackSource && (index = stackSource.indexOf(source)) !== -1) {
+ return stackDest[index];
+ }
+
+ // TypedArray, Date and RegExp have specific copy functionality and must be
+ // pushed onto the stack before returning.
+ // Array and other objects create the base object and recurse to copy child
+ // objects. The array/object will be pushed onto the stack when recursed.
if (isArray(source)) {
- destination = copy(source, [], stackSource, stackDest);
+ return copy(source, [], stackSource, stackDest);
} else if (isTypedArray(source)) {
destination = new source.constructor(source);
} else if (isDate(source)) {
destination = new Date(source.getTime());
} else if (isRegExp(source)) {
destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
- } else if (isObject(source)) {
+ } else {
var emptyObject = Object.create(getPrototypeOf(source));
- destination = copy(source, emptyObject, stackSource, stackDest);
+ return copy(source, emptyObject, stackSource, stackDest);
}
+
+ if (stackDest) {
+ stackSource.push(source);
+ stackDest.push(destination);
+ }
}
} else {
if (source === destination) throw ngMinErr('cpi',
"Can't copy! Source and destination are identical.");
stackSource = stackSource || [];
stackDest = stackDest || [];
if (isObject(source)) {
- var index = stackSource.indexOf(source);
- if (index !== -1) return stackDest[index];
-
stackSource.push(source);
stackDest.push(destination);
}
var result, key;
if (isArray(source)) {
destination.length = 0;
for (var i = 0; i < source.length; i++) {
- result = copy(source[i], null, stackSource, stackDest);
- if (isObject(source[i])) {
- stackSource.push(source[i]);
- stackDest.push(result);
- }
- destination.push(result);
+ destination.push(copy(source[i], null, stackSource, stackDest));
}
} else {
var h = destination.$$hashKey;
if (isArray(destination)) {
destination.length = 0;
@@ -915,41 +921,31 @@
});
}
if (isBlankObject(source)) {
// createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
for (key in source) {
- putValue(key, source[key], destination, stackSource, stackDest);
+ destination[key] = copy(source[key], null, stackSource, stackDest);
}
} else if (source && typeof source.hasOwnProperty === 'function') {
// Slow path, which must rely on hasOwnProperty
for (key in source) {
if (source.hasOwnProperty(key)) {
- putValue(key, source[key], destination, stackSource, stackDest);
+ destination[key] = copy(source[key], null, stackSource, stackDest);
}
}
} else {
// Slowest path --- hasOwnProperty can't be called as a method
for (key in source) {
if (hasOwnProperty.call(source, key)) {
- putValue(key, source[key], destination, stackSource, stackDest);
+ destination[key] = copy(source[key], null, stackSource, stackDest);
}
}
}
setHashKey(destination,h);
}
}
return destination;
-
- function putValue(key, val, destination, stackSource, stackDest) {
- // No context allocation, trivial outer scope, easily inlined
- var result = copy(val, null, stackSource, stackDest);
- if (isObject(val)) {
- stackSource.push(val);
- stackDest.push(result);
- }
- destination[key] = result;
- }
}
/**
* Creates a shallow copy of an object, an array or a primitive.
*
@@ -2003,33 +1999,33 @@
* @param {Function} providerType Construction function for creating new instance of the
* service.
* @description
* See {@link auto.$provide#provider $provide.provider()}.
*/
- provider: invokeLater('$provide', 'provider'),
+ provider: invokeLaterAndSetModuleName('$provide', 'provider'),
/**
* @ngdoc method
* @name angular.Module#factory
* @module ng
* @param {string} name service name
* @param {Function} providerFunction Function for creating new instance of the service.
* @description
* See {@link auto.$provide#factory $provide.factory()}.
*/
- factory: invokeLater('$provide', 'factory'),
+ factory: invokeLaterAndSetModuleName('$provide', 'factory'),
/**
* @ngdoc method
* @name angular.Module#service
* @module ng
* @param {string} name service name
* @param {Function} constructor A constructor function that will be instantiated.
* @description
* See {@link auto.$provide#service $provide.service()}.
*/
- service: invokeLater('$provide', 'service'),
+ service: invokeLaterAndSetModuleName('$provide', 'service'),
/**
* @ngdoc method
* @name angular.Module#value
* @module ng
@@ -2060,11 +2056,11 @@
* @param {Function} This function will be invoked when the service needs to be
* instantiated and should return the decorated service instance.
* @description
* See {@link auto.$provide#decorator $provide.decorator()}.
*/
- decorator: invokeLater('$provide', 'decorator'),
+ decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
/**
* @ngdoc method
* @name angular.Module#animation
* @module ng
@@ -2094,11 +2090,11 @@
* ```
*
* See {@link ng.$animateProvider#register $animateProvider.register()} and
* {@link ngAnimate ngAnimate module} for more information.
*/
- animation: invokeLater('$animateProvider', 'register'),
+ animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
/**
* @ngdoc method
* @name angular.Module#filter
* @module ng
@@ -2112,11 +2108,11 @@
* Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
* your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
* (`myapp_subsection_filterx`).
* </div>
*/
- filter: invokeLater('$filterProvider', 'register'),
+ filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
/**
* @ngdoc method
* @name angular.Module#controller
* @module ng
@@ -2124,11 +2120,11 @@
* keys are the names and the values are the constructors.
* @param {Function} constructor Controller constructor function.
* @description
* See {@link ng.$controllerProvider#register $controllerProvider.register()}.
*/
- controller: invokeLater('$controllerProvider', 'register'),
+ controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
/**
* @ngdoc method
* @name angular.Module#directive
* @module ng
@@ -2137,11 +2133,11 @@
* @param {Function} directiveFactory Factory function for creating new instance of
* directives.
* @description
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
- directive: invokeLater('$compileProvider', 'directive'),
+ directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
/**
* @ngdoc method
* @name angular.Module#config
* @module ng
@@ -2187,10 +2183,23 @@
return function() {
queue[insertMethod || 'push']([provider, method, arguments]);
return moduleInstance;
};
}
+
+ /**
+ * @param {string} provider
+ * @param {string} method
+ * @returns {angular.Module}
+ */
+ function invokeLaterAndSetModuleName(provider, method) {
+ return function(recipeName, factoryFunction) {
+ if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
+ invokeQueue.push([provider, method, arguments]);
+ return moduleInstance;
+ };
+ }
});
};
});
}
@@ -2330,15 +2339,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.4.0', // all of these placeholder strings will be replaced by grunt's
+ full: '1.4.1', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 4,
- dot: 0,
- codeName: 'jaracimrman-existence'
+ dot: 1,
+ codeName: 'hyperionic-illumination'
};
function publishExternalAPI(angular) {
extend(angular, {
@@ -2660,10 +2669,17 @@
// Otherwise we are only interested in elements (1) and documents (9)
var nodeType = node.nodeType;
return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
}
+function jqLiteHasData(node) {
+ for (var key in jqCache[node.ng339]) {
+ return true;
+ }
+ return false;
+}
+
function jqLiteBuildFragment(html, context) {
var tmp, tag, wrap,
fragment = context.createDocumentFragment(),
nodes = [], i;
@@ -3034,11 +3050,12 @@
return (nodeName === 'INPUT' || nodeName === 'TEXTAREA') && ALIASED_ATTR[name];
}
forEach({
data: jqLiteData,
- removeData: jqLiteRemoveData
+ removeData: jqLiteRemoveData,
+ hasData: jqLiteHasData
}, function(fn, name) {
JQLite[name] = fn;
});
forEach({
@@ -4243,11 +4260,11 @@
var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
}));
- forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
+ forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
return instanceInjector;
////////////////////////////////////
// $provider
@@ -5466,11 +5483,11 @@
history[replace ? 'replaceState' : 'pushState'](state, '', url);
cacheState();
// Do the assignment again so that those two variables are referentially identical.
lastHistoryState = cachedState;
} else {
- if (!sameBase) {
+ if (!sameBase || reloadLocation) {
reloadLocation = url;
}
if (replace) {
location.replace(url);
} else if (!sameBase) {
@@ -6472,17 +6489,20 @@
* between all directive linking functions.
*
* * `controller` - the directive's required controller instance(s) - Instances are shared
* among all directives, which allows the directives to use the controllers as a communication
* channel. The exact value depends on the directive's `require` property:
+ * * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
* * `string`: the controller instance
* * `array`: array of controller instances
- * * no controller(s) required: `undefined`
*
* If a required controller cannot be found, and it is optional, the instance is `null`,
* otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
*
+ * Note that you can also require the directive's own controller - it will be made available like
+ * like any other controller.
+ *
* * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
* This is the same as the `$transclude`
* parameter of directive controllers, see there for details.
* `function([scope], cloneLinkingFn, futureParentElement)`.
*
@@ -6925,10 +6945,11 @@
var bindings = directive.$$bindings =
parseDirectiveBindings(directive, directive.name);
if (isObject(bindings.isolateScope)) {
directive.$$isolateBindings = bindings.isolateScope;
}
+ directive.$$moduleName = directiveFactory.$$moduleName;
directives.push(directive);
} catch (e) {
$exceptionHandler(e);
}
});
@@ -7496,12 +7517,11 @@
childScope = scope;
}
if (nodeLinkFn.transcludeOnThisElement) {
childBoundTranscludeFn = createBoundTranscludeFn(
- scope, nodeLinkFn.transclude, parentBoundTranscludeFn,
- nodeLinkFn.elementTranscludeOnThisElement);
+ scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
} else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
childBoundTranscludeFn = parentBoundTranscludeFn;
} else if (!parentBoundTranscludeFn && transcludeFn) {
@@ -7519,11 +7539,11 @@
}
}
}
}
- function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn, elementTransclusion) {
+ function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
if (!transcludedScope) {
transcludedScope = scope.$new(false, containingScope);
@@ -7618,10 +7638,17 @@
className = className.substr(match.index + match[0].length);
}
}
break;
case NODE_TYPE_TEXT: /* Text Node */
+ if (msie === 11) {
+ // Workaround for #11781
+ while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
+ node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
+ node.parentNode.removeChild(node.nextSibling);
+ }
+ }
addTextInterpolateDirective(directives, node.nodeValue);
break;
case NODE_TYPE_COMMENT: /* Comment */
try {
match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
@@ -7910,11 +7937,10 @@
}
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
- nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
nodeLinkFn.templateOnThisElement = hasTemplate;
nodeLinkFn.transclude = childTranscludeFn;
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
@@ -8071,13 +8097,16 @@
}
}
for (i in elementControllers) {
controller = elementControllers[i];
var controllerResult = controller();
+
if (controllerResult !== controller.instance) {
+ // If the controller constructor has a return value, overwrite the instance
+ // from setupControllers and update the element data
controller.instance = controllerResult;
- $element.data('$' + directive.name + 'Controller', controllerResult);
+ $element.data('$' + i + 'Controller', controllerResult);
if (controller === controllerForBindings) {
// Remove and re-install bindToController bindings
thisLinkFn.$$destroyBindings();
thisLinkFn.$$destroyBindings =
initializeDirectiveBindings(scope, attrs, controllerResult, bindings, scopeDirective);
@@ -8373,15 +8402,22 @@
if (diff !== 0) return diff;
if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
return a.index - b.index;
}
-
function assertNoDuplicate(what, previousDirective, directive, element) {
+
+ function wrapModuleNameIfDefined(moduleName) {
+ return moduleName ?
+ (' (module: ' + moduleName + ')') :
+ '';
+ }
+
if (previousDirective) {
- throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
- previousDirective.name, directive.name, what, startingTag(element));
+ throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
+ previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
+ directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
}
}
function addTextInterpolateDirective(directives, text) {
@@ -8558,30 +8594,32 @@
// TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
var fragment = document.createDocumentFragment();
fragment.appendChild(firstElementToRemove);
- // Copy over user data (that includes Angular's $scope etc.). Don't copy private
- // data here because there's no public interface in jQuery to do that and copying over
- // event listeners (which is the main use of private data) wouldn't work anyway.
- jqLite(newNode).data(jqLite(firstElementToRemove).data());
+ if (jqLite.hasData(firstElementToRemove)) {
+ // Copy over user data (that includes Angular's $scope etc.). Don't copy private
+ // data here because there's no public interface in jQuery to do that and copying over
+ // event listeners (which is the main use of private data) wouldn't work anyway.
+ jqLite(newNode).data(jqLite(firstElementToRemove).data());
- // Remove data of the replaced element. We cannot just call .remove()
- // on the element it since that would deallocate scope that is needed
- // for the new node. Instead, remove the data "manually".
- if (!jQuery) {
- delete jqLite.cache[firstElementToRemove[jqLite.expando]];
- } else {
- // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
- // the replaced element. The cleanData version monkey-patched by Angular would cause
- // the scope to be trashed and we do need the very same scope to work with the new
- // element. However, we cannot just cache the non-patched version and use it here as
- // that would break if another library patches the method after Angular does (one
- // example is jQuery UI). Instead, set a flag indicating scope destroying should be
- // skipped this one time.
- skipDestroyOnNextJQueryCleanData = true;
- jQuery.cleanData([firstElementToRemove]);
+ // Remove data of the replaced element. We cannot just call .remove()
+ // on the element it since that would deallocate scope that is needed
+ // for the new node. Instead, remove the data "manually".
+ if (!jQuery) {
+ delete jqLite.cache[firstElementToRemove[jqLite.expando]];
+ } else {
+ // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
+ // the replaced element. The cleanData version monkey-patched by Angular would cause
+ // the scope to be trashed and we do need the very same scope to work with the new
+ // element. However, we cannot just cache the non-patched version and use it here as
+ // that would break if another library patches the method after Angular does (one
+ // example is jQuery UI). Instead, set a flag indicating scope destroying should be
+ // skipped this one time.
+ skipDestroyOnNextJQueryCleanData = true;
+ jQuery.cleanData([firstElementToRemove]);
+ }
}
for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
var element = elementsToRemove[k];
jqLite(element).remove(); // must do this way to clean up expando
@@ -8618,13 +8656,23 @@
optional = definition.optional,
mode = definition.mode, // @, =, or &
lastValue,
parentGet, parentSet, compare;
+ if (!hasOwnProperty.call(attrs, attrName)) {
+ // In the case of user defined a binding with the same name as a method in Object.prototype but didn't set
+ // the corresponding attribute. We need to make sure subsequent code won't access to the prototype function
+ attrs[attrName] = undefined;
+ }
+
switch (mode) {
case '@':
+ if (!attrs[attrName] && !optional) {
+ destination[scopeName] = undefined;
+ }
+
attrs.$observe(attrName, function(value) {
destination[scopeName] = value;
});
attrs.$$observers[attrName].$$scope = scope;
if (attrs[attrName]) {
@@ -8637,10 +8685,11 @@
case '=':
if (optional && !attrs[attrName]) {
return;
}
parentGet = $parse(attrs[attrName]);
+
if (parentGet.literal) {
compare = equals;
} else {
compare = function(a, b) { return a === b || (a !== a && b !== b); };
}
@@ -8675,13 +8724,10 @@
onNewScopeDestroyed = (onNewScopeDestroyed || []);
onNewScopeDestroyed.push(unwatch);
break;
case '&':
- // Don't assign Object.prototype method to scope
- if (!attrs.hasOwnProperty(attrName) && optional) break;
-
parentGet = $parse(attrs[attrName]);
// Don't assign noop to destination if expression is not valid
if (parentGet === noop && optional) break;
@@ -9078,17 +9124,21 @@
/**
* @ngdoc service
* @name $httpParamSerializer
* @description
*
- * Default $http params serializer that converts objects to a part of a request URL
+ * Default {@link $http `$http`} params serializer that converts objects to strings
* according to the following rules:
+ *
* * `{'foo': 'bar'}` results in `foo=bar`
* * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
* * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
* * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
+ *
+ * Note that serializer will sort the request parameters alphabetically.
* */
+
this.$get = function() {
return function ngParamSerializer(params) {
if (!params) return '';
var parts = [];
forEachSorted(params, function(value, key) {
@@ -9111,11 +9161,47 @@
/**
* @ngdoc service
* @name $httpParamSerializerJQLike
* @description
*
- * Alternative $http params serializer that follows jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
+ * Alternative {@link $http `$http`} params serializer that follows
+ * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
+ * The serializer will also sort the params alphabetically.
+ *
+ * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
+ *
+ * ```js
+ * $http({
+ * url: myUrl,
+ * method: 'GET',
+ * params: myParams,
+ * paramSerializer: '$httpParamSerializerJQLike'
+ * });
+ * ```
+ *
+ * It is also possible to set it as the default `paramSerializer` in the
+ * {@link $httpProvider#defaults `$httpProvider`}.
+ *
+ * Additionally, you can inject the serializer and use it explicitly, for example to serialize
+ * form data for submission:
+ *
+ * ```js
+ * .controller(function($http, $httpParamSerializerJQLike) {
+ * //...
+ *
+ * $http({
+ * url: myUrl,
+ * method: 'POST',
+ * data: $httpParamSerializerJQLike(myData),
+ * headers: {
+ * 'Content-Type': 'application/x-www-form-urlencoded'
+ * }
+ * });
+ *
+ * });
+ * ```
+ *
* */
this.$get = function() {
return function jQueryLikeParamSerializer(params) {
if (!params) return '';
var parts = [];
@@ -9285,15 +9371,16 @@
* - **`defaults.headers.common`**
* - **`defaults.headers.post`**
* - **`defaults.headers.put`**
* - **`defaults.headers.patch`**
*
- * - **`defaults.paramSerializer`** - {string|function(Object<string,string>):string} - A function used to prepare string representation
- * of request parameters (specified as an object).
- * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
- * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
*
+ * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
+ * used to the prepare string representation of request parameters (specified as an object).
+ * If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
+ * Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
+ *
**/
var defaults = this.defaults = {
// transform incoming response data
transformResponse: [defaultHttpResponseTransform],
@@ -9754,19 +9841,21 @@
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
* properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
* or the per-request config object.
*
+ * In order to prevent collisions in environments where multiple Angular apps share the
+ * same domain or subdomain, we recommend that each application uses unique cookie name.
*
+ *
* @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 serialized
+ * with the `paramSerializer` and appended as GET parameters.
* - **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. Functions accept a config object as an argument.
* - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
@@ -9780,14 +9869,18 @@
* - **transformResponse** –
* `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
* transform function or an array of such functions. The transform function takes the http
* response body, headers and status and returns its transformed (typically deserialized) version.
* See {@link ng.$http#overriding-the-default-transformations-per-request
- * Overriding the Default Transformations}
- * - **paramSerializer** - {string|function(Object<string,string>):string} - A function used to prepare string representation
- * of request parameters (specified as an object).
- * Is specified as string, it is interpreted as function registered in with the {$injector}.
+ * Overriding the Default TransformationjqLiks}
+ * - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
+ * prepare the string representation of request parameters (specified as an object).
+ * If specified as string, it is interpreted as function registered with the
+ * {@link $injector $injector}, which means you can create your own serializer
+ * by registering it as a {@link auto.$provide#service service}.
+ * The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
+ * alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
* - **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
* caching.
* - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
@@ -13211,12 +13304,14 @@
if (nameId) {
nameId.computed = false;
nameId.name = ast.property.name;
}
}
- recursionFn(intoId);
+ }, function() {
+ self.assign(intoId, 'undefined');
});
+ recursionFn(intoId);
}, !!create);
break;
case AST.CallExpression:
intoId = intoId || this.nextId();
if (ast.filter) {
@@ -13250,12 +13345,14 @@
} else {
expression = right + '(' + args.join(',') + ')';
}
expression = self.ensureSafeObject(expression);
self.assign(intoId, expression);
- recursionFn(intoId);
+ }, function() {
+ self.assign(intoId, 'undefined');
});
+ recursionFn(intoId);
});
}
break;
case AST.AssignmentExpression:
right = this.nextId();
@@ -14634,10 +14731,23 @@
return result.promise.then(callback, errback, progressBack);
};
/**
* @ngdoc method
+ * @name $q#resolve
+ * @kind function
+ *
+ * @description
+ * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
+ *
+ * @param {*} value Value or a promise
+ * @returns {Promise} Returns a promise of the passed value or promise
+ */
+ var resolve = when;
+
+ /**
+ * @ngdoc method
* @name $q#all
* @kind function
*
* @description
* Combines multiple promises into a single promise that is resolved when all of the input
@@ -14700,10 +14810,11 @@
};
$Q.defer = defer;
$Q.reject = reject;
$Q.when = when;
+ $Q.resolve = resolve;
$Q.all = all;
return $Q;
}
@@ -18009,14 +18120,16 @@
* Note that a named property will match properties on the same level only, while the special
* `$` property will match properties on the same level or deeper. E.g. an array item like
* `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
* **will** be matched by `{$: 'John'}`.
*
- * - `function(value, index)`: A predicate function can be used to write arbitrary filters. The
- * function is called for each element of `array`. The final result is an array of those
- * elements that the predicate returned true for.
+ * - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
+ * The function is called for each element of the array, with the element, its index, and
+ * the entire array itself as arguments.
*
+ * The final result is an array of those elements that the predicate returned true for.
+ *
* @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
* determining if the expected value (from the filter expression) and actual value (from
* the object in the array) should be considered a match.
*
* Can be one of:
@@ -18312,13 +18425,14 @@
* @kind function
*
* @description
* Formats a number as text.
*
+ * If the input is null or undefined, it will just be returned.
+ * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
* If the input is not a number an empty string is returned.
*
- * If the input is an infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
*
* @param {number|string} number Number to format.
* @param {(number|string)=} fractionSize Number of decimal places to round the number to.
* If this is not provided then the fraction size is computed from the current locale's number
* formatting pattern. In the case of the default locale, it will be 3.
@@ -18943,11 +19057,11 @@
* @kind function
*
* @description
* Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
* for strings and numerically for numbers. Note: if you notice numbers are not being sorted
- * correctly, make sure they are actually being saved as numbers and not strings.
+ * as expected, make sure they are actually being saved as numbers and not strings.
*
* @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.
*
@@ -19018,23 +19132,44 @@
[{name:'John', phone:'555-1212', age:10},
{name:'Mary', phone:'555-9876', age:19},
{name:'Mike', phone:'555-4321', age:21},
{name:'Adam', phone:'555-5678', age:35},
{name:'Julie', phone:'555-8765', age:29}];
- $scope.predicate = '-age';
+ $scope.predicate = 'age';
+ $scope.reverse = true;
+ $scope.order = function(predicate) {
+ $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
+ $scope.predicate = predicate;
+ };
}]);
</script>
+ <style type="text/css">
+ .sortorder:after {
+ content: '\25b2';
+ }
+ .sortorder.reverse:after {
+ content: '\25bc';
+ }
+ </style>
<div ng-controller="ExampleController">
<pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
<hr/>
[ <a href="" ng-click="predicate=''">unsorted</a> ]
<table class="friend">
<tr>
- <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
- (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
- <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
- <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
+ <th>
+ <a href="" ng-click="order('name')">Name</a>
+ <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
+ </th>
+ <th>
+ <a href="" ng-click="order('phone')">Phone Number</a>
+ <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
+ </th>
+ <th>
+ <a href="" ng-click="order('age')">Age</a>
+ <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
+ </th>
</tr>
<tr ng-repeat="friend in friends | orderBy:predicate:reverse">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
@@ -20193,11 +20328,11 @@
// Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
var ISO_DATE_REGEXP = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i;
-var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
+var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
@@ -20792,10 +20927,20 @@
* The model must always be of type `number` otherwise Angular will throw an error.
* Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
* error docs for more information and an example of how to convert your model if necessary.
* </div>
*
+ * ## Issues with HTML5 constraint validation
+ *
+ * In browsers that follow the
+ * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
+ * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
+ * If a non-number is entered in the input, the browser will report the value as an empty string,
+ * which means the view / model values in `ngModel` and subsequently the scope value
+ * will also be an empty string.
+ *
+ *
* @param {string} ngModel Assignable angular expression to data-bind to.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
* @param {string=} required Sets `required` validation error key if the value is not entered.
@@ -22328,22 +22473,22 @@
* element.
*
* @example Example that demonstrates basic bindings via ngClass directive.
<example>
<file name="index.html">
- <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
+ <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
<label>
<input type="checkbox" ng-model="deleted">
deleted (apply "strike" class)
</label><br>
<label>
<input type="checkbox" ng-model="important">
important (apply "bold" class)
</label><br>
<label>
<input type="checkbox" ng-model="error">
- error (apply "red" class)
+ error (apply "has-error" class)
</label>
<hr>
<p ng-class="style">Using String Syntax</p>
<input type="text" ng-model="style"
placeholder="Type: bold strike red" aria-label="Type: bold strike red">
@@ -22368,27 +22513,31 @@
font-weight: bold;
}
.red {
color: red;
}
+ .has-error {
+ color: red;
+ background-color: yellow;
+ }
.orange {
color: orange;
}
</file>
<file name="protractor.js" type="protractor">
var ps = element.all(by.css('p'));
it('should let you toggle the class', function() {
expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
- expect(ps.first().getAttribute('class')).not.toMatch(/red/);
+ expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
element(by.model('important')).click();
expect(ps.first().getAttribute('class')).toMatch(/bold/);
element(by.model('error')).click();
- expect(ps.first().getAttribute('class')).toMatch(/red/);
+ expect(ps.first().getAttribute('class')).toMatch(/has-error/);
});
it('should let you toggle string example', function() {
expect(ps.get(1).getAttribute('class')).toBe('');
element(by.model('style')).clear();
@@ -25218,11 +25367,11 @@
* events using an space delimited list. There is a special event called `default` that
* matches the default events belonging of the control.
* - `debounce`: integer value which contains the debounce model update value in milliseconds. A
* value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
* custom value for each event. For example:
- * `ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }"`
+ * `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
* - `allowInvalid`: boolean value which indicates that the model can be set with values that did
* not validate correctly instead of the default behavior of setting the model to undefined.
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
`ngModel` as getters/setters.
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
@@ -25468,11 +25617,13 @@
}
function isObjectEmpty(obj) {
if (obj) {
for (var prop in obj) {
- return false;
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
}
}
return true;
}
@@ -25811,10 +25962,11 @@
// that only runs the handler once if anything changes
var watchedArray = [];
values = values || [];
Object.keys(values).forEach(function getWatchable(key) {
+ if (key.charAt(0) === '$') return;
var locals = getLocals(values[key], key);
var selectValue = getTrackByValueFn(values[key], locals);
watchedArray.push(selectValue);
// Only need to watch the displayFn if there is a specific label expression
@@ -26214,12 +26366,11 @@
ngModelCtrl.$render();
// Check to see if the value has changed due to the update to the options
if (!ngModelCtrl.$isEmpty(previousValue)) {
var nextValue = selectCtrl.readValue();
- if (ngOptions.trackBy && !equals(previousValue, nextValue) ||
- previousValue !== nextValue) {
+ if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
ngModelCtrl.$setViewValue(nextValue);
ngModelCtrl.$render();
}
}
@@ -26563,10 +26714,19 @@
* <div ng-repeat="obj in collection track by $id(obj)">
* {{obj.prop}}
* </div>
* ```
*
+ * <div class="alert alert-warning">
+ * **Note:** `track by` must always be the last expression:
+ * </div>
+ * ```
+ * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
+ * {{model.name}}
+ * </div>
+ * ```
+ *
* # Special repeat start and end points
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
* the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
* The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
* up to and including the ending HTML tag where **ng-repeat-end** is placed.
@@ -26634,11 +26794,12 @@
*
* * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
* which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
* is specified, ng-repeat associates elements by identity. It is an error to have
* more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
- * mapped to the same DOM element, which is not possible.) If filters are used in the expression, they should be
- * applied before the tracking expression.
+ * mapped to the same DOM element, which is not possible.)
+ *
+ * Note that the tracking expression must come last, after any filters, and the alias expression.
*
* For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
* will be associated by item identity in the array.
*
* For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
\ No newline at end of file