diff options
author | Bernhard Posselt <dev@bernhard-posselt.com> | 2015-02-17 15:25:18 +0100 |
---|---|---|
committer | Bernhard Posselt <dev@bernhard-posselt.com> | 2015-02-17 15:25:18 +0100 |
commit | 17b7189e78edf701564dc677d6bab4b6c198eeda (patch) | |
tree | fa11d15f29f9df479d849e445faef00eb096dedc /js/vendor/angular | |
parent | 816a8beb0b77164aa60a7fe23b4b3d0881985be3 (diff) |
update angular and es6 shim
Diffstat (limited to 'js/vendor/angular')
-rw-r--r-- | js/vendor/angular/.bower.json | 8 | ||||
-rw-r--r-- | js/vendor/angular/angular.js | 2597 | ||||
-rw-r--r-- | js/vendor/angular/angular.min.js | 524 | ||||
-rw-r--r-- | js/vendor/angular/angular.min.js.gzip | bin | 45987 -> 49971 bytes | |||
-rw-r--r-- | js/vendor/angular/angular.min.js.map | 6 | ||||
-rw-r--r-- | js/vendor/angular/bower.json | 2 | ||||
-rw-r--r-- | js/vendor/angular/package.json | 2 |
7 files changed, 2027 insertions, 1112 deletions
diff --git a/js/vendor/angular/.bower.json b/js/vendor/angular/.bower.json index 407b30d01..d307464a4 100644 --- a/js/vendor/angular/.bower.json +++ b/js/vendor/angular/.bower.json @@ -1,15 +1,15 @@ { "name": "angular", - "version": "1.4.0-build.3807+sha.b3a9bd3", + "version": "1.4.0-build.3834+sha.75725b4", "main": "./angular.js", "ignore": [], "dependencies": {}, "homepage": "https://github.com/angular/bower-angular", - "_release": "1.4.0-build.3807+sha.b3a9bd3", + "_release": "1.4.0-build.3834+sha.75725b4", "_resolution": { "type": "version", - "tag": "v1.4.0-build.3807+sha.b3a9bd3", - "commit": "b370d20fe49db09a8e3e0c9596fbe6d27b2d00de" + "tag": "v1.4.0-build.3834+sha.75725b4", + "commit": "32125266f5b2a854e063e0db039e5d5864f404f0" }, "_source": "git://github.com/angular/bower-angular.git", "_target": "~1.4.*", diff --git a/js/vendor/angular/angular.js b/js/vendor/angular/angular.js index 67d9d67e5..66b6ed435 100644 --- a/js/vendor/angular/angular.js +++ b/js/vendor/angular/angular.js @@ -1,5 +1,5 @@ /** - * @license AngularJS v1.4.0-build.3807+sha.b3a9bd3 + * @license AngularJS v1.4.0-build.3834+sha.75725b4 * (c) 2010-2015 Google, Inc. http://angularjs.org * License: MIT */ @@ -57,7 +57,7 @@ function minErr(module, ErrorConstructor) { return match; }); - message += '\nhttp://errors.angularjs.org/1.4.0-build.3807+sha.b3a9bd3/' + + message += '\nhttp://errors.angularjs.org/1.4.0-build.3834+sha.75725b4/' + (module ? module + '/' : '') + code; for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') { @@ -127,6 +127,7 @@ function minErr(module, ErrorConstructor) { shallowCopy: true, equals: true, csp: true, + jq: true, concat: true, sliceArgs: true, bind: true, @@ -331,7 +332,7 @@ function forEach(obj, iterator, context) { obj.forEach(iterator, context, obj); } else { for (key in obj) { - if (hasOwnProperty.call(obj, key)) { + if (obj.hasOwnProperty(key)) { iterator.call(context, obj[key], key, obj); } } @@ -381,8 +382,7 @@ function nextUid() { function setHashKey(obj, h) { if (h) { obj.$$hashKey = h; - } - else { + } else { delete obj.$$hashKey; } } @@ -653,6 +653,12 @@ function isPromiseLike(obj) { } +var TYPED_ARRAY_REGEXP = /^\[object (Uint8(Clamped)?)|(Uint16)|(Uint32)|(Int8)|(Int16)|(Int32)|(Float(32)|(64))Array\]$/; +function isTypedArray(value) { + return TYPED_ARRAY_REGEXP.test(toString.call(value)); +} + + var trim = function(value) { return isString(value) ? value.trim() : value; }; @@ -690,8 +696,9 @@ function isElement(node) { */ function makeMap(str) { var obj = {}, items = str.split(","), i; - for (i = 0; i < items.length; i++) - obj[ items[i] ] = true; + for (i = 0; i < items.length; i++) { + obj[items[i]] = true; + } return obj; } @@ -706,9 +713,10 @@ function includes(array, obj) { function arrayRemove(array, value) { var index = array.indexOf(value); - if (index >= 0) + if (index >= 0) { array.splice(index, 1); - return value; + } + return index; } /** @@ -774,12 +782,18 @@ function copy(source, destination, stackSource, stackDest) { throw ngMinErr('cpws', "Can't copy! Making copies of Window or Scope instances is not supported."); } + if (isTypedArray(destination)) { + throw ngMinErr('cpta', + "Can't copy! TypedArray destination cannot be mutated."); + } if (!destination) { destination = source; if (source) { if (isArray(source)) { destination = copy(source, [], stackSource, stackDest); + } else if (isTypedArray(source)) { + destination = new source.constructor(source); } else if (isDate(source)) { destination = new Date(source.getTime()); } else if (isRegExp(source)) { @@ -957,7 +971,61 @@ var csp = function() { return (csp.isActive_ = active); }; +/** + * @ngdoc directive + * @module ng + * @name ngJq + * + * @element ANY + * @param {string=} the name of the library available under `window` + * to be used for angular.element + * @description + * Use this directive to force the angular.element library. This should be + * used to force either jqLite by leaving ng-jq blank or setting the name of + * the jquery variable under window (eg. jQuery). + * + * Since this directive is global for the angular library, it is recommended + * that it's added to the same element as ng-app or the HTML element, but it is not mandatory. + * It needs to be noted that only the first instance of `ng-jq` will be used and all others + * ignored. + * + * @example + * This example shows how to force jqLite using the `ngJq` directive to the `html` tag. + ```html + <!doctype html> + <html ng-app ng-jq> + ... + ... + </html> + ``` + * @example + * This example shows how to use a jQuery based library of a different name. + * The library name must be available at the top most 'window'. + ```html + <!doctype html> + <html ng-app ng-jq="jQueryLib"> + ... + ... + </html> + ``` + */ +var jq = function() { + if (isDefined(jq.name_)) return jq.name_; + var el; + var i, ii = ngAttrPrefixes.length; + for (i = 0; i < ii; ++i) { + if (el = document.querySelector('[' + ngAttrPrefixes[i].replace(':', '\\:') + 'jq]')) { + break; + } + } + + var name; + if (el) { + name = getNgAttribute(el, "jq"); + } + return (jq.name_ = name); +}; function concat(array1, array2, index) { return array1.concat(slice.call(array2, index)); @@ -1472,8 +1540,12 @@ function bootstrap(element, modules, config) { forEach(extraModules, function(module) { modules.push(module); }); - doBootstrap(); + return doBootstrap(); }; + + if (isFunction(angular.resumeDeferredBootstrap)) { + angular.resumeDeferredBootstrap(); + } } /** @@ -1526,7 +1598,12 @@ function bindJQuery() { } // bind to jQuery if present; - jQuery = window.jQuery; + var jqName = jq(); + jQuery = window.jQuery; // use default jQuery. + if (isDefined(jqName)) { // `ngJq` present + jQuery = jqName === null ? undefined : window[jqName]; // if empty; use jqLite. if not empty, use jQuery specified by `ngJq`. + } + // Use jQuery if it exists with proper functionality, otherwise default to us. // Angular 1.2+ requires jQuery 1.7+ for on()/off() support. // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older @@ -2118,7 +2195,7 @@ function toDebugString(obj) { * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat". */ var version = { - full: '1.4.0-build.3807+sha.b3a9bd3', // all of these placeholder strings will be replaced by grunt's + full: '1.4.0-build.3834+sha.75725b4', // all of these placeholder strings will be replaced by grunt's major: 1, // package task minor: 4, dot: 0, @@ -3110,8 +3187,9 @@ forEach({ children: function(element) { var children = []; forEach(element.childNodes, function(element) { - if (element.nodeType === NODE_TYPE_ELEMENT) + if (element.nodeType === NODE_TYPE_ELEMENT) { children.push(element); + } }); return children; }, @@ -4157,7 +4235,7 @@ function createInjector(modulesToLoad, strictDi) { } var args = [], - $inject = annotate(fn, strictDi, serviceName), + $inject = createInjector.$$annotate(fn, strictDi, serviceName), length, i, key; @@ -4196,7 +4274,7 @@ function createInjector(modulesToLoad, strictDi) { invoke: invoke, instantiate: instantiate, get: getService, - annotate: annotate, + annotate: createInjector.$$annotate, has: function(name) { return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); } @@ -5779,7 +5857,7 @@ function $TemplateCacheProvider() { * templateNamespace: 'html', * scope: false, * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... }, - * controllerAs: 'stringAlias', + * controllerAs: 'stringIdentifier', * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'], * compile: function compile(tElement, tAttrs, transclude) { * return { @@ -5939,9 +6017,10 @@ function $TemplateCacheProvider() { * * * #### `controllerAs` - * Controller alias at the directive scope. An alias for the controller so it - * can be referenced at the directive template. The directive needs to define a scope for this - * configuration to be used. Useful in the case when directive is used as component. + * Identifier name for a reference to the controller in the directive's scope. + * This allows the controller to be referenced from the directive template. The directive + * needs to define a scope for this configuration to be used. Useful in the case when + * directive is used as component. * * * #### `restrict` @@ -6427,7 +6506,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { // 'on' and be composed of only English letters. var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/; - function parseIsolateBindings(scope, directiveName) { + function parseIsolateBindings(scope, directiveName, isController) { var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/; var bindings = {}; @@ -6437,9 +6516,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (!match) { throw $compileMinErr('iscp', - "Invalid isolate scope definition for directive '{0}'." + + "Invalid {3} for directive '{0}'." + " Definition: {... {1}: '{2}' ...}", - directiveName, scopeName, definition); + directiveName, scopeName, definition, + (isController ? "controller bindings definition" : + "isolate scope definition")); } bindings[scopeName] = { @@ -6453,6 +6534,43 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { return bindings; } + function parseDirectiveBindings(directive, directiveName) { + var bindings = { + isolateScope: null, + bindToController: null + }; + if (isObject(directive.scope)) { + if (directive.bindToController === true) { + bindings.bindToController = parseIsolateBindings(directive.scope, + directiveName, true); + bindings.isolateScope = {}; + } else { + bindings.isolateScope = parseIsolateBindings(directive.scope, + directiveName, false); + } + } + if (isObject(directive.bindToController)) { + bindings.bindToController = + parseIsolateBindings(directive.bindToController, directiveName, true); + } + if (isObject(bindings.bindToController)) { + var controller = directive.controller; + var controllerAs = directive.controllerAs; + if (!controller) { + // There is no controller, there may or may not be a controllerAs property + throw $compileMinErr('noctrl', + "Cannot bind to controller without directive '{0}'s controller.", + directiveName); + } else if (!identifierForController(controller, controllerAs)) { + // There is a controller, but no identifier or controllerAs property + throw $compileMinErr('noident', + "Cannot bind to controller without identifier for directive '{0}'.", + directiveName); + } + } + return bindings; + } + /** * @ngdoc method * @name $compileProvider#directive @@ -6490,8 +6608,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { directive.name = directive.name || name; directive.require = directive.require || (directive.controller && directive.name); directive.restrict = directive.restrict || 'EA'; - if (isObject(directive.scope)) { - directive.$$isolateBindings = parseIsolateBindings(directive.scope, directive.name); + var bindings = directive.$$bindings = + parseDirectiveBindings(directive, directive.name); + if (isObject(bindings.isolateScope)) { + directive.$$isolateBindings = bindings.isolateScope; } directives.push(directive); } catch (e) { @@ -7053,6 +7173,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (nodeLinkFn.scope) { childScope = scope.$new(); compile.$$addScopeInfo(jqLite(node), childScope); + var destroyBindings = nodeLinkFn.$$destroyBindings; + if (destroyBindings) { + nodeLinkFn.$$destroyBindings = null; + childScope.$on('$destroyed', destroyBindings); + } } else { childScope = scope; } @@ -7072,7 +7197,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { childBoundTranscludeFn = null; } - nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn); + nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn, + nodeLinkFn); } else if (childLinkFn) { childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn); @@ -7281,7 +7407,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { var terminalPriority = -Number.MAX_VALUE, newScopeDirective, controllerDirectives = previousCompileContext.controllerDirectives, - controllers, newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective, templateDirective = previousCompileContext.templateDirective, nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective, @@ -7507,53 +7632,47 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { function getControllers(directiveName, require, $element, elementControllers) { - var value, retrievalMethod = 'data', optional = false; - var $searchElement = $element; - var match; - if (isString(require)) { - match = require.match(REQUIRE_PREFIX_REGEXP); - require = require.substring(match[0].length); + var value; - if (match[3]) { - if (match[1]) match[3] = null; - else match[1] = match[3]; - } - if (match[1] === '^') { - retrievalMethod = 'inheritedData'; - } else if (match[1] === '^^') { - retrievalMethod = 'inheritedData'; - $searchElement = $element.parent(); - } - if (match[2] === '?') { - optional = true; + if (isString(require)) { + var match = require.match(REQUIRE_PREFIX_REGEXP); + var name = require.substring(match[0].length); + var inheritType = match[1] || match[3]; + var optional = match[2] === '?'; + + //If only parents then start at the parent element + if (inheritType === '^^') { + $element = $element.parent(); + //Otherwise attempt getting the controller from elementControllers in case + //the element is transcluded (and has no data) and to avoid .data if possible + } else { + value = elementControllers && elementControllers[name]; + value = value && value.instance; } - value = null; - - if (elementControllers && retrievalMethod === 'data') { - if (value = elementControllers[require]) { - value = value.instance; - } + if (!value) { + var dataName = '$' + name + 'Controller'; + value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName); } - value = value || $searchElement[retrievalMethod]('$' + require + 'Controller'); if (!value && !optional) { throw $compileMinErr('ctreq', "Controller '{0}', required by directive '{1}', can't be found!", - require, directiveName); + name, directiveName); } - return value || null; } else if (isArray(require)) { value = []; - forEach(require, function(require) { - value.push(getControllers(directiveName, require, $element, elementControllers)); - }); + for (var i = 0, ii = require.length; i < ii; i++) { + value[i] = getControllers(directiveName, require[i], $element, elementControllers); + } } - return value; + + return value || null; } - function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) { + function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn, + thisLinkFn) { var i, ii, linkFn, controller, isolateScope, elementControllers, transcludeFn, $element, attrs; @@ -7577,8 +7696,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } if (controllerDirectives) { - // TODO: merge `controllers` and `elementControllers` into single object. - controllers = {}; elementControllers = {}; forEach(controllerDirectives, function(directive) { var locals = { @@ -7604,100 +7721,48 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (!hasElementTranscludeDirective) { $element.data('$' + directive.name + 'Controller', controllerInstance.instance); } - - controllers[directive.name] = controllerInstance; }); } if (newIsolateScopeDirective) { + // Initialize isolate scope bindings for new isolate scope directive. compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective || templateDirective === newIsolateScopeDirective.$$originalDirective))); compile.$$addScopeClass($element, true); - - var isolateScopeController = controllers && controllers[newIsolateScopeDirective.name]; - var isolateBindingContext = isolateScope; - if (isolateScopeController && isolateScopeController.identifier && - newIsolateScopeDirective.bindToController === true) { - isolateBindingContext = isolateScopeController.instance; + isolateScope.$$isolateBindings = + newIsolateScopeDirective.$$isolateBindings; + initializeDirectiveBindings(scope, attrs, isolateScope, + isolateScope.$$isolateBindings, + newIsolateScopeDirective, isolateScope); + } + if (elementControllers) { + // Initialize bindToController bindings for new/isolate scopes + var scopeDirective = newIsolateScopeDirective || newScopeDirective; + var bindings; + var controllerForBindings; + if (scopeDirective && elementControllers[scopeDirective.name]) { + bindings = scopeDirective.$$bindings.bindToController; + controller = elementControllers[scopeDirective.name]; + + if (controller && controller.identifier && bindings) { + controllerForBindings = controller; + thisLinkFn.$$destroyBindings = + initializeDirectiveBindings(scope, attrs, controller.instance, + bindings, scopeDirective); + } } - - forEach(isolateScope.$$isolateBindings = newIsolateScopeDirective.$$isolateBindings, function(definition, scopeName) { - var attrName = definition.attrName, - optional = definition.optional, - mode = definition.mode, // @, =, or & - lastValue, - parentGet, parentSet, compare; - - switch (mode) { - - case '@': - attrs.$observe(attrName, function(value) { - isolateBindingContext[scopeName] = value; - }); - attrs.$$observers[attrName].$$scope = scope; - if (attrs[attrName]) { - // If the attribute has been provided then we trigger an interpolation to ensure - // the value is there for use in the link fn - isolateBindingContext[scopeName] = $interpolate(attrs[attrName])(scope); - } - break; - - case '=': - if (optional && !attrs[attrName]) { - return; - } - parentGet = $parse(attrs[attrName]); - if (parentGet.literal) { - compare = equals; - } else { - compare = function(a, b) { return a === b || (a !== a && b !== b); }; - } - parentSet = parentGet.assign || function() { - // reset the change, or we will throw this exception on every $digest - lastValue = isolateBindingContext[scopeName] = parentGet(scope); - throw $compileMinErr('nonassign', - "Expression '{0}' used with directive '{1}' is non-assignable!", - attrs[attrName], newIsolateScopeDirective.name); - }; - lastValue = isolateBindingContext[scopeName] = parentGet(scope); - var parentValueWatch = function parentValueWatch(parentValue) { - if (!compare(parentValue, isolateBindingContext[scopeName])) { - // we are out of sync and need to copy - if (!compare(parentValue, lastValue)) { - // parent changed and it has precedence - isolateBindingContext[scopeName] = parentValue; - } else { - // if the parent can be assigned then do so - parentSet(scope, parentValue = isolateBindingContext[scopeName]); - } - } - return lastValue = parentValue; - }; - parentValueWatch.$stateful = true; - var unwatch; - if (definition.collection) { - unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch); - } else { - unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal); - } - isolateScope.$on('$destroy', unwatch); - break; - - case '&': - parentGet = $parse(attrs[attrName]); - isolateBindingContext[scopeName] = function(locals) { - return parentGet(scope, locals); - }; - break; + forEach(elementControllers, function(controller) { + var result = controller(); + if (result !== controller.instance && + controller === controllerForBindings) { + // Remove and re-install bindToController bindings + thisLinkFn.$$destroyBindings(); + thisLinkFn.$$destroyBindings = + initializeDirectiveBindings(scope, attrs, result, + bindings, scopeDirective); } }); } - if (controllers) { - forEach(controllers, function(controller) { - controller(); - }); - controllers = null; - } // PRELINKING for (i = 0, ii = preLinkFns.length; i < ii; i++) { @@ -7870,8 +7935,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { afterTemplateChildLinkFn, beforeTemplateCompileNode = $compileNode[0], origAsyncDirective = directives.shift(), - // The fact that we have to copy and patch the directive seems wrong! - derivedSyncDirective = extend({}, origAsyncDirective, { + derivedSyncDirective = inherit(origAsyncDirective, { templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective }), templateUrl = (isFunction(origAsyncDirective.templateUrl)) @@ -7955,7 +8019,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { childBoundTranscludeFn = boundTranscludeFn; } afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement, - childBoundTranscludeFn); + childBoundTranscludeFn, afterTemplateNodeLinkFn); } linkQueue = null; }); @@ -7972,7 +8036,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (afterTemplateNodeLinkFn.transcludeOnThisElement) { childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn); } - afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn); + afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn, + afterTemplateNodeLinkFn); } }; } @@ -8219,6 +8284,102 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { $exceptionHandler(e, startingTag($element)); } } + + + // Set up $watches for isolate scope and controller bindings. This process + // only occurs for isolate scopes and new scopes with controllerAs. + function initializeDirectiveBindings(scope, attrs, destination, bindings, + directive, newScope) { + var onNewScopeDestroyed; + forEach(bindings, function(definition, scopeName) { + var attrName = definition.attrName, + optional = definition.optional, + mode = definition.mode, // @, =, or & + lastValue, + parentGet, parentSet, compare; + + switch (mode) { + + case '@': + attrs.$observe(attrName, function(value) { + destination[scopeName] = value; + }); + attrs.$$observers[attrName].$$scope = scope; + if (attrs[attrName]) { + // If the attribute has been provided then we trigger an interpolation to ensure + // the value is there for use in the link fn + destination[scopeName] = $interpolate(attrs[attrName])(scope); + } + break; + + case '=': + if (optional && !attrs[attrName]) { + return; + } + parentGet = $parse(attrs[attrName]); + if (parentGet.literal) { + compare = equals; + } else { + compare = function(a, b) { return a === b || (a !== a && b !== b); }; + } + parentSet = parentGet.assign || function() { + // reset the change, or we will throw this exception on every $digest + lastValue = destination[scopeName] = parentGet(scope); + throw $compileMinErr('nonassign', + "Expression '{0}' used with directive '{1}' is non-assignable!", + attrs[attrName], directive.name); + }; + lastValue = destination[scopeName] = parentGet(scope); + var parentValueWatch = function parentValueWatch(parentValue) { + if (!compare(parentValue, destination[scopeName])) { + // we are out of sync and need to copy + if (!compare(parentValue, lastValue)) { + // parent changed and it has precedence + destination[scopeName] = parentValue; + } else { + // if the parent can be assigned then do so + parentSet(scope, parentValue = destination[scopeName]); + } + } + return lastValue = parentValue; + }; + parentValueWatch.$stateful = true; + var unwatch; + if (definition.collection) { + unwatch = scope.$watchCollection(attrs[attrName], parentValueWatch); + } else { + unwatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal); + } + onNewScopeDestroyed = (onNewScopeDestroyed || []); + onNewScopeDestroyed.push(unwatch); + break; + + case '&': + // Don't assign Object.prototype method to scope + if (!attrs.hasOwnProperty(attrName) && optional) break; + + parentGet = $parse(attrs[attrName]); + + // Don't assign noop to destination if expression is not valid + if (parentGet === noop && optional) break; + + destination[scopeName] = function(locals) { + return parentGet(scope, locals); + }; + break; + } + }); + var destroyBindings = onNewScopeDestroyed ? function destroyBindings() { + for (var i = 0, ii = onNewScopeDestroyed.length; i < ii; ++i) { + onNewScopeDestroyed[i](); + } + } : noop; + if (newScope && destroyBindings !== noop) { + newScope.$on('$destroy', destroyBindings); + return noop; + } + return destroyBindings; + } }]; } @@ -8324,6 +8485,19 @@ function removeComments(jqNodes) { return jqNodes; } +var $controllerMinErr = minErr('$controller'); + + +var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; +function identifierForController(controller, ident) { + if (ident && isString(ident)) return ident; + if (isString(controller)) { + var match = CNTRL_REG.exec(controller); + if (match) return match[3]; + } +} + + /** * @ngdoc provider * @name $controllerProvider @@ -8336,9 +8510,7 @@ function removeComments(jqNodes) { */ function $ControllerProvider() { var controllers = {}, - globals = false, - CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/; - + globals = false; /** * @ngdoc method @@ -8411,7 +8583,12 @@ function $ControllerProvider() { } if (isString(expression)) { - match = expression.match(CNTRL_REG), + match = expression.match(CNTRL_REG); + if (!match) { + throw $controllerMinErr('ctrlfmt', + "Badly formed controller string '{0}'. " + + "Must match `__name__ as __id__` or `__name__`.", expression); + } constructor = match[1], identifier = identifier || match[3]; expression = con |