Commit d2bfd1d8 authored by Pascal Hartig's avatar Pascal Hartig

AngularJS: Upgrade to 1.3.6

parent 81c8ad00
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
"name": "todomvc-angular", "name": "todomvc-angular",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"angular": "1.3.5", "angular": "1.3.6",
"todomvc-common": "~0.3.0" "todomvc-common": "~0.3.0"
}, },
"devDependencies": { "devDependencies": {
"angular-mocks": "1.3.5", "angular-mocks": "1.3.6",
"angular-route": "1.3.5" "angular-route": "1.3.6"
} }
} }
/** /**
* @license AngularJS v1.3.5 * @license AngularJS v1.3.6
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -788,7 +788,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory); ...@@ -788,7 +788,6 @@ ngRouteModule.directive('ngView', ngViewFillContentFactory);
.view-animate-container { .view-animate-container {
position:relative; position:relative;
height:100px!important; height:100px!important;
position:relative;
background:white; background:white;
border:1px solid black; border:1px solid black;
height:40px; height:40px;
......
/** /**
* @license AngularJS v1.3.5 * @license AngularJS v1.3.6
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -54,7 +54,7 @@ function minErr(module, ErrorConstructor) { ...@@ -54,7 +54,7 @@ function minErr(module, ErrorConstructor) {
return match; return match;
}); });
message = message + '\nhttp://errors.angularjs.org/1.3.5/' + message = message + '\nhttp://errors.angularjs.org/1.3.6/' +
(module ? module + '/' : '') + code; (module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) { for (i = 2; i < arguments.length; i++) {
message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' + message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
...@@ -1028,12 +1028,16 @@ function toJsonReplacer(key, value) { ...@@ -1028,12 +1028,16 @@ function toJsonReplacer(key, value) {
* stripped since angular uses this notation internally. * stripped since angular uses this notation internally.
* *
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON. * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
* @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace. * @param {boolean|number=} pretty If set to true, the JSON output will contain newlines and whitespace.
* If set to an integer, the JSON output will contain that many spaces per indentation (the default is 2).
* @returns {string|undefined} JSON-ified string representing `obj`. * @returns {string|undefined} JSON-ified string representing `obj`.
*/ */
function toJson(obj, pretty) { function toJson(obj, pretty) {
if (typeof obj === 'undefined') return undefined; if (typeof obj === 'undefined') return undefined;
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null); if (!isNumber(pretty)) {
pretty = pretty ? 2 : null;
}
return JSON.stringify(obj, toJsonReplacer, pretty);
} }
...@@ -2081,7 +2085,8 @@ function toDebugString(obj) { ...@@ -2081,7 +2085,8 @@ function toDebugString(obj) {
$TimeoutProvider, $TimeoutProvider,
$$RAFProvider, $$RAFProvider,
$$AsyncCallbackProvider, $$AsyncCallbackProvider,
$WindowProvider $WindowProvider,
$$jqLiteProvider
*/ */
...@@ -2100,11 +2105,11 @@ function toDebugString(obj) { ...@@ -2100,11 +2105,11 @@ function toDebugString(obj) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/ */
var version = { var version = {
full: '1.3.5', // all of these placeholder strings will be replaced by grunt's full: '1.3.6', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task major: 1, // package task
minor: 3, minor: 3,
dot: 5, dot: 6,
codeName: 'cybernetic-mercantilism' codeName: 'robofunky-danceblaster'
}; };
...@@ -2234,7 +2239,8 @@ function publishExternalAPI(angular) { ...@@ -2234,7 +2239,8 @@ function publishExternalAPI(angular) {
$timeout: $TimeoutProvider, $timeout: $TimeoutProvider,
$window: $WindowProvider, $window: $WindowProvider,
$$rAF: $$RAFProvider, $$rAF: $$RAFProvider,
$$asyncCallback: $$AsyncCallbackProvider $$asyncCallback: $$AsyncCallbackProvider,
$$jqLite: $$jqLiteProvider
}); });
} }
]); ]);
...@@ -3244,6 +3250,27 @@ forEach({ ...@@ -3244,6 +3250,27 @@ forEach({
JQLite.prototype.unbind = JQLite.prototype.off; JQLite.prototype.unbind = JQLite.prototype.off;
}); });
// Provider for private $$jqLite service
function $$jqLiteProvider() {
this.$get = function $$jqLite() {
return extend(JQLite, {
hasClass: function(node, classes) {
if (node.attr) node = node[0];
return jqLiteHasClass(node, classes);
},
addClass: function(node, classes) {
if (node.attr) node = node[0];
return jqLiteAddClass(node, classes);
},
removeClass: function(node, classes) {
if (node.attr) node = node[0];
return jqLiteRemoveClass(node, classes);
}
});
};
}
/** /**
* Computes a hash of an 'obj'. * Computes a hash of an 'obj'.
* Hash of a: * Hash of a:
...@@ -3496,6 +3523,7 @@ function annotate(fn, strictDi, name) { ...@@ -3496,6 +3523,7 @@ function annotate(fn, strictDi, name) {
* Return an instance of the service. * Return an instance of the service.
* *
* @param {string} name The name of the instance to retrieve. * @param {string} name The name of the instance to retrieve.
* @param {string} caller An optional string to provide the origin of the function call for error messages.
* @return {*} The instance. * @return {*} The instance.
*/ */
...@@ -3946,14 +3974,17 @@ function createInjector(modulesToLoad, strictDi) { ...@@ -3946,14 +3974,17 @@ function createInjector(modulesToLoad, strictDi) {
} }
}, },
providerInjector = (providerCache.$injector = providerInjector = (providerCache.$injector =
createInternalInjector(providerCache, function() { createInternalInjector(providerCache, function(serviceName, caller) {
if (angular.isString(caller)) {
path.push(caller);
}
throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- ')); throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
})), })),
instanceCache = {}, instanceCache = {},
instanceInjector = (instanceCache.$injector = instanceInjector = (instanceCache.$injector =
createInternalInjector(instanceCache, function(servicename) { createInternalInjector(instanceCache, function(serviceName, caller) {
var provider = providerInjector.get(servicename + providerSuffix); var provider = providerInjector.get(serviceName + providerSuffix, caller);
return instanceInjector.invoke(provider.$get, provider, undefined, servicename); return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
})); }));
...@@ -3988,7 +4019,7 @@ function createInjector(modulesToLoad, strictDi) { ...@@ -3988,7 +4019,7 @@ function createInjector(modulesToLoad, strictDi) {
function enforceReturnValue(name, factory) { function enforceReturnValue(name, factory) {
return function enforcedReturnValue() { return function enforcedReturnValue() {
var result = instanceInjector.invoke(factory, this, undefined, name); var result = instanceInjector.invoke(factory, this);
if (isUndefined(result)) { if (isUndefined(result)) {
throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name); throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
} }
...@@ -4083,7 +4114,7 @@ function createInjector(modulesToLoad, strictDi) { ...@@ -4083,7 +4114,7 @@ function createInjector(modulesToLoad, strictDi) {
function createInternalInjector(cache, factory) { function createInternalInjector(cache, factory) {
function getService(serviceName) { function getService(serviceName, caller) {
if (cache.hasOwnProperty(serviceName)) { if (cache.hasOwnProperty(serviceName)) {
if (cache[serviceName] === INSTANTIATING) { if (cache[serviceName] === INSTANTIATING) {
throw $injectorMinErr('cdep', 'Circular dependency found: {0}', throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
...@@ -4094,7 +4125,7 @@ function createInjector(modulesToLoad, strictDi) { ...@@ -4094,7 +4125,7 @@ function createInjector(modulesToLoad, strictDi) {
try { try {
path.unshift(serviceName); path.unshift(serviceName);
cache[serviceName] = INSTANTIATING; cache[serviceName] = INSTANTIATING;
return cache[serviceName] = factory(serviceName); return cache[serviceName] = factory(serviceName, caller);
} catch (err) { } catch (err) {
if (cache[serviceName] === INSTANTIATING) { if (cache[serviceName] === INSTANTIATING) {
delete cache[serviceName]; delete cache[serviceName];
...@@ -4126,7 +4157,7 @@ function createInjector(modulesToLoad, strictDi) { ...@@ -4126,7 +4157,7 @@ function createInjector(modulesToLoad, strictDi) {
args.push( args.push(
locals && locals.hasOwnProperty(key) locals && locals.hasOwnProperty(key)
? locals[key] ? locals[key]
: getService(key) : getService(key, serviceName)
); );
} }
if (isArray(fn)) { if (isArray(fn)) {
...@@ -4870,6 +4901,11 @@ function Browser(window, document, $log, $sniffer) { ...@@ -4870,6 +4901,11 @@ function Browser(window, document, $log, $sniffer) {
} }
} }
function getHash(url) {
var index = url.indexOf('#');
return index === -1 ? '' : url.substr(index + 1);
}
/** /**
* @private * @private
* Note: this method is used only by scenario runner * Note: this method is used only by scenario runner
...@@ -4999,8 +5035,10 @@ function Browser(window, document, $log, $sniffer) { ...@@ -4999,8 +5035,10 @@ function Browser(window, document, $log, $sniffer) {
} }
if (replace) { if (replace) {
location.replace(url); location.replace(url);
} else { } else if (!sameBase) {
location.href = url; location.href = url;
} else {
location.hash = getHash(url);
} }
} }
return self; return self;
...@@ -5779,7 +5817,7 @@ function $TemplateCacheProvider() { ...@@ -5779,7 +5817,7 @@ function $TemplateCacheProvider() {
* #### `multiElement` * #### `multiElement`
* When this property is set to true, the HTML compiler will collect DOM nodes between * When this property is set to true, the HTML compiler will collect DOM nodes between
* nodes with the attributes `directive-name-start` and `directive-name-end`, and group them * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
* together as the directive elements. It is recomended that this feature be used on directives * together as the directive elements. It is recommended that this feature be used on directives
* which are not strictly behavioural (such as {@link ngClick}), and which * which are not strictly behavioural (such as {@link ngClick}), and which
* do not manipulate or replace child nodes (such as {@link ngInclude}). * do not manipulate or replace child nodes (such as {@link ngInclude}).
* *
...@@ -6571,6 +6609,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6571,6 +6609,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}; };
Attributes.prototype = { Attributes.prototype = {
/**
* @ngdoc method
* @name $compile.directive.Attributes#$normalize
* @kind function
*
* @description
* Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
* `data-`) to its normalized, camelCase form.
*
* Also there is special case for Moz prefix starting with upper case letter.
*
* For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
*
* @param {string} name Name to normalize
*/
$normalize: directiveNormalize, $normalize: directiveNormalize,
...@@ -8149,13 +8202,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -8149,13 +8202,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i; var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
/** /**
* Converts all accepted directives format into proper directive name. * Converts all accepted directives format into proper directive name.
* All of these will become 'myDirective':
* my:Directive
* my-directive
* x-my-directive
* data-my:directive
*
* Also there is special case for Moz prefix starting with upper case letter.
* @param name Name to normalize * @param name Name to normalize
*/ */
function directiveNormalize(name) { function directiveNormalize(name) {
...@@ -9508,8 +9554,7 @@ function $HttpProvider() { ...@@ -9508,8 +9554,7 @@ function $HttpProvider() {
if (isDefined(cachedResp)) { if (isDefined(cachedResp)) {
if (isPromiseLike(cachedResp)) { if (isPromiseLike(cachedResp)) {
// cached request has already been sent, but there is no response yet // cached request has already been sent, but there is no response yet
cachedResp.then(removePendingReq, removePendingReq); cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
return cachedResp;
} else { } else {
// serving from cache // serving from cache
if (isArray(cachedResp)) { if (isArray(cachedResp)) {
...@@ -9587,6 +9632,9 @@ function $HttpProvider() { ...@@ -9587,6 +9632,9 @@ function $HttpProvider() {
}); });
} }
function resolvePromiseWithResult(result) {
resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
}
function removePendingReq() { function removePendingReq() {
var idx = $http.pendingRequests.indexOf(config); var idx = $http.pendingRequests.indexOf(config);
...@@ -10467,6 +10515,10 @@ function stripHash(url) { ...@@ -10467,6 +10515,10 @@ function stripHash(url) {
return index == -1 ? url : url.substr(0, index); return index == -1 ? url : url.substr(0, index);
} }
function trimEmptyHash(url) {
return url.replace(/(#.+)|#$/, '$1');
}
function stripFile(url) { function stripFile(url) {
return url.substr(0, stripHash(url).lastIndexOf('/') + 1); return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
...@@ -10578,16 +10630,25 @@ function LocationHashbangUrl(appBase, hashPrefix) { ...@@ -10578,16 +10630,25 @@ function LocationHashbangUrl(appBase, hashPrefix) {
*/ */
this.$$parse = function(url) { this.$$parse = function(url) {
var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url); var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
var withoutHashUrl = withoutBaseUrl.charAt(0) == '#' var withoutHashUrl;
? beginsWith(hashPrefix, withoutBaseUrl)
: (this.$$html5) if (withoutBaseUrl.charAt(0) === '#') {
? withoutBaseUrl
: '';
if (!isString(withoutHashUrl)) { // The rest of the url starts with a hash so we have
throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url, // got either a hashbang path or a plain hash fragment
hashPrefix); withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
if (isUndefined(withoutHashUrl)) {
// There was no hashbang prefix so we just have a hash fragment
withoutHashUrl = withoutBaseUrl;
} }
} 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 : '';
}
parseAppUrl(withoutHashUrl, this); parseAppUrl(withoutHashUrl, this);
this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase); this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
...@@ -10950,7 +11011,7 @@ var locationPrototype = { ...@@ -10950,7 +11011,7 @@ var locationPrototype = {
* *
* *
* ```js * ```js
* // given url http://example.com/some/path?foo=bar&baz=xoxo#hashValue * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
* var hash = $location.hash(); * var hash = $location.hash();
* // => "hashValue" * // => "hashValue"
* ``` * ```
...@@ -11302,10 +11363,11 @@ function $LocationProvider() { ...@@ -11302,10 +11363,11 @@ function $LocationProvider() {
// update browser // update browser
$rootScope.$watch(function $locationWatch() { $rootScope.$watch(function $locationWatch() {
var oldUrl = $browser.url(); var oldUrl = trimEmptyHash($browser.url());
var newUrl = trimEmptyHash($location.absUrl());
var oldState = $browser.state(); var oldState = $browser.state();
var currentReplace = $location.$$replace; var currentReplace = $location.$$replace;
var urlOrStateChanged = oldUrl !== $location.absUrl() || var urlOrStateChanged = oldUrl !== newUrl ||
($location.$$html5 && $sniffer.history && oldState !== $location.$$state); ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
if (initializing || urlOrStateChanged) { if (initializing || urlOrStateChanged) {
...@@ -12108,8 +12170,8 @@ Parser.prototype = { ...@@ -12108,8 +12170,8 @@ Parser.prototype = {
logicalAND: function() { logicalAND: function() {
var left = this.equality(); var left = this.equality();
var token; var token;
if ((token = this.expect('&&'))) { while ((token = this.expect('&&'))) {
left = this.binaryFn(left, token.text, this.logicalAND(), true); left = this.binaryFn(left, token.text, this.equality(), true);
} }
return left; return left;
}, },
...@@ -12117,8 +12179,8 @@ Parser.prototype = { ...@@ -12117,8 +12179,8 @@ Parser.prototype = {
equality: function() { equality: function() {
var left = this.relational(); var left = this.relational();
var token; var token;
if ((token = this.expect('==','!=','===','!=='))) { while ((token = this.expect('==','!=','===','!=='))) {
left = this.binaryFn(left, token.text, this.equality()); left = this.binaryFn(left, token.text, this.relational());
} }
return left; return left;
}, },
...@@ -12126,8 +12188,8 @@ Parser.prototype = { ...@@ -12126,8 +12188,8 @@ Parser.prototype = {
relational: function() { relational: function() {
var left = this.additive(); var left = this.additive();
var token; var token;
if ((token = this.expect('<', '>', '<=', '>='))) { while ((token = this.expect('<', '>', '<=', '>='))) {
left = this.binaryFn(left, token.text, this.relational()); left = this.binaryFn(left, token.text, this.additive());
} }
return left; return left;
}, },
...@@ -12219,7 +12281,7 @@ Parser.prototype = { ...@@ -12219,7 +12281,7 @@ Parser.prototype = {
var args = argsFn.length ? [] : null; var args = argsFn.length ? [] : null;
return function $parseFunctionCall(scope, locals) { return function $parseFunctionCall(scope, locals) {
var context = contextGetter ? contextGetter(scope, locals) : scope; var context = contextGetter ? contextGetter(scope, locals) : isDefined(contextGetter) ? undefined : scope;
var fn = fnGetter(scope, locals, context) || noop; var fn = fnGetter(scope, locals, context) || noop;
if (args) { if (args) {
...@@ -15874,7 +15936,9 @@ function $SnifferProvider() { ...@@ -15874,7 +15936,9 @@ function $SnifferProvider() {
// IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
// it. In particular the event is not fired when backspace or delete key are pressed or // it. In particular the event is not fired when backspace or delete key are pressed or
// when cut operation is performed. // when cut operation is performed.
if (event == 'input' && msie == 9) return false; // IE10+ implements 'input' event but it erroneously fires under various situations,
// e.g. when placeholder changes, or a form is focused.
if (event === 'input' && msie <= 11) return false;
if (isUndefined(eventSupport[event])) { if (isUndefined(eventSupport[event])) {
var divElm = document.createElement('div'); var divElm = document.createElement('div');
...@@ -15934,10 +15998,8 @@ function $TemplateRequestProvider() { ...@@ -15934,10 +15998,8 @@ function $TemplateRequestProvider() {
return $http.get(tpl, httpOptions) return $http.get(tpl, httpOptions)
.then(function(response) { .then(function(response) {
var html = response.data;
self.totalPendingRequests--; self.totalPendingRequests--;
$templateCache.put(tpl, html); return response.data;
return html;
}, handleError); }, handleError);
function handleError(resp) { function handleError(resp) {
...@@ -16568,106 +16630,103 @@ function filterFilter() { ...@@ -16568,106 +16630,103 @@ function filterFilter() {
return function(array, expression, comparator) { return function(array, expression, comparator) {
if (!isArray(array)) return array; if (!isArray(array)) return array;
var comparatorType = typeof(comparator), var predicateFn;
predicates = []; var matchAgainstAnyProp;
predicates.check = function(value, index) { switch (typeof expression) {
for (var j = 0; j < predicates.length; j++) { case 'function':
if (!predicates[j](value, index)) { predicateFn = expression;
return false; break;
} case 'boolean':
case 'number':
case 'string':
matchAgainstAnyProp = true;
//jshint -W086
case 'object':
//jshint +W086
predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
break;
default:
return array;
} }
return true;
};
if (comparatorType !== 'function') { return array.filter(predicateFn);
if (comparatorType === 'boolean' && comparator) {
comparator = function(obj, text) {
return angular.equals(obj, text);
}; };
} else { }
comparator = function(obj, text) {
if (obj && text && typeof obj === 'object' && typeof text === 'object') { // Helper functions for `filterFilter`
for (var objKey in obj) { function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
if (objKey.charAt(0) !== '$' && hasOwnProperty.call(obj, objKey) && var predicateFn;
comparator(obj[objKey], text[objKey])) {
return true; if (comparator === true) {
} comparator = equals;
} } else if (!isFunction(comparator)) {
comparator = function(actual, expected) {
if (isObject(actual) || isObject(expected)) {
// Prevent an object to be considered equal to a string like `'[object'`
return false; return false;
} }
text = ('' + text).toLowerCase();
return ('' + obj).toLowerCase().indexOf(text) > -1; actual = lowercase('' + actual);
expected = lowercase('' + expected);
return actual.indexOf(expected) !== -1;
}; };
} }
}
var search = function(obj, text) { predicateFn = function(item) {
if (typeof text === 'string' && text.charAt(0) === '!') { return deepCompare(item, expression, comparator, matchAgainstAnyProp);
return !search(obj, text.substr(1)); };
return predicateFn;
}
function deepCompare(actual, expected, comparator, matchAgainstAnyProp) {
var actualType = typeof actual;
var expectedType = typeof expected;
if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
} else if (actualType === 'array') {
// In case `actual` is an array, consider it a match
// if ANY of it's items matches `expected`
return actual.some(function(item) {
return deepCompare(item, expected, comparator, matchAgainstAnyProp);
});
} }
switch (typeof obj) {
case 'boolean': switch (actualType) {
case 'number':
case 'string':
return comparator(obj, text);
case 'object':
switch (typeof text) {
case 'object': case 'object':
return comparator(obj, text); var key;
default: if (matchAgainstAnyProp) {
for (var objKey in obj) { for (key in actual) {
if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) { if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator)) {
return true; return true;
} }
} }
break;
}
return false; return false;
case 'array': } else if (expectedType === 'object') {
for (var i = 0; i < obj.length; i++) { for (key in expected) {
if (search(obj[i], text)) { var expectedVal = expected[key];
return true; if (isFunction(expectedVal)) {
} continue;
} }
return false;
default: var keyIsDollar = key === '$';
var actualVal = keyIsDollar ? actual : actual[key];
if (!deepCompare(actualVal, expectedVal, comparator, keyIsDollar)) {
return false; return false;
} }
}; }
switch (typeof expression) { return true;
case 'boolean': } else {
case 'number': return comparator(actual, expected);
case 'string':
// Set up expression object and fall through
expression = {$:expression};
// jshint -W086
case 'object':
// jshint +W086
for (var key in expression) {
(function(path) {
if (typeof expression[path] === 'undefined') return;
predicates.push(function(value) {
return search(path == '$' ? value : (value && value[path]), expression[path]);
});
})(key);
} }
break; break;
case 'function': case 'function':
predicates.push(expression); return false;
break;
default: default:
return array; return comparator(actual, expected);
} }
var filtered = [];
for (var j = 0; j < array.length; j++) {
var value = array[j];
if (predicates.check(value, j)) {
filtered.push(value);
}
}
return filtered;
};
} }
/** /**
...@@ -16820,7 +16879,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -16820,7 +16879,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (numStr.indexOf('e') !== -1) { if (numStr.indexOf('e') !== -1) {
var match = numStr.match(/([\d\.]+)e(-?)(\d+)/); var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
if (match && match[2] == '-' && match[3] > fractionSize + 1) { if (match && match[2] == '-' && match[3] > fractionSize + 1) {
numStr = '0';
number = 0; number = 0;
} else { } else {
formatedText = numStr; formatedText = numStr;
...@@ -16841,10 +16899,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -16841,10 +16899,6 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize); number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
if (number === 0) {
isNegative = false;
}
var fraction = ('' + number).split(DECIMAL_SEP); var fraction = ('' + number).split(DECIMAL_SEP);
var whole = fraction[0]; var whole = fraction[0];
fraction = fraction[1] || ''; fraction = fraction[1] || '';
...@@ -16877,12 +16931,16 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) { ...@@ -16877,12 +16931,16 @@ function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize); if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
} else { } else {
if (fractionSize > 0 && number < 1) {
if (fractionSize > 0 && number > -1 && number < 1) {
formatedText = number.toFixed(fractionSize); formatedText = number.toFixed(fractionSize);
number = parseFloat(formatedText);
} }
} }
if (number === 0) {
isNegative = false;
}
parts.push(isNegative ? pattern.negPre : pattern.posPre, parts.push(isNegative ? pattern.negPre : pattern.posPre,
formatedText, formatedText,
isNegative ? pattern.negSuf : pattern.posSuf); isNegative ? pattern.negSuf : pattern.posSuf);
...@@ -17172,25 +17230,31 @@ function dateFilter($locale) { ...@@ -17172,25 +17230,31 @@ function dateFilter($locale) {
* the binding is automatically converted to JSON. * the binding is automatically converted to JSON.
* *
* @param {*} object Any JavaScript object (including arrays and primitive types) to filter. * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
* @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
* @returns {string} JSON string. * @returns {string} JSON string.
* *
* *
* @example * @example
<example> <example>
<file name="index.html"> <file name="index.html">
<pre>{{ {'name':'value'} | json }}</pre> <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
<pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
</file> </file>
<file name="protractor.js" type="protractor"> <file name="protractor.js" type="protractor">
it('should jsonify filtered objects', function() { it('should jsonify filtered objects', function() {
expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/); expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n "name": ?"value"\n}/);
}); });
</file> </file>
</example> </example>
* *
*/ */
function jsonFilter() { function jsonFilter() {
return function(object) { return function(object, spacing) {
return toJson(object, true); if (isUndefined(spacing)) {
spacing = 2;
}
return toJson(object, spacing);
}; };
} }
...@@ -17510,12 +17574,29 @@ function orderByFilter($parse) { ...@@ -17510,12 +17574,29 @@ function orderByFilter($parse) {
function compare(v1, v2) { function compare(v1, v2) {
var t1 = typeof v1; var t1 = typeof v1;
var t2 = typeof v2; var t2 = typeof v2;
if (t1 == t2) { // Prepare values for Abstract Relational Comparison
if (isDate(v1) && isDate(v2)) { // (http://www.ecma-international.org/ecma-262/5.1/#sec-11.8.5):
v1 = v1.valueOf(); // If the resulting values are identical, return 0 to prevent
v2 = v2.valueOf(); // incorrect re-ordering.
} if (t1 === t2 && t1 === "object") {
if (t1 == "string") { // If types are both numbers, emulate abstract ToPrimitive() operation
// in order to get primitive values suitable for comparison
t1 = typeof (v1.valueOf ? v1 = v1.valueOf() : v1);
t2 = typeof (v2.valueOf ? v2 = v2.valueOf() : v2);
if (t1 === t2 && t1 === "object") {
// Object.prototype.valueOf will return the original object, by
// default. If we do not receive a primitive value, use ToString()
// instead.
t1 = typeof (v1.toString ? v1 = v1.toString() : v1);
t2 = typeof (v2.toString ? v2 = v2.toString() : v2);
// If the end result of toString() for each item is the same, do not
// perform relational comparison, and do not re-order objects.
if (t1 === t2 && v1 === v2 || t1 === "object") return 0;
}
}
if (t1 === t2) {
if (t1 === "string") {
v1 = v1.toLowerCase(); v1 = v1.toLowerCase();
v2 = v2.toLowerCase(); v2 = v2.toLowerCase();
} }
...@@ -19464,7 +19545,6 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -19464,7 +19545,6 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
} }
function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
var placeholder = element[0].placeholder, noevent = {};
var type = lowercase(element[0].type); var type = lowercase(element[0].type);
// In composition mode, users are still inputing intermediate text buffer, // In composition mode, users are still inputing intermediate text buffer,
...@@ -19484,19 +19564,14 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -19484,19 +19564,14 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
} }
var listener = function(ev) { var listener = function(ev) {
if (timeout) {
$browser.defer.cancel(timeout);
timeout = null;
}
if (composing) return; if (composing) return;
var value = element.val(), var value = element.val(),
event = ev && ev.type; event = ev && ev.type;
// IE (11 and under) seem to emit an 'input' event if the placeholder value changes.
// We don't want to dirty the value when this happens, so we abort here. Unfortunately,
// IE also sends input events for other non-input-related things, (such as focusing on a
// form control), so this change is not entirely enough to solve this.
if (msie && (ev || noevent).type === 'input' && element[0].placeholder !== placeholder) {
placeholder = element[0].placeholder;
return;
}
// By default we will trim the value // By default we will trim the value
// If the attribute ng-trim exists we will avoid trimming // If the attribute ng-trim exists we will avoid trimming
// If input type is 'password', the value is never trimmed // If input type is 'password', the value is never trimmed
...@@ -19519,11 +19594,13 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -19519,11 +19594,13 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
} else { } else {
var timeout; var timeout;
var deferListener = function(ev) { var deferListener = function(ev, input, origValue) {
if (!timeout) { if (!timeout) {
timeout = $browser.defer(function() { timeout = $browser.defer(function() {
listener(ev);
timeout = null; timeout = null;
if (!input || input.value !== origValue) {
listener(ev);
}
}); });
} }
}; };
...@@ -19535,7 +19612,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) { ...@@ -19535,7 +19612,7 @@ function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// command modifiers arrows // command modifiers arrows
if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return; if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
deferListener(event); deferListener(event, this, this.value);
}); });
// if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
...@@ -20710,11 +20787,15 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$ ...@@ -20710,11 +20787,15 @@ var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$
var prevModelValue = ctrl.$modelValue; var prevModelValue = ctrl.$modelValue;
var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid; var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
ctrl.$$rawModelValue = modelValue; ctrl.$$rawModelValue = modelValue;
if (allowInvalid) { if (allowInvalid) {
ctrl.$modelValue = modelValue; ctrl.$modelValue = modelValue;
writeToModelIfNeeded(); writeToModelIfNeeded();
} }
ctrl.$$runValidators(parserValid, modelValue, viewValue, function(allValid) {
// Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
// This can happen if e.g. $setViewValue is called from inside a parser
ctrl.$$runValidators(parserValid, modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
if (!allowInvalid) { if (!allowInvalid) {
// Note: Don't check ctrl.$valid here, as we could have // Note: Don't check ctrl.$valid here, as we could have
// external validators (e.g. calculated on the server), // external validators (e.g. calculated on the server),
...@@ -25056,7 +25137,7 @@ var ngSwitchDefaultDirective = ngDirective({ ...@@ -25056,7 +25137,7 @@ var ngSwitchDefaultDirective = ngDirective({
}]); }]);
</script> </script>
<div ng-controller="ExampleController"> <div ng-controller="ExampleController">
<input ng-model="title"><br> <input ng-model="title"> <br/>
<textarea ng-model="text"></textarea> <br/> <textarea ng-model="text"></textarea> <br/>
<pane title="{{title}}">{{text}}</pane> <pane title="{{title}}">{{text}}</pane>
</div> </div>
...@@ -25184,9 +25265,9 @@ var ngOptionsMinErr = minErr('ngOptions'); ...@@ -25184,9 +25265,9 @@ var ngOptionsMinErr = minErr('ngOptions');
* or property name (for object data sources) of the value within the collection. If a `track by` expression * or property name (for object data sources) of the value within the collection. If a `track by` expression
* is used, the result of that expression will be set as the value of the `option` and `select` elements. * is used, the result of that expression will be set as the value of the `option` and `select` elements.
* *
* ### `select as` with `trackexpr` * ### `select as` with `track by`
* *
* Using `select as` together with `trackexpr` is not recommended. Reasoning: * Using `select as` together with `track by` is not recommended. Reasoning:
* *
* - Example: &lt;select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"&gt; * - Example: &lt;select ng-options="item.subItem as item.label for item in values track by item.id" ng-model="selected"&gt;
* values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}], * values: [{id: 1, label: 'aLabel', subItem: {name: 'aSubItem'}}, {id: 2, label: 'bLabel', subItem: {name: 'bSubItem'}}],
...@@ -25212,7 +25293,9 @@ var ngOptionsMinErr = minErr('ngOptions'); ...@@ -25212,7 +25293,9 @@ var ngOptionsMinErr = minErr('ngOptions');
* * `label` **`for`** `value` **`in`** `array` * * `label` **`for`** `value` **`in`** `array`
* * `select` **`as`** `label` **`for`** `value` **`in`** `array` * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
* * `label` **`group by`** `group` **`for`** `value` **`in`** `array` * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
* * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr` * * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
* * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
* (for including a filter with `track by`)
* * for object data sources: * * for object data sources:
* * `label` **`for (`**`key` **`,`** `value`**`) in`** `object` * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
* * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object` * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment