diff options
author | Bernhard Posselt <dev@bernhard-posselt.com> | 2014-03-14 10:22:09 +0100 |
---|---|---|
committer | Bernhard Posselt <dev@bernhard-posselt.com> | 2014-03-26 01:34:31 +0100 |
commit | 2fc5ca4f601174a7ecb7c77a7059f5fac2ab4611 (patch) | |
tree | aa7ab66e29fc7de98533d1e55832ca4fbcd39611 /js/vendor/angular/angular.js | |
parent | 22fc777ce7403d706649cf83bb23010dfd7dea04 (diff) |
update a lot of stuff, WIP
Diffstat (limited to 'js/vendor/angular/angular.js')
-rw-r--r--[-rwxr-xr-x] | js/vendor/angular/angular.js | 16195 |
1 files changed, 11045 insertions, 5150 deletions
diff --git a/js/vendor/angular/angular.js b/js/vendor/angular/angular.js index 719bc648e..83146684b 100755..100644 --- a/js/vendor/angular/angular.js +++ b/js/vendor/angular/angular.js @@ -1,16 +1,190 @@ /** - * @license AngularJS v1.0.8 - * (c) 2010-2012 Google, Inc. http://angularjs.org + * @license AngularJS v1.2.14 + * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ -(function(window, document, undefined) { -'use strict'; +(function(window, document, undefined) {'use strict'; + +/** + * @description + * + * This object provides a utility for producing rich Error messages within + * Angular. It can be called as follows: + * + * var exampleMinErr = minErr('example'); + * throw exampleMinErr('one', 'This {0} is {1}', foo, bar); + * + * The above creates an instance of minErr in the example namespace. The + * resulting error will have a namespaced error code of example.one. The + * resulting error will replace {0} with the value of foo, and {1} with the + * value of bar. The object is not restricted in the number of arguments it can + * take. + * + * If fewer arguments are specified than necessary for interpolation, the extra + * interpolation markers will be preserved in the final string. + * + * Since data will be parsed statically during a build step, some restrictions + * are applied with respect to how minErr instances are created and called. + * Instances should have names of the form namespaceMinErr for a minErr created + * using minErr('namespace') . Error codes, namespaces and template strings + * should all be static strings, not variables or general expressions. + * + * @param {string} module The namespace to use for the new minErr instance. + * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance + */ + +function minErr(module) { + return function () { + var code = arguments[0], + prefix = '[' + (module ? module + ':' : '') + code + '] ', + template = arguments[1], + templateArgs = arguments, + stringify = function (obj) { + if (typeof obj === 'function') { + return obj.toString().replace(/ \{[\s\S]*$/, ''); + } else if (typeof obj === 'undefined') { + return 'undefined'; + } else if (typeof obj !== 'string') { + return JSON.stringify(obj); + } + return obj; + }, + message, i; + + 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 (typeof arg === 'function') { + return arg.toString().replace(/ ?\{[\s\S]*$/, ''); + } else if (typeof arg === 'undefined') { + return 'undefined'; + } else if (typeof arg !== 'string') { + return toJson(arg); + } + return arg; + } + return match; + }); + + message = message + '\nhttp://errors.angularjs.org/1.2.14/' + + (module ? module + '/' : '') + code; + for (i = 2; i < arguments.length; i++) { + message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' + + encodeURIComponent(stringify(arguments[i])); + } + + return new Error(message); + }; +} + +/* We need to tell jshint what variables are being exported */ +/* global + -angular, + -msie, + -jqLite, + -jQuery, + -slice, + -push, + -toString, + -ngMinErr, + -_angular, + -angularModule, + -nodeName_, + -uid, + + -lowercase, + -uppercase, + -manualLowercase, + -manualUppercase, + -nodeName_, + -isArrayLike, + -forEach, + -sortedKeys, + -forEachSorted, + -reverseParams, + -nextUid, + -setHashKey, + -extend, + -int, + -inherit, + -noop, + -identity, + -valueFn, + -isUndefined, + -isDefined, + -isObject, + -isString, + -isNumber, + -isDate, + -isArray, + -isFunction, + -isRegExp, + -isWindow, + -isScope, + -isFile, + -isBoolean, + -trim, + -isElement, + -makeMap, + -map, + -size, + -includes, + -indexOf, + -arrayRemove, + -isLeafNode, + -copy, + -shallowCopy, + -equals, + -csp, + -concat, + -sliceArgs, + -bind, + -toJsonReplacer, + -toJson, + -fromJson, + -toBoolean, + -startingTag, + -tryDecodeURIComponent, + -parseKeyValue, + -toKeyValue, + -encodeUriSegment, + -encodeUriQuery, + -angularInit, + -bootstrap, + -snake_case, + -bindJQuery, + -assertArg, + -assertArgFn, + -assertNotHasOwnProperty, + -getter, + -getBlockElements, + -hasOwnProperty, + +*/ //////////////////////////////////// /** + * @ngdoc module + * @name ng + * @module ng + * @description + * + * # ng (core module) + * The ng module is loaded by default when an AngularJS application is started. The module itself + * contains the essential components for an AngularJS application to function. The table below + * lists a high level breakdown of each of the services/factories, filters, directives and testing + * components available within this core module. + * + * <div doc-module-components="ng"></div> + */ + +/** * @ngdoc function * @name angular.lowercase + * @module ng * @function * * @description Converts the specified string to lowercase. @@ -18,11 +192,12 @@ * @returns {string} Lowercased string. */ var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; - +var hasOwnProperty = Object.prototype.hasOwnProperty; /** * @ngdoc function * @name angular.uppercase + * @module ng * @function * * @description Converts the specified string to uppercase. @@ -33,11 +208,13 @@ var uppercase = function(string){return isString(string) ? string.toUpperCase() var manualLowercase = function(s) { + /* jshint bitwise: false */ return isString(s) ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { + /* jshint bitwise: false */ return isString(s) ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);}) : s; @@ -54,45 +231,57 @@ if ('i' !== 'I'.toLowerCase()) { var /** holds major version number for IE or NaN for real browsers */ - msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]), + msie, jqLite, // delay binding since jQuery could be loaded after us. jQuery, // delay binding slice = [].slice, push = [].push, toString = Object.prototype.toString, + ngMinErr = minErr('ng'), + + _angular = window.angular, /** @name angular */ angular = window.angular || (window.angular = {}), angularModule, nodeName_, uid = ['0', '0', '0']; +/** + * IE 11 changed the format of the UserAgent string. + * See http://msdn.microsoft.com/en-us/library/ms537503.aspx + */ +msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +if (isNaN(msie)) { + msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]); +} + /** * @private * @param {*} obj - * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...) + * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, + * String ...) */ function isArrayLike(obj) { - if (!obj || (typeof obj.length !== 'number')) return false; + if (obj == null || isWindow(obj)) { + return false; + } + + var length = obj.length; - // We have on object which has length property. Should we treat it as array? - if (typeof obj.hasOwnProperty != 'function' && - typeof obj.constructor != 'function') { - // This is here for IE8: it is a bogus object treat it as array; + if (obj.nodeType === 1 && length) { return true; - } else { - return obj instanceof JQLite || // JQLite - (jQuery && obj instanceof jQuery) || // jQuery - toString.call(obj) !== '[object Object]' || // some browser native object - typeof obj.callee === 'function'; // arguments (on IE8 looks like regular obj) } -} + return isString(obj) || isArray(obj) || length === 0 || + typeof length === 'number' && length > 0 && (length - 1) in obj; +} /** * @ngdoc function * @name angular.forEach + * @module ng * @function * * @description @@ -101,16 +290,17 @@ function isArrayLike(obj) { * 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`. + * It is worth noting that `.forEach` does not iterate over inherited properties because it filters + * using the `hasOwnProperty` method. * - <pre> + ```js 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> + expect(log).toEqual(['name: misko', 'gender: male']); + ``` * * @param {Object|Array} obj Object to iterate over. * @param {Function} iterator Iterator function. @@ -122,7 +312,9 @@ function forEach(obj, iterator, context) { if (obj) { if (isFunction(obj)){ for (key in obj) { - if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) { + // Need to check if hasOwnProperty exists, + // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function + if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) { iterator.call(context, obj[key], key); } } @@ -167,7 +359,7 @@ function forEachSorted(obj, iterator, context) { * @returns {function(*, string)} */ function reverseParams(iteratorFn) { - return function(value, key) { iteratorFn(key, value) }; + return function(value, key) { iteratorFn(key, value); }; } /** @@ -176,7 +368,7 @@ function reverseParams(iteratorFn) { * the number string gets longer over time, and it can also overflow, where as the nextId * will grow much slower, it is a string, and it will never overflow. * - * @returns an unique alpha-numeric string + * @returns {string} an unique alpha-numeric string */ function nextUid() { var index = uid.length; @@ -203,7 +395,7 @@ function nextUid() { /** * Set or clear the hashkey for an object. - * @param obj object + * @param obj object * @param h the hashkey (!truthy to delete the hashkey) */ function setHashKey(obj, h) { @@ -218,6 +410,7 @@ function setHashKey(obj, h) { /** * @ngdoc function * @name angular.extend + * @module ng * @function * * @description @@ -251,21 +444,21 @@ function inherit(parent, extra) { return extend(new (extend(function() {}, {prototype:parent}))(), extra); } - /** * @ngdoc function * @name angular.noop + * @module ng * @function * * @description * A function that performs no operations. This function can be useful when writing code in the * functional style. - <pre> + ```js function foo(callback) { var result = calculateResult(); (callback || angular.noop)(result); } - </pre> + ``` */ function noop() {} noop.$inject = []; @@ -274,17 +467,18 @@ noop.$inject = []; /** * @ngdoc function * @name angular.identity + * @module ng * @function * * @description * A function that returns its first argument. This function is useful when writing code in the * functional style. * - <pre> + ```js function transformer(transformationFn, value) { return (transformationFn || angular.identity)(value); }; - </pre> + ``` */ function identity($) {return $;} identity.$inject = []; @@ -295,6 +489,7 @@ function valueFn(value) {return function() {return value;};} /** * @ngdoc function * @name angular.isUndefined + * @module ng * @function * * @description @@ -303,12 +498,13 @@ function valueFn(value) {return function() {return value;};} * @param {*} value Reference to check. * @returns {boolean} True if `value` is undefined. */ -function isUndefined(value){return typeof value == 'undefined';} +function isUndefined(value){return typeof value === 'undefined';} /** * @ngdoc function * @name angular.isDefined + * @module ng * @function * * @description @@ -317,27 +513,29 @@ function isUndefined(value){return typeof value == 'undefined';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is defined. */ -function isDefined(value){return typeof value != 'undefined';} +function isDefined(value){return typeof value !== 'undefined';} /** * @ngdoc function * @name angular.isObject + * @module ng * @function * * @description * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not - * considered to be objects. + * considered to be objects. Note that JavaScript arrays are 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';} +function isObject(value){return value != null && typeof value === 'object';} /** * @ngdoc function * @name angular.isString + * @module ng * @function * * @description @@ -346,12 +544,13 @@ function isObject(value){return value != null && typeof value == 'object';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `String`. */ -function isString(value){return typeof value == 'string';} +function isString(value){return typeof value === 'string';} /** * @ngdoc function * @name angular.isNumber + * @module ng * @function * * @description @@ -360,12 +559,13 @@ function isString(value){return typeof value == 'string';} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Number`. */ -function isNumber(value){return typeof value == 'number';} +function isNumber(value){return typeof value === 'number';} /** * @ngdoc function * @name angular.isDate + * @module ng * @function * * @description @@ -375,13 +575,14 @@ function isNumber(value){return typeof value == 'number';} * @returns {boolean} True if `value` is a `Date`. */ function isDate(value){ - return toString.apply(value) == '[object Date]'; + return toString.call(value) === '[object Date]'; } /** * @ngdoc function * @name angular.isArray + * @module ng * @function * * @description @@ -391,13 +592,14 @@ function isDate(value){ * @returns {boolean} True if `value` is an `Array`. */ function isArray(value) { - return toString.apply(value) == '[object Array]'; + return toString.call(value) === '[object Array]'; } /** * @ngdoc function * @name angular.isFunction + * @module ng * @function * * @description @@ -406,7 +608,7 @@ function isArray(value) { * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Function`. */ -function isFunction(value){return typeof value == 'function';} +function isFunction(value){return typeof value === 'function';} /** @@ -417,7 +619,7 @@ function isFunction(value){return typeof value == 'function';} * @returns {boolean} True if `value` is a `RegExp`. */ function isRegExp(value) { - return toString.apply(value) == '[object RegExp]'; + return toString.call(value) === '[object RegExp]'; } @@ -439,12 +641,12 @@ function isScope(obj) { function isFile(obj) { - return toString.apply(obj) === '[object File]'; + return toString.call(obj) === '[object File]'; } function isBoolean(value) { - return typeof value == 'boolean'; + return typeof value === 'boolean'; } @@ -454,7 +656,7 @@ var trim = (function() { // TODO: we should move this into IE/ES5 polyfill if (!String.prototype.trim) { return function(value) { - return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; + return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value; }; } return function(value) { @@ -466,6 +668,7 @@ var trim = (function() { /** * @ngdoc function * @name angular.isElement + * @module ng * @function * * @description @@ -475,9 +678,9 @@ var trim = (function() { * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element). */ function isElement(node) { - return 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 + || (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API } /** @@ -527,17 +730,17 @@ function map(obj, iterator, context) { * @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; + var count = 0, key; if (isArray(obj) || isString(obj)) { return obj.length; } else if (isObject(obj)){ for (key in obj) if (!ownPropsOnly || obj.hasOwnProperty(key)) - size++; + count++; } - return size; + return count; } @@ -548,7 +751,7 @@ function includes(array, obj) { function indexOf(array, obj) { if (array.indexOf) return array.indexOf(obj); - for ( var i = 0; i < array.length; i++) { + for (var i = 0; i < array.length; i++) { if (obj === array[i]) return i; } return -1; @@ -576,6 +779,7 @@ function isLeafNode (node) { /** * @ngdoc function * @name angular.copy + * @module ng * @function * * @description @@ -584,19 +788,57 @@ function isLeafNode (node) { * * 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. + * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned. + * * If `source` is identical to 'destination' an exception will be thrown. * * @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. + * + * @example + <example> + <file name="index.html"> + <div ng-controller="Controller"> + <form novalidate class="simple-form"> + Name: <input type="text" ng-model="user.name" /><br /> + E-mail: <input type="email" ng-model="user.email" /><br /> + Gender: <input type="radio" ng-model="user.gender" value="male" />male + <input type="radio" ng-model="user.gender" value="female" />female<br /> + <button ng-click="reset()">RESET</button> + <button ng-click="update(user)">SAVE</button> + </form> + <pre>form = {{user | json}}</pre> + <pre>master = {{master | json}}</pre> + </div> + + <script> + function Controller($scope) { + $scope.master= {}; + + $scope.update = function(user) { + // Example with 1 argument + $scope.master= angular.copy(user); + }; + + $scope.reset = function() { + // Example with 2 arguments + angular.copy($scope.master, $scope.user); + }; + + $scope.reset(); + } + </script> + </file> + </example> */ function copy(source, destination){ - if (isWindow(source) || isScope(source)) throw Error("Can't copy Window or Scope"); + if (isWindow(source) || isScope(source)) { + throw ngMinErr('cpws', + "Can't copy! Making copies of Window or Scope instances is not supported."); + } + if (!destination) { destination = source; if (source) { @@ -611,7 +853,8 @@ function copy(source, destination){ } } } else { - if (source === destination) throw Error("Can't copy equivalent objects or arrays"); + if (source === destination) throw ngMinErr('cpi', + "Can't copy! Source and destination are identical."); if (isArray(source)) { destination.length = 0; for ( var i = 0; i < source.length; i++) { @@ -638,7 +881,9 @@ function shallowCopy(src, dst) { dst = dst || {}; for(var key in src) { - if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') { + // shallowCopy is only ever called by $compile nodeLinkFn, which has control over src + // so we don't need to worry about using our custom hasOwnProperty here + if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) { dst[key] = src[key]; } } @@ -650,22 +895,24 @@ function shallowCopy(src, dst) { /** * @ngdoc function * @name angular.equals + * @module ng * @function * * @description - * Determines if two objects or two values are equivalent. Supports value types, regular expressions, arrays and - * objects. + * Determines if two objects or two values are equivalent. Supports value types, regular + * expressions, 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) + * * Both objects or values are of the same type and all of their properties are equal by + * comparing them with `angular.equals`. + * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal) * * Both values represent the same regular expression (In JavasScript, * /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual * representation matches). * - * During a property comparision, properties of `function` type and properties with names + * During a property comparison, properties of `function` type and properties with names * that begin with `$` are ignored. * * Scope and DOMWindow objects are being compared only by identify (`===`). @@ -702,7 +949,7 @@ function equals(o1, o2) { keySet[key] = true; } for(key in o2) { - if (!keySet[key] && + if (!keySet.hasOwnProperty(key) && key.charAt(0) !== '$' && o2[key] !== undefined && !isFunction(o2[key])) return false; @@ -715,6 +962,13 @@ function equals(o1, o2) { } +function csp() { + return (document.securityPolicy && document.securityPolicy.isActive) || + (document.querySelector && + !!(document.querySelector('[ng-csp]') || document.querySelector('[data-ng-csp]'))); +} + + function concat(array1, array2, index) { return array1.concat(slice.call(array2, index)); } @@ -724,21 +978,25 @@ function sliceArgs(args, startIndex) { } +/* jshint -W101 */ /** * @ngdoc function * @name angular.bind + * @module ng * @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 prebound to the function. This feature is also - * known as [function currying](http://en.wikipedia.org/wiki/Currying). + * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as + * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application). * * @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. */ +/* jshint +W101 */ function bind(self, fn) { var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : []; if (isFunction(fn) && !(fn instanceof RegExp)) { @@ -763,7 +1021,7 @@ function bind(self, fn) { function toJsonReplacer(key, value) { var val = value; - if (/^\$+/.test(key)) { + if (typeof key === 'string' && key.charAt(0) === '$') { val = undefined; } else if (isWindow(value)) { val = '$WINDOW'; @@ -780,6 +1038,7 @@ function toJsonReplacer(key, value) { /** * @ngdoc function * @name angular.toJson + * @module ng * @function * * @description @@ -788,7 +1047,7 @@ function toJsonReplacer(key, value) { * * @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|undefined} Jsonified string representing `obj`. + * @returns {string|undefined} JSON-ified string representing `obj`. */ function toJson(obj, pretty) { if (typeof obj === 'undefined') return undefined; @@ -799,13 +1058,14 @@ function toJson(obj, pretty) { /** * @ngdoc function * @name angular.fromJson + * @module ng * @function * * @description * Deserializes a JSON string. * * @param {string} json JSON string to deserialize. - * @returns {Object|Array|Date|string|number} Deserialized thingy. + * @returns {Object|Array|string|number} Deserialized thingy. */ function fromJson(json) { return isString(json) @@ -815,7 +1075,9 @@ function fromJson(json) { function toBoolean(value) { - if (value && value.length !== 0) { + if (typeof value === 'function') { + value = true; + } else if (value && value.length !== 0) { var v = lowercase("" + value); value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]'); } else { @@ -832,7 +1094,7 @@ function startingTag(element) { 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(''); + element.empty(); } catch(e) {} // As Per DOM Standards var TEXT_NODE = 3; @@ -870,7 +1132,7 @@ function tryDecodeURIComponent(value) { /** * Parses an escaped url query string into key-value pairs. - * @returns Object.<(string|boolean)> + * @returns {Object.<string,boolean|Array>} */ function parseKeyValue(/**string*/keyValue) { var obj = {}, key_value, key; @@ -879,7 +1141,14 @@ function parseKeyValue(/**string*/keyValue) { key_value = keyValue.split('='); key = tryDecodeURIComponent(key_value[0]); if ( isDefined(key) ) { - obj[key] = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; + var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; + if (!obj[key]) { + obj[key] = val; + } else if(isArray(obj[key])) { + obj[key].push(val); + } else { + obj[key] = [obj[key],val]; + } } } }); @@ -889,14 +1158,22 @@ function parseKeyValue(/**string*/keyValue) { function toKeyValue(obj) { var parts = []; forEach(obj, function(value, key) { - parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true))); + if (isArray(value)) { + forEach(value, function(arrayValue) { + parts.push(encodeUriQuery(key, true) + + (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); + }); + } else { + 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 + * We need our custom method because encodeURIComponent is too aggressive and doesn't follow * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path * segments: * segment = *pchar @@ -916,7 +1193,7 @@ function encodeUriSegment(val) { /** * 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 + * method because encodeURIComponent is too aggressive 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 / ":" / "@" @@ -937,7 +1214,8 @@ function encodeUriQuery(val, pctEncodeSpaces) { /** * @ngdoc directive - * @name ng.directive:ngApp + * @name ngApp + * @module ng * * @element ANY * @param {angular.Module} ngApp an optional application @@ -945,26 +1223,39 @@ function encodeUriQuery(val, pctEncodeSpaces) { * * @description * - * Use this directive to auto-bootstrap an application. Only - * one ngApp directive can be used per HTML document. The directive - * designates the root of the application and is typically placed - * at the root of the page. - * - * The first ngApp found in the document will be auto-bootstrapped. To use multiple applications in an - * HTML document you must manually bootstrap them using {@link angular.bootstrap}. - * Applications cannot be nested. - * - * 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`. |