diff --git a/Gruntfile.js b/Gruntfile.js
index 98f0fc69b3..d1293fc1a0 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -16,7 +16,7 @@ module.exports = function(grunt) {
grunt.util.linefeed = '\n';
grunt.initConfig({
- ngversion: '1.2.7',
+ ngversion: '1.2.8',
bsversion: '3.0.3',
modules: [],//to be filled in by build task
pkg: grunt.file.readJSON('package.json'),
diff --git a/misc/test-lib/angular-mocks.js b/misc/test-lib/angular-mocks.js
index 61b2481a67..90ae186632 100644
--- a/misc/test-lib/angular-mocks.js
+++ b/misc/test-lib/angular-mocks.js
@@ -1,5 +1,5 @@
/**
- * @license AngularJS v1.2.7
+ * @license AngularJS v1.2.8
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
@@ -2086,6 +2086,20 @@ if(window.jasmine || window.mocha) {
*
* @param {...Function} fns any number of functions which will be injected using the injector.
*/
+
+
+
+ var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
+ this.message = e.message;
+ this.name = e.name;
+ if (e.line) this.line = e.line;
+ if (e.sourceId) this.sourceId = e.sourceId;
+ if (e.stack && errorForStack)
+ this.stack = e.stack + '\n' + errorForStack.stack;
+ if (e.stackArray) this.stackArray = e.stackArray;
+ };
+ ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
+
window.inject = angular.mock.inject = function() {
var blockFns = Array.prototype.slice.call(arguments, 0);
var errorForStack = new Error('Declaration Location');
@@ -2106,7 +2120,9 @@ if(window.jasmine || window.mocha) {
injector.invoke(blockFns[i] || angular.noop, this);
/* jshint +W040 */
} catch (e) {
- if(e.stack && errorForStack) e.stack += '\n' + errorForStack.stack;
+ if (e.stack && errorForStack) {
+ throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
+ }
throw e;
} finally {
errorForStack = null;
diff --git a/misc/test-lib/angular.js b/misc/test-lib/angular.js
index 14559457f7..7856504dd5 100644
--- a/misc/test-lib/angular.js
+++ b/misc/test-lib/angular.js
@@ -1,5 +1,5 @@
/**
- * @license AngularJS v1.2.7
+ * @license AngularJS v1.2.8
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
@@ -68,7 +68,7 @@ function minErr(module) {
return match;
});
- message = message + '\nhttp://errors.angularjs.org/1.2.7/' +
+ message = message + '\nhttp://errors.angularjs.org/1.2.8/' +
(module ? module + '/' : '') + code;
for (i = 2; i < arguments.length; i++) {
message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
@@ -1833,11 +1833,11 @@ function setupModuleLoader(window) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.2.7', // all of these placeholder strings will be replaced by grunt's
+ full: '1.2.8', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 2,
- dot: 7,
- codeName: 'emoji-clairvoyance'
+ dot: 8,
+ codeName: 'interdimensional-cartography'
};
@@ -6648,7 +6648,7 @@ function directiveNormalize(name) {
*
*
* @param {string} name Normalized element attribute name of the property to modify. The name is
- * revers translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
+ * reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
* property to the original name.
* @param {string} value Value to set the attribute to. The value can be an interpolated string.
*/
@@ -6786,8 +6786,7 @@ function $ControllerProvider() {
* @requires $window
*
* @description
- * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
- * element.
+ * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
*/
function $DocumentProvider(){
this.$get = ['$window', function(window){
@@ -7126,7 +7125,15 @@ function $HttpProvider() {
* `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }.
*
* The defaults can also be set at runtime via the `$http.defaults` object in the same
- * fashion. In addition, you can supply a `headers` property in the config object passed when
+ * fashion. For example:
+ *
+ * ```
+ * module.run(function($http) {
+ * $http.defaults.headers.common.Authentication = 'Basic YmVlcDpib29w'
+ * });
+ * ```
+ *
+ * In addition, you can supply a `headers` property in the config object passed when
* calling `$http(config)`, which overrides the defaults without changing them globally.
*
*
@@ -7150,7 +7157,9 @@ function $HttpProvider() {
* properties. These properties are by default an array of transform functions, which allows you
* to `push` or `unshift` a new transformation function into the transformation chain. You can
* also decide to completely override any default transformations by assigning your
- * transformation functions to these properties directly without the array wrapper.
+ * transformation functions to these properties directly without the array wrapper. These defaults
+ * are again available on the $http factory at run-time, which may be useful if you have run-time
+ * services you wish to be involved in your transformations.
*
* Similarly, to locally override the request/response transforms, augment the
* `transformRequest` and/or `transformResponse` properties of the configuration object passed
@@ -7364,7 +7373,8 @@ function $HttpProvider() {
* for added security.
*
* The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
- * properties of either $httpProvider.defaults, or the per-request config object.
+ * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
+ * or the per-request config object.
*
*
* @param {object} config Object describing the request to be made and how it should be
@@ -7927,7 +7937,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
} else {
completeRequest(callback, status || -2);
}
- delete callbacks[callbackId];
+ callbacks[callbackId] = angular.noop;
});
} else {
@@ -7944,7 +7954,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
// response is in the cache. the promise api will ensure that to the app code the api is
// always async
xhr.onreadystatechange = function() {
- // onreadystatechange might by called multiple times with readyState === 4 on mobile webkit caused by
+ // onreadystatechange might get called multiple times with readyState === 4 on mobile webkit caused by
// xhrs that are resolved while the app is in the background (see #5426).
// since calling completeRequest sets the `xhr` variable to null, we just check if it's not null before
// continuing
@@ -7957,11 +7967,12 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
if(status !== ABORTED) {
responseHeaders = xhr.getAllResponseHeaders();
- response = xhr.responseType ? xhr.response : xhr.responseText;
+
+ // responseText is the old-school way of retrieving response (supported by IE8 & 9)
+ // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
+ response = ('response' in xhr) ? xhr.response : xhr.responseText;
}
- // responseText is the old-school way of retrieving response (supported by IE8 & 9)
- // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
completeRequest(callback,
status || xhr.status,
response,
@@ -7994,14 +8005,14 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc
}
function completeRequest(callback, status, response, headersString) {
- var protocol = urlResolve(url).protocol;
-
// cancel timeout and subsequent timeout promise resolution
timeoutId && $browserDefer.cancel(timeoutId);
jsonpDone = xhr = null;
- // fix status code for file protocol (it's always 0)
- status = (protocol == 'file' && status === 0) ? (response ? 200 : 404) : status;
+ // fix status code when it is 0 (0 status is undocumented).
+ // Occurs when accessing file resources.
+ // On Android 4.1 stock browser it occurs while retrieving files from application cache.
+ status = (status === 0) ? (response ? 200 : 404) : status;
// normalize IE bug (http://bugs.jquery.com/ticket/1450)
status = status == 1223 ? 204 : status;
@@ -9115,7 +9126,7 @@ function $LocationProvider(){
* Broadcasted before a URL will change. This change can be prevented by calling
* `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
* details about event object. Upon successful change
- * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
+ * {@link ng.$location#events_$locationChangeSuccess $locationChangeSuccess} is fired.
*
* @param {Object} angularEvent Synthetic event object.
* @param {string} newUrl New URL
@@ -10306,16 +10317,20 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
- if (pathVal == null) return key1 ? undefined : pathVal;
+ if (!key1) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key1];
- if (pathVal == null) return key2 ? undefined : pathVal;
+ if (!key2) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key2];
- if (pathVal == null) return key3 ? undefined : pathVal;
+ if (!key3) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key3];
- if (pathVal == null) return key4 ? undefined : pathVal;
+ if (!key4) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key4];
return pathVal;
@@ -10336,8 +10351,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (pathVal == null) return key1 ? undefined : pathVal;
+ if (!key1) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -10348,8 +10364,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (pathVal == null) return key2 ? undefined : pathVal;
+ if (!key2) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -10360,8 +10377,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (pathVal == null) return key3 ? undefined : pathVal;
+ if (!key3) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -10372,8 +10390,9 @@ function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
}
pathVal = pathVal.$$v;
}
- if (pathVal == null) return key4 ? undefined : pathVal;
+ if (!key4) return pathVal;
+ if (pathVal == null) return undefined;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
@@ -11371,7 +11390,7 @@ function $RootScopeProvider(){
} else {
ChildScope = function() {}; // should be anonymous; This is so that when the minifier munges
// the name it does not become random set of chars. This will then show up as class
- // name in the debugger.
+ // name in the web inspector.
ChildScope.prototype = this;
child = new ChildScope();
child.$id = nextUid();
@@ -11472,7 +11491,7 @@ function $RootScopeProvider(){
// No digest has been run so the counter will be zero
expect(scope.foodCounter).toEqual(0);
- // Run the digest but since food has not changed cout will still be zero
+ // Run the digest but since food has not changed count will still be zero
scope.$digest();
expect(scope.foodCounter).toEqual(0);
@@ -13895,8 +13914,8 @@ function $FilterProvider($provide) {
*
* Can be one of:
*
- * - `string`: Predicate that results in a substring match using the value of `expression`
- * string. All strings or objects with string properties in `array` that contain this string
+ * - `string`: The string is evaluated as an expression and the resulting value is used for substring match against
+ * the contents of the `array`. All strings or objects with string properties in `array` that contain this string
* will be returned. The predicate can be negated by prefixing the string with `!`.
*
* - `Object`: A pattern object can be used to filter specific properties on objects contained
@@ -14054,23 +14073,12 @@ function filterFilter() {
case "object":
// jshint +W086
for (var key in expression) {
- if (key == '$') {
- (function() {
- if (!expression[key]) return;
- var path = key;
- predicates.push(function(value) {
- return search(value, expression[path]);
- });
- })();
- } else {
- (function() {
- if (typeof(expression[key]) == 'undefined') { return; }
- var path = key;
- predicates.push(function(value) {
- return search(getter(value,path), expression[path]);
- });
- })();
- }
+ (function(path) {
+ if (typeof expression[path] == 'undefined') return;
+ predicates.push(function(value) {
+ return search(path == '$' ? value : getter(value, path), expression[path]);
+ });
+ })(key);
}
break;
case 'function':
@@ -15191,12 +15199,10 @@ forEach(BOOLEAN_ATTR, function(propName, attrName) {
ngAttributeAliasDirectives[normalized] = function() {
return {
priority: 100,
- compile: function() {
- return function(scope, element, attr) {
- scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
- attr.$set(attrName, !!value);
- });
- };
+ link: function(scope, element, attr) {
+ scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
+ attr.$set(attrName, !!value);
+ });
}
};
};
@@ -15476,10 +15482,10 @@ function FormController(element, attrs) {
*
*
* # CSS classes
- * - `ng-valid` Is set if the form is valid.
- * - `ng-invalid` Is set if the form is invalid.
- * - `ng-pristine` Is set if the form is pristine.
- * - `ng-dirty` Is set if the form is dirty.
+ * - `ng-valid` is set if the form is valid.
+ * - `ng-invalid` is set if the form is invalid.
+ * - `ng-pristine` is set if the form is pristine.
+ * - `ng-dirty` is set if the form is dirty.
*
*
* # Submitting a form and preventing the default action
@@ -15996,6 +16002,12 @@ var inputType = {
'reset': noop
};
+// A helper function to call $setValidity and return the value / undefined,
+// a pattern that is repeated a lot in the input validation logic.
+function validate(ctrl, validatorName, validity, value){
+ ctrl.$setValidity(validatorName, validity);
+ return validity ? value : undefined;
+}
function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
// In composition mode, users are still inputing intermediate text buffer,
@@ -16080,22 +16092,15 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
patternValidator,
match;
- var validate = function(regexp, value) {
- if (ctrl.$isEmpty(value) || regexp.test(value)) {
- ctrl.$setValidity('pattern', true);
- return value;
- } else {
- ctrl.$setValidity('pattern', false);
- return undefined;
- }
- };
-
if (pattern) {
+ var validateRegex = function(regexp, value) {
+ return validate(ctrl, 'pattern', ctrl.$isEmpty(value) || regexp.test(value), value);
+ };
match = pattern.match(/^\/(.*)\/([gim]*)$/);
if (match) {
pattern = new RegExp(match[1], match[2]);
patternValidator = function(value) {
- return validate(pattern, value);
+ return validateRegex(pattern, value);
};
} else {
patternValidator = function(value) {
@@ -16106,7 +16111,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
patternObj, startingTag(element));
}
- return validate(patternObj, value);
+ return validateRegex(patternObj, value);
};
}
@@ -16118,13 +16123,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMinlength) {
var minlength = int(attr.ngMinlength);
var minLengthValidator = function(value) {
- if (!ctrl.$isEmpty(value) && value.length < minlength) {
- ctrl.$setValidity('minlength', false);
- return undefined;
- } else {
- ctrl.$setValidity('minlength', true);
- return value;
- }
+ return validate(ctrl, 'minlength', ctrl.$isEmpty(value) || value.length >= minlength, value);
};
ctrl.$parsers.push(minLengthValidator);
@@ -16135,13 +16134,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.ngMaxlength) {
var maxlength = int(attr.ngMaxlength);
var maxLengthValidator = function(value) {
- if (!ctrl.$isEmpty(value) && value.length > maxlength) {
- ctrl.$setValidity('maxlength', false);
- return undefined;
- } else {
- ctrl.$setValidity('maxlength', true);
- return value;
- }
+ return validate(ctrl, 'maxlength', ctrl.$isEmpty(value) || value.length <= maxlength, value);
};
ctrl.$parsers.push(maxLengthValidator);
@@ -16170,13 +16163,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.min) {
var minValidator = function(value) {
var min = parseFloat(attr.min);
- if (!ctrl.$isEmpty(value) && value < min) {
- ctrl.$setValidity('min', false);
- return undefined;
- } else {
- ctrl.$setValidity('min', true);
- return value;
- }
+ return validate(ctrl, 'min', ctrl.$isEmpty(value) || value >= min, value);
};
ctrl.$parsers.push(minValidator);
@@ -16186,13 +16173,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
if (attr.max) {
var maxValidator = function(value) {
var max = parseFloat(attr.max);
- if (!ctrl.$isEmpty(value) && value > max) {
- ctrl.$setValidity('max', false);
- return undefined;
- } else {
- ctrl.$setValidity('max', true);
- return value;
- }
+ return validate(ctrl, 'max', ctrl.$isEmpty(value) || value <= max, value);
};
ctrl.$parsers.push(maxValidator);
@@ -16200,14 +16181,7 @@ function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
}
ctrl.$formatters.push(function(value) {
-
- if (ctrl.$isEmpty(value) || isNumber(value)) {
- ctrl.$setValidity('number', true);
- return value;
- } else {
- ctrl.$setValidity('number', false);
- return undefined;
- }
+ return validate(ctrl, 'number', ctrl.$isEmpty(value) || isNumber(value), value);
});
}
@@ -16215,13 +16189,7 @@ function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var urlValidator = function(value) {
- if (ctrl.$isEmpty(value) || URL_REGEXP.test(value)) {
- ctrl.$setValidity('url', true);
- return value;
- } else {
- ctrl.$setValidity('url', false);
- return undefined;
- }
+ return validate(ctrl, 'url', ctrl.$isEmpty(value) || URL_REGEXP.test(value), value);
};
ctrl.$formatters.push(urlValidator);
@@ -16232,13 +16200,7 @@ function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
textInputType(scope, element, attr, ctrl, $sniffer, $browser);
var emailValidator = function(value) {
- if (ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value)) {
- ctrl.$setValidity('email', true);
- return value;
- } else {
- ctrl.$setValidity('email', false);
- return undefined;
- }
+ return validate(ctrl, 'email', ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value), value);
};
ctrl.$formatters.push(emailValidator);
@@ -17842,13 +17804,13 @@ var ngControllerDirective = [function() {
count: {{count}}
-
+
it('should check ng-click', function() {
- expect(binding('count')).toBe('0');
- element('.doc-example-live :button').click();
- expect(binding('count')).toBe('1');
+ expect(element(by.binding('count')).getText()).toMatch('0');
+ element(by.css('.doc-example-live button')).click();
+ expect(element(by.binding('count')).getText()).toMatch('1');
});
-
+
*/
/*
@@ -18927,6 +18889,8 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
* | `$even` | {@type boolean} | true if the iterator position `$index` is even (otherwise false). |
* | `$odd` | {@type boolean} | true if the iterator position `$index` is odd (otherwise false). |
*
+ * Creating aliases for these properties is possible with {@link api/ng.directive:ngInit `ngInit`}.
+ * This may be useful when, for instance, nesting ngRepeats.
*
* # Special repeat start and end points
* To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
@@ -19809,11 +19773,9 @@ var ngSwitchWhenDirective = ngDirective({
transclude: 'element',
priority: 800,
require: '^ngSwitch',
- 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 });
- };
+ link: function(scope, element, attrs, ctrl, $transclude) {
+ ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
+ ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
}
});
@@ -19908,10 +19870,14 @@ var ngTranscludeDirective = ngDirective({
* @restrict E
*
* @description
- * Load content of a script tag, with type `text/ng-template`, into `$templateCache`, so that the
- * template can be used by `ngInclude`, `ngView` or directive templates.
+ * Load the content of a `