summaryrefslogtreecommitdiffstats
path: root/js/vendor/angular/angular.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/vendor/angular/angular.js')
-rw-r--r--js/vendor/angular/angular.js449
1 files changed, 249 insertions, 200 deletions
diff --git a/js/vendor/angular/angular.js b/js/vendor/angular/angular.js
index 32c4d1b81..d2beecf03 100644
--- a/js/vendor/angular/angular.js
+++ b/js/vendor/angular/angular.js
@@ -1,5 +1,5 @@
/**
- * @license AngularJS v1.4.0-build.3861+sha.2c4ffd6
+ * @license AngularJS v1.4.0-build.3887+sha.41fdb3d
* (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.3861+sha.2c4ffd6/' +
+ message += '\nhttp://errors.angularjs.org/1.4.0-build.3887+sha.41fdb3d/' +
(module ? module + '/' : '') + code;
for (i = SKIP_INDEXES, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
@@ -98,6 +98,7 @@ function minErr(module, ErrorConstructor) {
extend: true,
toInt: true,
inherit: true,
+ merge: true,
noop: true,
identity: true,
valueFn: true,
@@ -134,6 +135,8 @@ function minErr(module, ErrorConstructor) {
toJsonReplacer: true,
toJson: true,
fromJson: true,
+ convertTimezoneToLocal: true,
+ timezoneToOffset: true,
startingTag: true,
tryDecodeURIComponent: true,
parseKeyValue: true,
@@ -387,6 +390,31 @@ function setHashKey(obj, h) {
}
}
+
+function baseExtend(dst, objs, deep) {
+ var h = dst.$$hashKey;
+
+ for (var i = 0, ii = objs.length; i < ii; ++i) {
+ var obj = objs[i];
+ if (!isObject(obj) && !isFunction(obj)) continue;
+ var keys = Object.keys(obj);
+ for (var j = 0, jj = keys.length; j < jj; j++) {
+ var key = keys[j];
+ var src = obj[key];
+
+ if (deep && isObject(src)) {
+ if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
+ baseExtend(dst[key], [src], true);
+ } else {
+ dst[key] = src;
+ }
+ }
+ }
+
+ setHashKey(dst, h);
+ return dst;
+}
+
/**
* @ngdoc function
* @name angular.extend
@@ -397,30 +425,45 @@ function setHashKey(obj, h) {
* Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
* by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
- * Note: Keep in mind that `angular.extend` does not support recursive merge (deep copy).
+ *
+ * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
+ * {@link angular.merge} for this.
*
* @param {Object} dst Destination object.
* @param {...Object} src Source object(s).
+ * @param {boolean=} deep if the last parameter is set to `true`, objects are recursively merged
+ * (deep copy). Defaults to `false`.
* @returns {Object} Reference to `dst`.
*/
function extend(dst) {
- var h = dst.$$hashKey;
+ return baseExtend(dst, slice.call(arguments, 1), false);
+}
- for (var i = 1, ii = arguments.length; i < ii; i++) {
- var obj = arguments[i];
- if (obj) {
- var keys = Object.keys(obj);
- for (var j = 0, jj = keys.length; j < jj; j++) {
- var key = keys[j];
- dst[key] = obj[key];
- }
- }
- }
- setHashKey(dst, h);
- return dst;
+/**
+* @ngdoc function
+* @name angular.merge
+* @module ng
+* @kind function
+*
+* @description
+* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
+* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
+* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
+*
+* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
+* objects, performing a deep copy.
+*
+* @param {Object} dst Destination object.
+* @param {...Object} src Source object(s).
+* @returns {Object} Reference to `dst`.
+*/
+function merge(dst) {
+ return baseExtend(dst, slice.call(arguments, 1), true);
}
+
+
function toInt(str) {
return parseInt(str, 10);
}
@@ -547,6 +590,12 @@ function isString(value) {return typeof value === 'string';}
* @description
* Determines if a reference is a `Number`.
*
+ * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
+ *
+ * If you wish to exclude these then you can use the native
+ * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
+ * method.
+ *
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
@@ -929,10 +978,11 @@ function equals(o1, o2) {
} else if (isDate(o1)) {
if (!isDate(o2)) return false;
return equals(o1.getTime(), o2.getTime());
- } else if (isRegExp(o1) && isRegExp(o2)) {
- return o1.toString() == o2.toString();
+ } else if (isRegExp(o1)) {
+ return isRegExp(o2) ? o1.toString() == o2.toString() : false;
} else {
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(o2)) return false;
+ if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
+ isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
keySet = {};
for (key in o1) {
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
@@ -1012,18 +1062,15 @@ var csp = function() {
var jq = function() {
if (isDefined(jq.name_)) return jq.name_;
var el;
- var i, ii = ngAttrPrefixes.length;
+ var i, ii = ngAttrPrefixes.length, prefix, name;
for (i = 0; i < ii; ++i) {
- if (el = document.querySelector('[' + ngAttrPrefixes[i].replace(':', '\\:') + 'jq]')) {
+ prefix = ngAttrPrefixes[i];
+ if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
+ name = el.getAttribute(prefix + 'jq');
break;
}
}
- var name;
- if (el) {
- name = getNgAttribute(el, "jq");
- }
-
return (jq.name_ = name);
};
@@ -1136,6 +1183,26 @@ function fromJson(json) {
}
+function timezoneToOffset(timezone, fallback) {
+ var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
+ return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
+}
+
+
+function addDateMinutes(date, minutes) {
+ date = new Date(date.getTime());
+ date.setMinutes(date.getMinutes() + minutes);
+ return date;
+}
+
+
+function convertTimezoneToLocal(date, timezone, reverse) {
+ reverse = reverse ? -1 : 1;
+ var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
+ return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
+}
+
+
/**
* @returns {string} Returns the string representation of the element.
*/
@@ -1264,10 +1331,9 @@ var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
function getNgAttribute(element, ngAttr) {
var attr, i, ii = ngAttrPrefixes.length;
- element = jqLite(element);
for (i = 0; i < ii; ++i) {
attr = ngAttrPrefixes[i] + ngAttr;
- if (isString(attr = element.attr(attr))) {
+ if (isString(attr = element.getAttribute(attr))) {
return attr;
}
}
@@ -2176,7 +2242,8 @@ function toDebugString(obj) {
$$RAFProvider,
$$AsyncCallbackProvider,
$WindowProvider,
- $$jqLiteProvider
+ $$jqLiteProvider,
+ $$CookieReaderProvider
*/
@@ -2195,7 +2262,7 @@ function toDebugString(obj) {
* - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
*/
var version = {
- full: '1.4.0-build.3861+sha.2c4ffd6', // all of these placeholder strings will be replaced by grunt's
+ full: '1.4.0-build.3887+sha.41fdb3d', // all of these placeholder strings will be replaced by grunt's
major: 1, // package task
minor: 4,
dot: 0,
@@ -2208,6 +2275,7 @@ function publishExternalAPI(angular) {
'bootstrap': bootstrap,
'copy': copy,
'extend': extend,
+ 'merge': merge,
'equals': equals,
'element': jqLite,
'forEach': forEach,
@@ -2330,7 +2398,8 @@ function publishExternalAPI(angular) {
$window: $WindowProvider,
$$rAF: $$RAFProvider,
$$asyncCallback: $$AsyncCallbackProvider,
- $$jqLite: $$jqLiteProvider
+ $$jqLite: $$jqLiteProvider,
+ $$cookieReader: $$CookieReaderProvider
});
}
]);
@@ -4760,6 +4829,7 @@ var $AnimateProvider = ['$provide', function($provide) {
* @return {Promise} the animation callback promise
*/
leave: function(element, options) {
+ applyStyles(element, options);
element.remove();
return asyncPromise();
},
@@ -5004,11 +5074,6 @@ function Browser(window, document, $log, $sniffer) {
* @param {function()} callback Function that will be called when no outstanding request
*/
self.notifyWhenNoOutstandingRequests = function(callback) {
- // force browser to execute all pollFns - this is needed so that cookies and other pollers fire
- // at some deterministic time in respect to the test runner's actions. Leaving things up to the
- // regular poller would result in flaky tests.
- forEach(pollFns, function(pollFn) { pollFn(); });
-
if (outstandingRequestCount === 0) {
callback();
} else {
@@ -5017,44 +5082,6 @@ function Browser(window, document, $log, $sniffer) {
};
//////////////////////////////////////////////////////////////
- // Poll Watcher API
- //////////////////////////////////////////////////////////////
- var pollFns = [],
- pollTimeout;
-
- /**
- * @name $browser#addPollFn
- *
- * @param {function()} fn Poll function to add
- *
- * @description
- * Adds a function to the list of functions that poller periodically executes,
- * and starts polling if not started yet.
- *
- * @returns {function()} the added function
- */
- self.addPollFn = function(fn) {
- if (isUndefined(pollTimeout)) startPoller(100, setTimeout);
- pollFns.push(fn);
- return fn;
- };
-
- /**
- * @param {number} interval How often should browser call poll functions (ms)
- * @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
- *
- * @description
- * Configures the poller to run in the specified intervals, using the specified
- * setTimeout fn and kicks it off.
- */
- function startPoller(interval, setTimeout) {
- (function check() {
- forEach(pollFns, function(pollFn) { pollFn(); });
- pollTimeout = setTimeout(check, interval);
- })();
- }
-
- //////////////////////////////////////////////////////////////
// URL API
//////////////////////////////////////////////////////////////
@@ -5164,11 +5191,19 @@ function Browser(window, document, $log, $sniffer) {
fireUrlChange();
}
+ function getCurrentState() {
+ try {
+ return history.state;
+ } catch (e) {
+ // MSIE can reportedly throw when there is no state (UNCONFIRMED).
+ }
+ }
+
// This variable should be used *only* inside the cacheState function.
var lastCachedState = null;
function cacheState() {
// This should be the only place in $browser where `history.state` is read.
- cachedState = window.history.state;
+ cachedState = getCurrentState();
cachedState = isUndefined(cachedState) ? null : cachedState;
// Prevent callbacks fo fire twice if both hashchange & popstate were fired.
@@ -5255,89 +5290,6 @@ function Browser(window, document, $log, $sniffer) {
return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
};
- //////////////////////////////////////////////////////////////
- // Cookies API
- //////////////////////////////////////////////////////////////
- var lastCookies = {};
- var lastCookieString = '';
- var cookiePath = self.baseHref();
-
- function safeDecodeURIComponent(str) {
- try {
- return decodeURIComponent(str);
- } catch (e) {
- return str;
- }
- }
-
- /**
- * @name $browser#cookies
- *
- * @param {string=} name Cookie name
- * @param {string=} value Cookie value
- *
- * @description
- * The cookies method provides a 'private' low level access to browser cookies.
- * It is not meant to be used directly, use the $cookie service instead.
- *
- * The return values vary depending on the arguments that the method was called with as follows:
- *
- * - cookies() -> hash of all cookies, this is NOT a copy of the internal state, so do not modify
- * it
- * - cookies(name, value) -> set name to value, if value is undefined delete the cookie
- * - cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that
- * way)
- *
- * @returns {Object} Hash of all cookies (if called without any parameter)
- */
- self.cookies = function(name, value) {
- var cookieLength, cookieArray, cookie, i, index;
-
- if (name) {
- if (value === undefined) {
- rawDocument.cookie = encodeURIComponent(name) + "=;path=" + cookiePath +
- ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
- } else {
- if (isString(value)) {
- cookieLength = (rawDocument.cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value) +
- ';path=' + cookiePath).length + 1;
-
- // per http://www.ietf.org/rfc/rfc2109.txt browser must allow at minimum:
- // - 300 cookies
- // - 20 cookies per unique domain
- // - 4096 bytes per cookie
- if (cookieLength > 4096) {
- $log.warn("Cookie '" + name +
- "' possibly not set or overflowed because it was too large (" +
- cookieLength + " > 4096 bytes)!");
- }
- }
- }
- } else {
- if (rawDocument.cookie !== lastCookieString) {
- lastCookieString = rawDocument.cookie;
- cookieArray = lastCookieString.split("; ");
- lastCookies = {};
-
- for (i = 0; i < cookieArray.length; i++) {
- cookie = cookieArray[i];
- index = cookie.indexOf('=');
- if (index > 0) { //ignore nameless cookies
- name = safeDecodeURIComponent(cookie.substring(0, index));
- // the first value that is seen for a cookie is the most
- // specific one. values for the same cookie name that
- // follow are for less specific paths.
- if (lastCookies[name] === undefined) {
- lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
- }
- }
- }
- }
- return lastCookies;
- }
- };
-
-
/**
* @name $browser#defer
* @param {function()} fn A function, who's execution should be deferred.
@@ -6004,7 +5956,8 @@ function $TemplateCacheProvider() {
* 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
* injected argument will be an array in corresponding order. If no such directive can be
- * found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
+ * found, or if the directive does not have a controller, then an error is raised (unless no link function
+ * is specified, in which case error checking is skipped). The name can be prefixed with:
*
* * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
* * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
@@ -6139,7 +6092,7 @@ function $TemplateCacheProvider() {
* `templateUrl` declaration or manual compilation inside the compile function.
* </div>
*
- * <div class="alert alert-error">
+ * <div class="alert alert-danger">
* **Note:** The `transclude` function that is passed to the compile function is deprecated, 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.
@@ -6418,7 +6371,7 @@ function $TemplateCacheProvider() {
* @param {string|DOMElement} element Element or HTML string to compile into a template function.
* @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
*
- * <div class="alert alert-error">
+ * <div class="alert alert-danger">
* **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
* e.g. will not use the right outer scope. Please pass the transclude function as a
* `parentBoundTranscludeFn` to the link function instead.
@@ -8961,8 +8914,8 @@ function $HttpProvider() {
**/
var interceptorFactories = this.interceptors = [];
- this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
- function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
+ this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
+ function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
var defaultCache = $cacheFactory('$http');
@@ -9807,7 +9760,7 @@ function $HttpProvider() {
// send the request to the backend
if (isUndefined(cachedResp)) {
var xsrfValue = urlIsSameOrigin(config.url)
- ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
+ ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
: undefined;
if (xsrfValue) {
reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
@@ -10362,7 +10315,7 @@ function $InterpolateProvider() {
// all of these properties are undocumented for now
exp: text, //just for compatibility with regular watchers created via $watch
expressions: expressions,
- $$watchDelegate: function(scope, listener, objectEquality) {
+ $$watchDelegate: function(scope, listener) {
var lastValue;
return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
var currValue = compute(values);
@@ -10370,7 +10323,7 @@ function $InterpolateProvider() {
listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
}
lastValue = currValue;
- }, objectEquality);
+ });
}
});
}
@@ -17264,6 +17217,60 @@ function $WindowProvider() {
this.$get = valueFn(window);
}
+/**
+ * @name $$cookieReader
+ * @requires $document
+ *
+ * @description
+ * This is a private service for reading cookies used by $http and ngCookies
+ *
+ * @return {Object} a key/value map of the current cookies
+ */
+function $$CookieReader($document) {
+ var rawDocument = $document[0];
+ var lastCookies = {};
+ var lastCookieString = '';
+
+ function safeDecodeURIComponent(str) {
+ try {
+ return decodeURIComponent(str);
+ } catch (e) {
+ return str;
+ }
+ }
+
+ return function() {
+ var cookieArray, cookie, i, index, name;
+
+ if (rawDocument.cookie !== lastCookieString) {
+ lastCookieString = rawDocument.cookie;
+ cookieArray = lastCookieString.split('; ');
+ lastCookies = {};
+
+ for (i = 0; i < cookieArray.length; i++) {
+ cookie = cookieArray[i];
+ index = cookie.indexOf('=');
+ if (index > 0) { //ignore nameless cookies
+ name = safeDecodeURIComponent(cookie.substring(0, index));
+ // the first value that is seen for a cookie is the most
+ // specific one. values for the same cookie name that
+ // follow are for less specific paths.
+ if (lastCookies[name] === undefined) {
+ lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
+ }
+ }
+ }
+ }
+ return lastCookies;
+ };
+}
+
+$$CookieReader.$inject = ['$document'];
+
+function $$CookieReaderProvider() {
+ this.$get = $$CookieReader;
+}
+
/* global currencyFilter: true,
dateFilter: true,
filterFilter: true,
@@ -17466,6 +17473,9 @@ function $FilterProvider($provide) {
* - `false|undefined`: A short hand for a function which will look for a substring match in case
* insensitive way.
*
+ * Primitive values are converted to strings. Objects are not compared against primitives,
+ * unless they have a custom `toString` method (e.g. `Date` objects).
+ *
* @example
<example>
<file name="index.html">
@@ -17568,6 +17578,10 @@ function filterFilter() {
};
}
+function hasCustomToString(obj) {
+ return isFunction(obj.toString) && obj.toString !== Object.prototype.toString;
+}
+
// Helper functions for `filterFilter`
function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
@@ -17577,8 +17591,8 @@ function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
comparator = equals;
} else if (!isFunction(comparator)) {
comparator = function(actual, expected) {
- if (isObject(actual) || isObject(expected)) {
- // Prevent an object to be considered equal to a string like `'[object'`
+ if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
+ // Should not compare primitives against objects, unless they have custom `toString` method
return false;
}
@@ -17625,7 +17639,7 @@ function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatc
} else if (expectedType === 'object') {
for (key in expected) {
var expectedVal = expected[key];
- if (isFunction(expectedVal)) {
+ if (isFunction(expectedVal) || isUndefined(expectedVal)) {
continue;
}
@@ -18135,12 +18149,8 @@ function dateFilter($locale) {
var dateTimezoneOffset = date.getTimezoneOffset();
if (timezone) {
- var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
- if (!isNaN(requestedTimezoneOffset)) {
- date = new Date(date.getTime());
- date.setMinutes(date.getMinutes() + dateTimezoneOffset - requestedTimezoneOffset);
- dateTimezoneOffset = requestedTimezoneOffset;
- }
+ dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
+ date = convertTimezoneToLocal(date, timezone, true);
}
forEach(parts, function(value) {
fn = DATE_FORMATS[value];
@@ -18365,6 +18375,43 @@ function limitToFilter() {
* @param {boolean=} reverse Reverse the order of the array.
* @returns {Array} Sorted copy of the source array.
*
+ *
+ * @example
+ * The example below demonstrates a simple ngRepeat, where the data is sorted
+ * by age in descending order (predicate is set to `'-age'`).
+ * `reverse` is not set, which means it defaults to `false`.
+ <example module="orderByExample">
+ <file name="index.html">
+ <script>
+ angular.module('orderByExample', [])
+ .controller('ExampleController', ['$scope', function($scope) {
+ $scope.friends =
+ [{name:'John', phone:'555-1212', age:10},
+ {name:'Mary', phone:'555-9876', age:19},
+ {name:'Mike', phone:'555-4321', age:21},
+ {name:'Adam', phone:'555-5678', age:35},
+ {name:'Julie', phone:'555-8765', age:29}];
+ }]);
+ </script>
+ <div ng-controller="ExampleController">
+ <table class="friend">
+ <tr>
+ <th>Name</th>
+ <th>Phone Number</th>
+ <th>Age</th>
+ </tr>
+ <tr ng-repeat="friend in friends | orderBy:'-age'">
+ <td>{{friend.name}}</td>
+ <td>{{friend.phone}}</td>
+ <td>{{friend.age}}</td>
+ </tr>
+ </table>
+ </div>
+ </file>
+ </example>
+ *
+ * The predicate and reverse parameters can be controlled dynamically through scope properties,
+ * as shown in the next example.
* @example
<example module="orderByExample">
<file name="index.html">
@@ -18747,6 +18794,7 @@ var htmlAnchorDirective = valueFn({
* but not on older IEs:
*
* ```html
+ * <!-- See below for an example of ng-disabled being used correctly -->
* <div ng-init="isDisabled = false">
* <button disabled="{{isDisabled}}">Disabled</button>
* </div>
@@ -19334,7 +19382,7 @@ function FormController(element, attrs, $scope, $animate, $interpolate) {
*
* # Alias: {@link ng.directive:ngForm `ngForm`}
*
- * In Angular forms can be nested. This means that the outer form is valid when all of the child
+ * In Angular, forms can be nested. This means that the outer form is valid when all of the child
* forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
* Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
* `<form>` but can be nested. This allows you to have nested forms, which is very useful when
@@ -19472,10 +19520,12 @@ var formDirectiveFactory = function(isNgForm) {
name: 'form',
restrict: isNgForm ? 'EAC' : 'E',
controller: FormController,
- compile: function ngFormCompile(formElement) {
+ compile: function ngFormCompile(formElement, attr) {
// Setup initial state of the control
formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
+ var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
+
return {
pre: function ngFormPreLink(scope, formElement, attr, controller) {
// if `action` attr is not present on the form, prevent the default action (submission)
@@ -19506,23 +19556,21 @@ var formDirectiveFactory = function(isNgForm) {
});
}
- var parentFormCtrl = controller.$$parentForm,
- alias = controller.$name;
-
- if (alias) {
- setter(scope, alias, controller, alias);
- attr.$observe(attr.name ? 'name' : 'ngForm', function(newValue) {
- if (alias === newValue) return;
- setter(scope, alias, undefined, alias);
- alias = newValue;
- setter(scope, alias, controller, alias);
- parentFormCtrl.$$renameControl(controller, alias);
+ var parentFormCtrl = controller.$$parentForm;
+
+ if (nameAttr) {
+ setter(scope, controller.$name, controller, controller.$name);
+ attr.$observe(nameAttr, function(newValue) {
+ if (controller.$name === newValue) return;
+ setter(scope, controller.$name, undefined, controller.$name);
+ parentFormCtrl.$$renameControl(controller, newValue);
+ setter(scope, controller.$name, controller, controller.$name);
});
}
formElement.on('$destroy', function() {
parentFormCtrl.$removeControl(controller);
- if (alias) {
- setter(scope, alias, undefined, alias);
+ if (nameAttr) {
+ setter(scope, attr[nameAttr], undefined, controller.$name);
}
extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
});
@@ -20694,8 +20742,8 @@ function createDateInputType(type, regexp, parseDate, format) {
// parser/formatter in the processing chain so that the model
// contains some different data format!
var parsedDate = parseDate(value, previousDate);
- if (timezone === 'UTC') {
- parsedDate.setMinutes(parsedDate.getMinutes() - parsedDate.getTimezoneOffset());
+ if (timezone) {
+ parsedDate = convertTimezoneToLocal(parsedDate, timezone);
}
return parsedDate;
}
@@ -20708,9 +20756,8 @@ function createDateInputType(type, regexp, parseDate, format) {
}
if (isValidDate(value)) {
previousDate = value;
- if (previousDate && timezone === 'UTC') {
- var timezoneOffset = 60000 * previousDate.getTimezoneOffset();
- previousDate = new Date(previousDate.getTime() + timezoneOffset);
+ if (previousDate && timezone) {
+ previousDate = convertTimezoneToLocal(previousDate, timezone, true);
}
return $filter('date')(value, format, timezone);
} else {
@@ -23182,7 +23229,7 @@ var ngIncludeFillContentDirective = ['$compile',
* The `ngInit` directive allows you to evaluate an expression in the
* current scope.
*
- * <div class="alert alert-error">
+ * <div class="alert alert-danger">
* The only appropriate use of `ngInit` is for aliasing special properties of
* {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
* should use {@link guide/controller controllers} rather than `ngInit`
@@ -23495,8 +23542,8 @@ is set to `true`. The parse error is stored in `ngModel.$error.parse`.
* data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
* collaborate together to achieve the desired result.
*
- * Note that `contenteditable` is an HTML5 attribute, which tells the browser to let the element
- * contents be edited in place by the user. This will not work on older browsers.
+ * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
+ * contents be edited in place by the user.
*
* We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
* module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
@@ -24459,8 +24506,10 @@ var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
* - `getterSetter`: boolean value which determines whether or not to treat functions bound to
`ngModel` as getters/setters.
* - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
- * `<input type="date">`, `<input type="time">`, ... . Right now, the only supported value is `'UTC'`,
- * otherwise the default timezone of the browser will be used.
+ * `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
+ * continental US time zone abbreviations, but for general use, use a time zone offset, for
+ * example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
+ * If not specified, the timezone of the browser will be used.
*
* @example