vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.0 vs vendor/assets/javascripts/angular-scenario.js in angularjs-rails-1.2.1
- old
+ new
@@ -9788,11 +9788,11 @@
}
})( window );
/**
- * @license AngularJS v1.2.0
+ * @license AngularJS v1.2.1
* (c) 2010-2012 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, document){
var _jQuery = window.jQuery.noConflict(true);
@@ -9830,15 +9830,15 @@
var code = arguments[0],
prefix = '[' + (module ? module + ':' : '') + code + '] ',
template = arguments[1],
templateArgs = arguments,
stringify = function (obj) {
- if (isFunction(obj)) {
+ if (typeof obj === 'function') {
return obj.toString().replace(/ \{[\s\S]*$/, '');
- } else if (isUndefined(obj)) {
+ } else if (typeof obj === 'undefined') {
return 'undefined';
- } else if (!isString(obj)) {
+ } else if (typeof obj !== 'string') {
return JSON.stringify(obj);
}
return obj;
},
message, i;
@@ -9846,23 +9846,23 @@
message = prefix + template.replace(/\{\d+\}/g, function (match) {
var index = +match.slice(1, -1), arg;
if (index + 2 < templateArgs.length) {
arg = templateArgs[index + 2];
- if (isFunction(arg)) {
+ if (typeof arg === 'function') {
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
- } else if (isUndefined(arg)) {
+ } else if (typeof arg === 'undefined') {
return 'undefined';
- } else if (!isString(arg)) {
+ } else if (typeof arg !== 'string') {
return toJson(arg);
}
return arg;
}
return match;
});
- message = message + '\nhttp://errors.angularjs.org/' + version.full + '/' +
+ message = message + '\nhttp://errors.angularjs.org/1.2.1/' +
(module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) {
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
encodeURIComponent(stringify(arguments[i]));
}
@@ -11219,10 +11219,11 @@
*/
function setupModuleLoader(window) {
var $injectorMinErr = minErr('$injector');
+ var ngMinErr = minErr('ng');
function ensure(obj, name, factory) {
return obj[name] || (obj[name] = factory());
}
@@ -11279,10 +11280,16 @@
* @param {Function} configFn Optional configuration function for the module. Same as
* {@link angular.Module#methods_config Module#config()}.
* @returns {module} new module with the {@link angular.Module} api.
*/
return function module(name, requires, configFn) {
+ var assertNotHasOwnProperty = function(name, context) {
+ if (name === 'hasOwnProperty') {
+ throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
+ }
+ };
+
assertNotHasOwnProperty(name, 'module');
if (requires && modules.hasOwnProperty(name)) {
modules[name] = null;
}
return ensure(modules, name, function() {
@@ -11591,15 +11598,15 @@
* - `minor` – `{number}` – Minor version number, such as "9".
* - `dot` – `{number}` – Dot version number, such as "18".
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.2.0', // all of these placeholder strings will be replaced by grunt's
+ full: '1.2.1', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
- minor: "NG_VERSION_MINOR",
- dot: 0,
- codeName: 'timely-delivery'
+ minor: 2,
+ dot: 1,
+ codeName: 'underscore-empathy'
};
function publishExternalAPI(angular){
extend(angular, {
@@ -14486,12 +14493,13 @@
*
* #### `priority`
* When there are multiple directives defined on a single DOM element, sometimes it
* is necessary to specify the order in which the directives are applied. The `priority` is used
* to sort the directives before their `compile` functions get called. Priority is defined as a
- * number. Directives with greater numerical `priority` are compiled first. The order of directives with
- * the same priority is undefined. The default priority is `0`.
+ * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
+ * are also run in priority order, but post-link functions are run in reverse order. The order
+ * of directives with the same priority is undefined. The default priority is `0`.
*
* #### `terminal`
* If set to true then the current `priority` will be the last set of directives
* which will execute (any directives at the current priority will still execute
* as the order of execution on same `priority` is undefined).
@@ -14548,12 +14556,13 @@
* each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
*
* * `$scope` - Current scope associated with the element
* * `$element` - Current element
* * `$attrs` - Current attributes object for the element
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
- * `function(cloneLinkingFn)`.
+ * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
+ * The scope can be overridden by an optional first argument.
+ * `function([scope], cloneLinkingFn)`.
*
*
* #### `require`
* Require another directive and inject its controller as the fourth argument to the linking function. The
* `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
@@ -14642,19 +14651,25 @@
* safe to do template transformation on the element and child elements only.
*
* * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
* between all directive compile functions.
*
- * * `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
+ * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
*
* <div class="alert alert-warning">
* **Note:** The template instance and the link instance may be different objects if the template has
* been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
* apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
* should be done in a linking function rather than in a compile function.
* </div>
*
+ * <div class="alert alert-error">
+ * **Note:** The `transclude` function that is passed to the compile function is deperecated, as it
+ * e.g. does not know about the right outer scope. Please use the transclude function that is passed
+ * to the link function instead.
+ * </div>
+
* A compile function can have a return value which can be either a function or an object.
*
* * returning a (post-link) function - is equivalent to registering the linking function via the
* `link` property of the config object when the compile function is empty.
*
@@ -14665,11 +14680,11 @@
*
* #### `link`
* This property is used only if the `compile` property is not defined.
*
* <pre>
- * function link(scope, iElement, iAttrs, controller) { ... }
+ * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
* </pre>
*
* The link function is responsible for registering DOM listeners as well as updating the DOM. It is
* executed after the template has been cloned. This is where most of the directive logic will be
* put.
@@ -14686,10 +14701,14 @@
*
* * `controller` - a controller instance - A controller instance if at least one directive on the
* element defines a controller. The controller is shared among all the directives, which allows
* the directives to use the controllers as a communication channel.
*
+ * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
+ * The scope can be overridden by an optional first argument. This is the same as the `$transclude`
+ * parameter of directive controllers.
+ * `function([scope], cloneLinkingFn)`.
*
*
* #### Pre-linking function
*
* Executed before the child elements are linked. Not safe to do DOM transformation since the
@@ -15191,18 +15210,22 @@
}
});
var compositeLinkFn =
compileNodes($compileNodes, transcludeFn, $compileNodes,
maxPriority, ignoreDirective, previousCompileContext);
- return function publicLinkFn(scope, cloneConnectFn){
+ return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
assertArg(scope, 'scope');
// important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
// and sometimes changes the structure of the DOM.
var $linkNode = cloneConnectFn
? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
: $compileNodes;
+ forEach(transcludeControllers, function(instance, name) {
+ $linkNode.data('$' + name + 'Controller', instance);
+ });
+
// Attach scope only to non-text nodes.
for(var i = 0, ii = $linkNode.length; i<ii; i++) {
var node = $linkNode[i];
if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
$linkNode.eq(i).data('$scope', scope);
@@ -15297,19 +15320,11 @@
childScope = scope;
}
childTranscludeFn = nodeLinkFn.transclude;
if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
nodeLinkFn(childLinkFn, childScope, node, $rootElement,
- (function(transcludeFn) {
- return function(cloneFn) {
- var transcludeScope = scope.$new();
- transcludeScope.$$transcluded = true;
-
- return transcludeFn(transcludeScope, cloneFn).
- on('$destroy', bind(transcludeScope, transcludeScope.$destroy));
- };
- })(childTranscludeFn || transcludeFn)
+ createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
);
} else {
nodeLinkFn(childLinkFn, childScope, node, undefined, boundTranscludeFn);
}
} else if (childLinkFn) {
@@ -15317,11 +15332,28 @@
}
}
}
}
+ function createBoundTranscludeFn(scope, transcludeFn) {
+ return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
+ var scopeCreated = false;
+ if (!transcludedScope) {
+ transcludedScope = scope.$new();
+ transcludedScope.$$transcluded = true;
+ scopeCreated = true;
+ }
+
+ var clone = transcludeFn(transcludedScope, cloneFn, controllers);
+ if (scopeCreated) {
+ clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
+ }
+ return clone;
+ };
+ }
+
/**
* Looks for directives on the given node and adds them to the directive collection which is
* sorted.
*
* @param node Node to search.
@@ -15454,13 +15486,13 @@
* @param attrStart
* @param attrEnd
* @returns {Function}
*/
function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
- return function(scope, element, attrs, controllers) {
+ return function(scope, element, attrs, controllers, transcludeFn) {
element = groupScan(element[0], attrStart, attrEnd);
- return linkFn(scope, element, attrs, controllers);
+ return linkFn(scope, element, attrs, controllers, transcludeFn);
};
}
/**
* Once the directives have been collected, their compile functions are executed. This method
@@ -15493,11 +15525,13 @@
var terminalPriority = -Number.MAX_VALUE,
newScopeDirective,
controllerDirectives = previousCompileContext.controllerDirectives,
newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
templateDirective = previousCompileContext.templateDirective,
- transcludeDirective = previousCompileContext.transcludeDirective,
+ nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
+ hasTranscludeDirective = false,
+ hasElementTranscludeDirective = false,
$compileNode = templateAttrs.$$element = jqLite(compileNode),
directive,
directiveName,
$template,
replaceDirective = originalReplaceDirective,
@@ -15544,19 +15578,22 @@
controllerDirectives[directiveName], directive, $compileNode);
controllerDirectives[directiveName] = directive;
}
if (directiveValue = directive.transclude) {
+ hasTranscludeDirective = true;
+
// Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
// This option should only be used by directives that know how to how to safely handle element transclusion,
// where the transcluded nodes are added or replaced after linking.
if (!directive.$$tlb) {
- assertNoDuplicate('transclusion', transcludeDirective, directive, $compileNode);
- transcludeDirective = directive;
+ assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
+ nonTlbTranscludeDirective = directive;
}
if (directiveValue == 'element') {
+ hasElementTranscludeDirective = true;
terminalPriority = directive.priority;
$template = groupScan(compileNode, attrStart, attrEnd);
$compileNode = templateAttrs.$$element =
jqLite(document.createComment(' ' + directiveName + ': ' +
templateAttrs[directiveName] + ' '));
@@ -15568,13 +15605,13 @@
// Don't pass in:
// - controllerDirectives - otherwise we'll create duplicates controllers
// - newIsolateScopeDirective or templateDirective - combining templates with
// element transclusion doesn't make sense.
//
- // We need only transcludeDirective so that we prevent putting transclusion
+ // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
// on the same element more than once.
- transcludeDirective: transcludeDirective
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
});
} else {
$template = jqLite(jqLiteClone(compileNode)).contents();
$compileNode.html(''); // clear contents
childTranscludeFn = compile($template, transcludeFn);
@@ -15639,11 +15676,11 @@
nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
controllerDirectives: controllerDirectives,
newIsolateScopeDirective: newIsolateScopeDirective,
templateDirective: templateDirective,
- transcludeDirective: transcludeDirective
+ nonTlbTranscludeDirective: nonTlbTranscludeDirective
});
ii = directives.length;
} else if (directive.compile) {
try {
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
@@ -15663,11 +15700,11 @@
}
}
nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
- nodeLinkFn.transclude = transcludeDirective && childTranscludeFn;
+ nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
// might be normal or delayed nodeLinkFn depending on if templateUrl is present
return nodeLinkFn;
////////////////////
@@ -15690,46 +15727,45 @@
postLinkFns.push(post);
}
}
- function getControllers(require, $element) {
+ function getControllers(require, $element, elementControllers) {
var value, retrievalMethod = 'data', optional = false;
if (isString(require)) {
while((value = require.charAt(0)) == '^' || value == '?') {
require = require.substr(1);
if (value == '^') {
retrievalMethod = 'inheritedData';
}
optional = optional || value == '?';
}
+ value = null;
- value = $element[retrievalMethod]('$' + require + 'Controller');
-
- if ($element[0].nodeType == 8 && $element[0].$$controller) { // Transclusion comment node
- value = value || $element[0].$$controller;
- $element[0].$$controller = null;
+ if (elementControllers && retrievalMethod === 'data') {
+ value = elementControllers[require];
}
+ value = value || $element[retrievalMethod]('$' + require + 'Controller');
if (!value && !optional) {
throw $compileMinErr('ctreq',
"Controller '{0}', required by directive '{1}', can't be found!",
require, directiveName);
}
return value;
} else if (isArray(require)) {
value = [];
forEach(require, function(require) {
- value.push(getControllers(require, $element));
+ value.push(getControllers(require, $element, elementControllers));
});
}
return value;
}
function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller, isolateScope;
+ var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
if (compileNode === linkNode) {
attrs = templateAttrs;
} else {
attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
@@ -15819,36 +15855,36 @@
" Definition: {... {1}: '{2}' ...}",
newIsolateScopeDirective.name, scopeName, definition);
}
});
}
-
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude;
if (controllerDirectives) {
forEach(controllerDirectives, function(directive) {
var locals = {
$scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
$element: $element,
$attrs: attrs,
- $transclude: boundTranscludeFn
+ $transclude: transcludeFn
}, controllerInstance;
controller = directive.controller;
if (controller == '@') {
controller = attrs[directive.name];
}
controllerInstance = $controller(controller, locals);
-
- // Directives with element transclusion and a controller need to attach controller
- // to the comment node created by the compiler, but jQuery .data doesn't support
- // attaching data to comment nodes so instead we set it directly on the element and
- // remove it after we read it later.
- if ($element[0].nodeType == 8) { // Transclusion comment node
- $element[0].$$controller = controllerInstance;
- } else {
+ // For directives with element transclusion the element is a comment,
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
+ // clean up (http://bugs.jquery.com/ticket/8335).
+ // Instead, we save the controllers for the element in a local hash and attach to .data
+ // later, once we have the actual element.
+ elementControllers[directive.name] = controllerInstance;
+ if (!hasElementTranscludeDirective) {
$element.data('$' + directive.name + 'Controller', controllerInstance);
}
+
if (directive.controllerAs) {
locals.$scope[directive.controllerAs] = controllerInstance;
}
});
}
@@ -15856,11 +15892,11 @@
// PRELINKING
for(i = 0, ii = preLinkFns.length; i < ii; i++) {
try {
linkFn = preLinkFns[i];
linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element));
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
@@ -15876,15 +15912,32 @@
// POSTLINKING
for(i = postLinkFns.length - 1; i >= 0; i--) {
try {
linkFn = postLinkFns[i];
linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element));
+ linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
} catch (e) {
$exceptionHandler(e, startingTag($element));
}
}
+
+ // This is the function that is injected as `$transclude`.
+ function controllersBoundTransclude(scope, cloneAttachFn) {
+ var transcludeControllers;
+
+ // no scope passed
+ if (arguments.length < 2) {
+ cloneAttachFn = scope;
+ scope = undefined;
+ }
+
+ if (hasElementTranscludeDirective) {
+ transcludeControllers = elementControllers;
+ }
+
+ return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
+ }
}
}
function markDirectivesAsIsolate(directives) {
// mark all directives as needing isolate scope.
@@ -15959,10 +16012,11 @@
if (key == 'class') {
safeAddClass($element, value);
dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
} else if (key == 'style') {
$element.attr('style', $element.attr('style') + ';' + value);
+ dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
// `dst` will never contain hasOwnProperty as DOM parser won't let it.
// You will get an "InvalidCharacterError: DOM Exception 5" error if you
// have an attribute like "has-own-property" or "data-has-own-property", etc.
} else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
dst[key] = value;
@@ -15989,11 +16043,11 @@
$compileNode.html('');
$http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
success(function(content) {
- var compileNode, tempTemplateAttrs, $template;
+ var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
content = denormalizeTemplate(content);
if (origAsyncDirective.replace) {
$template = jqLite('<div>' + trim(content) + '</div>').contents();
@@ -16034,36 +16088,40 @@
while(linkQueue.length) {
var scope = linkQueue.shift(),
beforeTemplateLinkNode = linkQueue.shift(),
linkRootElement = linkQueue.shift(),
- controller = linkQueue.shift(),
+ boundTranscludeFn = linkQueue.shift(),
linkNode = $compileNode[0];
if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
// it was cloned therefore we have to clone as well.
linkNode = jqLiteClone(compileNode);
replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
}
-
+ if (afterTemplateNodeLinkFn.transclude) {
+ childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
+ } else {
+ childBoundTranscludeFn = boundTranscludeFn;
+ }
afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
- controller);
+ childBoundTranscludeFn);
}
linkQueue = null;
}).
error(function(response, code, headers, config) {
throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
});
- return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, controller) {
+ return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
if (linkQueue) {
linkQueue.push(scope);
linkQueue.push(node);
linkQueue.push(rootElement);
- linkQueue.push(controller);
+ linkQueue.push(boundTranscludeFn);
} else {
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, controller);
+ afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
}
};
}
@@ -16764,24 +16822,30 @@
* into `$http`.
*
*
* # Caching
*
- * To enable caching, set the configuration property `cache` to `true`. When the cache is
- * enabled, `$http` stores the response from the server in local cache. Next time the
- * response is served from the cache without sending a request to the server.
+ * To enable caching, set the request configuration `cache` property to `true` (to use default
+ * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
+ * When the cache is enabled, `$http` stores the response from the server in the specified
+ * cache. The next time the same request is made, the response is served from the cache without
+ * sending a request to the server.
*
* Note that even if the response is served from cache, delivery of the data is asynchronous in
* the same way that real requests are.
*
* If there are multiple GET requests for the same URL that should be cached using the same
* cache, but the cache is not populated yet, only one request to the server will be made and
* the remaining requests will be fulfilled using the response from the first request.
*
- * A custom default cache built with $cacheFactory can be provided in $http.defaults.cache.
- * To skip it, set configuration property `cache` to `false`.
+ * You can change the default cache to a new object (built with
+ * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
+ * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
+ * their `cache` property to `true` will now use this cache object.
*
+ * If you set the default cache to `false` then only requests that specify their own custom
+ * cache object will be cached.
*
* # Interceptors
*
* Before you start creating interceptors, be sure to understand the
* {@link ng.$q $q and deferred/promise APIs}.
@@ -18041,25 +18105,25 @@
}
return segments.join('/');
}
-function parseAbsoluteUrl(absoluteUrl, locationObj) {
- var parsedUrl = urlResolve(absoluteUrl);
+function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
+ var parsedUrl = urlResolve(absoluteUrl, appBase);
locationObj.$$protocol = parsedUrl.protocol;
locationObj.$$host = parsedUrl.hostname;
locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
}
-function parseAppUrl(relativeUrl, locationObj) {
+function parseAppUrl(relativeUrl, locationObj, appBase) {
var prefixed = (relativeUrl.charAt(0) !== '/');
if (prefixed) {
relativeUrl = '/' + relativeUrl;
}
- var match = urlResolve(relativeUrl);
+ var match = urlResolve(relativeUrl, appBase);
locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
match.pathname.substring(1) : match.pathname);
locationObj.$$search = parseKeyValue(match.search);
locationObj.$$hash = decodeURIComponent(match.hash);
@@ -18110,11 +18174,11 @@
*/
function LocationHtml5Url(appBase, basePrefix) {
this.$$html5 = true;
basePrefix = basePrefix || '';
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this);
+ parseAbsoluteUrl(appBase, this, appBase);
/**
* Parse given html5 (regular) url string into properties
* @param {string} newAbsoluteUrl HTML5 url
@@ -18125,11 +18189,11 @@
if (!isString(pathUrl)) {
throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
appBaseNoFile);
}
- parseAppUrl(pathUrl, this);
+ parseAppUrl(pathUrl, this, appBase);
if (!this.$$path) {
this.$$path = '/';
}
@@ -18177,11 +18241,11 @@
* @param {string} hashPrefix hashbang prefix
*/
function LocationHashbangUrl(appBase, hashPrefix) {
var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this);
+ parseAbsoluteUrl(appBase, this, appBase);
/**
* Parse given hashbang url into properties
* @param {string} url Hashbang url
@@ -18197,11 +18261,11 @@
if (!isString(withoutHashUrl)) {
throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
hashPrefix);
}
- parseAppUrl(withoutHashUrl, this);
+ parseAppUrl(withoutHashUrl, this, appBase);
this.$$compose();
};
/**
* Compose hashbang url and update `absUrl` property
@@ -18845,27 +18909,22 @@
// Sandboxing Angular Expressions
// ------------------------------
// Angular expressions are generally considered safe because these expressions only have direct
// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
-// obtaining a reference to native JS functions such as the Function constructor, the global Window
-// or Document object. In addition, many powerful functions for use by JavaScript code are
-// published on scope that shouldn't be available from within an Angular expression.
+// obtaining a reference to native JS functions such as the Function constructor.
//
// As an example, consider the following Angular expression:
//
// {}.toString.constructor(alert("evil JS code"))
//
// We want to prevent this type of access. For the sake of performance, during the lexing phase we
-// disallow any "dotted" access to any member named "constructor" or to any member whose name begins
-// or ends with an underscore. The latter allows one to exclude the private / JavaScript only API
-// available on the scope and controllers from the context of an Angular expression.
+// disallow any "dotted" access to any member named "constructor".
//
-// For reflective calls (a[b]), we check that the value of the lookup is not the Function
-// constructor, Window or DOM node while evaluating the expression, which is a stronger but more
-// expensive test. Since reflective calls are expensive anyway, this is not such a big deal compared
-// to static dereferencing.
+// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
+// while evaluating the expression, which is a stronger but more expensive test. Since reflective
+// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
//
// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
// against the expression language, but not to prevent exploits that were enabled by exposing
// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
// practice and therefore we are not even trying to protect against interaction with an object
@@ -18875,24 +18934,16 @@
// name on the scope.
//
// In general, it is not possible to access a Window object from an angular expression unless a
// window or some DOM object that has a reference to window is published onto a Scope.
-function ensureSafeMemberName(name, fullExpression, allowConstructor) {
- if (typeof name !== 'string' && toString.apply(name) !== "[object String]") {
- return name;
- }
- if (name === "constructor" && !allowConstructor) {
+function ensureSafeMemberName(name, fullExpression) {
+ if (name === "constructor") {
throw $parseMinErr('isecfld',
'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
fullExpression);
}
- if (name.charAt(0) === '_' || name.charAt(name.length-1) === '_') {
- throw $parseMinErr('isecprv',
- 'Referencing private fields in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- }
return name;
}
function ensureSafeObject(obj, fullExpression) {
// nifty check if obj is Function that is fast and works across iframes and other contexts
@@ -19572,14 +19623,11 @@
var indexFn = this.expression();
this.consume(']');
return extend(function(self, locals) {
var o = obj(self, locals),
- // In the getter, we will not block looking up "constructor" by name in order to support user defined
- // constructors. However, if value looked up is the Function constructor, we will still block it in the
- // ensureSafeObject call right after we look up o[i] (a few lines below.)
- i = ensureSafeMemberName(indexFn(self, locals), parser.text, true /* allowConstructor */),
+ i = indexFn(self, locals),
v, p;
if (!o) return undefined;
v = ensureSafeObject(o[i], parser.text);
if (v && v.then && parser.options.unwrapPromises) {
@@ -19591,11 +19639,11 @@
v = v.$$v;
}
return v;
}, {
assign: function(self, value, locals) {
- var key = ensureSafeMemberName(indexFn(self, locals), parser.text);
+ var key = indexFn(self, locals);
// prevent overwriting of Function.constructor which would break ensureSafeObject check
var safe = ensureSafeObject(obj(self, locals), parser.text);
return safe[key] = value;
}
});
@@ -20251,11 +20299,11 @@
* expect(resolvedValue).toBeUndefined();
*
* // Propagate promise resolution to 'then' functions using $apply().
* $rootScope.$apply();
* expect(resolvedValue).toEqual(123);
- * });
+ * }));
* </pre>
*/
function $QProvider() {
this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
@@ -22068,14 +22116,14 @@
*
* Here's an example of a binding in a privileged context:
*
* <pre class="prettyprint">
* <input ng-model="userHtml">
- * <div ng-bind-html="{{userHtml}}">
+ * <div ng-bind-html="userHtml">
* </pre>
*
- * Notice that `ng-bind-html` is bound to `{{userHtml}}` controlled by the user. With SCE
+ * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
* disabled, this application allows the user to render arbitrary HTML into the DIV.
* In a more realistic example, one may be rendering user comments, blog articles, etc. via
* bindings. (HTML is just one example of a context where rendering user controlled input creates
* security vulnerabilities.)
*
@@ -22992,12 +23040,18 @@
// cause us to break tests. In addition, when the browser resolves a URL for XHR, it
// doesn't know about mocked locations and resolves URLs to the real document - which is
// exactly the behavior needed here. There is little value is mocking these out for this
// service.
var urlParsingNode = document.createElement("a");
+/*
+Matches paths for file protocol on windows,
+such as /C:/foo/bar, and captures only /foo/bar.
+*/
+var windowsFilePathExp = /^\/?.*?:(\/.*)/;
var originUrl = urlResolve(window.location.href, true);
+
/**
*
* Implementation Notes for non-IE browsers
* ----------------------------------------
* Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
@@ -23012,11 +23066,11 @@
* ---------------------------
* IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
* browsers. However, the parsed components will not be set if the URL assigned did not specify
* them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
* work around that by performing the parsing in a 2nd step by taking a previously normalized
- * URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the
+ * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
* properties such as protocol, hostname, port, etc.
*
* IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
* uses the inner HTML approach to assign the URL as part of an HTML snippet -
* http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL.
@@ -23046,32 +23100,48 @@
* | hostname | The hostname
* | port | The port, without ":"
* | pathname | The pathname, beginning with "/"
*
*/
-function urlResolve(url) {
- var href = url;
+function urlResolve(url, base) {
+ var href = url,
+ pathname;
+
if (msie) {
// Normalize before parse. Refer Implementation Notes on why this is
// done in two steps on IE.
urlParsingNode.setAttribute("href", href);
href = urlParsingNode.href;
}
urlParsingNode.setAttribute('href', href);
- // $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
+ /*
+ * In Windows, on an anchor node on documents loaded from
+ * the filesystem, the browser will return a pathname
+ * prefixed with the drive name ('/C:/path') when a
+ * pathname without a drive is set:
+ * * a.setAttribute('href', '/foo')
+ * * a.pathname === '/C:/foo' //true
+ *
+ * Inside of Angular, we're always using pathnames that
+ * do not include drive names for routing.
+ */
+
+ pathname = removeWindowsDriveName(urlParsingNode.pathname, url, base);
+ pathname = (pathname.charAt(0) === '/') ? pathname : '/' + pathname;
+
+ // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
return {
href: urlParsingNode.href,
protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
host: urlParsingNode.host,
search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
hostname: urlParsingNode.hostname,
port: urlParsingNode.port,
- pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ?
- urlParsingNode.pathname : '/' + urlParsingNode.pathname
+ pathname: pathname
};
}
/**
@@ -23085,10 +23155,30 @@
var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
return (parsed.protocol === originUrl.protocol &&
parsed.host === originUrl.host);
}
+function removeWindowsDriveName (path, url, base) {
+ var firstPathSegmentMatch;
+
+ //Get the relative path from the input URL.
+ if (url.indexOf(base) === 0) {
+ url = url.replace(base, '');
+ }
+
+ /*
+ * The input URL intentionally contains a
+ * first path segment that ends with a colon.
+ */
+ if (windowsFilePathExp.exec(url)) {
+ return path;
+ }
+
+ firstPathSegmentMatch = windowsFilePathExp.exec(path);
+ return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
+}
+
/**
* @ngdoc object
* @name ng.$window
*
* @description
@@ -24601,11 +24691,11 @@
* @property {boolean} $invalid True if at least one containing control or form is invalid.
*
* @property {Object} $error Is an object hash, containing references to all invalid controls or
* forms, where:
*
- * - keys are validation tokens (error names) — such as `required`, `url` or `email`),
+ * - keys are validation tokens (error names) — such as `required`, `url` or `email`,
* - values are arrays of controls or forms that are invalid with given error.
*
* @description
* `FormController` keeps track of all its controls and nested forms as well as state of them,
* such as being valid/invalid or dirty/pristine.
@@ -25786,10 +25876,15 @@
* return value.toUpperCase();
* }
* }
* ngModel.$formatters.push(formatter);
* </pre>
+ *
+ * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
+ * view value has changed. It is called with no arguments, and its return value is ignored.
+ * This can be used in place of additional $watches against the model value.
+ *
* @property {Object} $error An object hash with all errors as keys.
*
* @property {boolean} $pristine True if user has not interacted with the control yet.
* @property {boolean} $dirty True if user has already interacted with the control.
* @property {boolean} $valid True if there is no error.
@@ -26049,19 +26144,24 @@
* @ngdoc function
* @name ng.directive:ngModel.NgModelController#$setViewValue
* @methodOf ng.directive:ngModel.NgModelController
*
* @description
- * Read a value from view.
+ * Update the view value.
*
- * This method should be called from within a DOM event handler.
- * For example {@link ng.directive:input input} or
+ * This method should be called when the view value changes, typically from within a DOM event handler.
+ * For example {@link ng.directive:input input} and
* {@link ng.directive:select select} directives call it.
*
- * It internally calls all `$parsers` (including validators) and updates the `$modelValue` and the actual model path.
- * Lastly it calls all registered change listeners.
+ * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
+ * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
+ * `$modelValue` and the **expression** specified in the `ng-model` attribute.
+ *
+ * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
*
+ * Note that calling this function does not trigger a `$digest`.
+ *
* @param {string} value Value from the view.
*/
this.$setViewValue = function(value) {
this.$viewValue = value;
@@ -26558,31 +26658,37 @@
*
* @element ANY
* @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
*
* @example
- * Try it here: enter text in text box and watch the greeting change.
- <doc:example module="ngBindHtmlExample" deps="angular-sanitize.js" >
- <doc:source>
- <script>
- angular.module('ngBindHtmlExample', ['ngSanitize'])
-
- .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
- $scope.myHTML = 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
- }]);
- </script>
+ Try it here: enter text in text box and watch the greeting change.
+
+ <example module="ngBindHtmlExample" deps="angular-sanitize.js">
+ <file name="index.html">
<div ng-controller="ngBindHtmlCtrl">
<p ng-bind-html="myHTML"></p>
</div>
- </doc:source>
- <doc:scenario>
+ </file>
+
+ <file name="script.js">
+ angular.module('ngBindHtmlExample', ['ngSanitize'])
+
+ .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
+ $scope.myHTML =
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
+ }]);
+ </file>
+
+ <file name="scenario.js">
it('should check ng-bind-html', function() {
expect(using('.doc-example-live').binding('myHTML')).
- toBe('I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>');
+ toBe(
+ 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
+ );
});
- </doc:scenario>
- </doc:example>
+ </file>
+ </example>
*/
var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
return function(scope, element, attr) {
element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
@@ -26691,22 +26797,22 @@
* element.
*
* @example Example that demonstrates basic bindings via ngClass directive.
<example>
<file name="index.html">
- <p ng-class="{strike: strike, bold: bold, red: red}">Map Syntax Example</p>
- <input type="checkbox" ng-model="bold"> bold
- <input type="checkbox" ng-model="strike"> strike
- <input type="checkbox" ng-model="red"> red
+ <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
+ <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
+ <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
+ <input type="checkbox" ng-model="error"> error (apply "red" class)
<hr>
<p ng-class="style">Using String Syntax</p>
<input type="text" ng-model="style" placeholder="Type: bold strike red">
<hr>
<p ng-class="[style1, style2, style3]">Using Array Syntax</p>
- <input ng-model="style1" placeholder="Type: bold"><br>
- <input ng-model="style2" placeholder="Type: strike"><br>
- <input ng-model="style3" placeholder="Type: red"><br>
+ <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
+ <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
+ <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
</file>
<file name="style.css">
.strike {
text-decoration: line-through;
}
@@ -26721,14 +26827,14 @@
it('should let you toggle the class', function() {
expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
- input('bold').check();
+ input('important').check();
expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
- input('red').check();
+ input('error').check();
expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
});
it('should let you toggle string example', function() {
expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
@@ -27570,11 +27676,11 @@
border:1px solid black;
padding:10px;
}
/*
- The transition styles can also be placed on the CSS base class above
+ The transition styles can also be placed on the CSS base class above
*/
.animate-if.ng-enter, .animate-if.ng-leave {
-webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
}
@@ -27596,26 +27702,25 @@
transclude: 'element',
priority: 600,
terminal: true,
restrict: 'A',
$$tlb: true,
- compile: function (element, attr, transclude) {
- return function ($scope, $element, $attr) {
+ link: function ($scope, $element, $attr, ctrl, $transclude) {
var block, childScope;
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
if (toBoolean(value)) {
-
- childScope = $scope.$new();
- transclude(childScope, function (clone) {
- block = {
- startNode: clone[0],
- endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
- };
- $animate.enter(clone, $element.parent(), $element);
- });
-
+ if (!childScope) {
+ childScope = $scope.$new();
+ $transclude(childScope, function (clone) {
+ block = {
+ startNode: clone[0],
+ endNode: clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ')
+ };
+ $animate.enter(clone, $element.parent(), $element);
+ });
+ }
} else {
if (childScope) {
childScope.$destroy();
childScope = null;
@@ -27625,11 +27730,10 @@
$animate.leave(getBlockElements(block));
block = null;
}
}
});
- };
}
};
}];
/**
@@ -27784,16 +27888,16 @@
return {
restrict: 'ECA',
priority: 400,
terminal: true,
transclude: 'element',
- compile: function(element, attr, transclusion) {
+ compile: function(element, attr) {
var srcExp = attr.ngInclude || attr.src,
onloadExp = attr.onload || '',
autoScrollExp = attr.autoscroll;
- return function(scope, $element) {
+ return function(scope, $element, $attr, ctrl, $transclude) {
var changeCounter = 0,
currentScope,
currentElement;
var cleanupLastIncludeContent = function() {
@@ -27818,11 +27922,11 @@
if (src) {
$http.get(src, {cache: $templateCache}).success(function(response) {
if (thisChangeId !== changeCounter) return;
var newScope = scope.$new();
- transclusion(newScope, function(clone) {
+ $transclude(newScope, function(clone) {
cleanupLastIncludeContent();
currentScope = newScope;
currentElement = clone;
@@ -28347,12 +28451,11 @@
return {
transclude: 'element',
priority: 1000,
terminal: true,
$$tlb: true,
- compile: function(element, attr, linker) {
- return function($scope, $element, $attr){
+ link: function($scope, $element, $attr, ctrl, $transclude){
var expression = $attr.ngRepeat;
var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
lhs, rhs, valueIdentifier, keyIdentifier,
hashFnLocals = {$id: hashKey};
@@ -28510,11 +28613,11 @@
// jshint bitwise: false
childScope.$odd = !(childScope.$even = (index&1) === 0);
// jshint bitwise: true
if (!block.startNode) {
- linker(childScope, function(clone) {
+ $transclude(childScope, function(clone) {
clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
$animate.enter(clone, null, jqLite(previousNode));
previousNode = clone;
block.scope = childScope;
block.startNode = previousNode && previousNode.endNode ? previousNode.endNode : clone[0];
@@ -28523,11 +28626,10 @@
});
}
}
lastBlockMap = nextBlockMap;
});
- };
}
};
}];
/**
@@ -29032,27 +29134,25 @@
var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
priority: 800,
require: '^ngSwitch',
- compile: function(element, attrs, transclude) {
- return function(scope, element, attr, ctrl) {
+ compile: function(element, attrs) {
+ return function(scope, element, attr, ctrl, $transclude) {
ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
- ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: transclude, element: element });
+ ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
};
}
});
var ngSwitchDefaultDirective = ngDirective({
transclude: 'element',
priority: 800,
require: '^ngSwitch',
- compile: function(element, attrs, transclude) {
- return function(scope, element, attr, ctrl) {
- ctrl.cases['?'] = (ctrl.cases['?'] || []);
- ctrl.cases['?'].push({ transclude: transclude, element: element });
- };
- }
+ link: function(scope, element, attr, ctrl, $transclude) {
+ ctrl.cases['?'] = (ctrl.cases['?'] || []);
+ ctrl.cases['?'].push({ transclude: $transclude, element: element });
+ }
});
/**
* @ngdoc directive
* @name ng.directive:ngTransclude
\ No newline at end of file