{{ record.title }}
diff --git a/UI/WebServerResources/js/vendor/angular-animate.min.js b/UI/WebServerResources/js/vendor/angular-animate.min.js
index 6ba5b6d90..29fb5398c 100644
--- a/UI/WebServerResources/js/vendor/angular-animate.min.js
+++ b/UI/WebServerResources/js/vendor/angular-animate.min.js
@@ -1,57 +1,57 @@
/*
- AngularJS v1.5.10
+ AngularJS v1.6.1
(c) 2010-2016 Google, Inc. http://angularjs.org
License: MIT
*/
-(function(R,B){'use strict';function Da(a,b,c){if(!a)throw Ma("areq",b||"?",c||"required");return a}function Ea(a,b){if(!a&&!b)return"";if(!a)return b;if(!b)return a;X(a)&&(a=a.join(" "));X(b)&&(b=b.join(" "));return a+" "+b}function Na(a){var b={};a&&(a.to||a.from)&&(b.to=a.to,b.from=a.from);return b}function Y(a,b,c){var d="";a=X(a)?a:a&&G(a)&&a.length?a.split(/\s+/):[];s(a,function(a,l){a&&0=a&&(a=e,e=0,b.push(k),k=[]);k.push(g.fn);g.children.forEach(function(a){e++;c.push(a)});a--}k.length&&b.push(k);return b}(c)}var u=[],C=Z(a);return function(n,Q,t){function H(a){a=
-a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];s(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function T(a){var b=[],c={};s(a,function(a,d){var h=y(a.element),e=0<=["enter","move"].indexOf(a.event),h=a.structural?H(h):[];if(h.length){var k=e?"to":"from";s(h,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][k]={animationID:d,element:F(a)}})}else b.push(a)});var d={},e={};s(c,function(c,k){var r=c.from,
-p=c.to;if(r&&p){var z=a[r.animationID],g=a[p.animationID],A=r.animationID.toString();if(!e[A]){var n=e[A]={structural:!0,beforeStart:function(){z.beforeStart();g.beforeStart()},close:function(){z.close();g.close()},classes:O(z.classes,g.classes),from:z,to:g,anchors:[]};n.classes.length?b.push(n):(b.push(z),b.push(g))}e[A].anchors.push({out:r.element,"in":p.element})}else r=r?r.animationID:p.animationID,p=r.toString(),d[p]||(d[p]=!0,b.push(a[r]))});return b}function O(a,b){a=a.split(" ");b=b.split(" ");
-for(var c=[],d=0;d=R&&b>=m&&(F=!0,k())}function N(){function b(){if(!w){M(!1);s(x,function(a){h.style[a[0]]=a[1]});T(a,f);e.addClass(a,ea);if(q.recalculateTimingStyles){na=
-h.className+" "+ga;ia=B(h,na);D=H(h,na,ia);ca=D.maxDelay;J=Math.max(ca,0);m=D.maxDuration;if(0===m){k();return}q.hasTransitions=0l.expectedEndTime)?n.cancel(l.timer):g.push(k)}N&&(p=n(c,p,!1),g[0]={timer:p,expectedEndTime:d},g.push(k),a.data("$$animateCss",g));if(fa.length)a.on(fa.join(" "),z);f.to&&(f.cleanupStyles&&Ka(A,h,Object.keys(f.to)),Ga(a,f))}}function c(){var b=a.data("$$animateCss");if(b){for(var d=1;d=a&&(a=f,f=0,b.push(e),e=[]);e.push(k.fn);k.children.forEach(function(a){f++;c.push(a)});a--}e.length&&b.push(e);return b}(c)}var s=[],ba=Z(a);return function(m,O,v){function H(a){a=
+a.hasAttribute("ng-animate-ref")?[a]:a.querySelectorAll("[ng-animate-ref]");var b=[];r(a,function(a){var c=a.getAttribute("ng-animate-ref");c&&c.length&&b.push(a)});return b}function S(a){var b=[],c={};r(a,function(a,d){var h=z(a.element),k=0<=["enter","move"].indexOf(a.event),h=a.structural?H(h):[];if(h.length){var f=k?"to":"from";r(h,function(a){var b=a.getAttribute("ng-animate-ref");c[b]=c[b]||{};c[b][f]={animationID:d,element:w(a)}})}else b.push(a)});var d={},k={};r(c,function(c,f){var e=c.from,
+B=c.to;if(e&&B){var p=a[e.animationID],n=a[B.animationID],l=e.animationID.toString();if(!k[l]){var m=k[l]={structural:!0,beforeStart:function(){p.beforeStart();n.beforeStart()},close:function(){p.close();n.close()},classes:P(p.classes,n.classes),from:p,to:n,anchors:[]};m.classes.length?b.push(m):(b.push(p),b.push(n))}k[l].anchors.push({out:e.element,"in":B.element})}else e=e?e.animationID:B.animationID,B=e.toString(),d[B]||(d[B]=!0,b.push(a[e]))});return b}function P(a,b){a=a.split(" ");b=b.split(" ");
+for(var c=[],d=0;d=K&&b>=M&&(P=!0,l())}function E(){function b(){if(!A){k(!1);r(t,function(a){h.style[a[0]]=a[1]});S(a,g);f.addClass(a,ea);if(q.recalculateTimingStyles){na=
+h.getAttribute("class")+" "+ga;ja=C(h,na);D=H(h,na,ja);ca=D.maxDelay;u=Math.max(ca,0);M=D.maxDuration;if(0===M){l();return}q.hasTransitions=0p.expectedEndTime)?m.cancel(p.timer):e.push(l)}n&&(E=m(c,E,!1),e[0]={timer:E,expectedEndTime:d},e.push(l),a.data("$$animateCss",e));if(fa.length)a.on(fa.join(" "),Q);g.to&&(g.cleanupStyles&&La(I,h,Object.keys(g.to)),Ha(a,g))}}function c(){var b=a.data("$$animateCss");if(b){for(var d=
+1;d(?:<\/\1>|)$/;
@@ -3009,6 +3071,8 @@ function JQLite(element) {
if (argIsString) {
jqLiteAddNodes(this, jqLiteParseHTML(element));
+ } else if (isFunction(element)) {
+ jqLiteReady(element);
} else {
jqLiteAddNodes(this, element);
}
@@ -3041,7 +3105,7 @@ function jqLiteOff(element, type, fn, unsupported) {
if (!type) {
for (type in events) {
if (type !== '$destroy') {
- removeEventListenerFn(element, type, handle);
+ element.removeEventListener(type, handle);
}
delete events[type];
}
@@ -3053,7 +3117,7 @@ function jqLiteOff(element, type, fn, unsupported) {
arrayRemove(listenerFns || [], fn);
}
if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
- removeEventListenerFn(element, type, handle);
+ element.removeEventListener(type, handle);
delete events[type];
}
};
@@ -3104,6 +3168,7 @@ function jqLiteExpandoStore(element, createIfNecessary) {
function jqLiteData(element, key, value) {
if (jqLiteAcceptsData(element)) {
+ var prop;
var isSimpleSetter = isDefined(value);
var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
@@ -3112,16 +3177,18 @@ function jqLiteData(element, key, value) {
var data = expandoStore && expandoStore.data;
if (isSimpleSetter) { // data('key', value)
- data[key] = value;
+ data[kebabToCamel(key)] = value;
} else {
if (massGetter) { // data()
return data;
} else {
if (isSimpleGetter) { // data('key')
// don't force creation of expandoStore if it doesn't exist yet
- return data && data[key];
+ return data && data[kebabToCamel(key)];
} else { // mass-setter: data({key1: val1, key2: val2})
- extend(data, key);
+ for (prop in key) {
+ data[kebabToCamel(prop)] = key[prop];
+ }
}
}
}
@@ -3240,29 +3307,32 @@ function jqLiteDocumentLoaded(action, win) {
}
}
+function jqLiteReady(fn) {
+ function trigger() {
+ window.document.removeEventListener('DOMContentLoaded', trigger);
+ window.removeEventListener('load', trigger);
+ fn();
+ }
+
+ // check if document is already loaded
+ if (window.document.readyState === 'complete') {
+ window.setTimeout(fn);
+ } else {
+ // We can not use jqLite since we are not done loading and jQuery could be loaded later.
+
+ // Works for modern browsers and IE9
+ window.document.addEventListener('DOMContentLoaded', trigger);
+
+ // Fallback to window.onload for others
+ window.addEventListener('load', trigger);
+ }
+}
+
//////////////////////////////////////////
// Functions which are declared directly.
//////////////////////////////////////////
var JQLitePrototype = JQLite.prototype = {
- ready: function(fn) {
- var fired = false;
-
- function trigger() {
- if (fired) return;
- fired = true;
- fn();
- }
-
- // check if document is already loaded
- if (window.document.readyState === 'complete') {
- window.setTimeout(trigger);
- } else {
- this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
- // we can not use jqLite since we are not done loading and jQuery could be loaded later.
- // eslint-disable-next-line new-cap
- JQLite(window).on('load', trigger); // fallback to window.onload for others
- }
- },
+ ready: jqLiteReady,
toString: function() {
var value = [];
forEach(this, function(e) { value.push('' + e);});
@@ -3297,7 +3367,8 @@ var ALIASED_ATTR = {
'ngMaxlength': 'maxlength',
'ngMin': 'min',
'ngMax': 'max',
- 'ngPattern': 'pattern'
+ 'ngPattern': 'pattern',
+ 'ngStep': 'step'
};
function getBooleanAttrName(element, name) {
@@ -3348,7 +3419,7 @@ forEach({
hasClass: jqLiteHasClass,
css: function(element, name, value) {
- name = camelCase(name);
+ name = cssKebabToCamel(name);
if (isDefined(value)) {
element.style[name] = value;
@@ -3358,33 +3429,33 @@ forEach({
},
attr: function(element, name, value) {
+ var ret;
var nodeType = element.nodeType;
- if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
+ if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
+ !element.getAttribute) {
return;
}
+
var lowercasedName = lowercase(name);
- if (BOOLEAN_ATTR[lowercasedName]) {
- if (isDefined(value)) {
- if (value) {
- element[name] = true;
- element.setAttribute(name, lowercasedName);
- } else {
- element[name] = false;
- element.removeAttribute(lowercasedName);
- }
+ var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
+
+ if (isDefined(value)) {
+ // setter
+
+ if (value === null || (value === false && isBooleanAttr)) {
+ element.removeAttribute(name);
} else {
- return (element[name] ||
- (element.attributes.getNamedItem(name) || noop).specified)
- ? lowercasedName
- : undefined;
+ element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
}
- } else if (isDefined(value)) {
- element.setAttribute(name, value);
- } else if (element.getAttribute) {
- // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
- // some elements (e.g. Document) don't have get attribute, so return undefined
- var ret = element.getAttribute(name, 2);
- // normalize non-existing attributes to undefined (as jQuery)
+ } else {
+ // getter
+
+ ret = element.getAttribute(name);
+
+ if (isBooleanAttr && ret !== null) {
+ ret = lowercasedName;
+ }
+ // Normalize non-existing attributes to undefined (as jQuery).
return ret === null ? undefined : ret;
}
},
@@ -3419,7 +3490,7 @@ forEach({
result.push(option.value || option.text);
}
});
- return result.length === 0 ? null : result;
+ return result;
}
return element.value;
}
@@ -3589,7 +3660,7 @@ forEach({
eventFns = events[type] = [];
eventFns.specialHandlerWrapper = specialHandlerWrapper;
if (type !== '$destroy' && !noEventListener) {
- addEventListenerFn(element, type, handle);
+ element.addEventListener(type, handle);
}
}
@@ -4740,14 +4811,18 @@ function createInjector(modulesToLoad, strictDi) {
}
function isClass(func) {
+ // Support: IE 9-11 only
// IE 9-11 do not support classes and IE9 leaks with the code below.
- if (msie <= 11) {
+ if (msie || typeof func !== 'function') {
return false;
}
- // Support: Edge 12-13 only
- // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
- return typeof func === 'function'
- && /^(?:class\b|constructor\()/.test(stringifyFn(func));
+ var result = func.$$ngIsClass;
+ if (!isBoolean(result)) {
+ // Support: Edge 12-13 only
+ // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
+ result = func.$$ngIsClass = /^(?:class\b|constructor\()/.test(stringifyFn(func));
+ }
+ return result;
}
function invoke(fn, self, locals, serviceName) {
@@ -5322,7 +5397,6 @@ var $AnimateProvider = ['$provide', /** @this */ function($provide) {
var reservedRegex = new RegExp('(\\s+|\\/)' + NG_ANIMATE_CLASSNAME + '(\\s+|\\/)');
if (reservedRegex.test(this.$$classNameFilter.toString())) {
throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
-
}
}
}
@@ -5758,8 +5832,8 @@ var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
};
var $$AnimateRunnerFactoryProvider = /** @this */ function() {
- this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
- function($q, $sniffer, $$animateAsyncRun, $document, $timeout) {
+ this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
+ function($q, $sniffer, $$animateAsyncRun, $$isDocumentHidden, $timeout) {
var INITIAL_STATE = 0;
var DONE_PENDING_STATE = 1;
@@ -5811,11 +5885,7 @@ var $$AnimateRunnerFactoryProvider = /** @this */ function() {
this._doneCallbacks = [];
this._tick = function(fn) {
- var doc = $document[0];
-
- // the document may not be ready or attached
- // to the module for some internal tests
- if (doc && doc.hidden) {
+ if ($$isDocumentHidden()) {
timeoutTick(fn);
} else {
rafTick(fn);
@@ -8149,7 +8219,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
*
* The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.
*/
- var preAssignBindingsEnabled = true;
+ var preAssignBindingsEnabled = false;
this.preAssignBindingsEnabled = function(enabled) {
if (isDefined(enabled)) {
preAssignBindingsEnabled = enabled;
@@ -8611,25 +8681,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
// modify it.
$compileNodes = jqLite($compileNodes);
}
-
- var NOT_EMPTY = /\S+/;
-
- // We can not compile top level text elements since text nodes can be merged and we will
- // not be able to attach scope data to them, so we will wrap them in
- for (var i = 0, len = $compileNodes.length; i < len; i++) {
- var domNode = $compileNodes[i];
-
- if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
- jqLiteWrapNode(domNode, $compileNodes[i] = window.document.createElement('span'));
- }
- }
-
var compositeLinkFn =
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
compile.$$addScopeClass($compileNodes);
var namespace = null;
return function publicLinkFn(scope, cloneConnectFn, options) {
+ if (!$compileNodes) {
+ throw $compileMinErr('multilink', 'This element has already been linked.');
+ }
assertArg(scope, 'scope');
if (previousCompileContext && previousCompileContext.needsNewScope) {
@@ -8684,6 +8744,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (cloneConnectFn) cloneConnectFn($linkNode, scope);
if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
+
+ if (!cloneConnectFn) {
+ $compileNodes = compositeLinkFn = null;
+ }
return $linkNode;
};
}
@@ -8716,12 +8780,23 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
previousCompileContext) {
var linkFns = [],
+ // `nodeList` can be either an element's `.childNodes` (live NodeList)
+ // or a jqLite/jQuery collection or an array
+ notLiveList = isArray(nodeList) || (nodeList instanceof jqLite),
attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
+
for (var i = 0; i < nodeList.length; i++) {
attrs = new Attributes();
- // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
+ // Support: IE 11 only
+ // Workaround for #11781 and #14924
+ if (msie === 11) {
+ mergeConsecutiveTextNodes(nodeList, i, notLiveList);
+ }
+
+ // We must always refer to `nodeList[i]` hereafter,
+ // since the nodes can be replaced underneath us.
directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
ignoreDirective);
@@ -8812,6 +8887,32 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
}
+ function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) {
+ var node = nodeList[idx];
+ var parent = node.parentNode;
+ var sibling;
+
+ if (node.nodeType !== NODE_TYPE_TEXT) {
+ return;
+ }
+
+ while (true) {
+ sibling = parent ? node.nextSibling : nodeList[idx + 1];
+ if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) {
+ break;
+ }
+
+ node.nodeValue = node.nodeValue + sibling.nodeValue;
+
+ if (sibling.parentNode) {
+ sibling.parentNode.removeChild(sibling);
+ }
+ if (notLiveList && sibling === nodeList[idx + 1]) {
+ nodeList.splice(idx + 1, 1);
+ }
+ }
+ }
+
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
@@ -8875,7 +8976,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
attr = nAttrs[j];
name = attr.name;
- value = trim(attr.value);
+ value = attr.value;
// support ngAttr attribute binding
ngAttrName = directiveNormalize(name);
@@ -8931,13 +9032,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
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 */
@@ -9210,9 +9304,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var slots = createMap();
- $template = jqLite(jqLiteClone(compileNode)).contents();
-
- if (isObject(directiveValue)) {
+ if (!isObject(directiveValue)) {
+ $template = jqLite(jqLiteClone(compileNode)).contents();
+ } else {
// We have transclusion slots,
// collect them up, compile them and store their transclusion functions
@@ -9764,7 +9858,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
forEach(dst, function(value, key) {
if (key.charAt(0) !== '$') {
if (src[key] && src[key] !== value) {
- value += (key === 'style' ? ';' : ' ') + src[key];
+ if (value.length) {
+ value += (key === 'style' ? ';' : ' ') + src[key];
+ } else {
+ value = src[key];
+ }
}
dst.$set(key, value, true, srcAttr[key]);
}
@@ -9883,7 +9981,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
childBoundTranscludeFn);
}
linkQueue = null;
- });
+ }).catch(function(error) {
+ if (error instanceof Error) {
+ $exceptionHandler(error);
+ }
+ }).catch(noop);
return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
var childBoundTranscludeFn = boundTranscludeFn;
@@ -9983,7 +10085,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
// maction[xlink:href] can source SVG. It's not limited to .
} else if (attrNormalizedName === 'xlinkHref' ||
- (tag === 'form' && attrNormalizedName === 'action')
+ (tag === 'form' && attrNormalizedName === 'action') ||
+ // links can be stylesheets or imports, which can run script in the current origin
+ (tag === 'link' && attrNormalizedName === 'href')
) {
return $sce.RESOURCE_URL;
}
@@ -10006,6 +10110,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
startingTag(node));
}
+ if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
+ throw $compileMinErr('nodomevents',
+ 'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
+ 'ng- versions (such as ng-click instead of onclick) instead.');
+ }
+
directives.push({
priority: 100,
compile: function() {
@@ -10013,12 +10123,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
pre: function attrInterpolatePreLinkFn(scope, element, attr) {
var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
- if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
- throw $compileMinErr('nodomevents',
- 'Interpolations for HTML DOM event attributes are disallowed. Please use the ' +
- 'ng- versions (such as ng-click instead of onclick) instead.');
- }
-
// If the attribute has changed since last $interpolate()ed
var newValue = attr[name];
if (newValue !== value) {
@@ -10327,12 +10431,16 @@ SimpleChange.prototype.isFirstChange = function() { return this.previousValue ==
var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
+var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
+
/**
* Converts all accepted directives format into proper directive name.
* @param name Name to normalize
*/
function directiveNormalize(name) {
- return camelCase(name.replace(PREFIX_REGEXP, ''));
+ return name
+ .replace(PREFIX_REGEXP, '')
+ .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace);
}
/**
@@ -10487,13 +10595,12 @@ function $ControllerProvider() {
/**
* @ngdoc method
* @name $controllerProvider#allowGlobals
+ * @description If called, allows `$controller` to find controller constructors on `window`
*
* @deprecated
* sinceVersion="v1.3.0"
* removeVersion="v1.7.0"
* This method of finding controllers has been deprecated.
- *
- * @description If called, allows `$controller` to find controller constructors on `window` *
*/
this.allowGlobals = function() {
globals = true;
@@ -10514,7 +10621,7 @@ function $ControllerProvider() {
* * check if a controller with given name is registered via `$controllerProvider`
* * check if evaluating the string on the current scope returns a constructor
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
- * `window` object (not recommended)
+ * `window` object (deprecated, not recommended)
*
* The string can use the `controller as property` syntax, where the controller instance is published
* as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
@@ -10653,6 +10760,33 @@ function $DocumentProvider() {
}];
}
+
+/**
+ * @private
+ * @this
+ * Listens for document visibility change and makes the current status accessible.
+ */
+function $$IsDocumentHiddenProvider() {
+ this.$get = ['$document', '$rootScope', function($document, $rootScope) {
+ var doc = $document[0];
+ var hidden = doc && doc.hidden;
+
+ $document.on('visibilitychange', changeListener);
+
+ $rootScope.$on('$destroy', function() {
+ $document.off('visibilitychange', changeListener);
+ });
+
+ function changeListener() {
+ hidden = doc.hidden;
+ }
+
+ return function() {
+ return hidden;
+ };
+ }];
+}
+
/**
* @ngdoc service
* @name $exceptionHandler
@@ -10737,11 +10871,6 @@ var JSON_ENDS = {
};
var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/;
var $httpMinErr = minErr('$http');
-var $httpMinErrLegacyFn = function(method) {
- return function() {
- throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
- };
-};
function serializeValue(v) {
if (isObject(v)) {
@@ -11014,6 +11143,10 @@ function $HttpProvider() {
* If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
* Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
*
+ * - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
+ * callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
+ * {@link $jsonpCallbacks} service. Defaults to `'callback'`.
+ *
**/
var defaults = this.defaults = {
// transform incoming response data
@@ -11037,7 +11170,9 @@ function $HttpProvider() {
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
- paramSerializer: '$httpParamSerializer'
+ paramSerializer: '$httpParamSerializer',
+
+ jsonpCallbackParam: 'callback'
};
var useApplyAsync = false;
@@ -11068,35 +11203,6 @@ function $HttpProvider() {
return useApplyAsync;
};
- var useLegacyPromise = true;
- /**
- * @ngdoc method
- * @name $httpProvider#useLegacyPromiseExtensions
- * @description
- *
- * @deprecated
- * sinceVersion="v1.4.4"
- * removeVersion="v1.6.0"
- * This method will be removed in v1.6.0 along with the legacy promise methods.
- *
- * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
- * This should be used to make sure that applications work without these methods.
- *
- * Defaults to true. If no value is specified, returns the current configured value.
- *
- * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
- *
- * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
- * otherwise, returns the current configured value.
- **/
- this.useLegacyPromiseExtensions = function(value) {
- if (isDefined(value)) {
- useLegacyPromise = !!value;
- return this;
- }
- return useLegacyPromise;
- };
-
/**
* @ngdoc property
* @name $httpProvider#interceptors
@@ -11112,8 +11218,8 @@ function $HttpProvider() {
**/
var interceptorFactories = this.interceptors = [];
- this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
- function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
+ this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce',
+ function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) {
var defaultCache = $cacheFactory('$http');
@@ -11230,15 +11336,6 @@ function $HttpProvider() {
* $httpBackend.flush();
* ```
*
- * ## Deprecation Notice
- *
- * The `$http` legacy promise methods `success` and `error` have been deprecated and will be
- * removed in v1.6.0.
- * Use the standard `then` method instead.
- * If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
- * `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
- *
- *
* ## Setting HTTP Headers
*
* The $http service will automatically add certain HTTP headers to all requests. These defaults
@@ -11536,7 +11633,8 @@ function $HttpProvider() {
* 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.
+ * - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested;
+ * or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* - **params** – `{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.
@@ -11602,11 +11700,11 @@ function $HttpProvider() {
http status code: {{status}}
@@ -11615,6 +11713,13 @@ function $HttpProvider() {
angular.module('httpExample', [])
+ .config(['$sceDelegateProvider', function($sceDelegateProvider) {
+ // We must whitelist the JSONP endpoint that we are using to show that we trust it
+ $sceDelegateProvider.resourceUrlWhitelist([
+ 'self',
+ 'https://angularjs.org/**'
+ ]);
+ }])
.controller('FetchController', ['$scope', '$http', '$templateCache',
function($scope, $http, $templateCache) {
$scope.method = 'GET';
@@ -11682,15 +11787,16 @@ function $HttpProvider() {
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig);
}
- if (!isString(requestConfig.url)) {
- throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url);
+ if (!isString($sce.valueOf(requestConfig.url))) {
+ throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object. Received: {0}', requestConfig.url);
}
var config = extend({
method: 'get',
transformRequest: defaults.transformRequest,
transformResponse: defaults.transformResponse,
- paramSerializer: defaults.paramSerializer
+ paramSerializer: defaults.paramSerializer,
+ jsonpCallbackParam: defaults.jsonpCallbackParam
}, requestConfig);
config.headers = mergeHeaders(requestConfig);
@@ -11698,9 +11804,11 @@ function $HttpProvider() {
config.paramSerializer = isString(config.paramSerializer) ?
$injector.get(config.paramSerializer) : config.paramSerializer;
+ $browser.$$incOutstandingRequestCount();
+
var requestInterceptors = [];
var responseInterceptors = [];
- var promise = $q.when(config);
+ var promise = $q.resolve(config);
// apply interceptors
forEach(reversedInterceptors, function(interceptor) {
@@ -11715,29 +11823,7 @@ function $HttpProvider() {
promise = chainInterceptors(promise, requestInterceptors);
promise = promise.then(serverRequest);
promise = chainInterceptors(promise, responseInterceptors);
-
- if (useLegacyPromise) {
- promise.success = function(fn) {
- assertArgFn(fn, 'fn');
-
- promise.then(function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
-
- promise.error = function(fn) {
- assertArgFn(fn, 'fn');
-
- promise.then(null, function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
- } else {
- promise.success = $httpMinErrLegacyFn('success');
- promise.error = $httpMinErrLegacyFn('error');
- }
+ promise = promise.finally(completeOutstandingRequest);
return promise;
@@ -11755,6 +11841,10 @@ function $HttpProvider() {
return promise;
}
+ function completeOutstandingRequest() {
+ $browser.$$completeOutstandingRequest(noop);
+ }
+
function executeHeaderFns(headers, config) {
var headerContent, processedHeaders = {};
@@ -11838,7 +11928,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `GET` request.
*
- * @param {string} url Relative or absolute URL specifying the destination of the request
+ * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
+ * or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
@@ -11850,7 +11941,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `DELETE` request.
*
- * @param {string} url Relative or absolute URL specifying the destination of the request
+ * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
+ * or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
@@ -11862,7 +11954,8 @@ function $HttpProvider() {
* @description
* Shortcut method to perform `HEAD` request.
*
- * @param {string} url Relative or absolute URL specifying the destination of the request
+ * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
+ * or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
@@ -11873,11 +11966,34 @@ function $HttpProvider() {
*
* @description
* Shortcut method to perform `JSONP` request.
- * If you would like to customize where and how the callbacks are stored then try overriding
+ *
+ * Note that, since JSONP requests are sensitive because the response is given full access to the browser,
+ * the url must be declared, via {@link $sce} as a trusted resource URL.
+ * You can trust a URL by adding it to the whitelist via
+ * {@link $sceDelegateProvider#resourceUrlWhitelist `$sceDelegateProvider.resourceUrlWhitelist`} or
+ * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
+ *
+ * JSONP requests must specify a callback to be used in the response from the server. This callback
+ * is passed as a query parameter in the request. You must specify the name of this parameter by
+ * setting the `jsonpCallbackParam` property on the request config object.
+ *
+ * ```
+ * $http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
+ * ```
+ *
+ * You can also specify a default callback parameter name in `$http.defaults.jsonpCallbackParam`.
+ * Initially this is set to `'callback'`.
+ *
+ *
+ * You can no longer use the `JSON_CALLBACK` string as a placeholder for specifying where the callback
+ * parameter value should go.
+ *
+ *
+ * If you would like to customise where and how the callbacks are stored then try overriding
* or decorating the {@link $jsonpCallbacks} service.
*
- * @param {string} url Relative or absolute URL specifying the destination of the request.
- * The name of the callback should be the string `JSON_CALLBACK`.
+ * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
+ * or an object created by a call to `$sce.trustAsResourceUrl(url)`.
* @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object
*/
@@ -11976,12 +12092,28 @@ function $HttpProvider() {
cache,
cachedResp,
reqHeaders = config.headers,
- url = buildUrl(config.url, config.paramSerializer(config.params));
+ isJsonp = lowercase(config.method) === 'jsonp',
+ url = config.url;
+
+ if (isJsonp) {
+ // JSONP is a pretty sensitive operation where we're allowing a script to have full access to
+ // our DOM and JS space. So we require that the URL satisfies SCE.RESOURCE_URL.
+ url = $sce.getTrustedResourceUrl(url);
+ } else if (!isString(url)) {
+ // If it is not a string then the URL must be a $sce trusted object
+ url = $sce.valueOf(url);
+ }
+
+ url = buildUrl(url, config.paramSerializer(config.params));
+
+ if (isJsonp) {
+ // Check the url and add the JSONP callback placeholder
+ url = sanitizeJsonpCallbackParam(url, config.jsonpCallbackParam);
+ }
$http.pendingRequests.push(config);
promise.then(removePendingReq, removePendingReq);
-
if ((config.cache || defaults.cache) && config.cache !== false &&
(config.method === 'GET' || config.method === 'JSONP')) {
cache = isObject(config.cache) ? config.cache
@@ -12113,6 +12245,24 @@ function $HttpProvider() {
}
return url;
}
+
+ function sanitizeJsonpCallbackParam(url, key) {
+ if (/[&?][^=]+=JSON_CALLBACK/.test(url)) {
+ // Throw if the url already contains a reference to JSON_CALLBACK
+ throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url);
+ }
+
+ var callbackParamRegex = new RegExp('[&?]' + key + '=');
+ if (callbackParamRegex.test(url)) {
+ // Throw if the callback param was already provided
+ throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url);
+ }
+
+ // Add in the JSON_CALLBACK callback param value
+ url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK';
+
+ return url;
+ }
}];
}
@@ -12173,7 +12323,6 @@ function $HttpBackendProvider() {
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
// TODO(vojta): fix the signature
return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
- $browser.$$incOutstandingRequestCount();
url = url || $browser.url();
if (lowercase(method) === 'jsonp') {
@@ -12285,7 +12434,6 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
jsonpDone = xhr = null;
callback(status, response, headersString, statusText);
- $browser.$$completeOutstandingRequest(noop);
}
};
@@ -12300,8 +12448,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
script.async = true;
callback = function(event) {
- removeEventListenerFn(script, 'load', callback);
- removeEventListenerFn(script, 'error', callback);
+ script.removeEventListener('load', callback);
+ script.removeEventListener('error', callback);
rawDocument.body.removeChild(script);
script = null;
var status = -1;
@@ -12320,8 +12468,8 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
};
- addEventListenerFn(script, 'load', callback);
- addEventListenerFn(script, 'error', callback);
+ script.addEventListener('load', callback);
+ script.addEventListener('error', callback);
rawDocument.body.appendChild(script);
return callback;
}
@@ -12439,23 +12587,6 @@ function $InterpolateProvider() {
replace(escapedEndRegexp, endSymbol);
}
- function stringify(value) {
- if (value == null) { // null || undefined
- return '';
- }
- switch (typeof value) {
- case 'string':
- break;
- case 'number':
- value = '' + value;
- break;
- default:
- value = toJson(value);
- }
-
- return value;
- }
-
// TODO: this is the same as the constantWatchDelegate in parse.js
function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
@@ -12921,6 +13052,8 @@ function $IntervalProvider() {
*/
interval.cancel = function(promise) {
if (promise && promise.$$intervalId in intervals) {
+ // Interval cancels should not report as unhandled promise.
+ intervals[promise.$$intervalId].promise.catch(noop);
intervals[promise.$$intervalId].reject('canceled');
$window.clearInterval(promise.$$intervalId);
delete intervals[promise.$$intervalId];
@@ -13743,7 +13876,7 @@ function locationGetterSetter(property, preprocess) {
* Use the `$locationProvider` to configure how the application deep linking paths are stored.
*/
function $LocationProvider() {
- var hashPrefix = '',
+ var hashPrefix = '!',
html5Mode = {
enabled: false,
requireBase: true,
@@ -13754,7 +13887,7 @@ function $LocationProvider() {
* @ngdoc method
* @name $locationProvider#hashPrefix
* @description
- * The default value for the prefix is `''`.
+ * The default value for the prefix is `'!'`.
* @param {string=} prefix Prefix for hash part (containing path and search)
* @returns {*} current value if used as getter or itself (chaining) if used as setter
*/
@@ -13958,7 +14091,7 @@ function $LocationProvider() {
// update $location when $browser url changes
$browser.onUrlChange(function(newUrl, newState) {
- if (isUndefined(stripBaseUrl(appBaseNoFile, newUrl))) {
+ if (!startsWith(newUrl, appBaseNoFile)) {
// If we are navigating outside of the app then force a reload
$window.location.href = newUrl;
return;
@@ -14218,60 +14351,23 @@ function $LogProvider() {
var $parseMinErr = minErr('$parse');
-var ARRAY_CTOR = [].constructor;
-var BOOLEAN_CTOR = (false).constructor;
-var FUNCTION_CTOR = Function.constructor;
-var NUMBER_CTOR = (0).constructor;
-var OBJECT_CTOR = {}.constructor;
-var STRING_CTOR = ''.constructor;
-var ARRAY_CTOR_PROTO = ARRAY_CTOR.prototype;
-var BOOLEAN_CTOR_PROTO = BOOLEAN_CTOR.prototype;
-var FUNCTION_CTOR_PROTO = FUNCTION_CTOR.prototype;
-var NUMBER_CTOR_PROTO = NUMBER_CTOR.prototype;
-var OBJECT_CTOR_PROTO = OBJECT_CTOR.prototype;
-var STRING_CTOR_PROTO = STRING_CTOR.prototype;
-
-var CALL = FUNCTION_CTOR_PROTO.call;
-var APPLY = FUNCTION_CTOR_PROTO.apply;
-var BIND = FUNCTION_CTOR_PROTO.bind;
-
-var objectValueOf = OBJECT_CTOR_PROTO.valueOf;
+var objectValueOf = {}.constructor.prototype.valueOf;
// Sandboxing Angular Expressions
// ------------------------------
-// Angular expressions are generally considered safe because these expressions only have direct
-// access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
-// obtaining a reference to native JS functions such as the Function constructor.
+// Angular expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by
+// various means such as obtaining a reference to native JS functions like the Function constructor.
//
// As an example, consider the following Angular expression:
//
// {}.toString.constructor('alert("evil JS code")')
//
-// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
-// against the expression language, but not to prevent exploits that were enabled by exposing
-// sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
-// practice and therefore we are not even trying to protect against interaction with an object
-// explicitly exposed in this way.
-//
-// In general, it is not possible to access a Window object from an angular expression unless a
-// window or some DOM object that has a reference to window is published onto a Scope.
-// Similarly we prevent invocations of function known to be dangerous, as well as assignments to
-// native objects.
+// It is important to realize that if you create an expression from a string that contains user provided
+// content then it is possible that your application contains a security vulnerability to an XSS style attack.
//
// See https://docs.angularjs.org/guide/security
-function ensureSafeMemberName(name, fullExpression) {
- if (name === '__defineGetter__' || name === '__defineSetter__'
- || name === '__lookupGetter__' || name === '__lookupSetter__'
- || name === '__proto__') {
- throw $parseMinErr('isecfld',
- 'Attempting to access a disallowed field in Angular expressions! '
- + 'Expression: {0}', fullExpression);
- }
- return name;
-}
-
function getStringValue(name) {
// Property names must be strings. This means that non-string objects cannot be used
// as keys in an object. Any non-string object, including a number, is typecasted
@@ -14290,67 +14386,6 @@ function getStringValue(name) {
return name + '';
}
-function ensureSafeObject(obj, fullExpression) {
- // nifty check if obj is Function that is fast and works across iframes and other contexts
- if (obj) {
- if (obj.constructor === obj) {
- throw $parseMinErr('isecfn',
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (// isWindow(obj)
- obj.window === obj) {
- throw $parseMinErr('isecwindow',
- 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (// isElement(obj)
- obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
- throw $parseMinErr('isecdom',
- 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (// block Object so that we can't get hold of dangerous Object.* methods
- obj === Object) {
- throw $parseMinErr('isecobj',
- 'Referencing Object in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- }
- }
- return obj;
-}
-
-function ensureSafeFunction(obj, fullExpression) {
- if (obj) {
- if (obj.constructor === obj) {
- throw $parseMinErr('isecfn',
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (obj === CALL || obj === APPLY || obj === BIND) {
- throw $parseMinErr('isecff',
- 'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- }
- }
-}
-
-function ensureSafeAssignContext(obj, fullExpression) {
- if (obj) {
- if (obj === ARRAY_CTOR ||
- obj === BOOLEAN_CTOR ||
- obj === FUNCTION_CTOR ||
- obj === NUMBER_CTOR ||
- obj === OBJECT_CTOR ||
- obj === STRING_CTOR ||
- obj === ARRAY_CTOR_PROTO ||
- obj === BOOLEAN_CTOR_PROTO ||
- obj === FUNCTION_CTOR_PROTO ||
- obj === NUMBER_CTOR_PROTO ||
- obj === OBJECT_CTOR_PROTO ||
- obj === STRING_CTOR_PROTO) {
- throw $parseMinErr('isecaf',
- 'Assigning to a constructor or its prototype is disallowed! Expression: {0}',
- fullExpression);
- }
- }
-}
var OPERATORS = createMap();
forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
@@ -15071,13 +15106,12 @@ function ASTCompiler(astBuilder, $filter) {
}
ASTCompiler.prototype = {
- compile: function(expression, expensiveChecks) {
+ compile: function(expression) {
var self = this;
var ast = this.astBuilder.ast(expression);
this.state = {
nextId: 0,
filters: {},
- expensiveChecks: expensiveChecks,
fn: {vars: [], body: [], own: {}},
assign: {vars: [], body: [], own: {}},
inputs: []
@@ -15120,24 +15154,14 @@ ASTCompiler.prototype = {
// eslint-disable-next-line no-new-func
var fn = (new Function('$filter',
- 'ensureSafeMemberName',
- 'ensureSafeObject',
- 'ensureSafeFunction',
'getStringValue',
- 'ensureSafeAssignContext',
'ifDefined',
'plus',
- 'text',
fnString))(
this.$filter,
- ensureSafeMemberName,
- ensureSafeObject,
- ensureSafeFunction,
getStringValue,
- ensureSafeAssignContext,
ifDefined,
- plusFn,
- expression);
+ plusFn);
this.state = this.stage = undefined;
fn.literal = isLiteral(ast);
fn.constant = isConstant(ast);
@@ -15211,7 +15235,7 @@ ASTCompiler.prototype = {
case AST.Literal:
expression = this.escape(ast.value);
this.assign(intoId, expression);
- recursionFn(expression);
+ recursionFn(intoId || expression);
break;
case AST.UnaryExpression:
this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
@@ -15251,22 +15275,18 @@ ASTCompiler.prototype = {
nameId.computed = false;
nameId.name = ast.name;
}
- ensureSafeMemberName(ast.name);
self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
function() {
self.if_(self.stage === 'inputs' || 's', function() {
if (create && create !== 1) {
self.if_(
- self.not(self.nonComputedMember('s', ast.name)),
+ self.isNull(self.nonComputedMember('s', ast.name)),
self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
}
self.assign(intoId, self.nonComputedMember('s', ast.name));
});
}, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
);
- if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
- self.addEnsureSafeObject(intoId);
- }
recursionFn(intoId);
break;
case AST.MemberExpression:
@@ -15274,32 +15294,24 @@ ASTCompiler.prototype = {
intoId = intoId || this.nextId();
self.recurse(ast.object, left, undefined, function() {
self.if_(self.notNull(left), function() {
- if (create && create !== 1) {
- self.addEnsureSafeAssignContext(left);
- }
if (ast.computed) {
right = self.nextId();
self.recurse(ast.property, right);
self.getStringValue(right);
- self.addEnsureSafeMemberName(right);
if (create && create !== 1) {
self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
}
- expression = self.ensureSafeObject(self.computedMember(left, right));
+ expression = self.computedMember(left, right);
self.assign(intoId, expression);
if (nameId) {
nameId.computed = true;
nameId.name = right;
}
} else {
- ensureSafeMemberName(ast.property.name);
if (create && create !== 1) {
- self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
+ self.if_(self.isNull(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
}
expression = self.nonComputedMember(left, ast.property.name);
- if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
- expression = self.ensureSafeObject(expression);
- }
self.assign(intoId, expression);
if (nameId) {
nameId.computed = false;
@@ -15331,21 +15343,16 @@ ASTCompiler.prototype = {
args = [];
self.recurse(ast.callee, right, left, function() {
self.if_(self.notNull(right), function() {
- self.addEnsureSafeFunction(right);
forEach(ast.arguments, function(expr) {
- self.recurse(expr, self.nextId(), undefined, function(argument) {
- args.push(self.ensureSafeObject(argument));
+ self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
+ args.push(argument);
});
});
if (left.name) {
- if (!self.state.expensiveChecks) {
- self.addEnsureSafeObject(left.context);
- }
expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
} else {
expression = right + '(' + args.join(',') + ')';
}
- expression = self.ensureSafeObject(expression);
self.assign(intoId, expression);
}, function() {
self.assign(intoId, 'undefined');
@@ -15360,8 +15367,6 @@ ASTCompiler.prototype = {
this.recurse(ast.left, undefined, left, function() {
self.if_(self.notNull(left.context), function() {
self.recurse(ast.right, right);
- self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
- self.addEnsureSafeAssignContext(left.context);
expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
self.assign(intoId, expression);
recursionFn(intoId || expression);
@@ -15371,13 +15376,13 @@ ASTCompiler.prototype = {
case AST.ArrayExpression:
args = [];
forEach(ast.elements, function(expr) {
- self.recurse(expr, self.nextId(), undefined, function(argument) {
+ self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
args.push(argument);
});
});
expression = '[' + args.join(',') + ']';
this.assign(intoId, expression);
- recursionFn(expression);
+ recursionFn(intoId || expression);
break;
case AST.ObjectExpression:
args = [];
@@ -15419,15 +15424,15 @@ ASTCompiler.prototype = {
break;
case AST.ThisExpression:
this.assign(intoId, 's');
- recursionFn('s');
+ recursionFn(intoId || 's');
break;
case AST.LocalsExpression:
this.assign(intoId, 'l');
- recursionFn('l');
+ recursionFn(intoId || 'l');
break;
case AST.NGValueParameter:
this.assign(intoId, 'v');
- recursionFn('v');
+ recursionFn(intoId || 'v');
break;
}
},
@@ -15486,6 +15491,10 @@ ASTCompiler.prototype = {
return '!(' + expression + ')';
},
+ isNull: function(expression) {
+ return expression + '==null';
+ },
+
notNull: function(expression) {
return expression + '!=null';
},
@@ -15509,42 +15518,10 @@ ASTCompiler.prototype = {
return this.nonComputedMember(left, right);
},
- addEnsureSafeObject: function(item) {
- this.current().body.push(this.ensureSafeObject(item), ';');
- },
-
- addEnsureSafeMemberName: function(item) {
- this.current().body.push(this.ensureSafeMemberName(item), ';');
- },
-
- addEnsureSafeFunction: function(item) {
- this.current().body.push(this.ensureSafeFunction(item), ';');
- },
-
- addEnsureSafeAssignContext: function(item) {
- this.current().body.push(this.ensureSafeAssignContext(item), ';');
- },
-
- ensureSafeObject: function(item) {
- return 'ensureSafeObject(' + item + ',text)';
- },
-
- ensureSafeMemberName: function(item) {
- return 'ensureSafeMemberName(' + item + ',text)';
- },
-
- ensureSafeFunction: function(item) {
- return 'ensureSafeFunction(' + item + ',text)';
- },
-
getStringValue: function(item) {
this.assign(item, 'getStringValue(' + item + ')');
},
- ensureSafeAssignContext: function(item) {
- return 'ensureSafeAssignContext(' + item + ',text)';
- },
-
lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
var self = this;
return function() {
@@ -15596,11 +15573,9 @@ function ASTInterpreter(astBuilder, $filter) {
}
ASTInterpreter.prototype = {
- compile: function(expression, expensiveChecks) {
+ compile: function(expression) {
var self = this;
var ast = this.astBuilder.ast(expression);
- this.expression = expression;
- this.expensiveChecks = expensiveChecks;
findConstantAndWatchExpressions(ast, self.$filter);
var assignable;
var assign;
@@ -15671,20 +15646,16 @@ ASTInterpreter.prototype = {
context
);
case AST.Identifier:
- ensureSafeMemberName(ast.name, self.expression);
- return self.identifier(ast.name,
- self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
- context, create, self.expression);
+ return self.identifier(ast.name, context, create);
case AST.MemberExpression:
left = this.recurse(ast.object, false, !!create);
if (!ast.computed) {
- ensureSafeMemberName(ast.property.name, self.expression);
right = ast.property.name;
}
if (ast.computed) right = this.recurse(ast.property);
return ast.computed ?
- this.computedMember(left, right, context, create, self.expression) :
- this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
+ this.computedMember(left, right, context, create) :
+ this.nonComputedMember(left, right, context, create);
case AST.CallExpression:
args = [];
forEach(ast.arguments, function(expr) {
@@ -15705,13 +15676,11 @@ ASTInterpreter.prototype = {
var rhs = right(scope, locals, assign, inputs);
var value;
if (rhs.value != null) {
- ensureSafeObject(rhs.context, self.expression);
- ensureSafeFunction(rhs.value, self.expression);
var values = [];
for (var i = 0; i < args.length; ++i) {
- values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
+ values.push(args[i](scope, locals, assign, inputs));
}
- value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
+ value = rhs.value.apply(rhs.context, values);
}
return context ? {value: value} : value;
};
@@ -15721,8 +15690,6 @@ ASTInterpreter.prototype = {
return function(scope, locals, assign, inputs) {
var lhs = left(scope, locals, assign, inputs);
var rhs = right(scope, locals, assign, inputs);
- ensureSafeObject(lhs.value, self.expression);
- ensureSafeAssignContext(lhs.context);
lhs.context[lhs.name] = rhs;
return context ? {value: rhs} : rhs;
};
@@ -15798,7 +15765,7 @@ ASTInterpreter.prototype = {
if (isDefined(arg)) {
arg = -arg;
} else {
- arg = 0;
+ arg = -0;
}
return context ? {value: arg} : arg;
};
@@ -15914,16 +15881,13 @@ ASTInterpreter.prototype = {
value: function(value, context) {
return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
},
- identifier: function(name, expensiveChecks, context, create, expression) {
+ identifier: function(name, context, create) {
return function(scope, locals, assign, inputs) {
var base = locals && (name in locals) ? locals : scope;
- if (create && create !== 1 && base && !(base[name])) {
+ if (create && create !== 1 && base && base[name] == null) {
base[name] = {};
}
var value = base ? base[name] : undefined;
- if (expensiveChecks) {
- ensureSafeObject(value, expression);
- }
if (context) {
return {context: base, name: name, value: value};
} else {
@@ -15931,7 +15895,7 @@ ASTInterpreter.prototype = {
}
};
},
- computedMember: function(left, right, context, create, expression) {
+ computedMember: function(left, right, context, create) {
return function(scope, locals, assign, inputs) {
var lhs = left(scope, locals, assign, inputs);
var rhs;
@@ -15939,15 +15903,12 @@ ASTInterpreter.prototype = {
if (lhs != null) {
rhs = right(scope, locals, assign, inputs);
rhs = getStringValue(rhs);
- ensureSafeMemberName(rhs, expression);
if (create && create !== 1) {
- ensureSafeAssignContext(lhs);
if (lhs && !(lhs[rhs])) {
lhs[rhs] = {};
}
}
value = lhs[rhs];
- ensureSafeObject(value, expression);
}
if (context) {
return {context: lhs, name: rhs, value: value};
@@ -15956,19 +15917,15 @@ ASTInterpreter.prototype = {
}
};
},
- nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
+ nonComputedMember: function(left, right, context, create) {
return function(scope, locals, assign, inputs) {
var lhs = left(scope, locals, assign, inputs);
if (create && create !== 1) {
- ensureSafeAssignContext(lhs);
- if (lhs && !(lhs[right])) {
+ if (lhs && lhs[right] == null) {
lhs[right] = {};
}
}
var value = lhs != null ? lhs[right] : undefined;
- if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
- ensureSafeObject(value, expression);
- }
if (context) {
return {context: lhs, name: right, value: value};
} else {
@@ -16000,14 +15957,10 @@ Parser.prototype = {
constructor: Parser,
parse: function(text) {
- return this.astCompiler.compile(text, this.options.expensiveChecks);
+ return this.astCompiler.compile(text);
}
};
-function isPossiblyDangerousMemberName(name) {
- return name === 'constructor';
-}
-
function getValueOf(value) {
return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
}
@@ -16065,8 +16018,7 @@ function getValueOf(value) {
* service.
*/
function $ParseProvider() {
- var cacheDefault = createMap();
- var cacheExpensive = createMap();
+ var cache = createMap();
var literals = {
'true': true,
'false': false,
@@ -16124,37 +16076,20 @@ function $ParseProvider() {
var noUnsafeEval = csp().noUnsafeEval;
var $parseOptions = {
csp: noUnsafeEval,
- expensiveChecks: false,
- literals: copy(literals),
- isIdentifierStart: isFunction(identStart) && identStart,
- isIdentifierContinue: isFunction(identContinue) && identContinue
- },
- $parseOptionsExpensive = {
- csp: noUnsafeEval,
- expensiveChecks: true,
literals: copy(literals),
isIdentifierStart: isFunction(identStart) && identStart,
isIdentifierContinue: isFunction(identContinue) && identContinue
};
- var runningChecksEnabled = false;
-
- $parse.$$runningExpensiveChecks = function() {
- return runningChecksEnabled;
- };
-
return $parse;
- function $parse(exp, interceptorFn, expensiveChecks) {
+ function $parse(exp, interceptorFn) {
var parsedExpression, oneTime, cacheKey;
- expensiveChecks = expensiveChecks || runningChecksEnabled;
-
switch (typeof exp) {
case 'string':
exp = exp.trim();
cacheKey = exp;
- var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
parsedExpression = cache[cacheKey];
if (!parsedExpression) {
@@ -16162,9 +16097,8 @@ function $ParseProvider() {
oneTime = true;
exp = exp.substring(2);
}
- var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
- var lexer = new Lexer(parseOptions);
- var parser = new Parser(lexer, $filter, parseOptions);
+ var lexer = new Lexer($parseOptions);
+ var parser = new Parser(lexer, $filter, $parseOptions);
parsedExpression = parser.parse(exp);
if (parsedExpression.constant) {
parsedExpression.$$watchDelegate = constantWatchDelegate;
@@ -16174,9 +16108,6 @@ function $ParseProvider() {
} else if (parsedExpression.inputs) {
parsedExpression.$$watchDelegate = inputsWatchDelegate;
}
- if (expensiveChecks) {
- parsedExpression = expensiveChecksInterceptor(parsedExpression);
- }
cache[cacheKey] = parsedExpression;
}
return addInterceptor(parsedExpression, interceptorFn);
@@ -16189,30 +16120,6 @@ function $ParseProvider() {
}
}
- function expensiveChecksInterceptor(fn) {
- if (!fn) return fn;
- expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
- expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
- expensiveCheckFn.constant = fn.constant;
- expensiveCheckFn.literal = fn.literal;
- for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
- fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
- }
- expensiveCheckFn.inputs = fn.inputs;
-
- return expensiveCheckFn;
-
- function expensiveCheckFn(scope, locals, assign, inputs) {
- var expensiveCheckOldValue = runningChecksEnabled;
- runningChecksEnabled = true;
- try {
- return fn(scope, locals, assign, inputs);
- } finally {
- runningChecksEnabled = expensiveCheckOldValue;
- }
- }
- }
-
function expressionInputDirtyCheck(newValue, oldValueOfValue) {
if (newValue == null || oldValueOfValue == null) { // null/undefined
@@ -16282,14 +16189,22 @@ function $ParseProvider() {
}, listener, objectEquality, prettyPrintExpression);
}
- function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
+ function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
var unwatch, lastValue;
- unwatch = scope.$watch(function oneTimeWatch(scope) {
+ if (parsedExpression.inputs) {
+ unwatch = inputsWatchDelegate(scope, oneTimeListener, objectEquality, parsedExpression, prettyPrintExpression);
+ } else {
+ unwatch = scope.$watch(oneTimeWatch, oneTimeListener, objectEquality);
+ }
+ return unwatch;
+
+ function oneTimeWatch(scope) {
return parsedExpression(scope);
- }, /** @this */ function oneTimeListener(value, old, scope) {
+ }
+ function oneTimeListener(value, old, scope) {
lastValue = value;
if (isFunction(listener)) {
- listener.apply(this, arguments);
+ listener(value, old, scope);
}
if (isDefined(value)) {
scope.$$postDigest(function() {
@@ -16298,18 +16213,17 @@ function $ParseProvider() {
}
});
}
- }, objectEquality);
- return unwatch;
+ }
}
function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
var unwatch, lastValue;
unwatch = scope.$watch(function oneTimeWatch(scope) {
return parsedExpression(scope);
- }, /** @this */ function oneTimeListener(value, old, scope) {
+ }, function oneTimeListener(value, old, scope) {
lastValue = value;
if (isFunction(listener)) {
- listener.call(this, value, old, scope);
+ listener(value, old, scope);
}
if (isAllDefined(value)) {
scope.$$postDigest(function() {
@@ -16358,14 +16272,15 @@ function $ParseProvider() {
};
// Propagate $$watchDelegates other then inputsWatchDelegate
+ useInputs = !parsedExpression.inputs;
if (parsedExpression.$$watchDelegate &&
parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
fn.$$watchDelegate = parsedExpression.$$watchDelegate;
+ fn.inputs = parsedExpression.inputs;
} else if (!interceptorFn.$stateful) {
// If there is an interceptor, but no watchDelegate then treat the interceptor like
// we treat filters - it is assumed to be a pure function unless flagged with $stateful
fn.$$watchDelegate = inputsWatchDelegate;
- useInputs = !parsedExpression.inputs;
fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
}
@@ -16378,14 +16293,13 @@ function $ParseProvider() {
* @ngdoc service
* @name $q
* @requires $rootScope
- * @this
*
* @description
* A service that helps you run functions asynchronously, and use their return values (or exceptions)
* when they are done processing.
*
- * This is an implementation of promises/deferred objects inspired by
- * [Kris Kowal's Q](https://github.com/kriskowal/q).
+ * This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred
+ * objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
*
* $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
* implementations, and the other which resembles ES6 (ES2015) promises to some degree.
@@ -16592,22 +16506,61 @@ function $ParseProvider() {
*
* @returns {Promise} The newly created promise.
*/
+/**
+ * @ngdoc provider
+ * @name $qProvider
+ * @this
+ *
+ * @description
+ */
function $QProvider() {
-
+ var errorOnUnhandledRejections = true;
this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
return qFactory(function(callback) {
$rootScope.$evalAsync(callback);
- }, $exceptionHandler);
+ }, $exceptionHandler, errorOnUnhandledRejections);
}];
+
+ /**
+ * @ngdoc method
+ * @name $qProvider#errorOnUnhandledRejections
+ * @kind function
+ *
+ * @description
+ * Retrieves or overrides whether to generate an error when a rejected promise is not handled.
+ * This feature is enabled by default.
+ *
+ * @param {boolean=} value Whether to generate an error when a rejected promise is not handled.
+ * @returns {boolean|ng.$qProvider} Current value when called without a new value or self for
+ * chaining otherwise.
+ */
+ this.errorOnUnhandledRejections = function(value) {
+ if (isDefined(value)) {
+ errorOnUnhandledRejections = value;
+ return this;
+ } else {
+ return errorOnUnhandledRejections;
+ }
+ };
}
/** @this */
function $$QProvider() {
+ var errorOnUnhandledRejections = true;
this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
return qFactory(function(callback) {
$browser.defer(callback);
- }, $exceptionHandler);
+ }, $exceptionHandler, errorOnUnhandledRejections);
}];
+
+ this.errorOnUnhandledRejections = function(value) {
+ if (isDefined(value)) {
+ errorOnUnhandledRejections = value;
+ return this;
+ } else {
+ return errorOnUnhandledRejections;
+ }
+ };
}
/**
@@ -16616,10 +16569,14 @@ function $$QProvider() {
* @param {function(function)} nextTick Function for executing functions in the next turn.
* @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
* debugging purposes.
+ @ param {=boolean} errorOnUnhandledRejections Whether an error should be generated on unhandled
+ * promises rejections.
* @returns {object} Promise manager.
*/
-function qFactory(nextTick, exceptionHandler) {
+function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
var $qMinErr = minErr('$q', TypeError);
+ var queueSize = 0;
+ var checkQueue = [];
/**
* @ngdoc method
@@ -16632,14 +16589,18 @@ function qFactory(nextTick, exceptionHandler) {
* @returns {Deferred} Returns a new instance of deferred.
*/
function defer() {
- var d = new Deferred();
- //Necessary to support unbound execution :/
- d.resolve = simpleBind(d, d.resolve);
- d.reject = simpleBind(d, d.reject);
- d.notify = simpleBind(d, d.notify);
- return d;
+ return new Deferred();
}
+ function Deferred() {
+ var promise = this.promise = new Promise();
+ //Non prototype methods necessary to support unbound execution :/
+ this.resolve = function(val) { resolvePromise(promise, val); };
+ this.reject = function(reason) { rejectPromise(promise, reason); };
+ this.notify = function(progress) { notifyPromise(promise, progress); };
+ }
+
+
function Promise() {
this.$$state = { status: 0 };
}
@@ -16649,13 +16610,13 @@ function qFactory(nextTick, exceptionHandler) {
if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
return this;
}
- var result = new Deferred();
+ var result = new Promise();
this.$$state.pending = this.$$state.pending || [];
this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
- return result.promise;
+ return result;
},
'catch': function(callback) {
@@ -16671,122 +16632,140 @@ function qFactory(nextTick, exceptionHandler) {
}
});
- //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
- function simpleBind(context, fn) {
- return function(value) {
- fn.call(context, value);
- };
- }
-
function processQueue(state) {
- var fn, deferred, pending;
+ var fn, promise, pending;
pending = state.pending;
state.processScheduled = false;
state.pending = undefined;
- for (var i = 0, ii = pending.length; i < ii; ++i) {
- deferred = pending[i][0];
- fn = pending[i][state.status];
- try {
- if (isFunction(fn)) {
- deferred.resolve(fn(state.value));
- } else if (state.status === 1) {
- deferred.resolve(state.value);
- } else {
- deferred.reject(state.value);
+ try {
+ for (var i = 0, ii = pending.length; i < ii; ++i) {
+ state.pur = true;
+ promise = pending[i][0];
+ fn = pending[i][state.status];
+ try {
+ if (isFunction(fn)) {
+ resolvePromise(promise, fn(state.value));
+ } else if (state.status === 1) {
+ resolvePromise(promise, state.value);
+ } else {
+ rejectPromise(promise, state.value);
+ }
+ } catch (e) {
+ rejectPromise(promise, e);
+ }
+ }
+ } finally {
+ --queueSize;
+ if (errorOnUnhandledRejections && queueSize === 0) {
+ nextTick(processChecks);
+ }
+ }
+ }
+
+ function processChecks() {
+ // eslint-disable-next-line no-unmodified-loop-condition
+ while (!queueSize && checkQueue.length) {
+ var toCheck = checkQueue.shift();
+ if (!toCheck.pur) {
+ toCheck.pur = true;
+ var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
+ if (toCheck.value instanceof Error) {
+ exceptionHandler(toCheck.value, errorMessage);
+ } else {
+ exceptionHandler(errorMessage);
}
- } catch (e) {
- deferred.reject(e);
- exceptionHandler(e);
}
}
}
function scheduleProcessQueue(state) {
+ if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !state.pur) {
+ if (queueSize === 0 && checkQueue.length === 0) {
+ nextTick(processChecks);
+ }
+ checkQueue.push(state);
+ }
if (state.processScheduled || !state.pending) return;
state.processScheduled = true;
+ ++queueSize;
nextTick(function() { processQueue(state); });
}
- function Deferred() {
- this.promise = new Promise();
+ function resolvePromise(promise, val) {
+ if (promise.$$state.status) return;
+ if (val === promise) {
+ $$reject(promise, $qMinErr(
+ 'qcycle',
+ 'Expected promise to be resolved with value other than itself \'{0}\'',
+ val));
+ } else {
+ $$resolve(promise, val);
+ }
+
}
- extend(Deferred.prototype, {
- resolve: function(val) {
- if (this.promise.$$state.status) return;
- if (val === this.promise) {
- this.$$reject($qMinErr(
- 'qcycle',
- 'Expected promise to be resolved with value other than itself \'{0}\'',
- val));
+ function $$resolve(promise, val) {
+ var then;
+ var done = false;
+ try {
+ if (isObject(val) || isFunction(val)) then = val.then;
+ if (isFunction(then)) {
+ promise.$$state.status = -1;
+ then.call(val, doResolve, doReject, doNotify);
} else {
- this.$$resolve(val);
- }
-
- },
-
- $$resolve: function(val) {
- var then;
- var that = this;
- var done = false;
- try {
- if ((isObject(val) || isFunction(val))) then = val && val.then;
- if (isFunction(then)) {
- this.promise.$$state.status = -1;
- then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
- } else {
- this.promise.$$state.value = val;
- this.promise.$$state.status = 1;
- scheduleProcessQueue(this.promise.$$state);
- }
- } catch (e) {
- rejectPromise(e);
- exceptionHandler(e);
- }
-
- function resolvePromise(val) {
- if (done) return;
- done = true;
- that.$$resolve(val);
- }
- function rejectPromise(val) {
- if (done) return;
- done = true;
- that.$$reject(val);
- }
- },
-
- reject: function(reason) {
- if (this.promise.$$state.status) return;
- this.$$reject(reason);
- },
-
- $$reject: function(reason) {
- this.promise.$$state.value = reason;
- this.promise.$$state.status = 2;
- scheduleProcessQueue(this.promise.$$state);
- },
-
- notify: function(progress) {
- var callbacks = this.promise.$$state.pending;
-
- if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
- nextTick(function() {
- var callback, result;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- result = callbacks[i][0];
- callback = callbacks[i][3];
- try {
- result.notify(isFunction(callback) ? callback(progress) : progress);
- } catch (e) {
- exceptionHandler(e);
- }
- }
- });
+ promise.$$state.value = val;
+ promise.$$state.status = 1;
+ scheduleProcessQueue(promise.$$state);
}
+ } catch (e) {
+ doReject(e);
}
- });
+
+ function doResolve(val) {
+ if (done) return;
+ done = true;
+ $$resolve(promise, val);
+ }
+ function doReject(val) {
+ if (done) return;
+ done = true;
+ $$reject(promise, val);
+ }
+ function doNotify(progress) {
+ notifyPromise(promise, progress);
+ }
+ }
+
+ function rejectPromise(promise, reason) {
+ if (promise.$$state.status) return;
+ $$reject(promise, reason);
+ }
+
+ function $$reject(promise, reason) {
+ promise.$$state.value = reason;
+ promise.$$state.status = 2;
+ scheduleProcessQueue(promise.$$state);
+ }
+
+ function notifyPromise(promise, progress) {
+ var callbacks = promise.$$state.pending;
+
+ if ((promise.$$state.status <= 0) && callbacks && callbacks.length) {
+ nextTick(function() {
+ var callback, result;
+ for (var i = 0, ii = callbacks.length; i < ii; i++) {
+ result = callbacks[i][0];
+ callback = callbacks[i][3];
+ try {
+ notifyPromise(result, isFunction(callback) ? callback(progress) : progress);
+ } catch (e) {
+ exceptionHandler(e);
+ }
+ }
+ });
+ }
+ }
/**
* @ngdoc method
@@ -16825,9 +16804,9 @@ function qFactory(nextTick, exceptionHandler) {
* @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
*/
function reject(reason) {
- var result = new Deferred();
- result.reject(reason);
- return result.promise;
+ var result = new Promise();
+ rejectPromise(result, reason);
+ return result;
}
function handleCallback(value, resolver, callback) {
@@ -16865,9 +16844,9 @@ function qFactory(nextTick, exceptionHandler) {
function when(value, callback, errback, progressBack) {
- var result = new Deferred();
- result.resolve(value);
- return result.promise.then(callback, errback, progressBack);
+ var result = new Promise();
+ resolvePromise(result, value);
+ return result.then(callback, errback, progressBack);
}
/**
@@ -16903,7 +16882,7 @@ function qFactory(nextTick, exceptionHandler) {
*/
function all(promises) {
- var deferred = new Deferred(),
+ var result = new Promise(),
counter = 0,
results = isArray(promises) ? [] : {};
@@ -16911,17 +16890,17 @@ function qFactory(nextTick, exceptionHandler) {
counter++;
when(promise).then(function(value) {
results[key] = value;
- if (!(--counter)) deferred.resolve(results);
+ if (!(--counter)) resolvePromise(result, results);
}, function(reason) {
- deferred.reject(reason);
+ rejectPromise(result, reason);
});
});
if (counter === 0) {
- deferred.resolve(results);
+ resolvePromise(result, results);
}
- return deferred.promise;
+ return result;
}
/**
@@ -16953,19 +16932,19 @@ function qFactory(nextTick, exceptionHandler) {
throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver);
}
- var deferred = new Deferred();
+ var promise = new Promise();
function resolveFn(value) {
- deferred.resolve(value);
+ resolvePromise(promise, value);
}
function rejectFn(reason) {
- deferred.reject(reason);
+ rejectPromise(promise, reason);
}
resolver(resolveFn, rejectFn);
- return deferred.promise;
+ return promise;
}
// Let's make the instanceof operator work for promises, so that
@@ -17118,6 +17097,7 @@ function $RootScopeProvider() {
function cleanUpScope($scope) {
+ // Support: IE 9 only
if (msie === 9) {
// There is a memory leak in IE9 if all child scopes are not disconnected
// completely when a scope is destroyed. So this code will recurse up through
@@ -17309,6 +17289,8 @@ function $RootScopeProvider() {
* according to the {@link angular.equals} function. To save the value of the object for
* later comparison, the {@link angular.copy} function is used. This therefore means that
* watching complex objects will have adverse memory and performance implications.
+ * - This should not be used to watch for changes in objects that are
+ * or contain [File](https://developer.mozilla.org/docs/Web/API/File) objects due to limitations with {@link angular.copy `angular.copy`}.
* - The watch `listener` may change the model, which may trigger other `listener`s to fire.
* This is achieved by rerunning the watchers until no changes are detected. The rerun
* iteration limit is 10 to prevent an infinite loop deadlock.
@@ -18516,6 +18498,13 @@ var SCE_CONTEXTS = {
// Helper functions follow.
+var UNDERSCORE_LOWERCASE_REGEXP = /_([a-z])/g;
+
+function snakeToCamel(name) {
+ return name
+ .replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace);
+}
+
function adjustMatcher(matcher) {
if (matcher === 'self') {
return matcher;
@@ -19101,8 +19090,8 @@ function $SceDelegateProvider() {
* .controller('AppController', ['$http', '$templateCache', '$sce',
* function AppController($http, $templateCache, $sce) {
* var self = this;
- * $http.get('test_data.json', {cache: $templateCache}).success(function(userComments) {
- * self.userComments = userComments;
+ * $http.get('test_data.json', {cache: $templateCache}).then(function(response) {
+ * self.userComments = response.data;
* });
* self.explicitlyTrustedHtml = $sce.trustAsHtml(
* '
default currency symbol ($): {{amount | currency}}
- custom currency identifier (USD$): {{amount | currency:"USD$"}}
+ custom currency identifier (USD$): {{amount | currency:"USD$"}}
no fractions (0): {{amount | currency:"USD$":0}}
@@ -22612,10 +22601,11 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
attr.$set(name, value);
- // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
+ // Support: IE 9-11 only
+ // On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
// to set the property as well to achieve the desired effect.
- // we use attr[attrName] value since $set can sanitize the url.
+ // We use attr[attrName] value since $set can sanitize the url.
if (msie && propName) element.prop(propName, attr[name]);
});
}
@@ -22623,7 +22613,7 @@ forEach(['src', 'srcset', 'href'], function(attrName) {
};
});
-/* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
+/* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS
*/
var nullFormCtrl = {
$addControl: noop,
@@ -22634,6 +22624,7 @@ var nullFormCtrl = {
$setPristine: noop,
$setSubmitted: noop
},
+PENDING_CLASS = 'ng-pending',
SUBMITTED_CLASS = 'ng-submitted';
function nullFormRenameControl(control, name) {
@@ -22684,22 +22675,28 @@ function nullFormRenameControl(control, name) {
*/
//asks for $scope to fool the BC controller module
FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
-function FormController(element, attrs, $scope, $animate, $interpolate) {
- var form = this,
- controls = [];
+function FormController($element, $attrs, $scope, $animate, $interpolate) {
+ this.$$controls = [];
// init state
- form.$error = {};
- form.$$success = {};
- form.$pending = undefined;
- form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
- form.$dirty = false;
- form.$pristine = true;
- form.$valid = true;
- form.$invalid = false;
- form.$submitted = false;
- form.$$parentForm = nullFormCtrl;
+ this.$error = {};
+ this.$$success = {};
+ this.$pending = undefined;
+ this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope);
+ this.$dirty = false;
+ this.$pristine = true;
+ this.$valid = true;
+ this.$invalid = false;
+ this.$submitted = false;
+ this.$$parentForm = nullFormCtrl;
+ this.$$element = $element;
+ this.$$animate = $animate;
+
+ setupValidity(this);
+}
+
+FormController.prototype = {
/**
* @ngdoc method
* @name form.FormController#$rollbackViewValue
@@ -22711,11 +22708,11 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* event defined in `ng-model-options`. This method is typically needed by the reset button of
* a form that uses `ng-model-options` to pend updates.
*/
- form.$rollbackViewValue = function() {
- forEach(controls, function(control) {
+ $rollbackViewValue: function() {
+ forEach(this.$$controls, function(control) {
control.$rollbackViewValue();
});
- };
+ },
/**
* @ngdoc method
@@ -22728,11 +22725,11 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
* usually handles calling this in response to input events.
*/
- form.$commitViewValue = function() {
- forEach(controls, function(control) {
+ $commitViewValue: function() {
+ forEach(this.$$controls, function(control) {
control.$commitViewValue();
});
- };
+ },
/**
* @ngdoc method
@@ -22755,29 +22752,29 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* For example, if an input control is added that is already `$dirty` and has `$error` properties,
* calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
*/
- form.$addControl = function(control) {
+ $addControl: function(control) {
// Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
// and not added to the scope. Now we throw an error.
assertNotHasOwnProperty(control.$name, 'input');
- controls.push(control);
+ this.$$controls.push(control);
if (control.$name) {
- form[control.$name] = control;
+ this[control.$name] = control;
}
- control.$$parentForm = form;
- };
+ control.$$parentForm = this;
+ },
// Private API: rename a form control
- form.$$renameControl = function(control, newName) {
+ $$renameControl: function(control, newName) {
var oldName = control.$name;
- if (form[oldName] === control) {
- delete form[oldName];
+ if (this[oldName] === control) {
+ delete this[oldName];
}
- form[newName] = control;
+ this[newName] = control;
control.$name = newName;
- };
+ },
/**
* @ngdoc method
@@ -22795,60 +22792,26 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* different from case to case. For example, removing the only `$dirty` control from a form may or
* may not mean that the form is still `$dirty`.
*/
- form.$removeControl = function(control) {
- if (control.$name && form[control.$name] === control) {
- delete form[control.$name];
+ $removeControl: function(control) {
+ if (control.$name && this[control.$name] === control) {
+ delete this[control.$name];
}
- forEach(form.$pending, function(value, name) {
- form.$setValidity(name, null, control);
- });
- forEach(form.$error, function(value, name) {
- form.$setValidity(name, null, control);
- });
- forEach(form.$$success, function(value, name) {
- form.$setValidity(name, null, control);
- });
+ forEach(this.$pending, function(value, name) {
+ // eslint-disable-next-line no-invalid-this
+ this.$setValidity(name, null, control);
+ }, this);
+ forEach(this.$error, function(value, name) {
+ // eslint-disable-next-line no-invalid-this
+ this.$setValidity(name, null, control);
+ }, this);
+ forEach(this.$$success, function(value, name) {
+ // eslint-disable-next-line no-invalid-this
+ this.$setValidity(name, null, control);
+ }, this);
- arrayRemove(controls, control);
+ arrayRemove(this.$$controls, control);
control.$$parentForm = nullFormCtrl;
- };
-
-
- /**
- * @ngdoc method
- * @name form.FormController#$setValidity
- *
- * @description
- * Sets the validity of a form control.
- *
- * This method will also propagate to parent forms.
- */
- addSetValidityMethod({
- ctrl: this,
- $element: element,
- set: function(object, property, controller) {
- var list = object[property];
- if (!list) {
- object[property] = [controller];
- } else {
- var index = list.indexOf(controller);
- if (index === -1) {
- list.push(controller);
- }
- }
- },
- unset: function(object, property, controller) {
- var list = object[property];
- if (!list) {
- return;
- }
- arrayRemove(list, controller);
- if (list.length === 0) {
- delete object[property];
- }
- },
- $animate: $animate
- });
+ },
/**
* @ngdoc method
@@ -22860,13 +22823,13 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* This method can be called to add the 'ng-dirty' class and set the form to a dirty
* state (ng-dirty class). This method will also propagate to parent forms.
*/
- form.$setDirty = function() {
- $animate.removeClass(element, PRISTINE_CLASS);
- $animate.addClass(element, DIRTY_CLASS);
- form.$dirty = true;
- form.$pristine = false;
- form.$$parentForm.$setDirty();
- };
+ $setDirty: function() {
+ this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
+ this.$$animate.addClass(this.$$element, DIRTY_CLASS);
+ this.$dirty = true;
+ this.$pristine = false;
+ this.$$parentForm.$setDirty();
+ },
/**
* @ngdoc method
@@ -22884,15 +22847,15 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
* saving or resetting it.
*/
- form.$setPristine = function() {
- $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
- form.$dirty = false;
- form.$pristine = true;
- form.$submitted = false;
- forEach(controls, function(control) {
+ $setPristine: function() {
+ this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
+ this.$dirty = false;
+ this.$pristine = true;
+ this.$submitted = false;
+ forEach(this.$$controls, function(control) {
control.$setPristine();
});
- };
+ },
/**
* @ngdoc method
@@ -22907,11 +22870,11 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* Setting a form controls back to their untouched state is often useful when setting the form
* back to its pristine state.
*/
- form.$setUntouched = function() {
- forEach(controls, function(control) {
+ $setUntouched: function() {
+ forEach(this.$$controls, function(control) {
control.$setUntouched();
});
- };
+ },
/**
* @ngdoc method
@@ -22920,12 +22883,46 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
* @description
* Sets the form to its submitted state.
*/
- form.$setSubmitted = function() {
- $animate.addClass(element, SUBMITTED_CLASS);
- form.$submitted = true;
- form.$$parentForm.$setSubmitted();
- };
-}
+ $setSubmitted: function() {
+ this.$$animate.addClass(this.$$element, SUBMITTED_CLASS);
+ this.$submitted = true;
+ this.$$parentForm.$setSubmitted();
+ }
+};
+
+/**
+ * @ngdoc method
+ * @name form.FormController#$setValidity
+ *
+ * @description
+ * Sets the validity of a form control.
+ *
+ * This method will also propagate to parent forms.
+ */
+addSetValidityMethod({
+ clazz: FormController,
+ set: function(object, property, controller) {
+ var list = object[property];
+ if (!list) {
+ object[property] = [controller];
+ } else {
+ var index = list.indexOf(controller);
+ if (index === -1) {
+ list.push(controller);
+ }
+ }
+ },
+ unset: function(object, property, controller) {
+ var list = object[property];
+ if (!list) {
+ return;
+ }
+ arrayRemove(list, controller);
+ if (list.length === 0) {
+ delete object[property];
+ }
+ }
+});
/**
* @ngdoc directive
@@ -23122,13 +23119,13 @@ var formDirectiveFactory = function(isNgForm) {
event.preventDefault();
};
- addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
+ formElement[0].addEventListener('submit', handleFormSubmission);
// unregister the preventDefault listener so that we don't not leak memory but in a
// way that will achieve the prevention of the default action.
formElement.on('$destroy', function() {
$timeout(function() {
- removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
+ formElement[0].removeEventListener('submit', handleFormSubmission);
}, 0, false);
});
}
@@ -23173,6 +23170,111 @@ var formDirectiveFactory = function(isNgForm) {
var formDirective = formDirectiveFactory();
var ngFormDirective = formDirectiveFactory(true);
+
+
+// helper methods
+function setupValidity(instance) {
+ instance.$$classCache = {};
+ instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS));
+}
+function addSetValidityMethod(context) {
+ var clazz = context.clazz,
+ set = context.set,
+ unset = context.unset;
+
+ clazz.prototype.$setValidity = function(validationErrorKey, state, controller) {
+ if (isUndefined(state)) {
+ createAndSet(this, '$pending', validationErrorKey, controller);
+ } else {
+ unsetAndCleanup(this, '$pending', validationErrorKey, controller);
+ }
+ if (!isBoolean(state)) {
+ unset(this.$error, validationErrorKey, controller);
+ unset(this.$$success, validationErrorKey, controller);
+ } else {
+ if (state) {
+ unset(this.$error, validationErrorKey, controller);
+ set(this.$$success, validationErrorKey, controller);
+ } else {
+ set(this.$error, validationErrorKey, controller);
+ unset(this.$$success, validationErrorKey, controller);
+ }
+ }
+ if (this.$pending) {
+ cachedToggleClass(this, PENDING_CLASS, true);
+ this.$valid = this.$invalid = undefined;
+ toggleValidationCss(this, '', null);
+ } else {
+ cachedToggleClass(this, PENDING_CLASS, false);
+ this.$valid = isObjectEmpty(this.$error);
+ this.$invalid = !this.$valid;
+ toggleValidationCss(this, '', this.$valid);
+ }
+
+ // re-read the state as the set/unset methods could have
+ // combined state in this.$error[validationError] (used for forms),
+ // where setting/unsetting only increments/decrements the value,
+ // and does not replace it.
+ var combinedState;
+ if (this.$pending && this.$pending[validationErrorKey]) {
+ combinedState = undefined;
+ } else if (this.$error[validationErrorKey]) {
+ combinedState = false;
+ } else if (this.$$success[validationErrorKey]) {
+ combinedState = true;
+ } else {
+ combinedState = null;
+ }
+
+ toggleValidationCss(this, validationErrorKey, combinedState);
+ this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
+ };
+
+ function createAndSet(ctrl, name, value, controller) {
+ if (!ctrl[name]) {
+ ctrl[name] = {};
+ }
+ set(ctrl[name], value, controller);
+ }
+
+ function unsetAndCleanup(ctrl, name, value, controller) {
+ if (ctrl[name]) {
+ unset(ctrl[name], value, controller);
+ }
+ if (isObjectEmpty(ctrl[name])) {
+ ctrl[name] = undefined;
+ }
+ }
+
+ function cachedToggleClass(ctrl, className, switchValue) {
+ if (switchValue && !ctrl.$$classCache[className]) {
+ ctrl.$$animate.addClass(ctrl.$$element, className);
+ ctrl.$$classCache[className] = true;
+ } else if (!switchValue && ctrl.$$classCache[className]) {
+ ctrl.$$animate.removeClass(ctrl.$$element, className);
+ ctrl.$$classCache[className] = false;
+ }
+ }
+
+ function toggleValidationCss(ctrl, validationErrorKey, isValid) {
+ validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
+
+ cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true);
+ cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false);
+ }
+}
+
+function isObjectEmpty(obj) {
+ if (obj) {
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* global
VALID_CLASS: false,
INVALID_CLASS: false,
@@ -23852,7 +23954,17 @@ var inputType = {
* @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`.
+ * Can be interpolated.
* @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
+ * Can be interpolated.
+ * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
+ * but does not trigger HTML5 native validation. Takes an expression.
+ * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
+ * but does not trigger HTML5 native validation. Takes an expression.
+ * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
+ * Can be interpolated.
+ * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
+ * but does not trigger HTML5 native validation. Takes an expression.
* @param {string=} required Sets `required` validation error key if the value is not entered.
* @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
* the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
@@ -24207,28 +24319,6 @@ var inputType = {
* @description
* Native range input with validation and transformation.
*
- *
- *
- * In v1.5.9+, in order to avoid interfering with already existing, custom directives for
- * `input[range]`, you need to let Angular know that you want to enable its built-in support.
- * You can do this by adding the `ng-input-range` attribute to the input element. E.g.:
- * ``
- *
- *
- * Input elements without the `ng-input-range` attibute will continue to be treated the same
- * as in previous versions (e.g. their model value will be a string not a number and Angular
- * will not take `min`/`max`/`step` attributes and properties into account).
- *
- *
- * **Note:** From v1.6.x onwards, the support for `input[range]` will be always enabled and
- * the `ng-input-range` attribute will have no effect.
- *
- *
- * This documentation page refers to elements which have the built-in support enabled; i.e.
- * elements _with_ the `ng-input-range` attribute.
- *
- *
- *
* The model for the range input must always be a `Number`.
*
* IE9 and other browsers that do not support the `range` type fall back
@@ -24250,7 +24340,7 @@ var inputType = {
*
* Since the element value should always reflect the current model value, a range input
* will set the bound ngModel expression to the value that the browser has set for the
- * input element. For example, in the following input ``,
+ * input element. For example, in the following input ``,
* if the application sets `model.value = null`, the browser will set the input to `'50'`.
* Angular will then set the model to `50`, to prevent input and model value being out of sync.
*
@@ -24269,12 +24359,10 @@ var inputType = {
* instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step`
* error on the input, and set the model to `undefined`.
*
- * Note that `input[range]` is not compatible with `ngMax`, `ngMin`, and `ngStep`, because they do
+ * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
* not set the `min` and `max` attributes, which means that the browser won't automatically adjust
* the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
*
- * @param ngInputRange The presense of this attribute enables the built-in support for
- * `input[range]`.
* @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 to ensure that the value entered is greater
@@ -24302,7 +24390,7 @@ var inputType = {