Commit 0cfffc02 authored by Pascal Hartig's avatar Pascal Hartig

AngularJS: Upgrade to 1.2.22 (skipping 1.2.21, oops)

parent f07cabac
...@@ -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.2.20", "angular": "1.2.22",
"todomvc-common": "~0.1.4" "todomvc-common": "~0.1.4"
}, },
"devDependencies": { "devDependencies": {
"angular-mocks": "1.2.20", "angular-mocks": "1.2.22",
"angular-route": "1.2.20" "angular-route": "1.2.22"
} }
} }
/** /**
* @license AngularJS v1.2.20 * @license AngularJS v1.2.22
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -473,9 +473,7 @@ function $RouteProvider(){ ...@@ -473,9 +473,7 @@ function $RouteProvider(){
for (var i = 1, len = m.length; i < len; ++i) { for (var i = 1, len = m.length; i < len; ++i) {
var key = keys[i - 1]; var key = keys[i - 1];
var val = 'string' == typeof m[i] var val = m[i];
? decodeURIComponent(m[i])
: m[i];
if (key && val) { if (key && val) {
params[key.name] = val; params[key.name] = val;
......
/** /**
* @license AngularJS v1.2.20 * @license AngularJS v1.2.22
* (c) 2010-2014 Google, Inc. http://angularjs.org * (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT * License: MIT
*/ */
...@@ -68,7 +68,7 @@ function minErr(module) { ...@@ -68,7 +68,7 @@ function minErr(module) {
return match; return match;
}); });
message = message + '\nhttp://errors.angularjs.org/1.2.20/' + message = message + '\nhttp://errors.angularjs.org/1.2.22/' +
(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) + '=' +
...@@ -80,89 +80,88 @@ function minErr(module) { ...@@ -80,89 +80,88 @@ function minErr(module) {
} }
/* We need to tell jshint what variables are being exported */ /* We need to tell jshint what variables are being exported */
/* global /* global angular: true,
-angular, msie: true,
-msie, jqLite: true,
-jqLite, jQuery: true,
-jQuery, slice: true,
-slice, push: true,
-push, toString: true,
-toString, ngMinErr: true,
-ngMinErr, angularModule: true,
-angularModule, nodeName_: true,
-nodeName_, uid: true,
-uid, VALIDITY_STATE_PROPERTY: true,
-VALIDITY_STATE_PROPERTY,
lowercase: true,
-lowercase, uppercase: true,
-uppercase, manualLowercase: true,
-manualLowercase, manualUppercase: true,
-manualUppercase, nodeName_: true,
-nodeName_, isArrayLike: true,
-isArrayLike, forEach: true,
-forEach, sortedKeys: true,
-sortedKeys, forEachSorted: true,
-forEachSorted, reverseParams: true,
-reverseParams, nextUid: true,
-nextUid, setHashKey: true,
-setHashKey, extend: true,
-extend, int: true,
-int, inherit: true,
-inherit, noop: true,
-noop, identity: true,
-identity, valueFn: true,
-valueFn, isUndefined: true,
-isUndefined, isDefined: true,
-isDefined, isObject: true,
-isObject, isString: true,
-isString, isNumber: true,
-isNumber, isDate: true,
-isDate, isArray: true,
-isArray, isFunction: true,
-isFunction, isRegExp: true,
-isRegExp, isWindow: true,
-isWindow, isScope: true,
-isScope, isFile: true,
-isFile, isBlob: true,
-isBlob, isBoolean: true,
-isBoolean, isPromiseLike: true,
-trim, trim: true,
-isElement, isElement: true,
-makeMap, makeMap: true,
-map, map: true,
-size, size: true,
-includes, includes: true,
-indexOf, indexOf: true,
-arrayRemove, arrayRemove: true,
-isLeafNode, isLeafNode: true,
-copy, copy: true,
-shallowCopy, shallowCopy: true,
-equals, equals: true,
-csp, csp: true,
-concat, concat: true,
-sliceArgs, sliceArgs: true,
-bind, bind: true,
-toJsonReplacer, toJsonReplacer: true,
-toJson, toJson: true,
-fromJson, fromJson: true,
-toBoolean, toBoolean: true,
-startingTag, startingTag: true,
-tryDecodeURIComponent, tryDecodeURIComponent: true,
-parseKeyValue, parseKeyValue: true,
-toKeyValue, toKeyValue: true,
-encodeUriSegment, encodeUriSegment: true,
-encodeUriQuery, encodeUriQuery: true,
-angularInit, angularInit: true,
-bootstrap, bootstrap: true,
-snake_case, snake_case: true,
-bindJQuery, bindJQuery: true,
-assertArg, assertArg: true,
-assertArgFn, assertArgFn: true,
-assertNotHasOwnProperty, assertNotHasOwnProperty: true,
-getter, getter: true,
-getBlockElements, getBlockElements: true,
-hasOwnProperty, hasOwnProperty: true,
*/ */
//////////////////////////////////// ////////////////////////////////////
...@@ -321,11 +320,12 @@ function forEach(obj, iterator, context) { ...@@ -321,11 +320,12 @@ function forEach(obj, iterator, context) {
iterator.call(context, obj[key], key); iterator.call(context, obj[key], key);
} }
} }
} else if (obj.forEach && obj.forEach !== forEach) { } else if (isArray(obj) || isArrayLike(obj)) {
obj.forEach(iterator, context); for (key = 0; key < obj.length; key++) {
} else if (isArrayLike(obj)) {
for (key = 0; key < obj.length; key++)
iterator.call(context, obj[key], key); iterator.call(context, obj[key], key);
}
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
} else { } else {
for (key in obj) { for (key in obj) {
if (obj.hasOwnProperty(key)) { if (obj.hasOwnProperty(key)) {
...@@ -662,6 +662,11 @@ function isBoolean(value) { ...@@ -662,6 +662,11 @@ function isBoolean(value) {
} }
function isPromiseLike(obj) {
return obj && isFunction(obj.then);
}
var trim = (function() { var trim = (function() {
// native trim is way faster: http://jsperf.com/angular-trim-test // native trim is way faster: http://jsperf.com/angular-trim-test
// but IE doesn't have it... :-( // but IE doesn't have it... :-(
...@@ -826,7 +831,7 @@ function isLeafNode (node) { ...@@ -826,7 +831,7 @@ function isLeafNode (node) {
</div> </div>
<script> <script>
angular.module('copyExample') angular.module('copyExample', [])
.controller('ExampleController', ['$scope', function($scope) { .controller('ExampleController', ['$scope', function($scope) {
$scope.master= {}; $scope.master= {};
...@@ -860,7 +865,8 @@ function copy(source, destination, stackSource, stackDest) { ...@@ -860,7 +865,8 @@ function copy(source, destination, stackSource, stackDest) {
} else if (isDate(source)) { } else if (isDate(source)) {
destination = new Date(source.getTime()); destination = new Date(source.getTime());
} else if (isRegExp(source)) { } else if (isRegExp(source)) {
destination = new RegExp(source.source); destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
destination.lastIndex = source.lastIndex;
} else if (isObject(source)) { } else if (isObject(source)) {
destination = copy(source, {}, stackSource, stackDest); destination = copy(source, {}, stackSource, stackDest);
} }
...@@ -1004,12 +1010,25 @@ function equals(o1, o2) { ...@@ -1004,12 +1010,25 @@ function equals(o1, o2) {
return false; return false;
} }
var csp = function() {
if (isDefined(csp.isActive_)) return csp.isActive_;
var active = !!(document.querySelector('[ng-csp]') ||
document.querySelector('[data-ng-csp]'));
if (!active) {
try {
/* jshint -W031, -W054 */
new Function('');
/* jshint +W031, +W054 */
} catch (e) {
active = true;
}
}
return (csp.isActive_ = active);
};
function csp() {
return (document.securityPolicy && document.securityPolicy.isActive) ||
(document.querySelector &&
!!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]')));
}
function concat(array1, array2, index) { function concat(array1, array2, index) {
...@@ -1181,7 +1200,7 @@ function parseKeyValue(/**string*/keyValue) { ...@@ -1181,7 +1200,7 @@ function parseKeyValue(/**string*/keyValue) {
var obj = {}, key_value, key; var obj = {}, key_value, key;
forEach((keyValue || "").split('&'), function(keyValue) { forEach((keyValue || "").split('&'), function(keyValue) {
if ( keyValue ) { if ( keyValue ) {
key_value = keyValue.split('='); key_value = keyValue.replace(/\+/g,'%20').split('=');
key = tryDecodeURIComponent(key_value[0]); key = tryDecodeURIComponent(key_value[0]);
if ( isDefined(key) ) { if ( isDefined(key) ) {
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true;
...@@ -1866,12 +1885,11 @@ function setupModuleLoader(window) { ...@@ -1866,12 +1885,11 @@ function setupModuleLoader(window) {
} }
/* global /* global angularModule: true,
angularModule: true, version: true,
version: true,
$LocaleProvider, $LocaleProvider,
$CompileProvider, $CompileProvider,
htmlAnchorDirective, htmlAnchorDirective,
inputDirective, inputDirective,
...@@ -1959,11 +1977,11 @@ function setupModuleLoader(window) { ...@@ -1959,11 +1977,11 @@ function setupModuleLoader(window) {
* - `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.2.20', // all of these placeholder strings will be replaced by grunt's full: '1.2.22', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task major: 1, // package task
minor: 2, minor: 2,
dot: 20, dot: 22,
codeName: 'accidental-beautification' codeName: 'finicky-pleasure'
}; };
...@@ -1976,11 +1994,11 @@ function publishExternalAPI(angular){ ...@@ -1976,11 +1994,11 @@ function publishExternalAPI(angular){
'element': jqLite, 'element': jqLite,
'forEach': forEach, 'forEach': forEach,
'injector': createInjector, 'injector': createInjector,
'noop':noop, 'noop': noop,
'bind':bind, 'bind': bind,
'toJson': toJson, 'toJson': toJson,
'fromJson': fromJson, 'fromJson': fromJson,
'identity':identity, 'identity': identity,
'isUndefined': isUndefined, 'isUndefined': isUndefined,
'isDefined': isDefined, 'isDefined': isDefined,
'isString': isString, 'isString': isString,
...@@ -2087,12 +2105,10 @@ function publishExternalAPI(angular){ ...@@ -2087,12 +2105,10 @@ function publishExternalAPI(angular){
]); ]);
} }
/* global /* global JQLitePrototype: true,
addEventListenerFn: true,
-JQLitePrototype, removeEventListenerFn: true,
-addEventListenerFn, BOOLEAN_ATTR: true
-removeEventListenerFn,
-BOOLEAN_ATTR
*/ */
////////////////////////////////// //////////////////////////////////
...@@ -2506,25 +2522,22 @@ function jqLiteController(element, name) { ...@@ -2506,25 +2522,22 @@ function jqLiteController(element, name) {
} }
function jqLiteInheritedData(element, name, value) { function jqLiteInheritedData(element, name, value) {
element = jqLite(element);
// if element is the document object work with the html element instead // if element is the document object work with the html element instead
// this makes $(document).scope() possible // this makes $(document).scope() possible
if(element[0].nodeType == 9) { if(element.nodeType == 9) {
element = element.find('html'); element = element.documentElement;
} }
var names = isArray(name) ? name : [name]; var names = isArray(name) ? name : [name];
while (element.length) { while (element) {
var node = element[0];
for (var i = 0, ii = names.length; i < ii; i++) { for (var i = 0, ii = names.length; i < ii; i++) {
if ((value = element.data(names[i])) !== undefined) return value; if ((value = jqLite.data(element, names[i])) !== undefined) return value;
} }
// If dealing with a document fragment node with a host element, and no parent, use the host // If dealing with a document fragment node with a host element, and no parent, use the host
// element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
// to lookup parent controllers. // to lookup parent controllers.
element = jqLite(node.parentNode || (node.nodeType === 11 && node.host)); element = element.parentNode || (element.nodeType === 11 && element.host);
} }
} }
...@@ -2599,18 +2612,25 @@ function getBooleanAttrName(element, name) { ...@@ -2599,18 +2612,25 @@ function getBooleanAttrName(element, name) {
return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr; return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
} }
forEach({
data: jqLiteData,
removeData: jqLiteRemoveData
}, function(fn, name) {
JQLite[name] = fn;
});
forEach({ forEach({
data: jqLiteData, data: jqLiteData,
inheritedData: jqLiteInheritedData, inheritedData: jqLiteInheritedData,
scope: function(element) { scope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery! // Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']); return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
}, },
isolateScope: function(element) { isolateScope: function(element) {
// Can't use jqLiteData here directly so we stay compatible with jQuery! // Can't use jqLiteData here directly so we stay compatible with jQuery!
return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate'); return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
}, },
controller: jqLiteController, controller: jqLiteController,
...@@ -3037,19 +3057,37 @@ forEach({ ...@@ -3037,19 +3057,37 @@ forEach({
clone: jqLiteClone, clone: jqLiteClone,
triggerHandler: function(element, eventName, eventData) { triggerHandler: function(element, event, extraParameters) {
var dummyEvent, eventFnsCopy, handlerArgs;
var eventName = event.type || event;
var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName]; var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
eventData = eventData || []; if (eventFns) {
var event = [{ // Create a dummy event to pass to the handlers
preventDefault: noop, dummyEvent = {
stopPropagation: noop preventDefault: function() { this.defaultPrevented = true; },
}]; isDefaultPrevented: function() { return this.defaultPrevented === true; },
stopPropagation: noop,
type: eventName,
target: element
};
forEach(eventFns, function(fn) { // If a custom event was provided then extend our dummy event with it
fn.apply(element, event.concat(eventData)); if (event.type) {
}); dummyEvent = extend(dummyEvent, event);
}
// Copy event handlers in case event handlers array is modified during execution.
eventFnsCopy = shallowCopy(eventFns);
handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
forEach(eventFnsCopy, function(fn) {
fn.apply(element, handlerArgs);
});
}
} }
}, function(fn, name){ }, function(fn, name){
/** /**
...@@ -5293,14 +5331,16 @@ function $TemplateCacheProvider() { ...@@ -5293,14 +5331,16 @@ function $TemplateCacheProvider() {
* *
* *
* #### `template` * #### `template`
* replace the current element with the contents of the HTML. The replacement process * HTML markup that may:
* migrates all of the attributes / classes from the old element to the new one. See the * * Replace the contents of the directive's element (default).
* {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
* Directives Guide} for an example. * * Wrap the contents of the directive's element (if `transclude` is true).
*
* Value may be:
* *
* You can specify `template` as a string representing the template or as a function which takes * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
* two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
* returns a string value representing the template. * function api below) and returns a string value.
* *
* *
* #### `templateUrl` * #### `templateUrl`
...@@ -5315,11 +5355,14 @@ function $TemplateCacheProvider() { ...@@ -5315,11 +5355,14 @@ function $TemplateCacheProvider() {
* *
* *
* #### `replace` ([*DEPRECATED*!], will be removed in next major release) * #### `replace` ([*DEPRECATED*!], will be removed in next major release)
* specify where the template should be inserted. Defaults to `false`. * specify what the template should replace. Defaults to `false`.
* *
* * `true` - the template will replace the current element. * * `true` - the template will replace the directive's element.
* * `false` - the template will replace the contents of the current element. * * `false` - the template will replace the contents of the directive's element.
* *
* The replacement process migrates all of the attributes / classes from the old element to the new
* one. See the {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
* Directives Guide} for an example.
* *
* #### `transclude` * #### `transclude`
* compile the content of the element and make it available to the directive. * compile the content of the element and make it available to the directive.
...@@ -5333,6 +5376,11 @@ function $TemplateCacheProvider() { ...@@ -5333,6 +5376,11 @@ function $TemplateCacheProvider() {
* * `true` - transclude the content of the directive. * * `true` - transclude the content of the directive.
* * `'element'` - transclude the whole element including any directives defined at lower priority. * * `'element'` - transclude the whole element including any directives defined at lower priority.
* *
* <div class="alert alert-warning">
* **Note:** When testing an element transclude directive you must not place the directive at the root of the
* DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
* Testing Transclusion Directives}.
* </div>
* *
* #### `compile` * #### `compile`
* *
...@@ -5978,7 +6026,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -5978,7 +6026,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
: null; : null;
if (nodeLinkFn && nodeLinkFn.scope) { if (nodeLinkFn && nodeLinkFn.scope) {
safeAddClass(jqLite(nodeList[i]), 'ng-scope'); safeAddClass(attrs.$$element, 'ng-scope');
} }
childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
...@@ -6000,7 +6048,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6000,7 +6048,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return linkFnFound ? compositeLinkFn : null; return linkFnFound ? compositeLinkFn : null;
function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) { function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
var nodeLinkFn, childLinkFn, node, $node, childScope, i, ii, n, childBoundTranscludeFn; var nodeLinkFn, childLinkFn, node, childScope, i, ii, n, childBoundTranscludeFn;
// copy nodeList so that linking doesn't break due to live list updates. // copy nodeList so that linking doesn't break due to live list updates.
var nodeListLength = nodeList.length, var nodeListLength = nodeList.length,
...@@ -6013,12 +6061,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6013,12 +6061,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
node = stableNodeList[n]; node = stableNodeList[n];
nodeLinkFn = linkFns[i++]; nodeLinkFn = linkFns[i++];
childLinkFn = linkFns[i++]; childLinkFn = linkFns[i++];
$node = jqLite(node);
if (nodeLinkFn) { if (nodeLinkFn) {
if (nodeLinkFn.scope) { if (nodeLinkFn.scope) {
childScope = scope.$new(); childScope = scope.$new();
$node.data('$scope', childScope); jqLite.data(node, '$scope', childScope);
} else { } else {
childScope = scope; childScope = scope;
} }
...@@ -6310,12 +6357,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6310,12 +6357,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (directiveValue == 'element') { if (directiveValue == 'element') {
hasElementTranscludeDirective = true; hasElementTranscludeDirective = true;
terminalPriority = directive.priority; terminalPriority = directive.priority;
$template = groupScan(compileNode, attrStart, attrEnd); $template = $compileNode;
$compileNode = templateAttrs.$$element = $compileNode = templateAttrs.$$element =
jqLite(document.createComment(' ' + directiveName + ': ' + jqLite(document.createComment(' ' + directiveName + ': ' +
templateAttrs[directiveName] + ' ')); templateAttrs[directiveName] + ' '));
compileNode = $compileNode[0]; compileNode = $compileNode[0];
replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode); replaceWith(jqCollection, sliceArgs($template), compileNode);
childTranscludeFn = compile($template, transcludeFn, terminalPriority, childTranscludeFn = compile($template, transcludeFn, terminalPriority,
replaceDirective && replaceDirective.name, { replaceDirective && replaceDirective.name, {
...@@ -6492,29 +6539,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6492,29 +6539,26 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn; var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
if (compileNode === linkNode) { attrs = (compileNode === linkNode)
attrs = templateAttrs; ? templateAttrs
} else { : shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
}
$element = attrs.$$element; $element = attrs.$$element;
if (newIsolateScopeDirective) { if (newIsolateScopeDirective) {
var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/; var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
var $linkNode = jqLite(linkNode);
isolateScope = scope.$new(true); isolateScope = scope.$new(true);
if (templateDirective && (templateDirective === newIsolateScopeDirective || if (templateDirective && (templateDirective === newIsolateScopeDirective ||
templateDirective === newIsolateScopeDirective.$$originalDirective)) { templateDirective === newIsolateScopeDirective.$$originalDirective)) {
$linkNode.data('$isolateScope', isolateScope) ; $element.data('$isolateScope', isolateScope);
} else { } else {
$linkNode.data('$isolateScopeNoTemplate', isolateScope); $element.data('$isolateScopeNoTemplate', isolateScope);
} }
safeAddClass($linkNode, 'ng-isolate-scope'); safeAddClass($element, 'ng-isolate-scope');
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) { forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
var match = definition.match(LOCAL_REGEXP) || [], var match = definition.match(LOCAL_REGEXP) || [],
...@@ -6548,7 +6592,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { ...@@ -6548,7 +6592,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (parentGet.literal) { if (parentGet.literal) {
compare = equals; compare = equals;
} else { } else {
compare = function(a,b) { return a === b; }; compare = function(a,b) { return a === b || (a !== a && b !== b); };
} }
parentSet = parentGet.assign || function() { parentSet = parentGet.assign || function() {
// reset the change, or we will throw this exception on every $digest // reset the change, or we will throw this exception on every $digest
...@@ -7318,11 +7362,7 @@ function parseHeaders(headers) { ...@@ -7318,11 +7362,7 @@ function parseHeaders(headers) {
val = trim(line.substr(i + 1)); val = trim(line.substr(i + 1));
if (key) { if (key) {
if (parsed[key]) { parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
parsed[key] += ', ' + val;
} else {
parsed[key] = val;
}
} }
}); });
...@@ -7580,6 +7620,7 @@ function $HttpProvider() { ...@@ -7580,6 +7620,7 @@ function $HttpProvider() {
* - {@link ng.$http#put $http.put} * - {@link ng.$http#put $http.put}
* - {@link ng.$http#delete $http.delete} * - {@link ng.$http#delete $http.delete}
* - {@link ng.$http#jsonp $http.jsonp} * - {@link ng.$http#jsonp $http.jsonp}
* - {@link ng.$http#patch $http.patch}
* *
* *
* # Setting HTTP Headers * # Setting HTTP Headers
...@@ -7881,7 +7922,7 @@ function $HttpProvider() { ...@@ -7881,7 +7922,7 @@ function $HttpProvider() {
* - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
* that should abort the request when resolved. * that should abort the request when resolved.
* - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the * - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
* XHR object. See [requests with credentials]https://developer.mozilla.org/en/http_access_control#section_5 * XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
* for more information. * for more information.
* - **responseType** - `{string}` - see * - **responseType** - `{string}` - see
* [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType). * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
...@@ -8159,7 +8200,7 @@ function $HttpProvider() { ...@@ -8159,7 +8200,7 @@ function $HttpProvider() {
* Shortcut method to perform `JSONP` request. * Shortcut method to perform `JSONP` request.
* *
* @param {string} url Relative or absolute URL specifying the destination of the request. * @param {string} url Relative or absolute URL specifying the destination of the request.
* Should contain `JSON_CALLBACK` string. * The name of the callback should be the string `JSON_CALLBACK`.
* @param {Object=} config Optional configuration object * @param {Object=} config Optional configuration object
* @returns {HttpPromise} Future object * @returns {HttpPromise} Future object
*/ */
...@@ -8250,7 +8291,8 @@ function $HttpProvider() { ...@@ -8250,7 +8291,8 @@ function $HttpProvider() {
promise.then(removePendingReq, removePendingReq); promise.then(removePendingReq, removePendingReq);
if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') { if ((config.cache || defaults.cache) && config.cache !== false &&
(config.method === 'GET' || config.method === 'JSONP')) {
cache = isObject(config.cache) ? config.cache cache = isObject(config.cache) ? config.cache
: isObject(defaults.cache) ? defaults.cache : isObject(defaults.cache) ? defaults.cache
: defaultCache; : defaultCache;
...@@ -8259,7 +8301,7 @@ function $HttpProvider() { ...@@ -8259,7 +8301,7 @@ function $HttpProvider() {
if (cache) { if (cache) {
cachedResp = cache.get(url); cachedResp = cache.get(url);
if (isDefined(cachedResp)) { if (isDefined(cachedResp)) {
if (cachedResp.then) { 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(removePendingReq, removePendingReq);
return cachedResp; return cachedResp;
...@@ -8341,27 +8383,29 @@ function $HttpProvider() { ...@@ -8341,27 +8383,29 @@ function $HttpProvider() {
function buildUrl(url, params) { function buildUrl(url, params) {
if (!params) return url; if (!params) return url;
var parts = []; var parts = [];
forEachSorted(params, function(value, key) { forEachSorted(params, function(value, key) {
if (value === null || isUndefined(value)) return; if (value === null || isUndefined(value)) return;
if (!isArray(value)) value = [value]; if (!isArray(value)) value = [value];
forEach(value, function(v) { forEach(value, function(v) {
if (isObject(v)) { if (isObject(v)) {
v = toJson(v); if (isDate(v)){
} v = v.toISOString();
parts.push(encodeUriQuery(key) + '=' + } else if (isObject(v)) {
encodeUriQuery(v)); v = toJson(v);
}); }
});
if(parts.length > 0) {
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
} }
return url; parts.push(encodeUriQuery(key) + '=' +
} encodeUriQuery(v));
});
});
if(parts.length > 0) {
url += ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
}
return url;
}
}]; }];
} }
...@@ -8497,7 +8541,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc ...@@ -8497,7 +8541,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
if (timeout > 0) { if (timeout > 0) {
var timeoutId = $browserDefer(timeoutRequest, timeout); var timeoutId = $browserDefer(timeoutRequest, timeout);
} else if (timeout && timeout.then) { } else if (isPromiseLike(timeout)) {
timeout.then(timeoutRequest); timeout.then(timeoutRequest);
} }
...@@ -8910,7 +8954,7 @@ function $IntervalProvider() { ...@@ -8910,7 +8954,7 @@ function $IntervalProvider() {
* // Make sure that the interval nis destroyed too * // Make sure that the interval nis destroyed too
* $scope.stopFight(); * $scope.stopFight();
* }); * });
* }) * }])
* // Register the 'myCurrentTime' directive factory method. * // Register the 'myCurrentTime' directive factory method.
* // We inject $interval and dateFilter service since the factory method is DI. * // We inject $interval and dateFilter service since the factory method is DI.
* .directive('myCurrentTime', ['$interval', 'dateFilter', * .directive('myCurrentTime', ['$interval', 'dateFilter',
...@@ -8939,7 +8983,7 @@ function $IntervalProvider() { ...@@ -8939,7 +8983,7 @@ function $IntervalProvider() {
* $interval.cancel(stopTime); * $interval.cancel(stopTime);
* }); * });
* } * }
* }); * }]);
* </script> * </script>
* *
* <div> * <div>
...@@ -9720,6 +9764,8 @@ function $LocationProvider(){ ...@@ -9720,6 +9764,8 @@ function $LocationProvider(){
$location = new LocationMode(appBase, '#' + hashPrefix); $location = new LocationMode(appBase, '#' + hashPrefix);
$location.$$parse($location.$$rewrite(initialUrl)); $location.$$parse($location.$$rewrite(initialUrl));
var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
$rootElement.on('click', function(event) { $rootElement.on('click', function(event) {
// TODO(vojta): rewrite link when opening in new tab/window (in legacy browser) // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
// currently we open nice url link and redirect then // currently we open nice url link and redirect then
...@@ -9742,6 +9788,9 @@ function $LocationProvider(){ ...@@ -9742,6 +9788,9 @@ function $LocationProvider(){
absHref = urlResolve(absHref.animVal).href; absHref = urlResolve(absHref.animVal).href;
} }
// Ignore when url is started with javascript: or mailto:
if (IGNORE_URI_REGEXP.test(absHref)) return;
// Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9) // Make relative links work in HTML5 mode for legacy browsers (or at least IE8 & 9)
// The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or // The href should be a regular url e.g. /link/somewhere or link/somewhere or ../somewhere or
// somewhere#anchor or http://example.com/somewhere // somewhere#anchor or http://example.com/somewhere
...@@ -10368,11 +10417,7 @@ Lexer.prototype = { ...@@ -10368,11 +10417,7 @@ Lexer.prototype = {
string += String.fromCharCode(parseInt(hex, 16)); string += String.fromCharCode(parseInt(hex, 16));
} else { } else {
var rep = ESCAPE[ch]; var rep = ESCAPE[ch];
if (rep) { string = string + (rep || ch);
string += rep;
} else {
string += ch;
}
} }
escape = false; escape = false;
} else if (ch === '\\') { } else if (ch === '\\') {
...@@ -10617,9 +10662,9 @@ Parser.prototype = { ...@@ -10617,9 +10662,9 @@ Parser.prototype = {
var middle; var middle;
var token; var token;
if ((token = this.expect('?'))) { if ((token = this.expect('?'))) {
middle = this.ternary(); middle = this.assignment();
if ((token = this.expect(':'))) { if ((token = this.expect(':'))) {
return this.ternaryFn(left, middle, this.ternary()); return this.ternaryFn(left, middle, this.assignment());
} else { } else {
this.throwError('expected :', token); this.throwError('expected :', token);
} }
...@@ -10707,7 +10752,9 @@ Parser.prototype = { ...@@ -10707,7 +10752,9 @@ Parser.prototype = {
return getter(self || object(scope, locals)); return getter(self || object(scope, locals));
}, { }, {
assign: function(scope, value, locals) { assign: function(scope, value, locals) {
return setter(object(scope, locals), field, value, parser.text, parser.options); var o = object(scope, locals);
if (!o) object.assign(scope, o = {});
return setter(o, field, value, parser.text, parser.options);
} }
}); });
}, },
...@@ -10737,10 +10784,11 @@ Parser.prototype = { ...@@ -10737,10 +10784,11 @@ Parser.prototype = {
return v; return v;
}, { }, {
assign: function(self, value, locals) { assign: function(self, value, locals) {
var key = indexFn(self, locals); var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
// prevent overwriting of Function.constructor which would break ensureSafeObject check // prevent overwriting of Function.constructor which would break ensureSafeObject check
var safe = ensureSafeObject(obj(self, locals), parser.text); var o = ensureSafeObject(obj(self, locals), parser.text);
return safe[key] = value; if (!o) obj.assign(self, o = {});
return o[key] = value;
} }
}); });
}, },
...@@ -11551,7 +11599,7 @@ function qFactory(nextTick, exceptionHandler) { ...@@ -11551,7 +11599,7 @@ function qFactory(nextTick, exceptionHandler) {
} catch(e) { } catch(e) {
return makePromise(e, false); return makePromise(e, false);
} }
if (callbackOutput && isFunction(callbackOutput.then)) { if (isPromiseLike(callbackOutput)) {
return callbackOutput.then(function() { return callbackOutput.then(function() {
return makePromise(value, isResolved); return makePromise(value, isResolved);
}, function(error) { }, function(error) {
...@@ -11576,7 +11624,7 @@ function qFactory(nextTick, exceptionHandler) { ...@@ -11576,7 +11624,7 @@ function qFactory(nextTick, exceptionHandler) {
var ref = function(value) { var ref = function(value) {
if (value && isFunction(value.then)) return value; if (isPromiseLike(value)) return value;
return { return {
then: function(callback) { then: function(callback) {
var result = defer(); var result = defer();
...@@ -12243,7 +12291,7 @@ function $RootScopeProvider(){ ...@@ -12243,7 +12291,7 @@ function $RootScopeProvider(){
function $watchCollectionWatch() { function $watchCollectionWatch() {
newValue = objGetter(self); newValue = objGetter(self);
var newLength, key; var newLength, key, bothNaN;
if (!isObject(newValue)) { // if primitive if (!isObject(newValue)) { // if primitive
if (oldValue !== newValue) { if (oldValue !== newValue) {
...@@ -12267,7 +12315,7 @@ function $RootScopeProvider(){ ...@@ -12267,7 +12315,7 @@ function $RootScopeProvider(){
} }
// copy the items to oldValue and look for changes. // copy the items to oldValue and look for changes.
for (var i = 0; i < newLength; i++) { for (var i = 0; i < newLength; i++) {
var bothNaN = (oldValue[i] !== oldValue[i]) && bothNaN = (oldValue[i] !== oldValue[i]) &&
(newValue[i] !== newValue[i]); (newValue[i] !== newValue[i]);
if (!bothNaN && (oldValue[i] !== newValue[i])) { if (!bothNaN && (oldValue[i] !== newValue[i])) {
changeDetected++; changeDetected++;
...@@ -12287,7 +12335,9 @@ function $RootScopeProvider(){ ...@@ -12287,7 +12335,9 @@ function $RootScopeProvider(){
if (newValue.hasOwnProperty(key)) { if (newValue.hasOwnProperty(key)) {
newLength++; newLength++;
if (oldValue.hasOwnProperty(key)) { if (oldValue.hasOwnProperty(key)) {
if (oldValue[key] !== newValue[key]) { bothNaN = (oldValue[key] !== oldValue[key]) &&
(newValue[key] !== newValue[key]);
if (!bothNaN && (oldValue[key] !== newValue[key])) {
changeDetected++; changeDetected++;
oldValue[key] = newValue[key]; oldValue[key] = newValue[key];
} }
...@@ -14400,6 +14450,17 @@ function $WindowProvider(){ ...@@ -14400,6 +14450,17 @@ function $WindowProvider(){
this.$get = valueFn(window); this.$get = valueFn(window);
} }
/* global currencyFilter: true,
dateFilter: true,
filterFilter: true,
jsonFilter: true,
limitToFilter: true,
lowercaseFilter: true,
numberFilter: true,
orderByFilter: true,
uppercaseFilter: true,
*/
/** /**
* @ngdoc provider * @ngdoc provider
* @name $filterProvider * @name $filterProvider
...@@ -15093,7 +15154,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+ ...@@ -15093,7 +15154,7 @@ var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+
* (e.g. `"h 'o''clock'"`). * (e.g. `"h 'o''clock'"`).
* *
* @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
* number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
* shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
* specified in the string input, the time is considered to be in the local timezone. * specified in the string input, the time is considered to be in the local timezone.
* @param {string=} format Formatting rules (see Description). If not specified, * @param {string=} format Formatting rules (see Description). If not specified,
...@@ -15161,11 +15222,7 @@ function dateFilter($locale) { ...@@ -15161,11 +15222,7 @@ function dateFilter($locale) {
format = format || 'mediumDate'; format = format || 'mediumDate';
format = $locale.DATETIME_FORMATS[format] || format; format = $locale.DATETIME_FORMATS[format] || format;
if (isString(date)) { if (isString(date)) {
if (NUMBER_STRING.test(date)) { date = NUMBER_STRING.test(date) ? int(date) : jsonStringToDate(date);
date = int(date);
} else {
date = jsonStringToDate(date);
}
} }
if (isNumber(date)) { if (isNumber(date)) {
...@@ -15440,7 +15497,7 @@ function limitToFilter(){ ...@@ -15440,7 +15497,7 @@ function limitToFilter(){
* @example * @example
<example module="orderByExample"> <example module="orderByExample">
<file name="index.html"> <file name="index.html">
<div ng-controller="Ctrl"> <div ng-controller="ExampleController">
<table class="friend"> <table class="friend">
<tr> <tr>
<th><a href="" ng-click="reverse=false;order('name', false)">Name</a> <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
...@@ -15521,6 +15578,10 @@ function orderByFilter($parse){ ...@@ -15521,6 +15578,10 @@ function orderByFilter($parse){
var t1 = typeof v1; var t1 = typeof v1;
var t2 = typeof v2; var t2 = typeof v2;
if (t1 == t2) { if (t1 == t2) {
if (isDate(v1) && isDate(v2)) {
v1 = v1.valueOf();
v2 = v2.valueOf();
}
if (t1 == "string") { if (t1 == "string") {
v1 = v1.toLowerCase(); v1 = v1.toLowerCase();
v2 = v2.toLowerCase(); v2 = v2.toLowerCase();
...@@ -16414,12 +16475,10 @@ var formDirectiveFactory = function(isNgForm) { ...@@ -16414,12 +16475,10 @@ var formDirectiveFactory = function(isNgForm) {
var formDirective = formDirectiveFactory(); var formDirective = formDirectiveFactory();
var ngFormDirective = formDirectiveFactory(true); var ngFormDirective = formDirectiveFactory(true);
/* global /* global VALID_CLASS: true,
INVALID_CLASS: true,
-VALID_CLASS, PRISTINE_CLASS: true,
-INVALID_CLASS, DIRTY_CLASS: true
-PRISTINE_CLASS,
-DIRTY_CLASS
*/ */
var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
...@@ -18064,7 +18123,7 @@ var ngValueDirective = function() { ...@@ -18064,7 +18123,7 @@ var ngValueDirective = function() {
* Typically, you don't use `ngBind` directly, but instead you use the double curly markup like * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
* `{{ expression }}` which is similar but less verbose. * `{{ expression }}` which is similar but less verbose.
* *
* It is preferable to use `ngBind` instead of `{{ expression }}` when a template is momentarily * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
* displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
* element attribute, it makes the bindings invisible to the user while the page is loading. * element attribute, it makes the bindings invisible to the user while the page is loading.
* *
...@@ -18228,15 +18287,24 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) { ...@@ -18228,15 +18287,24 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
</example> </example>
*/ */
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
return function(scope, element, attr) { return {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml); compile: function (tElement) {
tElement.addClass('ng-binding');
var parsed = $parse(attr.ngBindHtml); return function (scope, element, attr) {
function getStringValue() { return (parsed(scope) || '').toString(); } element.data('$binding', attr.ngBindHtml);
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) { var parsed = $parse(attr.ngBindHtml);
element.html($sce.getTrustedHtml(parsed(scope)) || '');
}); function getStringValue() {
return (parsed(scope) || '').toString();
}
scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
element.html($sce.getTrustedHtml(parsed(scope)) || '');
});
};
}
}; };
}]; }];
...@@ -18899,8 +18967,10 @@ var ngControllerDirective = [function() { ...@@ -18899,8 +18967,10 @@ var ngControllerDirective = [function() {
* This is necessary when developing things like Google Chrome Extensions. * This is necessary when developing things like Google Chrome Extensions.
* *
* CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things). * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
* For us to be compatible, we just need to implement the "getterFn" in $parse without violating * For Angular to be CSP compatible there are only two things that we need to do differently:
* any of these restrictions. *
* - don't use `Function` constructor to generate optimized value getters
* - don't inject custom stylesheet into the document
* *
* AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp` * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
* directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
...@@ -18911,7 +18981,18 @@ var ngControllerDirective = [function() { ...@@ -18911,7 +18981,18 @@ var ngControllerDirective = [function() {
* includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}). * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
* To make those directives work in CSP mode, include the `angular-csp.css` manually. * To make those directives work in CSP mode, include the `angular-csp.css` manually.
* *
* In order to use this feature put the `ngCsp` directive on the root element of the application. * Angular tries to autodetect if CSP is active and automatically turn on the CSP-safe mode. This
* autodetection however triggers a CSP error to be logged in the console:
*
* ```
* Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
* script in the following Content Security Policy directive: "default-src 'self'". Note that
* 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
* ```
*
* This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
* directive on the root element of the application or on the `angular.js` script tag, whichever
* appears first in the html document.
* *
* *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.* * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
* *
...@@ -18926,9 +19007,9 @@ var ngControllerDirective = [function() { ...@@ -18926,9 +19007,9 @@ var ngControllerDirective = [function() {
``` ```
*/ */
// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute // bootstrap the system (before $parse is instantiated), for this reason we just have
// anywhere in the current doc // the csp.isActive() fn that looks for ng-csp attribute anywhere in the current doc
/** /**
* @ngdoc directive * @ngdoc directive
...@@ -19237,6 +19318,13 @@ forEach( ...@@ -19237,6 +19318,13 @@ forEach(
* server and reloading the current page), but only if the form does not contain `action`, * server and reloading the current page), but only if the form does not contain `action`,
* `data-action`, or `x-action` attributes. * `data-action`, or `x-action` attributes.
* *
* <div class="alert alert-warning">
* **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
* `ngSubmit` handlers together. See the
* {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
* for a detailed discussion of when `ngSubmit` may be triggered.
* </div>
*
* @element form * @element form
* @priority 0 * @priority 0
* @param {expression} ngSubmit {@link guide/expression Expression} to eval. * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
...@@ -21554,21 +21642,37 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -21554,21 +21642,37 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
value = valueFn(scope, locals); value = valueFn(scope, locals);
} }
} }
// Update the null option's selected property here so $render cleans it up correctly
if (optionGroupsCache[0].length > 1) {
if (optionGroupsCache[0][1].id !== key) {
optionGroupsCache[0][1].selected = false;
}
}
} }
ctrl.$setViewValue(value); ctrl.$setViewValue(value);
render();
}); });
}); });
ctrl.$render = render; ctrl.$render = render;
// TODO(vojta): can't we optimize this ? scope.$watchCollection(valuesFn, render);
scope.$watch(render); if ( multiple ) {
scope.$watchCollection(function() { return ctrl.$modelValue; }, render);
}
function getSelectedSet() {
var selectedSet = false;
if (multiple) {
var modelValue = ctrl.$modelValue;
if (trackFn && isArray(modelValue)) {
selectedSet = new HashMap([]);
var locals = {};
for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
locals[valueName] = modelValue[trackIndex];
selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
}
} else {
selectedSet = new HashMap(modelValue);
}
}
return selectedSet;
}
function render() { function render() {
// Temporary location for the option groups before we render them // Temporary location for the option groups before we render them
...@@ -21586,22 +21690,11 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -21586,22 +21690,11 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
groupIndex, index, groupIndex, index,
locals = {}, locals = {},
selected, selected,
selectedSet = false, // nothing is selected yet selectedSet = getSelectedSet(),
lastElement, lastElement,
element, element,
label; label;
if (multiple) {
if (trackFn && isArray(modelValue)) {
selectedSet = new HashMap([]);
for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
locals[valueName] = modelValue[trackIndex];
selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
}
} else {
selectedSet = new HashMap(modelValue);
}
}
// We now build up the list of options we need (we merge later) // We now build up the list of options we need (we merge later)
for (index = 0; length = keys.length, index < length; index++) { for (index = 0; length = keys.length, index < length; index++) {
...@@ -21697,8 +21790,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -21697,8 +21790,14 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
lastElement.val(existingOption.id = option.id); lastElement.val(existingOption.id = option.id);
} }
// lastElement.prop('selected') provided by jQuery has side-effects // lastElement.prop('selected') provided by jQuery has side-effects
if (existingOption.selected !== option.selected) { if (lastElement[0].selected !== option.selected) {
lastElement.prop('selected', (existingOption.selected = option.selected)); lastElement.prop('selected', (existingOption.selected = option.selected));
if (msie) {
// See #7692
// The selected item wouldn't visually update on IE without this.
// Tested on Win7: IE9, IE10 and IE11. Future IEs should be tested as well
lastElement.prop('selected', existingOption.selected);
}
} }
} else { } else {
// grow elements // grow elements
...@@ -21714,6 +21813,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) { ...@@ -21714,6 +21813,7 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
(element = optionTemplate.clone()) (element = optionTemplate.clone())
.val(option.id) .val(option.id)
.prop('selected', option.selected) .prop('selected', option.selected)
.attr('selected', option.selected)
.text(option.label); .text(option.label);
} }
......
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