vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.4.0 vs vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.4.2
- old
+ new
@@ -9188,11 +9188,11 @@
return jQuery;
}));
/**
- * @license AngularJS v1.4.0
+ * @license AngularJS v1.4.2
* (c) 2010-2015 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document){
var _jQuery = window.jQuery.noConflict(true);
@@ -9247,11 +9247,11 @@
}
return match;
});
- message += '\nhttp://errors.angularjs.org/1.4.0/' +
+ message += '\nhttp://errors.angularjs.org/1.4.2/' +
(module ? module + '/' : '') + code;
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
message += paramPrefix + 'p' + (i - SKIP_INDEXES) + '=' +
encodeURIComponent(toDebugString(templateArgs[i]));
@@ -9611,12 +9611,16 @@
for (var j = 0, jj = keys.length; j < jj; j++) {
var key = keys[j];
var src = obj[key];
if (deep && isObject(src)) {
- if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
- baseExtend(dst[key], [src], true);
+ if (isDate(src)) {
+ dst[key] = new Date(src.valueOf());
+ } else {
+ if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
+ baseExtend(dst[key], [src], true);
+ }
} else {
dst[key] = src;
}
}
}
@@ -9723,10 +9727,15 @@
identity.$inject = [];
function valueFn(value) {return function() {return value;};}
+function hasCustomToString(obj) {
+ return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
+}
+
+
/**
* @ngdoc function
* @name angular.isUndefined
* @module ng
* @kind function
@@ -10054,50 +10063,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;
@@ -10107,41 +10122,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.
*
@@ -11195,33 +11200,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
@@ -11252,11 +11257,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
@@ -11286,11 +11291,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
@@ -11304,11 +11309,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
@@ -11316,11 +11321,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
@@ -11329,11 +11334,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
@@ -11379,10 +11384,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;
+ };
+ }
});
};
});
}
@@ -11522,15 +11540,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.2', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 4,
- dot: 0,
- codeName: 'jaracimrman-existence'
+ dot: 2,
+ codeName: 'nebular-readjustment'
};
function publishExternalAPI(angular) {
extend(angular, {
@@ -11852,10 +11870,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;
@@ -12226,11 +12251,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({
@@ -13435,11 +13461,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
@@ -14574,11 +14600,11 @@
}
}
function getHash(url) {
var index = url.indexOf('#');
- return index === -1 ? '' : url.substr(index + 1);
+ return index === -1 ? '' : url.substr(index);
}
/**
* @private
* Note: this method is used only by scenario runner
@@ -14658,11 +14684,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) {
@@ -15664,17 +15690,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)`.
*
@@ -16117,10 +16146,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);
}
});
@@ -16688,12 +16718,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) {
@@ -16711,11 +16740,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);
@@ -16810,10 +16839,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);
@@ -16909,11 +16945,11 @@
jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
previousCompileContext) {
previousCompileContext = previousCompileContext || {};
var terminalPriority = -Number.MAX_VALUE,
- newScopeDirective,
+ newScopeDirective = previousCompileContext.newScopeDirective,
controllerDirectives = previousCompileContext.controllerDirectives,
newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
templateDirective = previousCompileContext.templateDirective,
nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
hasTranscludeDirective = false,
@@ -17075,10 +17111,11 @@
}
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
controllerDirectives: controllerDirectives,
+ newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
newIsolateScopeDirective: newIsolateScopeDirective,
templateDirective: templateDirective,
nonTlbTranscludeDirective: nonTlbTranscludeDirective
});
ii = directives.length;
@@ -17102,11 +17139,10 @@
}
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
- nodeLinkFn.elementTranscludeOnThisElement = hasElementTranscludeDirective;
nodeLinkFn.templateOnThisElement = hasTemplate;
nodeLinkFn.transclude = childTranscludeFn;
previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
@@ -17263,13 +17299,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);
@@ -17457,11 +17496,11 @@
: origAsyncDirective.templateUrl,
templateNamespace = origAsyncDirective.templateNamespace;
$compileNode.empty();
- $templateRequest($sce.getTrustedResourceUrl(templateUrl))
+ $templateRequest(templateUrl)
.then(function(content) {
var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
content = denormalizeTemplate(content);
@@ -17565,15 +17604,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) {
@@ -17750,30 +17796,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
@@ -17810,13 +17858,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]) {
@@ -17829,10 +17887,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); };
}
@@ -17867,13 +17926,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;
@@ -18270,17 +18326,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) {
@@ -18303,11 +18363,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 = [];
@@ -18460,11 +18556,11 @@
*
* Object containing default values for all {@link ng.$http $http} requests.
*
* - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
* that will provide the cache for all requests who set their `cache` property to `true`.
- * If you set the `default.cache = false` then only requests that specify their own custom
+ * If you set the `defaults.cache = false` then only requests that specify their own custom
* cache object will be cached. See {@link $http#caching $http Caching} for more information.
*
* - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
* Defaults value is `'XSRF-TOKEN'`.
*
@@ -18477,15 +18573,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],
@@ -18946,19 +19043,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.
@@ -18972,25 +19071,29 @@
* - **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}
* that should abort the request when resolved.
* - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
* XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
* for more information.
* - **responseType** - `{string}` - see
- * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
+ * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
*
* @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
* standard `then` method and two http specific methods: `success` and `error`. The `then`
* method takes two arguments a success and an error callback which will be called with a
* response object. The `success` and `error` methods take a single argument - a function that
@@ -20469,11 +20572,11 @@
*/
this.$$parse = function(url) {
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
var withoutHashUrl;
- if (withoutBaseUrl.charAt(0) === '#') {
+ if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
// The rest of the url starts with a hash so we have
// got either a hashbang path or a plain hash fragment
withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
if (isUndefined(withoutHashUrl)) {
@@ -20483,11 +20586,19 @@
} else {
// There was no hashbang path nor hash fragment:
// If we are in HTML5 mode we use what is left as the path;
// Otherwise we ignore what is left
- withoutHashUrl = this.$$html5 ? withoutBaseUrl : '';
+ if (this.$$html5) {
+ withoutHashUrl = withoutBaseUrl;
+ } else {
+ withoutHashUrl = '';
+ if (isUndefined(withoutBaseUrl)) {
+ appBase = url;
+ this.replace();
+ }
+ }
}
parseAppUrl(withoutHashUrl, this);
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
@@ -22403,12 +22514,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) {
@@ -22442,12 +22555,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();
@@ -23826,10 +23941,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
@@ -23892,10 +24020,11 @@
};
$Q.defer = defer;
$Q.reject = reject;
$Q.when = when;
+ $Q.resolve = resolve;
$Q.all = all;
return $Q;
}
@@ -26536,27 +26665,38 @@
/**
* @ngdoc service
* @name $templateRequest
*
* @description
- * The `$templateRequest` service downloads the provided template using `$http` and, upon success,
- * stores the contents inside of `$templateCache`. If the HTTP request fails or the response data
- * of the HTTP request is empty, a `$compile` error will be thrown (the exception can be thwarted
- * by setting the 2nd parameter of the function to true).
+ * The `$templateRequest` service runs security checks then downloads the provided template using
+ * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
+ * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
+ * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
+ * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
+ * when `tpl` is of type string and `$templateCache` has the matching entry.
*
- * @param {string} tpl The HTTP request template URL
+ * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
* @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
*
* @return {Promise} a promise for the HTTP response data of the given URL.
*
* @property {number} totalPendingRequests total amount of pending template requests being downloaded.
*/
function $TemplateRequestProvider() {
- this.$get = ['$templateCache', '$http', '$q', function($templateCache, $http, $q) {
+ this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
function handleRequestFn(tpl, ignoreRequestError) {
handleRequestFn.totalPendingRequests++;
+ // We consider the template cache holds only trusted templates, so
+ // there's no need to go through whitelisting again for keys that already
+ // are included in there. This also makes Angular accept any script
+ // directive, no matter its name. However, we still need to unwrap trusted
+ // types.
+ if (!isString(tpl) || !$templateCache.get(tpl)) {
+ tpl = $sce.getTrustedResourceUrl(tpl);
+ }
+
var transformResponse = $http.defaults && $http.defaults.transformResponse;
if (isArray(transformResponse)) {
transformResponse = transformResponse.filter(function(transformer) {
return transformer !== defaultHttpResponseTransform;
@@ -27201,14 +27341,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:
@@ -27328,14 +27470,10 @@
return Array.prototype.filter.call(array, predicateFn);
};
}
-function hasCustomToString(obj) {
- return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
-}
-
// Helper functions for `filterFilter`
function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
var predicateFn;
@@ -27504,13 +27642,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.
@@ -28135,11 +28274,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.
*
@@ -28210,23 +28349,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>
@@ -28282,94 +28442,120 @@
</example>
*/
orderByFilter.$inject = ['$parse'];
function orderByFilter($parse) {
return function(array, sortPredicate, reverseOrder) {
+
if (!(isArrayLike(array))) return array;
- sortPredicate = isArray(sortPredicate) ? sortPredicate : [sortPredicate];
+
+ if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
if (sortPredicate.length === 0) { sortPredicate = ['+']; }
- sortPredicate = sortPredicate.map(function(predicate) {
- var descending = false, get = predicate || identity;
- if (isString(predicate)) {
+
+ var predicates = processPredicates(sortPredicate, reverseOrder);
+
+ // The next three lines are a version of a Swartzian Transform idiom from Perl
+ // (sometimes called the Decorate-Sort-Undecorate idiom)
+ // See https://en.wikipedia.org/wiki/Schwartzian_transform
+ var compareValues = Array.prototype.map.call(array, getComparisonObject);
+ compareValues.sort(doComparison);
+ array = compareValues.map(function(item) { return item.value; });
+
+ return array;
+
+ function getComparisonObject(value, index) {
+ return {
+ value: value,
+ predicateValues: predicates.map(function(predicate) {
+ return getPredicateValue(predicate.get(value), index);
+ })
+ };
+ }
+
+ function doComparison(v1, v2) {
+ var result = 0;
+ for (var index=0, length = predicates.length; index < length; ++index) {
+ result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
+ if (result) break;
+ }
+ return result;
+ }
+ };
+
+ function processPredicates(sortPredicate, reverseOrder) {
+ reverseOrder = reverseOrder ? -1 : 1;
+ return sortPredicate.map(function(predicate) {
+ var descending = 1, get = identity;
+
+ if (isFunction(predicate)) {
+ get = predicate;
+ } else if (isString(predicate)) {
if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
- descending = predicate.charAt(0) == '-';
+ descending = predicate.charAt(0) == '-' ? -1 : 1;
predicate = predicate.substring(1);
}
- if (predicate === '') {
- // Effectively no predicate was passed so we compare identity
- return reverseComparator(compare, descending);
+ if (predicate !== '') {
+ get = $parse(predicate);
+ if (get.constant) {
+ var key = get();
+ get = function(value) { return value[key]; };
+ }
}
- get = $parse(predicate);
- if (get.constant) {
- var key = get();
- return reverseComparator(function(a, b) {
- return compare(a[key], b[key]);
- }, descending);
- }
}
- return reverseComparator(function(a, b) {
- return compare(get(a),get(b));
- }, descending);
+ return { get: get, descending: descending * reverseOrder };
});
- return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
+ }
- function comparator(o1, o2) {
- for (var i = 0; i < sortPredicate.length; i++) {
- var comp = sortPredicate[i](o1, o2);
- if (comp !== 0) return comp;
- }
- return 0;
+ function isPrimitive(value) {
+ switch (typeof value) {
+ case 'number': /* falls through */
+ case 'boolean': /* falls through */
+ case 'string':
+ return true;
+ default:
+ return false;
}
- function reverseComparator(comp, descending) {
- return descending
- ? function(a, b) {return comp(b,a);}
- : comp;
- }
+ }
- function isPrimitive(value) {
- switch (typeof value) {
- case 'number': /* falls through */
- case 'boolean': /* falls through */
- case 'string':
- return true;
- default:
- return false;
- }
+ function objectValue(value, index) {
+ // If `valueOf` is a valid function use that
+ if (typeof value.valueOf === 'function') {
+ value = value.valueOf();
+ if (isPrimitive(value)) return value;
}
+ // If `toString` is a valid function and not the one from `Object.prototype` use that
+ if (hasCustomToString(value)) {
+ value = value.toString();
+ if (isPrimitive(value)) return value;
+ }
+ // We have a basic object so we use the position of the object in the collection
+ return index;
+ }
- function objectToString(value) {
- if (value === null) return 'null';
- if (typeof value.valueOf === 'function') {
- value = value.valueOf();
- if (isPrimitive(value)) return value;
- }
- if (typeof value.toString === 'function') {
- value = value.toString();
- if (isPrimitive(value)) return value;
- }
- return '';
+ function getPredicateValue(value, index) {
+ var type = typeof value;
+ if (value === null) {
+ type = 'string';
+ value = 'null';
+ } else if (type === 'string') {
+ value = value.toLowerCase();
+ } else if (type === 'object') {
+ value = objectValue(value, index);
}
+ return { value: value, type: type };
+ }
- function compare(v1, v2) {
- var t1 = typeof v1;
- var t2 = typeof v2;
- if (t1 === t2 && t1 === "object") {
- v1 = objectToString(v1);
- v2 = objectToString(v2);
+ function compare(v1, v2) {
+ var result = 0;
+ if (v1.type === v2.type) {
+ if (v1.value !== v2.value) {
+ result = v1.value < v2.value ? -1 : 1;
}
- if (t1 === t2) {
- if (t1 === "string") {
- v1 = v1.toLowerCase();
- v2 = v2.toLowerCase();
- }
- if (v1 === v2) return 0;
- return v1 < v2 ? -1 : 1;
- } else {
- return t1 < t2 ? -1 : 1;
- }
+ } else {
+ result = v1.type < v2.type ? -1 : 1;
}
- };
+ return result;
+ }
}
function ngDirective(directive) {
if (isFunction(directive)) {
directive = {
@@ -28619,10 +28805,17 @@
* @name ngChecked
* @restrict A
* @priority 100
*
* @description
+ * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
+ *
+ * Note that this directive should not be used together with {@link ngModel `ngModel`},
+ * as this can lead to unexpected behavior.
+ *
+ * ### Why do we need `ngChecked`?
+ *
* The HTML specification does not require browsers to preserve the values of boolean attributes
* such as checked. (Their presence means true and their absence means false.)
* If we put an Angular interpolation expression into such an attribute then the
* binding information would be lost when the browser removes the attribute.
* The `ngChecked` directive solves this problem for the `checked` attribute.
@@ -28643,11 +28836,11 @@
</file>
</example>
*
* @element INPUT
* @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
- * then special attribute "checked" will be set on the element
+ * then the `checked` attribute will be set on the element
*/
/**
* @ngdoc directive
@@ -29385,11 +29578,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})?)?$/;
@@ -29984,10 +30177,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.
@@ -30275,16 +30478,19 @@
*
* @description
* HTML radio button.
*
* @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string} value The value to which the expression should be set when selected.
+ * @param {string} value The value to which the `ngModel` expression should be set when selected.
+ * Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
+ * too. Use `ngValue` if you need complex models (`number`, `object`, ...).
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} ngChange Angular expression to be executed when input changes due to user
* interaction with the input element.
- * @param {string} ngValue Angular expression which sets the value to which the expression should
- * be set when selected.
+ * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
+ * is selected. Should be used instead of the `value` attribute if you need
+ * a non-string `ngModel` (`boolean`, `array`, ...).
*
* @example
<example name="radio-input-directive" module="radioExample">
<file name="index.html">
<script>
@@ -31520,22 +31726,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">
@@ -31560,27 +31766,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();
@@ -32704,10 +32914,11 @@
/**
* @ngdoc directive
* @name ngIf
* @restrict A
+ * @multiElement
*
* @description
* The `ngIf` directive removes or recreates a portion of the DOM tree based on an
* {expression}. If the expression assigned to `ngIf` evaluates to a false
* value then the element is removed from the DOM, otherwise a clone of the
@@ -33002,12 +33213,12 @@
* Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
*
* @param {Object} angularEvent Synthetic event object.
* @param {String} src URL of content to load.
*/
-var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate', '$sce',
- function($templateRequest, $anchorScroll, $animate, $sce) {
+var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
+ function($templateRequest, $anchorScroll, $animate) {
return {
restrict: 'ECA',
priority: 400,
terminal: true,
transclude: 'element',
@@ -33039,11 +33250,11 @@
previousElement = currentElement;
currentElement = null;
}
};
- scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
+ scope.$watch(srcExp, function ngIncludeWatchAction(src) {
var afterAnimation = function() {
if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
$anchorScroll();
}
};
@@ -34410,11 +34621,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
@@ -34660,11 +34871,13 @@
}
function isObjectEmpty(obj) {
if (obj) {
for (var prop in obj) {
- return false;
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
}
}
return true;
}
@@ -34992,23 +35205,45 @@
this.label = label;
this.group = group;
this.disabled = disabled;
}
+ function getOptionValuesKeys(optionValues) {
+ var optionValuesKeys;
+
+ if (!keyName && isArrayLike(optionValues)) {
+ optionValuesKeys = optionValues;
+ } else {
+ // if object, extract keys, in enumeration order, unsorted
+ optionValuesKeys = [];
+ for (var itemKey in optionValues) {
+ if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
+ optionValuesKeys.push(itemKey);
+ }
+ }
+ }
+ return optionValuesKeys;
+ }
+
return {
trackBy: trackBy,
getTrackByValue: getTrackByValue,
- getWatchables: $parse(valuesFn, function(values) {
+ getWatchables: $parse(valuesFn, function(optionValues) {
// Create a collection of things that we would like to watch (watchedArray)
// so that they can all be watched using a single $watchCollection
// that only runs the handler once if anything changes
var watchedArray = [];
- values = values || [];
+ optionValues = optionValues || [];
- Object.keys(values).forEach(function getWatchable(key) {
- var locals = getLocals(values[key], key);
- var selectValue = getTrackByValueFn(values[key], locals);
+ var optionValuesKeys = getOptionValuesKeys(optionValues);
+ var optionValuesLength = optionValuesKeys.length;
+ for (var index = 0; index < optionValuesLength; index++) {
+ var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
+ var value = optionValues[key];
+
+ var locals = getLocals(optionValues[key], key);
+ var selectValue = getTrackByValueFn(optionValues[key], locals);
watchedArray.push(selectValue);
// Only need to watch the displayFn if there is a specific label expression
if (match[2] || match[1]) {
var label = displayFn(scope, locals);
@@ -35018,11 +35253,11 @@
// Only need to watch the disableWhenFn if there is a specific disable expression
if (match[4]) {
var disableWhen = disableWhenFn(scope, locals);
watchedArray.push(disableWhen);
}
- });
+ }
return watchedArray;
}),
getOptions: function() {
@@ -35030,25 +35265,11 @@
var selectValueMap = {};
// The option values were already computed in the `getWatchables` fn,
// which must have been called to trigger `getOptions`
var optionValues = valuesFn(scope) || [];
- var optionValuesKeys;
-
-
- if (!keyName && isArrayLike(optionValues)) {
- optionValuesKeys = optionValues;
- } else {
- // if object, extract keys, in enumeration order, unsorted
- optionValuesKeys = [];
- for (var itemKey in optionValues) {
- if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
- optionValuesKeys.push(itemKey);
- }
- }
- }
-
+ var optionValuesKeys = getOptionValuesKeys(optionValues);
var optionValuesLength = optionValuesKeys.length;
for (var index = 0; index < optionValuesLength; index++) {
var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
var value = optionValues[key];
@@ -35406,12 +35627,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();
}
}
@@ -35661,10 +35881,11 @@
}];
/**
* @ngdoc directive
* @name ngRepeat
+ * @multiElement
*
* @description
* The `ngRepeat` directive instantiates a template once per item from a collection. Each template
* instance gets its own scope, where the given loop variable is set to the current collection item,
* and `$index` is set to the item index or key.
@@ -35755,10 +35976,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.
@@ -35826,13 +36056,14 @@
*
* * `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
* `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
@@ -36180,10 +36411,11 @@
var NG_HIDE_CLASS = 'ng-hide';
var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
/**
* @ngdoc directive
* @name ngShow
+ * @multiElement
*
* @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
@@ -36355,9 +36587,10 @@
/**
* @ngdoc directive
* @name ngHide
+ * @multiElement
*
* @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
\ No newline at end of file