mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
Remove var Error = window.Error window.Error is a read-only property in Apps Script. Igor says, "we should just delete that line instead. I think it was misko's attempt to get better closure minification, but it turns out that it's actually hurting us after gzip (I verified it)."
981 lines
26 KiB
JavaScript
981 lines
26 KiB
JavaScript
'use strict';
|
|
|
|
////////////////////////////////////
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.lowercase
|
|
* @function
|
|
*
|
|
* @description Converts the specified string to lowercase.
|
|
* @param {string} string String to be converted to lowercase.
|
|
* @returns {string} Lowercased string.
|
|
*/
|
|
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.uppercase
|
|
* @function
|
|
*
|
|
* @description Converts the specified string to uppercase.
|
|
* @param {string} string String to be converted to uppercase.
|
|
* @returns {string} Uppercased string.
|
|
*/
|
|
var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;};
|
|
|
|
|
|
var manualLowercase = function(s) {
|
|
return isString(s)
|
|
? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);})
|
|
: s;
|
|
};
|
|
var manualUppercase = function(s) {
|
|
return isString(s)
|
|
? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);})
|
|
: s;
|
|
};
|
|
|
|
|
|
// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
|
|
// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
|
|
// with correct but slower alternatives.
|
|
if ('i' !== 'I'.toLowerCase()) {
|
|
lowercase = manualLowercase;
|
|
uppercase = manualUppercase;
|
|
}
|
|
|
|
function fromCharCode(code) {return String.fromCharCode(code);}
|
|
|
|
|
|
var /** holds major version number for IE or NaN for real browsers */
|
|
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]),
|
|
jqLite, // delay binding since jQuery could be loaded after us.
|
|
jQuery, // delay binding
|
|
slice = [].slice,
|
|
push = [].push,
|
|
toString = Object.prototype.toString,
|
|
|
|
/** @name angular */
|
|
angular = window.angular || (window.angular = {}),
|
|
angularModule,
|
|
nodeName_,
|
|
uid = ['0', '0', '0'];
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.forEach
|
|
* @function
|
|
*
|
|
* @description
|
|
* Invokes the `iterator` function once for each item in `obj` collection, which can be either an
|
|
* object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
|
|
* is the value of an object property or an array element and `key` is the object property key or
|
|
* array element index. Specifying a `context` for the function is optional.
|
|
*
|
|
* Note: this function was previously known as `angular.foreach`.
|
|
*
|
|
<pre>
|
|
var values = {name: 'misko', gender: 'male'};
|
|
var log = [];
|
|
angular.forEach(values, function(value, key){
|
|
this.push(key + ': ' + value);
|
|
}, log);
|
|
expect(log).toEqual(['name: misko', 'gender:male']);
|
|
</pre>
|
|
*
|
|
* @param {Object|Array} obj Object to iterate over.
|
|
* @param {Function} iterator Iterator function.
|
|
* @param {Object=} context Object to become context (`this`) for the iterator function.
|
|
* @returns {Object|Array} Reference to `obj`.
|
|
*/
|
|
function forEach(obj, iterator, context) {
|
|
var key;
|
|
if (obj) {
|
|
if (isFunction(obj)){
|
|
for (key in obj) {
|
|
if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
|
|
iterator.call(context, obj[key], key);
|
|
}
|
|
}
|
|
} else if (obj.forEach && obj.forEach !== forEach) {
|
|
obj.forEach(iterator, context);
|
|
} else if (isObject(obj) && isNumber(obj.length)) {
|
|
for (key = 0; key < obj.length; key++)
|
|
iterator.call(context, obj[key], key);
|
|
} else {
|
|
for (key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
iterator.call(context, obj[key], key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function sortedKeys(obj) {
|
|
var keys = [];
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
keys.push(key);
|
|
}
|
|
}
|
|
return keys.sort();
|
|
}
|
|
|
|
function forEachSorted(obj, iterator, context) {
|
|
var keys = sortedKeys(obj);
|
|
for ( var i = 0; i < keys.length; i++) {
|
|
iterator.call(context, obj[keys[i]], keys[i]);
|
|
}
|
|
return keys;
|
|
}
|
|
|
|
|
|
/**
|
|
* when using forEach the params are value, key, but it is often useful to have key, value.
|
|
* @param {function(string, *)} iteratorFn
|
|
* @returns {function(*, string)}
|
|
*/
|
|
function reverseParams(iteratorFn) {
|
|
return function(value, key) { iteratorFn(key, value) };
|
|
}
|
|
|
|
/**
|
|
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
|
|
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
|
|
* the number string gets longer over time, and it can also overflow, where as the the nextId
|
|
* will grow much slower, it is a string, and it will never overflow.
|
|
*
|
|
* @returns an unique alpha-numeric string
|
|
*/
|
|
function nextUid() {
|
|
var index = uid.length;
|
|
var digit;
|
|
|
|
while(index) {
|
|
index--;
|
|
digit = uid[index].charCodeAt(0);
|
|
if (digit == 57 /*'9'*/) {
|
|
uid[index] = 'A';
|
|
return uid.join('');
|
|
}
|
|
if (digit == 90 /*'Z'*/) {
|
|
uid[index] = '0';
|
|
} else {
|
|
uid[index] = String.fromCharCode(digit + 1);
|
|
return uid.join('');
|
|
}
|
|
}
|
|
uid.unshift('0');
|
|
return uid.join('');
|
|
}
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.extend
|
|
* @function
|
|
*
|
|
* @description
|
|
* Extends the destination object `dst` by copying all of the properties from the `src` object(s)
|
|
* to `dst`. You can specify multiple `src` objects.
|
|
*
|
|
* @param {Object} dst Destination object.
|
|
* @param {...Object} src Source object(s).
|
|
*/
|
|
function extend(dst) {
|
|
forEach(arguments, function(obj){
|
|
if (obj !== dst) {
|
|
forEach(obj, function(value, key){
|
|
dst[key] = value;
|
|
});
|
|
}
|
|
});
|
|
return dst;
|
|
}
|
|
|
|
function int(str) {
|
|
return parseInt(str, 10);
|
|
}
|
|
|
|
|
|
function inherit(parent, extra) {
|
|
return extend(new (extend(function() {}, {prototype:parent}))(), extra);
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.noop
|
|
* @function
|
|
*
|
|
* @description
|
|
* A function that performs no operations. This function can be useful when writing code in the
|
|
* functional style.
|
|
<pre>
|
|
function foo(callback) {
|
|
var result = calculateResult();
|
|
(callback || angular.noop)(result);
|
|
}
|
|
</pre>
|
|
*/
|
|
function noop() {}
|
|
noop.$inject = [];
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.identity
|
|
* @function
|
|
*
|
|
* @description
|
|
* A function that returns its first argument. This function is useful when writing code in the
|
|
* functional style.
|
|
*
|
|
<pre>
|
|
function transformer(transformationFn, value) {
|
|
return (transformationFn || identity)(value);
|
|
};
|
|
</pre>
|
|
*/
|
|
function identity($) {return $;}
|
|
identity.$inject = [];
|
|
|
|
|
|
function valueFn(value) {return function() {return value;};}
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isUndefined
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is undefined.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is undefined.
|
|
*/
|
|
function isUndefined(value){return typeof value == 'undefined';}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isDefined
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is defined.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is defined.
|
|
*/
|
|
function isDefined(value){return typeof value != 'undefined';}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isObject
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
|
|
* considered to be objects.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is an `Object` but not `null`.
|
|
*/
|
|
function isObject(value){return value != null && typeof value == 'object';}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isString
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is a `String`.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is a `String`.
|
|
*/
|
|
function isString(value){return typeof value == 'string';}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isNumber
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is a `Number`.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is a `Number`.
|
|
*/
|
|
function isNumber(value){return typeof value == 'number';}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isDate
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a value is a date.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is a `Date`.
|
|
*/
|
|
function isDate(value){
|
|
return toString.apply(value) == '[object Date]';
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isArray
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is an `Array`.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is an `Array`.
|
|
*/
|
|
function isArray(value) {
|
|
return toString.apply(value) == '[object Array]';
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isFunction
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is a `Function`.
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is a `Function`.
|
|
*/
|
|
function isFunction(value){return typeof value == 'function';}
|
|
|
|
|
|
/**
|
|
* Checks if `obj` is a window object.
|
|
*
|
|
* @private
|
|
* @param {*} obj Object to check
|
|
* @returns {boolean} True if `obj` is a window obj.
|
|
*/
|
|
function isWindow(obj) {
|
|
return obj && obj.document && obj.location && obj.alert && obj.setInterval;
|
|
}
|
|
|
|
|
|
function isScope(obj) {
|
|
return obj && obj.$evalAsync && obj.$watch;
|
|
}
|
|
|
|
|
|
function isFile(obj) {
|
|
return toString.apply(obj) === '[object File]';
|
|
}
|
|
|
|
|
|
function isBoolean(value) {
|
|
return typeof value == 'boolean';
|
|
}
|
|
|
|
|
|
function trim(value) {
|
|
return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
|
|
}
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.isElement
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if a reference is a DOM element (or wrapped jQuery element).
|
|
*
|
|
* @param {*} value Reference to check.
|
|
* @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
|
|
*/
|
|
function isElement(node) {
|
|
return node &&
|
|
(node.nodeName // we are a direct element
|
|
|| (node.bind && node.find)); // we have a bind and find method part of jQuery API
|
|
}
|
|
|
|
/**
|
|
* @param str 'key1,key2,...'
|
|
* @returns {object} in the form of {key1:true, key2:true, ...}
|
|
*/
|
|
function makeMap(str){
|
|
var obj = {}, items = str.split(","), i;
|
|
for ( i = 0; i < items.length; i++ )
|
|
obj[ items[i] ] = true;
|
|
return obj;
|
|
}
|
|
|
|
|
|
if (msie < 9) {
|
|
nodeName_ = function(element) {
|
|
element = element.nodeName ? element : element[0];
|
|
return (element.scopeName && element.scopeName != 'HTML')
|
|
? uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
|
|
};
|
|
} else {
|
|
nodeName_ = function(element) {
|
|
return element.nodeName ? element.nodeName : element[0].nodeName;
|
|
};
|
|
}
|
|
|
|
|
|
function map(obj, iterator, context) {
|
|
var results = [];
|
|
forEach(obj, function(value, index, list) {
|
|
results.push(iterator.call(context, value, index, list));
|
|
});
|
|
return results;
|
|
}
|
|
|
|
|
|
/**
|
|
* @description
|
|
* Determines the number of elements in an array, the number of properties an object has, or
|
|
* the length of a string.
|
|
*
|
|
* Note: This function is used to augment the Object type in Angular expressions. See
|
|
* {@link angular.Object} for more information about Angular arrays.
|
|
*
|
|
* @param {Object|Array|string} obj Object, array, or string to inspect.
|
|
* @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
|
|
* @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
|
|
*/
|
|
function size(obj, ownPropsOnly) {
|
|
var size = 0, key;
|
|
|
|
if (isArray(obj) || isString(obj)) {
|
|
return obj.length;
|
|
} else if (isObject(obj)){
|
|
for (key in obj)
|
|
if (!ownPropsOnly || obj.hasOwnProperty(key))
|
|
size++;
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
|
|
function includes(array, obj) {
|
|
return indexOf(array, obj) != -1;
|
|
}
|
|
|
|
function indexOf(array, obj) {
|
|
if (array.indexOf) return array.indexOf(obj);
|
|
|
|
for ( var i = 0; i < array.length; i++) {
|
|
if (obj === array[i]) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
function arrayRemove(array, value) {
|
|
var index = indexOf(array, value);
|
|
if (index >=0)
|
|
array.splice(index, 1);
|
|
return value;
|
|
}
|
|
|
|
function isLeafNode (node) {
|
|
if (node) {
|
|
switch (node.nodeName) {
|
|
case "OPTION":
|
|
case "PRE":
|
|
case "TITLE":
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.copy
|
|
* @function
|
|
*
|
|
* @description
|
|
* Creates a deep copy of `source`, which should be an object or an array.
|
|
*
|
|
* * If no destination is supplied, a copy of the object or array is created.
|
|
* * If a destination is provided, all of its elements (for array) or properties (for objects)
|
|
* are deleted and then all elements/properties from the source are copied to it.
|
|
* * If `source` is not an object or array, `source` is returned.
|
|
*
|
|
* Note: this function is used to augment the Object type in Angular expressions. See
|
|
* {@link ng.$filter} for more information about Angular arrays.
|
|
*
|
|
* @param {*} source The source that will be used to make a copy.
|
|
* Can be any type, including primitives, `null`, and `undefined`.
|
|
* @param {(Object|Array)=} destination Destination into which the source is copied. If
|
|
* provided, must be of the same type as `source`.
|
|
* @returns {*} The copy or updated `destination`, if `destination` was specified.
|
|
*/
|
|
function copy(source, destination){
|
|
if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope");
|
|
if (!destination) {
|
|
destination = source;
|
|
if (source) {
|
|
if (isArray(source)) {
|
|
destination = copy(source, []);
|
|
} else if (isDate(source)) {
|
|
destination = new Date(source.getTime());
|
|
} else if (isObject(source)) {
|
|
destination = copy(source, {});
|
|
}
|
|
}
|
|
} else {
|
|
if (source === destination) throw Error("Can't copy equivalent objects or arrays");
|
|
if (isArray(source)) {
|
|
while(destination.length) {
|
|
destination.pop();
|
|
}
|
|
for ( var i = 0; i < source.length; i++) {
|
|
destination.push(copy(source[i]));
|
|
}
|
|
} else {
|
|
forEach(destination, function(value, key){
|
|
delete destination[key];
|
|
});
|
|
for ( var key in source) {
|
|
destination[key] = copy(source[key]);
|
|
}
|
|
}
|
|
}
|
|
return destination;
|
|
}
|
|
|
|
/**
|
|
* Create a shallow copy of an object
|
|
*/
|
|
function shallowCopy(src, dst) {
|
|
dst = dst || {};
|
|
|
|
for(var key in src) {
|
|
if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
|
|
dst[key] = src[key];
|
|
}
|
|
}
|
|
|
|
return dst;
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.equals
|
|
* @function
|
|
*
|
|
* @description
|
|
* Determines if two objects or two values are equivalent. Supports value types, arrays and
|
|
* objects.
|
|
*
|
|
* Two objects or values are considered equivalent if at least one of the following is true:
|
|
*
|
|
* * Both objects or values pass `===` comparison.
|
|
* * Both objects or values are of the same type and all of their properties pass `===` comparison.
|
|
* * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
|
|
*
|
|
* During a property comparision, properties of `function` type and properties with names
|
|
* that begin with `$` are ignored.
|
|
*
|
|
* Scope and DOMWindow objects are being compared only be identify (`===`).
|
|
*
|
|
* @param {*} o1 Object or value to compare.
|
|
* @param {*} o2 Object or value to compare.
|
|
* @returns {boolean} True if arguments are equal.
|
|
*/
|
|
function equals(o1, o2) {
|
|
if (o1 === o2) return true;
|
|
if (o1 === null || o2 === null) return false;
|
|
if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
|
|
var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
|
|
if (t1 == t2) {
|
|
if (t1 == 'object') {
|
|
if (isArray(o1)) {
|
|
if ((length = o1.length) == o2.length) {
|
|
for(key=0; key<length; key++) {
|
|
if (!equals(o1[key], o2[key])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
} else if (isDate(o1)) {
|
|
return isDate(o2) && o1.getTime() == o2.getTime();
|
|
} else {
|
|
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2)) return false;
|
|
keySet = {};
|
|
for(key in o1) {
|
|
if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
|
|
if (!equals(o1[key], o2[key])) return false;
|
|
keySet[key] = true;
|
|
}
|
|
for(key in o2) {
|
|
if (!keySet[key] &&
|
|
key.charAt(0) !== '$' &&
|
|
o2[key] !== undefined &&
|
|
!isFunction(o2[key])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function concat(array1, array2, index) {
|
|
return array1.concat(slice.call(array2, index));
|
|
}
|
|
|
|
function sliceArgs(args, startIndex) {
|
|
return slice.call(args, startIndex || 0);
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.bind
|
|
* @function
|
|
*
|
|
* @description
|
|
* Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
|
|
* `fn`). You can supply optional `args` that are are prebound to the function. This feature is also
|
|
* known as [function currying](http://en.wikipedia.org/wiki/Currying).
|
|
*
|
|
* @param {Object} self Context which `fn` should be evaluated in.
|
|
* @param {function()} fn Function to be bound.
|
|
* @param {...*} args Optional arguments to be prebound to the `fn` function call.
|
|
* @returns {function()} Function that wraps the `fn` with all the specified bindings.
|
|
*/
|
|
function bind(self, fn) {
|
|
var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
|
|
if (isFunction(fn) && !(fn instanceof RegExp)) {
|
|
return curryArgs.length
|
|
? function() {
|
|
return arguments.length
|
|
? fn.apply(self, curryArgs.concat(slice.call(arguments, 0)))
|
|
: fn.apply(self, curryArgs);
|
|
}
|
|
: function() {
|
|
return arguments.length
|
|
? fn.apply(self, arguments)
|
|
: fn.call(self);
|
|
};
|
|
} else {
|
|
// in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
|
|
return fn;
|
|
}
|
|
}
|
|
|
|
|
|
function toJsonReplacer(key, value) {
|
|
var val = value;
|
|
|
|
if (/^\$+/.test(key)) {
|
|
val = undefined;
|
|
} else if (isWindow(value)) {
|
|
val = '$WINDOW';
|
|
} else if (value && document === value) {
|
|
val = '$DOCUMENT';
|
|
} else if (isScope(value)) {
|
|
val = '$SCOPE';
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.toJson
|
|
* @function
|
|
*
|
|
* @description
|
|
* Serializes input into a JSON-formatted string.
|
|
*
|
|
* @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
|
|
* @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
|
|
* @returns {string} Jsonified string representing `obj`.
|
|
*/
|
|
function toJson(obj, pretty) {
|
|
return JSON.stringify(obj, toJsonReplacer, pretty ? ' ' : null);
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.fromJson
|
|
* @function
|
|
*
|
|
* @description
|
|
* Deserializes a JSON string.
|
|
*
|
|
* @param {string} json JSON string to deserialize.
|
|
* @returns {Object|Array|Date|string|number} Deserialized thingy.
|
|
*/
|
|
function fromJson(json) {
|
|
return isString(json)
|
|
? JSON.parse(json)
|
|
: json;
|
|
}
|
|
|
|
|
|
function toBoolean(value) {
|
|
if (value && value.length !== 0) {
|
|
var v = lowercase("" + value);
|
|
value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
|
|
} else {
|
|
value = false;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* @returns {string} Returns the string representation of the element.
|
|
*/
|
|
function startingTag(element) {
|
|
element = jqLite(element).clone();
|
|
try {
|
|
// turns out IE does not let you set .html() on elements which
|
|
// are not allowed to have children. So we just ignore it.
|
|
element.html('');
|
|
} catch(e) {}
|
|
return jqLite('<div>').append(element).html().
|
|
match(/^(<[^>]+>)/)[1].
|
|
replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Parses an escaped url query string into key-value pairs.
|
|
* @returns Object.<(string|boolean)>
|
|
*/
|
|
function parseKeyValue(/**string*/keyValue) {
|
|
var obj = {}, key_value, key;
|
|
forEach((keyValue || "").split('&'), function(keyValue){
|
|
if (keyValue) {
|
|
key_value = keyValue.split('=');
|
|
key = decodeURIComponent(key_value[0]);
|
|
obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
|
|
}
|
|
});
|
|
return obj;
|
|
}
|
|
|
|
function toKeyValue(obj) {
|
|
var parts = [];
|
|
forEach(obj, function(value, key) {
|
|
parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
|
|
});
|
|
return parts.length ? parts.join('&') : '';
|
|
}
|
|
|
|
|
|
/**
|
|
* We need our custom method because encodeURIComponent is too agressive and doesn't follow
|
|
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
|
|
* segments:
|
|
* segment = *pchar
|
|
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
* pct-encoded = "%" HEXDIG HEXDIG
|
|
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
|
* / "*" / "+" / "," / ";" / "="
|
|
*/
|
|
function encodeUriSegment(val) {
|
|
return encodeUriQuery(val, true).
|
|
replace(/%26/gi, '&').
|
|
replace(/%3D/gi, '=').
|
|
replace(/%2B/gi, '+');
|
|
}
|
|
|
|
|
|
/**
|
|
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
|
* method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
|
|
* encoded per http://tools.ietf.org/html/rfc3986:
|
|
* query = *( pchar / "/" / "?" )
|
|
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
* pct-encoded = "%" HEXDIG HEXDIG
|
|
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
|
* / "*" / "+" / "," / ";" / "="
|
|
*/
|
|
function encodeUriQuery(val, pctEncodeSpaces) {
|
|
return encodeURIComponent(val).
|
|
replace(/%40/gi, '@').
|
|
replace(/%3A/gi, ':').
|
|
replace(/%24/g, '$').
|
|
replace(/%2C/gi, ',').
|
|
replace((pctEncodeSpaces ? null : /%20/g), '+');
|
|
}
|
|
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ng.directive:ngApp
|
|
*
|
|
* @element ANY
|
|
* @param {angular.Module} ngApp an optional application
|
|
* {@link angular.module module} name to load.
|
|
*
|
|
* @description
|
|
*
|
|
* Use this directive to auto-bootstrap on application. Only
|
|
* one directive can be used per HTML document. The directive
|
|
* designates the root of the application and is typically placed
|
|
* ot the root of the page.
|
|
*
|
|
* In the example below if the `ngApp` directive would not be placed
|
|
* on the `html` element then the document would not be compiled
|
|
* and the `{{ 1+2 }}` would not be resolved to `3`.
|
|
*
|
|
* `ngApp` is the easiest way to bootstrap an application.
|
|
*
|
|
<doc:example>
|
|
<doc:source>
|
|
I can add: 1 + 2 = {{ 1+2 }}
|
|
</doc:source>
|
|
</doc:example>
|
|
*
|
|
*/
|
|
function angularInit(element, bootstrap) {
|
|
var elements = [element],
|
|
appElement,
|
|
module,
|
|
names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
|
|
NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
|
|
|
|
function append(element) {
|
|
element && elements.push(element);
|
|
}
|
|
|
|
forEach(names, function(name) {
|
|
names[name] = true;
|
|
append(document.getElementById(name));
|
|
name = name.replace(':', '\\:');
|
|
if (element.querySelectorAll) {
|
|
forEach(element.querySelectorAll('.' + name), append);
|
|
forEach(element.querySelectorAll('.' + name + '\\:'), append);
|
|
forEach(element.querySelectorAll('[' + name + ']'), append);
|
|
}
|
|
});
|
|
|
|
forEach(elements, function(element) {
|
|
if (!appElement) {
|
|
var className = ' ' + element.className + ' ';
|
|
var match = NG_APP_CLASS_REGEXP.exec(className);
|
|
if (match) {
|
|
appElement = element;
|
|
module = (match[2] || '').replace(/\s+/g, ',');
|
|
} else {
|
|
forEach(element.attributes, function(attr) {
|
|
if (!appElement && names[attr.name]) {
|
|
appElement = element;
|
|
module = attr.value;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
if (appElement) {
|
|
bootstrap(appElement, module ? [module] : []);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @ngdoc function
|
|
* @name angular.bootstrap
|
|
* @description
|
|
* Use this function to manually start up angular application.
|
|
*
|
|
* See: {@link guide/bootstrap Bootstrap}
|
|
*
|
|
* @param {Element} element DOM element which is the root of angular application.
|
|
* @param {Array<String|Function>=} modules an array of module declarations. See: {@link angular.module modules}
|
|
* @returns {AUTO.$injector} Returns the newly created injector for this app.
|
|
*/
|
|
function bootstrap(element, modules) {
|
|
element = jqLite(element);
|
|
modules = modules || [];
|
|
modules.unshift(['$provide', function($provide) {
|
|
$provide.value('$rootElement', element);
|
|
}]);
|
|
modules.unshift('ng');
|
|
var injector = createInjector(modules);
|
|
injector.invoke(
|
|
['$rootScope', '$rootElement', '$compile', '$injector', function(scope, element, compile, injector){
|
|
scope.$apply(function() {
|
|
element.data('$injector', injector);
|
|
compile(element)(scope);
|
|
});
|
|
}]
|
|
);
|
|
return injector;
|
|
}
|
|
|
|
var SNAKE_CASE_REGEXP = /[A-Z]/g;
|
|
function snake_case(name, separator){
|
|
separator = separator || '_';
|
|
return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
|
|
return (pos ? separator : '') + letter.toLowerCase();
|
|
});
|
|
}
|
|
|
|
function bindJQuery() {
|
|
// bind to jQuery if present;
|
|
jQuery = window.jQuery;
|
|
// reset to jQuery or default to us.
|
|
if (jQuery) {
|
|
jqLite = jQuery;
|
|
extend(jQuery.fn, {
|
|
scope: JQLitePrototype.scope,
|
|
controller: JQLitePrototype.controller,
|
|
injector: JQLitePrototype.injector,
|
|
inheritedData: JQLitePrototype.inheritedData
|
|
});
|
|
JQLitePatchJQueryRemove('remove', true);
|
|
JQLitePatchJQueryRemove('empty');
|
|
JQLitePatchJQueryRemove('html');
|
|
} else {
|
|
jqLite = JQLite;
|
|
}
|
|
angular.element = jqLite;
|
|
}
|
|
|
|
/**
|
|
* throw error of the argument is falsy.
|
|
*/
|
|
function assertArg(arg, name, reason) {
|
|
if (!arg) {
|
|
throw new Error("Argument '" + (name || '?') + "' is " + (reason || "required"));
|
|
}
|
|
return arg;
|
|
}
|
|
|
|
function assertArgFn(arg, name, acceptArrayAnnotation) {
|
|
if (acceptArrayAnnotation && isArray(arg)) {
|
|
arg = arg[arg.length - 1];
|
|
}
|
|
|
|
assertArg(isFunction(arg), name, 'not a function, got ' +
|
|
(arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
|
|
return arg;
|
|
}
|