deleted file mode 100644
index 575fe6b7a6599f26fb3f5705dda41afa18b2ceea..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/angular-1.2.js
+++ /dev/null
@@ -1,20369 +0,0 @@
-/**
- * @license AngularJS v1.2.5
- * (c) 2010-2014 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(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(string, string, ...): Error} 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.5/' +
- (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,
-
-*/
-
-////////////////////////////////////
-
-/**
- * @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) {
- /* 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;
-};
-
-
-// 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;
-}
-
-
-var /** holds major version number for IE or NaN for real browsers */
- 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,
- * String ...)
- */
-function isArrayLike(obj) {
- if (obj == null || isWindow(obj)) {
- return false;
- }
-
- var length = obj.length;
-
- if (obj.nodeType === 1 && length) {
- return true;
- }
-
- return isString(obj) || isArray(obj) || length === 0 ||
- typeof length === 'number' && length > 0 && (length - 1) in obj;
-}
-
-/**
- * @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 (isArrayLike(obj)) {
- 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_1 in obj) {
- if (obj.hasOwnProperty(key_1)) {
- keys.push(key_1);
- }
- }
- 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 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('');
-}
-
-
-/**
- * Set or clear the hashkey for an object.
- * @param obj object
- * @param h the hashkey (!truthy to delete the hashkey)
- */
-function setHashKey(obj, h) {
- if (h) {
- obj.$$hashKey = h;
- }
- else {
- delete obj.$$hashKey;
- }
-}
-
-/**
- * @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).
- * @returns {Object} Reference to `dst`.
- */
-function extend(dst) {
- var h = dst.$$hashKey;
- forEach(arguments, function(obj){
- if (obj !== dst) {
- forEach(obj, function(value, key){
- dst[key] = value;
- });
- }
- });
-
- setHashKey(dst,h);
- 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 || angular.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.call(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.call(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';}
-
-
-/**
- * Determines if a value is a regular expression object.
- *
- * @private
- * @param {*} value Reference to check.
- * @returns {boolean} True if `value` is a `RegExp`.
- */
-function isRegExp(value) {
- return toString.call(value) === '[object RegExp]';
-}
-
-
-/**
- * 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.call(obj) === '[object File]';
-}
-
-
-function isBoolean(value) {
- return typeof value === 'boolean';
-}
-
-
-var trim = (function() {
- // native trim is way faster: http://jsperf.com/angular-trim-test
- // but IE doesn't have it... :-(
- // TODO: we should move this into IE/ES5 polyfill
- if (!String.prototype.trim) {
- return function(value) {
- return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
- };
- }
- return function(value) {
- return isString(value) ? value.trim() : 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.on && node.find))); // we have an on 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 count = 0, key;
-
- if (isArray(obj) || isString(obj)) {
- return obj.length;
- } else if (isObject(obj)){
- for (key in obj)
- if (!ownPropsOnly || obj.hasOwnProperty(key))
- count++;
- }
-
- return count;
-}
-
-
-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 (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
- <doc:example>
- <doc:source>
- <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>
- </doc:source>
- </doc:example>
- */
-function copy(source, destination){
- 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) {
- if (isArray(source)) {
- destination = copy(source, []);
- } else if (isDate(source)) {
- destination = new Date(source.getTime());
- } else if (isRegExp(source)) {
- destination = new RegExp(source.source);
- } else if (isObject(source)) {
- destination = copy(source, {});
- }
- }
- } else {
- 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++) {
- destination.push(copy(source[i]));
- }
- } else {
- var h = destination.$$hashKey;
- forEach(destination, function(value, key){
- delete destination[key];
- });
- for ( var key_2 in source) {
- destination[key_2] = copy(source[key_2]);
- }
- setHashKey(destination,h);
- }
- }
- return destination;
-}
-
-/**
- * Create a shallow copy of an object
- */
-function shallowCopy(src, dst) {
- dst = dst || {};
-
- for(var key_3 in src) {
- // 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_3) && key_3.substr(0, 2) !== '$$') {
- dst[key_3] = src[key_3];
- }
- }
-
- return dst;
-}
-
-
-/**
- * @ngdoc function
- * @name angular.equals
- * @function
- *
- * @description
- * 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 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 comparison, properties of `function` type and properties with names
- * that begin with `$` are ignored.
- *
- * Scope and DOMWindow objects are being compared only by 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 (!isArray(o2)) return false;
- 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 (isRegExp(o1) && isRegExp(o2)) {
- return o1.toString() == o2.toString();
- } else {
- if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || isArray(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.hasOwnProperty(key) &&
- key.charAt(0) !== '$' &&
- o2[key] !== undefined &&
- !isFunction(o2[key])) return false;
- }
- return true;
- }
- }
- }
- return false;
-}
-
-
-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));
-}
-
-function sliceArgs(args, startIndex) {
- return slice.call(args, startIndex || 0);
-}
-
-
-/* jshint -W101 */
-/**
- * @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 prebound to the function. This feature is also
- * 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)) {
- 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 (typeof key === 'string' && key.charAt(0) === '$') {
- 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. Properties with leading $ characters will be
- * stripped since angular uses this notation internally.
- *
- * @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} JSON-ified string representing `obj`.
- */
-function toJson(obj, pretty) {
- if (typeof obj === 'undefined') return undefined;
- 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.empty();
- } catch(e) {}
- // As Per DOM Standards
- var TEXT_NODE = 3;
- var elemHtml = jqLite('<div>').append(element).html();
- try {
- return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) :
- elemHtml.
- match(/^(<[^>]+>)/)[1].
- replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
- } catch(e) {
- return lowercase(elemHtml);
- }
-
-}
-
-
-/////////////////////////////////////////////////
-
-/**
- * Tries to decode the URI component without throwing an exception.
- *
- * @private
- * @param str value potential URI component to check.
- * @returns {boolean} True if `value` can be decoded
- * with the decodeURIComponent function.
- */
-function tryDecodeURIComponent(value) {
- try {
- return decodeURIComponent(value);
- } catch(e) {
- // Ignore any invalid uri component
- }
-}
-
-
-/**
- * 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 = tryDecodeURIComponent(key_value[0]);
- if ( isDefined(key) ) {
- 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];
- }
- }
- }
- });
- return obj;
-}
-
-function toKeyValue(obj) {
- var parts = [];
- forEach(obj, function(value, key) {
- 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 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
- * 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 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 / ":" / "@"
- * 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(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
-}
-
-
-/**
- * @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** an AngularJS application. The `ngApp` directive
- * designates the **root element** of the application and is typically placed near the root element
- * of the page - e.g. on the `<body>` or `<html>` tags.
- *
- * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
- * found in the document will be used to define the root element to auto-bootstrap as an
- * application. To run multiple applications in an HTML document you must manually bootstrap them using
- * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
- *
- * You can specify an **AngularJS module** to be used as the root module for the application. This
- * module will be loaded into the {@link AUTO.$injector} when the application is bootstrapped and
- * should contain the application code needed or have dependencies on other modules that will
- * contain the code. See {@link angular.module} for more information.
- *
- * In the example below if the `ngApp` directive were not placed on the `html` element then the
- * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
- * would not be resolved to `3`.
- *
- * `ngApp` is the easiest, and most common, way to bootstrap an application.
- *
- <example module="ngAppDemo">
- <file name="index.html">
- <div ng-controller="ngAppDemoController">
- I can add: {{a}} + {{b}} = {{ a+b }}
- </file>
- <file name="script.js">
- angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
- $scope.a = 1;
- $scope.b = 2;
- });
- </file>
- </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}
- *
- * Note that ngScenario-based end-to-end tests cannot use this function to bootstrap manually.
- * They must use {@link api/ng.directive:ngApp ngApp}.
- *
- * @param {Element} element DOM element which is the root of angular application.
- * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
- * Each item in the array should be the name of a predefined module or a (DI annotated)
- * function that will be invoked by the injector as a run block.
- * See: {@link angular.module modules}
- * @returns {AUTO.$injector} Returns the newly created injector for this app.
- */
-function bootstrap(element, modules) {
- var doBootstrap = function() {
- element = jqLite(element);
-
- if (element.injector()) {
- var tag = (element[0] === document) ? 'document' : startingTag(element);
- throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
- }
-
- modules = modules || [];
- modules.unshift(['$provide', function($provide) {
- $provide.value('$rootElement', element);
- }]);
- modules.unshift('ng');
- var injector = createInjector(modules);
- injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
- function(scope, element, compile, injector, animate) {
- scope.$apply(function() {
- element.data('$injector', injector);
- compile(element)(scope);
- });
- }]
- );
- return injector;
- };
-
- var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
-
- if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
- return doBootstrap();
- }
-
- window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
- angular.resumeBootstrap = function(extraModules) {
- forEach(extraModules, function(module) {
- modules.push(module);
- });
- doBootstrap();
- };
-}
-
-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,
- isolateScope: JQLitePrototype.isolateScope,
- controller: JQLitePrototype.controller,
- injector: JQLitePrototype.injector,
- inheritedData: JQLitePrototype.inheritedData
- });
- // Method signature:
- // jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
- jqLitePatchJQueryRemove('remove', true, true, false);
- jqLitePatchJQueryRemove('empty', false, false, false);
- jqLitePatchJQueryRemove('html', false, false, true);
- } else {
- jqLite = JQLite;
- }
- angular.element = jqLite;
-}
-
-/**
- * throw error if the argument is falsy.
- */
-function assertArg(arg, name, reason) {
- if (!arg) {
- throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (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;
-}
-
-/**
- * throw error if the name given is hasOwnProperty
- * @param {String} name the name to test
- * @param {String} context the context in which the name is used, such as module or directive
- */
-function assertNotHasOwnProperty(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
- }
-}
-
-/**
- * Return the value accessible from the object by path. Any undefined traversals are ignored
- * @param {Object} obj starting object
- * @param {string} path path to traverse
- * @param {boolean=true} bindFnToScope
- * @returns value as accessible by path
- */
-//TODO(misko): this function needs to be removed
-function getter(obj, path, bindFnToScope) {
- if (!path) return obj;
- var keys = path.split('.');
- var key;
- var lastInstance = obj;
- var len = keys.length;
-
- for (var i = 0; i < len; i++) {
- key = keys[i];
- if (obj) {
- obj = (lastInstance = obj)[key];
- }
- }
- if (!bindFnToScope && isFunction(obj)) {
- return bind(lastInstance, obj);
- }
- return obj;
-}
-
-/**
- * Return the DOM siblings between the first and last node in the given array.
- * @param {Array} array like object
- * @returns jQlite object containing the elements
- */
-function getBlockElements(nodes) {
- var startNode = nodes[0],
- endNode = nodes[nodes.length - 1];
- if (startNode === endNode) {
- return jqLite(startNode);
- }
-
- var element = startNode;
- var elements = [element];
-
- do {
- element = element.nextSibling;
- if (!element) break;
- elements.push(element);
- } while (element !== endNode);
-
- return jqLite(elements);
-}
-
-/**
- * @ngdoc interface
- * @name angular.Module
- * @description
- *
- * Interface for configuring angular {@link angular.module modules}.
- */
-
-function setupModuleLoader(window) {
-
- var $injectorMinErr = minErr('$injector');
- var ngMinErr = minErr('ng');
-
- function ensure(obj, name, factory) {
- return obj[name] || (obj[name] = factory());
- }
-
- var angular = ensure(window, 'angular', Object);
-
- // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
- angular.$$minErr = angular.$$minErr || minErr;
-
- return ensure(angular, 'module', function() {
- /** @type {Object.<string, angular.Module>} */
- var modules = {};
-
- /**
- * @ngdoc function
- * @name angular.module
- * @description
- *
- * The `angular.module` is a global place for creating, registering and retrieving Angular
- * modules.
- * All modules (angular core or 3rd party) that should be available to an application must be
- * registered using this mechanism.
- *
- * When passed two or more arguments, a new module is created. If passed only one argument, an
- * existing module (the name passed as the first argument to `module`) is retrieved.
- *
- *
- * # Module
- *
- * A module is a collection of services, directives, filters, and configuration information.
- * `angular.module` is used to configure the {@link AUTO.$injector $injector}.
- *
- * <pre>
- * // Create a new module
- * var myModule = angular.module('myModule', []);
- *
- * // register a new service
- * myModule.value('appName', 'MyCoolApp');
- *
- * // configure existing services inside initialization blocks.
- * myModule.config(function($locationProvider) {
- * // Configure existing providers
- * $locationProvider.hashPrefix('!');
- * });
- * </pre>
- *
- * Then you can create an injector and load your modules like this:
- *
- * <pre>
- * var injector = angular.injector(['ng', 'MyModule'])
- * </pre>
- *
- * However it's more likely that you'll just use
- * {@link ng.directive:ngApp ngApp} or
- * {@link angular.bootstrap} to simplify this process for you.
- *
- * @param {!string} name The name of the module to create or retrieve.
- * @param {Array.<string>=} requires If specified then new module is being created. If
- * unspecified then the the module is being retrieved for further configuration.
- * @param {Function} configFn Optional configuration function for the module. Same as
- * {@link angular.Module#methods_config Module#config()}.
- * @returns {module} new module with the {@link angular.Module} api.
- */
- return function module(name, requires, configFn) {
- var assertNotHasOwnProperty = function(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
- }
- };
-
- assertNotHasOwnProperty(name, 'module');
- if (requires && modules.hasOwnProperty(name)) {
- modules[name] = null;
- }
- return ensure(modules, name, function() {
- if (!requires) {
- throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
- "the module name or forgot to load it. If registering a module ensure that you " +
- "specify the dependencies as the second argument.", name);
- }
-
- /** @type {!Array.<Array.<*>>} */
- var invokeQueue = [];
-
- /** @type {!Array.<Function>} */
- var runBlocks = [];
-
- var config = invokeLater('$injector', 'invoke');
-
- /** @type {angular.Module} */
- var moduleInstance = {
- // Private state
- _invokeQueue: invokeQueue,
- _runBlocks: runBlocks,
-
- /**
- * @ngdoc property
- * @name angular.Module#requires
- * @propertyOf angular.Module
- * @returns {Array.<string>} List of module names which must be loaded before this module.
- * @description
- * Holds the list of modules which the injector will load before the current module is
- * loaded.
- */
- requires: requires,
-
- /**
- * @ngdoc property
- * @name angular.Module#name
- * @propertyOf angular.Module
- * @returns {string} Name of the module.
- * @description
- */
- name: name,
-
-
- /**
- * @ngdoc method
- * @name angular.Module#provider
- * @methodOf angular.Module
- * @param {string} name service name
- * @param {Function} providerType Construction function for creating new instance of the
- * service.
- * @description
- * See {@link AUTO.$provide#provider $provide.provider()}.
- */
- provider: invokeLater('$provide', 'provider'),
-
- /**
- * @ngdoc method
- * @name angular.Module#factory
- * @methodOf angular.Module
- * @param {string} name service name
- * @param {Function} providerFunction Function for creating new instance of the service.
- * @description
- * See {@link AUTO.$provide#factory $provide.factory()}.
- */
- factory: invokeLater('$provide', 'factory'),
-
- /**
- * @ngdoc method
- * @name angular.Module#service
- * @methodOf angular.Module
- * @param {string} name service name
- * @param {Function} constructor A constructor function that will be instantiated.
- * @description
- * See {@link AUTO.$provide#service $provide.service()}.
- */
- service: invokeLater('$provide', 'service'),
-
- /**
- * @ngdoc method
- * @name angular.Module#value
- * @methodOf angular.Module
- * @param {string} name service name
- * @param {*} object Service instance object.
- * @description
- * See {@link AUTO.$provide#value $provide.value()}.
- */
- value: invokeLater('$provide', 'value'),
-
- /**
- * @ngdoc method
- * @name angular.Module#constant
- * @methodOf angular.Module
- * @param {string} name constant name
- * @param {*} object Constant value.
- * @description
- * Because the constant are fixed, they get applied before other provide methods.
- * See {@link AUTO.$provide#constant $provide.constant()}.
- */
- constant: invokeLater('$provide', 'constant', 'unshift'),
-
- /**
- * @ngdoc method
- * @name angular.Module#animation
- * @methodOf angular.Module
- * @param {string} name animation name
- * @param {Function} animationFactory Factory function for creating new instance of an
- * animation.
- * @description
- *
- * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
- *
- *
- * Defines an animation hook that can be later used with
- * {@link ngAnimate.$animate $animate} service and directives that use this service.
- *
- * <pre>
- * module.animation('.animation-name', function($inject1, $inject2) {
- * return {
- * eventName : function(element, done) {
- * //code to run the animation
- * //once complete, then run done()
- * return function cancellationFunction(element) {
- * //code to cancel the animation
- * }
- * }
- * }
- * })
- * </pre>
- *
- * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
- * {@link ngAnimate ngAnimate module} for more information.
- */
- animation: invokeLater('$animateProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#filter
- * @methodOf angular.Module
- * @param {string} name Filter name.
- * @param {Function} filterFactory Factory function for creating new instance of filter.
- * @description
- * See {@link ng.$filterProvider#register $filterProvider.register()}.
- */
- filter: invokeLater('$filterProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#controller
- * @methodOf angular.Module
- * @param {string|Object} name Controller name, or an object map of controllers where the
- * keys are the names and the values are the constructors.
- * @param {Function} constructor Controller constructor function.
- * @description
- * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
- */
- controller: invokeLater('$controllerProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#directive
- * @methodOf angular.Module
- * @param {string|Object} name Directive name, or an object map of directives where the
- * keys are the names and the values are the factories.
- * @param {Function} directiveFactory Factory function for creating new instance of
- * directives.
- * @description
- * See {@link ng.$compileProvider#methods_directive $compileProvider.directive()}.
- */
- directive: invokeLater('$compileProvider', 'directive'),
-
- /**
- * @ngdoc method
- * @name angular.Module#config
- * @methodOf angular.Module
- * @param {Function} configFn Execute this function on module load. Useful for service
- * configuration.
- * @description
- * Use this method to register work which needs to be performed on module loading.
- */
- config: config,
-
- /**
- * @ngdoc method
- * @name angular.Module#run
- * @methodOf angular.Module
- * @param {Function} initializationFn Execute this function after injector creation.
- * Useful for application initialization.
- * @description
- * Use this method to register work which should be performed when the injector is done
- * loading all modules.
- */
- run: function(block) {
- runBlocks.push(block);
- return this;
- }
- };
-
- if (configFn) {
- config(configFn);
- }
-
- return moduleInstance;
-
- /**
- * @param {string} provider
- * @param {string} method
- * @param {String=} insertMethod
- * @returns {angular.Module}
- */
- function invokeLater(provider, method, insertMethod) {
- return function() {
- invokeQueue[insertMethod || 'push']([provider, method, arguments]);
- return moduleInstance;
- };
- }
- });
- };
- });
-
-}
-
-/* global
- angularModule: true,
- version: true,
-
- $LocaleProvider,
- $CompileProvider,
-
- htmlAnchorDirective,
- inputDirective,
- inputDirective,
- formDirective,
- scriptDirective,
- selectDirective,
- styleDirective,
- optionDirective,
- ngBindDirective,
- ngBindHtmlDirective,
- ngBindTemplateDirective,
- ngClassDirective,
- ngClassEvenDirective,
- ngClassOddDirective,
- ngCspDirective,
- ngCloakDirective,
- ngControllerDirective,
- ngFormDirective,
- ngHideDirective,
- ngIfDirective,
- ngIncludeDirective,
- ngIncludeFillContentDirective,
- ngInitDirective,
- ngNonBindableDirective,
- ngPluralizeDirective,
- ngRepeatDirective,
- ngShowDirective,
- ngStyleDirective,
- ngSwitchDirective,
- ngSwitchWhenDirective,
- ngSwitchDefaultDirective,
- ngOptionsDirective,
- ngTranscludeDirective,
- ngModelDirective,
- ngListDirective,
- ngChangeDirective,
- requiredDirective,
- requiredDirective,
- ngValueDirective,
- ngAttributeAliasDirectives,
- ngEventDirectives,
-
- $AnchorScrollProvider,
- $AnimateProvider,
- $BrowserProvider,
- $CacheFactoryProvider,
- $ControllerProvider,
- $DocumentProvider,
- $ExceptionHandlerProvider,
- $FilterProvider,
- $InterpolateProvider,
- $IntervalProvider,
- $HttpProvider,
- $HttpBackendProvider,
- $LocationProvider,
- $LogProvider,
- $ParseProvider,
- $RootScopeProvider,
- $QProvider,
- $$SanitizeUriProvider,
- $SceProvider,
- $SceDelegateProvider,
- $SnifferProvider,
- $TemplateCacheProvider,
- $TimeoutProvider,
- $WindowProvider
-*/
-
-
-/**
- * @ngdoc property
- * @name angular.version
- * @description
- * An object that contains information about the current AngularJS version. This object has the
- * following properties:
- *
- * - `full` – `{string}` – Full version string, such as "0.9.18".
- * - `major` – `{number}` – Major version number, such as "0".
- * - `minor` – `{number}` – Minor version number, such as "9".
- * - `dot` – `{number}` – Dot version number, such as "18".
- * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
- */
-var version = {
- full: '1.2.5', // all of these placeholder strings will be replaced by grunt's
- major: 1, // package task
- minor: 2,
- dot: 5,
- codeName: 'singularity-expansion'
-};
-
-
-function publishExternalAPI(angular){
- extend(angular, {
- 'bootstrap': bootstrap,
- 'copy': copy,
- 'extend': extend,
- 'equals': equals,
- 'element': jqLite,
- 'forEach': forEach,
- 'injector': createInjector,
- 'noop':noop,
- 'bind':bind,
- 'toJson': toJson,
- 'fromJson': fromJson,
- 'identity':identity,
- 'isUndefined': isUndefined,
- 'isDefined': isDefined,
- 'isString': isString,
- 'isFunction': isFunction,
- 'isObject': isObject,
- 'isNumber': isNumber,
- 'isElement': isElement,
- 'isArray': isArray,
- 'version': version,
- 'isDate': isDate,
- 'lowercase': lowercase,
- 'uppercase': uppercase,
- 'callbacks': {counter: 0},
- '$$minErr': minErr,
- '$$csp': csp
- });
-
- angularModule = setupModuleLoader(window);
- try {
- angularModule('ngLocale');
- } catch (e) {
- angularModule('ngLocale', []).provider('$locale', $LocaleProvider);
- }
-
- angularModule('ng', ['ngLocale'], ['$provide',
- function ngModule($provide) {
- // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
- $provide.provider({
- $$sanitizeUri: $$SanitizeUriProvider
- });
- $provide.provider('$compile', $CompileProvider).
- directive({
- a: htmlAnchorDirective,
- input: inputDirective,
- textarea: inputDirective,
- form: formDirective,
- script: scriptDirective,
- select: selectDirective,
- style: styleDirective,
- option: optionDirective,
- ngBind: ngBindDirective,
- ngBindHtml: ngBindHtmlDirective,
- ngBindTemplate: ngBindTemplateDirective,
- ngClass: ngClassDirective,
- ngClassEven: ngClassEvenDirective,
- ngClassOdd: ngClassOddDirective,
- ngCloak: ngCloakDirective,
- ngController: ngControllerDirective,
- ngForm: ngFormDirective,
- ngHide: ngHideDirective,
- ngIf: ngIfDirective,
- ngInclude: ngIncludeDirective,
- ngInit: ngInitDirective,
- ngNonBindable: ngNonBindableDirective,
- ngPluralize: ngPluralizeDirective,
- ngRepeat: ngRepeatDirective,
- ngShow: ngShowDirective,
- ngStyle: ngStyleDirective,
- ngSwitch: ngSwitchDirective,
- ngSwitchWhen: ngSwitchWhenDirective,
- ngSwitchDefault: ngSwitchDefaultDirective,
- ngOptions: ngOptionsDirective,
- ngTransclude: ngTranscludeDirective,
- ngModel: ngModelDirective,
- ngList: ngListDirective,
- ngChange: ngChangeDirective,
- required: requiredDirective,
- ngRequired: requiredDirective,
- ngValue: ngValueDirective
- }).
- directive({
- ngInclude: ngIncludeFillContentDirective
- }).
- directive(ngAttributeAliasDirectives).
- directive(ngEventDirectives);
- $provide.provider({
- $anchorScroll: $AnchorScrollProvider,
- $animate: $AnimateProvider,
- $browser: $BrowserProvider,
- $cacheFactory: $CacheFactoryProvider,
- $controller: $ControllerProvider,
- $document: $DocumentProvider,
- $exceptionHandler: $ExceptionHandlerProvider,
- $filter: $FilterProvider,
- $interpolate: $InterpolateProvider,
- $interval: $IntervalProvider,
- $http: $HttpProvider,
- $httpBackend: $HttpBackendProvider,
- $location: $LocationProvider,
- $log: $LogProvider,
- $parse: $ParseProvider,
- $rootScope: $RootScopeProvider,
- $q: $QProvider,
- $sce: $SceProvider,
- $sceDelegate: $SceDelegateProvider,
- $sniffer: $SnifferProvider,
- $templateCache: $TemplateCacheProvider,
- $timeout: $TimeoutProvider,
- $window: $WindowProvider
- });
- }
- ]);
-}
-
-/* global
-
- -JQLitePrototype,
- -addEventListenerFn,
- -removeEventListenerFn,
- -BOOLEAN_ATTR
-*/
-
-//////////////////////////////////
-//JQLite
-//////////////////////////////////
-
-/**
- * @ngdoc function
- * @name angular.element
- * @function
- *
- * @description
- * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
- *
- * If jQuery is available, `angular.element` is an alias for the
- * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
- * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
- *
- * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
- * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
- * commonly needed functionality with the goal of having a very small footprint.</div>
- *
- * To use jQuery, simply load it before `DOMContentLoaded` event fired.
- *
- * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
- * jqLite; they are never raw DOM references.</div>
- *
- * ## Angular's jqLite
- * jqLite provides only the following jQuery methods:
- *
- * - [`addClass()`](http://api.jquery.com/addClass/)
- * - [`after()`](http://api.jquery.com/after/)
- * - [`append()`](http://api.jquery.com/append/)
- * - [`attr()`](http://api.jquery.com/attr/)
- * - [`bind()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
- * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
- * - [`clone()`](http://api.jquery.com/clone/)
- * - [`contents()`](http://api.jquery.com/contents/)
- * - [`css()`](http://api.jquery.com/css/)
- * - [`data()`](http://api.jquery.com/data/)
- * - [`empty()`](http://api.jquery.com/empty/)
- * - [`eq()`](http://api.jquery.com/eq/)
- * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
- * - [`hasClass()`](http://api.jquery.com/hasClass/)
- * - [`html()`](http://api.jquery.com/html/)
- * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
- * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
- * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces or selectors
- * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
- * - [`prepend()`](http://api.jquery.com/prepend/)
- * - [`prop()`](http://api.jquery.com/prop/)
- * - [`ready()`](http://api.jquery.com/ready/)
- * - [`remove()`](http://api.jquery.com/remove/)
- * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
- * - [`removeClass()`](http://api.jquery.com/removeClass/)
- * - [`removeData()`](http://api.jquery.com/removeData/)
- * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
- * - [`text()`](http://api.jquery.com/text/)
- * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
- * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
- * - [`unbind()`](http://api.jquery.com/off/) - Does not support namespaces
- * - [`val()`](http://api.jquery.com/val/)
- * - [`wrap()`](http://api.jquery.com/wrap/)
- *
- * ## jQuery/jqLite Extras
- * Angular also provides the following additional methods and events to both jQuery and jqLite:
- *
- * ### Events
- * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
- * on all DOM nodes being removed. This can be used to clean up any 3rd party bindings to the DOM
- * element before it is removed.
- *
- * ### Methods
- * - `controller(name)` - retrieves the controller of the current element or its parent. By default
- * retrieves controller associated with the `ngController` directive. If `name` is provided as
- * camelCase directive name, then the controller for this directive will be retrieved (e.g.
- * `'ngModel'`).
- * - `injector()` - retrieves the injector of the current element or its parent.
- * - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
- * element or its parent.
- * - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the
- * current element. This getter should be used only on elements that contain a directive which starts a new isolate
- * scope. Calling `scope()` on this element always returns the original non-isolate scope.
- * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
- * parent element is reached.
- *
- * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
- * @returns {Object} jQuery object.
- */
-
-var jqCache = JQLite.cache = {},
- jqName = JQLite.expando = 'ng-' + new Date().getTime(),
- jqId = 1,
- addEventListenerFn = (window.document.addEventListener
- ? function(element, type, fn) {element.addEventListener(type, fn, false);}
- : function(element, type, fn) {element.attachEvent('on' + type, fn);}),
- removeEventListenerFn = (window.document.removeEventListener
- ? function(element, type, fn) {element.removeEventListener(type, fn, false); }
- : function(element, type, fn) {element.detachEvent('on' + type, fn); });
-
-function jqNextId() { return ++jqId; }
-
-
-var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
-var MOZ_HACK_REGEXP = /^moz([A-Z])/;
-var jqLiteMinErr = minErr('jqLite');
-
-/**
- * Converts snake_case to camelCase.
- * Also there is special case for Moz prefix starting with upper case letter.
- * @param name Name to normalize
- */
-function camelCase(name) {
- return name.
- replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
- return offset ? letter.toUpperCase() : letter;
- }).
- replace(MOZ_HACK_REGEXP, 'Moz$1');
-}
-
-/////////////////////////////////////////////
-// jQuery mutation patch
-//
-// In conjunction with bindJQuery intercepts all jQuery's DOM destruction apis and fires a
-// $destroy event on all DOM nodes being removed.
-//
-/////////////////////////////////////////////
-
-function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
- var originalJqFn = jQuery.fn[name];
- originalJqFn = originalJqFn.$original || originalJqFn;
- removePatch.$original = originalJqFn;
- jQuery.fn[name] = removePatch;
-
- function removePatch(param) {
- // jshint -W040
- var list = filterElems && param ? [this.filter(param)] : [this],
- fireEvent = dispatchThis,
- set, setIndex, setLength,
- element, childIndex, childLength, children;
-
- if (!getterIfNoArguments || param != null) {
- while(list.length) {
- set = list.shift();
- for(setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
- element = jqLite(set[setIndex]);
- if (fireEvent) {
- element.triggerHandler('$destroy');
- } else {
- fireEvent = !fireEvent;
- }
- for(childIndex = 0, childLength = (children = element.children()).length;
- childIndex < childLength;
- childIndex++) {
- list.push(jQuery(children[childIndex]));
- }
- }
- }
- }
- return originalJqFn.apply(this, arguments);
- }
-}
-
-/////////////////////////////////////////////
-function JQLite(element) {
- if (element instanceof JQLite) {
- return element;
- }
- if (!(this instanceof JQLite)) {
- if (isString(element) && element.charAt(0) != '<') {
- throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
- }
- return new JQLite(element);
- }
-
- if (isString(element)) {
- var div = document.createElement('div');
- // Read about the NoScope elements here:
- // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
- div.innerHTML = '<div> </div>' + element; // IE insanity to make NoScope elements work!
- div.removeChild(div.firstChild); // remove the superfluous div
- jqLiteAddNodes(this, div.childNodes);
- var fragment = jqLite(document.createDocumentFragment());
- fragment.append(this); // detach the elements from the temporary DOM div.
- } else {
- jqLiteAddNodes(this, element);
- }
-}
-
-function jqLiteClone(element) {
- return element.cloneNode(true);
-}
-
-function jqLiteDealoc(element){
- jqLiteRemoveData(element);
- for ( var i = 0, children = element.childNodes || []; i < children.length; i++) {
- jqLiteDealoc(children[i]);
- }
-}
-
-function jqLiteOff(element, type, fn, unsupported) {
- if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
-
- var events = jqLiteExpandoStore(element, 'events'),
- handle = jqLiteExpandoStore(element, 'handle');
-
- if (!handle) return; //no listeners registered
-
- if (isUndefined(type)) {
- forEach(events, function(eventHandler, type) {
- removeEventListenerFn(element, type, eventHandler);
- delete events[type];
- });
- } else {
- forEach(type.split(' '), function(type) {
- if (isUndefined(fn)) {
- removeEventListenerFn(element, type, events[type]);
- delete events[type];
- } else {
- arrayRemove(events[type] || [], fn);
- }
- });
- }
-}
-
-function jqLiteRemoveData(element, name) {
- var expandoId = element[jqName],
- expandoStore = jqCache[expandoId];
-
- if (expandoStore) {
- if (name) {
- delete jqCache[expandoId].data[name];
- return;
- }
-
- if (expandoStore.handle) {
- expandoStore.events.$destroy && expandoStore.handle({}, '$destroy');
- jqLiteOff(element);
- }
- delete jqCache[expandoId];
- element[jqName] = undefined; // ie does not allow deletion of attributes on elements.
- }
-}
-
-function jqLiteExpandoStore(element, key, value) {
- var expandoId = element[jqName],
- expandoStore = jqCache[expandoId || -1];
-
- if (isDefined(value)) {
- if (!expandoStore) {
- element[jqName] = expandoId = jqNextId();
- expandoStore = jqCache[expandoId] = {};
- }
- expandoStore[key] = value;
- } else {
- return expandoStore && expandoStore[key];
- }
-}
-
-function jqLiteData(element, key, value) {
- var data = jqLiteExpandoStore(element, 'data'),
- isSetter = isDefined(value),
- keyDefined = !isSetter && isDefined(key),
- isSimpleGetter = keyDefined && !isObject(key);
-
- if (!data && !isSimpleGetter) {
- jqLiteExpandoStore(element, 'data', data = {});
- }
-
- if (isSetter) {
- data[key] = value;
- } else {
- if (keyDefined) {
- if (isSimpleGetter) {
- // don't create data in this case.
- return data && data[key];
- } else {
- extend(data, key);
- }
- } else {
- return data;
- }
- }
-}
-
-function jqLiteHasClass(element, selector) {
- if (!element.getAttribute) return false;
- return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
- indexOf( " " + selector + " " ) > -1);
-}
-
-function jqLiteRemoveClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- forEach(cssClasses.split(' '), function(cssClass) {
- element.setAttribute('class', trim(
- (" " + (element.getAttribute('class') || '') + " ")
- .replace(/[\n\t]/g, " ")
- .replace(" " + trim(cssClass) + " ", " "))
- );
- });
- }
-}
-
-function jqLiteAddClass(element, cssClasses) {
- if (cssClasses && element.setAttribute) {
- var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
- .replace(/[\n\t]/g, " ");
-
- forEach(cssClasses.split(' '), function(cssClass) {
- cssClass = trim(cssClass);
- if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
- existingClasses += cssClass + ' ';
- }
- });
-
- element.setAttribute('class', trim(existingClasses));
- }
-}
-
-function jqLiteAddNodes(root, elements) {
- if (elements) {
- elements = (!elements.nodeName && isDefined(elements.length) && !isWindow(elements))
- ? elements
- : [ elements ];
- for(var i=0; i < elements.length; i++) {
- root.push(elements[i]);
- }
- }
-}
-
-function jqLiteController(element, name) {
- return jqLiteInheritedData(element, '$' + (name || 'ngController' ) + 'Controller');
-}
-
-function jqLiteInheritedData(element, name, value) {
- element = jqLite(element);
-
- // if element is the document object work with the html element instead
- // this makes $(document).scope() possible
- if(element[0].nodeType == 9) {
- element = element.find('html');
- }
- var names = isArray(name) ? name : [name];
-
- while (element.length) {
-
- for (var i = 0, ii = names.length; i < ii; i++) {
- if ((value = element.data(names[i])) !== undefined) return value;
- }
- element = element.parent();
- }
-}
-
-function jqLiteEmpty(element) {
- for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
- jqLiteDealoc(childNodes[i]);
- }
- while (element.firstChild) {
- element.removeChild(element.firstChild);
- }
-}
-
-//////////////////////////////////////////
-// Functions which are declared directly.
-//////////////////////////////////////////
-var JQLitePrototype = JQLite.prototype = {
- ready: function(fn) {
- var fired = false;
-
- function trigger() {
- if (fired) return;
- fired = true;
- fn();
- }
-
- // check if document already is loaded
- if (document.readyState === 'complete'){
- setTimeout(trigger);
- } else {
- this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
- // we can not use jqLite since we are not done loading and jQuery could be loaded later.
- // jshint -W064
- JQLite(window).on('load', trigger); // fallback to window.onload for others
- // jshint +W064
- }
- },
- toString: function() {
- var value = [];
- forEach(this, function(e){ value.push('' + e);});
- return '[' + value.join(', ') + ']';
- },
-
- eq: function(index) {
- return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
- },
-
- length: 0,
- push: push,
- sort: [].sort,
- splice: [].splice
-};
-
-//////////////////////////////////////////
-// Functions iterating getter/setters.
-// these functions return self on setter and
-// value on get.
-//////////////////////////////////////////
-var BOOLEAN_ATTR = {};
-forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
- BOOLEAN_ATTR[lowercase(value)] = value;
-});
-var BOOLEAN_ELEMENTS = {};
-forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
- BOOLEAN_ELEMENTS[uppercase(value)] = true;
-});
-
-function getBooleanAttrName(element, name) {
- // check dom last since we will most likely fail on name
- var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
-
- // booleanAttr is here twice to minimize DOM access
- return booleanAttr && BOOLEAN_ELEMENTS[element.nodeName] && booleanAttr;
-}
-
-forEach({
- data: jqLiteData,
- inheritedData: jqLiteInheritedData,
-
- scope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
- },
-
- isolateScope: function(element) {
- // Can't use jqLiteData here directly so we stay compatible with jQuery!
- return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
- },
-
- controller: jqLiteController ,
-
- injector: function(element) {
- return jqLiteInheritedData(element, '$injector');
- },
-
- removeAttr: function(element,name) {
- element.removeAttribute(name);
- },
-
- hasClass: jqLiteHasClass,
-
- css: function(element, name, value) {
- name = camelCase(name);
-
- if (isDefined(value)) {
- element.style[name] = value;
- } else {
- var val;
-
- if (msie <= 8) {
- // this is some IE specific weirdness that jQuery 1.6.4 does not sure why
- val = element.currentStyle && element.currentStyle[name];
- if (val === '') val = 'auto';
- }
-
- val = val || element.style[name];
-
- if (msie <= 8) {
- // jquery weirdness :-/
- val = (val === '') ? undefined : val;
- }
-
- return val;
- }
- },
-
- attr: function(element, name, value){
- var lowercasedName = lowercase(name);
- if (BOOLEAN_ATTR[lowercasedName]) {
- if (isDefined(value)) {
- if (!!value) {
- element[name] = true;
- element.setAttribute(name, lowercasedName);
- } else {
- element[name] = false;
- element.removeAttribute(lowercasedName);
- }
- } else {
- return (element[name] ||
- (element.attributes.getNamedItem(name)|| noop).specified)
- ? lowercasedName
- : undefined;
- }
- } else if (isDefined(value)) {
- element.setAttribute(name, value);
- } else if (element.getAttribute) {
- // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
- // some elements (e.g. Document) don't have get attribute, so return undefined
- var ret = element.getAttribute(name, 2);
- // normalize non-existing attributes to undefined (as jQuery)
- return ret === null ? undefined : ret;
- }
- },
-
- prop: function(element, name, value) {
- if (isDefined(value)) {
- element[name] = value;
- } else {
- return element[name];
- }
- },
-
- text: (function() {
- var NODE_TYPE_TEXT_PROPERTY = [];
- if (msie < 9) {
- NODE_TYPE_TEXT_PROPERTY[1] = 'innerText'; /** Element **/
- NODE_TYPE_TEXT_PROPERTY[3] = 'nodeValue'; /** Text **/
- } else {
- NODE_TYPE_TEXT_PROPERTY[1] = /** Element **/
- NODE_TYPE_TEXT_PROPERTY[3] = 'textContent'; /** Text **/
- }
- getText.$dv = '';
- return getText;
-
- function getText(element, value) {
- var textProp = NODE_TYPE_TEXT_PROPERTY[element.nodeType];
- if (isUndefined(value)) {
- return textProp ? element[textProp] : '';
- }
- element[textProp] = value;
- }
- })(),
-
- val: function(element, value) {
- if (isUndefined(value)) {
- if (nodeName_(element) === 'SELECT' && element.multiple) {
- var result = [];
- forEach(element.options, function (option) {
- if (option.selected) {
- result.push(option.value || option.text);
- }
- });
- return result.length === 0 ? null : result;
- }
- return element.value;
- }
- element.value = value;
- },
-
- html: function(element, value) {
- if (isUndefined(value)) {
- return element.innerHTML;
- }
- for (var i = 0, childNodes = element.childNodes; i < childNodes.length; i++) {
- jqLiteDealoc(childNodes[i]);
- }
- element.innerHTML = value;
- },
-
- empty: jqLiteEmpty
-}, function(fn, name){
- /**
- * Properties: writes return selection, reads return first value
- */
- JQLite.prototype[name] = function(arg1, arg2) {
- var i, key;
-
- // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
- // in a way that survives minification.
- // jqLiteEmpty takes no arguments but is a setter.
- if (fn !== jqLiteEmpty &&
- (((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2) === undefined)) {
- if (isObject(arg1)) {
-
- // we are a write, but the object properties are the key/values
- for (i = 0; i < this.length; i++) {
- if (fn === jqLiteData) {
- // data() takes the whole object in jQuery
- fn(this[i], arg1);
- } else {
- for (key in arg1) {
- fn(this[i], key, arg1[key]);
- }
- }
- }
- // return self for chaining
- return this;
- } else {
- // we are a read, so read the first child.
- var value = fn.$dv;
- // Only if we have $dv do we iterate over all, otherwise it is just the first element.
- var jj = (value === undefined) ? Math.min(this.length, 1) : this.length;
- for (var j = 0; j < jj; j++) {
- var nodeValue = fn(this[j], arg1, arg2);
- value = value ? value + nodeValue : nodeValue;
- }
- return value;
- }
- } else {
- // we are a write, so apply to all children
- for (i = 0; i < this.length; i++) {
- fn(this[i], arg1, arg2);
- }
- // return self for chaining
- return this;
- }
- };
-});
-
-function createEventHandler(element, events) {
- var eventHandler = function (event, type) {
- if (!event.preventDefault) {
- event.preventDefault = function() {
- event.returnValue = false; //ie
- };
- }
-
- if (!event.stopPropagation) {
- event.stopPropagation = function() {
- event.cancelBubble = true; //ie
- };
- }
-
- if (!event.target) {
- event.target = event.srcElement || document;
- }
-
- if (isUndefined(event.defaultPrevented)) {
- var prevent = event.preventDefault;
- event.preventDefault = function() {
- event.defaultPrevented = true;
- prevent.call(event);
- };
- event.defaultPrevented = false;
- }
-
- event.isDefaultPrevented = function() {
- return event.defaultPrevented || event.returnValue === false;
- };
-
- forEach(events[type || event.type], function(fn) {
- fn.call(element, event);
- });
-
- // Remove monkey-patched methods (IE),
- // as they would cause memory leaks in IE8.
- if (msie <= 8) {
- // IE7/8 does not allow to delete property on native object
- event.preventDefault = null;
- event.stopPropagation = null;
- event.isDefaultPrevented = null;
- } else {
- // It shouldn't affect normal browsers (native methods are defined on prototype).
- delete event.preventDefault;
- delete event.stopPropagation;
- delete event.isDefaultPrevented;
- }
- };
- eventHandler.elem = element;
- return eventHandler;
-}
-
-//////////////////////////////////////////
-// Functions iterating traversal.
-// These functions chain results into a single
-// selector.
-//////////////////////////////////////////
-forEach({
- removeData: jqLiteRemoveData,
-
- dealoc: jqLiteDealoc,
-
- on: function onFn(element, type, fn, unsupported){
- if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
-
- var events = jqLiteExpandoStore(element, 'events'),
- handle = jqLiteExpandoStore(element, 'handle');
-
- if (!events) jqLiteExpandoStore(element, 'events', events = {});
- if (!handle) jqLiteExpandoStore(element, 'handle', handle = createEventHandler(element, events));
-
- forEach(type.split(' '), function(type){
- var eventFns = events[type];
-
- if (!eventFns) {
- if (type == 'mouseenter' || type == 'mouseleave') {
- var contains = document.body.contains || document.body.compareDocumentPosition ?
- function( a, b ) {
- // jshint bitwise: false
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ));
- } :
- function( a, b ) {
- if ( b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
-
- events[type] = [];
-
- // Refer to jQuery's implementation of mouseenter & mouseleave
- // Read about mouseenter and mouseleave:
- // http://www.quirksmode.org/js/events_mouse.html#link8
- var eventmap = { mouseleave : "mouseout", mouseenter : "mouseover"};
-
- onFn(element, eventmap[type], function(event) {
- var target = this, related = event.relatedTarget;
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !contains(target, related)) ){
- handle(event, type);
- }
- });
-
- } else {
- addEventListenerFn(element, type, handle);
- events[type] = [];
- }
- eventFns = events[type];
- }
- eventFns.push(fn);
- });
- },
-
- off: jqLiteOff,
-
- replaceWith: function(element, replaceNode) {
- var index, parent = element.parentNode;
- jqLiteDealoc(element);
- forEach(new JQLite(replaceNode), function(node){
- if (index) {
- parent.insertBefore(node, index.nextSibling);
- } else {
- parent.replaceChild(node, element);
- }
- index = node;
- });
- },
-
- children: function(element) {
- var children = [];
- forEach(element.childNodes, function(element){
- if (element.nodeType === 1)
- children.push(element);
- });
- return children;
- },
-
- contents: function(element) {
- return element.childNodes || [];
- },
-
- append: function(element, node) {
- forEach(new JQLite(node), function(child){
- if (element.nodeType === 1 || element.nodeType === 11) {
- element.appendChild(child);
- }
- });
- },
-
- prepend: function(element, node) {
- if (element.nodeType === 1) {
- var index = element.firstChild;
- forEach(new JQLite(node), function(child){
- element.insertBefore(child, index);
- });
- }
- },
-
- wrap: function(element, wrapNode) {
- wrapNode = jqLite(wrapNode)[0];
- var parent = element.parentNode;
- if (parent) {
- parent.replaceChild(wrapNode, element);
- }
- wrapNode.appendChild(element);
- },
-
- remove: function(element) {
- jqLiteDealoc(element);
- var parent = element.parentNode;
- if (parent) parent.removeChild(element);
- },
-
- after: function(element, newElement) {
- var index = element, parent = element.parentNode;
- forEach(new JQLite(newElement), function(node){
- parent.insertBefore(node, index.nextSibling);
- index = node;
- });
- },
-
- addClass: jqLiteAddClass,
- removeClass: jqLiteRemoveClass,
-
- toggleClass: function(element, selector, condition) {
- if (isUndefined(condition)) {
- condition = !jqLiteHasClass(element, selector);
- }
- (condition ? jqLiteAddClass : jqLiteRemoveClass)(element, selector);
- },
-
- parent: function(element) {
- var parent = element.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
- },
-
- next: function(element) {
- if (element.nextElementSibling) {
- return element.nextElementSibling;
- }
-
- // IE8 doesn't have nextElementSibling
- var elm = element.nextSibling;
- while (elm != null && elm.nodeType !== 1) {
- elm = elm.nextSibling;
- }
- return elm;
- },
-
- find: function(element, selector) {
- if (element.getElementsByTagName) {
- return element.getElementsByTagName(selector);
- } else {
- return [];
- }
- },
-
- clone: jqLiteClone,
-
- triggerHandler: function(element, eventName, eventData) {
- var eventFns = (jqLiteExpandoStore(element, 'events') || {})[eventName];
-
- eventData = eventData || [];
-
- var event = [{
- preventDefault: noop,
- stopPropagation: noop
- }];
-
- forEach(eventFns, function(fn) {
- fn.apply(element, event.concat(eventData));
- });
- }
-}, function(fn, name){
- /**
- * chaining functions
- */
- JQLite.prototype[name] = function(arg1, arg2, arg3) {
- var value;
- for(var i=0; i < this.length; i++) {
- if (isUndefined(value)) {
- value = fn(this[i], arg1, arg2, arg3);
- if (isDefined(value)) {
- // any function which returns a value needs to be wrapped
- value = jqLite(value);
- }
- } else {
- jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
- }
- }
- return isDefined(value) ? value : this;
- };
-
- // bind legacy bind/unbind to on/off
- JQLite.prototype.bind = JQLite.prototype.on;
- JQLite.prototype.unbind = JQLite.prototype.off;
-});
-
-/**
- * Computes a hash of an 'obj'.
- * Hash of a:
- * string is string
- * number is number as string
- * object is either result of calling $$hashKey function on the object or uniquely generated id,
- * that is also assigned to the $$hashKey property of the object.
- *
- * @param obj
- * @returns {string} hash string such that the same input will have the same hash string.
- * The resulting string key is in 'type:hashKey' format.
- */
-function hashKey(obj) {
- var objType = typeof obj,
- key;
-
- if (objType == 'object' && obj !== null) {
- if (typeof (key = obj.$$hashKey) == 'function') {
- // must invoke on object to keep the right this
- key = obj.$$hashKey();
- } else if (key === undefined) {
- key = obj.$$hashKey = nextUid();
- }
- } else {
- key = obj;
- }
-
- return objType + ':' + key;
-}
-
-/**
- * HashMap which can use objects as keys
- */
-function HashMap(array){
- forEach(array, this.put, this);
-}
-HashMap.prototype = {
- /**
- * Store key value pair
- * @param key key to store can be any type
- * @param value value to store can be any type
- */
- put: function(key, value) {
- this[hashKey(key)] = value;
- },
-
- /**
- * @param key
- * @returns the value for the key
- */
- get: function(key) {
- return this[hashKey(key)];
- },
-
- /**
- * Remove the key/value pair
- * @param key
- */
- remove: function(key) {
- var value = this[key = hashKey(key)];
- delete this[key];
- return value;
- }
-};
-
-/**
- * @ngdoc function
- * @name angular.injector
- * @function
- *
- * @description
- * Creates an injector function that can be used for retrieving services as well as for
- * dependency injection (see {@link guide/di dependency injection}).
- *
-
- * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
- * {@link angular.module}. The `ng` module must be explicitly added.
- * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
- *
- * @example
- * Typical usage
- * <pre>
- * // create an injector
- * var $injector = angular.injector(['ng']);
- *
- * // use the injector to kick off your application
- * // use the type inference to auto inject arguments, or use implicit injection
- * $injector.invoke(function($rootScope, $compile, $document){
- * $compile($document)($rootScope);
- * $rootScope.$digest();
- * });
- * </pre>
- *
- * Sometimes you want to get access to the injector of a currently running Angular app
- * from outside Angular. Perhaps, you want to inject and compile some markup after the
- * application has been bootstrapped. You can do this using extra `injector()` added
- * to JQuery/jqLite elements. See {@link angular.element}.
- *
- * *This is fairly rare but could be the case if a third party library is injecting the
- * markup.*
- *
- * In the following example a new block of HTML containing a `ng-controller`
- * directive is added to the end of the document body by JQuery. We then compile and link
- * it into the current AngularJS scope.
- *
- * <pre>
- * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
- * $(document.body).append($div);
- *
- * angular.element(document).injector().invoke(function($compile) {
- * var scope = angular.element($div).scope();
- * $compile($div)(scope);
- * });
- * </pre>
- */
-
-
-/**
- * @ngdoc overview
- * @name AUTO
- * @description
- *
- * Implicit module which gets automatically added to each {@link AUTO.$injector $injector}.
- */
-
-var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
-var FN_ARG_SPLIT = /,/;
-var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
-var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
-var $injectorMinErr = minErr('$injector');
-function annotate(fn) {
- var $inject,
- fnText,
- argDecl,
- last;
-
- if (typeof fn == 'function') {
- if (!($inject = fn.$inject)) {
- $inject = [];
- if (fn.length) {
- fnText = fn.toString().replace(STRIP_COMMENTS, '');
- argDecl = fnText.match(FN_ARGS);
- forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
- arg.replace(FN_ARG, function(all, underscore, name){
- $inject.push(name);
- });
- });
- }
- fn.$inject = $inject;
- }
- } else if (isArray(fn)) {
- last = fn.length - 1;
- assertArgFn(fn[last], 'fn');
- $inject = fn.slice(0, last);
- } else {
- assertArgFn(fn, 'fn', true);
- }
- return $inject;
-}
-
-///////////////////////////////////////
-
-/**
- * @ngdoc object
- * @name AUTO.$injector
- * @function
- *
- * @description
- *
- * `$injector` is used to retrieve object instances as defined by
- * {@link AUTO.$provide provider}, instantiate types, invoke methods,
- * and load modules.
- *
- * The following always holds true:
- *
- * <pre>
- * var $injector = angular.injector();
- * expect($injector.get('$injector')).toBe($injector);
- * expect($injector.invoke(function($injector){
- * return $injector;
- * }).toBe($injector);
- * </pre>
- *
- * # Injection Function Annotation
- *
- * JavaScript does not have annotations, and annotations are needed for dependency injection. The
- * following are all valid ways of annotating function with injection arguments and are equivalent.
- *
- * <pre>
- * // inferred (only works if code not minified/obfuscated)
- * $injector.invoke(function(serviceA){});
- *
- * // annotated
- * function explicit(serviceA) {};
- * explicit.$inject = ['serviceA'];
- * $injector.invoke(explicit);
- *
- * // inline
- * $injector.invoke(['serviceA', function(serviceA){}]);
- * </pre>
- *
- * ## Inference
- *
- * In JavaScript calling `toString()` on a function returns the function definition. The definition
- * can then be parsed and the function arguments can be extracted. *NOTE:* This does not work with
- * minification, and obfuscation tools since these tools change the argument names.
- *
- * ## `$inject` Annotation
- * By adding a `$inject` property onto a function the injection parameters can be specified.
- *
- * ## Inline
- * As an array of injection names, where the last item in the array is the function to call.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$injector#get
- * @methodOf AUTO.$injector
- *
- * @description
- * Return an instance of the service.
- *
- * @param {string} name The name of the instance to retrieve.
- * @return {*} The instance.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$injector#invoke
- * @methodOf AUTO.$injector
- *
- * @description
- * Invoke the method and supply the method arguments from the `$injector`.
- *
- * @param {!function} fn The function to invoke. Function parameters are injected according to the
- * {@link guide/di $inject Annotation} rules.
- * @param {Object=} self The `this` for the invoked method.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {*} the value returned by the invoked `fn` function.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$injector#has
- * @methodOf AUTO.$injector
- *
- * @description
- * Allows the user to query if the particular service exist.
- *
- * @param {string} Name of the service to query.
- * @returns {boolean} returns true if injector has given service.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$injector#instantiate
- * @methodOf AUTO.$injector
- * @description
- * Create a new instance of JS type. The method takes a constructor function invokes the new
- * operator and supplies all of the arguments to the constructor function as specified by the
- * constructor annotation.
- *
- * @param {function} Type Annotated constructor function.
- * @param {Object=} locals Optional object. If preset then any argument names are read from this
- * object first, before the `$injector` is consulted.
- * @returns {Object} new instance of `Type`.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$injector#annotate
- * @methodOf AUTO.$injector
- *
- * @description
- * Returns an array of service names which the function is requesting for injection. This API is
- * used by the injector to determine which services need to be injected into the function when the
- * function is invoked. There are three ways in which the function can be annotated with the needed
- * dependencies.
- *
- * # Argument names
- *
- * The simplest form is to extract the dependencies from the arguments of the function. This is done
- * by converting the function into a string using `toString()` method and extracting the argument
- * names.
- * <pre>
- * // Given
- * function MyController($scope, $route) {
- * // ...
- * }
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * </pre>
- *
- * This method does not work with code minification / obfuscation. For this reason the following
- * annotation strategies are supported.
- *
- * # The `$inject` property
- *
- * If a function has an `$inject` property and its value is an array of strings, then the strings
- * represent names of services to be injected into the function.
- * <pre>
- * // Given
- * var MyController = function(obfuscatedScope, obfuscatedRoute) {
- * // ...
- * }
- * // Define function dependencies
- * MyController['$inject'] = ['$scope', '$route'];
- *
- * // Then
- * expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
- * </pre>
- *
- * # The array notation
- *
- * It is often desirable to inline Injected functions and that's when setting the `$inject` property
- * is very inconvenient. In these situations using the array notation to specify the dependencies in
- * a way that survives minification is a better choice:
- *
- * <pre>
- * // We wish to write this (not minification / obfuscation safe)
- * injector.invoke(function($compile, $rootScope) {
- * // ...
- * });
- *
- * // We are forced to write break inlining
- * var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
- * // ...
- * };
- * tmpFn.$inject = ['$compile', '$rootScope'];
- * injector.invoke(tmpFn);
- *
- * // To better support inline function the inline annotation is supported
- * injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
- * // ...
- * }]);
- *
- * // Therefore
- * expect(injector.annotate(
- * ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
- * ).toEqual(['$compile', '$rootScope']);
- * </pre>
- *
- * @param {function|Array.<string|Function>} fn Function for which dependent service names need to
- * be retrieved as described above.
- *
- * @returns {Array.<string>} The names of the services which the function requires.
- */
-
-
-
-
-/**
- * @ngdoc object
- * @name AUTO.$provide
- *
- * @description
- *
- * The {@link AUTO.$provide $provide} service has a number of methods for registering components
- * with the {@link AUTO.$injector $injector}. Many of these functions are also exposed on
- * {@link angular.Module}.
- *
- * An Angular **service** is a singleton object created by a **service factory**. These **service
- * factories** are functions which, in turn, are created by a **service provider**.
- * The **service providers** are constructor functions. When instantiated they must contain a
- * property called `$get`, which holds the **service factory** function.
- *
- * When you request a service, the {@link AUTO.$injector $injector} is responsible for finding the
- * correct **service provider**, instantiating it and then calling its `$get` **service factory**
- * function to get the instance of the **service**.
- *
- * Often services have no configuration options and there is no need to add methods to the service
- * provider. The provider will be no more than a constructor function with a `$get` property. For
- * these cases the {@link AUTO.$provide $provide} service has additional helper methods to register
- * services without specifying a provider.
- *
- * * {@link AUTO.$provide#methods_provider provider(provider)} - registers a **service provider** with the
- * {@link AUTO.$injector $injector}
- * * {@link AUTO.$provide#methods_constant constant(obj)} - registers a value/object that can be accessed by
- * providers and services.
- * * {@link AUTO.$provide#methods_value value(obj)} - registers a value/object that can only be accessed by
- * services, not providers.
- * * {@link AUTO.$provide#methods_factory factory(fn)} - registers a service **factory function**, `fn`,
- * that will be wrapped in a **service provider** object, whose `$get` property will contain the
- * given factory function.
- * * {@link AUTO.$provide#methods_service service(class)} - registers a **constructor function**, `class` that
- * that will be wrapped in a **service provider** object, whose `$get` property will instantiate
- * a new object using the given constructor function.
- *
- * See the individual methods for more information and examples.
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#provider
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **provider function** with the {@link AUTO.$injector $injector}. Provider functions
- * are constructor functions, whose instances are responsible for "providing" a factory for a
- * service.
- *
- * Service provider names start with the name of the service they provide followed by `Provider`.
- * For example, the {@link ng.$log $log} service has a provider called
- * {@link ng.$logProvider $logProvider}.
- *
- * Service provider objects can have additional methods which allow configuration of the provider
- * and its service. Importantly, you can configure what kind of service is created by the `$get`
- * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
- * method {@link ng.$logProvider#debugEnabled debugEnabled}
- * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
- * console or not.
- *
- * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
- 'Provider'` key.
- * @param {(Object|function())} provider If the provider is:
- *
- * - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
- * {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be
- * created.
- * - `Constructor`: a new instance of the provider will be created using
- * {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as
- * `object`.
- *
- * @returns {Object} registered provider instance
-
- * @example
- *
- * The following example shows how to create a simple event tracking service and register it using
- * {@link AUTO.$provide#methods_provider $provide.provider()}.
- *
- * <pre>
- * // Define the eventTracker provider
- * function EventTrackerProvider() {
- * var trackingUrl = '/track';
- *
- * // A provider method for configuring where the tracked events should been saved
- * this.setTrackingUrl = function(url) {
- * trackingUrl = url;
- * };
- *
- * // The service factory function
- * this.$get = ['$http', function($http) {
- * var trackedEvents = {};
- * return {
- * // Call this to track an event
- * event: function(event) {
- * var count = trackedEvents[event] || 0;
- * count += 1;
- * trackedEvents[event] = count;
- * return count;
- * },
- * // Call this to save the tracked events to the trackingUrl
- * save: function() {
- * $http.post(trackingUrl, trackedEvents);
- * }
- * };
- * }];
- * }
- *
- * describe('eventTracker', function() {
- * var postSpy;
- *
- * beforeEach(module(function($provide) {
- * // Register the eventTracker provider
- * $provide.provider('eventTracker', EventTrackerProvider);
- * }));
- *
- * beforeEach(module(function(eventTrackerProvider) {
- * // Configure eventTracker provider
- * eventTrackerProvider.setTrackingUrl('/custom-track');
- * }));
- *
- * it('tracks events', inject(function(eventTracker) {
- * expect(eventTracker.event('login')).toEqual(1);
- * expect(eventTracker.event('login')).toEqual(2);
- * }));
- *
- * it('saves to the tracking url', inject(function(eventTracker, $http) {
- * postSpy = spyOn($http, 'post');
- * eventTracker.event('login');
- * eventTracker.save();
- * expect(postSpy).toHaveBeenCalled();
- * expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
- * expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
- * expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
- * }));
- * });
- * </pre>
- */
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#factory
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **service factory**, which will be called to return the service instance.
- * This is short for registering a service where its provider consists of only a `$get` property,
- * which is the given service factory function.
- * You should use {@link AUTO.$provide#factory $provide.factory(getFn)} if you do not need to
- * configure your service in a provider.
- *
- * @param {string} name The name of the instance.
- * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand
- * for `$provide.provider(name, {$get: $getFn})`.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service
- * <pre>
- * $provide.factory('ping', ['$http', function($http) {
- * return function ping() {
- * return $http.send('/ping');
- * };
- * }]);
- * </pre>
- * You would then inject and use this service like this:
- * <pre>
- * someModule.controller('Ctrl', ['ping', function(ping) {
- * ping();
- * }]);
- * </pre>
- */
-
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#service
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **service constructor**, which will be invoked with `new` to create the service
- * instance.
- * This is short for registering a service where its provider's `$get` property is the service
- * constructor function that will be used to instantiate the service instance.
- *
- * You should use {@link AUTO.$provide#methods_service $provide.service(class)} if you define your service
- * as a type/class. This is common when using {@link http://coffeescript.org CoffeeScript}.
- *
- * @param {string} name The name of the instance.
- * @param {Function} constructor A class (constructor function) that will be instantiated.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here is an example of registering a service using
- * {@link AUTO.$provide#methods_service $provide.service(class)} that is defined as a CoffeeScript class.
- * <pre>
- * class Ping
- * constructor: (@$http)->
- * send: ()=>
- * @$http.get('/ping')
- *
- * $provide.service('ping', ['$http', Ping])
- * </pre>
- * You would then inject and use this service like this:
- * <pre>
- * someModule.controller 'Ctrl', ['ping', (ping)->
- * ping.send()
- * ]
- * </pre>
- */
-
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#value
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **value service** with the {@link AUTO.$injector $injector}, such as a string, a
- * number, an array, an object or a function. This is short for registering a service where its
- * provider's `$get` property is a factory function that takes no arguments and returns the **value
- * service**.
- *
- * Value services are similar to constant services, except that they cannot be injected into a
- * module configuration function (see {@link angular.Module#config}) but they can be overridden by
- * an Angular
- * {@link AUTO.$provide#decorator decorator}.
- *
- * @param {string} name The name of the instance.
- * @param {*} value The value.
- * @returns {Object} registered provider instance
- *
- * @example
- * Here are some examples of creating value services.
- * <pre>
- * $provide.value('ADMIN_USER', 'admin');
- *
- * $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
- *
- * $provide.value('halfOf', function(value) {
- * return value / 2;
- * });
- * </pre>
- */
-
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#constant
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **constant service**, such as a string, a number, an array, an object or a function,
- * with the {@link AUTO.$injector $injector}. Unlike {@link AUTO.$provide#value value} it can be
- * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
- * be overridden by an Angular {@link AUTO.$provide#decorator decorator}.
- *
- * @param {string} name The name of the constant.
- * @param {*} value The constant value.
- * @returns {Object} registered instance
- *
- * @example
- * Here a some examples of creating constants:
- * <pre>
- * $provide.constant('SHARD_HEIGHT', 306);
- *
- * $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
- *
- * $provide.constant('double', function(value) {
- * return value * 2;
- * });
- * </pre>
- */
-
-
-/**
- * @ngdoc method
- * @name AUTO.$provide#decorator
- * @methodOf AUTO.$provide
- * @description
- *
- * Register a **service decorator** with the {@link AUTO.$injector $injector}. A service decorator
- * intercepts the creation of a service, allowing it to override or modify the behaviour of the
- * service. The object returned by the decorator may be the original service, or a new service
- * object which replaces or wraps and delegates to the original service.
- *
- * @param {string} name The name of the service to decorate.
- * @param {function()} decorator This function will be invoked when the service needs to be
- * instantiated and should return the decorated service instance. The function is called using
- * the {@link AUTO.$injector#invoke injector.invoke} method and is therefore fully injectable.
- * Local injection arguments:
- *
- * * `$delegate` - The original service instance, which can be monkey patched, configured,
- * decorated or delegated to.
- *
- * @example
- * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
- * calls to {@link ng.$log#error $log.warn()}.
- * <pre>
- * $provider.decorator('$log', ['$delegate', function($delegate) {
- * $delegate.warn = $delegate.error;
- * return $delegate;
- * }]);
- * </pre>
- */
-
-
-function createInjector(modulesToLoad) {
- var INSTANTIATING = {},
- providerSuffix = 'Provider',
- path = [],
- loadedModules = new HashMap(),
- providerCache = {
- $provide: {
- provider: supportObject(provider),
- factory: supportObject(factory),
- service: supportObject(service),
- value: supportObject(value),
- constant: supportObject(constant),
- decorator: decorator
- }
- },
- providerInjector = (providerCache.$injector =
- createInternalInjector(providerCache, function() {
- throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
- })),
- instanceCache = {},
- instanceInjector = (instanceCache.$injector =
- createInternalInjector(instanceCache, function(servicename) {
- var provider = providerInjector.get(servicename + providerSuffix);
- return instanceInjector.invoke(provider.$get, provider);
- }));
-
-
- forEach(loadModules(modulesToLoad), function(fn) { instanceInjector.invoke(fn || noop); });
-
- return instanceInjector;
-
- ////////////////////////////////////
- // $provider
- ////////////////////////////////////
-
- function supportObject(delegate) {
- return function(key, value) {
- if (isObject(key)) {
- forEach(key, reverseParams(delegate));
- } else {
- return delegate(key, value);
- }
- };
- }
-
- function provider(name, provider_) {
- assertNotHasOwnProperty(name, 'service');
- if (isFunction(provider_) || isArray(provider_)) {
- provider_ = providerInjector.instantiate(provider_);
- }
- if (!provider_.$get) {
- throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
- }
- return providerCache[name + providerSuffix] = provider_;
- }
-
- function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }
-
- function service(name, constructor) {
- return factory(name, ['$injector', function($injector) {
- return $injector.instantiate(constructor);
- }]);
- }
-
- function value(name, val) { return factory(name, valueFn(val)); }
-
- function constant(name, value) {
- assertNotHasOwnProperty(name, 'constant');
- providerCache[name] = value;
- instanceCache[name] = value;
- }
-
- function decorator(serviceName, decorFn) {
- var origProvider = providerInjector.get(serviceName + providerSuffix),
- orig$get = origProvider.$get;
-
- origProvider.$get = function() {
- var origInstance = instanceInjector.invoke(orig$get, origProvider);
- return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
- };
- }
-
- ////////////////////////////////////
- // Module Loading
- ////////////////////////////////////
- function loadModules(modulesToLoad){
- var runBlocks = [], moduleFn, invokeQueue, i, ii;
- forEach(modulesToLoad, function(module) {
- if (loadedModules.get(module)) return;
- loadedModules.put(module, true);
-
- try {
- if (isString(module)) {
- moduleFn = angularModule(module);
- runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
-
- for(invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
- var invokeArgs = invokeQueue[i],
- provider = providerInjector.get(invokeArgs[0]);
-
- provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
- }
- } else if (isFunction(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else if (isArray(module)) {
- runBlocks.push(providerInjector.invoke(module));
- } else {
- assertArgFn(module, 'module');
- }
- } catch (e) {
- if (isArray(module)) {
- module = module[module.length - 1];
- }
- if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
- // Safari & FF's stack traces don't contain error.message content
- // unlike those of Chrome and IE
- // So if stack doesn't contain message, we create a new string that contains both.
- // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
- /* jshint -W022 */
- e = e.message + '\n' + e.stack;
- }
- throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
- module, e.stack || e.message || e);
- }
- });
- return runBlocks;
- }
-
- ////////////////////////////////////
- // internal Injector
- ////////////////////////////////////
-
- function createInternalInjector(cache, factory) {
-
- function getService(serviceName) {
- if (cache.hasOwnProperty(serviceName)) {
- if (cache[serviceName] === INSTANTIATING) {
- throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
- }
- return cache[serviceName];
- } else {
- try {
- path.unshift(serviceName);
- cache[serviceName] = INSTANTIATING;
- return cache[serviceName] = factory(serviceName);
- } finally {
- path.shift();
- }
- }
- }
-
- function invoke(fn, self, locals){
- var args = [],
- $inject = annotate(fn),
- length, i,
- key;
-
- for(i = 0, length = $inject.length; i < length; i++) {
- key = $inject[i];
- if (typeof key !== 'string') {
- throw $injectorMinErr('itkn',
- 'Incorrect injection token! Expected service name as string, got {0}', key);
- }
- args.push(
- locals && locals.hasOwnProperty(key)
- ? locals[key]
- : getService(key)
- );
- }
- if (!fn.$inject) {
- // this means that we must be an array.
- fn = fn[length];
- }
-
- // http://jsperf.com/angularjs-invoke-apply-vs-switch
- // #5388
- return fn.apply(self, args);
- }
-
- function instantiate(Type, locals) {
- var Constructor = function() {},
- instance, returnedValue;
-
- // Check if Type is annotated and use just the given function at n-1 as parameter
- // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
- Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
- instance = new Constructor();
- returnedValue = invoke(Type, instance, locals);
-
- return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
- }
-
- return {
- invoke: invoke,
- instantiate: instantiate,
- get: getService,
- annotate: annotate,
- has: function(name) {
- return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
- }
- };
- }
-}
-
-/**
- * @ngdoc function
- * @name ng.$anchorScroll
- * @requires $window
- * @requires $location
- * @requires $rootScope
- *
- * @description
- * When called, it checks current value of `$location.hash()` and scroll to related element,
- * according to rules specified in
- * {@link http://dev.w3.org/html5/spec/Overview.html#the-indicated-part-of-the-document Html5 spec}.
- *
- * It also watches the `$location.hash()` and scrolls whenever it changes to match any anchor.
- * This can be disabled by calling `$anchorScrollProvider.disableAutoScrolling()`.
- *
- * @example
- <example>
- <file name="index.html">
- <div id="scrollArea" ng-controller="ScrollCtrl">
- <a ng-click="gotoBottom()">Go to bottom</a>
- <a id="bottom"></a> You're at the bottom!
- </div>
- </file>
- <file name="script.js">
- function ScrollCtrl($scope, $location, $anchorScroll) {
- $scope.gotoBottom = function (){
- // set the location.hash to the id of
- // the element you wish to scroll to.
- $location.hash('bottom');
-
- // call $anchorScroll()
- $anchorScroll();
- }
- }
- </file>
- <file name="style.css">
- #scrollArea {
- height: 350px;
- overflow: auto;
- }
-
- #bottom {
- display: block;
- margin-top: 2000px;
- }
- </file>
- </example>
- */
-function $AnchorScrollProvider() {
-
- var autoScrollingEnabled = true;
-
- this.disableAutoScrolling = function() {
- autoScrollingEnabled = false;
- };
-
- this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
- var document = $window.document;
-
- // helper function to get first anchor from a NodeList
- // can't use filter.filter, as it accepts only instances of Array
- // and IE can't convert NodeList to an array using [].slice
- // TODO(vojta): use filter if we change it to accept lists as well
- function getFirstAnchor(list) {
- var result = null;
- forEach(list, function(element) {
- if (!result && lowercase(element.nodeName) === 'a') result = element;
- });
- return result;
- }
-
- function scroll() {
- var hash = $location.hash(), elm;
-
- // empty hash, scroll to the top of the page
- if (!hash) $window.scrollTo(0, 0);
-
- // element with given id
- else if ((elm = document.getElementById(hash))) elm.scrollIntoView();
-
- // first anchor with given name :-D
- else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) elm.scrollIntoView();
-
- // no element and hash == 'top', scroll to the top of the page
- else if (hash === 'top') $window.scrollTo(0, 0);
- }
-
- // does not scroll when user clicks on anchor link that is currently on
- // (no url change, no $location.hash() change), browser native does scroll
- if (autoScrollingEnabled) {
- $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
- function autoScrollWatchAction() {
- $rootScope.$evalAsync(scroll);
- });
- }
-
- return scroll;
- }];
-}
-
-var $animateMinErr = minErr('$animate');
-
-/**
- * @ngdoc object
- * @name ng.$animateProvider
- *
- * @description
- * Default implementation of $animate that doesn't perform any animations, instead just
- * synchronously performs DOM
- * updates and calls done() callbacks.
- *
- * In order to enable animations the ngAnimate module has to be loaded.
- *
- * To see the functional implementation check out src/ngAnimate/animate.js
- */
-var $AnimateProvider = ['$provide', function($provide) {
-
-
- this.$$selectors = {};
-
-
- /**
- * @ngdoc function
- * @name ng.$animateProvider#register
- * @methodOf ng.$animateProvider
- *
- * @description
- * Registers a new injectable animation factory function. The factory function produces the
- * animation object which contains callback functions for each event that is expected to be
- * animated.
- *
- * * `eventFn`: `function(Element, doneFunction)` The element to animate, the `doneFunction`
- * must be called once the element animation is complete. If a function is returned then the
- * animation service will use this function to cancel the animation whenever a cancel event is
- * triggered.
- *
- *
- *<pre>
- * return {
- * eventFn : function(element, done) {
- * //code to run the animation
- * //once complete, then run done()
- * return function cancellationFunction() {
- * //code to cancel the animation
- * }
- * }
- * }
- *</pre>
- *
- * @param {string} name The name of the animation.
- * @param {function} factory The factory function that will be executed to return the animation
- * object.
- */
- this.register = function(name, factory) {
- var key = name + '-animation';
- if (name && name.charAt(0) != '.') throw $animateMinErr('notcsel',
- "Expecting class selector starting with '.' got '{0}'.", name);
- this.$$selectors[name.substr(1)] = key;
- $provide.factory(key, factory);
- };
-
- this.$get = ['$timeout', function($timeout) {
-
- /**
- *
- * @ngdoc object
- * @name ng.$animate
- * @description The $animate service provides rudimentary DOM manipulation functions to
- * insert, remove and move elements within the DOM, as well as adding and removing classes.
- * This service is the core service used by the ngAnimate $animator service which provides
- * high-level animation hooks for CSS and JavaScript.
- *
- * $animate is available in the AngularJS core, however, the ngAnimate module must be included
- * to enable full out animation support. Otherwise, $animate will only perform simple DOM
- * manipulation operations.
- *
- * To learn more about enabling animation support, click here to visit the {@link ngAnimate
- * ngAnimate module page} as well as the {@link ngAnimate.$animate ngAnimate $animate service
- * page}.
- */
- return {
-
- /**
- *
- * @ngdoc function
- * @name ng.$animate#enter
- * @methodOf ng.$animate
- * @function
- * @description Inserts the element into the DOM either after the `after` element or within
- * the `parent` element. Once complete, the done() callback will be fired (if provided).
- * @param {jQuery/jqLite element} element the element which will be inserted into the DOM
- * @param {jQuery/jqLite element} parent the parent element which will append the element as
- * a child (if the after element is not present)
- * @param {jQuery/jqLite element} after the sibling element which will append the element
- * after itself
- * @param {function=} done callback function that will be called after the element has been
- * inserted into the DOM
- */
- enter : function(element, parent, after, done) {
- if (after) {
- after.after(element);
- } else {
- if (!parent || !parent[0]) {
- parent = after.parent();
- }
- parent.append(element);
- }
- done && $timeout(done, 0, false);
- },
-
- /**
- *
- * @ngdoc function
- * @name ng.$animate#leave
- * @methodOf ng.$animate
- * @function
- * @description Removes the element from the DOM. Once complete, the done() callback will be
- * fired (if provided).
- * @param {jQuery/jqLite element} element the element which will be removed from the DOM
- * @param {function=} done callback function that will be called after the element has been
- * removed from the DOM
- */
- leave : function(element, done) {
- element.remove();
- done && $timeout(done, 0, false);
- },
-
- /**
- *
- * @ngdoc function
- * @name ng.$animate#move
- * @methodOf ng.$animate
- * @function
- * @description Moves the position of the provided element within the DOM to be placed
- * either after the `after` element or inside of the `parent` element. Once complete, the
- * done() callback will be fired (if provided).
- *
- * @param {jQuery/jqLite element} element the element which will be moved around within the
- * DOM
- * @param {jQuery/jqLite element} parent the parent element where the element will be
- * inserted into (if the after element is not present)
- * @param {jQuery/jqLite element} after the sibling element where the element will be
- * positioned next to
- * @param {function=} done the callback function (if provided) that will be fired after the
- * element has been moved to its new position
- */
- move : function(element, parent, after, done) {
- // Do not remove element before insert. Removing will cause data associated with the
- // element to be dropped. Insert will implicitly do the remove.
- this.enter(element, parent, after, done);
- },
-
- /**
- *
- * @ngdoc function
- * @name ng.$animate#addClass
- * @methodOf ng.$animate
- * @function
- * @description Adds the provided className CSS class value to the provided element. Once
- * complete, the done() callback will be fired (if provided).
- * @param {jQuery/jqLite element} element the element which will have the className value
- * added to it
- * @param {string} className the CSS class which will be added to the element
- * @param {function=} done the callback function (if provided) that will be fired after the
- * className value has been added to the element
- */
- addClass : function(element, className, done) {
- className = isString(className) ?
- className :
- isArray(className) ? className.join(' ') : '';
- forEach(element, function (element) {
- jqLiteAddClass(element, className);
- });
- done && $timeout(done, 0, false);
- },
-
- /**
- *
- * @ngdoc function
- * @name ng.$animate#removeClass
- * @methodOf ng.$animate
- * @function
- * @description Removes the provided className CSS class value from the provided element.
- * Once complete, the done() callback will be fired (if provided).
- * @param {jQuery/jqLite element} element the element which will have the className value
- * removed from it
- * @param {string} className the CSS class which will be removed from the element
- * @param {function=} done the callback function (if provided) that will be fired after the
- * className value has been removed from the element
- */
- removeClass : function(element, className, done) {
- className = isString(className) ?
- className :
- isArray(className) ? className.join(' ') : '';
- forEach(element, function (element) {
- jqLiteRemoveClass(element, className);
- });
- done && $timeout(done, 0, false);
- },
-
- enabled : noop
- };
- }];
-}];
-
-/**
- * ! This is a private undocumented service !
- *
- * @name ng.$browser
- * @requires $log
- * @description
- * This object has two goals:
- *
- * - hide all the global state in the browser caused by the window object
- * - abstract away all the browser specific features and inconsistencies
- *
- * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
- * service, which can be used for convenient testing of the application without the interaction with
- * the real browser apis.
- */
-/**
- * @param {object} window The global window object.
- * @param {object} document jQuery wrapped document.
- * @param {function()} XHR XMLHttpRequest constructor.
- * @param {object} $log console.log or an object with the same interface.
- * @param {object} $sniffer $sniffer service
- */
-function Browser(window, document, $log, $sniffer) {
- var self = this,
- rawDocument = document[0],
- location = window.location,
- history = window.history,
- setTimeout = window.setTimeout,
- clearTimeout = window.clearTimeout,
- pendingDeferIds = {};
-
- self.isMock = false;
-
- var outstandingRequestCount = 0;
- var outstandingRequestCallbacks = [];
-
- // TODO(vojta): remove this temporary api
- self.$$completeOutstandingRequest = completeOutstandingRequest;
- self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
-
- /**
- * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
- * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
- */
- function completeOutstandingRequest(fn) {
- try {
- fn.apply(null, sliceArgs(arguments, 1));
- } finally {
- outstandingRequestCount--;
- if (outstandingRequestCount === 0) {
- while(outstandingRequestCallbacks.length) {
- try {
- outstandingRequestCallbacks.pop()();
- } catch (e) {
- $log.error(e);
- }
- }
- }
- }
- }
-
- /**
- * @private
- * Note: this method is used only by scenario runner
- * TODO(vojta): prefix this method with $$ ?
- * @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 {
- outstandingRequestCallbacks.push(callback);
- }
- };
-
- //////////////////////////////////////////////////////////////
- // Poll Watcher API
- //////////////////////////////////////////////////////////////
- var pollFns = [],
- pollTimeout;
-
- /**
- * @name ng.$browser#addPollFn
- * @methodOf ng.$browser
- *
- * @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
- //////////////////////////////////////////////////////////////
-
- var lastBrowserUrl = location.href,
- baseElement = document.find('base'),
- newLocation = null;
-
- /**
- * @name ng.$browser#url
- * @methodOf ng.$browser
- *
- * @description
- * GETTER:
- * Without any argument, this method just returns current value of location.href.
- *
- * SETTER:
- * With at least one argument, this method sets url to new value.
- * If html5 history api supported, pushState/replaceState is used, otherwise
- * location.href/location.replace is used.
- * Returns its own instance to allow chaining
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to change url.
- *
- * @param {string} url New url (when used as setter)
- * @param {boolean=} replace Should new url replace current history record ?
- */
- self.url = function(url, replace) {
- // Android Browser BFCache causes location reference to become stale.
- if (location !== window.location) location = window.location;
-
- // setter
- if (url) {
- if (lastBrowserUrl == url) return;
- lastBrowserUrl = url;
- if ($sniffer.history) {
- if (replace) history.replaceState(null, '', url);
- else {
- history.pushState(null, '', url);
- // Crazy Opera Bug: http://my.opera.com/community/forums/topic.dml?id=1185462
- baseElement.attr('href', baseElement.attr('href'));
- }
- } else {
- newLocation = url;
- if (replace) {
- location.replace(url);
- } else {
- location.href = url;
- }
- }
- return self;
- // getter
- } else {
- // - newLocation is a workaround for an IE7-9 issue with location.replace and location.href
- // methods not updating location.href synchronously.
- // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
- return newLocation || location.href.replace(/%27/g,"'");
- }
- };
-
- var urlChangeListeners = [],
- urlChangeInit = false;
-
- function fireUrlChange() {
- newLocation = null;
- if (lastBrowserUrl == self.url()) return;
-
- lastBrowserUrl = self.url();
- forEach(urlChangeListeners, function(listener) {
- listener(self.url());
- });
- }
-
- /**
- * @name ng.$browser#onUrlChange
- * @methodOf ng.$browser
- * @TODO(vojta): refactor to use node's syntax for events
- *
- * @description
- * Register callback function that will be called, when url changes.
- *
- * It's only called when the url is changed by outside of angular:
- * - user types different url into address bar
- * - user clicks on history (forward/back) button
- * - user clicks on a link
- *
- * It's not called when url is changed by $browser.url() method
- *
- * The listener gets called with new url as parameter.
- *
- * NOTE: this api is intended for use only by the $location service. Please use the
- * {@link ng.$location $location service} to monitor url changes in angular apps.
- *
- * @param {function(string)} listener Listener function to be called when url changes.
- * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
- */
- self.onUrlChange = function(callback) {
- if (!urlChangeInit) {
- // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
- // don't fire popstate when user change the address bar and don't fire hashchange when url
- // changed by push/replaceState
-
- // html5 history api - popstate event
- if ($sniffer.history) jqLite(window).on('popstate', fireUrlChange);
- // hashchange event
- if ($sniffer.hashchange) jqLite(window).on('hashchange', fireUrlChange);
- // polling
- else self.addPollFn(fireUrlChange);
-
- urlChangeInit = true;
- }
-
- urlChangeListeners.push(callback);
- return callback;
- };
-
- //////////////////////////////////////////////////////////////
- // Misc API
- //////////////////////////////////////////////////////////////
-
- /**
- * @name ng.$browser#baseHref
- * @methodOf ng.$browser
- *
- * @description
- * Returns current <base href>
- * (always relative - without domain)
- *
- * @returns {string=} current <base href>
- */
- self.baseHref = function() {
- var href = baseElement.attr('href');
- return href ? href.replace(/^https?\:\/\/[^\/]*/, '') : '';
- };
-
- //////////////////////////////////////////////////////////////
- // Cookies API
- //////////////////////////////////////////////////////////////
- var lastCookies = {};
- var lastCookieString = '';
- var cookiePath = self.baseHref();
-
- /**
- * @name ng.$browser#cookies
- * @methodOf ng.$browser
- *
- * @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) {
- /* global escape: false, unescape: false */
- var cookieLength, cookieArray, cookie, i, index;
-
- if (name) {
- if (value === undefined) {
- rawDocument.cookie = escape(name) + "=;path=" + cookiePath +
- ";expires=Thu, 01 Jan 1970 00:00:00 GMT";
- } else {
- if (isString(value)) {
- cookieLength = (rawDocument.cookie = escape(name) + '=' + escape(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 = unescape(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] = unescape(cookie.substring(index + 1));
- }
- }
- }
- }
- return lastCookies;
- }
- };
-
-
- /**
- * @name ng.$browser#defer
- * @methodOf ng.$browser
- * @param {function()} fn A function, who's execution should be deferred.
- * @param {number=} [delay=0] of milliseconds to defer the function execution.
- * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
- *
- * @description
- * Executes a fn asynchronously via `setTimeout(fn, delay)`.
- *
- * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
- * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
- * via `$browser.defer.flush()`.
- *
- */
- self.defer = function(fn, delay) {
- var timeoutId;
- outstandingRequestCount++;
- timeoutId = setTimeout(function() {
- delete pendingDeferIds[timeoutId];
- completeOutstandingRequest(fn);
- }, delay || 0);
- pendingDeferIds[timeoutId] = true;
- return timeoutId;
- };
-
-
- /**
- * @name ng.$browser#defer.cancel
- * @methodOf ng.$browser.defer
- *
- * @description
- * Cancels a deferred task identified with `deferId`.
- *
- * @param {*} deferId Token returned by the `$browser.defer` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
- * canceled.
- */
- self.defer.cancel = function(deferId) {
- if (pendingDeferIds[deferId]) {
- delete pendingDeferIds[deferId];
- clearTimeout(deferId);
- completeOutstandingRequest(noop);
- return true;
- }
- return false;
- };
-
-}
-
-function $BrowserProvider(){
- this.$get = ['$window', '$log', '$sniffer', '$document',
- function( $window, $log, $sniffer, $document){
- return new Browser($window, $document, $log, $sniffer);
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$cacheFactory
- *
- * @description
- * Factory that constructs cache objects and gives access to them.
- *
- * <pre>
- *
- * var cache = $cacheFactory('cacheId');
- * expect($cacheFactory.get('cacheId')).toBe(cache);
- * expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
- *
- * cache.put("key", "value");
- * cache.put("another key", "another value");
- *
- * // We've specified no options on creation
- * expect(cache.info()).toEqual({id: 'cacheId', size: 2});
- *
- * </pre>
- *
- *
- * @param {string} cacheId Name or id of the newly created cache.
- * @param {object=} options Options object that specifies the cache behavior. Properties:
- *
- * - `{number=}` `capacity` — turns the cache into LRU cache.
- *
- * @returns {object} Newly created cache object with the following set of methods:
- *
- * - `{object}` `info()` — Returns id, size, and options of cache.
- * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
- * it.
- * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
- * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
- * - `{void}` `removeAll()` — Removes all cached values.
- * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
- *
- */
-function $CacheFactoryProvider() {
-
- this.$get = function() {
- var caches = {};
-
- function cacheFactory(cacheId, options) {
- if (cacheId in caches) {
- throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
- }
-
- var size = 0,
- stats = extend({}, options, {id: cacheId}),
- data = {},
- capacity = (options && options.capacity) || Number.MAX_VALUE,
- lruHash = {},
- freshEnd = null,
- staleEnd = null;
-
- return caches[cacheId] = {
-
- put: function(key, value) {
- var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
-
- refresh(lruEntry);
-
- if (isUndefined(value)) return;
- if (!(key in data)) size++;
- data[key] = value;
-
- if (size > capacity) {
- this.remove(staleEnd.key);
- }
-
- return value;
- },
-
-
- get: function(key) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- refresh(lruEntry);
-
- return data[key];
- },
-
-
- remove: function(key) {
- var lruEntry = lruHash[key];
-
- if (!lruEntry) return;
-
- if (lruEntry == freshEnd) freshEnd = lruEntry.p;
- if (lruEntry == staleEnd) staleEnd = lruEntry.n;
- link(lruEntry.n,lruEntry.p);
-
- delete lruHash[key];
- delete data[key];
- size--;
- },
-
-
- removeAll: function() {
- data = {};
- size = 0;
- lruHash = {};
- freshEnd = staleEnd = null;
- },
-
-
- destroy: function() {
- data = null;
- stats = null;
- lruHash = null;
- delete caches[cacheId];
- },
-
-
- info: function() {
- return extend({}, stats, {size: size});
- }
- };
-
-
- /**
- * makes the `entry` the freshEnd of the LRU linked list
- */
- function refresh(entry) {
- if (entry != freshEnd) {
- if (!staleEnd) {
- staleEnd = entry;
- } else if (staleEnd == entry) {
- staleEnd = entry.n;
- }
-
- link(entry.n, entry.p);
- link(entry, freshEnd);
- freshEnd = entry;
- freshEnd.n = null;
- }
- }
-
-
- /**
- * bidirectionally links two entries of the LRU linked list
- */
- function link(nextEntry, prevEntry) {
- if (nextEntry != prevEntry) {
- if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
- if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
- }
- }
- }
-
-
- /**
- * @ngdoc method
- * @name ng.$cacheFactory#info
- * @methodOf ng.$cacheFactory
- *
- * @description
- * Get information about all the of the caches that have been created
- *
- * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
- */
- cacheFactory.info = function() {
- var info = {};
- forEach(caches, function(cache, cacheId) {
- info[cacheId] = cache.info();
- });
- return info;
- };
-
-
- /**
- * @ngdoc method
- * @name ng.$cacheFactory#get
- * @methodOf ng.$cacheFactory
- *
- * @description
- * Get access to a cache object by the `cacheId` used when it was created.
- *
- * @param {string} cacheId Name or id of a cache to access.
- * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
- */
- cacheFactory.get = function(cacheId) {
- return caches[cacheId];
- };
-
-
- return cacheFactory;
- };
-}
-
-/**
- * @ngdoc object
- * @name ng.$templateCache
- *
- * @description
- * The first time a template is used, it is loaded in the template cache for quick retrieval. You
- * can load templates directly into the cache in a `script` tag, or by consuming the
- * `$templateCache` service directly.
- *
- * Adding via the `script` tag:
- * <pre>
- * <html ng-app>
- * <head>
- * <script type="text/ng-template" id="templateId.html">
- * This is the content of the template
- * </script>
- * </head>
- * ...
- * </html>
- * </pre>
- *
- * **Note:** the `script` tag containing the template does not need to be included in the `head` of
- * the document, but it must be below the `ng-app` definition.
- *
- * Adding via the $templateCache service:
- *
- * <pre>
- * var myApp = angular.module('myApp', []);
- * myApp.run(function($templateCache) {
- * $templateCache.put('templateId.html', 'This is the content of the template');
- * });
- * </pre>
- *
- * To retrieve the template later, simply use it in your HTML:
- * <pre>
- * <div ng-include=" 'templateId.html' "></div>
- * </pre>
- *
- * or get it via Javascript:
- * <pre>
- * $templateCache.get('templateId.html')
- * </pre>
- *
- * See {@link ng.$cacheFactory $cacheFactory}.
- *
- */
-function $TemplateCacheProvider() {
- this.$get = ['$cacheFactory', function($cacheFactory) {
- return $cacheFactory('templates');
- }];
-}
-
-/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
- *
- * DOM-related variables:
- *
- * - "node" - DOM Node
- * - "element" - DOM Element or Node
- * - "$node" or "$element" - jqLite-wrapped node or element
- *
- *
- * Compiler related stuff:
- *
- * - "linkFn" - linking fn of a single directive
- * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
- * - "childLinkFn" - function that aggregates all linking fns for child nodes of a particular node
- * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
- */
-
-
-/**
- * @ngdoc function
- * @name ng.$compile
- * @function
- *
- * @description
- * Compiles a piece of HTML string or DOM into a template and produces a template function, which
- * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
- *
- * The compilation is a process of walking the DOM tree and matching DOM elements to
- * {@link ng.$compileProvider#methods_directive directives}.
- *
- * <div class="alert alert-warning">
- * **Note:** This document is an in-depth reference of all directive options.
- * For a gentle introduction to directives with examples of common use cases,
- * see the {@link guide/directive directive guide}.
- * </div>
- *
- * ## Comprehensive Directive API
- *
- * There are many different options for a directive.
- *
- * The difference resides in the return value of the factory function.
- * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
- * or just the `postLink` function (all other properties will have the default values).
- *
- * <div class="alert alert-success">
- * **Best Practice:** It's recommended to use the "directive definition object" form.
- * </div>
- *
- * Here's an example directive declared with a Directive Definition Object:
- *
- * <pre>
- * var myModule = angular.module(...);
- *
- * myModule.directive('directiveName', function factory(injectables) {
- * var directiveDefinitionObject = {
- * priority: 0,
- * template: '<div></div>', // or // function(tElement, tAttrs) { ... },
- * // or
- * // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
- * replace: false,
- * transclude: false,
- * restrict: 'A',
- * scope: false,
- * controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
- * require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
- * compile: function compile(tElement, tAttrs, transclude) {
- * return {
- * pre: function preLink(scope, iElement, iAttrs, controller) { ... },
- * post: function postLink(scope, iElement, iAttrs, controller) { ... }
- * }
- * // or
- * // return function postLink( ... ) { ... }
- * },
- * // or
- * // link: {
- * // pre: function preLink(scope, iElement, iAttrs, controller) { ... },
- * // post: function postLink(scope, iElement, iAttrs, controller) { ... }
- * // }
- * // or
- * // link: function postLink( ... ) { ... }
- * };
- * return directiveDefinitionObject;
- * });
- * </pre>
- *
- * <div class="alert alert-warning">
- * **Note:** Any unspecified options will use the default value. You can see the default values below.
- * </div>
- *
- * Therefore the above can be simplified as:
- *
- * <pre>
- * var myModule = angular.module(...);
- *
- * myModule.directive('directiveName', function factory(injectables) {
- * var directiveDefinitionObject = {
- * link: function postLink(scope, iElement, iAttrs) { ... }
- * };
- * return directiveDefinitionObject;
- * // or
- * // return function postLink(scope, iElement, iAttrs) { ... }
- * });
- * </pre>
- *
- *
- *
- * ### Directive Definition Object
- *
- * The directive definition object provides instructions to the {@link api/ng.$compile
- * compiler}. The attributes are:
- *
- * #### `priority`
- * When there are multiple directives defined on a single DOM element, sometimes it
- * is necessary to specify the order in which the directives are applied. The `priority` is used
- * to sort the directives before their `compile` functions get called. Priority is defined as a
- * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
- * are also run in priority order, but post-link functions are run in reverse order. The order
- * of directives with the same priority is undefined. The default priority is `0`.
- *
- * #### `terminal`
- * If set to true then the current `priority` will be the last set of directives
- * which will execute (any directives at the current priority will still execute
- * as the order of execution on same `priority` is undefined).
- *
- * #### `scope`
- * **If set to `true`,** then a new scope will be created for this directive. If multiple directives on the
- * same element request a new scope, only one new scope is created. The new scope rule does not
- * apply for the root of the template since the root of the template always gets a new scope.
- *
- * **If set to `{}` (object hash),** then a new "isolate" scope is created. The 'isolate' scope differs from
- * normal scope in that it does not prototypically inherit from the parent scope. This is useful
- * when creating reusable components, which should not accidentally read or modify data in the
- * parent scope.
- *
- * The 'isolate' scope takes an object hash which defines a set of local scope properties
- * derived from the parent scope. These local properties are useful for aliasing values for
- * templates. Locals definition is a hash of local scope property to its source:
- *
- * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
- * always a string since DOM attributes are strings. If no `attr` name is specified then the
- * attribute name is assumed to be the same as the local name.
- * Given `<widget my-attr="hello {{name}}">` and widget definition
- * of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
- * the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
- * `localName` property on the widget scope. The `name` is read from the parent scope (not
- * component scope).
- *
- * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
- * parent scope property of name defined via the value of the `attr` attribute. If no `attr`
- * name is specified then the attribute name is assumed to be the same as the local name.
- * Given `<widget my-attr="parentModel">` and widget definition of
- * `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
- * value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
- * in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
- * scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
- * can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional.
- *
- * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
- * If no `attr` name is specified then the attribute name is assumed to be the same as the
- * local name. Given `<widget my-attr="count = count + value">` and widget definition of
- * `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
- * a function wrapper for the `count = count + value` expression. Often it's desirable to
- * pass data from the isolated scope via an expression and to the parent scope, this can be
- * done by passing a map of local variable names and values into the expression wrapper fn.
- * For example, if the expression is `increment(amount)` then we can specify the amount value
- * by calling the `localFn` as `localFn({amount: 22})`.
- *
- *
- *
- * #### `controller`
- * Controller constructor function. The controller is instantiated before the
- * pre-linking phase and it is shared with other directives (see
- * `require` attribute). This allows the directives to communicate with each other and augment
- * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
- *
- * * `$scope` - Current scope associated with the element
- * * `$element` - Current element
- * * `$attrs` - Current attributes object for the element
- * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope.
- * The scope can be overridden by an optional first argument.
- * `function([scope], cloneLinkingFn)`.
- *
- *
- * #### `require`
- * Require another directive and inject its controller as the fourth argument to the linking function. The
- * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
- * 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:
- *
- * * (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.
- * * `^` - Locate the required controller by searching the element's parents. Throw an error if not found.
- * * `?^` - Attempt to locate the required controller by searching the element's parents or pass `null` to the
- * `link` fn if not found.
- *
- *
- * #### `controllerAs`
- * Controller alias at the directive scope. An alias for the controller so it
- * can be referenced at the directive template. The directive needs to define a scope for this
- * configuration to be used. Useful in the case when directive is used as component.
- *
- *
- * #### `restrict`
- * String of subset of `EACM` which restricts the directive to a specific directive
- * declaration style. If omitted, the default (attributes only) is used.
- *
- * * `E` - Element name: `<my-directive></my-directive>`
- * * `A` - Attribute (default): `<div my-directive="exp"></div>`
- * * `C` - Class: `<div class="my-directive: exp;"></div>`
- * * `M` - Comment: `<!-- directive: my-directive exp -->`
- *
- *
- * #### `template`
- * replace the current element with the contents of the HTML. The replacement process
- * migrates all of the attributes / classes from the old element to the new one. See the
- * {@link guide/directive#creating-custom-directives_creating-directives_template-expanding-directive
- * Directives Guide} for an example.
- *
- * You can specify `template` as a string representing the template or as a function which takes
- * two arguments `tElement` and `tAttrs` (described in the `compile` function api below) and
- * returns a string value representing the template.
- *
- *
- * #### `templateUrl`
- * Same as `template` but the template is loaded from the specified URL. Because
- * the template loading is asynchronous the compilation/linking is suspended until the template
- * is loaded.
- *
- * You can specify `templateUrl` as a string representing the URL or as a function which takes two
- * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
- * a string value representing the url. In either case, the template URL is passed through {@link
- * api/ng.$sce#methods_getTrustedResourceUrl $sce.getTrustedResourceUrl}.
- *
- *
- * #### `replace`
- * specify where the template should be inserted. Defaults to `false`.
- *
- * * `true` - the template will replace the current element.
- * * `false` - the template will replace the contents of the current element.
- *
- *
- * #### `transclude`
- * compile the content of the element and make it available to the directive.
- * Typically used with {@link api/ng.directive:ngTransclude
- * ngTransclude}. The advantage of transclusion is that the linking function receives a
- * transclusion function which is pre-bound to the correct scope. In a typical setup the widget
- * creates an `isolate` scope, but the transclusion is not a child, but a sibling of the `isolate`
- * scope. This makes it possible for the widget to have private state, and the transclusion to
- * be bound to the parent (pre-`isolate`) scope.
- *
- * * `true` - transclude the content of the directive.
- * * `'element'` - transclude the whole element including any directives defined at lower priority.
- *
- *
- * #### `compile`
- *
- * <pre>
- * function compile(tElement, tAttrs, transclude) { ... }
- * </pre>
- *
- * The compile function deals with transforming the template DOM. Since most directives do not do
- * template transformation, it is not used often. Examples that require compile functions are
- * directives that transform template DOM, such as {@link
- * api/ng.directive:ngRepeat ngRepeat}, or load the contents
- * asynchronously, such as {@link api/ngRoute.directive:ngView ngView}. The
- * compile function takes the following arguments.
- *
- * * `tElement` - template element - The element where the directive has been declared. It is
- * safe to do template transformation on the element and child elements only.
- *
- * * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
- * between all directive compile functions.
- *
- * * `transclude` - [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
- *
- * <div class="alert alert-warning">
- * **Note:** The template instance and the link instance may be different objects if the template has
- * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
- * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
- * should be done in a linking function rather than in a compile function.
- * </div>
- *
- * <div class="alert alert-error">
- * **Note:** The `transclude` function that is passed to the compile function is 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.
- * </div>
-
- * A compile function can have a return value which can be either a function or an object.
- *
- * * returning a (post-link) function - is equivalent to registering the linking function via the
- * `link` property of the config object when the compile function is empty.
- *
- * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
- * control when a linking function should be called during the linking phase. See info about
- * pre-linking and post-linking functions below.
- *
- *
- * #### `link`
- * This property is used only if the `compile` property is not defined.
- *
- * <pre>
- * function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
- * </pre>
- *
- * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
- * executed after the template has been cloned. This is where most of the directive logic will be
- * put.
- *
- * * `scope` - {@link api/ng.$rootScope.Scope Scope} - The scope to be used by the
- * directive for registering {@link api/ng.$rootScope.Scope#methods_$watch watches}.
- *
- * * `iElement` - instance element - The element where the directive is to be used. It is safe to
- * manipulate the children of the element only in `postLink` function since the children have
- * already been linked.
- *
- * * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
- * between all directive linking functions.
- *
- * * `controller` - a controller instance - A controller instance if at least one directive on the
- * element defines a controller. The controller is shared among all the directives, which allows
- * the directives to use the controllers as a communication channel.
- *
- * * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
- * The scope can be overridden by an optional first argument. This is the same as the `$transclude`
- * parameter of directive controllers.
- * `function([scope], cloneLinkingFn)`.
- *
- *
- * #### Pre-linking function
- *
- * Executed before the child elements are linked. Not safe to do DOM transformation since the
- * compiler linking function will fail to locate the correct elements for linking.
- *
- * #### Post-linking function
- *
- * Executed after the child elements are linked. It is safe to do DOM transformation in the post-linking function.
- *
- * <a name="Attributes"></a>
- * ### Attributes
- *
- * The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
- * `link()` or `compile()` functions. It has a variety of uses.
- *
- * accessing *Normalized attribute names:*
- * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
- * the attributes object allows for normalized access to
- * the attributes.
- *
- * * *Directive inter-communication:* All directives share the same instance of the attributes
- * object which allows the directives to use the attributes object as inter directive
- * communication.
- *
- * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
- * allowing other directives to read the interpolated value.
- *
- * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
- * that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
- * the only way to easily get the actual value because during the linking phase the interpolation
- * hasn't been evaluated yet and so the value is at this time set to `undefined`.
- *
- * <pre>
- * function linkingFn(scope, elm, attrs, ctrl) {
- * // get the attribute value
- * console.log(attrs.ngModel);
- *
- * // change the attribute
- * attrs.$set('ngModel', 'new value');
- *
- * // observe changes to interpolated attribute
- * attrs.$observe('ngModel', function(value) {
- * console.log('ngModel has changed value to ' + value);
- * });
- * }
- * </pre>
- *
- * Below is an example using `$compileProvider`.
- *
- * <div class="alert alert-warning">
- * **Note**: Typically directives are registered with `module.directive`. The example below is
- * to illustrate how `$compile` works.
- * </div>
- *
- <doc:example module="compile">
- <doc:source>
- <script>
- angular.module('compile', [], function($compileProvider) {
- // configure new 'compile' directive by passing a directive
- // factory function. The factory function injects the '$compile'
- $compileProvider.directive('compile', function($compile) {
- // directive factory creates a link function
- return function(scope, element, attrs) {
- scope.$watch(
- function(scope) {
- // watch the 'compile' expression for changes
- return scope.$eval(attrs.compile);
- },
- function(value) {
- // when the 'compile' expression changes
- // assign it into the current DOM
- element.html(value);
-
- // compile the new DOM and link it to the current
- // scope.
- // NOTE: we only compile .childNodes so that
- // we don't get into infinite loop compiling ourselves
- $compile(element.contents())(scope);
- }
- );
- };
- })
- });
-
- function Ctrl($scope) {
- $scope.name = 'Angular';
- $scope.html = 'Hello {{name}}';
- }
- </script>
- <div ng-controller="Ctrl">
- <input ng-model="name"> <br>
- <textarea ng-model="html"></textarea> <br>
- <div compile="html"></div>
- </div>
- </doc:source>
- <doc:scenario>
- it('should auto compile', function() {
- expect(element('div[compile]').text()).toBe('Hello Angular');
- input('html').enter('{{name}}!');
- expect(element('div[compile]').text()).toBe('Angular!');
- });
- </doc:scenario>
- </doc:example>
-
- *
- *
- * @param {string|DOMElement} element Element or HTML string to compile into a template function.
- * @param {function(angular.Scope[, cloneAttachFn]} transclude function available to directives.
- * @param {number} maxPriority only apply directives lower then given priority (Only effects the
- * root element(s), not their children)
- * @returns {function(scope[, cloneAttachFn])} a link function which is used to bind template
- * (a DOM element/tree) to a scope. Where:
- *
- * * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
- * * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
- * `template` and call the `cloneAttachFn` function allowing the caller to attach the
- * cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
- * called as: <br> `cloneAttachFn(clonedElement, scope)` where:
- *
- * * `clonedElement` - is a clone of the original `element` passed into the compiler.
- * * `scope` - is the current scope with which the linking function is working with.
- *
- * Calling the linking function returns the element of the template. It is either the original
- * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
- *
- * After linking the view is not updated until after a call to $digest which typically is done by
- * Angular automatically.
- *
- * If you need access to the bound view, there are two ways to do it:
- *
- * - If you are not asking the linking function to clone the template, create the DOM element(s)
- * before you send them to the compiler and keep this reference around.
- * <pre>
- * var element = $compile('<p>{{total}}</p>')(scope);
- * </pre>
- *
- * - if on the other hand, you need the element to be cloned, the view reference from the original
- * example would not point to the clone, but rather to the original template that was cloned. In
- * this case, you can access the clone via the cloneAttachFn:
- * <pre>
- * var templateHTML = angular.element('<p>{{total}}</p>'),
- * scope = ....;
- *
- * var clonedElement = $compile(templateHTML)(scope, function(clonedElement, scope) {
- * //attach the clone to DOM document at the right place
- * });
- *
- * //now we have reference to the cloned DOM via `clone`
- * </pre>
- *
- *
- * For information on how the compiler works, see the
- * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
- */
-
-var $compileMinErr = minErr('$compile');
-
-/**
- * @ngdoc service
- * @name ng.$compileProvider
- * @function
- *
- * @description
- */
-$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
-function $CompileProvider($provide, $$sanitizeUriProvider) {
- var hasDirectives = {},
- Suffix = 'Directive',
- COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
-
- // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
- // The assumption is that future DOM event attribute names will begin with
- // 'on' and be composed of only English letters.
- var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
-
- /**
- * @ngdoc function
- * @name ng.$compileProvider#directive
- * @methodOf ng.$compileProvider
- * @function
- *
- * @description
- * Register a new directive with the compiler.
- *
- * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
- * will match as <code>ng-bind</code>), or an object map of directives where the keys are the
- * names and the values are the factories.
- * @param {function|Array} directiveFactory An injectable directive factory function. See
- * {@link guide/directive} for more info.
- * @returns {ng.$compileProvider} Self for chaining.
- */
- this.directive = function registerDirective(name, directiveFactory) {
- assertNotHasOwnProperty(name, 'directive');
- if (isString(name)) {
- assertArg(directiveFactory, 'directiveFactory');
- if (!hasDirectives.hasOwnProperty(name)) {
- hasDirectives[name] = [];
- $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
- function($injector, $exceptionHandler) {
- var directives = [];
- forEach(hasDirectives[name], function(directiveFactory, index) {
- try {
- var directive = $injector.invoke(directiveFactory);
- if (isFunction(directive)) {
- directive = { compile: valueFn(directive) };
- } else if (!directive.compile && directive.link) {
- directive.compile = valueFn(directive.link);
- }
- directive.priority = directive.priority || 0;
- directive.index = index;
- directive.name = directive.name || name;
- directive.require = directive.require || (directive.controller && directive.name);
- directive.restrict = directive.restrict || 'A';
- directives.push(directive);
- } catch (e) {
- $exceptionHandler(e);
- }
- });
- return directives;
- }]);
- }
- hasDirectives[name].push(directiveFactory);
- } else {
- forEach(name, reverseParams(registerDirective));
- }
- return this;
- };
-
-
- /**
- * @ngdoc function
- * @name ng.$compileProvider#aHrefSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
- *
- * @description
- * Retrieves or overrides the default regular expression that is used for whitelisting of safe
- * urls during a[href] sanitization.
- *
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
- *
- * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
- * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
- * regular expression. If a match is found, the original url is written into the dom. Otherwise,
- * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
- *
- * @param {RegExp=} regexp New regexp to whitelist urls with.
- * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
- * chaining otherwise.
- */
- this.aHrefSanitizationWhitelist = function(regexp) {
- if (isDefined(regexp)) {
- $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
- return this;
- } else {
- return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
- }
- };
-
-
- /**
- * @ngdoc function
- * @name ng.$compileProvider#imgSrcSanitizationWhitelist
- * @methodOf ng.$compileProvider
- * @function
- *
- * @description
- * Retrieves or overrides the default regular expression that is used for whitelisting of safe
- * urls during img[src] sanitization.
- *
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
- *
- * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
- * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
- * regular expression. If a match is found, the original url is written into the dom. Otherwise,
- * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
- *
- * @param {RegExp=} regexp New regexp to whitelist urls with.
- * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
- * chaining otherwise.
- */
- this.imgSrcSanitizationWhitelist = function(regexp) {
- if (isDefined(regexp)) {
- $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
- return this;
- } else {
- return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
- }
- };
-
- this.$get = [
- '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse',
- '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
- function($injector, $interpolate, $exceptionHandler, $http, $templateCache, $parse,
- $controller, $rootScope, $document, $sce, $animate, $$sanitizeUri) {
-
- var Attributes = function(element, attr) {
- this.$$element = element;
- this.$attr = attr || {};
- };
-
- Attributes.prototype = {
- $normalize: directiveNormalize,
-
-
- /**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$addClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Adds the CSS class value specified by the classVal parameter to the element. If animations
- * are enabled then an animation will be triggered for the class addition.
- *
- * @param {string} classVal The className value that will be added to the element
- */
- $addClass : function(classVal) {
- if(classVal && classVal.length > 0) {
- $animate.addClass(this.$$element, classVal);
- }
- },
-
- /**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$removeClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Removes the CSS class value specified by the classVal parameter from the element. If
- * animations are enabled then an animation will be triggered for the class removal.
- *
- * @param {string} classVal The className value that will be removed from the element
- */
- $removeClass : function(classVal) {
- if(classVal && classVal.length > 0) {
- $animate.removeClass(this.$$element, classVal);
- }
- },
-
- /**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$updateClass
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Adds and removes the appropriate CSS class values to the element based on the difference
- * between the new and old CSS class values (specified as newClasses and oldClasses).
- *
- * @param {string} newClasses The current CSS className value
- * @param {string} oldClasses The former CSS className value
- */
- $updateClass : function(newClasses, oldClasses) {
- this.$removeClass(tokenDifference(oldClasses, newClasses));
- this.$addClass(tokenDifference(newClasses, oldClasses));
- },
-
- /**
- * Set a normalized attribute on the element in a way such that all directives
- * can share the attribute. This function properly handles boolean attributes.
- * @param {string} key Normalized key. (ie ngAttribute)
- * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
- * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
- * Defaults to true.
- * @param {string=} attrName Optional none normalized name. Defaults to key.
- */
- $set: function(key, value, writeAttr, attrName) {
- // TODO: decide whether or not to throw an error if "class"
- //is set through this function since it may cause $updateClass to
- //become unstable.
-
- var booleanKey = getBooleanAttrName(this.$$element[0], key),
- normalizedVal,
- nodeName;
-
- if (booleanKey) {
- this.$$element.prop(key, value);
- attrName = booleanKey;
- }
-
- this[key] = value;
-
- // translate normalized key to actual key
- if (attrName) {
- this.$attr[key] = attrName;
- } else {
- attrName = this.$attr[key];
- if (!attrName) {
- this.$attr[key] = attrName = snake_case(key, '-');
- }
- }
-
- nodeName = nodeName_(this.$$element);
-
- // sanitize a[href] and img[src] values
- if ((nodeName === 'A' && key === 'href') ||
- (nodeName === 'IMG' && key === 'src')) {
- this[key] = value = $$sanitizeUri(value, key === 'src');
- }
-
- if (writeAttr !== false) {
- if (value === null || value === undefined) {
- this.$$element.removeAttr(attrName);
- } else {
- this.$$element.attr(attrName, value);
- }
- }
-
- // fire observers
- var $$observers = this.$$observers;
- $$observers && forEach($$observers[key], function(fn) {
- try {
- fn(value);
- } catch (e) {
- $exceptionHandler(e);
- }
- });
- },
-
-
- /**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$observe
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Observes an interpolated attribute.
- *
- * The observer function will be invoked once during the next `$digest` following
- * compilation. The observer is then invoked whenever the interpolated value
- * changes.
- *
- * @param {string} key Normalized key. (ie ngAttribute) .
- * @param {function(interpolatedValue)} fn Function that will be called whenever
- the interpolated value of the attribute changes.
- * See the {@link guide/directive#Attributes Directives} guide for more info.
- * @returns {function()} the `fn` parameter.
- */
- $observe: function(key, fn) {
- var attrs = this,
- $$observers = (attrs.$$observers || (attrs.$$observers = {})),
- listeners = ($$observers[key] || ($$observers[key] = []));
-
- listeners.push(fn);
- $rootScope.$evalAsync(function() {
- if (!listeners.$$inter) {
- // no one registered attribute interpolation function, so lets call it manually
- fn(attrs[key]);
- }
- });
- return fn;
- }
- };
-
- var startSymbol = $interpolate.startSymbol(),
- endSymbol = $interpolate.endSymbol(),
- denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
- ? identity
- : function denormalizeTemplate(template) {
- return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
- },
- NG_ATTR_BINDING = /^ngAttr[A-Z]/;
-
-
- return compile;
-
- //================================
-
- function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
- previousCompileContext) {
- if (!($compileNodes instanceof jqLite)) {
- // jquery always rewraps, whereas we need to preserve the original selector so that we can
- // modify it.
- $compileNodes = jqLite($compileNodes);
- }
- // We can not compile top level text elements since text nodes can be merged and we will
- // not be able to attach scope data to them, so we will wrap them in <span>
- forEach($compileNodes, function(node, index){
- if (node.nodeType == 3 /* text node */ && node.nodeValue.match(/\S+/) /* non-empty */ ) {
- $compileNodes[index] = node = jqLite(node).wrap('<span></span>').parent()[0];
- }
- });
- var compositeLinkFn =
- compileNodes($compileNodes, transcludeFn, $compileNodes,
- maxPriority, ignoreDirective, previousCompileContext);
- return function publicLinkFn(scope, cloneConnectFn, transcludeControllers){
- assertArg(scope, 'scope');
- // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
- // and sometimes changes the structure of the DOM.
- var $linkNode = cloneConnectFn
- ? JQLitePrototype.clone.call($compileNodes) // IMPORTANT!!!
- : $compileNodes;
-
- forEach(transcludeControllers, function(instance, name) {
- $linkNode.data('$' + name + 'Controller', instance);
- });
-
- // Attach scope only to non-text nodes.
- for(var i = 0, ii = $linkNode.length; i<ii; i++) {
- var node = $linkNode[i];
- if (node.nodeType == 1 /* element */ || node.nodeType == 9 /* document */) {
- $linkNode.eq(i).data('$scope', scope);
- }
- }
- safeAddClass($linkNode, 'ng-scope');
- if (cloneConnectFn) cloneConnectFn($linkNode, scope);
- if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode);
- return $linkNode;
- };
- }
-
- function safeAddClass($element, className) {
- try {
- $element.addClass(className);
- } catch(e) {
- // ignore, since it means that we are trying to set class on
- // SVG element, where class name is read-only.
- }
- }
-
- /**
- * Compile function matches each node in nodeList against the directives. Once all directives
- * for a particular node are collected their compile functions are executed. The compile
- * functions return values - the linking functions - are combined into a composite linking
- * function, which is the a linking function for the node.
- *
- * @param {NodeList} nodeList an array of nodes or NodeList to compile
- * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
- * scope argument is auto-generated to the new child of the transcluded parent scope.
- * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
- * the rootElement must be set the jqLite collection of the compile root. This is
- * needed so that the jqLite collection items can be replaced with widgets.
- * @param {number=} max directive priority
- * @returns {?function} A composite linking function of all of the matched directives or null.
- */
- function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
- previousCompileContext) {
- var linkFns = [],
- nodeLinkFn, childLinkFn, directives, attrs, linkFnFound;
-
- for(var i = 0; i < nodeList.length; i++) {
- attrs = new Attributes();
-
- // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
- directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
- ignoreDirective);
-
- nodeLinkFn = (directives.length)
- ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
- null, [], [], previousCompileContext)
- : null;
-
- childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
- !nodeList[i].childNodes ||
- !nodeList[i].childNodes.length)
- ? null
- : compileNodes(nodeList[i].childNodes,
- nodeLinkFn ? nodeLinkFn.transclude : transcludeFn);
-
- linkFns.push(nodeLinkFn);
- linkFns.push(childLinkFn);
- linkFnFound = (linkFnFound || nodeLinkFn || childLinkFn);
- //use the previous context only for the first element in the virtual group
- previousCompileContext = null;
- }
-
- // return a linking function if we have found anything, null otherwise
- return linkFnFound ? compositeLinkFn : null;
-
- function compositeLinkFn(scope, nodeList, $rootElement, boundTranscludeFn) {
- var nodeLinkFn, childLinkFn, node, $node, childScope, childTranscludeFn, i, ii, n;
-
- // copy nodeList so that linking doesn't break due to live list updates.
- var stableNodeList = [];
- for (i = 0, ii = nodeList.length; i < ii; i++) {
- stableNodeList.push(nodeList[i]);
- }
-
- for(i = 0, n = 0, ii = linkFns.length; i < ii; n++) {
- node = stableNodeList[n];
- nodeLinkFn = linkFns[i++];
- childLinkFn = linkFns[i++];
- $node = jqLite(node);
-
- if (nodeLinkFn) {
- if (nodeLinkFn.scope) {
- childScope = scope.$new();
- $node.data('$scope', childScope);
- safeAddClass($node, 'ng-scope');
- } else {
- childScope = scope;
- }
- childTranscludeFn = nodeLinkFn.transclude;
- if (childTranscludeFn || (!boundTranscludeFn && transcludeFn)) {
- nodeLinkFn(childLinkFn, childScope, node, $rootElement,
- createBoundTranscludeFn(scope, childTranscludeFn || transcludeFn)
- );
- } else {
- nodeLinkFn(childLinkFn, childScope, node, $rootElement, boundTranscludeFn);
- }
- } else if (childLinkFn) {
- childLinkFn(scope, node.childNodes, undefined, boundTranscludeFn);
- }
- }
- }
- }
-
- function createBoundTranscludeFn(scope, transcludeFn) {
- return function boundTranscludeFn(transcludedScope, cloneFn, controllers) {
- var scopeCreated = false;
-
- if (!transcludedScope) {
- transcludedScope = scope.$new();
- transcludedScope.$$transcluded = true;
- scopeCreated = true;
- }
-
- var clone = transcludeFn(transcludedScope, cloneFn, controllers);
- if (scopeCreated) {
- clone.on('$destroy', bind(transcludedScope, transcludedScope.$destroy));
- }
- return clone;
- };
- }
-
- /**
- * Looks for directives on the given node and adds them to the directive collection which is
- * sorted.
- *
- * @param node Node to search.
- * @param directives An array to which the directives are added to. This array is sorted before
- * the function returns.
- * @param attrs The shared attrs object which is used to populate the normalized attributes.
- * @param {number=} maxPriority Max directive priority.
- */
- function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
- var nodeType = node.nodeType,
- attrsMap = attrs.$attr,
- match,
- className;
-
- switch(nodeType) {
- case 1: /* Element */
- // use the node name: <directive>
- addDirective(directives,
- directiveNormalize(nodeName_(node).toLowerCase()), 'E', maxPriority, ignoreDirective);
-
- // iterate over the attributes
- for (var attr, name, nName, ngAttrName, value, nAttrs = node.attributes,
- j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
- var attrStartName = false;
- var attrEndName = false;
-
- attr = nAttrs[j];
- if (!msie || msie >= 8 || attr.specified) {
- name = attr.name;
- // support ngAttr attribute binding
- ngAttrName = directiveNormalize(name);
- if (NG_ATTR_BINDING.test(ngAttrName)) {
- name = snake_case(ngAttrName.substr(6), '-');
- }
-
- var directiveNName = ngAttrName.replace(/(Start|End)$/, '');
- if (ngAttrName === directiveNName + 'Start') {
- attrStartName = name;
- attrEndName = name.substr(0, name.length - 5) + 'end';
- name = name.substr(0, name.length - 6);
- }
-
- nName = directiveNormalize(name.toLowerCase());
- attrsMap[nName] = name;
- attrs[nName] = value = trim((msie && name == 'href')
- ? decodeURIComponent(node.getAttribute(name, 2))
- : attr.value);
- if (getBooleanAttrName(node, nName)) {
- attrs[nName] = true; // presence means true
- }
- addAttrInterpolateDirective(node, directives, value, nName);
- addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
- attrEndName);
- }
- }
-
- // use class as directive
- className = node.className;
- if (isString(className) && className !== '') {
- while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
- nName = directiveNormalize(match[2]);
- if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
- attrs[nName] = trim(match[3]);
- }
- className = className.substr(match.index + match[0].length);
- }
- }
- break;
- case 3: /* Text Node */
- addTextInterpolateDirective(directives, node.nodeValue);
- break;
- case 8: /* Comment */
- try {
- match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
- if (match) {
- nName = directiveNormalize(match[1]);
- if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
- attrs[nName] = trim(match[2]);
- }
- }
- } catch (e) {
- // turns out that under some circumstances IE9 throws errors when one attempts to read
- // comment's node value.
- // Just ignore it and continue. (Can't seem to reproduce in test case.)
- }
- break;
- }
-
- directives.sort(byPriority);
- return directives;
- }
-
- /**
- * Given a node with an directive-start it collects all of the siblings until it finds
- * directive-end.
- * @param node
- * @param attrStart
- * @param attrEnd
- * @returns {*}
- */
- function groupScan(node, attrStart, attrEnd) {
- var nodes = [];
- var depth = 0;
- if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
- var startNode = node;
- do {
- if (!node) {
- throw $compileMinErr('uterdir',
- "Unterminated attribute, found '{0}' but no matching '{1}' found.",
- attrStart, attrEnd);
- }
- if (node.nodeType == 1 /** Element **/) {
- if (node.hasAttribute(attrStart)) depth++;
- if (node.hasAttribute(attrEnd)) depth--;
- }
- nodes.push(node);
- node = node.nextSibling;
- } while (depth > 0);
- } else {
- nodes.push(node);
- }
-
- return jqLite(nodes);
- }
-
- /**
- * Wrapper for linking function which converts normal linking function into a grouped
- * linking function.
- * @param linkFn
- * @param attrStart
- * @param attrEnd
- * @returns {Function}
- */
- function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
- return function(scope, element, attrs, controllers, transcludeFn) {
- element = groupScan(element[0], attrStart, attrEnd);
- return linkFn(scope, element, attrs, controllers, transcludeFn);
- };
- }
-
- /**
- * Once the directives have been collected, their compile functions are executed. This method
- * is responsible for inlining directive templates as well as terminating the application
- * of the directives if the terminal directive has been reached.
- *
- * @param {Array} directives Array of collected directives to execute their compile function.
- * this needs to be pre-sorted by priority order.
- * @param {Node} compileNode The raw DOM node to apply the compile functions to
- * @param {Object} templateAttrs The shared attribute function
- * @param {function(angular.Scope[, cloneAttachFn]} transcludeFn A linking function, where the
- * scope argument is auto-generated to the new
- * child of the transcluded parent scope.
- * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
- * argument has the root jqLite array so that we can replace nodes
- * on it.
- * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
- * compiling the transclusion.
- * @param {Array.<Function>} preLinkFns
- * @param {Array.<Function>} postLinkFns
- * @param {Object} previousCompileContext Context used for previous compilation of the current
- * node
- * @returns linkFn
- */
- function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
- jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
- previousCompileContext) {
- previousCompileContext = previousCompileContext || {};
-
- var terminalPriority = -Number.MAX_VALUE,
- newScopeDirective,
- controllerDirectives = previousCompileContext.controllerDirectives,
- newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
- templateDirective = previousCompileContext.templateDirective,
- nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
- hasTranscludeDirective = false,
- hasElementTranscludeDirective = false,
- $compileNode = templateAttrs.$$element = jqLite(compileNode),
- directive,
- directiveName,
- $template,
- replaceDirective = originalReplaceDirective,
- childTranscludeFn = transcludeFn,
- linkFn,
- directiveValue;
-
- // executes all directives on the current element
- for(var i = 0, ii = directives.length; i < ii; i++) {
- directive = directives[i];
- var attrStart = directive.$$start;
- var attrEnd = directive.$$end;
-
- // collect multiblock sections
- if (attrStart) {
- $compileNode = groupScan(compileNode, attrStart, attrEnd);
- }
- $template = undefined;
-
- if (terminalPriority > directive.priority) {
- break; // prevent further processing of directives
- }
-
- if (directiveValue = directive.scope) {
- newScopeDirective = newScopeDirective || directive;
-
- // skip the check for directives with async templates, we'll check the derived sync
- // directive when the template arrives
- if (!directive.templateUrl) {
- assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
- $compileNode);
- if (isObject(directiveValue)) {
- newIsolateScopeDirective = directive;
- }
- }
- }
-
- directiveName = directive.name;
-
- if (!directive.templateUrl && directive.controller) {
- directiveValue = directive.controller;
- controllerDirectives = controllerDirectives || {};
- assertNoDuplicate("'" + directiveName + "' controller",
- controllerDirectives[directiveName], directive, $compileNode);
- controllerDirectives[directiveName] = directive;
- }
-
- if (directiveValue = directive.transclude) {
- hasTranscludeDirective = true;
-
- // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
- // This option should only be used by directives that know how to how to safely handle element transclusion,
- // where the transcluded nodes are added or replaced after linking.
- if (!directive.$$tlb) {
- assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
- nonTlbTranscludeDirective = directive;
- }
-
- if (directiveValue == 'element') {
- hasElementTranscludeDirective = true;
- terminalPriority = directive.priority;
- $template = groupScan(compileNode, attrStart, attrEnd);
- $compileNode = templateAttrs.$$element =
- jqLite(document.createComment(' ' + directiveName + ': ' +
- templateAttrs[directiveName] + ' '));
- compileNode = $compileNode[0];
- replaceWith(jqCollection, jqLite(sliceArgs($template)), compileNode);
-
- childTranscludeFn = compile($template, transcludeFn, terminalPriority,
- replaceDirective && replaceDirective.name, {
- // Don't pass in:
- // - controllerDirectives - otherwise we'll create duplicates controllers
- // - newIsolateScopeDirective or templateDirective - combining templates with
- // element transclusion doesn't make sense.
- //
- // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
- // on the same element more than once.
- nonTlbTranscludeDirective: nonTlbTranscludeDirective
- });
- } else {
- $template = jqLite(jqLiteClone(compileNode)).contents();
- $compileNode.empty(); // clear contents
- childTranscludeFn = compile($template, transcludeFn);
- }
- }
-
- if (directive.template) {
- assertNoDuplicate('template', templateDirective, directive, $compileNode);
- templateDirective = directive;
-
- directiveValue = (isFunction(directive.template))
- ? directive.template($compileNode, templateAttrs)
- : directive.template;
-
- directiveValue = denormalizeTemplate(directiveValue);
-
- if (directive.replace) {
- replaceDirective = directive;
- $template = jqLite('<div>' +
- trim(directiveValue) +
- '</div>').contents();
- compileNode = $template[0];
-
- if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw $compileMinErr('tplrt',
- "Template for directive '{0}' must have exactly one root element. {1}",
- directiveName, '');
- }
-
- replaceWith(jqCollection, $compileNode, compileNode);
-
- var newTemplateAttrs = {$attr: {}};
-
- // combine directives from the original node and from the template:
- // - take the array of directives for this element
- // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
- // - collect directives from the template and sort them by priority
- // - combine directives as: processed + template + unprocessed
- var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
- var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
-
- if (newIsolateScopeDirective) {
- markDirectivesAsIsolate(templateDirectives);
- }
- directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
- mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
-
- ii = directives.length;
- } else {
- $compileNode.html(directiveValue);
- }
- }
-
- if (directive.templateUrl) {
- assertNoDuplicate('template', templateDirective, directive, $compileNode);
- templateDirective = directive;
-
- if (directive.replace) {
- replaceDirective = directive;
- }
-
- nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
- templateAttrs, jqCollection, childTranscludeFn, preLinkFns, postLinkFns, {
- controllerDirectives: controllerDirectives,
- newIsolateScopeDirective: newIsolateScopeDirective,
- templateDirective: templateDirective,
- nonTlbTranscludeDirective: nonTlbTranscludeDirective
- });
- ii = directives.length;
- } else if (directive.compile) {
- try {
- linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
- if (isFunction(linkFn)) {
- addLinkFns(null, linkFn, attrStart, attrEnd);
- } else if (linkFn) {
- addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
- }
- } catch (e) {
- $exceptionHandler(e, startingTag($compileNode));
- }
- }
-
- if (directive.terminal) {
- nodeLinkFn.terminal = true;
- terminalPriority = Math.max(terminalPriority, directive.priority);
- }
-
- }
-
- nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
- nodeLinkFn.transclude = hasTranscludeDirective && childTranscludeFn;
-
- // might be normal or delayed nodeLinkFn depending on if templateUrl is present
- return nodeLinkFn;
-
- ////////////////////
-
- function addLinkFns(pre, post, attrStart, attrEnd) {
- if (pre) {
- if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
- pre.require = directive.require;
- if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
- pre = cloneAndAnnotateFn(pre, {isolateScope: true});
- }
- preLinkFns.push(pre);
- }
- if (post) {
- if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
- post.require = directive.require;
- if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
- post = cloneAndAnnotateFn(post, {isolateScope: true});
- }
- postLinkFns.push(post);
- }
- }
-
-
- function getControllers(require, $element, elementControllers) {
- var value, retrievalMethod = 'data', optional = false;
- if (isString(require)) {
- while((value = require.charAt(0)) == '^' || value == '?') {
- require = require.substr(1);
- if (value == '^') {
- retrievalMethod = 'inheritedData';
- }
- optional = optional || value == '?';
- }
- value = null;
-
- if (elementControllers && retrievalMethod === 'data') {
- value = elementControllers[require];
- }
- value = value || $element[retrievalMethod]('$' + require + 'Controller');
-
- if (!value && !optional) {
- throw $compileMinErr('ctreq',
- "Controller '{0}', required by directive '{1}', can't be found!",
- require, directiveName);
- }
- return value;
- } else if (isArray(require)) {
- value = [];
- forEach(require, function(require) {
- value.push(getControllers(require, $element, elementControllers));
- });
- }
- return value;
- }
-
-
- function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
- var attrs, $element, i, ii, linkFn, controller, isolateScope, elementControllers = {}, transcludeFn;
-
- if (compileNode === linkNode) {
- attrs = templateAttrs;
- } else {
- attrs = shallowCopy(templateAttrs, new Attributes(jqLite(linkNode), templateAttrs.$attr));
- }
- $element = attrs.$$element;
-
- if (newIsolateScopeDirective) {
- var LOCAL_REGEXP = /^\s*([@=&])(\??)\s*(\w*)\s*$/;
- var $linkNode = jqLite(linkNode);
-
- isolateScope = scope.$new(true);
-
- if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
- $linkNode.data('$isolateScope', isolateScope) ;
- } else {
- $linkNode.data('$isolateScopeNoTemplate', isolateScope);
- }
-
-
-
- safeAddClass($linkNode, 'ng-isolate-scope');
-
- forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
- var match = definition.match(LOCAL_REGEXP) || [],
- attrName = match[3] || scopeName,
- optional = (match[2] == '?'),
- mode = match[1], // @, =, or &
- lastValue,
- parentGet, parentSet, compare;
-
- isolateScope.$$isolateBindings[scopeName] = mode + attrName;
-
- switch (mode) {
-
- case '@':
- attrs.$observe(attrName, function(value) {
- isolateScope[scopeName] = value;
- });
- attrs.$$observers[attrName].$$scope = scope;
- if( attrs[attrName] ) {
- // If the attribute has been provided then we trigger an interpolation to ensure
- // the value is there for use in the link fn
- isolateScope[scopeName] = $interpolate(attrs[attrName])(scope);
- }
- break;
-
- case '=':
- if (optional && !attrs[attrName]) {
- return;
- }
- parentGet = $parse(attrs[attrName]);
- if (parentGet.literal) {
- compare = equals;
- } else {
- compare = function(a,b) { return a === b; };
- }
- parentSet = parentGet.assign || function() {
- // reset the change, or we will throw this exception on every $digest
- lastValue = isolateScope[scopeName] = parentGet(scope);
- throw $compileMinErr('nonassign',
- "Expression '{0}' used with directive '{1}' is non-assignable!",
- attrs[attrName], newIsolateScopeDirective.name);
- };
- lastValue = isolateScope[scopeName] = parentGet(scope);
- isolateScope.$watch(function parentValueWatch() {
- var parentValue = parentGet(scope);
- if (!compare(parentValue, isolateScope[scopeName])) {
- // we are out of sync and need to copy
- if (!compare(parentValue, lastValue)) {
- // parent changed and it has precedence
- isolateScope[scopeName] = parentValue;
- } else {
- // if the parent can be assigned then do so
- parentSet(scope, parentValue = isolateScope[scopeName]);
- }
- }
- return lastValue = parentValue;
- }, null, parentGet.literal);
- break;
-
- case '&':
- parentGet = $parse(attrs[attrName]);
- isolateScope[scopeName] = function(locals) {
- return parentGet(scope, locals);
- };
- break;
-
- default:
- throw $compileMinErr('iscp',
- "Invalid isolate scope definition for directive '{0}'." +
- " Definition: {... {1}: '{2}' ...}",
- newIsolateScopeDirective.name, scopeName, definition);
- }
- });
- }
- transcludeFn = boundTranscludeFn && controllersBoundTransclude;
- if (controllerDirectives) {
- forEach(controllerDirectives, function(directive) {
- var locals = {
- $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
- $element: $element,
- $attrs: attrs,
- $transclude: transcludeFn
- }, controllerInstance;
-
- controller = directive.controller;
- if (controller == '@') {
- controller = attrs[directive.name];
- }
-
- controllerInstance = $controller(controller, locals);
- // For directives with element transclusion the element is a comment,
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
- // clean up (http://bugs.jquery.com/ticket/8335).
- // Instead, we save the controllers for the element in a local hash and attach to .data
- // later, once we have the actual element.
- elementControllers[directive.name] = controllerInstance;
- if (!hasElementTranscludeDirective) {
- $element.data('$' + directive.name + 'Controller', controllerInstance);
- }
-
- if (directive.controllerAs) {
- locals.$scope[directive.controllerAs] = controllerInstance;
- }
- });
- }
-
- // PRELINKING
- for(i = 0, ii = preLinkFns.length; i < ii; i++) {
- try {
- linkFn = preLinkFns[i];
- linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
- }
-
- // RECURSION
- // We only pass the isolate scope, if the isolate directive has a template,
- // otherwise the child elements do not belong to the isolate directive.
- var scopeToChild = scope;
- if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
- scopeToChild = isolateScope;
- }
- childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
-
- // POSTLINKING
- for(i = postLinkFns.length - 1; i >= 0; i--) {
- try {
- linkFn = postLinkFns[i];
- linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs,
- linkFn.require && getControllers(linkFn.require, $element, elementControllers), transcludeFn);
- } catch (e) {
- $exceptionHandler(e, startingTag($element));
- }
- }
-
- // This is the function that is injected as `$transclude`.
- function controllersBoundTransclude(scope, cloneAttachFn) {
- var transcludeControllers;
-
- // no scope passed
- if (arguments.length < 2) {
- cloneAttachFn = scope;
- scope = undefined;
- }
-
- if (hasElementTranscludeDirective) {
- transcludeControllers = elementControllers;
- }
-
- return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers);
- }
- }
- }
-
- function markDirectivesAsIsolate(directives) {
- // mark all directives as needing isolate scope.
- for (var j = 0, jj = directives.length; j < jj; j++) {
- directives[j] = inherit(directives[j], {$$isolateScope: true});
- }
- }
-
- /**
- * looks up the directive and decorates it with exception handling and proper parameters. We
- * call this the boundDirective.
- *
- * @param {string} name name of the directive to look up.
- * @param {string} location The directive must be found in specific format.
- * String containing any of theses characters:
- *
- * * `E`: element name
- * * `A': attribute
- * * `C`: class
- * * `M`: comment
- * @returns true if directive was added.
- */
- function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
- endAttrName) {
- if (name === ignoreDirective) return null;
- var match = null;
- if (hasDirectives.hasOwnProperty(name)) {
- for(var directive, directives = $injector.get(name + Suffix),
- i = 0, ii = directives.length; i<ii; i++) {
- try {
- directive = directives[i];
- if ( (maxPriority === undefined || maxPriority > directive.priority) &&
- directive.restrict.indexOf(location) != -1) {
- if (startAttrName) {
- directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
- }
- tDirectives.push(directive);
- match = directive;
- }
- } catch(e) { $exceptionHandler(e); }
- }
- }
- return match;
- }
-
-
- /**
- * When the element is replaced with HTML template then the new attributes
- * on the template need to be merged with the existing attributes in the DOM.
- * The desired effect is to have both of the attributes present.
- *
- * @param {object} dst destination attributes (original DOM)
- * @param {object} src source attributes (from the directive template)
- */
- function mergeTemplateAttributes(dst, src) {
- var srcAttr = src.$attr,
- dstAttr = dst.$attr,
- $element = dst.$$element;
-
- // reapply the old attributes to the new element
- forEach(dst, function(value, key) {
- if (key.charAt(0) != '$') {
- if (src[key]) {
- value += (key === 'style' ? ';' : ' ') + src[key];
- }
- dst.$set(key, value, true, srcAttr[key]);
- }
- });
-
- // copy the new attributes on the old attrs object
- forEach(src, function(value, key) {
- if (key == 'class') {
- safeAddClass($element, value);
- dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
- } else if (key == 'style') {
- $element.attr('style', $element.attr('style') + ';' + value);
- dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
- // `dst` will never contain hasOwnProperty as DOM parser won't let it.
- // You will get an "InvalidCharacterError: DOM Exception 5" error if you
- // have an attribute like "has-own-property" or "data-has-own-property", etc.
- } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
- dst[key] = value;
- dstAttr[key] = srcAttr[key];
- }
- });
- }
-
-
- function compileTemplateUrl(directives, $compileNode, tAttrs,
- $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
- var linkQueue = [],
- afterTemplateNodeLinkFn,
- afterTemplateChildLinkFn,
- beforeTemplateCompileNode = $compileNode[0],
- origAsyncDirective = directives.shift(),
- // The fact that we have to copy and patch the directive seems wrong!
- derivedSyncDirective = extend({}, origAsyncDirective, {
- templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
- }),
- templateUrl = (isFunction(origAsyncDirective.templateUrl))
- ? origAsyncDirective.templateUrl($compileNode, tAttrs)
- : origAsyncDirective.templateUrl;
-
- $compileNode.empty();
-
- $http.get($sce.getTrustedResourceUrl(templateUrl), {cache: $templateCache}).
- success(function(content) {
- var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
-
- content = denormalizeTemplate(content);
-
- if (origAsyncDirective.replace) {
- $template = jqLite('<div>' + trim(content) + '</div>').contents();
- compileNode = $template[0];
-
- if ($template.length != 1 || compileNode.nodeType !== 1) {
- throw $compileMinErr('tplrt',
- "Template for directive '{0}' must have exactly one root element. {1}",
- origAsyncDirective.name, templateUrl);
- }
-
- tempTemplateAttrs = {$attr: {}};
- replaceWith($rootElement, $compileNode, compileNode);
- var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
-
- if (isObject(origAsyncDirective.scope)) {
- markDirectivesAsIsolate(templateDirectives);
- }
- directives = templateDirectives.concat(directives);
- mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
- } else {
- compileNode = beforeTemplateCompileNode;
- $compileNode.html(content);
- }
-
- directives.unshift(derivedSyncDirective);
-
- afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
- childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
- previousCompileContext);
- forEach($rootElement, function(node, i) {
- if (node == compileNode) {
- $rootElement[i] = $compileNode[0];
- }
- });
- afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
-
-
- while(linkQueue.length) {
- var scope = linkQueue.shift(),
- beforeTemplateLinkNode = linkQueue.shift(),
- linkRootElement = linkQueue.shift(),
- boundTranscludeFn = linkQueue.shift(),
- linkNode = $compileNode[0];
-
- if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
- // it was cloned therefore we have to clone as well.
- linkNode = jqLiteClone(compileNode);
- replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
- }
- if (afterTemplateNodeLinkFn.transclude) {
- childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude);
- } else {
- childBoundTranscludeFn = boundTranscludeFn;
- }
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
- childBoundTranscludeFn);
- }
- linkQueue = null;
- }).
- error(function(response, code, headers, config) {
- throw $compileMinErr('tpload', 'Failed to load template: {0}', config.url);
- });
-
- return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
- if (linkQueue) {
- linkQueue.push(scope);
- linkQueue.push(node);
- linkQueue.push(rootElement);
- linkQueue.push(boundTranscludeFn);
- } else {
- afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, boundTranscludeFn);
- }
- };
- }
-
-
- /**
- * Sorting function for bound directives.
- */
- function byPriority(a, b) {
- var diff = b.priority - a.priority;
- if (diff !== 0) return diff;
- if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
- return a.index - b.index;
- }
-
-
- function assertNoDuplicate(what, previousDirective, directive, element) {
- if (previousDirective) {
- throw $compileMinErr('multidir', 'Multiple directives [{0}, {1}] asking for {2} on: {3}',
- previousDirective.name, directive.name, what, startingTag(element));
- }
- }
-
-
- function addTextInterpolateDirective(directives, text) {
- var interpolateFn = $interpolate(text, true);
- if (interpolateFn) {
- directives.push({
- priority: 0,
- compile: valueFn(function textInterpolateLinkFn(scope, node) {
- var parent = node.parent(),
- bindings = parent.data('$binding') || [];
- bindings.push(interpolateFn);
- safeAddClass(parent.data('$binding', bindings), 'ng-binding');
- scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
- node[0].nodeValue = value;
- });
- })
- });
- }
- }
-
-
- function getTrustedContext(node, attrNormalizedName) {
- if (attrNormalizedName == "srcdoc") {
- return $sce.HTML;
- }
- var tag = nodeName_(node);
- // maction[xlink:href] can source SVG. It's not limited to <maction>.
- if (attrNormalizedName == "xlinkHref" ||
- (tag == "FORM" && attrNormalizedName == "action") ||
- (tag != "IMG" && (attrNormalizedName == "src" ||
- attrNormalizedName == "ngSrc"))) {
- return $sce.RESOURCE_URL;
- }
- }
-
-
- function addAttrInterpolateDirective(node, directives, value, name) {
- var interpolateFn = $interpolate(value, true);
-
- // no interpolation found -> ignore
- if (!interpolateFn) return;
-
-
- if (name === "multiple" && nodeName_(node) === "SELECT") {
- throw $compileMinErr("selmulti",
- "Binding to the 'multiple' attribute is not supported. Element: {0}",
- startingTag(node));
- }
-
- directives.push({
- priority: 100,
- compile: function() {
- return {
- pre: function attrInterpolatePreLinkFn(scope, element, attr) {
- var $$observers = (attr.$$observers || (attr.$$observers = {}));
-
- if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
- throw $compileMinErr('nodomevents',
- "Interpolations for HTML DOM event attributes are disallowed. Please use the " +
- "ng- versions (such as ng-click instead of onclick) instead.");
- }
-
- // we need to interpolate again, in case the attribute value has been updated
- // (e.g. by another directive's compile function)
- interpolateFn = $interpolate(attr[name], true, getTrustedContext(node, name));
-
- // if attribute was updated so that there is no interpolation going on we don't want to
- // register any observers
- if (!interpolateFn) return;
-
- // TODO(i): this should likely be attr.$set(name, iterpolateFn(scope) so that we reset the
- // actual attr value
- attr[name] = interpolateFn(scope);
- ($$observers[name] || ($$observers[name] = [])).$$inter = true;
- (attr.$$observers && attr.$$observers[name].$$scope || scope).
- $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
- //special case for class attribute addition + removal
- //so that class changes can tap into the animation
- //hooks provided by the $animate service. Be sure to
- //skip animations when the first digest occurs (when
- //both the new and the old values are the same) since
- //the CSS classes are the non-interpolated values
- if(name === 'class' && newValue != oldValue) {
- attr.$updateClass(newValue, oldValue);
- } else {
- attr.$set(name, newValue);
- }
- });
- }
- };
- }
- });
- }
-
-
- /**
- * This is a special jqLite.replaceWith, which can replace items which
- * have no parents, provided that the containing jqLite collection is provided.
- *
- * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
- * in the root of the tree.
- * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
- * the shell, but replace its DOM node reference.
- * @param {Node} newNode The new DOM node.
- */
- function replaceWith($rootElement, elementsToRemove, newNode) {
- var firstElementToRemove = elementsToRemove[0],
- removeCount = elementsToRemove.length,
- parent = firstElementToRemove.parentNode,
- i, ii;
-
- if ($rootElement) {
- for(i = 0, ii = $rootElement.length; i < ii; i++) {
- if ($rootElement[i] == firstElementToRemove) {
- $rootElement[i++] = newNode;
- for (var j = i, j2 = j + removeCount - 1,
- jj = $rootElement.length;
- j < jj; j++, j2++) {
- if (j2 < jj) {
- $rootElement[j] = $rootElement[j2];
- } else {
- delete $rootElement[j];
- }
- }
- $rootElement.length -= removeCount - 1;
- break;
- }
- }
- }
-
- if (parent) {
- parent.replaceChild(newNode, firstElementToRemove);
- }
- var fragment = document.createDocumentFragment();
- fragment.appendChild(firstElementToRemove);
- newNode[jqLite.expando] = firstElementToRemove[jqLite.expando];
- for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
- var element = elementsToRemove[k];
- jqLite(element).remove(); // must do this way to clean up expando
- fragment.appendChild(element);
- delete elementsToRemove[k];
- }
-
- elementsToRemove[0] = newNode;
- elementsToRemove.length = 1;
- }
-
-
- function cloneAndAnnotateFn(fn, annotation) {
- return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
- }
- }];
-}
-
-var PREFIX_REGEXP = /^(x[\:\-_]|data[\:\-_])/i;
-/**
- * Converts all accepted directives format into proper directive name.
- * All of these will become 'myDirective':
- * my:Directive
- * my-directive
- * x-my-directive
- * data-my:directive
- *
- * Also there is special case for Moz prefix starting with upper case letter.
- * @param name Name to normalize
- */
-function directiveNormalize(name) {
- return camelCase(name.replace(PREFIX_REGEXP, ''));
-}
-
-/**
- * @ngdoc object
- * @name ng.$compile.directive.Attributes
- *
- * @description
- * A shared object between directive compile / linking functions which contains normalized DOM
- * element attributes. The values reflect current binding state `{{ }}`. The normalization is
- * needed since all of these are treated as equivalent in Angular:
- *
- * <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
- */
-
-/**
- * @ngdoc property
- * @name ng.$compile.directive.Attributes#$attr
- * @propertyOf ng.$compile.directive.Attributes
- * @returns {object} A map of DOM element attribute names to the normalized name. This is
- * needed to do reverse lookup from normalized name back to actual name.
- */
-
-
-/**
- * @ngdoc function
- * @name ng.$compile.directive.Attributes#$set
- * @methodOf ng.$compile.directive.Attributes
- * @function
- *
- * @description
- * Set DOM element attribute value.
- *
- *
- * @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}
- * property to the original name.
- * @param {string} value Value to set the attribute to. The value can be an interpolated string.
- */
-
-
-
-/**
- * Closure compiler type information
- */
-
-function nodesetLinkingFn(
- /* angular.Scope */ scope,
- /* NodeList */ nodeList,
- /* Element */ rootElement,
- /* function(Function) */ boundTranscludeFn
-){}
-
-function directiveLinkingFn(
- /* nodesetLinkingFn */ nodesetLinkingFn,
- /* angular.Scope */ scope,
- /* Node */ node,
- /* Element */ rootElement,
- /* function(Function) */ boundTranscludeFn
-){}
-
-function tokenDifference(str1, str2) {
- var values = '',
- tokens1 = str1.split(/\s+/),
- tokens2 = str2.split(/\s+/);
-
- outer:
- for(var i = 0; i < tokens1.length; i++) {
- var token = tokens1[i];
- for(var j = 0; j < tokens2.length; j++) {
- if(token == tokens2[j]) continue outer;
- }
- values += (values.length > 0 ? ' ' : '') + token;
- }
- return values;
-}
-
-/**
- * @ngdoc object
- * @name ng.$controllerProvider
- * @description
- * The {@link ng.$controller $controller service} is used by Angular to create new
- * controllers.
- *
- * This provider allows controller registration via the
- * {@link ng.$controllerProvider#methods_register register} method.
- */
-function $ControllerProvider() {
- var controllers = {},
- CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
-
-
- /**
- * @ngdoc function
- * @name ng.$controllerProvider#register
- * @methodOf ng.$controllerProvider
- * @param {string|Object} name Controller name, or an object map of controllers where the keys are
- * the names and the values are the constructors.
- * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
- * annotations in the array notation).
- */
- this.register = function(name, constructor) {
- assertNotHasOwnProperty(name, 'controller');
- if (isObject(name)) {
- extend(controllers, name);
- } else {
- controllers[name] = constructor;
- }
- };
-
-
- this.$get = ['$injector', '$window', function($injector, $window) {
-
- /**
- * @ngdoc function
- * @name ng.$controller
- * @requires $injector
- *
- * @param {Function|string} constructor If called with a function then it's considered to be the
- * controller constructor function. Otherwise it's considered to be a string which is used
- * to retrieve the controller constructor using the following steps:
- *
- * * check if a controller with given name is registered via `$controllerProvider`
- * * check if evaluating the string on the current scope returns a constructor
- * * check `window[constructor]` on the global `window` object
- *
- * @param {Object} locals Injection locals for Controller.
- * @return {Object} Instance of given controller.
- *
- * @description
- * `$controller` service is responsible for instantiating controllers.
- *
- * It's just a simple call to {@link AUTO.$injector $injector}, but extracted into
- * a service, so that one can override this service with {@link https://gist.github.com/1649788
- * BC version}.
- */
- return function(expression, locals) {
- var instance, match, constructor, identifier;
-
- if(isString(expression)) {
- match = expression.match(CNTRL_REG),
- constructor = match[1],
- identifier = match[3];
- expression = controllers.hasOwnProperty(constructor)
- ? controllers[constructor]
- : getter(locals.$scope, constructor, true) || getter($window, constructor, true);
-
- assertArgFn(expression, constructor, true);
- }
-
- instance = $injector.instantiate(expression, locals);
-
- if (identifier) {
- if (!(locals && typeof locals.$scope == 'object')) {
- throw minErr('$controller')('noscp',
- "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
- constructor || expression.name, identifier);
- }
-
- locals.$scope[identifier] = instance;
- }
-
- return instance;
- };
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$document
- * @requires $window
- *
- * @description
- * A {@link angular.element jQuery (lite)}-wrapped reference to the browser's `window.document`
- * element.
- */
-function $DocumentProvider(){
- this.$get = ['$window', function(window){
- return jqLite(window.document);
- }];
-}
-
-/**
- * @ngdoc function
- * @name ng.$exceptionHandler
- * @requires $log
- *
- * @description
- * Any uncaught exception in angular expressions is delegated to this service.
- * The default implementation simply delegates to `$log.error` which logs it into
- * the browser console.
- *
- * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
- * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
- *
- * ## Example:
- *
- * <pre>
- * angular.module('exceptionOverride', []).factory('$exceptionHandler', function () {
- * return function (exception, cause) {
- * exception.message += ' (caused by "' + cause + '")';
- * throw exception;
- * };
- * });
- * </pre>
- *
- * This example will override the normal action of `$exceptionHandler`, to make angular
- * exceptions fail hard when they happen, instead of just logging to the console.
- *
- * @param {Error} exception Exception associated with the error.
- * @param {string=} cause optional information about the context in which
- * the error was thrown.
- *
- */
-function $ExceptionHandlerProvider() {
- this.$get = ['$log', function($log) {
- return function(exception, cause) {
- $log.error.apply($log, arguments);
- };
- }];
-}
-
-/**
- * Parse headers into key value object
- *
- * @param {string} headers Raw headers as a string
- * @returns {Object} Parsed headers as key value object
- */
-function parseHeaders(headers) {
- var parsed = {}, key, val, i;
-
- if (!headers) return parsed;
-
- forEach(headers.split('\n'), function(line) {
- i = line.indexOf(':');
- key = lowercase(trim(line.substr(0, i)));
- val = trim(line.substr(i + 1));
-
- if (key) {
- if (parsed[key]) {
- parsed[key] += ', ' + val;
- } else {
- parsed[key] = val;
- }
- }
- });
-
- return parsed;
-}
-
-
-/**
- * Returns a function that provides access to parsed headers.
- *
- * Headers are lazy parsed when first requested.
- * @see parseHeaders
- *
- * @param {(string|Object)} headers Headers to provide access to.
- * @returns {function(string=)} Returns a getter function which if called with:
- *
- * - if called with single an argument returns a single header value or null
- * - if called with no arguments returns an object containing all headers.
- */
-function headersGetter(headers) {
- var headersObj = isObject(headers) ? headers : undefined;
-
- return function(name) {
- if (!headersObj) headersObj = parseHeaders(headers);
-
- if (name) {
- return headersObj[lowercase(name)] || null;
- }
-
- return headersObj;
- };
-}
-
-
-/**
- * Chain all given functions
- *
- * This function is used for both request and response transforming
- *
- * @param {*} data Data to transform.
- * @param {function(string=)} headers Http headers getter fn.
- * @param {(function|Array.<function>)} fns Function or an array of functions.
- * @returns {*} Transformed data.
- */
-function transformData(data, headers, fns) {
- if (isFunction(fns))
- return fns(data, headers);
-
- forEach(fns, function(fn) {
- data = fn(data, headers);
- });
-
- return data;
-}
-
-
-function isSuccess(status) {
- return 200 <= status && status < 300;
-}
-
-
-function $HttpProvider() {
- var JSON_START = /^\s*(\[|\{[^\{])/,
- JSON_END = /[\}\]]\s*$/,
- PROTECTION_PREFIX = /^\)\]\}',?\n/,
- CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': 'application/json;charset=utf-8'};
-
- var defaults = this.defaults = {
- // transform incoming response data
- transformResponse: [function(data) {
- if (isString(data)) {
- // strip json vulnerability protection prefix
- data = data.replace(PROTECTION_PREFIX, '');
- if (JSON_START.test(data) && JSON_END.test(data))
- data = fromJson(data);
- }
- return data;
- }],
-
- // transform outgoing request data
- transformRequest: [function(d) {
- return isObject(d) && !isFile(d) ? toJson(d) : d;
- }],
-
- // default headers
- headers: {
- common: {
- 'Accept': 'application/json, text/plain, */*'
- },
- post: CONTENT_TYPE_APPLICATION_JSON,
- put: CONTENT_TYPE_APPLICATION_JSON,
- patch: CONTENT_TYPE_APPLICATION_JSON
- },
-
- xsrfCookieName: 'XSRF-TOKEN',
- xsrfHeaderName: 'X-XSRF-TOKEN'
- };
-
- /**
- * Are ordered by request, i.e. they are applied in the same order as the
- * array, on request, but reverse order, on response.
- */
- var interceptorFactories = this.interceptors = [];
-
- /**
- * For historical reasons, response interceptors are ordered by the order in which
- * they are applied to the response. (This is the opposite of interceptorFactories)
- */
- var responseInterceptorFactories = this.responseInterceptors = [];
-
- this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
- function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {
-
- var defaultCache = $cacheFactory('$http');
-
- /**
- * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
- * The reversal is needed so that we can build up the interception chain around the
- * server request.
- */
- var reversedInterceptors = [];
-
- forEach(interceptorFactories, function(interceptorFactory) {
- reversedInterceptors.unshift(isString(interceptorFactory)
- ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
- });
-
- forEach(responseInterceptorFactories, function(interceptorFactory, index) {
- var responseFn = isString(interceptorFactory)
- ? $injector.get(interceptorFactory)
- : $injector.invoke(interceptorFactory);
-
- /**
- * Response interceptors go before "around" interceptors (no real reason, just
- * had to pick one.) But they are already reversed, so we can't use unshift, hence
- * the splice.
- */
- reversedInterceptors.splice(index, 0, {
- response: function(response) {
- return responseFn($q.when(response));
- },
- responseError: function(response) {
- return responseFn($q.reject(response));
- }
- });
- });
-
-
- /**
- * @ngdoc function
- * @name ng.$http
- * @requires $httpBackend
- * @requires $browser
- * @requires $cacheFactory
- * @requires $rootScope
- * @requires $q
- * @requires $injector
- *
- * @description
- * The `$http` service is a core Angular service that facilitates communication with the remote
- * HTTP servers via the browser's {@link https://developer.mozilla.org/en/xmlhttprequest
- * XMLHttpRequest} object or via {@link http://en.wikipedia.org/wiki/JSONP JSONP}.
- *
- * For unit testing applications that use `$http` service, see
- * {@link ngMock.$httpBackend $httpBackend mock}.
- *
- * For a higher level of abstraction, please check out the {@link ngResource.$resource
- * $resource} service.
- *
- * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
- * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
- * it is important to familiarize yourself with these APIs and the guarantees they provide.
- *
- *
- * # General usage
- * The `$http` service is a function which takes a single argument — a configuration object —
- * that is used to generate an HTTP request and returns a {@link ng.$q promise}
- * with two $http specific methods: `success` and `error`.
- *
- * <pre>
- * $http({method: 'GET', url: '/someUrl'}).
- * success(function(data, status, headers, config) {
- * // this callback will be called asynchronously
- * // when the response is available
- * }).
- * error(function(data, status, headers, config) {
- * // called asynchronously if an error occurs
- * // or server returns response with an error status.
- * });
- * </pre>
- *
- * Since the returned value of calling the $http function is a `promise`, you can also use
- * the `then` method to register callbacks, and these callbacks will receive a single argument –
- * an object representing the response. See the API signature and type info below for more
- * details.
- *
- * A response status code between 200 and 299 is considered a success status and
- * will result in the success callback being called. Note that if the response is a redirect,
- * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
- * called for such responses.
- *
- * # Calling $http from outside AngularJS
- * The `$http` service will not actually send the request until the next `$digest()` is
- * executed. Normally this is not an issue, since almost all the time your call to `$http` will
- * be from within a `$apply()` block.
- * If you are calling `$http` from outside Angular, then you should wrap it in a call to
- * `$apply` to cause a $digest to occur and also to handle errors in the block correctly.
- *
- * ```
- * $scope.$apply(function() {
- * $http(...);
- * });
- * ```
- *
- * # Writing Unit Tests that use $http
- * When unit testing you are mostly responsible for scheduling the `$digest` cycle. If you do
- * not trigger a `$digest` before calling `$httpBackend.flush()` then the request will not have
- * been made and `$httpBackend.expect(...)` expectations will fail. The solution is to run the
- * code that calls the `$http()` method inside a $apply block as explained in the previous
- * section.
- *
- * ```
- * $httpBackend.expectGET(...);
- * $scope.$apply(function() {
- * $http.get(...);
- * });
- * $httpBackend.flush();
- * ```
- *
- * # Shortcut methods
- *
- * Since all invocations of the $http service require passing in an HTTP method and URL, and
- * POST/PUT requests require request data to be provided as well, shortcut methods
- * were created:
- *
- * <pre>
- * $http.get('/someUrl').success(successCallback);
- * $http.post('/someUrl', data).success(successCallback);
- * </pre>
- *
- * Complete list of shortcut methods:
- *
- * - {@link ng.$http#methods_get $http.get}
- * - {@link ng.$http#methods_head $http.head}
- * - {@link ng.$http#methods_post $http.post}
- * - {@link ng.$http#methods_put $http.put}
- * - {@link ng.$http#methods_delete $http.delete}
- * - {@link ng.$http#methods_jsonp $http.jsonp}
- *
- *
- * # Setting HTTP Headers
- *
- * The $http service will automatically add certain HTTP headers to all requests. These defaults
- * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
- * object, which currently contains this default configuration:
- *
- * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
- * - `Accept: application/json, text/plain, * / *`
- * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
- * - `Content-Type: application/json`
- * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
- * - `Content-Type: application/json`
- *
- * To add or overwrite these defaults, simply add or remove a property from these configuration
- * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
- * with the lowercased HTTP method name as the key, e.g.
- * `$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
- * calling `$http(config)`, which overrides the defaults without changing them globally.
- *
- *
- * # Transforming Requests and Responses
- *
- * Both requests and responses can be transformed using transform functions. By default, Angular
- * applies these transformations:
- *
- * Request transformations:
- *
- * - If the `data` property of the request configuration object contains an object, serialize it
- * into JSON format.
- *
- * Response transformations:
- *
- * - If XSRF prefix is detected, strip it (see Security Considerations section below).
- * - If JSON response is detected, deserialize it using a JSON parser.
- *
- * To globally augment or override the default transforms, modify the
- * `$httpProvider.defaults.transformRequest` and `$httpProvider.defaults.transformResponse`
- * 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.
- *
- * Similarly, to locally override the request/response transforms, augment the
- * `transformRequest` and/or `transformResponse` properties of the configuration object passed
- * into `$http`.
- *
- *
- * # Caching
- *
- * To enable caching, set the request configuration `cache` property to `true` (to use default
- * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
- * When the cache is enabled, `$http` stores the response from the server in the specified
- * cache. The next time the same request is made, the response is served from the cache without
- * sending a request to the server.
- *
- * Note that even if the response is served from cache, delivery of the data is asynchronous in
- * the same way that real requests are.
- *
- * If there are multiple GET requests for the same URL that should be cached using the same
- * cache, but the cache is not populated yet, only one request to the server will be made and
- * the remaining requests will be fulfilled using the response from the first request.
- *
- * You can change the default cache to a new object (built with
- * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
- * {@link ng.$http#properties_defaults `$http.defaults.cache`} property. All requests who set
- * their `cache` property to `true` will now use this cache object.
- *
- * If you set the default cache to `false` then only requests that specify their own custom
- * cache object will be cached.
- *
- * # Interceptors
- *
- * Before you start creating interceptors, be sure to understand the
- * {@link ng.$q $q and deferred/promise APIs}.
- *
- * For purposes of global error handling, authentication, or any kind of synchronous or
- * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
- * able to intercept requests before they are handed to the server and
- * responses before they are handed over to the application code that
- * initiated these requests. The interceptors leverage the {@link ng.$q
- * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
- *
- * The interceptors are service factories that are registered with the `$httpProvider` by
- * adding them to the `$httpProvider.interceptors` array. The factory is called and
- * injected with dependencies (if specified) and returns the interceptor.
- *
- * There are two kinds of interceptors (and two kinds of rejection interceptors):
- *
- * * `request`: interceptors get called with http `config` object. The function is free to
- * modify the `config` or create a new one. The function needs to return the `config`
- * directly or as a promise.
- * * `requestError`: interceptor gets called when a previous interceptor threw an error or
- * resolved with a rejection.
- * * `response`: interceptors get called with http `response` object. The function is free to
- * modify the `response` or create a new one. The function needs to return the `response`
- * directly or as a promise.
- * * `responseError`: interceptor gets called when a previous interceptor threw an error or
- * resolved with a rejection.
- *
- *
- * <pre>
- * // register the interceptor as a service
- * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
- * return {
- * // optional method
- * 'request': function(config) {
- * // do something on success
- * return config || $q.when(config);
- * },
- *
- * // optional method
- * 'requestError': function(rejection) {
- * // do something on error
- * if (canRecover(rejection)) {
- * return responseOrNewPromise
- * }
- * return $q.reject(rejection);
- * },
- *
- *
- *
- * // optional method
- * 'response': function(response) {
- * // do something on success
- * return response || $q.when(response);
- * },
- *
- * // optional method
- * 'responseError': function(rejection) {
- * // do something on error
- * if (canRecover(rejection)) {
- * return responseOrNewPromise
- * }
- * return $q.reject(rejection);
- * };
- * }
- * });
- *
- * $httpProvider.interceptors.push('myHttpInterceptor');
- *
- *
- * // register the interceptor via an anonymous factory
- * $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
- * return {
- * 'request': function(config) {
- * // same as above
- * },
- * 'response': function(response) {
- * // same as above
- * }
- * };
- * });
- * </pre>
- *
- * # Response interceptors (DEPRECATED)
- *
- * Before you start creating interceptors, be sure to understand the
- * {@link ng.$q $q and deferred/promise APIs}.
- *
- * For purposes of global error handling, authentication or any kind of synchronous or
- * asynchronous preprocessing of received responses, it is desirable to be able to intercept
- * responses for http requests before they are handed over to the application code that
- * initiated these requests. The response interceptors leverage the {@link ng.$q
- * promise apis} to fulfil this need for both synchronous and asynchronous preprocessing.
- *
- * The interceptors are service factories that are registered with the $httpProvider by
- * adding them to the `$httpProvider.responseInterceptors` array. The factory is called and
- * injected with dependencies (if specified) and returns the interceptor — a function that
- * takes a {@link ng.$q promise} and returns the original or a new promise.
- *
- * <pre>
- * // register the interceptor as a service
- * $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
- * return function(promise) {
- * return promise.then(function(response) {
- * // do something on success
- * return response;
- * }, function(response) {
- * // do something on error
- * if (canRecover(response)) {
- * return responseOrNewPromise
- * }
- * return $q.reject(response);
- * });
- * }
- * });
- *
- * $httpProvider.responseInterceptors.push('myHttpInterceptor');
- *
- *
- * // register the interceptor via an anonymous factory
- * $httpProvider.responseInterceptors.push(function($q, dependency1, dependency2) {
- * return function(promise) {
- * // same as above
- * }
- * });
- * </pre>
- *
- *
- * # Security Considerations
- *
- * When designing web applications, consider security threats from:
- *
- * - {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON vulnerability}
- * - {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF}
- *
- * Both server and the client must cooperate in order to eliminate these threats. Angular comes
- * pre-configured with strategies that address these issues, but for this to work backend server
- * cooperation is required.
- *
- * ## JSON Vulnerability Protection
- *
- * A {@link http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx
- * JSON vulnerability} allows third party website to turn your JSON resource URL into
- * {@link http://en.wikipedia.org/wiki/JSONP JSONP} request under some conditions. To
- * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
- * Angular will automatically strip the prefix before processing it as JSON.
- *
- * For example if your server needs to return:
- * <pre>
- * ['one','two']
- * </pre>
- *
- * which is vulnerable to attack, your server can return:
- * <pre>
- * )]}',
- * ['one','two']
- * </pre>
- *
- * Angular will strip the prefix, before processing the JSON.
- *
- *
- * ## Cross Site Request Forgery (XSRF) Protection
- *
- * {@link http://en.wikipedia.org/wiki/Cross-site_request_forgery XSRF} is a technique by which
- * an unauthorized site can gain your user's private data. Angular provides a mechanism
- * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
- * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
- * JavaScript that runs on your domain could read the cookie, your server can be assured that
- * the XHR came from JavaScript running on your domain. The header will not be set for
- * cross-domain requests.
- *
- * To take advantage of this, your server needs to set a token in a JavaScript readable session
- * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
- * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
- * that only JavaScript running on your domain could have sent the request. The token must be
- * unique for each user and must be verifiable by the server (to prevent the JavaScript from
- * making up its own tokens). We recommend that the token is a digest of your site's
- * authentication cookie with a {@link https://en.wikipedia.org/wiki/Salt_(cryptography) salt}
- * 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.
- *
- *
- * @param {object} config Object describing the request to be made and how it should be
- * processed. The object has following properties:
- *
- * - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
- * - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
- * - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be turned
- * to `?key1=value1&key2=value2` after the url. If the value is not a string, it will be
- * JSONified.
- * - **data** – `{string|Object}` – Data to be sent as the request message data.
- * - **headers** – `{Object}` – Map of strings or functions which return strings representing
- * HTTP headers to send to the server. If the return value of a function is null, the
- * header will not be sent.
- * - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
- * - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
- * - **transformRequest** –
- * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
- * transform function or an array of such functions. The transform function takes the http
- * request body and headers and returns its transformed (typically serialized) version.
- * - **transformResponse** –
- * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
- * transform function or an array of such functions. The transform function takes the http
- * response body and headers and returns its transformed (typically deserialized) version.
- * - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
- * GET request, otherwise if a cache instance built with
- * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
- * caching.
- * - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
- * that should abort the request when resolved.
- * - **withCredentials** - `{boolean}` - whether to to set the `withCredentials` flag on the
- * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
- * requests with credentials} for more information.
- * - **responseType** - `{string}` - see {@link
- * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
- *
- * @returns {HttpPromise} Returns a {@link ng.$q promise} object with the
- * standard `then` method and two http specific methods: `success` and `error`. The `then`
- * method takes two arguments a success and an error callback which will be called with a
- * response object. The `success` and `error` methods take a single argument - a function that
- * will be called when the request succeeds or fails respectively. The arguments passed into
- * these functions are destructured representation of the response object passed into the
- * `then` method. The response object has these properties:
- *
- * - **data** – `{string|Object}` – The response body transformed with the transform
- * functions.
- * - **status** – `{number}` – HTTP status code of the response.
- * - **headers** – `{function([headerName])}` – Header getter function.
- * - **config** – `{Object}` – The configuration object that was used to generate the request.
- *
- * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
- * requests. This is primarily meant to be used for debugging purposes.
- *
- *
- * @example
-<example>
-<file name="index.html">
- <div ng-controller="FetchCtrl">
- <select ng-model="method">
- <option>GET</option>
- <option>JSONP</option>
- </select>
- <input type="text" ng-model="url" size="80"/>
- <button ng-click="fetch()">fetch</button><br>
- <button ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
- <button
- ng-click="updateModel('JSONP',
- 'http://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
- Sample JSONP
- </button>
- <button
- ng-click="updateModel('JSONP', 'http://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
- Invalid JSONP
- </button>
- <pre>http status code: {{status}}</pre>
- <pre>http response data: {{data}}</pre>
- </div>
-</file>
-<file name="script.js">
- function FetchCtrl($scope, $http, $templateCache) {
- $scope.method = 'GET';
- $scope.url = 'http-hello.html';
-
- $scope.fetch = function() {
- $scope.code = null;
- $scope.response = null;
-
- $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
- success(function(data, status) {
- $scope.status = status;
- $scope.data = data;
- }).
- error(function(data, status) {
- $scope.data = data || "Request failed";
- $scope.status = status;
- });
- };
-
- $scope.updateModel = function(method, url) {
- $scope.method = method;
- $scope.url = url;
- };
- }
-</file>
-<file name="http-hello.html">
- Hello, $http!
-</file>
-<file name="scenario.js">
- it('should make an xhr GET request', function() {
- element(':button:contains("Sample GET")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Hello, \$http!/);
- });
-
- it('should make a JSONP request to angularjs.org', function() {
- element(':button:contains("Sample JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('200');
- expect(binding('data')).toMatch(/Super Hero!/);
- });
-
- it('should make JSONP request to invalid URL and invoke the error handler',
- function() {
- element(':button:contains("Invalid JSONP")').click();
- element(':button:contains("fetch")').click();
- expect(binding('status')).toBe('0');
- expect(binding('data')).toBe('Request failed');
- });
-</file>
-</example>
- */
- function $http(requestConfig) {
- var config = {
- transformRequest: defaults.transformRequest,
- transformResponse: defaults.transformResponse
- };
- var headers = mergeHeaders(requestConfig);
-
- extend(config, requestConfig);
- config.headers = headers;
- config.method = uppercase(config.method);
-
- var xsrfValue = urlIsSameOrigin(config.url)
- ? $browser.cookies()[config.xsrfCookieName || defaults.xsrfCookieName]
- : undefined;
- if (xsrfValue) {
- headers[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
- }
-
-
- var serverRequest = function(config) {
- headers = config.headers;
- var reqData = transformData(config.data, headersGetter(headers), config.transformRequest);
-
- // strip content-type if data is undefined
- if (isUndefined(config.data)) {
- forEach(headers, function(value, header) {
- if (lowercase(header) === 'content-type') {
- delete headers[header];
- }
- });
- }
-
- if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
- config.withCredentials = defaults.withCredentials;
- }
-
- // send request
- return sendReq(config, reqData, headers).then(transformResponse, transformResponse);
- };
-
- var chain = [serverRequest, undefined];
- var promise = $q.when(config);
-
- // apply interceptors
- forEach(reversedInterceptors, function(interceptor) {
- if (interceptor.request || interceptor.requestError) {
- chain.unshift(interceptor.request, interceptor.requestError);
- }
- if (interceptor.response || interceptor.responseError) {
- chain.push(interceptor.response, interceptor.responseError);
- }
- });
-
- while(chain.length) {
- var thenFn = chain.shift();
- var rejectFn = chain.shift();
-
- promise = promise.then(thenFn, rejectFn);
- }
-
- promise.success = function(fn) {
- promise.then(function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
-
- promise.error = function(fn) {
- promise.then(null, function(response) {
- fn(response.data, response.status, response.headers, config);
- });
- return promise;
- };
-
- return promise;
-
- function transformResponse(response) {
- // make a copy since the response must be cacheable
- var resp = extend({}, response, {
- data: transformData(response.data, response.headers, config.transformResponse)
- });
- return (isSuccess(response.status))
- ? resp
- : $q.reject(resp);
- }
-
- function mergeHeaders(config) {
- var defHeaders = defaults.headers,
- reqHeaders = extend({}, config.headers),
- defHeaderName, lowercaseDefHeaderName, reqHeaderName;
-
- defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
-
- // execute if header value is function
- execHeaders(defHeaders);
- execHeaders(reqHeaders);
-
- // using for-in instead of forEach to avoid unecessary iteration after header has been found
- defaultHeadersIteration:
- for (defHeaderName in defHeaders) {
- lowercaseDefHeaderName = lowercase(defHeaderName);
-
- for (reqHeaderName in reqHeaders) {
- if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
- continue defaultHeadersIteration;
- }
- }
-
- reqHeaders[defHeaderName] = defHeaders[defHeaderName];
- }
-
- return reqHeaders;
-
- function execHeaders(headers) {
- var headerContent;
-
- forEach(headers, function(headerFn, header) {
- if (isFunction(headerFn)) {
- headerContent = headerFn();
- if (headerContent != null) {
- headers[header] = headerContent;
- } else {
- delete headers[header];
- }
- }
- });
- }
- }
- }
-
- $http.pendingRequests = [];
-
- /**
- * @ngdoc method
- * @name ng.$http#get
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `GET` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#delete
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `DELETE` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#head
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `HEAD` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#jsonp
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `JSONP` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request.
- * Should contain `JSON_CALLBACK` string.
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
- createShortMethods('get', 'delete', 'head', 'jsonp');
-
- /**
- * @ngdoc method
- * @name ng.$http#post
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `POST` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {*} data Request content
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
-
- /**
- * @ngdoc method
- * @name ng.$http#put
- * @methodOf ng.$http
- *
- * @description
- * Shortcut method to perform `PUT` request.
- *
- * @param {string} url Relative or absolute URL specifying the destination of the request
- * @param {*} data Request content
- * @param {Object=} config Optional configuration object
- * @returns {HttpPromise} Future object
- */
- createShortMethodsWithData('post', 'put');
-
- /**
- * @ngdoc property
- * @name ng.$http#defaults
- * @propertyOf ng.$http
- *
- * @description
- * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
- * default headers, withCredentials as well as request and response transformations.
- *
- * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
- */
- $http.defaults = defaults;
-
-
- return $http;
-
-
- function createShortMethods(names) {
- forEach(arguments, function(name) {
- $http[name] = function(url, config) {
- return $http(extend(config || {}, {
- method: name,
- url: url
- }));
- };
- });
- }
-
-
- function createShortMethodsWithData(name) {
- forEach(arguments, function(name) {
- $http[name] = function(url, data, config) {
- return $http(extend(config || {}, {
- method: name,
- url: url,
- data: data
- }));
- };
- });
- }
-
-
- /**
- * Makes the request.
- *
- * !!! ACCESSES CLOSURE VARS:
- * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
- */
- function sendReq(config, reqData, reqHeaders) {
- var deferred = $q.defer(),
- promise = deferred.promise,
- cache,
- cachedResp,
- url = buildUrl(config.url, config.params);
-
- $http.pendingRequests.push(config);
- promise.then(removePendingReq, removePendingReq);
-
-
- if ((config.cache || defaults.cache) && config.cache !== false && config.method == 'GET') {
- cache = isObject(config.cache) ? config.cache
- : isObject(defaults.cache) ? defaults.cache
- : defaultCache;
- }
-
- if (cache) {
- cachedResp = cache.get(url);
- if (isDefined(cachedResp)) {
- if (cachedResp.then) {
- // cached request has already been sent, but there is no response yet
- cachedResp.then(removePendingReq, removePendingReq);
- return cachedResp;
- } else {
- // serving from cache
- if (isArray(cachedResp)) {
- resolvePromise(cachedResp[1], cachedResp[0], copy(cachedResp[2]));
- } else {
- resolvePromise(cachedResp, 200, {});
- }
- }
- } else {
- // put the promise for the non-transformed response into cache as a placeholder
- cache.put(url, promise);
- }
- }
-
- // if we won't have the response in cache, send the request to the backend
- if (isUndefined(cachedResp)) {
- $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
- config.withCredentials, config.responseType);
- }
-
- return promise;
-
-
- /**
- * Callback registered to $httpBackend():
- * - caches the response if desired
- * - resolves the raw $http promise
- * - calls $apply
- */
- function done(status, response, headersString) {
- if (cache) {
- if (isSuccess(status)) {
- cache.put(url, [status, response, parseHeaders(headersString)]);
- } else {
- // remove promise from the cache
- cache.remove(url);
- }
- }
-
- resolvePromise(response, status, headersString);
- if (!$rootScope.$$phase) $rootScope.$apply();
- }
-
-
- /**
- * Resolves the raw $http promise.
- */
- function resolvePromise(response, status, headers) {
- // normalize internal statuses to 0
- status = Math.max(status, 0);
-
- (isSuccess(status) ? deferred.resolve : deferred.reject)({
- data: response,
- status: status,
- headers: headersGetter(headers),
- config: config
- });
- }
-
-
- function removePendingReq() {
- var idx = indexOf($http.pendingRequests, config);
- if (idx !== -1) $http.pendingRequests.splice(idx, 1);
- }
- }
-
-
- function buildUrl(url, params) {
- if (!params) return url;
- var parts = [];
- forEachSorted(params, function(value, key) {
- if (value === null || isUndefined(value)) return;
- if (!isArray(value)) value = [value];
-
- forEach(value, function(v) {
- if (isObject(v)) {
- v = toJson(v);
- }
- parts.push(encodeUriQuery(key) + '=' +
- encodeUriQuery(v));
- });
- });
- return url + ((url.indexOf('?') == -1) ? '?' : '&') + parts.join('&');
- }
-
-
- }];
-}
-
-var XHR = window.XMLHttpRequest || function() {
- /* global ActiveXObject */
- try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
- try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
- try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
- throw minErr('$httpBackend')('noxhr', "This browser does not support XMLHttpRequest.");
-};
-
-
-/**
- * @ngdoc object
- * @name ng.$httpBackend
- * @requires $browser
- * @requires $window
- * @requires $document
- *
- * @description
- * HTTP backend used by the {@link ng.$http service} that delegates to
- * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
- *
- * You should never need to use this service directly, instead use the higher-level abstractions:
- * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
- *
- * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
- * $httpBackend} which can be trained with responses.
- */
-function $HttpBackendProvider() {
- this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) {
- return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, $document[0]);
- }];
-}
-
-function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument) {
- var ABORTED = -1;
-
- // TODO(vojta): fix the signature
- return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
- var status;
- $browser.$$incOutstandingRequestCount();
- url = url || $browser.url();
-
- if (lowercase(method) == 'jsonp') {
- var callbackId = '_' + (callbacks.counter++).toString(36);
- callbacks[callbackId] = function(data) {
- callbacks[callbackId].data = data;
- };
-
- var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
- function() {
- if (callbacks[callbackId].data) {
- completeRequest(callback, 200, callbacks[callbackId].data);
- } else {
- completeRequest(callback, status || -2);
- }
- delete callbacks[callbackId];
- });
- } else {
- var xhr = new XHR();
- xhr.open(method, url, true);
- forEach(headers, function(value, key) {
- if (isDefined(value)) {
- xhr.setRequestHeader(key, value);
- }
- });
-
- // In IE6 and 7, this might be called synchronously when xhr.send below is called and the
- // response is in the cache. the promise api will ensure that to the app code the api is
- // always async
- xhr.onreadystatechange = function() {
- if (xhr.readyState == 4) {
- var responseHeaders = null,
- response = null;
-
- 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)
- completeRequest(callback,
- status || xhr.status,
- response,
- responseHeaders);
- }
- };
-
- if (withCredentials) {
- xhr.withCredentials = true;
- }
-
- if (responseType) {
- xhr.responseType = responseType;
- }
-
- xhr.send(post || null);
- }
-
- if (timeout > 0) {
- var timeoutId = $browserDefer(timeoutRequest, timeout);
- } else if (timeout && timeout.then) {
- timeout.then(timeoutRequest);
- }
-
-
- function timeoutRequest() {
- status = ABORTED;
- jsonpDone && jsonpDone();
- xhr && xhr.abort();
- }
-
- 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;
-
- // normalize IE bug (http://bugs.jquery.com/ticket/1450)
- status = status == 1223 ? 204 : status;
-
- callback(status, response, headersString);
- $browser.$$completeOutstandingRequest(noop);
- }
- };
-
- function jsonpReq(url, done) {
- // we can't use jQuery/jqLite here because jQuery does crazy shit with script elements, e.g.:
- // - fetches local scripts via XHR and evals them
- // - adds and immediately removes script elements from the document
- var script = rawDocument.createElement('script'),
- doneWrapper = function() {
- script.onreadystatechange = script.onload = script.onerror = null;
- rawDocument.body.removeChild(script);
- if (done) done();
- };
-
- script.type = 'text/javascript';
- script.src = url;
-
- if (msie && msie <= 8) {
- script.onreadystatechange = function() {
- if (/loaded|complete/.test(script.readyState)) {
- doneWrapper();
- }
- };
- } else {
- script.onload = script.onerror = function() {
- doneWrapper();
- };
- }
-
- rawDocument.body.appendChild(script);
- return doneWrapper;
- }
-}
-
-var $interpolateMinErr = minErr('$interpolate');
-
-/**
- * @ngdoc object
- * @name ng.$interpolateProvider
- * @function
- *
- * @description
- *
- * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
- *
- * @example
-<doc:example module="customInterpolationApp">
-<doc:source>
-<script>
- var customInterpolationApp = angular.module('customInterpolationApp', []);
-
- customInterpolationApp.config(function($interpolateProvider) {
- $interpolateProvider.startSymbol('//');
- $interpolateProvider.endSymbol('//');
- });
-
-
- customInterpolationApp.controller('DemoController', function DemoController() {
- this.label = "This binding is brought you by // interpolation symbols.";
- });
-</script>
-<div ng-app="App" ng-controller="DemoController as demo">
- //demo.label//
-</div>
-</doc:source>
-<doc:scenario>
- it('should interpolate binding with custom symbols', function() {
- expect(binding('demo.label')).toBe('This binding is brought you by // interpolation symbols.');
- });
-</doc:scenario>
-</doc:example>
- */
-function $InterpolateProvider() {
- var startSymbol = '{{';
- var endSymbol = '}}';
-
- /**
- * @ngdoc method
- * @name ng.$interpolateProvider#startSymbol
- * @methodOf ng.$interpolateProvider
- * @description
- * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
- *
- * @param {string=} value new value to set the starting symbol to.
- * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
- */
- this.startSymbol = function(value){
- if (value) {
- startSymbol = value;
- return this;
- } else {
- return startSymbol;
- }
- };
-
- /**
- * @ngdoc method
- * @name ng.$interpolateProvider#endSymbol
- * @methodOf ng.$interpolateProvider
- * @description
- * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
- *
- * @param {string=} value new value to set the ending symbol to.
- * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
- */
- this.endSymbol = function(value){
- if (value) {
- endSymbol = value;
- return this;
- } else {
- return endSymbol;
- }
- };
-
-
- this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
- var startSymbolLength = startSymbol.length,
- endSymbolLength = endSymbol.length;
-
- /**
- * @ngdoc function
- * @name ng.$interpolate
- * @function
- *
- * @requires $parse
- * @requires $sce
- *
- * @description
- *
- * Compiles a string with markup into an interpolation function. This service is used by the
- * HTML {@link ng.$compile $compile} service for data binding. See
- * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
- * interpolation markup.
- *
- *
- <pre>
- var $interpolate = ...; // injected
- var exp = $interpolate('Hello {{name | uppercase}}!');
- expect(exp({name:'Angular'}).toEqual('Hello ANGULAR!');
- </pre>
- *
- *
- * @param {string} text The text with markup to interpolate.
- * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
- * embedded expression in order to return an interpolation function. Strings with no
- * embedded expression will return null for the interpolation function.
- * @param {string=} trustedContext when provided, the returned function passes the interpolated
- * result through {@link ng.$sce#methods_getTrusted $sce.getTrusted(interpolatedResult,
- * trustedContext)} before returning it. Refer to the {@link ng.$sce $sce} service that
- * provides Strict Contextual Escaping for details.
- * @returns {function(context)} an interpolation function which is used to compute the
- * interpolated string. The function has these parameters:
- *
- * * `context`: an object against which any expressions embedded in the strings are evaluated
- * against.
- *
- */
- function $interpolate(text, mustHaveExpression, trustedContext) {
- var startIndex,
- endIndex,
- index = 0,
- parts = [],
- length = text.length,
- hasInterpolation = false,
- fn,
- exp,
- concat = [];
-
- while(index < length) {
- if ( ((startIndex = text.indexOf(startSymbol, index)) != -1) &&
- ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1) ) {
- (index != startIndex) && parts.push(text.substring(index, startIndex));
- parts.push(fn = $parse(exp = text.substring(startIndex + startSymbolLength, endIndex)));
- fn.exp = exp;
- index = endIndex + endSymbolLength;
- hasInterpolation = true;
- } else {
- // we did not find anything, so we have to add the remainder to the parts array
- (index != length) && parts.push(text.substring(index));
- index = length;
- }
- }
-
- if (!(length = parts.length)) {
- // we added, nothing, must have been an empty string.
- parts.push('');
- length = 1;
- }
-
- // Concatenating expressions makes it hard to reason about whether some combination of
- // concatenated values are unsafe to use and could easily lead to XSS. By requiring that a
- // single expression be used for iframe[src], object[src], etc., we ensure that the value
- // that's used is assigned or constructed by some JS code somewhere that is more testable or
- // make it obvious that you bound the value to some user controlled value. This helps reduce
- // the load when auditing for XSS issues.
- if (trustedContext && parts.length > 1) {
- throw $interpolateMinErr('noconcat',
- "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
- "interpolations that concatenate multiple expressions when a trusted value is " +
- "required. See http://docs.angularjs.org/api/ng.$sce", text);
- }
-
- if (!mustHaveExpression || hasInterpolation) {
- concat.length = length;
- fn = function(context) {
- try {
- for(var i = 0, ii = length, part; i<ii; i++) {
- if (typeof (part = parts[i]) == 'function') {
- part = part(context);
- if (trustedContext) {
- part = $sce.getTrusted(trustedContext, part);
- } else {
- part = $sce.valueOf(part);
- }
- if (part === null || isUndefined(part)) {
- part = '';
- } else if (typeof part != 'string') {
- part = toJson(part);
- }
- }
- concat[i] = part;
- }
- return concat.join('');
- }
- catch(err) {
- var newErr = $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text,
- err.toString());
- $exceptionHandler(newErr);
- }
- };
- fn.exp = text;
- fn.parts = parts;
- return fn;
- }
- }
-
-
- /**
- * @ngdoc method
- * @name ng.$interpolate#startSymbol
- * @methodOf ng.$interpolate
- * @description
- * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
- *
- * Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
- * the symbol.
- *
- * @returns {string} start symbol.
- */
- $interpolate.startSymbol = function() {
- return startSymbol;
- };
-
-
- /**
- * @ngdoc method
- * @name ng.$interpolate#endSymbol
- * @methodOf ng.$interpolate
- * @description
- * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
- *
- * Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
- * the symbol.
- *
- * @returns {string} start symbol.
- */
- $interpolate.endSymbol = function() {
- return endSymbol;
- };
-
- return $interpolate;
- }];
-}
-
-function $IntervalProvider() {
- this.$get = ['$rootScope', '$window', '$q',
- function($rootScope, $window, $q) {
- var intervals = {};
-
-
- /**
- * @ngdoc function
- * @name ng.$interval
- *
- * @description
- * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
- * milliseconds.
- *
- * The return value of registering an interval function is a promise. This promise will be
- * notified upon each tick of the interval, and will be resolved after `count` iterations, or
- * run indefinitely if `count` is not defined. The value of the notification will be the
- * number of iterations that have run.
- * To cancel an interval, call `$interval.cancel(promise)`.
- *
- * In tests you can use {@link ngMock.$interval#methods_flush `$interval.flush(millis)`} to
- * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
- * time.
- *
- * @param {function()} fn A function that should be called repeatedly.
- * @param {number} delay Number of milliseconds between each function call.
- * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
- * indefinitely.
- * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
- * @returns {promise} A promise which will be notified on each iteration.
- */
- function interval(fn, delay, count, invokeApply) {
- var setInterval = $window.setInterval,
- clearInterval = $window.clearInterval,
- deferred = $q.defer(),
- promise = deferred.promise,
- iteration = 0,
- skipApply = (isDefined(invokeApply) && !invokeApply);
-
- count = isDefined(count) ? count : 0,
-
- promise.then(null, null, fn);
-
- promise.$$intervalId = setInterval(function tick() {
- deferred.notify(iteration++);
-
- if (count > 0 && iteration >= count) {
- deferred.resolve(iteration);
- clearInterval(promise.$$intervalId);
- delete intervals[promise.$$intervalId];
- }
-
- if (!skipApply) $rootScope.$apply();
-
- }, delay);
-
- intervals[promise.$$intervalId] = deferred;
-
- return promise;
- }
-
-
- /**
- * @ngdoc function
- * @name ng.$interval#cancel
- * @methodOf ng.$interval
- *
- * @description
- * Cancels a task associated with the `promise`.
- *
- * @param {number} promise Promise returned by the `$interval` function.
- * @returns {boolean} Returns `true` if the task was successfully canceled.
- */
- interval.cancel = function(promise) {
- if (promise && promise.$$intervalId in intervals) {
- intervals[promise.$$intervalId].reject('canceled');
- clearInterval(promise.$$intervalId);
- delete intervals[promise.$$intervalId];
- return true;
- }
- return false;
- };
-
- return interval;
- }];
-}
-
-/**
- * @ngdoc object
- * @name ng.$locale
- *
- * @description
- * $locale service provides localization rules for various Angular components. As of right now the
- * only public api is:
- *
- * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
- */
-function $LocaleProvider(){
- this.$get = function() {
- return {
- id: 'en-us',
-
- NUMBER_FORMATS: {
- DECIMAL_SEP: '.',
- GROUP_SEP: ',',
- PATTERNS: [
- { // Decimal Pattern
- minInt: 1,
- minFrac: 0,
- maxFrac: 3,
- posPre: '',
- posSuf: '',
- negPre: '-',
- negSuf: '',
- gSize: 3,
- lgSize: 3
- },{ //Currency Pattern
- minInt: 1,
- minFrac: 2,
- maxFrac: 2,
- posPre: '\u00A4',
- posSuf: '',
- negPre: '(\u00A4',
- negSuf: ')',
- gSize: 3,
- lgSize: 3
- }
- ],
- CURRENCY_SYM: '$'
- },
-
- DATETIME_FORMATS: {
- MONTH:
- 'January,February,March,April,May,June,July,August,September,October,November,December'
- .split(','),
- SHORTMONTH: 'Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','),
- DAY: 'Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday'.split(','),
- SHORTDAY: 'Sun,Mon,Tue,Wed,Thu,Fri,Sat'.split(','),
- AMPMS: ['AM','PM'],
- medium: 'MMM d, y h:mm:ss a',
- short: 'M/d/yy h:mm a',
- fullDate: 'EEEE, MMMM d, y',
- longDate: 'MMMM d, y',
- mediumDate: 'MMM d, y',
- shortDate: 'M/d/yy',
- mediumTime: 'h:mm:ss a',
- shortTime: 'h:mm a'
- },
-
- pluralCat: function(num) {
- if (num === 1) {
- return 'one';
- }
- return 'other';
- }
- };
- };
-}
-
-var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
- DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
-var $locationMinErr = minErr('$location');
-
-
-/**
- * Encode path using encodeUriSegment, ignoring forward slashes
- *
- * @param {string} path Path to encode
- * @returns {string}
- */
-function encodePath(path) {
- var segments = path.split('/'),
- i = segments.length;
-
- while (i--) {
- segments[i] = encodeUriSegment(segments[i]);
- }
-
- return segments.join('/');
-}
-
-function parseAbsoluteUrl(absoluteUrl, locationObj, appBase) {
- var parsedUrl = urlResolve(absoluteUrl, appBase);
-
- locationObj.$$protocol = parsedUrl.protocol;
- locationObj.$$host = parsedUrl.hostname;
- locationObj.$$port = int(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
-}
-
-
-function parseAppUrl(relativeUrl, locationObj, appBase) {
- var prefixed = (relativeUrl.charAt(0) !== '/');
- if (prefixed) {
- relativeUrl = '/' + relativeUrl;
- }
- var match = urlResolve(relativeUrl, appBase);
- locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
- match.pathname.substring(1) : match.pathname);
- locationObj.$$search = parseKeyValue(match.search);
- locationObj.$$hash = decodeURIComponent(match.hash);
-
- // make sure path starts with '/';
- if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
- locationObj.$$path = '/' + locationObj.$$path;
- }
-}
-
-
-/**
- *
- * @param {string} begin
- * @param {string} whole
- * @returns {string} returns text from whole after begin or undefined if it does not begin with
- * expected string.
- */
-function beginsWith(begin, whole) {
- if (whole.indexOf(begin) === 0) {
- return whole.substr(begin.length);
- }
-}
-
-
-function stripHash(url) {
- var index = url.indexOf('#');
- return index == -1 ? url : url.substr(0, index);
-}
-
-
-function stripFile(url) {
- return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
-}
-
-/* return the server only (scheme://host:port) */
-function serverBase(url) {
- return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
-}
-
-
-/**
- * LocationHtml5Url represents an url
- * This object is exposed as $location service when HTML5 mode is enabled and supported
- *
- * @constructor
- * @param {string} appBase application base URL
- * @param {string} basePrefix url path prefix
- */
-function LocationHtml5Url(appBase, basePrefix) {
- this.$$html5 = true;
- basePrefix = basePrefix || '';
- var appBaseNoFile = stripFile(appBase);
- parseAbsoluteUrl(appBase, this, appBase);
-
-
- /**
- * Parse given html5 (regular) url string into properties
- * @param {string} newAbsoluteUrl HTML5 url
- * @private
- */
- this.$$parse = function(url) {
- var pathUrl = beginsWith(appBaseNoFile, url);
- if (!isString(pathUrl)) {
- throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
- appBaseNoFile);
- }
-
- parseAppUrl(pathUrl, this, appBase);
-
- if (!this.$$path) {
- this.$$path = '/';
- }
-
- this.$$compose();
- };
-
- /**
- * Compose url and update `absUrl` property
- * @private
- */
- this.$$compose = function() {
- var search = toKeyValue(this.$$search),
- hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
-
- this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
- this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
- };
-
- this.$$rewrite = function(url) {
- var appUrl, prevAppUrl;
-
- if ( (appUrl = beginsWith(appBase, url)) !== undefined ) {
- prevAppUrl = appUrl;
- if ( (appUrl = beginsWith(basePrefix, appUrl)) !== undefined ) {
- return appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
- } else {
- return appBase + prevAppUrl;
- }
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) !== undefined ) {
- return appBaseNoFile + appUrl;
- } else if (appBaseNoFile == url + '/') {
- return appBaseNoFile;
- }
- };
-}
-
-
-/**
- * LocationHashbangUrl represents url
- * This object is exposed as $location service when developer doesn't opt into html5 mode.
- * It also serves as the base class for html5 mode fallback on legacy browsers.
- *
- * @constructor
- * @param {string} appBase application base URL
- * @param {string} hashPrefix hashbang prefix
- */
-function LocationHashbangUrl(appBase, hashPrefix) {
- var appBaseNoFile = stripFile(appBase);
-
- parseAbsoluteUrl(appBase, this, appBase);
-
-
- /**
- * Parse given hashbang url into properties
- * @param {string} url Hashbang url
- * @private
- */
- this.$$parse = function(url) {
- var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
- var withoutHashUrl = withoutBaseUrl.charAt(0) == '#'
- ? beginsWith(hashPrefix, withoutBaseUrl)
- : (this.$$html5)
- ? withoutBaseUrl
- : '';
-
- if (!isString(withoutHashUrl)) {
- throw $locationMinErr('ihshprfx', 'Invalid url "{0}", missing hash prefix "{1}".', url,
- hashPrefix);
- }
- parseAppUrl(withoutHashUrl, this, appBase);
-
- this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
-
- this.$$compose();
-
- /*
- * In Windows, on an anchor node on documents loaded from
- * the filesystem, the browser will return a pathname
- * prefixed with the drive name ('/C:/path') when a
- * pathname without a drive is set:
- * * a.setAttribute('href', '/foo')
- * * a.pathname === '/C:/foo' //true
- *
- * Inside of Angular, we're always using pathnames that
- * do not include drive names for routing.
- */
- function removeWindowsDriveName (path, url, base) {
- /*
- Matches paths for file protocol on windows,
- such as /C:/foo/bar, and captures only /foo/bar.
- */
- var windowsFilePathExp = /^\/?.*?:(\/.*)/;
-
- var firstPathSegmentMatch;
-
- //Get the relative path from the input URL.
- if (url.indexOf(base) === 0) {
- url = url.replace(base, '');
- }
-
- /*
- * The input URL intentionally contains a
- * first path segment that ends with a colon.
- */
- if (windowsFilePathExp.exec(url)) {
- return path;
- }
-
- firstPathSegmentMatch = windowsFilePathExp.exec(path);
- return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
- }
- };
-
- /**
- * Compose hashbang url and update `absUrl` property
- * @private
- */
- this.$$compose = function() {
- var search = toKeyValue(this.$$search),
- hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
-
- this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
- this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
- };
-
- this.$$rewrite = function(url) {
- if(stripHash(appBase) == stripHash(url)) {
- return url;
- }
- };
-}
-
-
-/**
- * LocationHashbangUrl represents url
- * This object is exposed as $location service when html5 history api is enabled but the browser
- * does not support it.
- *
- * @constructor
- * @param {string} appBase application base URL
- * @param {string} hashPrefix hashbang prefix
- */
-function LocationHashbangInHtml5Url(appBase, hashPrefix) {
- this.$$html5 = true;
- LocationHashbangUrl.apply(this, arguments);
-
- var appBaseNoFile = stripFile(appBase);
-
- this.$$rewrite = function(url) {
- var appUrl;
-
- if ( appBase == stripHash(url) ) {
- return url;
- } else if ( (appUrl = beginsWith(appBaseNoFile, url)) ) {
- return appBase + hashPrefix + appUrl;
- } else if ( appBaseNoFile === url + '/') {
- return appBaseNoFile;
- }
- };
-}
-
-
-LocationHashbangInHtml5Url.prototype =
- LocationHashbangUrl.prototype =
- LocationHtml5Url.prototype = {
-
- /**
- * Are we in html5 mode?
- * @private
- */
- $$html5: false,
-
- /**
- * Has any change been replacing ?
- * @private
- */
- $$replace: false,
-
- /**
- * @ngdoc method
- * @name ng.$location#absUrl
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return full url representation with all segments encoded according to rules specified in
- * {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}.
- *
- * @return {string} full url
- */
- absUrl: locationGetter('$$absUrl'),
-
- /**
- * @ngdoc method
- * @name ng.$location#url
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
- *
- * Change path, search and hash, when called with parameter and return `$location`.
- *
- * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
- * @param {string=} replace The path that will be changed
- * @return {string} url
- */
- url: function(url, replace) {
- if (isUndefined(url))
- return this.$$url;
-
- var match = PATH_MATCH.exec(url);
- if (match[1]) this.path(decodeURIComponent(match[1]));
- if (match[2] || match[1]) this.search(match[3] || '');
- this.hash(match[5] || '', replace);
-
- return this;
- },
-
- /**
- * @ngdoc method
- * @name ng.$location#protocol
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return protocol of current url.
- *
- * @return {string} protocol of current url
- */
- protocol: locationGetter('$$protocol'),
-
- /**
- * @ngdoc method
- * @name ng.$location#host
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return host of current url.
- *
- * @return {string} host of current url.
- */
- host: locationGetter('$$host'),
-
- /**
- * @ngdoc method
- * @name ng.$location#port
- * @methodOf ng.$location
- *
- * @description
- * This method is getter only.
- *
- * Return port of current url.
- *
- * @return {Number} port
- */
- port: locationGetter('$$port'),
-
- /**
- * @ngdoc method
- * @name ng.$location#path
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return path of current url when called without any parameter.
- *
- * Change path when called with parameter and return `$location`.
- *
- * Note: Path should always begin with forward slash (/), this method will add the forward slash
- * if it is missing.
- *
- * @param {string=} path New path
- * @return {string} path
- */
- path: locationGetterSetter('$$path', function(path) {
- return path.charAt(0) == '/' ? path : '/' + path;
- }),
-
- /**
- * @ngdoc method
- * @name ng.$location#search
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return search part (as object) of current url when called without any parameter.
- *
- * Change search part when called with parameter and return `$location`.
- *
- * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
- * hash object. Hash object may contain an array of values, which will be decoded as duplicates in
- * the url.
- *
- * @param {(string|Array<string>)=} paramValue If `search` is a string, then `paramValue` will override only a
- * single search parameter. If `paramValue` is an array, it will set the parameter as a
- * comma-separated value. If `paramValue` is `null`, the parameter will be deleted.
- *
- * @return {string} search
- */
- search: function(search, paramValue) {
- switch (arguments.length) {
- case 0:
- return this.$$search;
- case 1:
- if (isString(search)) {
- this.$$search = parseKeyValue(search);
- } else if (isObject(search)) {
- this.$$search = search;
- } else {
- throw $locationMinErr('isrcharg',
- 'The first argument of the `$location#search()` call must be a string or an object.');
- }
- break;
- default:
- if (isUndefined(paramValue) || paramValue === null) {
- delete this.$$search[search];
- } else {
- this.$$search[search] = paramValue;
- }
- }
-
- this.$$compose();
- return this;
- },
-
- /**
- * @ngdoc method
- * @name ng.$location#hash
- * @methodOf ng.$location
- *
- * @description
- * This method is getter / setter.
- *
- * Return hash fragment when called without any parameter.
- *
- * Change hash fragment when called with parameter and return `$location`.
- *
- * @param {string=} hash New hash fragment
- * @return {string} hash
- */
- hash: locationGetterSetter('$$hash', identity),
-
- /**
- * @ngdoc method
- * @name ng.$location#replace
- * @methodOf ng.$location
- *
- * @description
- * If called, all changes to $location during current `$digest` will be replacing current history
- * record, instead of adding new one.
- */
- replace: function() {
- this.$$replace = true;
- return this;
- }
-};
-
-function locationGetter(property) {
- return function() {
- return this[property];
- };
-}
-
-
-function locationGetterSetter(property, preprocess) {
- return function(value) {
- if (isUndefined(value))
- return this[property];
-
- this[property] = preprocess(value);
- this.$$compose();
-
- return this;
- };
-}
-
-
-/**
- * @ngdoc object
- * @name ng.$location
- *
- * @requires $browser
- * @requires $sniffer
- * @requires $rootElement
- *
- * @description
- * The $location service parses the URL in the browser address bar (based on the
- * {@link https://developer.mozilla.org/en/window.location window.location}) and makes the URL
- * available to your application. Changes to the URL in the address bar are reflected into
- * $location service and changes to $location are reflected into the browser address bar.
- *
- * **The $location service:**
- *
- * - Exposes the current URL in the browser address bar, so you can
- * - Watch and observe the URL.
- * - Change the URL.
- * - Synchronizes the URL with the browser when the user
- * - Changes the address bar.
- * - Clicks the back or forward button (or clicks a History link).
- * - Clicks on a link.
- * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
- *
- * For more information see {@link guide/dev_guide.services.$location Developer Guide: Angular
- * Services: Using $location}
- */
-
-/**
- * @ngdoc object
- * @name ng.$locationProvider
- * @description
- * Use the `$locationProvider` to configure how the application deep linking paths are stored.
- */
-function $LocationProvider(){
- var hashPrefix = '',
- html5Mode = false;
-
- /**
- * @ngdoc property
- * @name ng.$locationProvider#hashPrefix
- * @methodOf ng.$locationProvider
- * @description
- * @param {string=} prefix Prefix for hash part (containing path and search)
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
- */
- this.hashPrefix = function(prefix) {
- if (isDefined(prefix)) {
- hashPrefix = prefix;
- return this;
- } else {
- return hashPrefix;
- }
- };
-
- /**
- * @ngdoc property
- * @name ng.$locationProvider#html5Mode
- * @methodOf ng.$locationProvider
- * @description
- * @param {boolean=} mode Use HTML5 strategy if available.
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
- */
- this.html5Mode = function(mode) {
- if (isDefined(mode)) {
- html5Mode = mode;
- return this;
- } else {
- return html5Mode;
- }
- };
-
- /**
- * @ngdoc event
- * @name ng.$location#$locationChangeStart
- * @eventOf ng.$location
- * @eventType broadcast on root scope
- * @description
- * 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.
- *
- * @param {Object} angularEvent Synthetic event object.
- * @param {string} newUrl New URL
- * @param {string=} oldUrl URL that was before it was changed.
- */
-
- /**
- * @ngdoc event
- * @name ng.$location#$locationChangeSuccess
- * @eventOf ng.$location
- * @eventType broadcast on root scope
- * @description
- * Broadcasted after a URL was changed.
- *
- * @param {Object} angularEvent Synthetic event object.
- * @param {string} newUrl New URL
- * @param {string=} oldUrl URL that was before it was changed.
- */
-
- this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement',
- function( $rootScope, $browser, $sniffer, $rootElement) {
- var $location,
- LocationMode,
- baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
- initialUrl = $browser.url(),
- appBase;
-
- if (html5Mode) {
- appBase = serverBase(initialUrl) + (baseHref || '/');
- LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
- } else {
- appBase = stripHash(initialUrl);
- LocationMode = LocationHashbangUrl;
- }
- $location = new LocationMode(appBase, '#' + hashPrefix);
- $location.$$parse($location.$$rewrite(initialUrl));
-
- $rootElement.on('click', function(event) {
- // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
- // currently we open nice url link and redirect then
-
- if (event.ctrlKey || event.metaKey || event.which == 2) return;
-
- var elm = jqLite(event.target);
-
- // traverse the DOM up to find first A tag
- while (lowercase(elm[0].nodeName) !== 'a') {
- // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
- if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
- }
-
- var absHref = elm.prop('href');
- var rewrittenUrl = $location.$$rewrite(absHref);
-
- if (absHref && !elm.attr('target') && rewrittenUrl && !event.isDefaultPrevented()) {
- event.preventDefault();
- if (rewrittenUrl != $browser.url()) {
- // update location manually
- $location.$$parse(rewrittenUrl);
- $rootScope.$apply();
- // hack to work around FF6 bug 684208 when scenario runner clicks on links
- window.angular['ff-684208-preventDefault'] = true;
- }
- }
- });
-
-
- // rewrite hashbang url <> html5 url
- if ($location.absUrl() != initialUrl) {
- $browser.url($location.absUrl(), true);
- }
-
- // update $location when $browser url changes
- $browser.onUrlChange(function(newUrl) {
- if ($location.absUrl() != newUrl) {
- if ($rootScope.$broadcast('$locationChangeStart', newUrl,
- $location.absUrl()).defaultPrevented) {
- $browser.url($location.absUrl());
- return;
- }
- $rootScope.$evalAsync(function() {
- var oldUrl = $location.absUrl();
-
- $location.$$parse(newUrl);
- afterLocationChange(oldUrl);
- });
- if (!$rootScope.$$phase) $rootScope.$digest();
- }
- });
-
- // update browser
- var changeCounter = 0;
- $rootScope.$watch(function $locationWatch() {
- var oldUrl = $browser.url();
- var currentReplace = $location.$$replace;
-
- if (!changeCounter || oldUrl != $location.absUrl()) {
- changeCounter++;
- $rootScope.$evalAsync(function() {
- if ($rootScope.$broadcast('$locationChangeStart', $location.absUrl(), oldUrl).
- defaultPrevented) {
- $location.$$parse(oldUrl);
- } else {
- $browser.url($location.absUrl(), currentReplace);
- afterLocationChange(oldUrl);
- }
- });
- }
- $location.$$replace = false;
-
- return changeCounter;
- });
-
- return $location;
-
- function afterLocationChange(oldUrl) {
- $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl);
- }
-}];
-}
-
-/**
- * @ngdoc object
- * @name ng.$log
- * @requires $window
- *
- * @description
- * Simple service for logging. Default implementation safely writes the message
- * into the browser's console (if present).
- *
- * The main purpose of this service is to simplify debugging and troubleshooting.
- *
- * The default is to log `debug` messages. You can use
- * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
- *
- * @example
- <example>
- <file name="script.js">
- function LogCtrl($scope, $log) {
- $scope.$log = $log;
- $scope.message = 'Hello World!';
- }
- </file>
- <file name="index.html">
- <div ng-controller="LogCtrl">
- <p>Reload this page with open console, enter text and hit the log button...</p>
- Message:
- <input type="text" ng-model="message"/>
- <button ng-click="$log.log(message)">log</button>
- <button ng-click="$log.warn(message)">warn</button>
- <button ng-click="$log.info(message)">info</button>
- <button ng-click="$log.error(message)">error</button>
- </div>
- </file>
- </example>
- */
-
-/**
- * @ngdoc object
- * @name ng.$logProvider
- * @description
- * Use the `$logProvider` to configure how the application logs messages
- */
-function $LogProvider(){
- var debug = true,
- self = this;
-
- /**
- * @ngdoc property
- * @name ng.$logProvider#debugEnabled
- * @methodOf ng.$logProvider
- * @description
- * @param {string=} flag enable or disable debug level messages
- * @returns {*} current value if used as getter or itself (chaining) if used as setter
- */
- this.debugEnabled = function(flag) {
- if (isDefined(flag)) {
- debug = flag;
- return this;
- } else {
- return debug;
- }
- };
-
- this.$get = ['$window', function($window){
- return {
- /**
- * @ngdoc method
- * @name ng.$log#log
- * @methodOf ng.$log
- *
- * @description
- * Write a log message
- */
- log: consoleLog('log'),
-
- /**
- * @ngdoc method
- * @name ng.$log#info
- * @methodOf ng.$log
- *
- * @description
- * Write an information message
- */
- info: consoleLog('info'),
-
- /**
- * @ngdoc method
- * @name ng.$log#warn
- * @methodOf ng.$log
- *
- * @description
- * Write a warning message
- */
- warn: consoleLog('warn'),
-
- /**
- * @ngdoc method
- * @name ng.$log#error
- * @methodOf ng.$log
- *
- * @description
- * Write an error message
- */
- error: consoleLog('error'),
-
- /**
- * @ngdoc method
- * @name ng.$log#debug
- * @methodOf ng.$log
- *
- * @description
- * Write a debug message
- */
- debug: (function () {
- var fn = consoleLog('debug');
-
- return function() {
- if (debug) {
- fn.apply(self, arguments);
- }
- };
- }())
- };
-
- function formatError(arg) {
- if (arg instanceof Error) {
- if (arg.stack) {
- arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
- ? 'Error: ' + arg.message + '\n' + arg.stack
- : arg.stack;
- } else if (arg.sourceURL) {
- arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
- }
- }
- return arg;
- }
-
- function consoleLog(type) {
- var console = $window.console || {},
- logFn = console[type] || console.log || noop;
-
- if (logFn.apply) {
- return function() {
- var args = [];
- forEach(arguments, function(arg) {
- args.push(formatError(arg));
- });
- return logFn.apply(console, args);
- };
- }
-
- // we are IE which either doesn't have window.console => this is noop and we do nothing,
- // or we are IE where console.log doesn't have apply so we log at least first 2 args
- return function(arg1, arg2) {
- logFn(arg1, arg2 == null ? '' : arg2);
- };
- }
- }];
-}
-
-var $parseMinErr = minErr('$parse');
-var promiseWarningCache = {};
-var promiseWarning;
-
-// Sandboxing Angular Expressions
-// ------------------------------
-// Angular expressions are generally considered safe because these expressions only have direct
-// access to $scope and locals. However, one can obtain the ability to execute arbitrary JS code by
-// obtaining a reference to native JS functions such as the Function constructor.
-//
-// As an example, consider the following Angular expression:
-//
-// {}.toString.constructor(alert("evil JS code"))
-//
-// We want to prevent this type of access. For the sake of performance, during the lexing phase we
-// disallow any "dotted" access to any member named "constructor".
-//
-// For reflective calls (a[b]) we check that the value of the lookup is not the Function constructor
-// while evaluating the expression, which is a stronger but more expensive test. Since reflective
-// calls are expensive anyway, this is not such a big deal compared to static dereferencing.
-//
-// This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
-// against the expression language, but not to prevent exploits that were enabled by exposing
-// sensitive JavaScript or browser apis on Scope. Exposing such objects on a Scope is never a good
-// practice and therefore we are not even trying to protect against interaction with an object
-// explicitly exposed in this way.
-//
-// A developer could foil the name check by aliasing the Function constructor under a different
-// name on the scope.
-//
-// In general, it is not possible to access a Window object from an angular expression unless a
-// window or some DOM object that has a reference to window is published onto a Scope.
-
-function ensureSafeMemberName(name, fullExpression) {
- if (name === "constructor") {
- throw $parseMinErr('isecfld',
- 'Referencing "constructor" field in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- }
- return name;
-}
-
-function ensureSafeObject(obj, fullExpression) {
- // nifty check if obj is Function that is fast and works across iframes and other contexts
- if (obj) {
- if (obj.constructor === obj) {
- throw $parseMinErr('isecfn',
- 'Referencing Function in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (// isWindow(obj)
- obj.document && obj.location && obj.alert && obj.setInterval) {
- throw $parseMinErr('isecwindow',
- 'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- } else if (// isElement(obj)
- obj.children && (obj.nodeName || (obj.on && obj.find))) {
- throw $parseMinErr('isecdom',
- 'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
- fullExpression);
- }
- }
- return obj;
-}
-
-var OPERATORS = {
- /* jshint bitwise : false */
- 'null':function(){return null;},
- 'true':function(){return true;},
- 'false':function(){return false;},
- undefined:noop,
- '+':function(self, locals, a,b){
- a=a(self, locals); b=b(self, locals);
- if (isDefined(a)) {
- if (isDefined(b)) {
- return a + b;
- }
- return a;
- }
- return isDefined(b)?b:undefined;},
- '-':function(self, locals, a,b){
- a=a(self, locals); b=b(self, locals);
- return (isDefined(a)?a:0)-(isDefined(b)?b:0);
- },
- '*':function(self, locals, a,b){return a(self, locals)*b(self, locals);},
- '/':function(self, locals, a,b){return a(self, locals)/b(self, locals);},
- '%':function(self, locals, a,b){return a(self, locals)%b(self, locals);},
- '^':function(self, locals, a,b){return a(self, locals)^b(self, locals);},
- '=':noop,
- '===':function(self, locals, a, b){return a(self, locals)===b(self, locals);},
- '!==':function(self, locals, a, b){return a(self, locals)!==b(self, locals);},
- '==':function(self, locals, a,b){return a(self, locals)==b(self, locals);},
- '!=':function(self, locals, a,b){return a(self, locals)!=b(self, locals);},
- '<':function(self, locals, a,b){return a(self, locals)<b(self, locals);},
- '>':function(self, locals, a,b){return a(self, locals)>b(self, locals);},
- '<=':function(self, locals, a,b){return a(self, locals)<=b(self, locals);},
- '>=':function(self, locals, a,b){return a(self, locals)>=b(self, locals);},
- '&&':function(self, locals, a,b){return a(self, locals)&&b(self, locals);},
- '||':function(self, locals, a,b){return a(self, locals)||b(self, locals);},
- '&':function(self, locals, a,b){return a(self, locals)&b(self, locals);},
-// '|':function(self, locals, a,b){return a|b;},
- '|':function(self, locals, a,b){return b(self, locals)(self, locals, a(self, locals));},
- '!':function(self, locals, a){return !a(self, locals);}
-};
-/* jshint bitwise: true */
-var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
-
-
-/////////////////////////////////////////
-
-
-/**
- * @constructor
- */
-var Lexer = function (options) {
- this.options = options;
-};
-
-Lexer.prototype = {
- constructor: Lexer,
-
- lex: function (text) {
- this.text = text;
-
- this.index = 0;
- this.ch = undefined;
- this.lastCh = ':'; // can start regexp
-
- this.tokens = [];
-
- var token;
- var json = [];
-
- while (this.index < this.text.length) {
- this.ch = this.text.charAt(this.index);
- if (this.is('"\'')) {
- this.readString(this.ch);
- } else if (this.isNumber(this.ch) || this.is('.') && this.isNumber(this.peek())) {
- this.readNumber();
- } else if (this.isIdent(this.ch)) {
- this.readIdent();
- // identifiers can only be if the preceding char was a { or ,
- if (this.was('{,') && json[0] === '{' &&
- (token = this.tokens[this.tokens.length - 1])) {
- token.json = token.text.indexOf('.') === -1;
- }
- } else if (this.is('(){}[].,;:?')) {
- this.tokens.push({
- index: this.index,
- text: this.ch,
- json: (this.was(':[,') && this.is('{[')) || this.is('}]:,')
- });
- if (this.is('{[')) json.unshift(this.ch);
- if (this.is('}]')) json.shift();
- this.index++;
- } else if (this.isWhitespace(this.ch)) {
- this.index++;
- continue;
- } else {
- var ch2 = this.ch + this.peek();
- var ch3 = ch2 + this.peek(2);
- var fn = OPERATORS[this.ch];
- var fn2 = OPERATORS[ch2];
- var fn3 = OPERATORS[ch3];
- if (fn3) {
- this.tokens.push({index: this.index, text: ch3, fn: fn3});
- this.index += 3;
- } else if (fn2) {
- this.tokens.push({index: this.index, text: ch2, fn: fn2});
- this.index += 2;
- } else if (fn) {
- this.tokens.push({
- index: this.index,
- text: this.ch,
- fn: fn,
- json: (this.was('[,:') && this.is('+-'))
- });
- this.index += 1;
- } else {
- this.throwError('Unexpected next character ', this.index, this.index + 1);
- }
- }
- this.lastCh = this.ch;
- }
- return this.tokens;
- },
-
- is: function(chars) {
- return chars.indexOf(this.ch) !== -1;
- },
-
- was: function(chars) {
- return chars.indexOf(this.lastCh) !== -1;
- },
-
- peek: function(i) {
- var num = i || 1;
- return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
- },
-
- isNumber: function(ch) {
- return ('0' <= ch && ch <= '9');
- },
-
- isWhitespace: function(ch) {
- // IE treats non-breaking space as \u00A0
- return (ch === ' ' || ch === '\r' || ch === '\t' ||
- ch === '\n' || ch === '\v' || ch === '\u00A0');
- },
-
- isIdent: function(ch) {
- return ('a' <= ch && ch <= 'z' ||
- 'A' <= ch && ch <= 'Z' ||
- '_' === ch || ch === '$');
- },
-
- isExpOperator: function(ch) {
- return (ch === '-' || ch === '+' || this.isNumber(ch));
- },
-
- throwError: function(error, start, end) {
- end = end || this.index;
- var colStr = (isDefined(start)
- ? 's ' + start + '-' + this.index + ' [' + this.text.substring(start, end) + ']'
- : ' ' + end);
- throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
- error, colStr, this.text);
- },
-
- readNumber: function() {
- var number = '';
- var start = this.index;
- while (this.index < this.text.length) {
- var ch = lowercase(this.text.charAt(this.index));
- if (ch == '.' || this.isNumber(ch)) {
- number += ch;
- } else {
- var peekCh = this.peek();
- if (ch == 'e' && this.isExpOperator(peekCh)) {
- number += ch;
- } else if (this.isExpOperator(ch) &&
- peekCh && this.isNumber(peekCh) &&
- number.charAt(number.length - 1) == 'e') {
- number += ch;
- } else if (this.isExpOperator(ch) &&
- (!peekCh || !this.isNumber(peekCh)) &&
- number.charAt(number.length - 1) == 'e') {
- this.throwError('Invalid exponent');
- } else {
- break;
- }
- }
- this.index++;
- }
- number = 1 * number;
- this.tokens.push({
- index: start,
- text: number,
- json: true,
- fn: function() { return number; }
- });
- },
-
- readIdent: function() {
- var parser = this;
-
- var ident = '';
- var start = this.index;
-
- var lastDot, peekIndex, methodName, ch;
-
- while (this.index < this.text.length) {
- ch = this.text.charAt(this.index);
- if (ch === '.' || this.isIdent(ch) || this.isNumber(ch)) {
- if (ch === '.') lastDot = this.index;
- ident += ch;
- } else {
- break;
- }
- this.index++;
- }
-
- //check if this is not a method invocation and if it is back out to last dot
- if (lastDot) {
- peekIndex = this.index;
- while (peekIndex < this.text.length) {
- ch = this.text.charAt(peekIndex);
- if (ch === '(') {
- methodName = ident.substr(lastDot - start + 1);
- ident = ident.substr(0, lastDot - start);
- this.index = peekIndex;
- break;
- }
- if (this.isWhitespace(ch)) {
- peekIndex++;
- } else {
- break;
- }
- }
- }
-
-
- var token = {
- index: start,
- text: ident
- };
-
- // OPERATORS is our own object so we don't need to use special hasOwnPropertyFn
- if (OPERATORS.hasOwnProperty(ident)) {
- token.fn = OPERATORS[ident];
- token.json = OPERATORS[ident];
- } else {
- var getter = getterFn(ident, this.options, this.text);
- token.fn = extend(function(self, locals) {
- return (getter(self, locals));
- }, {
- assign: function(self, value) {
- return setter(self, ident, value, parser.text, parser.options);
- }
- });
- }
-
- this.tokens.push(token);
-
- if (methodName) {
- this.tokens.push({
- index:lastDot,
- text: '.',
- json: false
- });
- this.tokens.push({
- index: lastDot + 1,
- text: methodName,
- json: false
- });
- }
- },
-
- readString: function(quote) {
- var start = this.index;
- this.index++;
- var string = '';
- var rawString = quote;
- var escape = false;
- while (this.index < this.text.length) {
- var ch = this.text.charAt(this.index);
- rawString += ch;
- if (escape) {
- if (ch === 'u') {
- var hex = this.text.substring(this.index + 1, this.index + 5);
- if (!hex.match(/[\da-f]{4}/i))
- this.throwError('Invalid unicode escape [\\u' + hex + ']');
- this.index += 4;
- string += String.fromCharCode(parseInt(hex, 16));
- } else {
- var rep = ESCAPE[ch];
- if (rep) {
- string += rep;
- } else {
- string += ch;
- }
- }
- escape = false;
- } else if (ch === '\\') {
- escape = true;
- } else if (ch === quote) {
- this.index++;
- this.tokens.push({
- index: start,
- text: rawString,
- string: string,
- json: true,
- fn: function() { return string; }
- });
- return;
- } else {
- string += ch;
- }
- this.index++;
- }
- this.throwError('Unterminated quote', start);
- }
-};
-
-
-/**
- * @constructor
- */
-var Parser = function (lexer, $filter, options) {
- this.lexer = lexer;
- this.$filter = $filter;
- this.options = options;
-};
-
-Parser.ZERO = function () { return 0; };
-
-Parser.prototype = {
- constructor: Parser,
-
- parse: function (text, json) {
- this.text = text;
-
- //TODO(i): strip all the obsolte json stuff from this file
- this.json = json;
-
- this.tokens = this.lexer.lex(text);
-
- if (json) {
- // The extra level of aliasing is here, just in case the lexer misses something, so that
- // we prevent any accidental execution in JSON.
- this.assignment = this.logicalOR;
-
- this.functionCall =
- this.fieldAccess =
- this.objectIndex =
- this.filterChain = function() {
- this.throwError('is not valid json', {text: text, index: 0});
- };
- }
-
- var value = json ? this.primary() : this.statements();
-
- if (this.tokens.length !== 0) {
- this.throwError('is an unexpected token', this.tokens[0]);
- }
-
- value.literal = !!value.literal;
- value.constant = !!value.constant;
-
- return value;
- },
-
- primary: function () {
- var primary;
- if (this.expect('(')) {
- primary = this.filterChain();
- this.consume(')');
- } else if (this.expect('[')) {
- primary = this.arrayDeclaration();
- } else if (this.expect('{')) {
- primary = this.object();
- } else {
- var token = this.expect();
- primary = token.fn;
- if (!primary) {
- this.throwError('not a primary expression', token);
- }
- if (token.json) {
- primary.constant = true;
- primary.literal = true;
- }
- }
-
- var next, context;
- while ((next = this.expect('(', '[', '.'))) {
- if (next.text === '(') {
- primary = this.functionCall(primary, context);
- context = null;
- } else if (next.text === '[') {
- context = primary;
- primary = this.objectIndex(primary);
- } else if (next.text === '.') {
- context = primary;
- primary = this.fieldAccess(primary);
- } else {
- this.throwError('IMPOSSIBLE');
- }
- }
- return primary;
- },
-
- throwError: function(msg, token) {
- throw $parseMinErr('syntax',
- 'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
- token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
- },
-
- peekToken: function() {
- if (this.tokens.length === 0)
- throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
- return this.tokens[0];
- },
-
- peek: function(e1, e2, e3, e4) {
- if (this.tokens.length > 0) {
- var token = this.tokens[0];
- var t = token.text;
- if (t === e1 || t === e2 || t === e3 || t === e4 ||
- (!e1 && !e2 && !e3 && !e4)) {
- return token;
- }
- }
- return false;
- },
-
- expect: function(e1, e2, e3, e4){
- var token = this.peek(e1, e2, e3, e4);
- if (token) {
- if (this.json && !token.json) {
- this.throwError('is not valid json', token);
- }
- this.tokens.shift();
- return token;
- }
- return false;
- },
-
- consume: function(e1){
- if (!this.expect(e1)) {
- this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
- }
- },
-
- unaryFn: function(fn, right) {
- return extend(function(self, locals) {
- return fn(self, locals, right);
- }, {
- constant:right.constant
- });
- },
-
- ternaryFn: function(left, middle, right){
- return extend(function(self, locals){
- return left(self, locals) ? middle(self, locals) : right(self, locals);
- }, {
- constant: left.constant && middle.constant && right.constant
- });
- },
-
- binaryFn: function(left, fn, right) {
- return extend(function(self, locals) {
- return fn(self, locals, left, right);
- }, {
- constant:left.constant && right.constant
- });
- },
-
- statements: function() {
- var statements = [];
- while (true) {
- if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
- statements.push(this.filterChain());
- if (!this.expect(';')) {
- // optimize for the common case where there is only one statement.
- // TODO(size): maybe we should not support multiple statements?
- return (statements.length === 1)
- ? statements[0]
- : function(self, locals) {
- var value;
- for (var i = 0; i < statements.length; i++) {
- var statement = statements[i];
- if (statement) {
- value = statement(self, locals);
- }
- }
- return value;
- };
- }
- }
- },
-
- filterChain: function() {
- var left = this.expression();
- var token;
- while (true) {
- if ((token = this.expect('|'))) {
- left = this.binaryFn(left, token.fn, this.filter());
- } else {
- return left;
- }
- }
- },
-
- filter: function() {
- var token = this.expect();
- var fn = this.$filter(token.text);
- var argsFn = [];
- while (true) {
- if ((token = this.expect(':'))) {
- argsFn.push(this.expression());
- } else {
- var fnInvoke = function(self, locals, input) {
- var args = [input];
- for (var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](self, locals));
- }
- return fn.apply(self, args);
- };
- return function() {
- return fnInvoke;
- };
- }
- }
- },
-
- expression: function() {
- return this.assignment();
- },
-
- assignment: function() {
- var left = this.ternary();
- var right;
- var token;
- if ((token = this.expect('='))) {
- if (!left.assign) {
- this.throwError('implies assignment but [' +
- this.text.substring(0, token.index) + '] can not be assigned to', token);
- }
- right = this.ternary();
- return function(scope, locals) {
- return left.assign(scope, right(scope, locals), locals);
- };
- }
- return left;
- },
-
- ternary: function() {
- var left = this.logicalOR();
- var middle;
- var token;
- if ((token = this.expect('?'))) {
- middle = this.ternary();
- if ((token = this.expect(':'))) {
- return this.ternaryFn(left, middle, this.ternary());
- } else {
- this.throwError('expected :', token);
- }
- } else {
- return left;
- }
- },
-
- logicalOR: function() {
- var left = this.logicalAND();
- var token;
- while (true) {
- if ((token = this.expect('||'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND());
- } else {
- return left;
- }
- }
- },
-
- logicalAND: function() {
- var left = this.equality();
- var token;
- if ((token = this.expect('&&'))) {
- left = this.binaryFn(left, token.fn, this.logicalAND());
- }
- return left;
- },
-
- equality: function() {
- var left = this.relational();
- var token;
- if ((token = this.expect('==','!=','===','!=='))) {
- left = this.binaryFn(left, token.fn, this.equality());
- }
- return left;
- },
-
- relational: function() {
- var left = this.additive();
- var token;
- if ((token = this.expect('<', '>', '<=', '>='))) {
- left = this.binaryFn(left, token.fn, this.relational());
- }
- return left;
- },
-
- additive: function() {
- var left = this.multiplicative();
- var token;
- while ((token = this.expect('+','-'))) {
- left = this.binaryFn(left, token.fn, this.multiplicative());
- }
- return left;
- },
-
- multiplicative: function() {
- var left = this.unary();
- var token;
- while ((token = this.expect('*','/','%'))) {
- left = this.binaryFn(left, token.fn, this.unary());
- }
- return left;
- },
-
- unary: function() {
- var token;
- if (this.expect('+')) {
- return this.primary();
- } else if ((token = this.expect('-'))) {
- return this.binaryFn(Parser.ZERO, token.fn, this.unary());
- } else if ((token = this.expect('!'))) {
- return this.unaryFn(token.fn, this.unary());
- } else {
- return this.primary();
- }
- },
-
- fieldAccess: function(object) {
- var parser = this;
- var field = this.expect().text;
- var getter = getterFn(field, this.options, this.text);
-
- return extend(function(scope, locals, self) {
- return getter(self || object(scope, locals), locals);
- }, {
- assign: function(scope, value, locals) {
- return setter(object(scope, locals), field, value, parser.text, parser.options);
- }
- });
- },
-
- objectIndex: function(obj) {
- var parser = this;
-
- var indexFn = this.expression();
- this.consume(']');
-
- return extend(function(self, locals) {
- var o = obj(self, locals),
- i = indexFn(self, locals),
- v, p;
-
- if (!o) return undefined;
- v = ensureSafeObject(o[i], parser.text);
- if (v && v.then && parser.options.unwrapPromises) {
- p = v;
- if (!('$$v' in v)) {
- p.$$v = undefined;
- p.then(function(val) { p.$$v = val; });
- }
- v = v.$$v;
- }
- return v;
- }, {
- assign: function(self, value, locals) {
- var key = indexFn(self, locals);
- // prevent overwriting of Function.constructor which would break ensureSafeObject check
- var safe = ensureSafeObject(obj(self, locals), parser.text);
- return safe[key] = value;
- }
- });
- },
-
- functionCall: function(fn, contextGetter) {
- var argsFn = [];
- if (this.peekToken().text !== ')') {
- do {
- argsFn.push(this.expression());
- } while (this.expect(','));
- }
- this.consume(')');
-
- var parser = this;
-
- return function(scope, locals) {
- var args = [];
- var context = contextGetter ? contextGetter(scope, locals) : scope;
-
- for (var i = 0; i < argsFn.length; i++) {
- args.push(argsFn[i](scope, locals));
- }
- var fnPtr = fn(scope, locals, context) || noop;
-
- ensureSafeObject(context, parser.text);
- ensureSafeObject(fnPtr, parser.text);
-
- // IE stupidity! (IE doesn't have apply for some native functions)
- var v = fnPtr.apply
- ? fnPtr.apply(context, args)
- : fnPtr(args[0], args[1], args[2], args[3], args[4]);
-
- return ensureSafeObject(v, parser.text);
- };
- },
-
- // This is used with json array declaration
- arrayDeclaration: function () {
- var elementFns = [];
- var allConstant = true;
- if (this.peekToken().text !== ']') {
- do {
- var elementFn = this.expression();
- elementFns.push(elementFn);
- if (!elementFn.constant) {
- allConstant = false;
- }
- } while (this.expect(','));
- }
- this.consume(']');
-
- return extend(function(self, locals) {
- var array = [];
- for (var i = 0; i < elementFns.length; i++) {
- array.push(elementFns[i](self, locals));
- }
- return array;
- }, {
- literal: true,
- constant: allConstant
- });
- },
-
- object: function () {
- var keyValues = [];
- var allConstant = true;
- if (this.peekToken().text !== '}') {
- do {
- var token = this.expect(),
- key = token.string || token.text;
- this.consume(':');
- var value = this.expression();
- keyValues.push({key: key, value: value});
- if (!value.constant) {
- allConstant = false;
- }
- } while (this.expect(','));
- }
- this.consume('}');
-
- return extend(function(self, locals) {
- var object = {};
- for (var i = 0; i < keyValues.length; i++) {
- var keyValue = keyValues[i];
- object[keyValue.key] = keyValue.value(self, locals);
- }
- return object;
- }, {
- literal: true,
- constant: allConstant
- });
- }
-};
-
-
-//////////////////////////////////////////////////
-// Parser helper functions
-//////////////////////////////////////////////////
-
-function setter(obj, path, setValue, fullExp, options) {
- //needed?
- options = options || {};
-
- var element = path.split('.'), key;
- for (var i = 0; element.length > 1; i++) {
- key = ensureSafeMemberName(element.shift(), fullExp);
- var propertyObj = obj[key];
- if (!propertyObj) {
- propertyObj = {};
- obj[key] = propertyObj;
- }
- obj = propertyObj;
- if (obj.then && options.unwrapPromises) {
- promiseWarning(fullExp);
- if (!("$$v" in obj)) {
- (function(promise) {
- promise.then(function(val) { promise.$$v = val; }); }
- )(obj);
- }
- if (obj.$$v === undefined) {
- obj.$$v = {};
- }
- obj = obj.$$v;
- }
- }
- key = ensureSafeMemberName(element.shift(), fullExp);
- obj[key] = setValue;
- return setValue;
-}
-
-var getterFnCache = {};
-
-/**
- * Implementation of the "Black Hole" variant from:
- * - http://jsperf.com/angularjs-parse-getter/4
- * - http://jsperf.com/path-evaluation-simplified/7
- */
-function cspSafeGetterFn(key0, key1, key2, key3, key4, fullExp, options) {
- ensureSafeMemberName(key0, fullExp);
- ensureSafeMemberName(key1, fullExp);
- ensureSafeMemberName(key2, fullExp);
- ensureSafeMemberName(key3, fullExp);
- ensureSafeMemberName(key4, fullExp);
-
- return !options.unwrapPromises
- ? function cspSafeGetter(scope, locals) {
- var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
-
- if (pathVal === null || pathVal === undefined) return pathVal;
- pathVal = pathVal[key0];
-
- if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
- pathVal = pathVal[key1];
-
- if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
- pathVal = pathVal[key2];
-
- if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
- pathVal = pathVal[key3];
-
- if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
- pathVal = pathVal[key4];
-
- return pathVal;
- }
- : function cspSafePromiseEnabledGetter(scope, locals) {
- var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
- promise;
-
- if (pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key0];
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key1 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key1];
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key2 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key2];
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key3 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key3];
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- if (!key4 || pathVal === null || pathVal === undefined) return pathVal;
-
- pathVal = pathVal[key4];
- if (pathVal && pathVal.then) {
- promiseWarning(fullExp);
- if (!("$$v" in pathVal)) {
- promise = pathVal;
- promise.$$v = undefined;
- promise.then(function(val) { promise.$$v = val; });
- }
- pathVal = pathVal.$$v;
- }
- return pathVal;
- };
-}
-
-function getterFn(path, options, fullExp) {
- // Check whether the cache has this getter already.
- // We can use hasOwnProperty directly on the cache because we ensure,
- // see below, that the cache never stores a path called 'hasOwnProperty'
- if (getterFnCache.hasOwnProperty(path)) {
- return getterFnCache[path];
- }
-
- var pathKeys = path.split('.'),
- pathKeysLength = pathKeys.length,
- fn;
-
- if (options.csp) {
- if (pathKeysLength < 6) {
- fn = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
- options);
- } else {
- fn = function(scope, locals) {
- var i = 0, val;
- do {
- val = cspSafeGetterFn(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
- pathKeys[i++], fullExp, options)(scope, locals);
-
- locals = undefined; // clear after first iteration
- scope = val;
- } while (i < pathKeysLength);
- return val;
- };
- }
- } else {
- var code = 'var l, fn, p;\n';
- forEach(pathKeys, function(key, index) {
- ensureSafeMemberName(key, fullExp);
- code += 'if(s === null || s === undefined) return s;\n' +
- 'l=s;\n' +
- 's='+ (index
- // we simply dereference 's' on any .dot notation
- ? 's'
- // but if we are first then we check locals first, and if so read it first
- : '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
- (options.unwrapPromises
- ? 'if (s && s.then) {\n' +
- ' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
- ' if (!("$$v" in s)) {\n' +
- ' p=s;\n' +
- ' p.$$v = undefined;\n' +
- ' p.then(function(v) {p.$$v=v;});\n' +
- '}\n' +
- ' s=s.$$v\n' +
- '}\n'
- : '');
- });
- code += 'return s;';
-
- /* jshint -W054 */
- var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
- /* jshint +W054 */
- evaledFnGetter.toString = function() { return code; };
- fn = function(scope, locals) {
- return evaledFnGetter(scope, locals, promiseWarning);
- };
- }
-
- // Only cache the value if it's not going to mess up the cache object
- // This is more performant that using Object.prototype.hasOwnProperty.call
- if (path !== 'hasOwnProperty') {
- getterFnCache[path] = fn;
- }
- return fn;
-}
-
-///////////////////////////////////
-
-/**
- * @ngdoc function
- * @name ng.$parse
- * @function
- *
- * @description
- *
- * Converts Angular {@link guide/expression expression} into a function.
- *
- * <pre>
- * var getter = $parse('user.name');
- * var setter = getter.assign;
- * var context = {user:{name:'angular'}};
- * var locals = {user:{name:'local'}};
- *
- * expect(getter(context)).toEqual('angular');
- * setter(context, 'newValue');
- * expect(context.user.name).toEqual('newValue');
- * expect(getter(context, locals)).toEqual('local');
- * </pre>
- *
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- *
- * The returned function also has the following properties:
- * * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
- * literal.
- * * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
- * constant literals.
- * * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
- * set to a function to change its value on the given context.
- *
- */
-
-
-/**
- * @ngdoc object
- * @name ng.$parseProvider
- * @function
- *
- * @description
- * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
- * service.
- */
-function $ParseProvider() {
- var cache = {};
-
- var $parseOptions = {
- csp: false,
- unwrapPromises: false,
- logPromiseWarnings: true
- };
-
-
- /**
- * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
- *
- * @ngdoc method
- * @name ng.$parseProvider#unwrapPromises
- * @methodOf ng.$parseProvider
- * @description
- *
- * **This feature is deprecated, see deprecation notes below for more info**
- *
- * If set to true (default is false), $parse will unwrap promises automatically when a promise is
- * found at any part of the expression. In other words, if set to true, the expression will always
- * result in a non-promise value.
- *
- * While the promise is unresolved, it's treated as undefined, but once resolved and fulfilled,
- * the fulfillment value is used in place of the promise while evaluating the expression.
- *
- * **Deprecation notice**
- *
- * This is a feature that didn't prove to be wildly useful or popular, primarily because of the
- * dichotomy between data access in templates (accessed as raw values) and controller code
- * (accessed as promises).
- *
- * In most code we ended up resolving promises manually in controllers anyway and thus unifying
- * the model access there.
- *
- * Other downsides of automatic promise unwrapping:
- *
- * - when building components it's often desirable to receive the raw promises
- * - adds complexity and slows down expression evaluation
- * - makes expression code pre-generation unattractive due to the amount of code that needs to be
- * generated
- * - makes IDE auto-completion and tool support hard
- *
- * **Warning Logs**
- *
- * If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a
- * promise (to reduce the noise, each expression is logged only once). To disable this logging use
- * `$parseProvider.logPromiseWarnings(false)` api.
- *
- *
- * @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as
- * setter.
- */
- this.unwrapPromises = function(value) {
- if (isDefined(value)) {
- $parseOptions.unwrapPromises = !!value;
- return this;
- } else {
- return $parseOptions.unwrapPromises;
- }
- };
-
-
- /**
- * @deprecated Promise unwrapping via $parse is deprecated and will be removed in the future.
- *
- * @ngdoc method
- * @name ng.$parseProvider#logPromiseWarnings
- * @methodOf ng.$parseProvider
- * @description
- *
- * Controls whether Angular should log a warning on any encounter of a promise in an expression.
- *
- * The default is set to `true`.
- *
- * This setting applies only if `$parseProvider.unwrapPromises` setting is set to true as well.
- *
- * @param {boolean=} value New value.
- * @returns {boolean|self} Returns the current setting when used as getter and self if used as
- * setter.
- */
- this.logPromiseWarnings = function(value) {
- if (isDefined(value)) {
- $parseOptions.logPromiseWarnings = value;
- return this;
- } else {
- return $parseOptions.logPromiseWarnings;
- }
- };
-
-
- this.$get = ['$filter', '$sniffer', '$log', function($filter, $sniffer, $log) {
- $parseOptions.csp = $sniffer.csp;
-
- promiseWarning = function promiseWarningFn(fullExp) {
- if (!$parseOptions.logPromiseWarnings || promiseWarningCache.hasOwnProperty(fullExp)) return;
- promiseWarningCache[fullExp] = true;
- $log.warn('[$parse] Promise found in the expression `' + fullExp + '`. ' +
- 'Automatic unwrapping of promises in Angular expressions is deprecated.');
- };
-
- return function(exp) {
- var parsedExpression;
-
- switch (typeof exp) {
- case 'string':
-
- if (cache.hasOwnProperty(exp)) {
- return cache[exp];
- }
-
- var lexer = new Lexer($parseOptions);
- var parser = new Parser(lexer, $filter, $parseOptions);
- parsedExpression = parser.parse(exp, false);
-
- if (exp !== 'hasOwnProperty') {
- // Only cache the value if it's not going to mess up the cache object
- // This is more performant that using Object.prototype.hasOwnProperty.call
- cache[exp] = parsedExpression;
- }
-
- return parsedExpression;
-
- case 'function':
- return exp;
-
- default:
- return noop;
- }
- };
- }];
-}
-
-/**
- * @ngdoc service
- * @name ng.$q
- * @requires $rootScope
- *
- * @description
- * A promise/deferred implementation inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
- *
- * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
- * interface for interacting with an object that represents the result of an action that is
- * performed asynchronously, and may or may not be finished at any given point in time.
- *
- * From the perspective of dealing with error handling, deferred and promise APIs are to
- * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
- *
- * <pre>
- * // for the purpose of this example let's assume that variables `$q` and `scope` are
- * // available in the current lexical scope (they could have been injected or passed in).
- *
- * function asyncGreet(name) {
- * var deferred = $q.defer();
- *
- * setTimeout(function() {
- * // since this fn executes async in a future turn of the event loop, we need to wrap
- * // our code into an $apply call so that the model changes are properly observed.
- * scope.$apply(function() {
- * deferred.notify('About to greet ' + name + '.');
- *
- * if (okToGreet(name)) {
- * deferred.resolve('Hello, ' + name + '!');
- * } else {
- * deferred.reject('Greeting ' + name + ' is not allowed.');
- * }
- * });
- * }, 1000);
- *
- * return deferred.promise;
- * }
- *
- * var promise = asyncGreet('Robin Hood');
- * promise.then(function(greeting) {
- * alert('Success: ' + greeting);
- * }, function(reason) {
- * alert('Failed: ' + reason);
- * }, function(update) {
- * alert('Got notification: ' + update);
- * });
- * </pre>
- *
- * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
- * comes in the way of guarantees that promise and deferred APIs make, see
- * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
- *
- * Additionally the promise api allows for composition that is very hard to do with the
- * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
- * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
- * section on serial or parallel joining of promises.
- *
- *
- * # The Deferred API
- *
- * A new instance of deferred is constructed by calling `$q.defer()`.
- *
- * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
- * that can be used for signaling the successful or unsuccessful completion, as well as the status
- * of the task.
- *
- * **Methods**
- *
- * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
- * constructed via `$q.reject`, the promise will be rejected instead.
- * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
- * resolving it with a rejection constructed via `$q.reject`.
- * - `notify(value)` - provides updates on the status of the promises execution. This may be called
- * multiple times before the promise is either resolved or rejected.
- *
- * **Properties**
- *
- * - promise – `{Promise}` – promise object associated with this deferred.
- *
- *
- * # The Promise API
- *
- * A new promise instance is created when a deferred instance is created and can be retrieved by
- * calling `deferred.promise`.
- *
- * The purpose of the promise object is to allow for interested parties to get access to the result
- * of the deferred task when it completes.
- *
- * **Methods**
- *
- * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
- * will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
- * as soon as the result is available. The callbacks are called with a single argument: the result
- * or rejection reason. Additionally, the notify callback may be called zero or more times to
- * provide a progress indication, before the promise is resolved or rejected.
- *
- * This method *returns a new promise* which is resolved or rejected via the return value of the
- * `successCallback`, `errorCallback`. It also notifies via the return value of the
- * `notifyCallback` method. The promise can not be resolved or rejected from the notifyCallback
- * method.
- *
- * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
- *
- * - `finally(callback)` – allows you to observe either the fulfillment or rejection of a promise,
- * but to do so without modifying the final value. This is useful to release resources or do some
- * clean-up that needs to be done whether the promise was rejected or resolved. See the [full
- * specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
- * more information.
- *
- * Because `finally` is a reserved word in JavaScript and reserved keywords are not supported as
- * property names by ES3, you'll need to invoke the method like `promise['finally'](callback)` to
- * make your code IE8 compatible.
- *
- * # Chaining promises
- *
- * Because calling the `then` method of a promise returns a new derived promise, it is easily
- * possible to create a chain of promises:
- *
- * <pre>
- * promiseB = promiseA.then(function(result) {
- * return result + 1;
- * });
- *
- * // promiseB will be resolved immediately after promiseA is resolved and its value
- * // will be the result of promiseA incremented by 1
- * </pre>
- *
- * It is possible to create chains of any length and since a promise can be resolved with another
- * promise (which will defer its resolution further), it is possible to pause/defer resolution of
- * the promises at any point in the chain. This makes it possible to implement powerful APIs like
- * $http's response interceptors.
- *
- *
- * # Differences between Kris Kowal's Q and $q
- *
- * There are two main differences:
- *
- * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
- * mechanism in angular, which means faster propagation of resolution or rejection into your
- * models and avoiding unnecessary browser repaints, which would result in flickering UI.
- * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
- * all the important functionality needed for common async tasks.
- *
- * # Testing
- *
- * <pre>
- * it('should simulate promise', inject(function($q, $rootScope) {
- * var deferred = $q.defer();
- * var promise = deferred.promise;
- * var resolvedValue;
- *
- * promise.then(function(value) { resolvedValue = value; });
- * expect(resolvedValue).toBeUndefined();
- *
- * // Simulate resolving of promise
- * deferred.resolve(123);
- * // Note that the 'then' function does not get called synchronously.
- * // This is because we want the promise API to always be async, whether or not
- * // it got called synchronously or asynchronously.
- * expect(resolvedValue).toBeUndefined();
- *
- * // Propagate promise resolution to 'then' functions using $apply().
- * $rootScope.$apply();
- * expect(resolvedValue).toEqual(123);
- * }));
- * </pre>
- */
-function $QProvider() {
-
- this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
- return qFactory(function(callback) {
- $rootScope.$evalAsync(callback);
- }, $exceptionHandler);
- }];
-}
-
-
-/**
- * Constructs a promise manager.
- *
- * @param {function(function)} nextTick Function for executing functions in the next turn.
- * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
- * debugging purposes.
- * @returns {object} Promise manager.
- */
-function qFactory(nextTick, exceptionHandler) {
-
- /**
- * @ngdoc
- * @name ng.$q#defer
- * @methodOf ng.$q
- * @description
- * Creates a `Deferred` object which represents a task which will finish in the future.
- *
- * @returns {Deferred} Returns a new instance of deferred.
- */
- var defer = function() {
- var pending = [],
- value, deferred;
-
- deferred = {
-
- resolve: function(val) {
- if (pending) {
- var callbacks = pending;
- pending = undefined;
- value = ref(val);
-
- if (callbacks.length) {
- nextTick(function() {
- var callback;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- callback = callbacks[i];
- value.then(callback[0], callback[1], callback[2]);
- }
- });
- }
- }
- },
-
-
- reject: function(reason) {
- deferred.resolve(reject(reason));
- },
-
-
- notify: function(progress) {
- if (pending) {
- var callbacks = pending;
-
- if (pending.length) {
- nextTick(function() {
- var callback;
- for (var i = 0, ii = callbacks.length; i < ii; i++) {
- callback = callbacks[i];
- callback[2](progress);
- }
- });
- }
- }
- },
-
-
- promise: {
- then: function(callback, errback, progressback) {
- var result = defer();
-
- var wrappedCallback = function(value) {
- try {
- result.resolve((isFunction(callback) ? callback : defaultCallback)(value));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- };
-
- var wrappedErrback = function(reason) {
- try {
- result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- };
-
- var wrappedProgressback = function(progress) {
- try {
- result.notify((isFunction(progressback) ? progressback : defaultCallback)(progress));
- } catch(e) {
- exceptionHandler(e);
- }
- };
-
- if (pending) {
- pending.push([wrappedCallback, wrappedErrback, wrappedProgressback]);
- } else {
- value.then(wrappedCallback, wrappedErrback, wrappedProgressback);
- }
-
- return result.promise;
- },
-
- "catch": function(callback) {
- return this.then(null, callback);
- },
-
- "finally": function(callback) {
-
- function makePromise(value, resolved) {
- var result = defer();
- if (resolved) {
- result.resolve(value);
- } else {
- result.reject(value);
- }
- return result.promise;
- }
-
- function handleCallback(value, isResolved) {
- var callbackOutput = null;
- try {
- callbackOutput = (callback ||defaultCallback)();
- } catch(e) {
- return makePromise(e, false);
- }
- if (callbackOutput && isFunction(callbackOutput.then)) {
- return callbackOutput.then(function() {
- return makePromise(value, isResolved);
- }, function(error) {
- return makePromise(error, false);
- });
- } else {
- return makePromise(value, isResolved);
- }
- }
-
- return this.then(function(value) {
- return handleCallback(value, true);
- }, function(error) {
- return handleCallback(error, false);
- });
- }
- }
- };
-
- return deferred;
- };
-
-
- var ref = function(value) {
- if (value && isFunction(value.then)) return value;
- return {
- then: function(callback) {
- var result = defer();
- nextTick(function() {
- result.resolve(callback(value));
- });
- return result.promise;
- }
- };
- };
-
-
- /**
- * @ngdoc
- * @name ng.$q#reject
- * @methodOf ng.$q
- * @description
- * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
- * used to forward rejection in a chain of promises. If you are dealing with the last promise in
- * a promise chain, you don't need to worry about it.
- *
- * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
- * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
- * a promise error callback and you want to forward the error to the promise derived from the
- * current promise, you have to "rethrow" the error by returning a rejection constructed via
- * `reject`.
- *
- * <pre>
- * promiseB = promiseA.then(function(result) {
- * // success: do something and resolve promiseB
- * // with the old or a new result
- * return result;
- * }, function(reason) {
- * // error: handle the error if possible and
- * // resolve promiseB with newPromiseOrValue,
- * // otherwise forward the rejection to promiseB
- * if (canHandle(reason)) {
- * // handle the error and recover
- * return newPromiseOrValue;
- * }
- * return $q.reject(reason);
- * });
- * </pre>
- *
- * @param {*} reason Constant, message, exception or an object representing the rejection reason.
- * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
- */
- var reject = function(reason) {
- return {
- then: function(callback, errback) {
- var result = defer();
- nextTick(function() {
- try {
- result.resolve((isFunction(errback) ? errback : defaultErrback)(reason));
- } catch(e) {
- result.reject(e);
- exceptionHandler(e);
- }
- });
- return result.promise;
- }
- };
- };
-
-
- /**
- * @ngdoc
- * @name ng.$q#when
- * @methodOf ng.$q
- * @description
- * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
- * This is useful when you are dealing with an object that might or might not be a promise, or if
- * the promise comes from a source that can't be trusted.
- *
- * @param {*} value Value or a promise
- * @returns {Promise} Returns a promise of the passed value or promise
- */
- var when = function(value, callback, errback, progressback) {
- var result = defer(),
- done;
-
- var wrappedCallback = function(value) {
- try {
- return (isFunction(callback) ? callback : defaultCallback)(value);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- var wrappedErrback = function(reason) {
- try {
- return (isFunction(errback) ? errback : defaultErrback)(reason);
- } catch (e) {
- exceptionHandler(e);
- return reject(e);
- }
- };
-
- var wrappedProgressback = function(progress) {
- try {
- return (isFunction(progressback) ? progressback : defaultCallback)(progress);
- } catch (e) {
- exceptionHandler(e);
- }
- };
-
- nextTick(function() {
- ref(value).then(function(value) {
- if (done) return;
- done = true;
- result.resolve(ref(value).then(wrappedCallback, wrappedErrback, wrappedProgressback));
- }, function(reason) {
- if (done) return;
- done = true;
- result.resolve(wrappedErrback(reason));
- }, function(progress) {
- if (done) return;
- result.notify(wrappedProgressback(progress));
- });
- });
-
- return result.promise;
- };
-
-
- function defaultCallback(value) {
- return value;
- }
-
-
- function defaultErrback(reason) {
- return reject(reason);
- }
-
-
- /**
- * @ngdoc
- * @name ng.$q#all
- * @methodOf ng.$q
- * @description
- * Combines multiple promises into a single promise that is resolved when all of the input
- * promises are resolved.
- *
- * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
- * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
- * each value corresponding to the promise at the same index/key in the `promises` array/hash.
- * If any of the promises is resolved with a rejection, this resulting promise will be rejected
- * with the same rejection value.
- */
- function all(promises) {
- var deferred = defer(),
- counter = 0,
- results = isArray(promises) ? [] : {};
-
- forEach(promises, function(promise, key) {
- counter++;
- ref(promise).then(function(value) {
- if (results.hasOwnProperty(key)) return;
- results[key] = value;
- if (!(--counter)) deferred.resolve(results);
- }, function(reason) {
- if (results.hasOwnProperty(key)) return;
- deferred.reject(reason);
- });
- });
-
- if (counter === 0) {
- deferred.resolve(results);
- }
-
- return deferred.promise;
- }
-
- return {
- defer: defer,
- reject: reject,
- when: when,
- all: all
- };
-}
-
-/**
- * DESIGN NOTES
- *
- * The design decisions behind the scope are heavily favored for speed and memory consumption.
- *
- * The typical use of scope is to watch the expressions, which most of the time return the same
- * value as last time so we optimize the operation.
- *
- * Closures construction is expensive in terms of speed as well as memory:
- * - No closures, instead use prototypical inheritance for API
- * - Internal state needs to be stored on scope directly, which means that private state is
- * exposed as $$____ properties
- *
- * Loop operations are optimized by using while(count--) { ... }
- * - this means that in order to keep the same order of execution as addition we have to add
- * items to the array at the beginning (shift) instead of at the end (push)
- *
- * Child scopes are created and removed often
- * - Using an array would be slow since inserts in middle are expensive so we use linked list
- *
- * There are few watches then a lot of observers. This is why you don't want the observer to be
- * implemented in the same way as watch. Watch requires return of initialization function which
- * are expensive to construct.
- */
-
-
-/**
- * @ngdoc object
- * @name ng.$rootScopeProvider
- * @description
- *
- * Provider for the $rootScope service.
- */
-
-/**
- * @ngdoc function
- * @name ng.$rootScopeProvider#digestTtl
- * @methodOf ng.$rootScopeProvider
- * @description
- *
- * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
- * assuming that the model is unstable.
- *
- * The current default is 10 iterations.
- *
- * In complex applications it's possible that the dependencies between `$watch`s will result in
- * several digest iterations. However if an application needs more than the default 10 digest
- * iterations for its model to stabilize then you should investigate what is causing the model to
- * continuously change during the digest.
- *
- * Increasing the TTL could have performance implications, so you should not change it without
- * proper justification.
- *
- * @param {number} limit The number of digest iterations.
- */
-
-
-/**
- * @ngdoc object
- * @name ng.$rootScope
- * @description
- *
- * Every application has a single root {@link ng.$rootScope.Scope scope}.
- * All other scopes are descendant scopes of the root scope. Scopes provide separation
- * between the model and the view, via a mechanism for watching the model for changes.
- * They also provide an event emission/broadcast and subscription facility. See the
- * {@link guide/scope developer guide on scopes}.
- */
-function $RootScopeProvider(){
- var TTL = 10;
- var $rootScopeMinErr = minErr('$rootScope');
- var lastDirtyWatch = null;
-
- this.digestTtl = function(value) {
- if (arguments.length) {
- TTL = value;
- }
- return TTL;
- };
-
- this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
- function( $injector, $exceptionHandler, $parse, $browser) {
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope
- *
- * @description
- * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
- * {@link AUTO.$injector $injector}. Child scopes are created using the
- * {@link ng.$rootScope.Scope#methods_$new $new()} method. (Most scopes are created automatically when
- * compiled HTML template is executed.)
- *
- * Here is a simple scope snippet to show how you can interact with the scope.
- * <pre>
- * <file src="./test/ng/rootScopeSpec.js" tag="docs1" />
- * </pre>
- *
- * # Inheritance
- * A scope can inherit from a parent scope, as in this example:
- * <pre>
- var parent = $rootScope;
- var child = parent.$new();
-
- parent.salutation = "Hello";
- child.name = "World";
- expect(child.salutation).toEqual('Hello');
-
- child.salutation = "Welcome";
- expect(child.salutation).toEqual('Welcome');
- expect(parent.salutation).toEqual('Hello');
- * </pre>
- *
- *
- * @param {Object.<string, function()>=} providers Map of service factory which need to be
- * provided for the current scope. Defaults to {@link ng}.
- * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
- * append/override services provided by `providers`. This is handy
- * when unit-testing and having the need to override a default
- * service.
- * @returns {Object} Newly created scope.
- *
- */
- function Scope() {
- this.$id = nextUid();
- this.$$phase = this.$parent = this.$$watchers =
- this.$$nextSibling = this.$$prevSibling =
- this.$$childHead = this.$$childTail = null;
- this['this'] = this.$root = this;
- this.$$destroyed = false;
- this.$$asyncQueue = [];
- this.$$postDigestQueue = [];
- this.$$listeners = {};
- this.$$isolateBindings = {};
- }
-
- /**
- * @ngdoc property
- * @name ng.$rootScope.Scope#$id
- * @propertyOf ng.$rootScope.Scope
- * @returns {number} Unique scope ID (monotonically increasing alphanumeric sequence) useful for
- * debugging.
- */
-
-
- Scope.prototype = {
- constructor: Scope,
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$new
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Creates a new child {@link ng.$rootScope.Scope scope}.
- *
- * The parent scope will propagate the {@link ng.$rootScope.Scope#methods_$digest $digest()} and
- * {@link ng.$rootScope.Scope#methods_$digest $digest()} events. The scope can be removed from the
- * scope hierarchy using {@link ng.$rootScope.Scope#methods_$destroy $destroy()}.
- *
- * {@link ng.$rootScope.Scope#methods_$destroy $destroy()} must be called on a scope when it is
- * desired for the scope and its child scopes to be permanently detached from the parent and
- * thus stop participating in model change detection and listener notification by invoking.
- *
- * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
- * parent scope. The scope is isolated, as it can not see parent scope properties.
- * When creating widgets, it is useful for the widget to not accidentally read parent
- * state.
- *
- * @returns {Object} The newly created child scope.
- *
- */
- $new: function(isolate) {
- var ChildScope,
- child;
-
- if (isolate) {
- child = new Scope();
- child.$root = this.$root;
- // ensure that there is just one async queue per $rootScope and its children
- child.$$asyncQueue = this.$$asyncQueue;
- child.$$postDigestQueue = this.$$postDigestQueue;
- } 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.
- ChildScope.prototype = this;
- child = new ChildScope();
- child.$id = nextUid();
- }
- child['this'] = child;
- child.$$listeners = {};
- child.$parent = this;
- child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
- child.$$prevSibling = this.$$childTail;
- if (this.$$childHead) {
- this.$$childTail.$$nextSibling = child;
- this.$$childTail = child;
- } else {
- this.$$childHead = this.$$childTail = child;
- }
- return child;
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$watch
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
- *
- * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#methods_$digest
- * $digest()} and should return the value that will be watched. (Since
- * {@link ng.$rootScope.Scope#methods_$digest $digest()} reruns when it detects changes the
- * `watchExpression` can execute multiple times per
- * {@link ng.$rootScope.Scope#methods_$digest $digest()} and should be idempotent.)
- * - The `listener` is called only when the value from the current `watchExpression` and the
- * previous call to `watchExpression` are not equal (with the exception of the initial run,
- * see below). The inequality is determined according to
- * {@link angular.equals} function. To save the value of the object for later comparison,
- * the {@link angular.copy} function is used. It also means that watching complex options
- * will have adverse memory and performance implications.
- * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
- * This is achieved by rerunning the watchers until no changes are detected. The rerun
- * iteration limit is 10 to prevent an infinite loop deadlock.
- *
- *
- * If you want to be notified whenever {@link ng.$rootScope.Scope#methods_$digest $digest} is called,
- * you can register a `watchExpression` function with no `listener`. (Since `watchExpression`
- * can execute multiple times per {@link ng.$rootScope.Scope#methods_$digest $digest} cycle when a
- * change is detected, be prepared for multiple calls to your listener.)
- *
- * After a watcher is registered with the scope, the `listener` fn is called asynchronously
- * (via {@link ng.$rootScope.Scope#methods_$evalAsync $evalAsync}) to initialize the
- * watcher. In rare cases, this is undesirable because the listener is called when the result
- * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
- * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
- * listener was called due to initialization.
- *
- * The example below contains an illustration of using a function as your $watch listener
- *
- *
- * # Example
- * <pre>
- // let's assume that scope was dependency injected as the $rootScope
- var scope = $rootScope;
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(newValue, oldValue) {
- scope.counter = scope.counter + 1;
- });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
-
-
-
- // Using a listener function
- var food;
- scope.foodCounter = 0;
- expect(scope.foodCounter).toEqual(0);
- scope.$watch(
- // This is the listener function
- function() { return food; },
- // This is the change handler
- function(newValue, oldValue) {
- if ( newValue !== oldValue ) {
- // Only increment the counter if the value changed
- scope.foodCounter = scope.foodCounter + 1;
- }
- }
- );
- // 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
- scope.$digest();
- expect(scope.foodCounter).toEqual(0);
-
- // Update food and run digest. Now the counter will increment
- food = 'cheeseburger';
- scope.$digest();
- expect(scope.foodCounter).toEqual(1);
-
- * </pre>
- *
- *
- *
- * @param {(function()|string)} watchExpression Expression that is evaluated on each
- * {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. A change in the return value triggers
- * a call to the `listener`.
- *
- * - `string`: Evaluated as {@link guide/expression expression}
- * - `function(scope)`: called with current `scope` as a parameter.
- * @param {(function()|string)=} listener Callback called whenever the return value of
- * the `watchExpression` changes.
- *
- * - `string`: Evaluated as {@link guide/expression expression}
- * - `function(newValue, oldValue, scope)`: called with current and previous values as
- * parameters.
- *
- * @param {boolean=} objectEquality Compare object for equality rather than for reference.
- * @returns {function()} Returns a deregistration function for this listener.
- */
- $watch: function(watchExp, listener, objectEquality) {
- var scope = this,
- get = compileToFn(watchExp, 'watch'),
- array = scope.$$watchers,
- watcher = {
- fn: listener,
- last: initWatchVal,
- get: get,
- exp: watchExp,
- eq: !!objectEquality
- };
-
- lastDirtyWatch = null;
-
- // in the case user pass string, we need to compile it, do we really need this ?
- if (!isFunction(listener)) {
- var listenFn = compileToFn(listener || noop, 'listener');
- watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
- }
-
- if (typeof watchExp == 'string' && get.constant) {
- var originalFn = watcher.fn;
- watcher.fn = function(newVal, oldVal, scope) {
- originalFn.call(this, newVal, oldVal, scope);
- arrayRemove(array, watcher);
- };
- }
-
- if (!array) {
- array = scope.$$watchers = [];
- }
- // we use unshift since we use a while loop in $digest for speed.
- // the while loop reads in reverse order.
- array.unshift(watcher);
-
- return function() {
- arrayRemove(array, watcher);
- };
- },
-
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$watchCollection
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Shallow watches the properties of an object and fires whenever any of the properties change
- * (for arrays, this implies watching the array items; for object maps, this implies watching
- * the properties). If a change is detected, the `listener` callback is fired.
- *
- * - The `obj` collection is observed via standard $watch operation and is examined on every
- * call to $digest() to see if any items have been added, removed, or moved.
- * - The `listener` is called whenever anything within the `obj` has changed. Examples include
- * adding, removing, and moving items belonging to an object or array.
- *
- *
- * # Example
- * <pre>
- $scope.names = ['igor', 'matias', 'misko', 'james'];
- $scope.dataCount = 4;
-
- $scope.$watchCollection('names', function(newNames, oldNames) {
- $scope.dataCount = newNames.length;
- });
-
- expect($scope.dataCount).toEqual(4);
- $scope.$digest();
-
- //still at 4 ... no changes
- expect($scope.dataCount).toEqual(4);
-
- $scope.names.pop();
- $scope.$digest();
-
- //now there's been a change
- expect($scope.dataCount).toEqual(3);
- * </pre>
- *
- *
- * @param {string|Function(scope)} obj Evaluated as {@link guide/expression expression}. The
- * expression value should evaluate to an object or an array which is observed on each
- * {@link ng.$rootScope.Scope#methods_$digest $digest} cycle. Any shallow change within the
- * collection will trigger a call to the `listener`.
- *
- * @param {function(newCollection, oldCollection, scope)} listener a callback function that is
- * fired with both the `newCollection` and `oldCollection` as parameters.
- * The `newCollection` object is the newly modified data obtained from the `obj` expression
- * and the `oldCollection` object is a copy of the former collection data.
- * The `scope` refers to the current scope.
- *
- * @returns {function()} Returns a de-registration function for this listener. When the
- * de-registration function is executed, the internal watch operation is terminated.
- */
- $watchCollection: function(obj, listener) {
- var self = this;
- var oldValue;
- var newValue;
- var changeDetected = 0;
- var objGetter = $parse(obj);
- var internalArray = [];
- var internalObject = {};
- var oldLength = 0;
-
- function $watchCollectionWatch() {
- newValue = objGetter(self);
- var newLength, key;
-
- if (!isObject(newValue)) {
- if (oldValue !== newValue) {
- oldValue = newValue;
- changeDetected++;
- }
- } else if (isArrayLike(newValue)) {
- if (oldValue !== internalArray) {
- // we are transitioning from something which was not an array into array.
- oldValue = internalArray;
- oldLength = oldValue.length = 0;
- changeDetected++;
- }
-
- newLength = newValue.length;
-
- if (oldLength !== newLength) {
- // if lengths do not match we need to trigger change notification
- changeDetected++;
- oldValue.length = oldLength = newLength;
- }
- // copy the items to oldValue and look for changes.
- for (var i = 0; i < newLength; i++) {
- if (oldValue[i] !== newValue[i]) {
- changeDetected++;
- oldValue[i] = newValue[i];
- }
- }
- } else {
- if (oldValue !== internalObject) {
- // we are transitioning from something which was not an object into object.
- oldValue = internalObject = {};
- oldLength = 0;
- changeDetected++;
- }
- // copy the items to oldValue and look for changes.
- newLength = 0;
- for (key in newValue) {
- if (newValue.hasOwnProperty(key)) {
- newLength++;
- if (oldValue.hasOwnProperty(key)) {
- if (oldValue[key] !== newValue[key]) {
- changeDetected++;
- oldValue[key] = newValue[key];
- }
- } else {
- oldLength++;
- oldValue[key] = newValue[key];
- changeDetected++;
- }
- }
- }
- if (oldLength > newLength) {
- // we used to have more keys, need to find them and destroy them.
- changeDetected++;
- for(key in oldValue) {
- if (oldValue.hasOwnProperty(key) && !newValue.hasOwnProperty(key)) {
- oldLength--;
- delete oldValue[key];
- }
- }
- }
- }
- return changeDetected;
- }
-
- function $watchCollectionAction() {
- listener(newValue, oldValue, self);
- }
-
- return this.$watch($watchCollectionWatch, $watchCollectionAction);
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$digest
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Processes all of the {@link ng.$rootScope.Scope#methods_$watch watchers} of the current scope and
- * its children. Because a {@link ng.$rootScope.Scope#methods_$watch watcher}'s listener can change
- * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#methods_$watch watchers}
- * until no more listeners are firing. This means that it is possible to get into an infinite
- * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
- * iterations exceeds 10.
- *
- * Usually, you don't call `$digest()` directly in
- * {@link ng.directive:ngController controllers} or in
- * {@link ng.$compileProvider#methods_directive directives}.
- * Instead, you should call {@link ng.$rootScope.Scope#methods_$apply $apply()} (typically from within
- * a {@link ng.$compileProvider#methods_directive directives}), which will force a `$digest()`.
- *
- * If you want to be notified whenever `$digest()` is called,
- * you can register a `watchExpression` function with
- * {@link ng.$rootScope.Scope#methods_$watch $watch()} with no `listener`.
- *
- * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
- *
- * # Example
- * <pre>
- var scope = ...;
- scope.name = 'misko';
- scope.counter = 0;
-
- expect(scope.counter).toEqual(0);
- scope.$watch('name', function(newValue, oldValue) {
- scope.counter = scope.counter + 1;
- });
- expect(scope.counter).toEqual(0);
-
- scope.$digest();
- // no variable change
- expect(scope.counter).toEqual(0);
-
- scope.name = 'adam';
- scope.$digest();
- expect(scope.counter).toEqual(1);
- * </pre>
- *
- */
- $digest: function() {
- var watch, value, last,
- watchers,
- asyncQueue = this.$$asyncQueue,
- postDigestQueue = this.$$postDigestQueue,
- length,
- dirty, ttl = TTL,
- next, current, target = this,
- watchLog = [],
- logIdx, logMsg, asyncTask;
-
- beginPhase('$digest');
-
- lastDirtyWatch = null;
-
- do { // "while dirty" loop
- dirty = false;
- current = target;
-
- while(asyncQueue.length) {
- try {
- asyncTask = asyncQueue.shift();
- asyncTask.scope.$eval(asyncTask.expression);
- } catch (e) {
- clearPhase();
- $exceptionHandler(e);
- }
- lastDirtyWatch = null;
- }
-
- traverseScopesLoop:
- do { // "traverse the scopes" loop
- if ((watchers = current.$$watchers)) {
- // process our watches
- length = watchers.length;
- while (length--) {
- try {
- watch = watchers[length];
- // Most common watches are on primitives, in which case we can short
- // circuit it with === operator, only when === fails do we use .equals
- if (watch) {
- if ((value = watch.get(current)) !== (last = watch.last) &&
- !(watch.eq
- ? equals(value, last)
- : (typeof value == 'number' && typeof last == 'number'
- && isNaN(value) && isNaN(last)))) {
- dirty = true;
- lastDirtyWatch = watch;
- watch.last = watch.eq ? copy(value) : value;
- watch.fn(value, ((last === initWatchVal) ? value : last), current);
- if (ttl < 5) {
- logIdx = 4 - ttl;
- if (!watchLog[logIdx]) watchLog[logIdx] = [];
- logMsg = (isFunction(watch.exp))
- ? 'fn: ' + (watch.exp.name || watch.exp.toString())
- : watch.exp;
- logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
- watchLog[logIdx].push(logMsg);
- }
- } else if (watch === lastDirtyWatch) {
- // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
- // have already been tested.
- dirty = false;
- break traverseScopesLoop;
- }
- }
- } catch (e) {
- clearPhase();
- $exceptionHandler(e);
- }
- }
- }
-
- // Insanity Warning: scope depth-first traversal
- // yes, this code is a bit crazy, but it works and we have tests to prove it!
- // this piece should be kept in sync with the traversal in $broadcast
- if (!(next = (current.$$childHead ||
- (current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
- current = current.$parent;
- }
- }
- } while ((current = next));
-
- // `break traverseScopesLoop;` takes us to here
-
- if(dirty && !(ttl--)) {
- clearPhase();
- throw $rootScopeMinErr('infdig',
- '{0} $digest() iterations reached. Aborting!\n' +
- 'Watchers fired in the last 5 iterations: {1}',
- TTL, toJson(watchLog));
- }
-
- } while (dirty || asyncQueue.length);
-
- clearPhase();
-
- while(postDigestQueue.length) {
- try {
- postDigestQueue.shift()();
- } catch (e) {
- $exceptionHandler(e);
- }
- }
- },
-
-
- /**
- * @ngdoc event
- * @name ng.$rootScope.Scope#$destroy
- * @eventOf ng.$rootScope.Scope
- * @eventType broadcast on scope being destroyed
- *
- * @description
- * Broadcasted when a scope and its children are being destroyed.
- *
- * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
- * clean up DOM bindings before an element is removed from the DOM.
- */
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$destroy
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Removes the current scope (and all of its children) from the parent scope. Removal implies
- * that calls to {@link ng.$rootScope.Scope#methods_$digest $digest()} will no longer
- * propagate to the current scope and its children. Removal also implies that the current
- * scope is eligible for garbage collection.
- *
- * The `$destroy()` is usually used by directives such as
- * {@link ng.directive:ngRepeat ngRepeat} for managing the
- * unrolling of the loop.
- *
- * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
- * Application code can register a `$destroy` event handler that will give it a chance to
- * perform any necessary cleanup.
- *
- * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
- * clean up DOM bindings before an element is removed from the DOM.
- */
- $destroy: function() {
- // we can't destroy the root scope or a scope that has been already destroyed
- if (this.$$destroyed) return;
- var parent = this.$parent;
-
- this.$broadcast('$destroy');
- this.$$destroyed = true;
- if (this === $rootScope) return;
-
- if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
- if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
- if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
- if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
-
- // This is bogus code that works around Chrome's GC leak
- // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
- this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead =
- this.$$childTail = null;
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$eval
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Executes the `expression` on the current scope and returns the result. Any exceptions in
- * the expression are propagated (uncaught). This is useful when evaluating Angular
- * expressions.
- *
- * # Example
- * <pre>
- var scope = ng.$rootScope.Scope();
- scope.a = 1;
- scope.b = 2;
-
- expect(scope.$eval('a+b')).toEqual(3);
- expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
- * </pre>
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- * @param {(object)=} locals Local variables object, useful for overriding values in scope.
- * @returns {*} The result of evaluating the expression.
- */
- $eval: function(expr, locals) {
- return $parse(expr)(this, locals);
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$evalAsync
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Executes the expression on the current scope at a later point in time.
- *
- * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
- * that:
- *
- * - it will execute after the function that scheduled the evaluation (preferably before DOM
- * rendering).
- * - at least one {@link ng.$rootScope.Scope#methods_$digest $digest cycle} will be performed after
- * `expression` execution.
- *
- * Any exceptions from the execution of the expression are forwarded to the
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
- * will be scheduled. However, it is encouraged to always call code that changes the model
- * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
- *
- * @param {(string|function())=} expression An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with the current `scope` parameter.
- *
- */
- $evalAsync: function(expr) {
- // if we are outside of an $digest loop and this is the first time we are scheduling async
- // task also schedule async auto-flush
- if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
- $browser.defer(function() {
- if ($rootScope.$$asyncQueue.length) {
- $rootScope.$digest();
- }
- });
- }
-
- this.$$asyncQueue.push({scope: this, expression: expr});
- },
-
- $$postDigest : function(fn) {
- this.$$postDigestQueue.push(fn);
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$apply
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * `$apply()` is used to execute an expression in angular from outside of the angular
- * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
- * Because we are calling into the angular framework we need to perform proper scope life
- * cycle of {@link ng.$exceptionHandler exception handling},
- * {@link ng.$rootScope.Scope#methods_$digest executing watches}.
- *
- * ## Life cycle
- *
- * # Pseudo-Code of `$apply()`
- * <pre>
- function $apply(expr) {
- try {
- return $eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- $root.$digest();
- }
- }
- * </pre>
- *
- *
- * Scope's `$apply()` method transitions through the following stages:
- *
- * 1. The {@link guide/expression expression} is executed using the
- * {@link ng.$rootScope.Scope#methods_$eval $eval()} method.
- * 2. Any exceptions from the execution of the expression are forwarded to the
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- * 3. The {@link ng.$rootScope.Scope#methods_$watch watch} listeners are fired immediately after the
- * expression was executed using the {@link ng.$rootScope.Scope#methods_$digest $digest()} method.
- *
- *
- * @param {(string|function())=} exp An angular expression to be executed.
- *
- * - `string`: execute using the rules as defined in {@link guide/expression expression}.
- * - `function(scope)`: execute the function with current `scope` parameter.
- *
- * @returns {*} The result of evaluating the expression.
- */
- $apply: function(expr) {
- try {
- beginPhase('$apply');
- return this.$eval(expr);
- } catch (e) {
- $exceptionHandler(e);
- } finally {
- clearPhase();
- try {
- $rootScope.$digest();
- } catch (e) {
- $exceptionHandler(e);
- throw e;
- }
- }
- },
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$on
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Listens on events of a given type. See {@link ng.$rootScope.Scope#methods_$emit $emit} for
- * discussion of event life cycle.
- *
- * The event listener function format is: `function(event, args...)`. The `event` object
- * passed into the listener has the following attributes:
- *
- * - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
- * `$broadcast`-ed.
- * - `currentScope` - `{Scope}`: the current scope which is handling the event.
- * - `name` - `{string}`: name of the event.
- * - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
- * further event propagation (available only for events that were `$emit`-ed).
- * - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
- * to true.
- * - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
- *
- * @param {string} name Event name to listen on.
- * @param {function(event, args...)} listener Function to call when the event is emitted.
- * @returns {function()} Returns a deregistration function for this listener.
- */
- $on: function(name, listener) {
- var namedListeners = this.$$listeners[name];
- if (!namedListeners) {
- this.$$listeners[name] = namedListeners = [];
- }
- namedListeners.push(listener);
-
- return function() {
- namedListeners[indexOf(namedListeners, listener)] = null;
- };
- },
-
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$emit
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Dispatches an event `name` upwards through the scope hierarchy notifying the
- * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
- *
- * The event life cycle starts at the scope on which `$emit` was called. All
- * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
- * notified. Afterwards, the event traverses upwards toward the root scope and calls all
- * registered listeners along the way. The event will stop propagating if one of the listeners
- * cancels it.
- *
- * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
- * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to emit.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- * @return {Object} Event object (see {@link ng.$rootScope.Scope#methods_$on}).
- */
- $emit: function(name, args) {
- var empty = [],
- namedListeners,
- scope = this,
- stopPropagation = false,
- event = {
- name: name,
- targetScope: scope,
- stopPropagation: function() {stopPropagation = true;},
- preventDefault: function() {
- event.defaultPrevented = true;
- },
- defaultPrevented: false
- },
- listenerArgs = concat([event], arguments, 1),
- i, length;
-
- do {
- namedListeners = scope.$$listeners[name] || empty;
- event.currentScope = scope;
- for (i=0, length=namedListeners.length; i<length; i++) {
-
- // if listeners were deregistered, defragment the array
- if (!namedListeners[i]) {
- namedListeners.splice(i, 1);
- i--;
- length--;
- continue;
- }
- try {
- //allow all listeners attached to the current scope to run
- namedListeners[i].apply(null, listenerArgs);
- } catch (e) {
- $exceptionHandler(e);
- }
- }
- //if any listener on the current scope stops propagation, prevent bubbling
- if (stopPropagation) return event;
- //traverse upwards
- scope = scope.$parent;
- } while (scope);
-
- return event;
- },
-
-
- /**
- * @ngdoc function
- * @name ng.$rootScope.Scope#$broadcast
- * @methodOf ng.$rootScope.Scope
- * @function
- *
- * @description
- * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
- * registered {@link ng.$rootScope.Scope#methods_$on} listeners.
- *
- * The event life cycle starts at the scope on which `$broadcast` was called. All
- * {@link ng.$rootScope.Scope#methods_$on listeners} listening for `name` event on this scope get
- * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
- * scope and calls all registered listeners along the way. The event cannot be canceled.
- *
- * Any exception emitted from the {@link ng.$rootScope.Scope#methods_$on listeners} will be passed
- * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * @param {string} name Event name to broadcast.
- * @param {...*} args Optional set of arguments which will be passed onto the event listeners.
- * @return {Object} Event object, see {@link ng.$rootScope.Scope#methods_$on}
- */
- $broadcast: function(name, args) {
- var target = this,
- current = target,
- next = target,
- event = {
- name: name,
- targetScope: target,
- preventDefault: function() {
- event.defaultPrevented = true;
- },
- defaultPrevented: false
- },
- listenerArgs = concat([event], arguments, 1),
- listeners, i, length;
-
- //down while you can, then up and next sibling or up and next sibling until back at root
- do {
- current = next;
- event.currentScope = current;
- listeners = current.$$listeners[name] || [];
- for (i=0, length = listeners.length; i<length; i++) {
- // if listeners were deregistered, defragment the array
- if (!listeners[i]) {
- listeners.splice(i, 1);
- i--;
- length--;
- continue;
- }
-
- try {
- listeners[i].apply(null, listenerArgs);
- } catch(e) {
- $exceptionHandler(e);
- }
- }
-
- // Insanity Warning: scope depth-first traversal
- // yes, this code is a bit crazy, but it works and we have tests to prove it!
- // this piece should be kept in sync with the traversal in $digest
- if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
- while(current !== target && !(next = current.$$nextSibling)) {
- current = current.$parent;
- }
- }
- } while ((current = next));
-
- return event;
- }
- };
-
- var $rootScope = new Scope();
-
- return $rootScope;
-
-
- function beginPhase(phase) {
- if ($rootScope.$$phase) {
- throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
- }
-
- $rootScope.$$phase = phase;
- }
-
- function clearPhase() {
- $rootScope.$$phase = null;
- }
-
- function compileToFn(exp, name) {
- var fn = $parse(exp);
- assertArgFn(fn, name);
- return fn;
- }
-
- /**
- * function used as an initial value for watchers.
- * because it's unique we can easily tell it apart from other values
- */
- function initWatchVal() {}
- }];
-}
-
-/**
- * @description
- * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
- */
-function $$SanitizeUriProvider() {
- var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
- imgSrcSanitizationWhitelist = /^\s*(https?|ftp|file):|data:image\//;
-
- /**
- * @description
- * Retrieves or overrides the default regular expression that is used for whitelisting of safe
- * urls during a[href] sanitization.
- *
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
- *
- * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
- * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
- * regular expression. If a match is found, the original url is written into the dom. Otherwise,
- * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
- *
- * @param {RegExp=} regexp New regexp to whitelist urls with.
- * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
- * chaining otherwise.
- */
- this.aHrefSanitizationWhitelist = function(regexp) {
- if (isDefined(regexp)) {
- aHrefSanitizationWhitelist = regexp;
- return this;
- }
- return aHrefSanitizationWhitelist;
- };
-
-
- /**
- * @description
- * Retrieves or overrides the default regular expression that is used for whitelisting of safe
- * urls during img[src] sanitization.
- *
- * The sanitization is a security measure aimed at prevent XSS attacks via html links.
- *
- * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
- * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
- * regular expression. If a match is found, the original url is written into the dom. Otherwise,
- * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
- *
- * @param {RegExp=} regexp New regexp to whitelist urls with.
- * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
- * chaining otherwise.
- */
- this.imgSrcSanitizationWhitelist = function(regexp) {
- if (isDefined(regexp)) {
- imgSrcSanitizationWhitelist = regexp;
- return this;
- }
- return imgSrcSanitizationWhitelist;
- };
-
- this.$get = function() {
- return function sanitizeUri(uri, isImage) {
- var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
- var normalizedVal;
- // NOTE: urlResolve() doesn't support IE < 8 so we don't sanitize for that case.
- if (!msie || msie >= 8 ) {
- normalizedVal = urlResolve(uri).href;
- if (normalizedVal !== '' && !normalizedVal.match(regex)) {
- return 'unsafe:'+normalizedVal;
- }
- }
- return uri;
- };
- };
-}
-
-var $sceMinErr = minErr('$sce');
-
-var SCE_CONTEXTS = {
- HTML: 'html',
- CSS: 'css',
- URL: 'url',
- // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
- // url. (e.g. ng-include, script src, templateUrl)
- RESOURCE_URL: 'resourceUrl',
- JS: 'js'
-};
-
-// Helper functions follow.
-
-// Copied from:
-// http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962
-// Prereq: s is a string.
-function escapeForRegexp(s) {
- return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
- replace(/\x08/g, '\\x08');
-}
-
-
-function adjustMatcher(matcher) {
- if (matcher === 'self') {
- return matcher;
- } else if (isString(matcher)) {
- // Strings match exactly except for 2 wildcards - '*' and '**'.
- // '*' matches any character except those from the set ':/.?&'.
- // '**' matches any character (like .* in a RegExp).
- // More than 2 *'s raises an error as it's ill defined.
- if (matcher.indexOf('***') > -1) {
- throw $sceMinErr('iwcard',
- 'Illegal sequence *** in string matcher. String: {0}', matcher);
- }
- matcher = escapeForRegexp(matcher).
- replace('\\*\\*', '.*').
- replace('\\*', '[^:/.?&;]*');
- return new RegExp('^' + matcher + '$');
- } else if (isRegExp(matcher)) {
- // The only other type of matcher allowed is a Regexp.
- // Match entire URL / disallow partial matches.
- // Flags are reset (i.e. no global, ignoreCase or multiline)
- return new RegExp('^' + matcher.source + '$');
- } else {
- throw $sceMinErr('imatcher',
- 'Matchers may only be "self", string patterns or RegExp objects');
- }
-}
-
-
-function adjustMatchers(matchers) {
- var adjustedMatchers = [];
- if (isDefined(matchers)) {
- forEach(matchers, function(matcher) {
- adjustedMatchers.push(adjustMatcher(matcher));
- });
- }
- return adjustedMatchers;
-}
-
-
-/**
- * @ngdoc service
- * @name ng.$sceDelegate
- * @function
- *
- * @description
- *
- * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
- * Contextual Escaping (SCE)} services to AngularJS.
- *
- * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
- * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS. This is
- * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
- * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
- * work because `$sce` delegates to `$sceDelegate` for these operations.
- *
- * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
- *
- * The default instance of `$sceDelegate` should work out of the box with little pain. While you
- * can override it completely to change the behavior of `$sce`, the common case would
- * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
- * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
- * templates. Refer {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist
- * $sceDelegateProvider.resourceUrlWhitelist} and {@link
- * ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
- */
-
-/**
- * @ngdoc object
- * @name ng.$sceDelegateProvider
- * @description
- *
- * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
- * $sceDelegate} service. This allows one to get/set the whitelists and blacklists used to ensure
- * that the URLs used for sourcing Angular templates are safe. Refer {@link
- * ng.$sceDelegateProvider#methods_resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
- * {@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
- *
- * For the general details about this service in Angular, read the main page for {@link ng.$sce
- * Strict Contextual Escaping (SCE)}.
- *
- * **Example**: Consider the following case. <a name="example"></a>
- *
- * - your app is hosted at url `http://myapp.example.com/`
- * - but some of your templates are hosted on other domains you control such as
- * `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc.
- * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
- *
- * Here is what a secure configuration for this scenario might look like:
- *
- * <pre class="prettyprint">
- * angular.module('myApp', []).config(function($sceDelegateProvider) {
- * $sceDelegateProvider.resourceUrlWhitelist([
- * // Allow same origin resource loads.
- * 'self',
- * // Allow loading from our assets domain. Notice the difference between * and **.
- * 'http://srv*.assets.example.com/**']);
- *
- * // The blacklist overrides the whitelist so the open redirect here is blocked.
- * $sceDelegateProvider.resourceUrlBlacklist([
- * 'http://myapp.example.com/clickThru**']);
- * });
- * </pre>
- */
-
-function $SceDelegateProvider() {
- this.SCE_CONTEXTS = SCE_CONTEXTS;
-
- // Resource URLs can also be trusted by policy.
- var resourceUrlWhitelist = ['self'],
- resourceUrlBlacklist = [];
-
- /**
- * @ngdoc function
- * @name ng.sceDelegateProvider#resourceUrlWhitelist
- * @methodOf ng.$sceDelegateProvider
- * @function
- *
- * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
- * provided. This must be an array or null. A snapshot of this array is used so further
- * changes to the array are ignored.
- *
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
- * allowed in this array.
- *
- * Note: **an empty whitelist array will block all URLs**!
- *
- * @return {Array} the currently set whitelist array.
- *
- * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
- * same origin resource requests.
- *
- * @description
- * Sets/Gets the whitelist of trusted resource URLs.
- */
- this.resourceUrlWhitelist = function (value) {
- if (arguments.length) {
- resourceUrlWhitelist = adjustMatchers(value);
- }
- return resourceUrlWhitelist;
- };
-
- /**
- * @ngdoc function
- * @name ng.sceDelegateProvider#resourceUrlBlacklist
- * @methodOf ng.$sceDelegateProvider
- * @function
- *
- * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
- * provided. This must be an array or null. A snapshot of this array is used so further
- * changes to the array are ignored.
- *
- * Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
- * allowed in this array.
- *
- * The typical usage for the blacklist is to **block
- * [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
- * these would otherwise be trusted but actually return content from the redirected domain.
- *
- * Finally, **the blacklist overrides the whitelist** and has the final say.
- *
- * @return {Array} the currently set blacklist array.
- *
- * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
- * is no blacklist.)
- *
- * @description
- * Sets/Gets the blacklist of trusted resource URLs.
- */
-
- this.resourceUrlBlacklist = function (value) {
- if (arguments.length) {
- resourceUrlBlacklist = adjustMatchers(value);
- }
- return resourceUrlBlacklist;
- };
-
- this.$get = ['$injector', function($injector) {
-
- var htmlSanitizer = function htmlSanitizer(html) {
- throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
- };
-
- if ($injector.has('$sanitize')) {
- htmlSanitizer = $injector.get('$sanitize');
- }
-
-
- function matchUrl(matcher, parsedUrl) {
- if (matcher === 'self') {
- return urlIsSameOrigin(parsedUrl);
- } else {
- // definitely a regex. See adjustMatchers()
- return !!matcher.exec(parsedUrl.href);
- }
- }
-
- function isResourceUrlAllowedByPolicy(url) {
- var parsedUrl = urlResolve(url.toString());
- var i, n, allowed = false;
- // Ensure that at least one item from the whitelist allows this url.
- for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
- if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
- allowed = true;
- break;
- }
- }
- if (allowed) {
- // Ensure that no item from the blacklist blocked this url.
- for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
- if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
- allowed = false;
- break;
- }
- }
- }
- return allowed;
- }
-
- function generateHolderType(Base) {
- var holderType = function TrustedValueHolderType(trustedValue) {
- this.$$unwrapTrustedValue = function() {
- return trustedValue;
- };
- };
- if (Base) {
- holderType.prototype = new Base();
- }
- holderType.prototype.valueOf = function sceValueOf() {
- return this.$$unwrapTrustedValue();
- };
- holderType.prototype.toString = function sceToString() {
- return this.$$unwrapTrustedValue().toString();
- };
- return holderType;
- }
-
- var trustedValueHolderBase = generateHolderType(),
- byType = {};
-
- byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
- byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
- byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
- byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
- byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
-
- /**
- * @ngdoc method
- * @name ng.$sceDelegate#trustAs
- * @methodOf ng.$sceDelegate
- *
- * @description
- * Returns an object that is trusted by angular for use in specified strict
- * contextual escaping contexts (such as ng-html-bind-unsafe, ng-include, any src
- * attribute interpolation, any dom event binding attribute interpolation
- * such as for onclick, etc.) that uses the provided value.
- * See {@link ng.$sce $sce} for enabling strict contextual escaping.
- *
- * @param {string} type The kind of context in which this value is safe for use. e.g. url,
- * resourceUrl, html, js and css.
- * @param {*} value The value that that should be considered trusted/safe.
- * @returns {*} A value that can be used to stand in for the provided `value` in places
- * where Angular expects a $sce.trustAs() return value.
- */
- function trustAs(type, trustedValue) {
- var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
- if (!Constructor) {
- throw $sceMinErr('icontext',
- 'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
- type, trustedValue);
- }
- if (trustedValue === null || trustedValue === undefined || trustedValue === '') {
- return trustedValue;
- }
- // All the current contexts in SCE_CONTEXTS happen to be strings. In order to avoid trusting
- // mutable objects, we ensure here that the value passed in is actually a string.
- if (typeof trustedValue !== 'string') {
- throw $sceMinErr('itype',
- 'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
- type);
- }
- return new Constructor(trustedValue);
- }
-
- /**
- * @ngdoc method
- * @name ng.$sceDelegate#valueOf
- * @methodOf ng.$sceDelegate
- *
- * @description
- * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#methods_trustAs
- * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
- * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}.
- *
- * If the passed parameter is not a value that had been returned by {@link
- * ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}, returns it as-is.
- *
- * @param {*} value The result of a prior {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}
- * call or anything else.
- * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
- * `$sceDelegate.trustAs`} if `value` is the result of such a call. Otherwise, returns
- * `value` unchanged.
- */
- function valueOf(maybeTrusted) {
- if (maybeTrusted instanceof trustedValueHolderBase) {
- return maybeTrusted.$$unwrapTrustedValue();
- } else {
- return maybeTrusted;
- }
- }
-
- /**
- * @ngdoc method
- * @name ng.$sceDelegate#getTrusted
- * @methodOf ng.$sceDelegate
- *
- * @description
- * Takes the result of a {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`} call and
- * returns the originally supplied value if the queried context type is a supertype of the
- * created type. If this condition isn't satisfied, throws an exception.
- *
- * @param {string} type The kind of context in which this value is to be used.
- * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#methods_trustAs
- * `$sceDelegate.trustAs`} call.
- * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#methods_trustAs
- * `$sceDelegate.trustAs`} if valid in this context. Otherwise, throws an exception.
- */
- function getTrusted(type, maybeTrusted) {
- if (maybeTrusted === null || maybeTrusted === undefined || maybeTrusted === '') {
- return maybeTrusted;
- }
- var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
- if (constructor && maybeTrusted instanceof constructor) {
- return maybeTrusted.$$unwrapTrustedValue();
- }
- // If we get here, then we may only take one of two actions.
- // 1. sanitize the value for the requested type, or
- // 2. throw an exception.
- if (type === SCE_CONTEXTS.RESOURCE_URL) {
- if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
- return maybeTrusted;
- } else {
- throw $sceMinErr('insecurl',
- 'Blocked loading resource from url not allowed by $sceDelegate policy. URL: {0}',
- maybeTrusted.toString());
- }
- } else if (type === SCE_CONTEXTS.HTML) {
- return htmlSanitizer(maybeTrusted);
- }
- throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
- }
-
- return { trustAs: trustAs,
- getTrusted: getTrusted,
- valueOf: valueOf };
- }];
-}
-
-
-/**
- * @ngdoc object
- * @name ng.$sceProvider
- * @description
- *
- * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
- * - enable/disable Strict Contextual Escaping (SCE) in a module
- * - override the default implementation with a custom delegate
- *
- * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
- */
-
-/* jshint maxlen: false*/
-
-/**
- * @ngdoc service
- * @name ng.$sce
- * @function
- *
- * @description
- *
- * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
- *
- * # Strict Contextual Escaping
- *
- * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
- * contexts to result in a value that is marked as safe to use for that context. One example of
- * such a context is binding arbitrary html controlled by the user via `ng-bind-html`. We refer
- * to these contexts as privileged or SCE contexts.
- *
- * As of version 1.2, Angular ships with SCE enabled by default.
- *
- * Note: When enabled (the default), IE8 in quirks mode is not supported. In this mode, IE8 allows
- * one to execute arbitrary javascript by the use of the expression() syntax. Refer
- * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
- * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
- * to the top of your HTML document.
- *
- * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
- * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
- *
- * Here's an example of a binding in a privileged context:
- *
- * <pre class="prettyprint">
- * <input ng-model="userHtml">
- * <div ng-bind-html="userHtml">
- * </pre>
- *
- * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user. With SCE
- * disabled, this application allows the user to render arbitrary HTML into the DIV.
- * In a more realistic example, one may be rendering user comments, blog articles, etc. via
- * bindings. (HTML is just one example of a context where rendering user controlled input creates
- * security vulnerabilities.)
- *
- * For the case of HTML, you might use a library, either on the client side, or on the server side,
- * to sanitize unsafe HTML before binding to the value and rendering it in the document.
- *
- * How would you ensure that every place that used these types of bindings was bound to a value that
- * was sanitized by your library (or returned as safe for rendering by your server?) How can you
- * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
- * properties/fields and forgot to update the binding to the sanitized value?
- *
- * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
- * determine that something explicitly says it's safe to use a value for binding in that
- * context. You can then audit your code (a simple grep would do) to ensure that this is only done
- * for those values that you can easily tell are safe - because they were received from your server,
- * sanitized by your library, etc. You can organize your codebase to help with this - perhaps
- * allowing only the files in a specific directory to do this. Ensuring that the internal API
- * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
- *
- * In the case of AngularJS' SCE service, one uses {@link ng.$sce#methods_trustAs $sce.trustAs}
- * (and shorthand methods such as {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}, etc.) to
- * obtain values that will be accepted by SCE / privileged contexts.
- *
- *
- * ## How does it work?
- *
- * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#methods_getTrusted
- * $sce.getTrusted(context, value)} rather than to the value directly. Directives use {@link
- * ng.$sce#methods_parse $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
- * {@link ng.$sce#methods_getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
- *
- * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
- * ng.$sce#methods_parseAsHtml $sce.parseAsHtml(binding expression)}. Here's the actual code (slightly
- * simplified):
- *
- * <pre class="prettyprint">
- * var ngBindHtmlDirective = ['$sce', function($sce) {
- * return function(scope, element, attr) {
- * scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
- * element.html(value || '');
- * });
- * };
- * }];
- * </pre>
- *
- * ## Impact on loading templates
- *
- * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
- * `templateUrl`'s specified by {@link guide/directive directives}.
- *
- * By default, Angular only loads templates from the same domain and protocol as the application
- * document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
- * $sce.getTrustedResourceUrl} on the template URL. To load templates from other domains and/or
- * protocols, you may either either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist
- * them} or {@link ng.$sce#methods_trustAsResourceUrl wrap it} into a trusted value.
- *
- * *Please note*:
- * The browser's
- * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
- * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing (CORS)}
- * policy apply in addition to this and may further restrict whether the template is successfully
- * loaded. This means that without the right CORS policy, loading templates from a different domain
- * won't work on all browsers. Also, loading templates from `file://` URL does not work on some
- * browsers.
- *
- * ## This feels like too much overhead for the developer?
- *
- * It's important to remember that SCE only applies to interpolation expressions.
- *
- * If your expressions are constant literals, they're automatically trusted and you don't need to
- * call `$sce.trustAs` on them. (e.g.
- * `<div ng-html-bind-unsafe="'<b>implicitly trusted</b>'"></div>`) just works.
- *
- * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
- * through {@link ng.$sce#methods_getTrusted $sce.getTrusted}. SCE doesn't play a role here.
- *
- * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
- * templates in `ng-include` from your application's domain without having to even know about SCE.
- * It blocks loading templates from other domains or loading templates over http from an https
- * served document. You can change these by setting your own custom {@link
- * ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelists} and {@link
- * ng.$sceDelegateProvider#methods_resourceUrlBlacklist blacklists} for matching such URLs.
- *
- * This significantly reduces the overhead. It is far easier to pay the small overhead and have an
- * application that's secure and can be audited to verify that with much more ease than bolting
- * security onto an application later.
- *
- * <a name="contexts"></a>
- * ## What trusted context types are supported?
- *
- * | Context | Notes |
- * |---------------------|----------------|
- * | `$sce.HTML` | For HTML that's safe to source into the application. The {@link ng.directive:ngBindHtml ngBindHtml} directive uses this context for bindings. |
- * | `$sce.CSS` | For CSS that's safe to source into the application. Currently unused. Feel free to use it in your own directives. |
- * | `$sce.URL` | For URLs that are safe to follow as links. Currently unused (`<a href=` and `<img src=` sanitize their urls and don't consititute an SCE context. |
- * | `$sce.RESOURCE_URL` | For URLs that are not only safe to follow as links, but whose contens are also safe to include in your application. Examples include `ng-include`, `src` / `ngSrc` bindings for tags other than `IMG` (e.g. `IFRAME`, `OBJECT`, etc.) <br><br>Note that `$sce.RESOURCE_URL` makes a stronger statement about the URL than `$sce.URL` does and therefore contexts requiring values trusted for `$sce.RESOURCE_URL` can be used anywhere that values trusted for `$sce.URL` are required. |
- * | `$sce.JS` | For JavaScript that is safe to execute in your application's context. Currently unused. Feel free to use it in your own directives. |
- *
- * ## Format of items in {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#methods_resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
- *
- * Each element in these arrays must be one of the following:
- *
- * - **'self'**
- * - The special **string**, `'self'`, can be used to match against all URLs of the **same
- * domain** as the application document using the **same protocol**.
- * - **String** (except the special value `'self'`)
- * - The string is matched against the full *normalized / absolute URL* of the resource
- * being tested (substring matches are not good enough.)
- * - There are exactly **two wildcard sequences** - `*` and `**`. All other characters
- * match themselves.
- * - `*`: matches zero or more occurances of any character other than one of the following 6
- * characters: '`:`', '`/`', '`.`', '`?`', '`&`' and ';'. It's a useful wildcard for use
- * in a whitelist.
- * - `**`: matches zero or more occurances of *any* character. As such, it's not
- * not appropriate to use in for a scheme, domain, etc. as it would match too much. (e.g.
- * http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
- * not have been the intention.) It's usage at the very end of the path is ok. (e.g.
- * http://foo.example.com/templates/**).
- * - **RegExp** (*see caveat below*)
- * - *Caveat*: While regular expressions are powerful and offer great flexibility, their syntax
- * (and all the inevitable escaping) makes them *harder to maintain*. It's easy to
- * accidentally introduce a bug when one updates a complex expression (imho, all regexes should
- * have good test coverage.). For instance, the use of `.` in the regex is correct only in a
- * small number of cases. A `.` character in the regex used when matching the scheme or a
- * subdomain could be matched against a `:` or literal `.` that was likely not intended. It
- * is highly recommended to use the string patterns and only fall back to regular expressions
- * if they as a last resort.
- * - The regular expression must be an instance of RegExp (i.e. not a string.) It is
- * matched against the **entire** *normalized / absolute URL* of the resource being tested
- * (even when the RegExp did not have the `^` and `$` codes.) In addition, any flags
- * present on the RegExp (such as multiline, global, ignoreCase) are ignored.
- * - If you are generating your Javascript from some other templating engine (not
- * recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
- * remember to escape your regular expression (and be aware that you might need more than
- * one level of escaping depending on your templating engine and the way you interpolated
- * the value.) Do make use of your platform's escaping mechanism as it might be good
- * enough before coding your own. e.g. Ruby has
- * [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
- * and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
- * Javascript lacks a similar built in function for escaping. Take a look at Google
- * Closure library's [goog.string.regExpEscape(s)](
- * http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
- *
- * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
- *
- * ## Show me an example using SCE.
- *
- * @example
-<example module="mySceApp">
-<file name="index.html">
- <div ng-controller="myAppController as myCtrl">
- <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
- <b>User comments</b><br>
- By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
- $sanitize is available. If $sanitize isn't available, this results in an error instead of an
- exploit.
- <div class="well">
- <div ng-repeat="userComment in myCtrl.userComments">
- <b>{{userComment.name}}</b>:
- <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
- <br>
- </div>
- </div>
- </div>
-</file>
-
-<file name="script.js">
- var mySceApp = angular.module('mySceApp', ['ngSanitize']);
-
- mySceApp.controller("myAppController", function myAppController($http, $templateCache, $sce) {
- var self = this;
- $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
- self.userComments = userComments;
- });
- self.explicitlyTrustedHtml = $sce.trustAsHtml(
- '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
- 'sanitization."">Hover over this text.</span>');
- });
-</file>
-
-<file name="test_data.json">
-[
- { "name": "Alice",
- "htmlComment":
- "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
- },
- { "name": "Bob",
- "htmlComment": "<i>Yes!</i> Am I the only other one?"
- }
-]
-</file>
-
-<file name="scenario.js">
- describe('SCE doc demo', function() {
- it('should sanitize untrusted values', function() {
- expect(element('.htmlComment').html()).toBe('<span>Is <i>anyone</i> reading this?</span>');
- });
- it('should NOT sanitize explicitly trusted values', function() {
- expect(element('#explicitlyTrustedHtml').html()).toBe(
- '<span onmouseover="this.textContent="Explicitly trusted HTML bypasses ' +
- 'sanitization."">Hover over this text.</span>');
- });
- });
-</file>
-</example>
- *
- *
- *
- * ## Can I disable SCE completely?
- *
- * Yes, you can. However, this is strongly discouraged. SCE gives you a lot of security benefits
- * for little coding overhead. It will be much harder to take an SCE disabled application and
- * either secure it on your own or enable SCE at a later stage. It might make sense to disable SCE
- * for cases where you have a lot of existing code that was written before SCE was introduced and
- * you're migrating them a module at a time.
- *
- * That said, here's how you can completely disable SCE:
- *
- * <pre class="prettyprint">
- * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
- * // Completely disable SCE. For demonstration purposes only!
- * // Do not use in new projects.
- * $sceProvider.enabled(false);
- * });
- * </pre>
- *
- */
-/* jshint maxlen: 100 */
-
-function $SceProvider() {
- var enabled = true;
-
- /**
- * @ngdoc function
- * @name ng.sceProvider#enabled
- * @methodOf ng.$sceProvider
- * @function
- *
- * @param {boolean=} value If provided, then enables/disables SCE.
- * @return {boolean} true if SCE is enabled, false otherwise.
- *
- * @description
- * Enables/disables SCE and returns the current value.
- */
- this.enabled = function (value) {
- if (arguments.length) {
- enabled = !!value;
- }
- return enabled;
- };
-
-
- /* Design notes on the default implementation for SCE.
- *
- * The API contract for the SCE delegate
- * -------------------------------------
- * The SCE delegate object must provide the following 3 methods:
- *
- * - trustAs(contextEnum, value)
- * This method is used to tell the SCE service that the provided value is OK to use in the
- * contexts specified by contextEnum. It must return an object that will be accepted by
- * getTrusted() for a compatible contextEnum and return this value.
- *
- * - valueOf(value)
- * For values that were not produced by trustAs(), return them as is. For values that were
- * produced by trustAs(), return the corresponding input value to trustAs. Basically, if
- * trustAs is wrapping the given values into some type, this operation unwraps it when given
- * such a value.
- *
- * - getTrusted(contextEnum, value)
- * This function should return the a value that is safe to use in the context specified by
- * contextEnum or throw and exception otherwise.
- *
- * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
- * opaque or wrapped in some holder object. That happens to be an implementation detail. For
- * instance, an implementation could maintain a registry of all trusted objects by context. In
- * such a case, trustAs() would return the same object that was passed in. getTrusted() would
- * return the same object passed in if it was found in the registry under a compatible context or
- * throw an exception otherwise. An implementation might only wrap values some of the time based
- * on some criteria. getTrusted() might return a value and not throw an exception for special
- * constants or objects even if not wrapped. All such implementations fulfill this contract.
- *
- *
- * A note on the inheritance model for SCE contexts
- * ------------------------------------------------
- * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types. This
- * is purely an implementation details.
- *
- * The contract is simply this:
- *
- * getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
- * will also succeed.
- *
- * Inheritance happens to capture this in a natural way. In some future, we
- * may not use inheritance anymore. That is OK because no code outside of
- * sce.js and sceSpecs.js would need to be aware of this detail.
- */
-
- this.$get = ['$parse', '$sniffer', '$sceDelegate', function(
- $parse, $sniffer, $sceDelegate) {
- // Prereq: Ensure that we're not running in IE8 quirks mode. In that mode, IE allows
- // the "expression(javascript expression)" syntax which is insecure.
- if (enabled && $sniffer.msie && $sniffer.msieDocumentMode < 8) {
- throw $sceMinErr('iequirks',
- 'Strict Contextual Escaping does not support Internet Explorer version < 9 in quirks ' +
- 'mode. You can fix this by adding the text <!doctype html> to the top of your HTML ' +
- 'document. See http://docs.angularjs.org/api/ng.$sce for more information.');
- }
-
- var sce = copy(SCE_CONTEXTS);
-
- /**
- * @ngdoc function
- * @name ng.sce#isEnabled
- * @methodOf ng.$sce
- * @function
- *
- * @return {Boolean} true if SCE is enabled, false otherwise. If you want to set the value, you
- * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
- *
- * @description
- * Returns a boolean indicating if SCE is enabled.
- */
- sce.isEnabled = function () {
- return enabled;
- };
- sce.trustAs = $sceDelegate.trustAs;
- sce.getTrusted = $sceDelegate.getTrusted;
- sce.valueOf = $sceDelegate.valueOf;
-
- if (!enabled) {
- sce.trustAs = sce.getTrusted = function(type, value) { return value; };
- sce.valueOf = identity;
- }
-
- /**
- * @ngdoc method
- * @name ng.$sce#parse
- * @methodOf ng.$sce
- *
- * @description
- * Converts Angular {@link guide/expression expression} into a function. This is like {@link
- * ng.$parse $parse} and is identical when the expression is a literal constant. Otherwise, it
- * wraps the expression in a call to {@link ng.$sce#methods_getTrusted $sce.getTrusted(*type*,
- * *result*)}
- *
- * @param {string} type The kind of SCE context in which this result will be used.
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
- sce.parseAs = function sceParseAs(type, expr) {
- var parsed = $parse(expr);
- if (parsed.literal && parsed.constant) {
- return parsed;
- } else {
- return function sceParseAsTrusted(self, locals) {
- return sce.getTrusted(type, parsed(self, locals));
- };
- }
- };
-
- /**
- * @ngdoc method
- * @name ng.$sce#trustAs
- * @methodOf ng.$sce
- *
- * @description
- * Delegates to {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs`}. As such,
- * returns an objectthat is trusted by angular for use in specified strict contextual
- * escaping contexts (such as ng-html-bind-unsafe, ng-include, any src attribute
- * interpolation, any dom event binding attribute interpolation such as for onclick, etc.)
- * that uses the provided value. See * {@link ng.$sce $sce} for enabling strict contextual
- * escaping.
- *
- * @param {string} type The kind of context in which this value is safe for use. e.g. url,
- * resource_url, html, js and css.
- * @param {*} value The value that that should be considered trusted/safe.
- * @returns {*} A value that can be used to stand in for the provided `value` in places
- * where Angular expects a $sce.trustAs() return value.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#trustAsHtml
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.trustAsHtml(value)` →
- * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
- *
- * @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedHtml
- * $sce.getTrustedHtml(value)} to obtain the original value. (privileged directives
- * only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#trustAsUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.trustAsUrl(value)` →
- * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.URL, value)`}
- *
- * @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedUrl
- * $sce.getTrustedUrl(value)} to obtain the original value. (privileged directives
- * only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#trustAsResourceUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.trustAsResourceUrl(value)` →
- * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
- *
- * @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedResourceUrl
- * $sce.getTrustedResourceUrl(value)} to obtain the original value. (privileged directives
- * only accept expressions that are either literal constants or are the return
- * value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#trustAsJs
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.trustAsJs(value)` →
- * {@link ng.$sceDelegate#methods_trustAs `$sceDelegate.trustAs($sce.JS, value)`}
- *
- * @param {*} value The value to trustAs.
- * @returns {*} An object that can be passed to {@link ng.$sce#methods_getTrustedJs
- * $sce.getTrustedJs(value)} to obtain the original value. (privileged directives
- * only accept expressions that are either literal constants or are the
- * return value of {@link ng.$sce#methods_trustAs $sce.trustAs}.)
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrusted
- * @methodOf ng.$sce
- *
- * @description
- * Delegates to {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted`}. As such,
- * takes the result of a {@link ng.$sce#methods_trustAs `$sce.trustAs`}() call and returns the
- * originally supplied value if the queried context type is a supertype of the created type.
- * If this condition isn't satisfied, throws an exception.
- *
- * @param {string} type The kind of context in which this value is to be used.
- * @param {*} maybeTrusted The result of a prior {@link ng.$sce#methods_trustAs `$sce.trustAs`}
- * call.
- * @returns {*} The value the was originally provided to
- * {@link ng.$sce#methods_trustAs `$sce.trustAs`} if valid in this context.
- * Otherwise, throws an exception.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrustedHtml
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.getTrustedHtml(value)` →
- * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
- *
- * @param {*} value The value to pass to `$sce.getTrusted`.
- * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrustedCss
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.getTrustedCss(value)` →
- * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
- *
- * @param {*} value The value to pass to `$sce.getTrusted`.
- * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrustedUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.getTrustedUrl(value)` →
- * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
- *
- * @param {*} value The value to pass to `$sce.getTrusted`.
- * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrustedResourceUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.getTrustedResourceUrl(value)` →
- * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
- *
- * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
- * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#getTrustedJs
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.getTrustedJs(value)` →
- * {@link ng.$sceDelegate#methods_getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
- *
- * @param {*} value The value to pass to `$sce.getTrusted`.
- * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#parseAsHtml
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.parseAsHtml(expression string)` →
- * {@link ng.$sce#methods_parse `$sce.parseAs($sce.HTML, value)`}
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#parseAsCss
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.parseAsCss(value)` →
- * {@link ng.$sce#methods_parse `$sce.parseAs($sce.CSS, value)`}
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#parseAsUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.parseAsUrl(value)` →
- * {@link ng.$sce#methods_parse `$sce.parseAs($sce.URL, value)`}
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#parseAsResourceUrl
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.parseAsResourceUrl(value)` →
- * {@link ng.$sce#methods_parse `$sce.parseAs($sce.RESOURCE_URL, value)`}
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
-
- /**
- * @ngdoc method
- * @name ng.$sce#parseAsJs
- * @methodOf ng.$sce
- *
- * @description
- * Shorthand method. `$sce.parseAsJs(value)` →
- * {@link ng.$sce#methods_parse `$sce.parseAs($sce.JS, value)`}
- *
- * @param {string} expression String expression to compile.
- * @returns {function(context, locals)} a function which represents the compiled expression:
- *
- * * `context` – `{object}` – an object against which any expressions embedded in the strings
- * are evaluated against (typically a scope object).
- * * `locals` – `{object=}` – local variables context object, useful for overriding values in
- * `context`.
- */
-
- // Shorthand delegations.
- var parse = sce.parseAs,
- getTrusted = sce.getTrusted,
- trustAs = sce.trustAs;
-
- forEach(SCE_CONTEXTS, function (enumValue, name) {
- var lName = lowercase(name);
- sce[camelCase("parse_as_" + lName)] = function (expr) {
- return parse(enumValue, expr);
- };
- sce[camelCase("get_trusted_" + lName)] = function (value) {
- return getTrusted(enumValue, value);
- };
- sce[camelCase("trust_as_" + lName)] = function (value) {
- return trustAs(enumValue, value);
- };
- });
-
- return sce;
- }];
-}
-
-/**
- * !!! This is an undocumented "private" service !!!
- *
- * @name ng.$sniffer
- * @requires $window
- * @requires $document
- *
- * @property {boolean} history Does the browser support html5 history api ?
- * @property {boolean} hashchange Does the browser support hashchange event ?
- * @property {boolean} transitions Does the browser support CSS transition events ?
- * @property {boolean} animations Does the browser support CSS animation events ?
- *
- * @description
- * This is very simple implementation of testing browser's features.
- */
-function $SnifferProvider() {
- this.$get = ['$window', '$document', function($window, $document) {
- var eventSupport = {},
- android =
- int((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
- boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
- document = $document[0] || {},
- documentMode = document.documentMode,
- vendorPrefix,
- vendorRegex = /^(Moz|webkit|O|ms)(?=[A-Z])/,
- bodyStyle = document.body && document.body.style,
- transitions = false,
- animations = false,
- match;
-
- if (bodyStyle) {
- for(var prop in bodyStyle) {
- if(match = vendorRegex.exec(prop)) {
- vendorPrefix = match[0];
- vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
- break;
- }
- }
-
- if(!vendorPrefix) {
- vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
- }
-
- transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
- animations = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
-
- if (android && (!transitions||!animations)) {
- transitions = isString(document.body.style.webkitTransition);
- animations = isString(document.body.style.webkitAnimation);
- }
- }
-
-
- return {
- // Android has history.pushState, but it does not update location correctly
- // so let's not use the history API at all.
- // http://code.google.com/p/android/issues/detail?id=17471
- // https://github.com/angular/angular.js/issues/904
-
- // older webit browser (533.9) on Boxee box has exactly the same problem as Android has
- // so let's not use the history API also
- // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
- // jshint -W018
- history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
- // jshint +W018
- hashchange: 'onhashchange' in $window &&
- // IE8 compatible mode lies
- (!documentMode || documentMode > 7),
- hasEvent: function(event) {
- // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
- // it. In particular the event is not fired when backspace or delete key are pressed or
- // when cut operation is performed.
- if (event == 'input' && msie == 9) return false;
-
- if (isUndefined(eventSupport[event])) {
- var divElm = document.createElement('div');
- eventSupport[event] = 'on' + event in divElm;
- }
-
- return eventSupport[event];
- },
- csp: csp(),
- vendorPrefix: vendorPrefix,
- transitions : transitions,
- animations : animations,
- msie : msie,
- msieDocumentMode: documentMode
- };
- }];
-}
-
-function $TimeoutProvider() {
- this.$get = ['$rootScope', '$browser', '$q', '$exceptionHandler',
- function($rootScope, $browser, $q, $exceptionHandler) {
- var deferreds = {};
-
-
- /**
- * @ngdoc function
- * @name ng.$timeout
- * @requires $browser
- *
- * @description
- * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
- * block and delegates any exceptions to
- * {@link ng.$exceptionHandler $exceptionHandler} service.
- *
- * The return value of registering a timeout function is a promise, which will be resolved when
- * the timeout is reached and the timeout function is executed.
- *
- * To cancel a timeout request, call `$timeout.cancel(promise)`.
- *
- * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
- * synchronously flush the queue of deferred functions.
- *
- * @param {function()} fn A function, whose execution should be delayed.
- * @param {number=} [delay=0] Delay in milliseconds.
- * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#methods_$apply $apply} block.
- * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
- * promise will be resolved with is the return value of the `fn` function.
- *
- * @example
- <doc:example module="time">
- <doc:source>
- <script>
- function Ctrl2($scope,$timeout) {
- $scope.format = 'M/d/yy h:mm:ss a';
- $scope.blood_1 = 100;
- $scope.blood_2 = 120;
-
- var stop;
- $scope.fight = function() {
- stop = $timeout(function() {
- if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
- $scope.blood_1 = $scope.blood_1 - 3;
- $scope.blood_2 = $scope.blood_2 - 4;
- $scope.fight();
- } else {
- $timeout.cancel(stop);
- }
- }, 100);
- };
-
- $scope.stopFight = function() {
- $timeout.cancel(stop);
- };
-
- $scope.resetFight = function() {
- $scope.blood_1 = 100;
- $scope.blood_2 = 120;
- }
- }
-
- angular.module('time', [])
- // Register the 'myCurrentTime' directive factory method.
- // We inject $timeout and dateFilter service since the factory method is DI.
- .directive('myCurrentTime', function($timeout, dateFilter) {
- // return the directive link function. (compile function not needed)
- return function(scope, element, attrs) {
- var format, // date format
- timeoutId; // timeoutId, so that we can cancel the time updates
-
- // used to update the UI
- function updateTime() {
- element.text(dateFilter(new Date(), format));
- }
-
- // watch the expression, and update the UI on change.
- scope.$watch(attrs.myCurrentTime, function(value) {
- format = value;
- updateTime();
- });
-
- // schedule update in one second
- function updateLater() {
- // save the timeoutId for canceling
- timeoutId = $timeout(function() {
- updateTime(); // update DOM
- updateLater(); // schedule another update
- }, 1000);
- }
-
- // listen on DOM destroy (removal) event, and cancel the next UI update
- // to prevent updating time ofter the DOM element was removed.
- element.bind('$destroy', function() {
- $timeout.cancel(timeoutId);
- });
-
- updateLater(); // kick off the UI update process.
- }
- });
- </script>
-
- <div>
- <div ng-controller="Ctrl2">
- Date format: <input ng-model="format"> <hr/>
- Current time is: <span my-current-time="format"></span>
- <hr/>
- Blood 1 : <font color='red'>{{blood_1}}</font>
- Blood 2 : <font color='red'>{{blood_2}}</font>
- <button type="button" data-ng-click="fight()">Fight</button>
- <button type="button" data-ng-click="stopFight()">StopFight</button>
- <button type="button" data-ng-click="resetFight()">resetFight</button>
- </div>
- </div>
-
- </doc:source>
- </doc:example>
- */
- function timeout(fn, delay, invokeApply) {
- var deferred = $q.defer(),
- promise = deferred.promise,
- skipApply = (isDefined(invokeApply) && !invokeApply),
- timeoutId;
-
- timeoutId = $browser.defer(function() {
- try {
- deferred.resolve(fn());
- } catch(e) {
- deferred.reject(e);
- $exceptionHandler(e);
- }
- finally {
- delete deferreds[promise.$$timeoutId];
- }
-
- if (!skipApply) $rootScope.$apply();
- }, delay);
-
- promise.$$timeoutId = timeoutId;
- deferreds[timeoutId] = deferred;
-
- return promise;
- }
-
-
- /**
- * @ngdoc function
- * @name ng.$timeout#cancel
- * @methodOf ng.$timeout
- *
- * @description
- * Cancels a task associated with the `promise`. As a result of this, the promise will be
- * resolved with a rejection.
- *
- * @param {Promise=} promise Promise returned by the `$timeout` function.
- * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
- * canceled.
- */
- timeout.cancel = function(promise) {
- if (promise && promise.$$timeoutId in deferreds) {
- deferreds[promise.$$timeoutId].reject('canceled');
- delete deferreds[promise.$$timeoutId];
- return $browser.defer.cancel(promise.$$timeoutId);
- }
- return false;
- };
-
- return timeout;
- }];
-}
-
-// NOTE: The usage of window and document instead of $window and $document here is
-// deliberate. This service depends on the specific behavior of anchor nodes created by the
-// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
-// cause us to break tests. In addition, when the browser resolves a URL for XHR, it
-// doesn't know about mocked locations and resolves URLs to the real document - which is
-// exactly the behavior needed here. There is little value is mocking these out for this
-// service.
-var urlParsingNode = document.createElement("a");
-var originUrl = urlResolve(window.location.href, true);
-
-
-/**
- *
- * Implementation Notes for non-IE browsers
- * ----------------------------------------
- * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
- * results both in the normalizing and parsing of the URL. Normalizing means that a relative
- * URL will be resolved into an absolute URL in the context of the application document.
- * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
- * properties are all populated to reflect the normalized URL. This approach has wide
- * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See
- * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
- *
- * Implementation Notes for IE
- * ---------------------------
- * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other
- * browsers. However, the parsed components will not be set if the URL assigned did not specify
- * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We
- * work around that by performing the parsing in a 2nd step by taking a previously normalized
- * URL (e.g. by assigning to a.href) and assigning it a.href again. This correctly populates the
- * properties such as protocol, hostname, port, etc.
- *
- * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one
- * uses the inner HTML approach to assign the URL as part of an HTML snippet -
- * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL.
- * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception.
- * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that
- * method and IE < 8 is unsupported.
- *
- * References:
- * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
- * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
- * http://url.spec.whatwg.org/#urlutils
- * https://github.com/angular/angular.js/pull/2902
- * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
- *
- * @function
- * @param {string} url The URL to be parsed.
- * @description Normalizes and parses a URL.
- * @returns {object} Returns the normalized URL as a dictionary.
- *
- * | member name | Description |
- * |---------------|----------------|
- * | href | A normalized version of the provided URL if it was not an absolute URL |
- * | protocol | The protocol including the trailing colon |
- * | host | The host and port (if the port is non-default) of the normalizedUrl |
- * | search | The search params, minus the question mark |
- * | hash | The hash string, minus the hash symbol
- * | hostname | The hostname
- * | port | The port, without ":"
- * | pathname | The pathname, beginning with "/"
- *
- */
-function urlResolve(url, base) {
- var href = url;
-
- if (msie) {
- // Normalize before parse. Refer Implementation Notes on why this is
- // done in two steps on IE.
- urlParsingNode.setAttribute("href", href);
- href = urlParsingNode.href;
- }
-
- urlParsingNode.setAttribute('href', href);
-
- // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
- return {
- href: urlParsingNode.href,
- protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
- host: urlParsingNode.host,
- search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
- hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
- hostname: urlParsingNode.hostname,
- port: urlParsingNode.port,
- pathname: (urlParsingNode.pathname.charAt(0) === '/')
- ? urlParsingNode.pathname
- : '/' + urlParsingNode.pathname
- };
-}
-
-/**
- * Parse a request URL and determine whether this is a same-origin request as the application document.
- *
- * @param {string|object} requestUrl The url of the request as a string that will be resolved
- * or a parsed URL object.
- * @returns {boolean} Whether the request is for the same origin as the application document.
- */
-function urlIsSameOrigin(requestUrl) {
- var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
- return (parsed.protocol === originUrl.protocol &&
- parsed.host === originUrl.host);
-}
-
-/**
- * @ngdoc object
- * @name ng.$window
- *
- * @description
- * A reference to the browser's `window` object. While `window`
- * is globally available in JavaScript, it causes testability problems, because
- * it is a global variable. In angular we always refer to it through the
- * `$window` service, so it may be overridden, removed or mocked for testing.
- *
- * Expressions, like the one defined for the `ngClick` directive in the example
- * below, are evaluated with respect to the current scope. Therefore, there is
- * no risk of inadvertently coding in a dependency on a global value in such an
- * expression.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope, $window) {
- $scope.greeting = 'Hello, World!';
- $scope.doGreeting = function(greeting) {
- $window.alert(greeting);
- };
- }
- </script>
- <div ng-controller="Ctrl">
- <input type="text" ng-model="greeting" />
- <button ng-click="doGreeting(greeting)">ALERT</button>
- </div>
- </doc:source>
- <doc:scenario>
- it('should display the greeting in the input box', function() {
- input('greeting').enter('Hello, E2E Tests');
- // If we click the button it will block the test runner
- // element(':button').click();
- });
- </doc:scenario>
- </doc:example>
- */
-function $WindowProvider(){
- this.$get = valueFn(window);
-}
-
-/**
- * @ngdoc object
- * @name ng.$filterProvider
- * @description
- *
- * Filters are just functions which transform input to an output. However filters need to be
- * Dependency Injected. To achieve this a filter definition consists of a factory function which is
- * annotated with dependencies and is responsible for creating a filter function.
- *
- * <pre>
- * // Filter registration
- * function MyModule($provide, $filterProvider) {
- * // create a service to demonstrate injection (not always needed)
- * $provide.value('greet', function(name){
- * return 'Hello ' + name + '!';
- * });
- *
- * // register a filter factory which uses the
- * // greet service to demonstrate DI.
- * $filterProvider.register('greet', function(greet){
- * // return the filter function which uses the greet service
- * // to generate salutation
- * return function(text) {
- * // filters need to be forgiving so check input validity
- * return text && greet(text) || text;
- * };
- * });
- * }
- * </pre>
- *
- * The filter function is registered with the `$injector` under the filter name suffix with
- * `Filter`.
- *
- * <pre>
- * it('should be the same instance', inject(
- * function($filterProvider) {
- * $filterProvider.register('reverse', function(){
- * return ...;
- * });
- * },
- * function($filter, reverseFilter) {
- * expect($filter('reverse')).toBe(reverseFilter);
- * });
- * </pre>
- *
- *
- * For more information about how angular filters work, and how to create your own filters, see
- * {@link guide/filter Filters} in the Angular Developer Guide.
- */
-/**
- * @ngdoc method
- * @name ng.$filterProvider#register
- * @methodOf ng.$filterProvider
- * @description
- * Register filter factory function.
- *
- * @param {String} name Name of the filter.
- * @param {function} fn The filter factory function which is injectable.
- */
-
-
-/**
- * @ngdoc function
- * @name ng.$filter
- * @function
- * @description
- * Filters are used for formatting data displayed to the user.
- *
- * The general syntax in templates is as follows:
- *
- * {{ expression [| filter_name[:parameter_value] ... ] }}
- *
- * @param {String} name Name of the filter function to retrieve
- * @return {Function} the filter function
- */
-$FilterProvider.$inject = ['$provide'];
-function $FilterProvider($provide) {
- var suffix = 'Filter';
-
- /**
- * @ngdoc function
- * @name ng.$controllerProvider#register
- * @methodOf ng.$controllerProvider
- * @param {string|Object} name Name of the filter function, or an object map of filters where
- * the keys are the filter names and the values are the filter factories.
- * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
- * of the registered filter instances.
- */
- function register(name, factory) {
- if(isObject(name)) {
- var filters = {};
- forEach(name, function(filter, key) {
- filters[key] = register(key, filter);
- });
- return filters;
- } else {
- return $provide.factory(name + suffix, factory);
- }
- }
- this.register = register;
-
- this.$get = ['$injector', function($injector) {
- return function(name) {
- return $injector.get(name + suffix);
- };
- }];
-
- ////////////////////////////////////////
-
- /* global
- currencyFilter: false,
- dateFilter: false,
- filterFilter: false,
- jsonFilter: false,
- limitToFilter: false,
- lowercaseFilter: false,
- numberFilter: false,
- orderByFilter: false,
- uppercaseFilter: false,
- */
-
- register('currency', currencyFilter);
- register('date', dateFilter);
- register('filter', filterFilter);
- register('json', jsonFilter);
- register('limitTo', limitToFilter);
- register('lowercase', lowercaseFilter);
- register('number', numberFilter);
- register('orderBy', orderByFilter);
- register('uppercase', uppercaseFilter);
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:filter
- * @function
- *
- * @description
- * Selects a subset of items from `array` and returns it as a new array.
- *
- * @param {Array} array The source array.
- * @param {string|Object|function()} expression The predicate to be used for selecting items from
- * `array`.
- *
- * 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
- * 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
- * by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
- * which have property `name` containing "M" and property `phone` containing "1". A special
- * property name `$` can be used (as in `{$:"text"}`) to accept a match against any
- * property of the object. That's equivalent to the simple substring match with a `string`
- * as described above.
- *
- * - `function`: A predicate function can be used to write arbitrary filters. The function is
- * called for each element of `array`. The final result is an array of those elements that
- * the predicate returned true for.
- *
- * @param {function(expected, actual)|true|undefined} comparator Comparator which is used in
- * determining if the expected value (from the filter expression) and actual value (from
- * the object in the array) should be considered a match.
- *
- * Can be one of:
- *
- * - `function(expected, actual)`:
- * The function will be given the object value and the predicate value to compare and
- * should return true if the item should be included in filtered result.
- *
- * - `true`: A shorthand for `function(expected, actual) { return angular.equals(expected, actual)}`.
- * this is essentially strict comparison of expected and actual.
- *
- * - `false|undefined`: A short hand for a function which will look for a substring match in case
- * insensitive way.
- *
- * @example
- <doc:example>
- <doc:source>
- <div ng-init="friends = [{name:'John', phone:'555-1276'},
- {name:'Mary', phone:'800-BIG-MARY'},
- {name:'Mike', phone:'555-4321'},
- {name:'Adam', phone:'555-5678'},
- {name:'Julie', phone:'555-8765'},
- {name:'Juliette', phone:'555-5678'}]"></div>
-
- Search: <input ng-model="searchText">
- <table id="searchTextResults">
- <tr><th>Name</th><th>Phone</th></tr>
- <tr ng-repeat="friend in friends | filter:searchText">
- <td>{{friend.name}}</td>
- <td>{{friend.phone}}</td>
- </tr>
- </table>
- <hr>
- Any: <input ng-model="search.$"> <br>
- Name only <input ng-model="search.name"><br>
- Phone only <input ng-model="search.phone"><br>
- Equality <input type="checkbox" ng-model="strict"><br>
- <table id="searchObjResults">
- <tr><th>Name</th><th>Phone</th></tr>
- <tr ng-repeat="friend in friends | filter:search:strict">
- <td>{{friend.name}}</td>
- <td>{{friend.phone}}</td>
- </tr>
- </table>
- </doc:source>
- <doc:scenario>
- it('should search across all fields when filtering with a string', function() {
- input('searchText').enter('m');
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Mike', 'Adam']);
-
- input('searchText').enter('76');
- expect(repeater('#searchTextResults tr', 'friend in friends').column('friend.name')).
- toEqual(['John', 'Julie']);
- });
-
- it('should search in specific fields when filtering with a predicate object', function() {
- input('search.$').enter('i');
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Mike', 'Julie', 'Juliette']);
- });
- it('should use a equal comparison when comparator is true', function() {
- input('search.name').enter('Julie');
- input('strict').check();
- expect(repeater('#searchObjResults tr', 'friend in friends').column('friend.name')).
- toEqual(['Julie']);
- });
- </doc:scenario>
- </doc:example>
- */
-function filterFilter() {
- return function(array, expression, comparator) {
- if (!isArray(array)) return array;
-
- var comparatorType = typeof(comparator),
- predicates = [];
-
- predicates.check = function(value) {
- for (var j = 0; j < predicates.length; j++) {
- if(!predicates[j](value)) {
- return false;
- }
- }
- return true;
- };
-
- if (comparatorType !== 'function') {
- if (comparatorType === 'boolean' && comparator) {
- comparator = function(obj, text) {
- return angular.equals(obj, text);
- };
- } else {
- comparator = function(obj, text) {
- text = (''+text).toLowerCase();
- return (''+obj).toLowerCase().indexOf(text) > -1;
- };
- }
- }
-
- var search = function(obj, text){
- if (typeof text == 'string' && text.charAt(0) === '!') {
- return !search(obj, text.substr(1));
- }
- switch (typeof obj) {
- case "boolean":
- case "number":
- case "string":
- return comparator(obj, text);
- case "object":
- switch (typeof text) {
- case "object":
- return comparator(obj, text);
- default:
- for ( var objKey in obj) {
- if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
- return true;
- }
- }
- break;
- }
- return false;
- case "array":
- for ( var i = 0; i < obj.length; i++) {
- if (search(obj[i], text)) {
- return true;
- }
- }
- return false;
- default:
- return false;
- }
- };
- switch (typeof expression) {
- case "boolean":
- case "number":
- case "string":
- // Set up expression object and fall through
- expression = {$:expression};
- // jshint -W086
- case "object":
- // jshint +W086
- for (var key_4 in expression) {
- if (key_4 == '$') {
- (function() {
- if (!expression[key_4]) return;
- var path = key_4;
- predicates.push(function(value) {
- return search(value, expression[path]);
- });
- })();
- } else {
- (function() {
- if (typeof(expression[key_4]) == 'undefined') { return; }
- var path = key_4;
- predicates.push(function(value) {
- return search(getter(value,path), expression[path]);
- });
- })();
- }
- }
- break;
- case 'function':
- predicates.push(expression);
- break;
- default:
- return array;
- }
- var filtered = [];
- for ( var j = 0; j < array.length; j++) {
- var value = array[j];
- if (predicates.check(value)) {
- filtered.push(value);
- }
- }
- return filtered;
- };
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:currency
- * @function
- *
- * @description
- * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
- * symbol for current locale is used.
- *
- * @param {number} amount Input to filter.
- * @param {string=} symbol Currency symbol or identifier to be displayed.
- * @returns {string} Formatted number.
- *
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.amount = 1234.56;
- }
- </script>
- <div ng-controller="Ctrl">
- <input type="number" ng-model="amount"> <br>
- default currency symbol ($): {{amount | currency}}<br>
- custom currency identifier (USD$): {{amount | currency:"USD$"}}
- </div>
- </doc:source>
- <doc:scenario>
- it('should init with 1234.56', function() {
- expect(binding('amount | currency')).toBe('$1,234.56');
- expect(binding('amount | currency:"USD$"')).toBe('USD$1,234.56');
- });
- it('should update', function() {
- input('amount').enter('-1234');
- expect(binding('amount | currency')).toBe('($1,234.00)');
- expect(binding('amount | currency:"USD$"')).toBe('(USD$1,234.00)');
- });
- </doc:scenario>
- </doc:example>
- */
-currencyFilter.$inject = ['$locale'];
-function currencyFilter($locale) {
- var formats = $locale.NUMBER_FORMATS;
- return function(amount, currencySymbol){
- if (isUndefined(currencySymbol)) currencySymbol = formats.CURRENCY_SYM;
- return formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, 2).
- replace(/\u00A4/g, currencySymbol);
- };
-}
-
-/**
- * @ngdoc filter
- * @name ng.filter:number
- * @function
- *
- * @description
- * Formats a number as text.
- *
- * If the input is not a number an empty string is returned.
- *
- * @param {number|string} number Number to format.
- * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
- * If this is not provided then the fraction size is computed from the current locale's number
- * formatting pattern. In the case of the default locale, it will be 3.
- * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.val = 1234.56789;
- }
- </script>
- <div ng-controller="Ctrl">
- Enter number: <input ng-model='val'><br>
- Default formatting: {{val | number}}<br>
- No fractions: {{val | number:0}}<br>
- Negative number: {{-val | number:4}}
- </div>
- </doc:source>
- <doc:scenario>
- it('should format numbers', function() {
- expect(binding('val | number')).toBe('1,234.568');
- expect(binding('val | number:0')).toBe('1,235');
- expect(binding('-val | number:4')).toBe('-1,234.5679');
- });
-
- it('should update', function() {
- input('val').enter('3374.333');
- expect(binding('val | number')).toBe('3,374.333');
- expect(binding('val | number:0')).toBe('3,374');
- expect(binding('-val | number:4')).toBe('-3,374.3330');
- });
- </doc:scenario>
- </doc:example>
- */
-
-
-numberFilter.$inject = ['$locale'];
-function numberFilter($locale) {
- var formats = $locale.NUMBER_FORMATS;
- return function(number, fractionSize) {
- return formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
- fractionSize);
- };
-}
-
-var DECIMAL_SEP = '.';
-function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
- if (isNaN(number) || !isFinite(number)) return '';
-
- var isNegative = number < 0;
- number = Math.abs(number);
- var numStr = number + '',
- formatedText = '',
- parts = [];
-
- var hasExponent = false;
- if (numStr.indexOf('e') !== -1) {
- var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
- if (match && match[2] == '-' && match[3] > fractionSize + 1) {
- numStr = '0';
- } else {
- formatedText = numStr;
- hasExponent = true;
- }
- }
-
- if (!hasExponent) {
- var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
-
- // determine fractionSize if it is not specified
- if (isUndefined(fractionSize)) {
- fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
- }
-
- var pow = Math.pow(10, fractionSize);
- number = Math.round(number * pow) / pow;
- var fraction = ('' + number).split(DECIMAL_SEP);
- var whole = fraction[0];
- fraction = fraction[1] || '';
-
- var i, pos = 0,
- lgroup = pattern.lgSize,
- group = pattern.gSize;
-
- if (whole.length >= (lgroup + group)) {
- pos = whole.length - lgroup;
- for (i = 0; i < pos; i++) {
- if ((pos - i)%group === 0 && i !== 0) {
- formatedText += groupSep;
- }
- formatedText += whole.charAt(i);
- }
- }
-
- for (i = pos; i < whole.length; i++) {
- if ((whole.length - i)%lgroup === 0 && i !== 0) {
- formatedText += groupSep;
- }
- formatedText += whole.charAt(i);
- }
-
- // format fraction part.
- while(fraction.length < fractionSize) {
- fraction += '0';
- }
-
- if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
- } else {
-
- if (fractionSize > 0 && number > -1 && number < 1) {
- formatedText = number.toFixed(fractionSize);
- }
- }
-
- parts.push(isNegative ? pattern.negPre : pattern.posPre);
- parts.push(formatedText);
- parts.push(isNegative ? pattern.negSuf : pattern.posSuf);
- return parts.join('');
-}
-
-function padNumber(num, digits, trim) {
- var neg = '';
- if (num < 0) {
- neg = '-';
- num = -num;
- }
- num = '' + num;
- while(num.length < digits) num = '0' + num;
- if (trim)
- num = num.substr(num.length - digits);
- return neg + num;
-}
-
-
-function dateGetter(name, size, offset, trim) {
- offset = offset || 0;
- return function(date) {
- var value = date['get' + name]();
- if (offset > 0 || value > -offset)
- value += offset;
- if (value === 0 && offset == -12 ) value = 12;
- return padNumber(value, size, trim);
- };
-}
-
-function dateStrGetter(name, shortForm) {
- return function(date, formats) {
- var value = date['get' + name]();
- var get = uppercase(shortForm ? ('SHORT' + name) : name);
-
- return formats[get][value];
- };
-}
-
-function timeZoneGetter(date) {
- var zone = -1 * date.getTimezoneOffset();
- var paddedZone = (zone >= 0) ? "+" : "";
-
- paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
- padNumber(Math.abs(zone % 60), 2);
-
- return paddedZone;
-}
-
-function ampmGetter(date, formats) {
- return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
-}
-
-var DATE_FORMATS = {
- yyyy: dateGetter('FullYear', 4),
- yy: dateGetter('FullYear', 2, 0, true),
- y: dateGetter('FullYear', 1),
- MMMM: dateStrGetter('Month'),
- MMM: dateStrGetter('Month', true),
- MM: dateGetter('Month', 2, 1),
- M: dateGetter('Month', 1, 1),
- dd: dateGetter('Date', 2),
- d: dateGetter('Date', 1),
- HH: dateGetter('Hours', 2),
- H: dateGetter('Hours', 1),
- hh: dateGetter('Hours', 2, -12),
- h: dateGetter('Hours', 1, -12),
- mm: dateGetter('Minutes', 2),
- m: dateGetter('Minutes', 1),
- ss: dateGetter('Seconds', 2),
- s: dateGetter('Seconds', 1),
- // while ISO 8601 requires fractions to be prefixed with `.` or `,`
- // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
- sss: dateGetter('Milliseconds', 3),
- EEEE: dateStrGetter('Day'),
- EEE: dateStrGetter('Day', true),
- a: ampmGetter,
- Z: timeZoneGetter
-};
-
-var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,
- NUMBER_STRING = /^\-?\d+$/;
-
-/**
- * @ngdoc filter
- * @name ng.filter:date
- * @function
- *
- * @description
- * Formats `date` to a string based on the requested `format`.
- *
- * `format` string can be composed of the following elements:
- *
- * * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
- * * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
- * * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
- * * `'MMMM'`: Month in year (January-December)
- * * `'MMM'`: Month in year (Jan-Dec)
- * * `'MM'`: Month in year, padded (01-12)
- * * `'M'`: Month in year (1-12)
- * * `'dd'`: Day in month, padded (01-31)
- * * `'d'`: Day in month (1-31)
- * * `'EEEE'`: Day in Week,(Sunday-Saturday)
- * * `'EEE'`: Day in Week, (Sun-Sat)
- * * `'HH'`: Hour in day, padded (00-23)
- * * `'H'`: Hour in day (0-23)
- * * `'hh'`: Hour in am/pm, padded (01-12)
- * * `'h'`: Hour in am/pm, (1-12)
- * * `'mm'`: Minute in hour, padded (00-59)
- * * `'m'`: Minute in hour (0-59)
- * * `'ss'`: Second in minute, padded (00-59)
- * * `'s'`: Second in minute (0-59)
- * * `'.sss' or ',sss'`: Millisecond in second, padded (000-999)
- * * `'a'`: am/pm marker
- * * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
- *
- * `format` string can also be one of the following predefined
- * {@link guide/i18n localizable formats}:
- *
- * * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
- * (e.g. Sep 3, 2010 12:05:08 pm)
- * * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US locale (e.g. 9/3/10 12:05 pm)
- * * `'fullDate'`: equivalent to `'EEEE, MMMM d,y'` for en_US locale
- * (e.g. Friday, September 3, 2010)
- * * `'longDate'`: equivalent to `'MMMM d, y'` for en_US locale (e.g. September 3, 2010)
- * * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US locale (e.g. Sep 3, 2010)
- * * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
- * * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 pm)
- * * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 pm)
- *
- * `format` string can contain literal values. These need to be quoted with single quotes (e.g.
- * `"h 'in the morning'"`). In order to output single quote, use two single quotes in a sequence
- * (e.g. `"h 'o''clock'"`).
- *
- * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
- * number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.SSSZ and its
- * shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
- * specified in the string input, the time is considered to be in the local timezone.
- * @param {string=} format Formatting rules (see Description). If not specified,
- * `mediumDate` is used.
- * @returns {string} Formatted string or the input if input is not recognized as date/millis.
- *
- * @example
- <doc:example>
- <doc:source>
- <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
- {{1288323623006 | date:'medium'}}<br>
- <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
- {{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}<br>
- <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
- {{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}<br>
- </doc:source>
- <doc:scenario>
- it('should format date', function() {
- expect(binding("1288323623006 | date:'medium'")).
- toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
- expect(binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).
- toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
- expect(binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).
- toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
- });
- </doc:scenario>
- </doc:example>
- */
-dateFilter.$inject = ['$locale'];
-function dateFilter($locale) {
-
-
- var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
- // 1 2 3 4 5 6 7 8 9 10 11
- function jsonStringToDate(string) {
- var match;
- if (match = string.match(R_ISO8601_STR)) {
- var date = new Date(0),
- tzHour = 0,
- tzMin = 0,
- dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
- timeSetter = match[8] ? date.setUTCHours : date.setHours;
-
- if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
- }
- dateSetter.call(date, int(match[1]), int(match[2]) - 1, int(match[3]));
- var h = int(match[4]||0) - tzHour;
- var m = int(match[5]||0) - tzMin;
- var s = int(match[6]||0);
- var ms = Math.round(parseFloat('0.' + (match[7]||0)) * 1000);
- timeSetter.call(date, h, m, s, ms);
- return date;
- }
- return string;
- }
-
-
- return function(date, format) {
- var text = '',
- parts = [],
- fn, match;
-
- format = format || 'mediumDate';
- format = $locale.DATETIME_FORMATS[format] || format;
- if (isString(date)) {
- if (NUMBER_STRING.test(date)) {
- date = int(date);
- } else {
- date = jsonStringToDate(date);
- }
- }
-
- if (isNumber(date)) {
- date = new Date(date);
- }
-
- if (!isDate(date)) {
- return date;
- }
-
- while(format) {
- match = DATE_FORMATS_SPLIT.exec(format);
- if (match) {
- parts = concat(parts, match, 1);
- format = parts.pop();
- } else {
- parts.push(format);
- format = null;
- }
- }
-
- forEach(parts, function(value){
- fn = DATE_FORMATS[value];
- text += fn ? fn(date, $locale.DATETIME_FORMATS)
- : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
- });
-
- return text;
- };
-}
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:json
- * @function
- *
- * @description
- * Allows you to convert a JavaScript object into JSON string.
- *
- * This filter is mostly useful for debugging. When using the double curly {{value}} notation
- * the binding is automatically converted to JSON.
- *
- * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
- * @returns {string} JSON string.
- *
- *
- * @example:
- <doc:example>
- <doc:source>
- <pre>{{ {'name':'value'} | json }}</pre>
- </doc:source>
- <doc:scenario>
- it('should jsonify filtered objects', function() {
- expect(binding("{'name':'value'}")).toMatch(/\{\n "name": ?"value"\n}/);
- });
- </doc:scenario>
- </doc:example>
- *
- */
-function jsonFilter() {
- return function(object) {
- return toJson(object, true);
- };
-}
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:lowercase
- * @function
- * @description
- * Converts string to lowercase.
- * @see angular.lowercase
- */
-var lowercaseFilter = valueFn(lowercase);
-
-
-/**
- * @ngdoc filter
- * @name ng.filter:uppercase
- * @function
- * @description
- * Converts string to uppercase.
- * @see angular.uppercase
- */
-var uppercaseFilter = valueFn(uppercase);
-
-/**
- * @ngdoc function
- * @name ng.filter:limitTo
- * @function
- *
- * @description
- * Creates a new array or string containing only a specified number of elements. The elements
- * are taken from either the beginning or the end of the source array or string, as specified by
- * the value and sign (positive or negative) of `limit`.
- *
- * @param {Array|string} input Source array or string to be limited.
- * @param {string|number} limit The length of the returned array or string. If the `limit` number
- * is positive, `limit` number of items from the beginning of the source array/string are copied.
- * If the number is negative, `limit` number of items from the end of the source array/string
- * are copied. The `limit` will be trimmed if it exceeds `array.length`
- * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
- * had less than `limit` elements.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.numbers = [1,2,3,4,5,6,7,8,9];
- $scope.letters = "abcdefghi";
- $scope.numLimit = 3;
- $scope.letterLimit = 3;
- }
- </script>
- <div ng-controller="Ctrl">
- Limit {{numbers}} to: <input type="integer" ng-model="numLimit">
- <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
- Limit {{letters}} to: <input type="integer" ng-model="letterLimit">
- <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
- </div>
- </doc:source>
- <doc:scenario>
- it('should limit the number array to first three items', function() {
- expect(element('.doc-example-live input[ng-model=numLimit]').val()).toBe('3');
- expect(element('.doc-example-live input[ng-model=letterLimit]').val()).toBe('3');
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3]');
- expect(binding('letters | limitTo:letterLimit')).toEqual('abc');
- });
-
- it('should update the output when -3 is entered', function() {
- input('numLimit').enter(-3);
- input('letterLimit').enter(-3);
- expect(binding('numbers | limitTo:numLimit')).toEqual('[7,8,9]');
- expect(binding('letters | limitTo:letterLimit')).toEqual('ghi');
- });
-
- it('should not exceed the maximum size of input array', function() {
- input('numLimit').enter(100);
- input('letterLimit').enter(100);
- expect(binding('numbers | limitTo:numLimit')).toEqual('[1,2,3,4,5,6,7,8,9]');
- expect(binding('letters | limitTo:letterLimit')).toEqual('abcdefghi');
- });
- </doc:scenario>
- </doc:example>
- */
-function limitToFilter(){
- return function(input, limit) {
- if (!isArray(input) && !isString(input)) return input;
-
- limit = int(limit);
-
- if (isString(input)) {
- //NaN check on limit
- if (limit) {
- return limit >= 0 ? input.slice(0, limit) : input.slice(limit, input.length);
- } else {
- return "";
- }
- }
-
- var out = [],
- i, n;
-
- // if abs(limit) exceeds maximum length, trim it
- if (limit > input.length)
- limit = input.length;
- else if (limit < -input.length)
- limit = -input.length;
-
- if (limit > 0) {
- i = 0;
- n = limit;
- } else {
- i = input.length + limit;
- n = input.length;
- }
-
- for (; i<n; i++) {
- out.push(input[i]);
- }
-
- return out;
- };
-}
-
-/**
- * @ngdoc function
- * @name ng.filter:orderBy
- * @function
- *
- * @description
- * Orders a specified `array` by the `expression` predicate.
- *
- * @param {Array} array The array to sort.
- * @param {function(*)|string|Array.<(function(*)|string)>} expression A predicate to be
- * used by the comparator to determine the order of elements.
- *
- * Can be one of:
- *
- * - `function`: Getter function. The result of this function will be sorted using the
- * `<`, `=`, `>` operator.
- * - `string`: An Angular expression which evaluates to an object to order by, such as 'name'
- * to sort by a property called 'name'. Optionally prefixed with `+` or `-` to control
- * ascending or descending sort order (for example, +name or -name).
- * - `Array`: An array of function or string predicates. The first predicate in the array
- * is used for sorting, but when two items are equivalent, the next predicate is used.
- *
- * @param {boolean=} reverse Reverse the order the array.
- * @returns {Array} Sorted copy of the source array.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($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}]
- $scope.predicate = '-age';
- }
- </script>
- <div ng-controller="Ctrl">
- <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
- <hr/>
- [ <a href="" ng-click="predicate=''">unsorted</a> ]
- <table class="friend">
- <tr>
- <th><a href="" ng-click="predicate = 'name'; reverse=false">Name</a>
- (<a href="" ng-click="predicate = '-name'; reverse=false">^</a>)</th>
- <th><a href="" ng-click="predicate = 'phone'; reverse=!reverse">Phone Number</a></th>
- <th><a href="" ng-click="predicate = 'age'; reverse=!reverse">Age</a></th>
- </tr>
- <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
- <td>{{friend.name}}</td>
- <td>{{friend.phone}}</td>
- <td>{{friend.age}}</td>
- </tr>
- </table>
- </div>
- </doc:source>
- <doc:scenario>
- it('should be reverse ordered by aged', function() {
- expect(binding('predicate')).toBe('-age');
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
- toEqual(['35', '29', '21', '19', '10']);
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']);
- });
-
- it('should reorder the table when user selects different predicate', function() {
- element('.doc-example-live a:contains("Name")').click();
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']);
- expect(repeater('table.friend', 'friend in friends').column('friend.age')).
- toEqual(['35', '10', '29', '19', '21']);
-
- element('.doc-example-live a:contains("Phone")').click();
- expect(repeater('table.friend', 'friend in friends').column('friend.phone')).
- toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']);
- expect(repeater('table.friend', 'friend in friends').column('friend.name')).
- toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']);
- });
- </doc:scenario>
- </doc:example>
- */
-orderByFilter.$inject = ['$parse'];
-function orderByFilter($parse){
- return function(array, sortPredicate, reverseOrder) {
- if (!isArray(array)) return array;
- if (!sortPredicate) return array;
- sortPredicate = isArray(sortPredicate) ? sortPredicate: [sortPredicate];
- sortPredicate = map(sortPredicate, function(predicate){
- var descending = false, get = predicate || identity;
- if (isString(predicate)) {
- if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
- descending = predicate.charAt(0) == '-';
- predicate = predicate.substring(1);
- }
- get = $parse(predicate);
- }
- return reverseComparator(function(a,b){
- return compare(get(a),get(b));
- }, descending);
- });
- var arrayCopy = [];
- for ( var i = 0; i < array.length; i++) { arrayCopy.push(array[i]); }
- return arrayCopy.sort(reverseComparator(comparator, reverseOrder));
-
- function comparator(o1, o2){
- for ( var i = 0; i < sortPredicate.length; i++) {
- var comp = sortPredicate[i](o1, o2);
- if (comp !== 0) return comp;
- }
- return 0;
- }
- function reverseComparator(comp, descending) {
- return toBoolean(descending)
- ? function(a,b){return comp(b,a);}
- : comp;
- }
- function compare(v1, v2){
- var t1 = typeof v1;
- var t2 = typeof v2;
- if (t1 == t2) {
- if (t1 == "string") {
- v1 = v1.toLowerCase();
- v2 = v2.toLowerCase();
- }
- if (v1 === v2) return 0;
- return v1 < v2 ? -1 : 1;
- } else {
- return t1 < t2 ? -1 : 1;
- }
- }
- };
-}
-
-function ngDirective(directive) {
- if (isFunction(directive)) {
- directive = {
- link: directive
- };
- }
- directive.restrict = directive.restrict || 'AC';
- return valueFn(directive);
-}
-
-/**
- * @ngdoc directive
- * @name ng.directive:a
- * @restrict E
- *
- * @description
- * Modifies the default behavior of the html A tag so that the default action is prevented when
- * the href attribute is empty.
- *
- * This change permits the easy creation of action links with the `ngClick` directive
- * without changing the location or causing page reloads, e.g.:
- * `<a href="" ng-click="list.addItem()">Add Item</a>`
- */
-var htmlAnchorDirective = valueFn({
- restrict: 'E',
- compile: function(element, attr) {
-
- if (msie <= 8) {
-
- // turn <a href ng-click="..">link</a> into a stylable link in IE
- // but only if it doesn't have name attribute, in which case it's an anchor
- if (!attr.href && !attr.name) {
- attr.$set('href', '');
- }
-
- // add a comment node to anchors to workaround IE bug that causes element content to be reset
- // to new attribute content if attribute is updated with value containing @ and element also
- // contains value with @
- // see issue #1949
- element.append(document.createComment('IE fix'));
- }
-
- if (!attr.href && !attr.name) {
- return function(scope, element) {
- element.on('click', function(event){
- // if we have no href url, then don't navigate anywhere.
- if (!element.attr('href')) {
- event.preventDefault();
- }
- });
- };
- }
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngHref
- * @restrict A
- *
- * @description
- * Using Angular markup like `{{hash}}` in an href attribute will
- * make the link go to the wrong URL if the user clicks it before
- * Angular has a chance to replace the `{{hash}}` markup with its
- * value. Until Angular replaces the markup the link will be broken
- * and will most likely return a 404 error.
- *
- * The `ngHref` directive solves this problem.
- *
- * The wrong way to write it:
- * <pre>
- * <a href="http://www.gravatar.com/avatar/{{hash}}"/>
- * </pre>
- *
- * The correct way to write it:
- * <pre>
- * <a ng-href="http://www.gravatar.com/avatar/{{hash}}"/>
- * </pre>
- *
- * @element A
- * @param {template} ngHref any string which can contain `{{}}` markup.
- *
- * @example
- * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
- * in links and their different behaviors:
- <doc:example>
- <doc:source>
- <input ng-model="value" /><br />
- <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
- <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
- <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
- <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
- <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
- <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
- </doc:source>
- <doc:scenario>
- it('should execute ng-click but not reload when href without value', function() {
- element('#link-1').click();
- expect(input('value').val()).toEqual('1');
- expect(element('#link-1').attr('href')).toBe("");
- });
-
- it('should execute ng-click but not reload when href empty string', function() {
- element('#link-2').click();
- expect(input('value').val()).toEqual('2');
- expect(element('#link-2').attr('href')).toBe("");
- });
-
- it('should execute ng-click and change url when ng-href specified', function() {
- expect(element('#link-3').attr('href')).toBe("/123");
-
- element('#link-3').click();
- expect(browser().window().path()).toEqual('/123');
- });
-
- it('should execute ng-click but not reload when href empty string and name specified', function() {
- element('#link-4').click();
- expect(input('value').val()).toEqual('4');
- expect(element('#link-4').attr('href')).toBe('');
- });
-
- it('should execute ng-click but not reload when no href but name specified', function() {
- element('#link-5').click();
- expect(input('value').val()).toEqual('5');
- expect(element('#link-5').attr('href')).toBe(undefined);
- });
-
- it('should only change url when only ng-href', function() {
- input('value').enter('6');
- expect(element('#link-6').attr('href')).toBe('6');
-
- element('#link-6').click();
- expect(browser().location().url()).toEqual('/6');
- });
- </doc:scenario>
- </doc:example>
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSrc
- * @restrict A
- *
- * @description
- * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
- * work right: The browser will fetch from the URL with the literal
- * text `{{hash}}` until Angular replaces the expression inside
- * `{{hash}}`. The `ngSrc` directive solves this problem.
- *
- * The buggy way to write it:
- * <pre>
- * <img src="http://www.gravatar.com/avatar/{{hash}}"/>
- * </pre>
- *
- * The correct way to write it:
- * <pre>
- * <img ng-src="http://www.gravatar.com/avatar/{{hash}}"/>
- * </pre>
- *
- * @element IMG
- * @param {template} ngSrc any string which can contain `{{}}` markup.
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSrcset
- * @restrict A
- *
- * @description
- * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
- * work right: The browser will fetch from the URL with the literal
- * text `{{hash}}` until Angular replaces the expression inside
- * `{{hash}}`. The `ngSrcset` directive solves this problem.
- *
- * The buggy way to write it:
- * <pre>
- * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
- * </pre>
- *
- * The correct way to write it:
- * <pre>
- * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x"/>
- * </pre>
- *
- * @element IMG
- * @param {template} ngSrcset any string which can contain `{{}}` markup.
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngDisabled
- * @restrict A
- *
- * @description
- *
- * The following markup will make the button enabled on Chrome/Firefox but not on IE8 and older IEs:
- * <pre>
- * <div ng-init="scope = { isDisabled: false }">
- * <button disabled="{{scope.isDisabled}}">Disabled</button>
- * </div>
- * </pre>
- *
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as disabled. (Their presence means true and their absence means false.)
- * If we put an Angular interpolation expression into such an attribute then the
- * binding information would be lost when the browser removes the attribute.
- * The `ngDisabled` directive solves this problem for the `disabled` attribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
- *
- * @example
- <doc:example>
- <doc:source>
- Click me to toggle: <input type="checkbox" ng-model="checked"><br/>
- <button ng-model="button" ng-disabled="checked">Button</button>
- </doc:source>
- <doc:scenario>
- it('should toggle button', function() {
- expect(element('.doc-example-live :button').prop('disabled')).toBeFalsy();
- input('checked').check();
- expect(element('.doc-example-live :button').prop('disabled')).toBeTruthy();
- });
- </doc:scenario>
- </doc:example>
- *
- * @element INPUT
- * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
- * then special attribute "disabled" will be set on the element
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngChecked
- * @restrict A
- *
- * @description
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as checked. (Their presence means true and their absence means false.)
- * If we put an Angular interpolation expression into such an attribute then the
- * binding information would be lost when the browser removes the attribute.
- * The `ngChecked` directive solves this problem for the `checked` attribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
- * @example
- <doc:example>
- <doc:source>
- Check me to check both: <input type="checkbox" ng-model="master"><br/>
- <input id="checkSlave" type="checkbox" ng-checked="master">
- </doc:source>
- <doc:scenario>
- it('should check both checkBoxes', function() {
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeFalsy();
- input('master').check();
- expect(element('.doc-example-live #checkSlave').prop('checked')).toBeTruthy();
- });
- </doc:scenario>
- </doc:example>
- *
- * @element INPUT
- * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
- * then special attribute "checked" will be set on the element
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngReadonly
- * @restrict A
- *
- * @description
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as readonly. (Their presence means true and their absence means false.)
- * If we put an Angular interpolation expression into such an attribute then the
- * binding information would be lost when the browser removes the attribute.
- * The `ngReadonly` directive solves this problem for the `readonly` attribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
-
- * @example
- <doc:example>
- <doc:source>
- Check me to make text readonly: <input type="checkbox" ng-model="checked"><br/>
- <input type="text" ng-readonly="checked" value="I'm Angular"/>
- </doc:source>
- <doc:scenario>
- it('should toggle readonly attr', function() {
- expect(element('.doc-example-live :text').prop('readonly')).toBeFalsy();
- input('checked').check();
- expect(element('.doc-example-live :text').prop('readonly')).toBeTruthy();
- });
- </doc:scenario>
- </doc:example>
- *
- * @element INPUT
- * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
- * then special attribute "readonly" will be set on the element
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSelected
- * @restrict A
- *
- * @description
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as selected. (Their presence means true and their absence means false.)
- * If we put an Angular interpolation expression into such an attribute then the
- * binding information would be lost when the browser removes the attribute.
- * The `ngSelected` directive solves this problem for the `selected` atttribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
- * @example
- <doc:example>
- <doc:source>
- Check me to select: <input type="checkbox" ng-model="selected"><br/>
- <select>
- <option>Hello!</option>
- <option id="greet" ng-selected="selected">Greetings!</option>
- </select>
- </doc:source>
- <doc:scenario>
- it('should select Greetings!', function() {
- expect(element('.doc-example-live #greet').prop('selected')).toBeFalsy();
- input('selected').check();
- expect(element('.doc-example-live #greet').prop('selected')).toBeTruthy();
- });
- </doc:scenario>
- </doc:example>
- *
- * @element OPTION
- * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
- * then special attribute "selected" will be set on the element
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngOpen
- * @restrict A
- *
- * @description
- * The HTML specification does not require browsers to preserve the values of boolean attributes
- * such as open. (Their presence means true and their absence means false.)
- * If we put an Angular interpolation expression into such an attribute then the
- * binding information would be lost when the browser removes the attribute.
- * The `ngOpen` directive solves this problem for the `open` attribute.
- * This complementary directive is not removed by the browser and so provides
- * a permanent reliable place to store the binding information.
-
- *
- * @example
- <doc:example>
- <doc:source>
- Check me check multiple: <input type="checkbox" ng-model="open"><br/>
- <details id="details" ng-open="open">
- <summary>Show/Hide me</summary>
- </details>
- </doc:source>
- <doc:scenario>
- it('should toggle open', function() {
- expect(element('#details').prop('open')).toBeFalsy();
- input('open').check();
- expect(element('#details').prop('open')).toBeTruthy();
- });
- </doc:scenario>
- </doc:example>
- *
- * @element DETAILS
- * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
- * then special attribute "open" will be set on the element
- */
-
-var ngAttributeAliasDirectives = {};
-
-
-// boolean attrs are evaluated
-forEach(BOOLEAN_ATTR, function(propName, attrName) {
- // binding to multiple is not supported
- if (propName == "multiple") return;
-
- var normalized = directiveNormalize('ng-' + 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);
- });
- };
- }
- };
- };
-});
-
-
-// ng-src, ng-srcset, ng-href are interpolated
-forEach(['src', 'srcset', 'href'], function(attrName) {
- var normalized = directiveNormalize('ng-' + attrName);
- ngAttributeAliasDirectives[normalized] = function() {
- return {
- priority: 99, // it needs to run after the attributes are interpolated
- link: function(scope, element, attr) {
- attr.$observe(normalized, function(value) {
- if (!value)
- return;
-
- attr.$set(attrName, value);
-
- // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
- // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
- // to set the property as well to achieve the desired effect.
- // we use attr[attrName] value since $set can sanitize the url.
- if (msie) element.prop(attrName, attr[attrName]);
- });
- }
- };
- };
-});
-
-/* global -nullFormCtrl */
-var nullFormCtrl = {
- $addControl: noop,
- $removeControl: noop,
- $setValidity: noop,
- $setDirty: noop,
- $setPristine: noop
-};
-
-/**
- * @ngdoc object
- * @name ng.directive:form.FormController
- *
- * @property {boolean} $pristine True if user has not interacted with the form yet.
- * @property {boolean} $dirty True if user has already interacted with the form.
- * @property {boolean} $valid True if all of the containing forms and controls are valid.
- * @property {boolean} $invalid True if at least one containing control or form is invalid.
- *
- * @property {Object} $error Is an object hash, containing references to all invalid controls or
- * forms, where:
- *
- * - keys are validation tokens (error names),
- * - values are arrays of controls or forms that are invalid for given error name.
- *
- *
- * Built-in validation tokens:
- *
- * - `email`
- * - `max`
- * - `maxlength`
- * - `min`
- * - `minlength`
- * - `number`
- * - `pattern`
- * - `required`
- * - `url`
- *
- * @description
- * `FormController` keeps track of all its controls and nested forms as well as state of them,
- * such as being valid/invalid or dirty/pristine.
- *
- * Each {@link ng.directive:form form} directive creates an instance
- * of `FormController`.
- *
- */
-//asks for $scope to fool the BC controller module
-FormController.$inject = ['$element', '$attrs', '$scope'];
-function FormController(element, attrs) {
- var form = this,
- parentForm = element.parent().controller('form') || nullFormCtrl,
- invalidCount = 0, // used to easily determine if we are valid
- errors = form.$error = {},
- controls = [];
-
- // init state
- form.$name = attrs.name || attrs.ngForm;
- form.$dirty = false;
- form.$pristine = true;
- form.$valid = true;
- form.$invalid = false;
-
- parentForm.$addControl(form);
-
- // Setup initial state of the control
- element.addClass(PRISTINE_CLASS);
- toggleValidCss(true);
-
- // convenience method for easy toggling of classes
- function toggleValidCss(isValid, validationErrorKey) {
- validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
- element.
- removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
- addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
- }
-
- /**
- * @ngdoc function
- * @name ng.directive:form.FormController#$addControl
- * @methodOf ng.directive:form.FormController
- *
- * @description
- * Register a control with the form.
- *
- * Input elements using ngModelController do this automatically when they are linked.
- */
- form.$addControl = function(control) {
- // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
- // and not added to the scope. Now we throw an error.
- assertNotHasOwnProperty(control.$name, 'input');
- controls.push(control);
-
- if (control.$name) {
- form[control.$name] = control;
- }
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:form.FormController#$removeControl
- * @methodOf ng.directive:form.FormController
- *
- * @description
- * Deregister a control from the form.
- *
- * Input elements using ngModelController do this automatically when they are destroyed.
- */
- form.$removeControl = function(control) {
- if (control.$name && form[control.$name] === control) {
- delete form[control.$name];
- }
- forEach(errors, function(queue, validationToken) {
- form.$setValidity(validationToken, true, control);
- });
-
- arrayRemove(controls, control);
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:form.FormController#$setValidity
- * @methodOf ng.directive:form.FormController
- *
- * @description
- * Sets the validity of a form control.
- *
- * This method will also propagate to parent forms.
- */
- form.$setValidity = function(validationToken, isValid, control) {
- var queue = errors[validationToken];
-
- if (isValid) {
- if (queue) {
- arrayRemove(queue, control);
- if (!queue.length) {
- invalidCount--;
- if (!invalidCount) {
- toggleValidCss(isValid);
- form.$valid = true;
- form.$invalid = false;
- }
- errors[validationToken] = false;
- toggleValidCss(true, validationToken);
- parentForm.$setValidity(validationToken, true, form);
- }
- }
-
- } else {
- if (!invalidCount) {
- toggleValidCss(isValid);
- }
- if (queue) {
- if (includes(queue, control)) return;
- } else {
- errors[validationToken] = queue = [];
- invalidCount++;
- toggleValidCss(false, validationToken);
- parentForm.$setValidity(validationToken, false, form);
- }
- queue.push(control);
-
- form.$valid = false;
- form.$invalid = true;
- }
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:form.FormController#$setDirty
- * @methodOf ng.directive:form.FormController
- *
- * @description
- * Sets the form to a dirty state.
- *
- * This method can be called to add the 'ng-dirty' class and set the form to a dirty
- * state (ng-dirty class). This method will also propagate to parent forms.
- */
- form.$setDirty = function() {
- element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
- form.$dirty = true;
- form.$pristine = false;
- parentForm.$setDirty();
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:form.FormController#$setPristine
- * @methodOf ng.directive:form.FormController
- *
- * @description
- * Sets the form to its pristine state.
- *
- * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
- * state (ng-pristine class). This method will also propagate to all the controls contained
- * in this form.
- *
- * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
- * saving or resetting it.
- */
- form.$setPristine = function () {
- element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
- form.$dirty = false;
- form.$pristine = true;
- forEach(controls, function(control) {
- control.$setPristine();
- });
- };
-}
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngForm
- * @restrict EAC
- *
- * @description
- * Nestable alias of {@link ng.directive:form `form`} directive. HTML
- * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
- * sub-group of controls needs to be determined.
- *
- * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
- * related scope, under this name.
- *
- */
-
- /**
- * @ngdoc directive
- * @name ng.directive:form
- * @restrict E
- *
- * @description
- * Directive that instantiates
- * {@link ng.directive:form.FormController FormController}.
- *
- * If the `name` attribute is specified, the form controller is published onto the current scope under
- * this name.
- *
- * # 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
- * 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
- * using Angular validation directives in forms that are dynamically generated using the
- * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
- * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
- * `ngForm` directive and nest these in an outer `form` element.
- *
- *
- * # 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.
- *
- *
- * # Submitting a form and preventing the default action
- *
- * Since the role of forms in client-side Angular applications is different than in classical
- * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
- * page reload that sends the data to the server. Instead some javascript logic should be triggered
- * to handle the form submission in an application-specific way.
- *
- * For this reason, Angular prevents the default action (form submission to the server) unless the
- * `<form>` element has an `action` attribute specified.
- *
- * You can use one of the following two ways to specify what javascript method should be called when
- * a form is submitted:
- *
- * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
- * - {@link ng.directive:ngClick ngClick} directive on the first
- * button or input field of type submit (input[type=submit])
- *
- * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
- * or {@link ng.directive:ngClick ngClick} directives.
- * This is because of the following form submission rules in the HTML specification:
- *
- * - If a form has only one input field then hitting enter in this field triggers form submit
- * (`ngSubmit`)
- * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
- * doesn't trigger submit
- * - if a form has one or more input fields and one or more buttons or input[type=submit] then
- * hitting enter in any of the input fields will trigger the click handler on the *first* button or
- * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
- *
- * @param {string=} name Name of the form. If specified, the form controller will be published into
- * related scope, under this name.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.userType = 'guest';
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- userType: <input name="input" ng-model="userType" required>
- <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
- <tt>userType = {{userType}}</tt><br>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('userType')).toEqual('guest');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty', function() {
- input('userType').enter('');
- expect(binding('userType')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
- </doc:scenario>
- </doc:example>
- */
-var formDirectiveFactory = function(isNgForm) {
- return ['$timeout', function($timeout) {
- var formDirective = {
- name: 'form',
- restrict: isNgForm ? 'EAC' : 'E',
- controller: FormController,
- compile: function() {
- return {
- pre: function(scope, formElement, attr, controller) {
- if (!attr.action) {
- // we can't use jq events because if a form is destroyed during submission the default
- // action is not prevented. see #1238
- //
- // IE 9 is not affected because it doesn't fire a submit event and try to do a full
- // page reload if the form was destroyed by submission of the form via a click handler
- // on a button in the form. Looks like an IE9 specific bug.
- var preventDefaultListener = function(event) {
- event.preventDefault
- ? event.preventDefault()
- : event.returnValue = false; // IE
- };
-
- addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
-
- // unregister the preventDefault listener so that we don't not leak memory but in a
- // way that will achieve the prevention of the default action.
- formElement.on('$destroy', function() {
- $timeout(function() {
- removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
- }, 0, false);
- });
- }
-
- var parentFormCtrl = formElement.parent().controller('form'),
- alias = attr.name || attr.ngForm;
-
- if (alias) {
- setter(scope, alias, controller, alias);
- }
- if (parentFormCtrl) {
- formElement.on('$destroy', function() {
- parentFormCtrl.$removeControl(controller);
- if (alias) {
- setter(scope, alias, undefined, alias);
- }
- extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
- });
- }
- }
- };
- }
- };
-
- return formDirective;
- }];
-};
-
-var formDirective = formDirectiveFactory();
-var ngFormDirective = formDirectiveFactory(true);
-
-/* global
-
- -VALID_CLASS,
- -INVALID_CLASS,
- -PRISTINE_CLASS,
- -DIRTY_CLASS
-*/
-
-var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/;
-var EMAIL_REGEXP = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$/;
-var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/;
-
-var inputType = {
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.text
- *
- * @description
- * Standard HTML text input with angular data binding.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required Adds `required` validation error key if the value is not entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.text = 'guest';
- $scope.word = /^\s*\w*\s*$/;
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- Single word: <input type="text" name="input" ng-model="text"
- ng-pattern="word" required ng-trim="false">
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.pattern">
- Single word only!</span>
-
- <tt>text = {{text}}</tt><br/>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('text')).toEqual('guest');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty', function() {
- input('text').enter('');
- expect(binding('text')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
-
- it('should be invalid if multi word', function() {
- input('text').enter('hello world');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
-
- it('should not be trimmed', function() {
- input('text').enter('untrimmed ');
- expect(binding('text')).toEqual('untrimmed ');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
- </doc:scenario>
- </doc:example>
- */
- 'text': textInputType,
-
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.number
- *
- * @description
- * Text input with number validation and transformation. Sets the `number` validation
- * error if not a valid number.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
- * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
- * @param {string=} required Sets `required` validation error key if the value is not entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.value = 12;
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- Number: <input type="number" name="input" ng-model="value"
- min="0" max="99" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.number">
- Not valid number!</span>
- <tt>value = {{value}}</tt><br/>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('value')).toEqual('12');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty', function() {
- input('value').enter('');
- expect(binding('value')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
-
- it('should be invalid if over max', function() {
- input('value').enter('123');
- expect(binding('value')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
- </doc:scenario>
- </doc:example>
- */
- 'number': numberInputType,
-
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.url
- *
- * @description
- * Text input with URL validation. Sets the `url` validation error key if the content is not a
- * valid URL.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required Sets `required` validation error key if the value is not entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.text = 'http://google.com';
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- URL: <input type="url" name="input" ng-model="text" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.url">
- Not valid url!</span>
- <tt>text = {{text}}</tt><br/>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('text')).toEqual('http://google.com');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty', function() {
- input('text').enter('');
- expect(binding('text')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
-
- it('should be invalid if not url', function() {
- input('text').enter('xxx');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
- </doc:scenario>
- </doc:example>
- */
- 'url': urlInputType,
-
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.email
- *
- * @description
- * Text input with email validation. Sets the `email` validation error key if not a valid email
- * address.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required Sets `required` validation error key if the value is not entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.text = 'me@example.com';
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- Email: <input type="email" name="input" ng-model="text" required>
- <span class="error" ng-show="myForm.input.$error.required">
- Required!</span>
- <span class="error" ng-show="myForm.input.$error.email">
- Not valid email!</span>
- <tt>text = {{text}}</tt><br/>
- <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
- <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('text')).toEqual('me@example.com');
- expect(binding('myForm.input.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty', function() {
- input('text').enter('');
- expect(binding('text')).toEqual('');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
-
- it('should be invalid if not email', function() {
- input('text').enter('xxx');
- expect(binding('myForm.input.$valid')).toEqual('false');
- });
- </doc:scenario>
- </doc:example>
- */
- 'email': emailInputType,
-
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.radio
- *
- * @description
- * HTML radio button.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string} value The value to which the expression should be set when selected.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.color = 'blue';
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- <input type="radio" ng-model="color" value="red"> Red <br/>
- <input type="radio" ng-model="color" value="green"> Green <br/>
- <input type="radio" ng-model="color" value="blue"> Blue <br/>
- <tt>color = {{color}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should change state', function() {
- expect(binding('color')).toEqual('blue');
-
- input('color').select('red');
- expect(binding('color')).toEqual('red');
- });
- </doc:scenario>
- </doc:example>
- */
- 'radio': radioInputType,
-
-
- /**
- * @ngdoc inputType
- * @name ng.directive:input.checkbox
- *
- * @description
- * HTML checkbox.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} ngTrueValue The value to which the expression should be set when selected.
- * @param {string=} ngFalseValue The value to which the expression should be set when not selected.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.value1 = true;
- $scope.value2 = 'YES'
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- Value1: <input type="checkbox" ng-model="value1"> <br/>
- Value2: <input type="checkbox" ng-model="value2"
- ng-true-value="YES" ng-false-value="NO"> <br/>
- <tt>value1 = {{value1}}</tt><br/>
- <tt>value2 = {{value2}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should change state', function() {
- expect(binding('value1')).toEqual('true');
- expect(binding('value2')).toEqual('YES');
-
- input('value1').check();
- input('value2').check();
- expect(binding('value1')).toEqual('false');
- expect(binding('value2')).toEqual('NO');
- });
- </doc:scenario>
- </doc:example>
- */
- 'checkbox': checkboxInputType,
-
- 'hidden': noop,
- 'button': noop,
- 'submit': noop,
- 'reset': noop
-};
-
-
-function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- // In composition mode, users are still inputing intermediate text buffer,
- // hold the listener until composition is done.
- // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
- var composing = false;
-
- element.on('compositionstart', function() {
- composing = true;
- });
-
- element.on('compositionend', function() {
- composing = false;
- });
-
- var listener = function() {
- if (composing) return;
- var value = element.val();
-
- // By default we will trim the value
- // If the attribute ng-trim exists we will avoid trimming
- // e.g. <input ng-model="foo" ng-trim="false">
- if (toBoolean(attr.ngTrim || 'T')) {
- value = trim(value);
- }
-
- if (ctrl.$viewValue !== value) {
- scope.$apply(function() {
- ctrl.$setViewValue(value);
- });
- }
- };
-
- // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
- // input event on backspace, delete or cut
- if ($sniffer.hasEvent('input')) {
- element.on('input', listener);
- } else {
- var timeout;
-
- var deferListener = function() {
- if (!timeout) {
- timeout = $browser.defer(function() {
- listener();
- timeout = null;
- });
- }
- };
-
- element.on('keydown', function(event) {
- var key = event.keyCode;
-
- // ignore
- // command modifiers arrows
- if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
-
- deferListener();
- });
-
- // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
- if ($sniffer.hasEvent('paste')) {
- element.on('paste cut', deferListener);
- }
- }
-
- // if user paste into input using mouse on older browser
- // or form autocomplete on newer browser, we need "change" event to catch it
- element.on('change', listener);
-
- ctrl.$render = function() {
- element.val(ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue);
- };
-
- // pattern validator
- var pattern = attr.ngPattern,
- 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) {
- match = pattern.match(/^\/(.*)\/([gim]*)$/);
- if (match) {
- pattern = new RegExp(match[1], match[2]);
- patternValidator = function(value) {
- return validate(pattern, value);
- };
- } else {
- patternValidator = function(value) {
- var patternObj = scope.$eval(pattern);
-
- if (!patternObj || !patternObj.test) {
- throw minErr('ngPattern')('noregexp',
- 'Expected {0} to be a RegExp but was {1}. Element: {2}', pattern,
- patternObj, startingTag(element));
- }
- return validate(patternObj, value);
- };
- }
-
- ctrl.$formatters.push(patternValidator);
- ctrl.$parsers.push(patternValidator);
- }
-
- // min length validator
- 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;
- }
- };
-
- ctrl.$parsers.push(minLengthValidator);
- ctrl.$formatters.push(minLengthValidator);
- }
-
- // max length validator
- 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;
- }
- };
-
- ctrl.$parsers.push(maxLengthValidator);
- ctrl.$formatters.push(maxLengthValidator);
- }
-}
-
-function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
- textInputType(scope, element, attr, ctrl, $sniffer, $browser);
-
- ctrl.$parsers.push(function(value) {
- var empty = ctrl.$isEmpty(value);
- if (empty || NUMBER_REGEXP.test(value)) {
- ctrl.$setValidity('number', true);
- return value === '' ? null : (empty ? value : parseFloat(value));
- } else {
- ctrl.$setValidity('number', false);
- return undefined;
- }
- });
-
- ctrl.$formatters.push(function(value) {
- return ctrl.$isEmpty(value) ? '' : '' + value;
- });
-
- 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;
- }
- };
-
- ctrl.$parsers.push(minValidator);
- ctrl.$formatters.push(minValidator);
- }
-
- 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;
- }
- };
-
- ctrl.$parsers.push(maxValidator);
- ctrl.$formatters.push(maxValidator);
- }
-
- ctrl.$formatters.push(function(value) {
-
- if (ctrl.$isEmpty(value) || isNumber(value)) {
- ctrl.$setValidity('number', true);
- return value;
- } else {
- ctrl.$setValidity('number', false);
- return undefined;
- }
- });
-}
-
-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;
- }
- };
-
- ctrl.$formatters.push(urlValidator);
- ctrl.$parsers.push(urlValidator);
-}
-
-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;
- }
- };
-
- ctrl.$formatters.push(emailValidator);
- ctrl.$parsers.push(emailValidator);
-}
-
-function radioInputType(scope, element, attr, ctrl) {
- // make the name unique, if not defined
- if (isUndefined(attr.name)) {
- element.attr('name', nextUid());
- }
-
- element.on('click', function() {
- if (element[0].checked) {
- scope.$apply(function() {
- ctrl.$setViewValue(attr.value);
- });
- }
- });
-
- ctrl.$render = function() {
- var value = attr.value;
- element[0].checked = (value == ctrl.$viewValue);
- };
-
- attr.$observe('value', ctrl.$render);
-}
-
-function checkboxInputType(scope, element, attr, ctrl) {
- var trueValue = attr.ngTrueValue,
- falseValue = attr.ngFalseValue;
-
- if (!isString(trueValue)) trueValue = true;
- if (!isString(falseValue)) falseValue = false;
-
- element.on('click', function() {
- scope.$apply(function() {
- ctrl.$setViewValue(element[0].checked);
- });
- });
-
- ctrl.$render = function() {
- element[0].checked = ctrl.$viewValue;
- };
-
- // Override the standard `$isEmpty` because a value of `false` means empty in a checkbox.
- ctrl.$isEmpty = function(value) {
- return value !== trueValue;
- };
-
- ctrl.$formatters.push(function(value) {
- return value === trueValue;
- });
-
- ctrl.$parsers.push(function(value) {
- return value ? trueValue : falseValue;
- });
-}
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:textarea
- * @restrict E
- *
- * @description
- * HTML textarea element control with angular data-binding. The data-binding and validation
- * properties of this element are exactly the same as those of the
- * {@link ng.directive:input input element}.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required Sets `required` validation error key if the value is not entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:input
- * @restrict E
- *
- * @description
- * HTML input element control with angular data-binding. Input control follows HTML5 input types
- * and polyfills the HTML5 validation behavior for older browsers.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required Sets `required` validation error key if the value is not entered.
- * @param {boolean=} ngRequired Sets `required` attribute if set to true
- * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
- * minlength.
- * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
- * maxlength.
- * @param {string=} ngPattern Sets `pattern` validation error key if the value does not match the
- * RegExp pattern expression. Expected value is `/regexp/` for inline patterns or `regexp` for
- * patterns defined as scope expressions.
- * @param {string=} ngChange Angular expression to be executed when input changes due to user
- * interaction with the input element.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.user = {name: 'guest', last: 'visitor'};
- }
- </script>
- <div ng-controller="Ctrl">
- <form name="myForm">
- User name: <input type="text" name="userName" ng-model="user.name" required>
- <span class="error" ng-show="myForm.userName.$error.required">
- Required!</span><br>
- Last name: <input type="text" name="lastName" ng-model="user.last"
- ng-minlength="3" ng-maxlength="10">
- <span class="error" ng-show="myForm.lastName.$error.minlength">
- Too short!</span>
- <span class="error" ng-show="myForm.lastName.$error.maxlength">
- Too long!</span><br>
- </form>
- <hr>
- <tt>user = {{user}}</tt><br/>
- <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br>
- <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br>
- <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br>
- <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
- <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br>
- <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br>
- </div>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('user')).toEqual('{"name":"guest","last":"visitor"}');
- expect(binding('myForm.userName.$valid')).toEqual('true');
- expect(binding('myForm.$valid')).toEqual('true');
- });
-
- it('should be invalid if empty when required', function() {
- input('user.name').enter('');
- expect(binding('user')).toEqual('{"last":"visitor"}');
- expect(binding('myForm.userName.$valid')).toEqual('false');
- expect(binding('myForm.$valid')).toEqual('false');
- });
-
- it('should be valid if empty when min length is set', function() {
- input('user.last').enter('');
- expect(binding('user')).toEqual('{"name":"guest","last":""}');
- expect(binding('myForm.lastName.$valid')).toEqual('true');
- expect(binding('myForm.$valid')).toEqual('true');
- });
-
- it('should be invalid if less than required min length', function() {
- input('user.last').enter('xx');
- expect(binding('user')).toEqual('{"name":"guest"}');
- expect(binding('myForm.lastName.$valid')).toEqual('false');
- expect(binding('myForm.lastName.$error')).toMatch(/minlength/);
- expect(binding('myForm.$valid')).toEqual('false');
- });
-
- it('should be invalid if longer than max length', function() {
- input('user.last').enter('some ridiculously long name');
- expect(binding('user'))
- .toEqual('{"name":"guest"}');
- expect(binding('myForm.lastName.$valid')).toEqual('false');
- expect(binding('myForm.lastName.$error')).toMatch(/maxlength/);
- expect(binding('myForm.$valid')).toEqual('false');
- });
- </doc:scenario>
- </doc:example>
- */
-var inputDirective = ['$browser', '$sniffer', function($browser, $sniffer) {
- return {
- restrict: 'E',
- require: '?ngModel',
- link: function(scope, element, attr, ctrl) {
- if (ctrl) {
- (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrl, $sniffer,
- $browser);
- }
- }
- };
-}];
-
-var VALID_CLASS = 'ng-valid',
- INVALID_CLASS = 'ng-invalid',
- PRISTINE_CLASS = 'ng-pristine',
- DIRTY_CLASS = 'ng-dirty';
-
-/**
- * @ngdoc object
- * @name ng.directive:ngModel.NgModelController
- *
- * @property {string} $viewValue Actual string value in the view.
- * @property {*} $modelValue The value in the model, that the control is bound to.
- * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
- the control reads value from the DOM. Each function is called, in turn, passing the value
- through to the next. Used to sanitize / convert the value as well as validation.
- For validation, the parsers should update the validity state using
- {@link ng.directive:ngModel.NgModelController#methods_$setValidity $setValidity()},
- and return `undefined` for invalid values.
-
- *
- * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
- the model value changes. Each function is called, in turn, passing the value through to the
- next. Used to format / convert values for display in the control and validation.
- * <pre>
- * function formatter(value) {
- * if (value) {
- * return value.toUpperCase();
- * }
- * }
- * ngModel.$formatters.push(formatter);
- * </pre>
- *
- * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
- * view value has changed. It is called with no arguments, and its return value is ignored.
- * This can be used in place of additional $watches against the model value.
- *
- * @property {Object} $error An object hash with all errors as keys.
- *
- * @property {boolean} $pristine True if user has not interacted with the control yet.
- * @property {boolean} $dirty True if user has already interacted with the control.
- * @property {boolean} $valid True if there is no error.
- * @property {boolean} $invalid True if at least one error on the control.
- *
- * @description
- *
- * `NgModelController` provides API for the `ng-model` directive. The controller contains
- * services for data-binding, validation, CSS updates, and value formatting and parsing. It
- * purposefully does not contain any logic which deals with DOM rendering or listening to
- * DOM events. Such DOM related logic should be provided by other directives which make use of
- * `NgModelController` for data-binding.
- *
- * ## Custom Control Example
- * This example shows how to use `NgModelController` with a custom control to achieve
- * 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.
- *
- * <example module="customControl">
- <file name="style.css">
- [contenteditable] {
- border: 1px solid black;
- background-color: white;
- min-height: 20px;
- }
-
- .ng-invalid {
- border: 1px solid red;
- }
-
- </file>
- <file name="script.js">
- angular.module('customControl', []).
- directive('contenteditable', function() {
- return {
- restrict: 'A', // only activate on element attribute
- require: '?ngModel', // get a hold of NgModelController
- link: function(scope, element, attrs, ngModel) {
- if(!ngModel) return; // do nothing if no ng-model
-
- // Specify how UI should be updated
- ngModel.$render = function() {
- element.html(ngModel.$viewValue || '');
- };
-
- // Listen for change events to enable binding
- element.on('blur keyup change', function() {
- scope.$apply(read);
- });
- read(); // initialize
-
- // Write data to the model
- function read() {
- var html = element.html();
- // When we clear the content editable the browser leaves a <br> behind
- // If strip-br attribute is provided then we strip this out
- if( attrs.stripBr && html == '<br>' ) {
- html = '';
- }
- ngModel.$setViewValue(html);
- }
- }
- };
- });
- </file>
- <file name="index.html">
- <form name="myForm">
- <div contenteditable
- name="myWidget" ng-model="userContent"
- strip-br="true"
- required>Change me!</div>
- <span ng-show="myForm.myWidget.$error.required">Required!</span>
- <hr>
- <textarea ng-model="userContent"></textarea>
- </form>
- </file>
- <file name="scenario.js">
- it('should data-bind and become invalid', function() {
- var contentEditable = element('[contenteditable]');
-
- expect(contentEditable.text()).toEqual('Change me!');
- input('userContent').enter('');
- expect(contentEditable.text()).toEqual('');
- expect(contentEditable.prop('className')).toMatch(/ng-invalid-required/);
- });
- </file>
- * </example>
- *
- *
- */
-var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse',
- function($scope, $exceptionHandler, $attr, $element, $parse) {
- this.$viewValue = Number.NaN;
- this.$modelValue = Number.NaN;
- this.$parsers = [];
- this.$formatters = [];
- this.$viewChangeListeners = [];
- this.$pristine = true;
- this.$dirty = false;
- this.$valid = true;
- this.$invalid = false;
- this.$name = $attr.name;
-
- var ngModelGet = $parse($attr.ngModel),
- ngModelSet = ngModelGet.assign;
-
- if (!ngModelSet) {
- throw minErr('ngModel')('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
- $attr.ngModel, startingTag($element));
- }
-
- /**
- * @ngdoc function
- * @name ng.directive:ngModel.NgModelController#$render
- * @methodOf ng.directive:ngModel.NgModelController
- *
- * @description
- * Called when the view needs to be updated. It is expected that the user of the ng-model
- * directive will implement this method.
- */
- this.$render = noop;
-
- /**
- * @ngdoc function
- * @name { ng.directive:ngModel.NgModelController#$isEmpty
- * @methodOf ng.directive:ngModel.NgModelController
- *
- * @description
- * This is called when we need to determine if the value of the input is empty.
- *
- * For instance, the required directive does this to work out if the input has data or not.
- * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
- *
- * You can override this for input directives whose concept of being empty is different to the
- * default. The `checkboxInputType` directive does this because in its case a value of `false`
- * implies empty.
- */
- this.$isEmpty = function(value) {
- return isUndefined(value) || value === '' || value === null || value !== value;
- };
-
- var parentForm = $element.inheritedData('$formController') || nullFormCtrl,
- invalidCount = 0, // used to easily determine if we are valid
- $error = this.$error = {}; // keep invalid keys here
-
-
- // Setup initial state of the control
- $element.addClass(PRISTINE_CLASS);
- toggleValidCss(true);
-
- // convenience method for easy toggling of classes
- function toggleValidCss(isValid, validationErrorKey) {
- validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
- $element.
- removeClass((isValid ? INVALID_CLASS : VALID_CLASS) + validationErrorKey).
- addClass((isValid ? VALID_CLASS : INVALID_CLASS) + validationErrorKey);
- }
-
- /**
- * @ngdoc function
- * @name ng.directive:ngModel.NgModelController#$setValidity
- * @methodOf ng.directive:ngModel.NgModelController
- *
- * @description
- * Change the validity state, and notifies the form when the control changes validity. (i.e. it
- * does not notify form if given validator is already marked as invalid).
- *
- * This method should be called by validators - i.e. the parser or formatter functions.
- *
- * @param {string} validationErrorKey Name of the validator. the `validationErrorKey` will assign
- * to `$error[validationErrorKey]=isValid` so that it is available for data-binding.
- * The `validationErrorKey` should be in camelCase and will get converted into dash-case
- * for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
- * class and can be bound to as `{{someForm.someControl.$error.myError}}` .
- * @param {boolean} isValid Whether the current state is valid (true) or invalid (false).
- */
- this.$setValidity = function(validationErrorKey, isValid) {
- // Purposeful use of ! here to cast isValid to boolean in case it is undefined
- // jshint -W018
- if ($error[validationErrorKey] === !isValid) return;
- // jshint +W018
-
- if (isValid) {
- if ($error[validationErrorKey]) invalidCount--;
- if (!invalidCount) {
- toggleValidCss(true);
- this.$valid = true;
- this.$invalid = false;
- }
- } else {
- toggleValidCss(false);
- this.$invalid = true;
- this.$valid = false;
- invalidCount++;
- }
-
- $error[validationErrorKey] = !isValid;
- toggleValidCss(isValid, validationErrorKey);
-
- parentForm.$setValidity(validationErrorKey, isValid, this);
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:ngModel.NgModelController#$setPristine
- * @methodOf ng.directive:ngModel.NgModelController
- *
- * @description
- * Sets the control to its pristine state.
- *
- * This method can be called to remove the 'ng-dirty' class and set the control to its pristine
- * state (ng-pristine class).
- */
- this.$setPristine = function () {
- this.$dirty = false;
- this.$pristine = true;
- $element.removeClass(DIRTY_CLASS).addClass(PRISTINE_CLASS);
- };
-
- /**
- * @ngdoc function
- * @name ng.directive:ngModel.NgModelController#$setViewValue
- * @methodOf ng.directive:ngModel.NgModelController
- *
- * @description
- * Update the view value.
- *
- * This method should be called when the view value changes, typically from within a DOM event handler.
- * For example {@link ng.directive:input input} and
- * {@link ng.directive:select select} directives call it.
- *
- * It will update the $viewValue, then pass this value through each of the functions in `$parsers`,
- * which includes any validators. The value that comes out of this `$parsers` pipeline, be applied to
- * `$modelValue` and the **expression** specified in the `ng-model` attribute.
- *
- * Lastly, all the registered change listeners, in the `$viewChangeListeners` list, are called.
- *
- * Note that calling this function does not trigger a `$digest`.
- *
- * @param {string} value Value from the view.
- */
- this.$setViewValue = function(value) {
- this.$viewValue = value;
-
- // change to dirty
- if (this.$pristine) {
- this.$dirty = true;
- this.$pristine = false;
- $element.removeClass(PRISTINE_CLASS).addClass(DIRTY_CLASS);
- parentForm.$setDirty();
- }
-
- forEach(this.$parsers, function(fn) {
- value = fn(value);
- });
-
- if (this.$modelValue !== value) {
- this.$modelValue = value;
- ngModelSet($scope, value);
- forEach(this.$viewChangeListeners, function(listener) {
- try {
- listener();
- } catch(e) {
- $exceptionHandler(e);
- }
- });
- }
- };
-
- // model -> value
- var ctrl = this;
-
- $scope.$watch(function ngModelWatch() {
- var value = ngModelGet($scope);
-
- // if scope model value and ngModel value are out of sync
- if (ctrl.$modelValue !== value) {
-
- var formatters = ctrl.$formatters,
- idx = formatters.length;
-
- ctrl.$modelValue = value;
- while(idx--) {
- value = formatters[idx](value);
- }
-
- if (ctrl.$viewValue !== value) {
- ctrl.$viewValue = value;
- ctrl.$render();
- }
- }
-
- return value;
- });
-}];
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngModel
- *
- * @element input
- *
- * @description
- * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
- * property on the scope using {@link ng.directive:ngModel.NgModelController NgModelController},
- * which is created and exposed by this directive.
- *
- * `ngModel` is responsible for:
- *
- * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
- * require.
- * - Providing validation behavior (i.e. required, number, email, url).
- * - Keeping the state of the control (valid/invalid, dirty/pristine, validation errors).
- * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`).
- * - Registering the control with its parent {@link ng.directive:form form}.
- *
- * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
- * current scope. If the property doesn't already exist on this scope, it will be created
- * implicitly and added to the scope.
- *
- * For best practices on using `ngModel`, see:
- *
- * - {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes}
- *
- * For basic examples, how to use `ngModel`, see:
- *
- * - {@link ng.directive:input input}
- * - {@link ng.directive:input.text text}
- * - {@link ng.directive:input.checkbox checkbox}
- * - {@link ng.directive:input.radio radio}
- * - {@link ng.directive:input.number number}
- * - {@link ng.directive:input.email email}
- * - {@link ng.directive:input.url url}
- * - {@link ng.directive:select select}
- * - {@link ng.directive:textarea textarea}
- *
- */
-var ngModelDirective = function() {
- return {
- require: ['ngModel', '^?form'],
- controller: NgModelController,
- link: function(scope, element, attr, ctrls) {
- // notify others, especially parent forms
-
- var modelCtrl = ctrls[0],
- formCtrl = ctrls[1] || nullFormCtrl;
-
- formCtrl.$addControl(modelCtrl);
-
- scope.$on('$destroy', function() {
- formCtrl.$removeControl(modelCtrl);
- });
- }
- };
-};
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngChange
- *
- * @description
- * Evaluate given expression when user changes the input.
- * The expression is not evaluated when the value change is coming from the model.
- *
- * Note, this directive requires `ngModel` to be present.
- *
- * @element input
- * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
- * in input value.
- *
- * @example
- * <doc:example>
- * <doc:source>
- * <script>
- * function Controller($scope) {
- * $scope.counter = 0;
- * $scope.change = function() {
- * $scope.counter++;
- * };
- * }
- * </script>
- * <div ng-controller="Controller">
- * <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
- * <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
- * <label for="ng-change-example2">Confirmed</label><br />
- * debug = {{confirmed}}<br />
- * counter = {{counter}}
- * </div>
- * </doc:source>
- * <doc:scenario>
- * it('should evaluate the expression if changing from view', function() {
- * expect(binding('counter')).toEqual('0');
- * element('#ng-change-example1').click();
- * expect(binding('counter')).toEqual('1');
- * expect(binding('confirmed')).toEqual('true');
- * });
- *
- * it('should not evaluate the expression if changing from model', function() {
- * element('#ng-change-example2').click();
- * expect(binding('counter')).toEqual('0');
- * expect(binding('confirmed')).toEqual('true');
- * });
- * </doc:scenario>
- * </doc:example>
- */
-var ngChangeDirective = valueFn({
- require: 'ngModel',
- link: function(scope, element, attr, ctrl) {
- ctrl.$viewChangeListeners.push(function() {
- scope.$eval(attr.ngChange);
- });
- }
-});
-
-
-var requiredDirective = function() {
- return {
- require: '?ngModel',
- link: function(scope, elm, attr, ctrl) {
- if (!ctrl) return;
- attr.required = true; // force truthy in case we are on non input element
-
- var validator = function(value) {
- if (attr.required && ctrl.$isEmpty(value)) {
- ctrl.$setValidity('required', false);
- return;
- } else {
- ctrl.$setValidity('required', true);
- return value;
- }
- };
-
- ctrl.$formatters.push(validator);
- ctrl.$parsers.unshift(validator);
-
- attr.$observe('required', function() {
- validator(ctrl.$viewValue);
- });
- }
- };
-};
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngList
- *
- * @description
- * Text input that converts between a delimited string and an array of strings. The delimiter
- * can be a fixed string (by default a comma) or a regular expression.
- *
- * @element input
- * @param {string=} ngList optional delimiter that should be used to split the value. If
- * specified in form `/something/` then the value will be converted into a regular expression.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.names = ['igor', 'misko', 'vojta'];
- }
- </script>
- <form name="myForm" ng-controller="Ctrl">
- List: <input name="namesInput" ng-model="names" ng-list required>
- <span class="error" ng-show="myForm.namesInput.$error.required">
- Required!</span>
- <br>
- <tt>names = {{names}}</tt><br/>
- <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
- <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
- <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
- <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('names')).toEqual('["igor","misko","vojta"]');
- expect(binding('myForm.namesInput.$valid')).toEqual('true');
- expect(element('span.error').css('display')).toBe('none');
- });
-
- it('should be invalid if empty', function() {
- input('names').enter('');
- expect(binding('names')).toEqual('');
- expect(binding('myForm.namesInput.$valid')).toEqual('false');
- expect(element('span.error').css('display')).not().toBe('none');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngListDirective = function() {
- return {
- require: 'ngModel',
- link: function(scope, element, attr, ctrl) {
- var match = /\/(.*)\//.exec(attr.ngList),
- separator = match && new RegExp(match[1]) || attr.ngList || ',';
-
- var parse = function(viewValue) {
- // If the viewValue is invalid (say required but empty) it will be `undefined`
- if (isUndefined(viewValue)) return;
-
- var list = [];
-
- if (viewValue) {
- forEach(viewValue.split(separator), function(value) {
- if (value) list.push(trim(value));
- });
- }
-
- return list;
- };
-
- ctrl.$parsers.push(parse);
- ctrl.$formatters.push(function(value) {
- if (isArray(value)) {
- return value.join(', ');
- }
-
- return undefined;
- });
-
- // Override the standard $isEmpty because an empty array means the input is empty.
- ctrl.$isEmpty = function(value) {
- return !value || !value.length;
- };
- }
- };
-};
-
-
-var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
-/**
- * @ngdoc directive
- * @name ng.directive:ngValue
- *
- * @description
- * Binds the given expression to the value of `input[select]` or `input[radio]`, so
- * that when the element is selected, the `ngModel` of that element is set to the
- * bound value.
- *
- * `ngValue` is useful when dynamically generating lists of radio buttons using `ng-repeat`, as
- * shown below.
- *
- * @element input
- * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
- * of the `input` element
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.names = ['pizza', 'unicorns', 'robots'];
- $scope.my = { favorite: 'unicorns' };
- }
- </script>
- <form ng-controller="Ctrl">
- <h2>Which is your favorite?</h2>
- <label ng-repeat="name in names" for="{{name}}">
- {{name}}
- <input type="radio"
- ng-model="my.favorite"
- ng-value="name"
- id="{{name}}"
- name="favorite">
- </label>
- <div>You chose {{my.favorite}}</div>
- </form>
- </doc:source>
- <doc:scenario>
- it('should initialize to model', function() {
- expect(binding('my.favorite')).toEqual('unicorns');
- });
- it('should bind the values to the inputs', function() {
- input('my.favorite').select('pizza');
- expect(binding('my.favorite')).toEqual('pizza');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngValueDirective = function() {
- return {
- priority: 100,
- compile: function(tpl, tplAttr) {
- if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
- return function ngValueConstantLink(scope, elm, attr) {
- attr.$set('value', scope.$eval(attr.ngValue));
- };
- } else {
- return function ngValueLink(scope, elm, attr) {
- scope.$watch(attr.ngValue, function valueWatchAction(value) {
- attr.$set('value', value);
- });
- };
- }
- }
- };
-};
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngBind
- * @restrict AC
- *
- * @description
- * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
- * with the value of a given expression, and to update the text content when the value of that
- * expression changes.
- *
- * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
- * `{{ expression }}` which is similar but less verbose.
- *
- * It is preferrable to use `ngBind` instead of `{{ expression }}` when a template is momentarily
- * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
- * element attribute, it makes the bindings invisible to the user while the page is loading.
- *
- * An alternative solution to this problem would be using the
- * {@link ng.directive:ngCloak ngCloak} directive.
- *
- *
- * @element ANY
- * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
- *
- * @example
- * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.name = 'Whirled';
- }
- </script>
- <div ng-controller="Ctrl">
- Enter name: <input type="text" ng-model="name"><br>
- Hello <span ng-bind="name"></span>!
- </div>
- </doc:source>
- <doc:scenario>
- it('should check ng-bind', function() {
- expect(using('.doc-example-live').binding('name')).toBe('Whirled');
- using('.doc-example-live').input('name').enter('world');
- expect(using('.doc-example-live').binding('name')).toBe('world');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngBindDirective = ngDirective(function(scope, element, attr) {
- element.addClass('ng-binding').data('$binding', attr.ngBind);
- scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
- // We are purposefully using == here rather than === because we want to
- // catch when value is "null or undefined"
- // jshint -W041
- element.text(value == undefined ? '' : value);
- });
-});
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngBindTemplate
- *
- * @description
- * The `ngBindTemplate` directive specifies that the element
- * text content should be replaced with the interpolation of the template
- * in the `ngBindTemplate` attribute.
- * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
- * expressions. This directive is needed since some HTML elements
- * (such as TITLE and OPTION) cannot contain SPAN elements.
- *
- * @element ANY
- * @param {string} ngBindTemplate template of form
- * <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
- *
- * @example
- * Try it here: enter text in text box and watch the greeting change.
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.salutation = 'Hello';
- $scope.name = 'World';
- }
- </script>
- <div ng-controller="Ctrl">
- Salutation: <input type="text" ng-model="salutation"><br>
- Name: <input type="text" ng-model="name"><br>
- <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
- </div>
- </doc:source>
- <doc:scenario>
- it('should check ng-bind', function() {
- expect(using('.doc-example-live').binding('salutation')).
- toBe('Hello');
- expect(using('.doc-example-live').binding('name')).
- toBe('World');
- using('.doc-example-live').input('salutation').enter('Greetings');
- using('.doc-example-live').input('name').enter('user');
- expect(using('.doc-example-live').binding('salutation')).
- toBe('Greetings');
- expect(using('.doc-example-live').binding('name')).
- toBe('user');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngBindTemplateDirective = ['$interpolate', function($interpolate) {
- return function(scope, element, attr) {
- // TODO: move this to scenario runner
- var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
- element.addClass('ng-binding').data('$binding', interpolateFn);
- attr.$observe('ngBindTemplate', function(value) {
- element.text(value);
- });
- };
-}];
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngBindHtml
- *
- * @description
- * Creates a binding that will innerHTML the result of evaluating the `expression` into the current
- * element in a secure way. By default, the innerHTML-ed content will be sanitized using the {@link
- * ngSanitize.$sanitize $sanitize} service. To utilize this functionality, ensure that `$sanitize`
- * is available, for example, by including {@link ngSanitize} in your module's dependencies (not in
- * core Angular.) You may also bypass sanitization for values you know are safe. To do so, bind to
- * an explicitly trusted value via {@link ng.$sce#methods_trustAsHtml $sce.trustAsHtml}. See the example
- * under {@link ng.$sce#Example Strict Contextual Escaping (SCE)}.
- *
- * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
- * will have an exception (instead of an exploit.)
- *
- * @element ANY
- * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
- *
- * @example
- Try it here: enter text in text box and watch the greeting change.
-
- <example module="ngBindHtmlExample" deps="angular-sanitize.js">
- <file name="index.html">
- <div ng-controller="ngBindHtmlCtrl">
- <p ng-bind-html="myHTML"></p>
- </div>
- </file>
-
- <file name="script.js">
- angular.module('ngBindHtmlExample', ['ngSanitize'])
-
- .controller('ngBindHtmlCtrl', ['$scope', function ngBindHtmlCtrl($scope) {
- $scope.myHTML =
- 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>';
- }]);
- </file>
-
- <file name="scenario.js">
- it('should check ng-bind-html', function() {
- expect(using('.doc-example-live').binding('myHTML')).
- toBe(
- 'I am an <code>HTML</code>string with <a href="#">links!</a> and other <em>stuff</em>'
- );
- });
- </file>
- </example>
- */
-var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) {
- return function(scope, element, attr) {
- element.addClass('ng-binding').data('$binding', attr.ngBindHtml);
-
- var parsed = $parse(attr.ngBindHtml);
- function getStringValue() { return (parsed(scope) || '').toString(); }
-
- scope.$watch(getStringValue, function ngBindHtmlWatchAction(value) {
- element.html($sce.getTrustedHtml(parsed(scope)) || '');
- });
- };
-}];
-
-function classDirective(name, selector) {
- name = 'ngClass' + name;
- return function() {
- return {
- restrict: 'AC',
- link: function(scope, element, attr) {
- var oldVal;
-
- scope.$watch(attr[name], ngClassWatchAction, true);
-
- attr.$observe('class', function(value) {
- ngClassWatchAction(scope.$eval(attr[name]));
- });
-
-
- if (name !== 'ngClass') {
- scope.$watch('$index', function($index, old$index) {
- // jshint bitwise: false
- var mod = $index & 1;
- if (mod !== old$index & 1) {
- var classes = flattenClasses(scope.$eval(attr[name]));
- mod === selector ?
- attr.$addClass(classes) :
- attr.$removeClass(classes);
- }
- });
- }
-
-
- function ngClassWatchAction(newVal) {
- if (selector === true || scope.$index % 2 === selector) {
- var newClasses = flattenClasses(newVal || '');
- if(!oldVal) {
- attr.$addClass(newClasses);
- } else if(!equals(newVal,oldVal)) {
- attr.$updateClass(newClasses, flattenClasses(oldVal));
- }
- }
- oldVal = copy(newVal);
- }
-
-
- function flattenClasses(classVal) {
- if(isArray(classVal)) {
- return classVal.join(' ');
- } else if (isObject(classVal)) {
- var classes = [], i = 0;
- forEach(classVal, function(v, k) {
- if (v) {
- classes.push(k);
- }
- });
- return classes.join(' ');
- }
-
- return classVal;
- }
- }
- };
- };
-}
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngClass
- * @restrict AC
- *
- * @description
- * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
- * an expression that represents all classes to be added.
- *
- * The directive won't add duplicate classes if a particular class was already set.
- *
- * When the expression changes, the previously added classes are removed and only then the
- * new classes are added.
- *
- * @animations
- * add - happens just before the class is applied to the element
- * remove - happens just before the class is removed from the element
- *
- * @element ANY
- * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
- * of the evaluation can be a string representing space delimited class
- * names, an array, or a map of class names to boolean values. In the case of a map, the
- * names of the properties whose values are truthy will be added as css classes to the
- * element.
- *
- * @example Example that demonstrates basic bindings via ngClass directive.
- <example>
- <file name="index.html">
- <p ng-class="{strike: deleted, bold: important, red: error}">Map Syntax Example</p>
- <input type="checkbox" ng-model="deleted"> deleted (apply "strike" class)<br>
- <input type="checkbox" ng-model="important"> important (apply "bold" class)<br>
- <input type="checkbox" ng-model="error"> error (apply "red" class)
- <hr>
- <p ng-class="style">Using String Syntax</p>
- <input type="text" ng-model="style" placeholder="Type: bold strike red">
- <hr>
- <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
- <input ng-model="style1" placeholder="Type: bold, strike or red"><br>
- <input ng-model="style2" placeholder="Type: bold, strike or red"><br>
- <input ng-model="style3" placeholder="Type: bold, strike or red"><br>
- </file>
- <file name="style.css">
- .strike {
- text-decoration: line-through;
- }
- .bold {
- font-weight: bold;
- }
- .red {
- color: red;
- }
- </file>
- <file name="scenario.js">
- it('should let you toggle the class', function() {
-
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/bold/);
- expect(element('.doc-example-live p:first').prop('className')).not().toMatch(/red/);
-
- input('important').check();
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/bold/);
-
- input('error').check();
- expect(element('.doc-example-live p:first').prop('className')).toMatch(/red/);
- });
-
- it('should let you toggle string example', function() {
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('');
- input('style').enter('red');
- expect(element('.doc-example-live p:nth-of-type(2)').prop('className')).toBe('red');
- });
-
- it('array example should have 3 classes', function() {
- expect(element('.doc-example-live p:last').prop('className')).toBe('');
- input('style1').enter('bold');
- input('style2').enter('strike');
- input('style3').enter('red');
- expect(element('.doc-example-live p:last').prop('className')).toBe('bold strike red');
- });
- </file>
- </example>
-
- ## Animations
-
- The example below demonstrates how to perform animations using ngClass.
-
- <example animations="true">
- <file name="index.html">
- <input type="button" value="set" ng-click="myVar='my-class'">
- <input type="button" value="clear" ng-click="myVar=''">
- <br>
- <span class="base-class" ng-class="myVar">Sample Text</span>
- </file>
- <file name="style.css">
- .base-class {
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- }
-
- .base-class.my-class {
- color: red;
- font-size:3em;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-class', function() {
- expect(element('.doc-example-live span').prop('className')).not().
- toMatch(/my-class/);
-
- using('.doc-example-live').element(':button:first').click();
-
- expect(element('.doc-example-live span').prop('className')).
- toMatch(/my-class/);
-
- using('.doc-example-live').element(':button:last').click();
-
- expect(element('.doc-example-live span').prop('className')).not().
- toMatch(/my-class/);
- });
- </file>
- </example>
-
-
- ## ngClass and pre-existing CSS3 Transitions/Animations
- The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
- Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
- any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
- to view the step by step details of {@link ngAnimate.$animate#methods_addclass $animate.addClass} and
- {@link ngAnimate.$animate#methods_removeclass $animate.removeClass}.
- */
-var ngClassDirective = classDirective('', true);
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngClassOdd
- * @restrict AC
- *
- * @description
- * The `ngClassOdd` and `ngClassEven` directives work exactly as
- * {@link ng.directive:ngClass ngClass}, except they work in
- * conjunction with `ngRepeat` and take effect only on odd (even) rows.
- *
- * This directive can be applied only within the scope of an
- * {@link ng.directive:ngRepeat ngRepeat}.
- *
- * @element ANY
- * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
- * of the evaluation can be a string representing space delimited class names or an array.
- *
- * @example
- <example>
- <file name="index.html">
- <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
- <li ng-repeat="name in names">
- <span ng-class-odd="'odd'" ng-class-even="'even'">
- {{name}}
- </span>
- </li>
- </ol>
- </file>
- <file name="style.css">
- .odd {
- color: red;
- }
- .even {
- color: blue;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-class-odd and ng-class-even', function() {
- expect(element('.doc-example-live li:first span').prop('className')).
- toMatch(/odd/);
- expect(element('.doc-example-live li:last span').prop('className')).
- toMatch(/even/);
- });
- </file>
- </example>
- */
-var ngClassOddDirective = classDirective('Odd', 0);
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngClassEven
- * @restrict AC
- *
- * @description
- * The `ngClassOdd` and `ngClassEven` directives work exactly as
- * {@link ng.directive:ngClass ngClass}, except they work in
- * conjunction with `ngRepeat` and take effect only on odd (even) rows.
- *
- * This directive can be applied only within the scope of an
- * {@link ng.directive:ngRepeat ngRepeat}.
- *
- * @element ANY
- * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
- * result of the evaluation can be a string representing space delimited class names or an array.
- *
- * @example
- <example>
- <file name="index.html">
- <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
- <li ng-repeat="name in names">
- <span ng-class-odd="'odd'" ng-class-even="'even'">
- {{name}}
- </span>
- </li>
- </ol>
- </file>
- <file name="style.css">
- .odd {
- color: red;
- }
- .even {
- color: blue;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-class-odd and ng-class-even', function() {
- expect(element('.doc-example-live li:first span').prop('className')).
- toMatch(/odd/);
- expect(element('.doc-example-live li:last span').prop('className')).
- toMatch(/even/);
- });
- </file>
- </example>
- */
-var ngClassEvenDirective = classDirective('Even', 1);
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngCloak
- * @restrict AC
- *
- * @description
- * The `ngCloak` directive is used to prevent the Angular html template from being briefly
- * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
- * directive to avoid the undesirable flicker effect caused by the html template display.
- *
- * The directive can be applied to the `<body>` element, but the preferred usage is to apply
- * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
- * of the browser view.
- *
- * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
- * `angular.min.js`.
- * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
- *
- * <pre>
- * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
- * display: none !important;
- * }
- * </pre>
- *
- * When this css rule is loaded by the browser, all html elements (including their children) that
- * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
- * during the compilation of the template it deletes the `ngCloak` element attribute, making
- * the compiled element visible.
- *
- * For the best result, the `angular.js` script must be loaded in the head section of the html
- * document; alternatively, the css rule above must be included in the external stylesheet of the
- * application.
- *
- * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they
- * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css
- * class `ngCloak` in addition to the `ngCloak` directive as shown in the example below.
- *
- * @element ANY
- *
- * @example
- <doc:example>
- <doc:source>
- <div id="template1" ng-cloak>{{ 'hello' }}</div>
- <div id="template2" ng-cloak class="ng-cloak">{{ 'hello IE7' }}</div>
- </doc:source>
- <doc:scenario>
- it('should remove the template directive and css class', function() {
- expect(element('.doc-example-live #template1').attr('ng-cloak')).
- not().toBeDefined();
- expect(element('.doc-example-live #template2').attr('ng-cloak')).
- not().toBeDefined();
- });
- </doc:scenario>
- </doc:example>
- *
- */
-var ngCloakDirective = ngDirective({
- compile: function(element, attr) {
- attr.$set('ngCloak', undefined);
- element.removeClass('ng-cloak');
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngController
- *
- * @description
- * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
- * supports the principles behind the Model-View-Controller design pattern.
- *
- * MVC components in angular:
- *
- * * Model — The Model is scope properties; scopes are attached to the DOM where scope properties
- * are accessed through bindings.
- * * View — The template (HTML with data bindings) that is rendered into the View.
- * * Controller — The `ngController` directive specifies a Controller class; the class contains business
- * logic behind the application to decorate the scope with functions and values
- *
- * Note that you can also attach controllers to the DOM by declaring it in a route definition
- * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
- * again using `ng-controller` in the template itself. This will cause the controller to be attached
- * and executed twice.
- *
- * @element ANY
- * @scope
- * @param {expression} ngController Name of a globally accessible constructor function or an
- * {@link guide/expression expression} that on the current scope evaluates to a
- * constructor function. The controller instance can be published into a scope property
- * by specifying `as propertyName`.
- *
- * @example
- * Here is a simple form for editing user contact information. Adding, removing, clearing, and
- * greeting are methods declared on the controller (see source tab). These methods can
- * easily be called from the angular markup. Notice that the scope becomes the `this` for the
- * controller's instance. This allows for easy access to the view data from the controller. Also
- * notice that any changes to the data are automatically reflected in the View without the need
- * for a manual update. The example is shown in two different declaration styles you may use
- * according to preference.
- <doc:example>
- <doc:source>
- <script>
- function SettingsController1() {
- this.name = "John Smith";
- this.contacts = [
- {type: 'phone', value: '408 555 1212'},
- {type: 'email', value: 'john.smith@example.org'} ];
- };
-
- SettingsController1.prototype.greet = function() {
- alert(this.name);
- };
-
- SettingsController1.prototype.addContact = function() {
- this.contacts.push({type: 'email', value: 'yourname@example.org'});
- };
-
- SettingsController1.prototype.removeContact = function(contactToRemove) {
- var index = this.contacts.indexOf(contactToRemove);
- this.contacts.splice(index, 1);
- };
-
- SettingsController1.prototype.clearContact = function(contact) {
- contact.type = 'phone';
- contact.value = '';
- };
- </script>
- <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
- Name: <input type="text" ng-model="settings.name"/>
- [ <a href="" ng-click="settings.greet()">greet</a> ]<br/>
- Contact:
- <ul>
- <li ng-repeat="contact in settings.contacts">
- <select ng-model="contact.type">
- <option>phone</option>
- <option>email</option>
- </select>
- <input type="text" ng-model="contact.value"/>
- [ <a href="" ng-click="settings.clearContact(contact)">clear</a>
- | <a href="" ng-click="settings.removeContact(contact)">X</a> ]
- </li>
- <li>[ <a href="" ng-click="settings.addContact()">add</a> ]</li>
- </ul>
- </div>
- </doc:source>
- <doc:scenario>
- it('should check controller as', function() {
- expect(element('#ctrl-as-exmpl>:input').val()).toBe('John Smith');
- expect(element('#ctrl-as-exmpl li:nth-child(1) input').val())
- .toBe('408 555 1212');
- expect(element('#ctrl-as-exmpl li:nth-child(2) input').val())
- .toBe('john.smith@example.org');
-
- element('#ctrl-as-exmpl li:first a:contains("clear")').click();
- expect(element('#ctrl-as-exmpl li:first input').val()).toBe('');
-
- element('#ctrl-as-exmpl li:last a:contains("add")').click();
- expect(element('#ctrl-as-exmpl li:nth-child(3) input').val())
- .toBe('yourname@example.org');
- });
- </doc:scenario>
- </doc:example>
- <doc:example>
- <doc:source>
- <script>
- function SettingsController2($scope) {
- $scope.name = "John Smith";
- $scope.contacts = [
- {type:'phone', value:'408 555 1212'},
- {type:'email', value:'john.smith@example.org'} ];
-
- $scope.greet = function() {
- alert(this.name);
- };
-
- $scope.addContact = function() {
- this.contacts.push({type:'email', value:'yourname@example.org'});
- };
-
- $scope.removeContact = function(contactToRemove) {
- var index = this.contacts.indexOf(contactToRemove);
- this.contacts.splice(index, 1);
- };
-
- $scope.clearContact = function(contact) {
- contact.type = 'phone';
- contact.value = '';
- };
- }
- </script>
- <div id="ctrl-exmpl" ng-controller="SettingsController2">
- Name: <input type="text" ng-model="name"/>
- [ <a href="" ng-click="greet()">greet</a> ]<br/>
- Contact:
- <ul>
- <li ng-repeat="contact in contacts">
- <select ng-model="contact.type">
- <option>phone</option>
- <option>email</option>
- </select>
- <input type="text" ng-model="contact.value"/>
- [ <a href="" ng-click="clearContact(contact)">clear</a>
- | <a href="" ng-click="removeContact(contact)">X</a> ]
- </li>
- <li>[ <a href="" ng-click="addContact()">add</a> ]</li>
- </ul>
- </div>
- </doc:source>
- <doc:scenario>
- it('should check controller', function() {
- expect(element('#ctrl-exmpl>:input').val()).toBe('John Smith');
- expect(element('#ctrl-exmpl li:nth-child(1) input').val())
- .toBe('408 555 1212');
- expect(element('#ctrl-exmpl li:nth-child(2) input').val())
- .toBe('john.smith@example.org');
-
- element('#ctrl-exmpl li:first a:contains("clear")').click();
- expect(element('#ctrl-exmpl li:first input').val()).toBe('');
-
- element('#ctrl-exmpl li:last a:contains("add")').click();
- expect(element('#ctrl-exmpl li:nth-child(3) input').val())
- .toBe('yourname@example.org');
- });
- </doc:scenario>
- </doc:example>
-
- */
-var ngControllerDirective = [function() {
- return {
- scope: true,
- controller: '@',
- priority: 500
- };
-}];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngCsp
- *
- * @element html
- * @description
- * Enables [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) support.
- *
- * This is necessary when developing things like Google Chrome Extensions.
- *
- * CSP forbids apps to use `eval` or `Function(string)` generated functions (among other things).
- * For us to be compatible, we just need to implement the "getterFn" in $parse without violating
- * any of these restrictions.
- *
- * AngularJS uses `Function(string)` generated functions as a speed optimization. Applying the `ngCsp`
- * directive will cause Angular to use CSP compatibility mode. When this mode is on AngularJS will
- * evaluate all expressions up to 30% slower than in non-CSP mode, but no security violations will
- * be raised.
- *
- * CSP forbids JavaScript to inline stylesheet rules. In non CSP mode Angular automatically
- * includes some CSS rules (e.g. {@link ng.directive:ngCloak ngCloak}).
- * To make those directives work in CSP mode, include the `angular-csp.css` manually.
- *
- * In order to use this feature put the `ngCsp` directive on the root element of the application.
- *
- * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
- *
- * @example
- * This example shows how to apply the `ngCsp` directive to the `html` tag.
- <pre>
- <!doctype html>
- <html ng-app ng-csp>
- ...
- ...
- </html>
- </pre>
- */
-
-// ngCsp is not implemented as a proper directive any more, because we need it be processed while we bootstrap
-// the system (before $parse is instantiated), for this reason we just have a csp() fn that looks for ng-csp attribute
-// anywhere in the current doc
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngClick
- *
- * @description
- * The ngClick directive allows you to specify custom behavior when
- * an element is clicked.
- *
- * @element ANY
- * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
- * click. (Event object is available as `$event`)
- *
- * @example
- <doc:example>
- <doc:source>
- <button ng-click="count = count + 1" ng-init="count=0">
- Increment
- </button>
- count: {{count}}
- </doc:source>
- <doc:scenario>
- it('should check ng-click', function() {
- expect(binding('count')).toBe('0');
- element('.doc-example-live :button').click();
- expect(binding('count')).toBe('1');
- });
- </doc:scenario>
- </doc:example>
- */
-/*
- * A directive that allows creation of custom onclick handlers that are defined as angular
- * expressions and are compiled and executed within the current scope.
- *
- * Events that are handled via these handler are always configured not to propagate further.
- */
-var ngEventDirectives = {};
-forEach(
- 'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
- function(name) {
- var directiveName = directiveNormalize('ng-' + name);
- ngEventDirectives[directiveName] = ['$parse', function($parse) {
- return {
- compile: function($element, attr) {
- var fn = $parse(attr[directiveName]);
- return function(scope, element, attr) {
- element.on(lowercase(name), function(event) {
- scope.$apply(function() {
- fn(scope, {$event:event});
- });
- });
- };
- }
- };
- }];
- }
-);
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngDblclick
- *
- * @description
- * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
- *
- * @element ANY
- * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
- * a dblclick. (The Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMousedown
- *
- * @description
- * The ngMousedown directive allows you to specify custom behavior on mousedown event.
- *
- * @element ANY
- * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
- * mousedown. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMouseup
- *
- * @description
- * Specify custom behavior on mouseup event.
- *
- * @element ANY
- * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
- * mouseup. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMouseover
- *
- * @description
- * Specify custom behavior on mouseover event.
- *
- * @element ANY
- * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
- * mouseover. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMouseenter
- *
- * @description
- * Specify custom behavior on mouseenter event.
- *
- * @element ANY
- * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
- * mouseenter. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMouseleave
- *
- * @description
- * Specify custom behavior on mouseleave event.
- *
- * @element ANY
- * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
- * mouseleave. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngMousemove
- *
- * @description
- * Specify custom behavior on mousemove event.
- *
- * @element ANY
- * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
- * mousemove. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngKeydown
- *
- * @description
- * Specify custom behavior on keydown event.
- *
- * @element ANY
- * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
- * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngKeyup
- *
- * @description
- * Specify custom behavior on keyup event.
- *
- * @element ANY
- * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
- * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngKeypress
- *
- * @description
- * Specify custom behavior on keypress event.
- *
- * @element ANY
- * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
- * keypress. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSubmit
- *
- * @description
- * Enables binding angular expressions to onsubmit events.
- *
- * Additionally it prevents the default action (which for form means sending the request to the
- * server and reloading the current page) **but only if the form does not contain an `action`
- * attribute**.
- *
- * @element form
- * @param {expression} ngSubmit {@link guide/expression Expression} to eval. (Event object is available as `$event`)
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.list = [];
- $scope.text = 'hello';
- $scope.submit = function() {
- if (this.text) {
- this.list.push(this.text);
- this.text = '';
- }
- };
- }
- </script>
- <form ng-submit="submit()" ng-controller="Ctrl">
- Enter text and hit enter:
- <input type="text" ng-model="text" name="text" />
- <input type="submit" id="submit" value="Submit" />
- <pre>list={{list}}</pre>
- </form>
- </doc:source>
- <doc:scenario>
- it('should check ng-submit', function() {
- expect(binding('list')).toBe('[]');
- element('.doc-example-live #submit').click();
- expect(binding('list')).toBe('["hello"]');
- expect(input('text').val()).toBe('');
- });
- it('should ignore empty strings', function() {
- expect(binding('list')).toBe('[]');
- element('.doc-example-live #submit').click();
- element('.doc-example-live #submit').click();
- expect(binding('list')).toBe('["hello"]');
- });
- </doc:scenario>
- </doc:example>
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngFocus
- *
- * @description
- * Specify custom behavior on focus event.
- *
- * @element window, input, select, textarea, a
- * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
- * focus. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngBlur
- *
- * @description
- * Specify custom behavior on blur event.
- *
- * @element window, input, select, textarea, a
- * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
- * blur. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngCopy
- *
- * @description
- * Specify custom behavior on copy event.
- *
- * @element window, input, select, textarea, a
- * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
- * copy. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngCut
- *
- * @description
- * Specify custom behavior on cut event.
- *
- * @element window, input, select, textarea, a
- * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
- * cut. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngPaste
- *
- * @description
- * Specify custom behavior on paste event.
- *
- * @element window, input, select, textarea, a
- * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
- * paste. (Event object is available as `$event`)
- *
- * @example
- * See {@link ng.directive:ngClick ngClick}
- */
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngIf
- * @restrict A
- *
- * @description
- * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
- * {expression}. If the expression assigned to `ngIf` evaluates to a false
- * value then the element is removed from the DOM, otherwise a clone of the
- * element is reinserted into the DOM.
- *
- * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
- * element in the DOM rather than changing its visibility via the `display` css property. A common
- * case when this difference is significant is when using css selectors that rely on an element's
- * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
- *
- * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
- * is created when the element is restored. The scope created within `ngIf` inherits from
- * its parent scope using
- * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
- * An important implication of this is if `ngModel` is used within `ngIf` to bind to
- * a javascript primitive defined in the parent scope. In this case any modifications made to the
- * variable within the child scope will override (hide) the value in the parent scope.
- *
- * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
- * is if an element's class attribute is directly modified after it's compiled, using something like
- * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
- * the added class will be lost because the original compiled state is used to regenerate the element.
- *
- * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
- * and `leave` effects.
- *
- * @animations
- * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
- * leave - happens just before the ngIf contents are removed from the DOM
- *
- * @element ANY
- * @scope
- * @priority 600
- * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
- * the element is removed from the DOM tree. If it is truthy a copy of the compiled
- * element is added to the DOM tree.
- *
- * @example
- <example animations="true">
- <file name="index.html">
- Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
- Show when checked:
- <span ng-if="checked" class="animate-if">
- I'm removed when the checkbox is unchecked.
- </span>
- </file>
- <file name="animations.css">
- .animate-if {
- background:white;
- border:1px solid black;
- padding:10px;
- }
-
- /*
- The transition styles can also be placed on the CSS base class above
- */
- .animate-if.ng-enter, .animate-if.ng-leave {
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- }
-
- .animate-if.ng-enter,
- .animate-if.ng-leave.ng-leave-active {
- opacity:0;
- }
-
- .animate-if.ng-leave,
- .animate-if.ng-enter.ng-enter-active {
- opacity:1;
- }
- </file>
- </example>
- */
-var ngIfDirective = ['$animate', function($animate) {
- return {
- transclude: 'element',
- priority: 600,
- terminal: true,
- restrict: 'A',
- $$tlb: true,
- link: function ($scope, $element, $attr, ctrl, $transclude) {
- var block, childScope;
- $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
-
- if (toBoolean(value)) {
- if (!childScope) {
- childScope = $scope.$new();
- $transclude(childScope, function (clone) {
- clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
- // Note: We only need the first/last node of the cloned nodes.
- // However, we need to keep the reference to the jqlite wrapper as it might be changed later
- // by a directive with templateUrl when it's template arrives.
- block = {
- clone: clone
- };
- $animate.enter(clone, $element.parent(), $element);
- });
- }
- } else {
-
- if (childScope) {
- childScope.$destroy();
- childScope = null;
- }
-
- if (block) {
- $animate.leave(getBlockElements(block.clone));
- block = null;
- }
- }
- });
- }
- };
-}];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngInclude
- * @restrict ECA
- *
- * @description
- * Fetches, compiles and includes an external HTML fragment.
- *
- * By default, the template URL is restricted to the same domain and protocol as the
- * application document. This is done by calling {@link ng.$sce#methods_getTrustedResourceUrl
- * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
- * you may either {@link ng.$sceDelegateProvider#methods_resourceUrlWhitelist whitelist them} or
- * {@link ng.$sce#methods_trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
- * ng.$sce Strict Contextual Escaping}.
- *
- * In addition, the browser's
- * {@link https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest
- * Same Origin Policy} and {@link http://www.w3.org/TR/cors/ Cross-Origin Resource Sharing
- * (CORS)} policy may further restrict whether the template is successfully loaded.
- * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
- * access on some browsers.
- *
- * @animations
- * enter - animation is used to bring new content into the browser.
- * leave - animation is used to animate existing content away.
- *
- * The enter and leave animation occur concurrently.
- *
- * @scope
- * @priority 400
- *
- * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
- * make sure you wrap it in quotes, e.g. `src="'myPartialTemplate.html'"`.
- * @param {string=} onload Expression to evaluate when a new partial is loaded.
- *
- * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
- * $anchorScroll} to scroll the viewport after the content is loaded.
- *
- * - If the attribute is not set, disable scrolling.
- * - If the attribute is set without value, enable scrolling.
- * - Otherwise enable scrolling only if the expression evaluates to truthy value.
- *
- * @example
- <example animations="true">
- <file name="index.html">
- <div ng-controller="Ctrl">
- <select ng-model="template" ng-options="t.name for t in templates">
- <option value="">(blank)</option>
- </select>
- url of the template: <tt>{{template.url}}</tt>
- <hr/>
- <div class="slide-animate-container">
- <div class="slide-animate" ng-include="template.url"></div>
- </div>
- </div>
- </file>
- <file name="script.js">
- function Ctrl($scope) {
- $scope.templates =
- [ { name: 'template1.html', url: 'template1.html'}
- , { name: 'template2.html', url: 'template2.html'} ];
- $scope.template = $scope.templates[0];
- }
- </file>
- <file name="template1.html">
- Content of template1.html
- </file>
- <file name="template2.html">
- Content of template2.html
- </file>
- <file name="animations.css">
- .slide-animate-container {
- position:relative;
- background:white;
- border:1px solid black;
- height:40px;
- overflow:hidden;
- }
-
- .slide-animate {
- padding:10px;
- }
-
- .slide-animate.ng-enter, .slide-animate.ng-leave {
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-
- position:absolute;
- top:0;
- left:0;
- right:0;
- bottom:0;
- display:block;
- padding:10px;
- }
-
- .slide-animate.ng-enter {
- top:-50px;
- }
- .slide-animate.ng-enter.ng-enter-active {
- top:0;
- }
-
- .slide-animate.ng-leave {
- top:0;
- }
- .slide-animate.ng-leave.ng-leave-active {
- top:50px;
- }
- </file>
- <file name="scenario.js">
- it('should load template1.html', function() {
- expect(element('.doc-example-live [ng-include]').text()).
- toMatch(/Content of template1.html/);
- });
- it('should load template2.html', function() {
- select('template').option('1');
- expect(element('.doc-example-live [ng-include]').text()).
- toMatch(/Content of template2.html/);
- });
- it('should change to blank', function() {
- select('template').option('');
- expect(element('.doc-example-live [ng-include]')).toBe(undefined);
- });
- </file>
- </example>
- */
-
-
-/**
- * @ngdoc event
- * @name ng.directive:ngInclude#$includeContentRequested
- * @eventOf ng.directive:ngInclude
- * @eventType emit on the scope ngInclude was declared in
- * @description
- * Emitted every time the ngInclude content is requested.
- */
-
-
-/**
- * @ngdoc event
- * @name ng.directive:ngInclude#$includeContentLoaded
- * @eventOf ng.directive:ngInclude
- * @eventType emit on the current ngInclude scope
- * @description
- * Emitted every time the ngInclude content is reloaded.
- */
-var ngIncludeDirective = ['$http', '$templateCache', '$anchorScroll', '$animate', '$sce',
- function($http, $templateCache, $anchorScroll, $animate, $sce) {
- return {
- restrict: 'ECA',
- priority: 400,
- terminal: true,
- transclude: 'element',
- controller: angular.noop,
- compile: function(element, attr) {
- var srcExp = attr.ngInclude || attr.src,
- onloadExp = attr.onload || '',
- autoScrollExp = attr.autoscroll;
-
- return function(scope, $element, $attr, ctrl, $transclude) {
- var changeCounter = 0,
- currentScope,
- currentElement;
-
- var cleanupLastIncludeContent = function() {
- if (currentScope) {
- currentScope.$destroy();
- currentScope = null;
- }
- if(currentElement) {
- $animate.leave(currentElement);
- currentElement = null;
- }
- };
-
- scope.$watch($sce.parseAsResourceUrl(srcExp), function ngIncludeWatchAction(src) {
- var afterAnimation = function() {
- if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
- $anchorScroll();
- }
- };
- var thisChangeId = ++changeCounter;
-
- if (src) {
- $http.get(src, {cache: $templateCache}).success(function(response) {
- if (thisChangeId !== changeCounter) return;
- var newScope = scope.$new();
- ctrl.template = response;
-
- // Note: This will also link all children of ng-include that were contained in the original
- // html. If that content contains controllers, ... they could pollute/change the scope.
- // However, using ng-include on an element with additional content does not make sense...
- // Note: We can't remove them in the cloneAttchFn of $transclude as that
- // function is called before linking the content, which would apply child
- // directives to non existing elements.
- var clone = $transclude(newScope, function(clone) {
- cleanupLastIncludeContent();
- $animate.enter(clone, null, $element, afterAnimation);
- });
-
- currentScope = newScope;
- currentElement = clone;
-
- currentScope.$emit('$includeContentLoaded');
- scope.$eval(onloadExp);
- }).error(function() {
- if (thisChangeId === changeCounter) cleanupLastIncludeContent();
- });
- scope.$emit('$includeContentRequested');
- } else {
- cleanupLastIncludeContent();
- ctrl.template = null;
- }
- });
- };
- }
- };
-}];
-
-// This directive is called during the $transclude call of the first `ngInclude` directive.
-// It will replace and compile the content of the element with the loaded template.
-// We need this directive so that the element content is already filled when
-// the link function of another directive on the same element as ngInclude
-// is called.
-var ngIncludeFillContentDirective = ['$compile',
- function($compile) {
- return {
- restrict: 'ECA',
- priority: -400,
- require: 'ngInclude',
- link: function(scope, $element, $attr, ctrl) {
- $element.html(ctrl.template);
- $compile($element.contents())(scope);
- }
- };
- }];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngInit
- * @restrict AC
- *
- * @description
- * The `ngInit` directive allows you to evaluate an expression in the
- * current scope.
- *
- * <div class="alert alert-error">
- * The only appropriate use of `ngInit` for aliasing special properties of
- * {@link api/ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below. Besides this case, you
- * should use {@link guide/controller controllers} rather than `ngInit`
- * to initialize values on a scope.
- * </div>
- *
- * @priority 450
- *
- * @element ANY
- * @param {expression} ngInit {@link guide/expression Expression} to eval.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.list = [['a', 'b'], ['c', 'd']];
- }
- </script>
- <div ng-controller="Ctrl">
- <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
- <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
- <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
- </div>
- </div>
- </div>
- </doc:source>
- <doc:scenario>
- it('should alias index positions', function() {
- expect(element('.example-init').text())
- .toBe('list[ 0 ][ 0 ] = a;' +
- 'list[ 0 ][ 1 ] = b;' +
- 'list[ 1 ][ 0 ] = c;' +
- 'list[ 1 ][ 1 ] = d;');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngInitDirective = ngDirective({
- priority: 450,
- compile: function() {
- return {
- pre: function(scope, element, attrs) {
- scope.$eval(attrs.ngInit);
- }
- };
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngNonBindable
- * @restrict AC
- * @priority 1000
- *
- * @description
- * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
- * DOM element. This is useful if the element contains what appears to be Angular directives and
- * bindings but which should be ignored by Angular. This could be the case if you have a site that
- * displays snippets of code, for instance.
- *
- * @element ANY
- *
- * @example
- * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
- * but the one wrapped in `ngNonBindable` is left alone.
- *
- * @example
- <doc:example>
- <doc:source>
- <div>Normal: {{1 + 2}}</div>
- <div ng-non-bindable>Ignored: {{1 + 2}}</div>
- </doc:source>
- <doc:scenario>
- it('should check ng-non-bindable', function() {
- expect(using('.doc-example-live').binding('1 + 2')).toBe('3');
- expect(using('.doc-example-live').element('div:last').text()).
- toMatch(/1 \+ 2/);
- });
- </doc:scenario>
- </doc:example>
- */
-var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngPluralize
- * @restrict EA
- *
- * @description
- * # Overview
- * `ngPluralize` is a directive that displays messages according to en-US localization rules.
- * These rules are bundled with angular.js, but can be overridden
- * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
- * by specifying the mappings between
- * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
- * plural categories} and the strings to be displayed.
- *
- * # Plural categories and explicit number rules
- * There are two
- * {@link http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
- * plural categories} in Angular's default en-US locale: "one" and "other".
- *
- * While a plural category may match many numbers (for example, in en-US locale, "other" can match
- * any number that is not 1), an explicit number rule can only match one number. For example, the
- * explicit number rule for "3" matches the number 3. There are examples of plural categories
- * and explicit number rules throughout the rest of this documentation.
- *
- * # Configuring ngPluralize
- * You configure ngPluralize by providing 2 attributes: `count` and `when`.
- * You can also provide an optional attribute, `offset`.
- *
- * The value of the `count` attribute can be either a string or an {@link guide/expression
- * Angular expression}; these are evaluated on the current scope for its bound value.
- *
- * The `when` attribute specifies the mappings between plural categories and the actual
- * string to be displayed. The value of the attribute should be a JSON object.
- *
- * The following example shows how to configure ngPluralize:
- *
- * <pre>
- * <ng-pluralize count="personCount"
- when="{'0': 'Nobody is viewing.',
- * 'one': '1 person is viewing.',
- * 'other': '{} people are viewing.'}">
- * </ng-pluralize>
- *</pre>
- *
- * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
- * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
- * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
- * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
- * show "a dozen people are viewing".
- *
- * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
- * into pluralized strings. In the previous example, Angular will replace `{}` with
- * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
- * for <span ng-non-bindable>{{numberExpression}}</span>.
- *
- * # Configuring ngPluralize with offset
- * The `offset` attribute allows further customization of pluralized text, which can result in
- * a better user experience. For example, instead of the message "4 people are viewing this document",
- * you might display "John, Kate and 2 others are viewing this document".
- * The offset attribute allows you to offset a number by any desired value.
- * Let's take a look at an example:
- *
- * <pre>
- * <ng-pluralize count="personCount" offset=2
- * when="{'0': 'Nobody is viewing.',
- * '1': '{{person1}} is viewing.',
- * '2': '{{person1}} and {{person2}} are viewing.',
- * 'one': '{{person1}}, {{person2}} and one other person are viewing.',
- * 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
- * </ng-pluralize>
- * </pre>
- *
- * Notice that we are still using two plural categories(one, other), but we added
- * three explicit number rules 0, 1 and 2.
- * When one person, perhaps John, views the document, "John is viewing" will be shown.
- * When three people view the document, no explicit number rule is found, so
- * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
- * In this case, plural category 'one' is matched and "John, Marry and one other person are viewing"
- * is shown.
- *
- * Note that when you specify offsets, you must provide explicit number rules for
- * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
- * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
- * plural categories "one" and "other".
- *
- * @param {string|expression} count The variable to be bounded to.
- * @param {string} when The mapping between plural category to its corresponding strings.
- * @param {number=} offset Offset to deduct from the total number.
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.person1 = 'Igor';
- $scope.person2 = 'Misko';
- $scope.personCount = 1;
- }
- </script>
- <div ng-controller="Ctrl">
- Person 1:<input type="text" ng-model="person1" value="Igor" /><br/>
- Person 2:<input type="text" ng-model="person2" value="Misko" /><br/>
- Number of People:<input type="text" ng-model="personCount" value="1" /><br/>
-
- <!--- Example with simple pluralization rules for en locale --->
- Without Offset:
- <ng-pluralize count="personCount"
- when="{'0': 'Nobody is viewing.',
- 'one': '1 person is viewing.',
- 'other': '{} people are viewing.'}">
- </ng-pluralize><br>
-
- <!--- Example with offset --->
- With Offset(2):
- <ng-pluralize count="personCount" offset=2
- when="{'0': 'Nobody is viewing.',
- '1': '{{person1}} is viewing.',
- '2': '{{person1}} and {{person2}} are viewing.',
- 'one': '{{person1}}, {{person2}} and one other person are viewing.',
- 'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
- </ng-pluralize>
- </div>
- </doc:source>
- <doc:scenario>
- it('should show correct pluralized string', function() {
- expect(element('.doc-example-live ng-pluralize:first').text()).
- toBe('1 person is viewing.');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Igor is viewing.');
-
- using('.doc-example-live').input('personCount').enter('0');
- expect(element('.doc-example-live ng-pluralize:first').text()).
- toBe('Nobody is viewing.');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Nobody is viewing.');
-
- using('.doc-example-live').input('personCount').enter('2');
- expect(element('.doc-example-live ng-pluralize:first').text()).
- toBe('2 people are viewing.');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Igor and Misko are viewing.');
-
- using('.doc-example-live').input('personCount').enter('3');
- expect(element('.doc-example-live ng-pluralize:first').text()).
- toBe('3 people are viewing.');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Igor, Misko and one other person are viewing.');
-
- using('.doc-example-live').input('personCount').enter('4');
- expect(element('.doc-example-live ng-pluralize:first').text()).
- toBe('4 people are viewing.');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Igor, Misko and 2 other people are viewing.');
- });
-
- it('should show data-binded names', function() {
- using('.doc-example-live').input('personCount').enter('4');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Igor, Misko and 2 other people are viewing.');
-
- using('.doc-example-live').input('person1').enter('Di');
- using('.doc-example-live').input('person2').enter('Vojta');
- expect(element('.doc-example-live ng-pluralize:last').text()).
- toBe('Di, Vojta and 2 other people are viewing.');
- });
- </doc:scenario>
- </doc:example>
- */
-var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interpolate) {
- var BRACE = /{}/g;
- return {
- restrict: 'EA',
- link: function(scope, element, attr) {
- var numberExp = attr.count,
- whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
- offset = attr.offset || 0,
- whens = scope.$eval(whenExp) || {},
- whensExpFns = {},
- startSymbol = $interpolate.startSymbol(),
- endSymbol = $interpolate.endSymbol(),
- isWhen = /^when(Minus)?(.+)$/;
-
- forEach(attr, function(expression, attributeName) {
- if (isWhen.test(attributeName)) {
- whens[lowercase(attributeName.replace('when', '').replace('Minus', '-'))] =
- element.attr(attr.$attr[attributeName]);
- }
- });
- forEach(whens, function(expression, key) {
- whensExpFns[key] =
- $interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
- offset + endSymbol));
- });
-
- scope.$watch(function ngPluralizeWatch() {
- var value = parseFloat(scope.$eval(numberExp));
-
- if (!isNaN(value)) {
- //if explicit number rule such as 1, 2, 3... is defined, just use it. Otherwise,
- //check it against pluralization rules in $locale service
- if (!(value in whens)) value = $locale.pluralCat(value - offset);
- return whensExpFns[value](scope, element, true);
- } else {
- return '';
- }
- }, function ngPluralizeWatchAction(newVal) {
- element.text(newVal);
- });
- }
- };
-}];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngRepeat
- *
- * @description
- * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
- * instance gets its own scope, where the given loop variable is set to the current collection item,
- * and `$index` is set to the item index or key.
- *
- * Special properties are exposed on the local scope of each template instance, including:
- *
- * | Variable | Type | Details |
- * |-----------|-----------------|-----------------------------------------------------------------------------|
- * | `$index` | {@type number} | iterator offset of the repeated element (0..length-1) |
- * | `$first` | {@type boolean} | true if the repeated element is first in the iterator. |
- * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
- * | `$last` | {@type boolean} | true if the repeated element is last in the iterator. |
- * | `$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). |
- *
- *
- * # 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
- * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
- * The **ng-repeat-start** directive works the same as **ng-repeat**, but will repeat all the HTML code (including the tag it's defined on)
- * up to and including the ending HTML tag where **ng-repeat-end** is placed.
- *
- * The example below makes use of this feature:
- * <pre>
- * <header ng-repeat-start="item in items">
- * Header {{ item }}
- * </header>
- * <div class="body">
- * Body {{ item }}
- * </div>
- * <footer ng-repeat-end>
- * Footer {{ item }}
- * </footer>
- * </pre>
- *
- * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
- * <pre>
- * <header>
- * Header A
- * </header>
- * <div class="body">
- * Body A
- * </div>
- * <footer>
- * Footer A
- * </footer>
- * <header>
- * Header B
- * </header>
- * <div class="body">
- * Body B
- * </div>
- * <footer>
- * Footer B
- * </footer>
- * </pre>
- *
- * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
- * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
- *
- * @animations
- * enter - when a new item is added to the list or when an item is revealed after a filter
- * leave - when an item is removed from the list or when an item is filtered out
- * move - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
- *
- * @element ANY
- * @scope
- * @priority 1000
- * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
- * formats are currently supported:
- *
- * * `variable in expression` – where variable is the user defined loop variable and `expression`
- * is a scope expression giving the collection to enumerate.
- *
- * For example: `album in artist.albums`.
- *
- * * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
- * and `expression` is the scope expression giving the collection to enumerate.
- *
- * For example: `(name, age) in {'adam':10, 'amalie':12}`.
- *
- * * `variable in expression track by tracking_expression` – You can also provide an optional tracking function
- * which can be used to associate the objects in the collection with the DOM elements. If no tracking function
- * is specified the ng-repeat associates elements by identity in the collection. It is an error to have
- * more than one tracking function to resolve to the same key. (This would mean that two distinct objects are
- * mapped to the same DOM element, which is not possible.) Filters should be applied to the expression,
- * before specifying a tracking expression.
- *
- * For example: `item in items` is equivalent to `item in items track by $id(item)'. This implies that the DOM elements
- * will be associated by item identity in the array.
- *
- * For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
- * `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
- * with the corresponding item in the array by identity. Moving the same object in array would move the DOM
- * element in the same way in the DOM.
- *
- * For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
- * case the object identity does not matter. Two objects are considered equivalent as long as their `id`
- * property is same.
- *
- * For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
- * to items in conjunction with a tracking expression.
- *
- * @example
- * This example initializes the scope to a list of names and
- * then uses `ngRepeat` to display every person:
- <example animations="true">
- <file name="index.html">
- <div ng-init="friends = [
- {name:'John', age:25, gender:'boy'},
- {name:'Jessie', age:30, gender:'girl'},
- {name:'Johanna', age:28, gender:'girl'},
- {name:'Joy', age:15, gender:'girl'},
- {name:'Mary', age:28, gender:'girl'},
- {name:'Peter', age:95, gender:'boy'},
- {name:'Sebastian', age:50, gender:'boy'},
- {name:'Erika', age:27, gender:'girl'},
- {name:'Patrick', age:40, gender:'boy'},
- {name:'Samantha', age:60, gender:'girl'}
- ]">
- I have {{friends.length}} friends. They are:
- <input type="search" ng-model="q" placeholder="filter friends..." />
- <ul class="example-animate-container">
- <li class="animate-repeat" ng-repeat="friend in friends | filter:q">
- [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
- </li>
- </ul>
- </div>
- </file>
- <file name="animations.css">
- .example-animate-container {
- background:white;
- border:1px solid black;
- list-style:none;
- margin:0;
- padding:0 10px;
- }
-
- .animate-repeat {
- line-height:40px;
- list-style:none;
- box-sizing:border-box;
- }
-
- .animate-repeat.ng-move,
- .animate-repeat.ng-enter,
- .animate-repeat.ng-leave {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- }
-
- .animate-repeat.ng-leave.ng-leave-active,
- .animate-repeat.ng-move,
- .animate-repeat.ng-enter {
- opacity:0;
- max-height:0;
- }
-
- .animate-repeat.ng-leave,
- .animate-repeat.ng-move.ng-move-active,
- .animate-repeat.ng-enter.ng-enter-active {
- opacity:1;
- max-height:40px;
- }
- </file>
- <file name="scenario.js">
- it('should render initial data set', function() {
- var r = using('.doc-example-live').repeater('ul li');
- expect(r.count()).toBe(10);
- expect(r.row(0)).toEqual(["1","John","25"]);
- expect(r.row(1)).toEqual(["2","Jessie","30"]);
- expect(r.row(9)).toEqual(["10","Samantha","60"]);
- expect(binding('friends.length')).toBe("10");
- });
-
- it('should update repeater when filter predicate changes', function() {
- var r = using('.doc-example-live').repeater('ul li');
- expect(r.count()).toBe(10);
-
- input('q').enter('ma');
-
- expect(r.count()).toBe(2);
- expect(r.row(0)).toEqual(["1","Mary","28"]);
- expect(r.row(1)).toEqual(["2","Samantha","60"]);
- });
- </file>
- </example>
- */
-var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
- var NG_REMOVED = '$$NG_REMOVED';
- var ngRepeatMinErr = minErr('ngRepeat');
- return {
- transclude: 'element',
- priority: 1000,
- terminal: true,
- $$tlb: true,
- link: function($scope, $element, $attr, ctrl, $transclude){
- var expression = $attr.ngRepeat;
- var match = expression.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/),
- trackByExp, trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn,
- lhs, rhs, valueIdentifier, keyIdentifier,
- hashFnLocals = {$id: hashKey};
-
- if (!match) {
- throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
- expression);
- }
-
- lhs = match[1];
- rhs = match[2];
- trackByExp = match[4];
-
- if (trackByExp) {
- trackByExpGetter = $parse(trackByExp);
- trackByIdExpFn = function(key, value, index) {
- // assign key, value, and $index to the locals so that they can be used in hash functions
- if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
- hashFnLocals[valueIdentifier] = value;
- hashFnLocals.$index = index;
- return trackByExpGetter($scope, hashFnLocals);
- };
- } else {
- trackByIdArrayFn = function(key, value) {
- return hashKey(value);
- };
- trackByIdObjFn = function(key) {
- return key;
- };
- }
-
- match = lhs.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);
- if (!match) {
- throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
- lhs);
- }
- valueIdentifier = match[3] || match[1];
- keyIdentifier = match[2];
-
- // Store a list of elements from previous run. This is a hash where key is the item from the
- // iterator, and the value is objects with following properties.
- // - scope: bound scope
- // - element: previous element.
- // - index: position
- var lastBlockMap = {};
-
- //watch props
- $scope.$watchCollection(rhs, function ngRepeatAction(collection){
- var index, length,
- previousNode = $element[0], // current position of the node
- nextNode,
- // Same as lastBlockMap but it has the current state. It will become the
- // lastBlockMap on the next iteration.
- nextBlockMap = {},
- arrayLength,
- childScope,
- key, value, // key/value of iteration
- trackById,
- trackByIdFn,
- collectionKeys,
- block, // last object information {scope, element, id}
- nextBlockOrder = [],
- elementsToRemove;
-
-
- if (isArrayLike(collection)) {
- collectionKeys = collection;
- trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
- } else {
- trackByIdFn = trackByIdExpFn || trackByIdObjFn;
- // if object, extract keys, sort them and use to determine order of iteration over obj props
- collectionKeys = [];
- for (key in collection) {
- if (collection.hasOwnProperty(key) && key.charAt(0) != '$') {
- collectionKeys.push(key);
- }
- }
- collectionKeys.sort();
- }
-
- arrayLength = collectionKeys.length;
-
- // locate existing items
- length = nextBlockOrder.length = collectionKeys.length;
- for(index = 0; index < length; index++) {
- key = (collection === collectionKeys) ? index : collectionKeys[index];
- value = collection[key];
- trackById = trackByIdFn(key, value, index);
- assertNotHasOwnProperty(trackById, '`track by` id');
- if(lastBlockMap.hasOwnProperty(trackById)) {
- block = lastBlockMap[trackById];
- delete lastBlockMap[trackById];
- nextBlockMap[trackById] = block;
- nextBlockOrder[index] = block;
- } else if (nextBlockMap.hasOwnProperty(trackById)) {
- // restore lastBlockMap
- forEach(nextBlockOrder, function(block) {
- if (block && block.scope) lastBlockMap[block.id] = block;
- });
- // This is a duplicate and we need to throw an error
- throw ngRepeatMinErr('dupes', "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}",
- expression, trackById);
- } else {
- // new never before seen block
- nextBlockOrder[index] = { id: trackById };
- nextBlockMap[trackById] = false;
- }
- }
-
- // remove existing items
- for (key in lastBlockMap) {
- // lastBlockMap is our own object so we don't need to use special hasOwnPropertyFn
- if (lastBlockMap.hasOwnProperty(key)) {
- block = lastBlockMap[key];
- elementsToRemove = getBlockElements(block.clone);
- $animate.leave(elementsToRemove);
- forEach(elementsToRemove, function(element) { element[NG_REMOVED] = true; });
- block.scope.$destroy();
- }
- }
-
- // we are not using forEach for perf reasons (trying to avoid #call)
- for (index = 0, length = collectionKeys.length; index < length; index++) {
- key = (collection === collectionKeys) ? index : collectionKeys[index];
- value = collection[key];
- block = nextBlockOrder[index];
- if (nextBlockOrder[index - 1]) previousNode = getBlockEnd(nextBlockOrder[index - 1]);
-
- if (block.scope) {
- // if we have already seen this object, then we need to reuse the
- // associated scope/element
- childScope = block.scope;
-
- nextNode = previousNode;
- do {
- nextNode = nextNode.nextSibling;
- } while(nextNode && nextNode[NG_REMOVED]);
-
- if (getBlockStart(block) != nextNode) {
- // existing item which got moved
- $animate.move(getBlockElements(block.clone), null, jqLite(previousNode));
- }
- previousNode = getBlockEnd(block);
- } else {
- // new item which we don't know about
- childScope = $scope.$new();
- }
-
- childScope[valueIdentifier] = value;
- if (keyIdentifier) childScope[keyIdentifier] = key;
- childScope.$index = index;
- childScope.$first = (index === 0);
- childScope.$last = (index === (arrayLength - 1));
- childScope.$middle = !(childScope.$first || childScope.$last);
- // jshint bitwise: false
- childScope.$odd = !(childScope.$even = (index&1) === 0);
- // jshint bitwise: true
-
- if (!block.scope) {
- $transclude(childScope, function(clone) {
- clone[clone.length++] = document.createComment(' end ngRepeat: ' + expression + ' ');
- $animate.enter(clone, null, jqLite(previousNode));
- previousNode = clone;
- block.scope = childScope;
- // Note: We only need the first/last node of the cloned nodes.
- // However, we need to keep the reference to the jqlite wrapper as it might be changed later
- // by a directive with templateUrl when it's template arrives.
- block.clone = clone;
- nextBlockMap[block.id] = block;
- });
- }
- }
- lastBlockMap = nextBlockMap;
- });
- }
- };
-
- function getBlockStart(block) {
- return block.clone[0];
- }
-
- function getBlockEnd(block) {
- return block.clone[block.clone.length - 1];
- }
-}];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngShow
- *
- * @description
- * The `ngShow` directive shows or hides the given HTML element based on the expression
- * provided to the ngShow attribute. The element is shown or hidden by removing or adding
- * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
- * in AngularJS and sets the display style to none (using an !important flag).
- * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
- *
- * <pre>
- * <!-- when $scope.myValue is truthy (element is visible) -->
- * <div ng-show="myValue"></div>
- *
- * <!-- when $scope.myValue is falsy (element is hidden) -->
- * <div ng-show="myValue" class="ng-hide"></div>
- * </pre>
- *
- * When the ngShow expression evaluates to false then the ng-hide CSS class is added to the class attribute
- * on the element causing it to become hidden. When true, the ng-hide CSS class is removed
- * from the element causing the element not to appear hidden.
- *
- * ## Why is !important used?
- *
- * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
- * can be easily overridden by heavier selectors. For example, something as simple
- * as changing the display style on a HTML list item would make hidden elements appear visible.
- * This also becomes a bigger issue when dealing with CSS frameworks.
- *
- * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
- * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
- * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
- *
- * ### Overriding .ng-hide
- *
- * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
- * restating the styles for the .ng-hide class in CSS:
- * <pre>
- * .ng-hide {
- * //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
- * display:block!important;
- *
- * //this is just another form of hiding an element
- * position:absolute;
- * top:-9999px;
- * left:-9999px;
- * }
- * </pre>
- *
- * Just remember to include the important flag so the CSS override will function.
- *
- * ## A note about animations with ngShow
- *
- * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
- * is true and false. This system works like the animation system present with ngClass except that
- * you must also include the !important flag to override the display property
- * so that you can perform an animation when the element is hidden during the time of the animation.
- *
- * <pre>
- * //
- * //a working example can be found at the bottom of this page
- * //
- * .my-element.ng-hide-add, .my-element.ng-hide-remove {
- * transition:0.5s linear all;
- * display:block!important;
- * }
- *
- * .my-element.ng-hide-add { ... }
- * .my-element.ng-hide-add.ng-hide-add-active { ... }
- * .my-element.ng-hide-remove { ... }
- * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
- * </pre>
- *
- * @animations
- * addClass: .ng-hide - happens after the ngShow expression evaluates to a truthy value and the just before contents are set to visible
- * removeClass: .ng-hide - happens after the ngShow expression evaluates to a non truthy value and just before the contents are set to hidden
- *
- * @element ANY
- * @param {expression} ngShow If the {@link guide/expression expression} is truthy
- * then the element is shown or hidden respectively.
- *
- * @example
- <example animations="true">
- <file name="index.html">
- Click me: <input type="checkbox" ng-model="checked"><br/>
- <div>
- Show:
- <div class="check-element animate-show" ng-show="checked">
- <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
- </div>
- </div>
- <div>
- Hide:
- <div class="check-element animate-show" ng-hide="checked">
- <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
- </div>
- </div>
- </file>
- <file name="animations.css">
- .animate-show {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
- }
-
- .animate-show.ng-hide-add,
- .animate-show.ng-hide-remove {
- display:block!important;
- }
-
- .animate-show.ng-hide {
- line-height:0;
- opacity:0;
- padding:0 10px;
- }
-
- .check-element {
- padding:10px;
- border:1px solid black;
- background:white;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-show / ng-hide', function() {
- expect(element('.doc-example-live span:first:hidden').count()).toEqual(1);
- expect(element('.doc-example-live span:last:visible').count()).toEqual(1);
-
- input('checked').check();
-
- expect(element('.doc-example-live span:first:visible').count()).toEqual(1);
- expect(element('.doc-example-live span:last:hidden').count()).toEqual(1);
- });
- </file>
- </example>
- */
-var ngShowDirective = ['$animate', function($animate) {
- return function(scope, element, attr) {
- scope.$watch(attr.ngShow, function ngShowWatchAction(value){
- $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide');
- });
- };
-}];
-
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngHide
- *
- * @description
- * The `ngHide` directive shows or hides the given HTML element based on the expression
- * provided to the ngHide attribute. The element is shown or hidden by removing or adding
- * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
- * in AngularJS and sets the display style to none (using an !important flag).
- * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
- *
- * <pre>
- * <!-- when $scope.myValue is truthy (element is hidden) -->
- * <div ng-hide="myValue"></div>
- *
- * <!-- when $scope.myValue is falsy (element is visible) -->
- * <div ng-hide="myValue" class="ng-hide"></div>
- * </pre>
- *
- * When the ngHide expression evaluates to true then the .ng-hide CSS class is added to the class attribute
- * on the element causing it to become hidden. When false, the ng-hide CSS class is removed
- * from the element causing the element not to appear hidden.
- *
- * ## Why is !important used?
- *
- * You may be wondering why !important is used for the .ng-hide CSS class. This is because the `.ng-hide` selector
- * can be easily overridden by heavier selectors. For example, something as simple
- * as changing the display style on a HTML list item would make hidden elements appear visible.
- * This also becomes a bigger issue when dealing with CSS frameworks.
- *
- * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
- * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
- * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
- *
- * ### Overriding .ng-hide
- *
- * If you wish to change the hide behavior with ngShow/ngHide then this can be achieved by
- * restating the styles for the .ng-hide class in CSS:
- * <pre>
- * .ng-hide {
- * //!annotate CSS Specificity|Not to worry, this will override the AngularJS default...
- * display:block!important;
- *
- * //this is just another form of hiding an element
- * position:absolute;
- * top:-9999px;
- * left:-9999px;
- * }
- * </pre>
- *
- * Just remember to include the important flag so the CSS override will function.
- *
- * ## A note about animations with ngHide
- *
- * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
- * is true and false. This system works like the animation system present with ngClass, except that
- * you must also include the !important flag to override the display property so
- * that you can perform an animation when the element is hidden during the time of the animation.
- *
- * <pre>
- * //
- * //a working example can be found at the bottom of this page
- * //
- * .my-element.ng-hide-add, .my-element.ng-hide-remove {
- * transition:0.5s linear all;
- * display:block!important;
- * }
- *
- * .my-element.ng-hide-add { ... }
- * .my-element.ng-hide-add.ng-hide-add-active { ... }
- * .my-element.ng-hide-remove { ... }
- * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
- * </pre>
- *
- * @animations
- * removeClass: .ng-hide - happens after the ngHide expression evaluates to a truthy value and just before the contents are set to hidden
- * addClass: .ng-hide - happens after the ngHide expression evaluates to a non truthy value and just before the contents are set to visible
- *
- * @element ANY
- * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
- * the element is shown or hidden respectively.
- *
- * @example
- <example animations="true">
- <file name="index.html">
- Click me: <input type="checkbox" ng-model="checked"><br/>
- <div>
- Show:
- <div class="check-element animate-hide" ng-show="checked">
- <span class="icon-thumbs-up"></span> I show up when your checkbox is checked.
- </div>
- </div>
- <div>
- Hide:
- <div class="check-element animate-hide" ng-hide="checked">
- <span class="icon-thumbs-down"></span> I hide when your checkbox is checked.
- </div>
- </div>
- </file>
- <file name="animations.css">
- .animate-hide {
- -webkit-transition:all linear 0.5s;
- transition:all linear 0.5s;
- line-height:20px;
- opacity:1;
- padding:10px;
- border:1px solid black;
- background:white;
- }
-
- .animate-hide.ng-hide-add,
- .animate-hide.ng-hide-remove {
- display:block!important;
- }
-
- .animate-hide.ng-hide {
- line-height:0;
- opacity:0;
- padding:0 10px;
- }
-
- .check-element {
- padding:10px;
- border:1px solid black;
- background:white;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-show / ng-hide', function() {
- expect(element('.doc-example-live .check-element:first:hidden').count()).toEqual(1);
- expect(element('.doc-example-live .check-element:last:visible').count()).toEqual(1);
-
- input('checked').check();
-
- expect(element('.doc-example-live .check-element:first:visible').count()).toEqual(1);
- expect(element('.doc-example-live .check-element:last:hidden').count()).toEqual(1);
- });
- </file>
- </example>
- */
-var ngHideDirective = ['$animate', function($animate) {
- return function(scope, element, attr) {
- scope.$watch(attr.ngHide, function ngHideWatchAction(value){
- $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide');
- });
- };
-}];
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngStyle
- * @restrict AC
- *
- * @description
- * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
- *
- * @element ANY
- * @param {expression} ngStyle {@link guide/expression Expression} which evals to an
- * object whose keys are CSS style names and values are corresponding values for those CSS
- * keys.
- *
- * @example
- <example>
- <file name="index.html">
- <input type="button" value="set" ng-click="myStyle={color:'red'}">
- <input type="button" value="clear" ng-click="myStyle={}">
- <br/>
- <span ng-style="myStyle">Sample Text</span>
- <pre>myStyle={{myStyle}}</pre>
- </file>
- <file name="style.css">
- span {
- color: black;
- }
- </file>
- <file name="scenario.js">
- it('should check ng-style', function() {
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
- element('.doc-example-live :button[value=set]').click();
- expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)');
- element('.doc-example-live :button[value=clear]').click();
- expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
- });
- </file>
- </example>
- */
-var ngStyleDirective = ngDirective(function(scope, element, attr) {
- scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
- if (oldStyles && (newStyles !== oldStyles)) {
- forEach(oldStyles, function(val, style) { element.css(style, '');});
- }
- if (newStyles) element.css(newStyles);
- }, true);
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngSwitch
- * @restrict EA
- *
- * @description
- * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
- * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
- * as specified in the template.
- *
- * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
- * from the template cache), `ngSwitch` simply choses one of the nested elements and makes it visible based on which element
- * matches the value obtained from the evaluated expression. In other words, you define a container element
- * (where you place the directive), place an expression on the **`on="..."` attribute**
- * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
- * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
- * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
- * attribute is displayed.
- *
- * <div class="alert alert-info">
- * Be aware that the attribute values to match against cannot be expressions. They are interpreted
- * as literal string values to match against.
- * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
- * value of the expression `$scope.someVal`.
- * </div>
-
- * @animations
- * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
- * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
- *
- * @usage
- * <ANY ng-switch="expression">
- * <ANY ng-switch-when="matchValue1">...</ANY>
- * <ANY ng-switch-when="matchValue2">...</ANY>
- * <ANY ng-switch-default>...</ANY>
- * </ANY>
- *
- *
- * @scope
- * @priority 800
- * @param {*} ngSwitch|on expression to match against <tt>ng-switch-when</tt>.
- * @paramDescription
- * On child elements add:
- *
- * * `ngSwitchWhen`: the case statement to match against. If match then this
- * case will be displayed. If the same match appears multiple times, all the
- * elements will be displayed.
- * * `ngSwitchDefault`: the default case when no other case match. If there
- * are multiple default cases, all of them will be displayed when no other
- * case match.
- *
- *
- * @example
- <example animations="true">
- <file name="index.html">
- <div ng-controller="Ctrl">
- <select ng-model="selection" ng-options="item for item in items">
- </select>
- <tt>selection={{selection}}</tt>
- <hr/>
- <div class="animate-switch-container"
- ng-switch on="selection">
- <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
- <div class="animate-switch" ng-switch-when="home">Home Span</div>
- <div class="animate-switch" ng-switch-default>default</div>
- </div>
- </div>
- </file>
- <file name="script.js">
- function Ctrl($scope) {
- $scope.items = ['settings', 'home', 'other'];
- $scope.selection = $scope.items[0];
- }
- </file>
- <file name="animations.css">
- .animate-switch-container {
- position:relative;
- background:white;
- border:1px solid black;
- height:40px;
- overflow:hidden;
- }
-
- .animate-switch {
- padding:10px;
- }
-
- .animate-switch.ng-animate {
- -webkit-transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
- transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
-
- position:absolute;
- top:0;
- left:0;
- right:0;
- bottom:0;
- }
-
- .animate-switch.ng-leave.ng-leave-active,
- .animate-switch.ng-enter {
- top:-50px;
- }
- .animate-switch.ng-leave,
- .animate-switch.ng-enter.ng-enter-active {
- top:0;
- }
- </file>
- <file name="scenario.js">
- it('should start in settings', function() {
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Settings Div/);
- });
- it('should change to home', function() {
- select('selection').option('home');
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/Home Span/);
- });
- it('should select default', function() {
- select('selection').option('other');
- expect(element('.doc-example-live [ng-switch]').text()).toMatch(/default/);
- });
- </file>
- </example>
- */
-var ngSwitchDirective = ['$animate', function($animate) {
- return {
- restrict: 'EA',
- require: 'ngSwitch',
-
- // asks for $scope to fool the BC controller module
- controller: ['$scope', function ngSwitchController() {
- this.cases = {};
- }],
- link: function(scope, element, attr, ngSwitchController) {
- var watchExpr = attr.ngSwitch || attr.on,
- selectedTranscludes,
- selectedElements,
- selectedScopes = [];
-
- scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
- for (var i= 0, ii=selectedScopes.length; i<ii; i++) {
- selectedScopes[i].$destroy();
- $animate.leave(selectedElements[i]);
- }
-
- selectedElements = [];
- selectedScopes = [];
-
- if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
- scope.$eval(attr.change);
- forEach(selectedTranscludes, function(selectedTransclude) {
- var selectedScope = scope.$new();
- selectedScopes.push(selectedScope);
- selectedTransclude.transclude(selectedScope, function(caseElement) {
- var anchor = selectedTransclude.element;
-
- selectedElements.push(caseElement);
- $animate.enter(caseElement, anchor.parent(), anchor);
- });
- });
- }
- });
- }
- };
-}];
-
-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 });
- };
- }
-});
-
-var ngSwitchDefaultDirective = ngDirective({
- transclude: 'element',
- priority: 800,
- require: '^ngSwitch',
- link: function(scope, element, attr, ctrl, $transclude) {
- ctrl.cases['?'] = (ctrl.cases['?'] || []);
- ctrl.cases['?'].push({ transclude: $transclude, element: element });
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:ngTransclude
- * @restrict AC
- *
- * @description
- * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
- *
- * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
- *
- * @element ANY
- *
- * @example
- <doc:example module="transclude">
- <doc:source>
- <script>
- function Ctrl($scope) {
- $scope.title = 'Lorem Ipsum';
- $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
- }
-
- angular.module('transclude', [])
- .directive('pane', function(){
- return {
- restrict: 'E',
- transclude: true,
- scope: { title:'@' },
- template: '<div style="border: 1px solid black;">' +
- '<div style="background-color: gray">{{title}}</div>' +
- '<div ng-transclude></div>' +
- '</div>'
- };
- });
- </script>
- <div ng-controller="Ctrl">
- <input ng-model="title"><br>
- <textarea ng-model="text"></textarea> <br/>
- <pane title="{{title}}">{{text}}</pane>
- </div>
- </doc:source>
- <doc:scenario>
- it('should have transcluded', function() {
- input('title').enter('TITLE');
- input('text').enter('TEXT');
- expect(binding('title')).toEqual('TITLE');
- expect(binding('text')).toEqual('TEXT');
- });
- </doc:scenario>
- </doc:example>
- *
- */
-var ngTranscludeDirective = ngDirective({
- controller: ['$element', '$transclude', function($element, $transclude) {
- if (!$transclude) {
- throw minErr('ngTransclude')('orphan',
- 'Illegal use of ngTransclude directive in the template! ' +
- 'No parent directive that requires a transclusion found. ' +
- 'Element: {0}',
- startingTag($element));
- }
-
- // remember the transclusion fn but call it during linking so that we don't process transclusion before directives on
- // the parent element even when the transclusion replaces the current element. (we can't use priority here because
- // that applies only to compile fns and not controllers
- this.$transclude = $transclude;
- }],
-
- link: function($scope, $element, $attrs, controller) {
- controller.$transclude(function(clone) {
- $element.empty();
- $element.append(clone);
- });
- }
-});
-
-/**
- * @ngdoc directive
- * @name ng.directive:script
- * @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.
- *
- * @param {'text/ng-template'} type must be set to `'text/ng-template'`
- *
- * @example
- <doc:example>
- <doc:source>
- <script type="text/ng-template" id="/tpl.html">
- Content of the template.
- </script>
-
- <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
- <div id="tpl-content" ng-include src="currentTpl"></div>
- </doc:source>
- <doc:scenario>
- it('should load template defined inside script tag', function() {
- element('#tpl-link').click();
- expect(element('#tpl-content').text()).toMatch(/Content of the template/);
- });
- </doc:scenario>
- </doc:example>
- */
-var scriptDirective = ['$templateCache', function($templateCache) {
- return {
- restrict: 'E',
- terminal: true,
- compile: function(element, attr) {
- if (attr.type == 'text/ng-template') {
- var templateUrl = attr.id,
- // IE is not consistent, in scripts we have to read .text but in other nodes we have to read .textContent
- text = element[0].text;
-
- $templateCache.put(templateUrl, text);
- }
- }
- };
-}];
-
-var ngOptionsMinErr = minErr('ngOptions');
-/**
- * @ngdoc directive
- * @name ng.directive:select
- * @restrict E
- *
- * @description
- * HTML `SELECT` element with angular data-binding.
- *
- * # `ngOptions`
- *
- * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
- * elements for the `<select>` element using the array or object obtained by evaluating the
- * `ngOptions` comprehension_expression.
- *
- * When an item in the `<select>` menu is selected, the array element or object property
- * represented by the selected option will be bound to the model identified by the `ngModel`
- * directive.
- *
- * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
- * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
- * option. See example below for demonstration.
- *
- * Note: `ngOptions` provides iterator facility for `<option>` element which should be used instead
- * of {@link ng.directive:ngRepeat ngRepeat} when you want the
- * `select` model to be bound to a non-string value. This is because an option element can only
- * be bound to string values at present.
- *
- * @param {string} ngModel Assignable angular expression to data-bind to.
- * @param {string=} name Property name of the form under which the control is published.
- * @param {string=} required The control is considered valid only if value is entered.
- * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
- * the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
- * `required` when you want to data-bind to the `required` attribute.
- * @param {comprehension_expression=} ngOptions in one of the following forms:
- *
- * * for array data sources:
- * * `label` **`for`** `value` **`in`** `array`
- * * `select` **`as`** `label` **`for`** `value` **`in`** `array`
- * * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
- * * `select` **`as`** `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
- * * for object data sources:
- * * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
- * * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
- * * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
- * * `select` **`as`** `label` **`group by`** `group`
- * **`for` `(`**`key`**`,`** `value`**`) in`** `object`
- *
- * Where:
- *
- * * `array` / `object`: an expression which evaluates to an array / object to iterate over.
- * * `value`: local variable which will refer to each item in the `array` or each property value
- * of `object` during iteration.
- * * `key`: local variable which will refer to a property name in `object` during iteration.
- * * `label`: The result of this expression will be the label for `<option>` element. The
- * `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
- * * `select`: The result of this expression will be bound to the model of the parent `<select>`
- * element. If not specified, `select` expression will default to `value`.
- * * `group`: The result of this expression will be used to group options using the `<optgroup>`
- * DOM element.
- * * `trackexpr`: Used when working with an array of objects. The result of this expression will be
- * used to identify the objects in the array. The `trackexpr` will most likely refer to the
- * `value` variable (e.g. `value.propertyName`).
- *
- * @example
- <doc:example>
- <doc:source>
- <script>
- function MyCntrl($scope) {
- $scope.colors = [
- {name:'black', shade:'dark'},
- {name:'white', shade:'light'},
- {name:'red', shade:'dark'},
- {name:'blue', shade:'dark'},
- {name:'yellow', shade:'light'}
- ];
- $scope.color = $scope.colors[2]; // red
- }
- </script>
- <div ng-controller="MyCntrl">
- <ul>
- <li ng-repeat="color in colors">
- Name: <input ng-model="color.name">
- [<a href ng-click="colors.splice($index, 1)">X</a>]
- </li>
- <li>
- [<a href ng-click="colors.push({})">add</a>]
- </li>
- </ul>
- <hr/>
- Color (null not allowed):
- <select ng-model="color" ng-options="c.name for c in colors"></select><br>
-
- Color (null allowed):
- <span class="nullable">
- <select ng-model="color" ng-options="c.name for c in colors">
- <option value="">-- choose color --</option>
- </select>
- </span><br/>
-
- Color grouped by shade:
- <select ng-model="color" ng-options="c.name group by c.shade for c in colors">
- </select><br/>
-
-
- Select <a href ng-click="color={name:'not in list'}">bogus</a>.<br>
- <hr/>
- Currently selected: {{ {selected_color:color} }}
- <div style="border:solid 1px black; height:20px"
- ng-style="{'background-color':color.name}">
- </div>
- </div>
- </doc:source>
- <doc:scenario>
- it('should check ng-options', function() {
- expect(binding('{selected_color:color}')).toMatch('red');
- select('color').option('0');
- expect(binding('{selected_color:color}')).toMatch('black');
- using('.nullable').select('color').option('');
- expect(binding('{selected_color:color}')).toMatch('null');
- });
- </doc:scenario>
- </doc:example>
- */
-
-var ngOptionsDirective = valueFn({ terminal: true });
-// jshint maxlen: false
-var selectDirective = ['$compile', '$parse', function($compile, $parse) {
- //0000111110000000000022220000000000000000000000333300000000000000444444444444444000000000555555555555555000000066666666666666600000000000000007777000000000000000000088888
- var NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/,
- nullModelCtrl = {$setViewValue: noop};
-// jshint maxlen: 100
-
- return {
- restrict: 'E',
- require: ['select', '?ngModel'],
- controller: ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
- var self = this,
- optionsMap = {},
- ngModelCtrl = nullModelCtrl,
- nullOption,
- unknownOption;
-
-
- self.databound = $attrs.ngModel;
-
-
- self.init = function(ngModelCtrl_, nullOption_, unknownOption_) {
- ngModelCtrl = ngModelCtrl_;
- nullOption = nullOption_;
- unknownOption = unknownOption_;
- };
-
-
- self.addOption = function(value) {
- assertNotHasOwnProperty(value, '"option value"');
- optionsMap[value] = true;
-
- if (ngModelCtrl.$viewValue == value) {
- $element.val(value);
- if (unknownOption.parent()) unknownOption.remove();
- }
- };
-
-
- self.removeOption = function(value) {
- if (this.hasOption(value)) {
- delete optionsMap[value];
- if (ngModelCtrl.$viewValue == value) {
- this.renderUnknownOption(value);
- }
- }
- };
-
-
- self.renderUnknownOption = function(val) {
- var unknownVal = '? ' + hashKey(val) + ' ?';
- unknownOption.val(unknownVal);
- $element.prepend(unknownOption);
- $element.val(unknownVal);
- unknownOption.prop('selected', true); // needed for IE
- };
-
-
- self.hasOption = function(value) {
- return optionsMap.hasOwnProperty(value);
- };
-
- $scope.$on('$destroy', function() {
- // disable unknown option so that we don't do work when the whole select is being destroyed
- self.renderUnknownOption = noop;
- });
- }],
-
- link: function(scope, element, attr, ctrls) {
- // if ngModel is not defined, we don't need to do anything
- if (!ctrls[1]) return;
-
- var selectCtrl = ctrls[0],
- ngModelCtrl = ctrls[1],
- multiple = attr.multiple,
- optionsExp = attr.ngOptions,
- nullOption = false, // if false, user will not be able to select it (used by ngOptions)
- emptyOption,
- // we can't just jqLite('<option>') since jqLite is not smart enough
- // to create it in <select> and IE barfs otherwise.
- optionTemplate = jqLite(document.createElement('option')),
- optGroupTemplate =jqLite(document.createElement('optgroup')),
- unknownOption = optionTemplate.clone();
-
- // find "null" option
- for(var i = 0, children = element.children(), ii = children.length; i < ii; i++) {
- if (children[i].value === '') {
- emptyOption = nullOption = children.eq(i);
- break;
- }
- }
-
- selectCtrl.init(ngModelCtrl, nullOption, unknownOption);
-
- // required validator
- if (multiple && (attr.required || attr.ngRequired)) {
- var requiredValidator = function(value) {
- ngModelCtrl.$setValidity('required', !attr.required || (value && value.length));
- return value;
- };
-
- ngModelCtrl.$parsers.push(requiredValidator);
- ngModelCtrl.$formatters.unshift(requiredValidator);
-
- attr.$observe('required', function() {
- requiredValidator(ngModelCtrl.$viewValue);
- });
- }
-
- if (optionsExp) setupAsOptions(scope, element, ngModelCtrl);
- else if (multiple) setupAsMultiple(scope, element, ngModelCtrl);
- else setupAsSingle(scope, element, ngModelCtrl, selectCtrl);
-
-
- ////////////////////////////
-
-
-
- function setupAsSingle(scope, selectElement, ngModelCtrl, selectCtrl) {
- ngModelCtrl.$render = function() {
- var viewValue = ngModelCtrl.$viewValue;
-
- if (selectCtrl.hasOption(viewValue)) {
- if (unknownOption.parent()) unknownOption.remove();
- selectElement.val(viewValue);
- if (viewValue === '') emptyOption.prop('selected', true); // to make IE9 happy
- } else {
- if (isUndefined(viewValue) && emptyOption) {
- selectElement.val('');
- } else {
- selectCtrl.renderUnknownOption(viewValue);
- }
- }
- };
-
- selectElement.on('change', function() {
- scope.$apply(function() {
- if (unknownOption.parent()) unknownOption.remove();
- ngModelCtrl.$setViewValue(selectElement.val());
- });
- });
- }
-
- function setupAsMultiple(scope, selectElement, ctrl) {
- var lastView;
- ctrl.$render = function() {
- var items = new HashMap(ctrl.$viewValue);
- forEach(selectElement.find('option'), function(option) {
- option.selected = isDefined(items.get(option.value));
- });
- };
-
- // we have to do it on each watch since ngModel watches reference, but
- // we need to work of an array, so we need to see if anything was inserted/removed
- scope.$watch(function selectMultipleWatch() {
- if (!equals(lastView, ctrl.$viewValue)) {
- lastView = copy(ctrl.$viewValue);
- ctrl.$render();
- }
- });
-
- selectElement.on('change', function() {
- scope.$apply(function() {
- var array = [];
- forEach(selectElement.find('option'), function(option) {
- if (option.selected) {
- array.push(option.value);
- }
- });
- ctrl.$setViewValue(array);
- });
- });
- }
-
- function setupAsOptions(scope, selectElement, ctrl) {
- var match;
-
- if (! (match = optionsExp.match(NG_OPTIONS_REGEXP))) {
- throw ngOptionsMinErr('iexp',
- "Expected expression in form of " +
- "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
- " but got '{0}'. Element: {1}",
- optionsExp, startingTag(selectElement));
- }
-
- var displayFn = $parse(match[2] || match[1]),
- valueName = match[4] || match[6],
- keyName = match[5],
- groupByFn = $parse(match[3] || ''),
- valueFn = $parse(match[2] ? match[1] : valueName),
- valuesFn = $parse(match[7]),
- track = match[8],
- trackFn = track ? $parse(match[8]) : null,
- // This is an array of array of existing option groups in DOM.
- // We try to reuse these if possible
- // - optionGroupsCache[0] is the options with no option group
- // - optionGroupsCache[?][0] is the parent: either the SELECT or OPTGROUP element
- optionGroupsCache = [[{element: selectElement, label:''}]];
-
- if (nullOption) {
- // compile the element since there might be bindings in it
- $compile(nullOption)(scope);
-
- // remove the class, which is added automatically because we recompile the element and it
- // becomes the compilation root
- nullOption.removeClass('ng-scope');
-
- // we need to remove it before calling selectElement.empty() because otherwise IE will
- // remove the label from the element. wtf?
- nullOption.remove();
- }
-
- // clear contents, we'll add what's needed based on the model
- selectElement.empty();
-
- selectElement.on('change', function() {
- scope.$apply(function() {
- var optionGroup,
- collection = valuesFn(scope) || [],
- locals = {},
- key, value, optionElement, index, groupIndex, length, groupLength, trackIndex;
-
- if (multiple) {
- value = [];
- for (groupIndex = 0, groupLength = optionGroupsCache.length;
- groupIndex < groupLength;
- groupIndex++) {
- // list of options for that group. (first item has the parent)
- optionGroup = optionGroupsCache[groupIndex];
-
- for(index = 1, length = optionGroup.length; index < length; index++) {
- if ((optionElement = optionGroup[index].element)[0].selected) {
- key = optionElement.val();
- if (keyName) locals[keyName] = key;
- if (trackFn) {
- for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
- locals[valueName] = collection[trackIndex];
- if (trackFn(scope, locals) == key) break;
- }
- } else {
- locals[valueName] = collection[key];
- }
- value.push(valueFn(scope, locals));
- }
- }
- }
- } else {
- key = selectElement.val();
- if (key == '?') {
- value = undefined;
- } else if (key === ''){
- value = null;
- } else {
- if (trackFn) {
- for (trackIndex = 0; trackIndex < collection.length; trackIndex++) {
- locals[valueName] = collection[trackIndex];
- if (trackFn(scope, locals) == key) {
- value = valueFn(scope, locals);
- break;
- }
- }
- } else {
- locals[valueName] = collection[key];
- if (keyName) locals[keyName] = key;
- value = valueFn(scope, locals);
- }
- }
- }
- ctrl.$setViewValue(value);
- });
- });
-
- ctrl.$render = render;
-
- // TODO(vojta): can't we optimize this ?
- scope.$watch(render);
-
- function render() {
- // Temporary location for the option groups before we render them
- var optionGroups = {'':[]},
- optionGroupNames = [''],
- optionGroupName,
- optionGroup,
- option,
- existingParent, existingOptions, existingOption,
- modelValue = ctrl.$modelValue,
- values = valuesFn(scope) || [],
- keys = keyName ? sortedKeys(values) : values,
- key,
- groupLength, length,
- groupIndex, index,
- locals = {},
- selected,
- selectedSet = false, // nothing is selected yet
- lastElement,
- element,
- label;
-
- if (multiple) {
- if (trackFn && isArray(modelValue)) {
- selectedSet = new HashMap([]);
- for (var trackIndex = 0; trackIndex < modelValue.length; trackIndex++) {
- locals[valueName] = modelValue[trackIndex];
- selectedSet.put(trackFn(scope, locals), modelValue[trackIndex]);
- }
- } else {
- selectedSet = new HashMap(modelValue);
- }
- }
-
- // We now build up the list of options we need (we merge later)
- for (index = 0; length = keys.length, index < length; index++) {
-
- key = index;
- if (keyName) {
- key = keys[index];
- if ( key.charAt(0) === '$' ) continue;
- locals[keyName] = key;
- }
-
- locals[valueName] = values[key];
-
- optionGroupName = groupByFn(scope, locals) || '';
- if (!(optionGroup = optionGroups[optionGroupName])) {
- optionGroup = optionGroups[optionGroupName] = [];
- optionGroupNames.push(optionGroupName);
- }
- if (multiple) {
- selected = isDefined(
- selectedSet.remove(trackFn ? trackFn(scope, locals) : valueFn(scope, locals))
- );
- } else {
- if (trackFn) {
- var modelCast = {};
- modelCast[valueName] = modelValue;
- selected = trackFn(scope, modelCast) === trackFn(scope, locals);
- } else {
- selected = modelValue === valueFn(scope, locals);
- }
- selectedSet = selectedSet || selected; // see if at least one item is selected
- }
- label = displayFn(scope, locals); // what will be seen by the user
-
- // doing displayFn(scope, locals) || '' overwrites zero values
- label = isDefined(label) ? label : '';
- optionGroup.push({
- // either the index into array or key from object
- id: trackFn ? trackFn(scope, locals) : (keyName ? keys[index] : index),
- label: label,
- selected: selected // determine if we should be selected
- });
- }
- if (!multiple) {
- if (nullOption || modelValue === null) {
- // insert null option if we have a placeholder, or the model is null
- optionGroups[''].unshift({id:'', label:'', selected:!selectedSet});
- } else if (!selectedSet) {
- // option could not be found, we have to insert the undefined item
- optionGroups[''].unshift({id:'?', label:'', selected:true});
- }
- }
-
- // Now we need to update the list of DOM nodes to match the optionGroups we computed above
- for (groupIndex = 0, groupLength = optionGroupNames.length;
- groupIndex < groupLength;
- groupIndex++) {
- // current option group name or '' if no group
- optionGroupName = optionGroupNames[groupIndex];
-
- // list of options for that group. (first item has the parent)
- optionGroup = optionGroups[optionGroupName];
-
- if (optionGroupsCache.length <= groupIndex) {
- // we need to grow the optionGroups
- existingParent = {
- element: optGroupTemplate.clone().attr('label', optionGroupName),
- label: optionGroup.label
- };
- existingOptions = [existingParent];
- optionGroupsCache.push(existingOptions);
- selectElement.append(existingParent.element);
- } else {
- existingOptions = optionGroupsCache[groupIndex];
- existingParent = existingOptions[0]; // either SELECT (no group) or OPTGROUP element
-
- // update the OPTGROUP label if not the same.
- if (existingParent.label != optionGroupName) {
- existingParent.element.attr('label', existingParent.label = optionGroupName);
- }
- }
-
- lastElement = null; // start at the beginning
- for(index = 0, length = optionGroup.length; index < length; index++) {
- option = optionGroup[index];
- if ((existingOption = existingOptions[index+1])) {
- // reuse elements
- lastElement = existingOption.element;
- if (existingOption.label !== option.label) {
- lastElement.text(existingOption.label = option.label);
- }
- if (existingOption.id !== option.id) {
- lastElement.val(existingOption.id = option.id);
- }
- // lastElement.prop('selected') provided by jQuery has side-effects
- if (lastElement[0].selected !== option.selected) {
- lastElement.prop('selected', (existingOption.selected = option.selected));
- }
- } else {
- // grow elements
-
- // if it's a null option
- if (option.id === '' && nullOption) {
- // put back the pre-compiled element
- element = nullOption;
- } else {
- // jQuery(v1.4.2) Bug: We should be able to chain the method calls, but
- // in this version of jQuery on some browser the .text() returns a string
- // rather then the element.
- (element = optionTemplate.clone())
- .val(option.id)
- .attr('selected', option.selected)
- .text(option.label);
- }
-
- existingOptions.push(existingOption = {
- element: element,
- label: option.label,
- id: option.id,
- selected: option.selected
- });
- if (lastElement) {
- lastElement.after(element);
- } else {
- existingParent.element.append(element);
- }
- lastElement = element;
- }
- }
- // remove any excessive OPTIONs in a group
- index++; // increment since the existingOptions[0] is parent element not OPTION
- while(existingOptions.length > index) {
- existingOptions.pop().element.remove();
- }
- }
- // remove any excessive OPTGROUPs from select
- while(optionGroupsCache.length > groupIndex) {
- optionGroupsCache.pop()[0].element.remove();
- }
- }
- }
- }
- };
-}];
-
-var optionDirective = ['$interpolate', function($interpolate) {
- var nullSelectCtrl = {
- addOption: noop,
- removeOption: noop
- };
-
- return {
- restrict: 'E',
- priority: 100,
- compile: function(element, attr) {
- if (isUndefined(attr.value)) {
- var interpolateFn = $interpolate(element.text(), true);
- if (!interpolateFn) {
- attr.$set('value', element.text());
- }
- }
-
- return function (scope, element, attr) {
- var selectCtrlName = '$selectController',
- parent = element.parent(),
- selectCtrl = parent.data(selectCtrlName) ||
- parent.parent().data(selectCtrlName); // in case we are in optgroup
-
- if (selectCtrl && selectCtrl.databound) {
- // For some reason Opera defaults to true and if not overridden this messes up the repeater.
- // We don't want the view to drive the initialization of the model anyway.
- element.prop('selected', false);
- } else {
- selectCtrl = nullSelectCtrl;
- }
-
- if (interpolateFn) {
- scope.$watch(interpolateFn, function interpolateWatchAction(newVal, oldVal) {
- attr.$set('value', newVal);
- if (newVal !== oldVal) selectCtrl.removeOption(oldVal);
- selectCtrl.addOption(newVal);
- });
- } else {
- selectCtrl.addOption(attr.value);
- }
-
- element.on('$destroy', function() {
- selectCtrl.removeOption(attr.value);
- });
- };
- }
- };
-}];
-
-var styleDirective = valueFn({
- restrict: 'E',
- terminal: true
-});
-
- //try to bind to jquery now so that one can write angular.element().read()
- //but we will rebind on bootstrap again.
- bindJQuery();
-
- publishExternalAPI(angular);
-
- jqLite(document).ready(function() {
- angularInit(document, bootstrap);
- });
-
-})(window, document);
-
-!angular.$$csp() && angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide{display:none !important;}ng\\:form{display:block;}.ng-animate-start{border-spacing:1px 1px;-ms-zoom:1.0001;}.ng-animate-active{border-spacing:0px 0px;-ms-zoom:1;}</style>');
\ No newline at end of file
deleted file mode 100644
index 2e8c6eca3c148d6d3ea742cba13b3a60a39230e1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/backbone-1.1.js
+++ /dev/null
@@ -1,1581 +0,0 @@
-// Backbone.js 1.1.0
-
-// (c) 2010-2011 Jeremy Ashkenas, DocumentCloud Inc.
-// (c) 2011-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
-// Backbone may be freely distributed under the MIT license.
-// For all details and documentation:
-// http://backbonejs.org
-
-(function(){
-
- // Initial Setup
- // -------------
-
- // Save a reference to the global object (`window` in the browser, `exports`
- // on the server).
- var root = this;
-
- // Save the previous value of the `Backbone` variable, so that it can be
- // restored later on, if `noConflict` is used.
- var previousBackbone = root.Backbone;
-
- // Create local references to array methods we'll want to use later.
- var array = [];
- var push = array.push;
- var slice = array.slice;
- var splice = array.splice;
-
- // The top-level namespace. All public Backbone classes and modules will
- // be attached to this. Exported for both the browser and the server.
- var Backbone;
- if (typeof exports !== 'undefined') {
- Backbone = exports;
- } else {
- Backbone = root.Backbone = {};
- }
-
- // Current version of the library. Keep in sync with `package.json`.
- Backbone.VERSION = '1.1.0';
-
- // Require Underscore, if we're on the server, and it's not already present.
- var _ = root._;
- if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
-
- // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
- // the `$` variable.
- Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
-
- // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
- // to its previous owner. Returns a reference to this Backbone object.
- Backbone.noConflict = function() {
- root.Backbone = previousBackbone;
- return this;
- };
-
- // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
- // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and
- // set a `X-Http-Method-Override` header.
- Backbone.emulateHTTP = false;
-
- // Turn on `emulateJSON` to support legacy servers that can't deal with direct
- // `application/json` requests ... will encode the body as
- // `application/x-www-form-urlencoded` instead and will send the model in a
- // form param named `model`.
- Backbone.emulateJSON = false;
-
- // Backbone.Events
- // ---------------
-
- // A module that can be mixed in to *any object* in order to provide it with
- // custom events. You may bind with `on` or remove with `off` callback
- // functions to an event; `trigger`-ing an event fires all callbacks in
- // succession.
- //
- // var object = {};
- // _.extend(object, Backbone.Events);
- // object.on('expand', function(){ alert('expanded'); });
- // object.trigger('expand');
- //
- var Events = Backbone.Events = {
-
- // Bind an event to a `callback` function. Passing `"all"` will bind
- // the callback to all events fired.
- on: function(name, callback, context) {
- if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
- this._events || (this._events = {});
- var events = this._events[name] || (this._events[name] = []);
- events.push({callback: callback, context: context, ctx: context || this});
- return this;
- },
-
- // Bind an event to only be triggered a single time. After the first time
- // the callback is invoked, it will be removed.
- once: function(name, callback, context) {
- if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
- var self = this;
- var once = _.once(function() {
- self.off(name, once);
- callback.apply(this, arguments);
- });
- once._callback = callback;
- return this.on(name, once, context);
- },
-
- // Remove one or many callbacks. If `context` is null, removes all
- // callbacks with that function. If `callback` is null, removes all
- // callbacks for the event. If `name` is null, removes all bound
- // callbacks for all events.
- off: function(name, callback, context) {
- var retain, ev, events, names, i, l, j, k;
- if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
- if (!name && !callback && !context) {
- this._events = {};
- return this;
- }
- names = name ? [name] : _.keys(this._events);
- for (i = 0, l = names.length; i < l; i++) {
- name = names[i];
- if (events = this._events[name]) {
- this._events[name] = retain = [];
- if (callback || context) {
- for (j = 0, k = events.length; j < k; j++) {
- ev = events[j];
- if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
- (context && context !== ev.context)) {
- retain.push(ev);
- }
- }
- }
- if (!retain.length) delete this._events[name];
- }
- }
-
- return this;
- },
-
- // Trigger one or many events, firing all bound callbacks. Callbacks are
- // passed the same arguments as `trigger` is, apart from the event name
- // (unless you're listening on `"all"`, which will cause your callback to
- // receive the true name of the event as the first argument).
- trigger: function(name) {
- if (!this._events) return this;
- var args = slice.call(arguments, 1);
- if (!eventsApi(this, 'trigger', name, args)) return this;
- var events = this._events[name];
- var allEvents = this._events.all;
- if (events) triggerEvents(events, args);
- if (allEvents) triggerEvents(allEvents, arguments);
- return this;
- },
-
- // Tell this object to stop listening to either specific events ... or
- // to every object it's currently listening to.
- stopListening: function(obj, name, callback) {
- var listeningTo = this._listeningTo;
- if (!listeningTo) return this;
- var remove = !name && !callback;
- if (!callback && typeof name === 'object') callback = this;
- if (obj) (listeningTo = {})[obj._listenId] = obj;
- for (var id in listeningTo) {
- obj = listeningTo[id];
- obj.off(name, callback, this);
- if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
- }
- return this;
- }
-
- };
-
- // Regular expression used to split event strings.
- var eventSplitter = /\s+/;
-
- // Implement fancy features of the Events API such as multiple event
- // names `"change blur"` and jQuery-style event maps `{change: action}`
- // in terms of the existing API.
- var eventsApi = function(obj, action, name, rest) {
- if (!name) return true;
-
- // Handle event maps.
- if (typeof name === 'object') {
- for (var key in name) {
- obj[action].apply(obj, [key, name[key]].concat(rest));
- }
- return false;
- }
-
- // Handle space separated event names.
- if (eventSplitter.test(name)) {
- var names = name.split(eventSplitter);
- for (var i = 0, l = names.length; i < l; i++) {
- obj[action].apply(obj, [names[i]].concat(rest));
- }
- return false;
- }
-
- return true;
- };
-
- // A difficult-to-believe, but optimized internal dispatch function for
- // triggering events. Tries to keep the usual cases speedy (most internal
- // Backbone events have 3 arguments).
- var triggerEvents = function(events, args) {
- var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
- switch (args.length) {
- case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
- case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
- case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
- case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
- default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
- }
- };
-
- var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
-
- // Inversion-of-control versions of `on` and `once`. Tell *this* object to
- // listen to an event in another object ... keeping track of what it's
- // listening to.
- _.each(listenMethods, function(implementation, method) {
- Events[method] = function(obj, name, callback) {
- var listeningTo = this._listeningTo || (this._listeningTo = {});
- var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
- listeningTo[id] = obj;
- if (!callback && typeof name === 'object') callback = this;
- obj[implementation](name, callback, this);
- return this;
- };
- });
-
- // Aliases for backwards compatibility.
- Events.bind = Events.on;
- Events.unbind = Events.off;
-
- // Allow the `Backbone` object to serve as a global event bus, for folks who
- // want global "pubsub" in a convenient place.
- _.extend(Backbone, Events);
-
- // Backbone.Model
- // --------------
-
- // Backbone **Models** are the basic data object in the framework --
- // frequently representing a row in a table in a database on your server.
- // A discrete chunk of data and a bunch of useful, related methods for
- // performing computations and transformations on that data.
-
- // Create a new model with the specified attributes. A client id (`cid`)
- // is automatically generated and assigned for you.
- var Model = Backbone.Model = function(attributes, options) {
- var attrs = attributes || {};
- options || (options = {});
- this.cid = _.uniqueId('c');
- this.attributes = {};
- if (options.collection) this.collection = options.collection;
- if (options.parse) attrs = this.parse(attrs, options) || {};
- attrs = _.defaults({}, attrs, _.result(this, 'defaults'));
- this.set(attrs, options);
- this.changed = {};
- this.initialize.apply(this, arguments);
- };
-
- // Attach all inheritable methods to the Model prototype.
- _.extend(Model.prototype, Events, {
-
- // A hash of attributes whose current and previous value differ.
- changed: null,
-
- // The value returned during the last failed validation.
- validationError: null,
-
- // The default name for the JSON `id` attribute is `"id"`. MongoDB and
- // CouchDB users may want to set this to `"_id"`.
- idAttribute: 'id',
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // Return a copy of the model's `attributes` object.
- toJSON: function(options) {
- return _.clone(this.attributes);
- },
-
- // Proxy `Backbone.sync` by default -- but override this if you need
- // custom syncing semantics for *this* particular model.
- sync: function() {
- return Backbone.sync.apply(this, arguments);
- },
-
- // Get the value of an attribute.
- get: function(attr) {
- return this.attributes[attr];
- },
-
- // Get the HTML-escaped value of an attribute.
- escape: function(attr) {
- return _.escape(this.get(attr));
- },
-
- // Returns `true` if the attribute contains a value that is not null
- // or undefined.
- has: function(attr) {
- return this.get(attr) != null;
- },
-
- // Set a hash of model attributes on the object, firing `"change"`. This is
- // the core primitive operation of a model, updating the data and notifying
- // anyone who needs to know about the change in state. The heart of the beast.
- set: function(key, val, options) {
- var attr, attrs, unset, changes, silent, changing, prev, current;
- if (key == null) return this;
-
- // Handle both `"key", value` and `{key: value}` -style arguments.
- if (typeof key === 'object') {
- attrs = key;
- options = val;
- } else {
- (attrs = {})[key] = val;
- }
-
- options || (options = {});
-
- // Run validation.
- if (!this._validate(attrs, options)) return false;
-
- // Extract attributes and options.
- unset = options.unset;
- silent = options.silent;
- changes = [];
- changing = this._changing;
- this._changing = true;
-
- if (!changing) {
- this._previousAttributes = _.clone(this.attributes);
- this.changed = {};
- }
- current = this.attributes, prev = this._previousAttributes;
-
- // Check for changes of `id`.
- if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
-
- // For each `set` attribute, update or delete the current value.
- for (attr in attrs) {
- val = attrs[attr];
- if (!_.isEqual(current[attr], val)) changes.push(attr);
- if (!_.isEqual(prev[attr], val)) {
- this.changed[attr] = val;
- } else {
- delete this.changed[attr];
- }
- unset ? delete current[attr] : current[attr] = val;
- }
-
- // Trigger all relevant attribute changes.
- if (!silent) {
- if (changes.length) this._pending = true;
- for (var i = 0, l = changes.length; i < l; i++) {
- this.trigger('change:' + changes[i], this, current[changes[i]], options);
- }
- }
-
- // You might be wondering why there's a `while` loop here. Changes can
- // be recursively nested within `"change"` events.
- if (changing) return this;
- if (!silent) {
- while (this._pending) {
- this._pending = false;
- this.trigger('change', this, options);
- }
- }
- this._pending = false;
- this._changing = false;
- return this;
- },
-
- // Remove an attribute from the model, firing `"change"`. `unset` is a noop
- // if the attribute doesn't exist.
- unset: function(attr, options) {
- return this.set(attr, void 0, _.extend({}, options, {unset: true}));
- },
-
- // Clear all attributes on the model, firing `"change"`.
- clear: function(options) {
- var attrs = {};
- for (var key in this.attributes) attrs[key] = void 0;
- return this.set(attrs, _.extend({}, options, {unset: true}));
- },
-
- // Determine if the model has changed since the last `"change"` event.
- // If you specify an attribute name, determine if that attribute has changed.
- hasChanged: function(attr) {
- if (attr == null) return !_.isEmpty(this.changed);
- return _.has(this.changed, attr);
- },
-
- // Return an object containing all the attributes that have changed, or
- // false if there are no changed attributes. Useful for determining what
- // parts of a view need to be updated and/or what attributes need to be
- // persisted to the server. Unset attributes will be set to undefined.
- // You can also pass an attributes object to diff against the model,
- // determining if there *would be* a change.
- changedAttributes: function(diff) {
- if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
- var val, changed = false;
- var old = this._changing ? this._previousAttributes : this.attributes;
- for (var attr in diff) {
- if (_.isEqual(old[attr], (val = diff[attr]))) continue;
- (changed || (changed = {}))[attr] = val;
- }
- return changed;
- },
-
- // Get the previous value of an attribute, recorded at the time the last
- // `"change"` event was fired.
- previous: function(attr) {
- if (attr == null || !this._previousAttributes) return null;
- return this._previousAttributes[attr];
- },
-
- // Get all of the attributes of the model at the time of the previous
- // `"change"` event.
- previousAttributes: function() {
- return _.clone(this._previousAttributes);
- },
-
- // Fetch the model from the server. If the server's representation of the
- // model differs from its current attributes, they will be overridden,
- // triggering a `"change"` event.
- fetch: function(options) {
- options = options ? _.clone(options) : {};
- if (options.parse === void 0) options.parse = true;
- var model = this;
- var success = options.success;
- options.success = function(resp) {
- if (!model.set(model.parse(resp, options), options)) return false;
- if (success) success(model, resp, options);
- model.trigger('sync', model, resp, options);
- };
- wrapError(this, options);
- return this.sync('read', this, options);
- },
-
- // Set a hash of model attributes, and sync the model to the server.
- // If the server returns an attributes hash that differs, the model's
- // state will be `set` again.
- save: function(key, val, options) {
- var attrs, method, xhr, attributes = this.attributes;
-
- // Handle both `"key", value` and `{key: value}` -style arguments.
- if (key == null || typeof key === 'object') {
- attrs = key;
- options = val;
- } else {
- (attrs = {})[key] = val;
- }
-
- options = _.extend({validate: true}, options);
-
- // If we're not waiting and attributes exist, save acts as
- // `set(attr).save(null, opts)` with validation. Otherwise, check if
- // the model will be valid when the attributes, if any, are set.
- if (attrs && !options.wait) {
- if (!this.set(attrs, options)) return false;
- } else {
- if (!this._validate(attrs, options)) return false;
- }
-
- // Set temporary attributes if `{wait: true}`.
- if (attrs && options.wait) {
- this.attributes = _.extend({}, attributes, attrs);
- }
-
- // After a successful server-side save, the client is (optionally)
- // updated with the server-side state.
- if (options.parse === void 0) options.parse = true;
- var model = this;
- var success = options.success;
- options.success = function(resp) {
- // Ensure attributes are restored during synchronous saves.
- model.attributes = attributes;
- var serverAttrs = model.parse(resp, options);
- if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
- if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
- return false;
- }
- if (success) success(model, resp, options);
- model.trigger('sync', model, resp, options);
- };
- wrapError(this, options);
-
- method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
- if (method === 'patch') options.attrs = attrs;
- xhr = this.sync(method, this, options);
-
- // Restore attributes.
- if (attrs && options.wait) this.attributes = attributes;
-
- return xhr;
- },
-
- // Destroy this model on the server if it was already persisted.
- // Optimistically removes the model from its collection, if it has one.
- // If `wait: true` is passed, waits for the server to respond before removal.
- destroy: function(options) {
- options = options ? _.clone(options) : {};
- var model = this;
- var success = options.success;
-
- var destroy = function() {
- model.trigger('destroy', model, model.collection, options);
- };
-
- options.success = function(resp) {
- if (options.wait || model.isNew()) destroy();
- if (success) success(model, resp, options);
- if (!model.isNew()) model.trigger('sync', model, resp, options);
- };
-
- if (this.isNew()) {
- options.success();
- return false;
- }
- wrapError(this, options);
-
- var xhr = this.sync('delete', this, options);
- if (!options.wait) destroy();
- return xhr;
- },
-
- // Default URL for the model's representation on the server -- if you're
- // using Backbone's restful methods, override this to change the endpoint
- // that will be called.
- url: function() {
- var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
- if (this.isNew()) return base;
- return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
- },
-
- // **parse** converts a response into the hash of attributes to be `set` on
- // the model. The default implementation is just to pass the response along.
- parse: function(resp, options) {
- return resp;
- },
-
- // Create a new model with identical attributes to this one.
- clone: function() {
- return new this.constructor(this.attributes);
- },
-
- // A model is new if it has never been saved to the server, and lacks an id.
- isNew: function() {
- return this.id == null;
- },
-
- // Check if the model is currently in a valid state.
- isValid: function(options) {
- return this._validate({}, _.extend(options || {}, { validate: true }));
- },
-
- // Run validation against the next complete set of model attributes,
- // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
- _validate: function(attrs, options) {
- if (!options.validate || !this.validate) return true;
- attrs = _.extend({}, this.attributes, attrs);
- var error = this.validationError = this.validate(attrs, options) || null;
- if (!error) return true;
- this.trigger('invalid', this, error, _.extend(options, {validationError: error}));
- return false;
- }
-
- });
-
- // Underscore methods that we want to implement on the Model.
- var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
-
- // Mix in each Underscore method as a proxy to `Model#attributes`.
- _.each(modelMethods, function(method) {
- Model.prototype[method] = function() {
- var args = slice.call(arguments);
- args.unshift(this.attributes);
- return _[method].apply(_, args);
- };
- });
-
- // Backbone.Collection
- // -------------------
-
- // If models tend to represent a single row of data, a Backbone Collection is
- // more analagous to a table full of data ... or a small slice or page of that
- // table, or a collection of rows that belong together for a particular reason
- // -- all of the messages in this particular folder, all of the documents
- // belonging to this particular author, and so on. Collections maintain
- // indexes of their models, both in order, and for lookup by `id`.
-
- // Create a new **Collection**, perhaps to contain a specific type of `model`.
- // If a `comparator` is specified, the Collection will maintain
- // its models in sort order, as they're added and removed.
- var Collection = Backbone.Collection = function(models, options) {
- options || (options = {});
- if (options.model) this.model = options.model;
- if (options.comparator !== void 0) this.comparator = options.comparator;
- this._reset();
- this.initialize.apply(this, arguments);
- if (models) this.reset(models, _.extend({silent: true}, options));
- };
-
- // Default options for `Collection#set`.
- var setOptions = {add: true, remove: true, merge: true};
- var addOptions = {add: true, remove: false};
-
- // Define the Collection's inheritable methods.
- _.extend(Collection.prototype, Events, {
-
- // The default model for a collection is just a **Backbone.Model**.
- // This should be overridden in most cases.
- model: Model,
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // The JSON representation of a Collection is an array of the
- // models' attributes.
- toJSON: function(options) {
- return this.map(function(model){ return model.toJSON(options); });
- },
-
- // Proxy `Backbone.sync` by default.
- sync: function() {
- return Backbone.sync.apply(this, arguments);
- },
-
- // Add a model, or list of models to the set.
- add: function(models, options) {
- return this.set(models, _.extend({merge: false}, options, addOptions));
- },
-
- // Remove a model, or a list of models from the set.
- remove: function(models, options) {
- var singular = !_.isArray(models);
- models = singular ? [models] : _.clone(models);
- options || (options = {});
- var i, l, index, model;
- for (i = 0, l = models.length; i < l; i++) {
- model = models[i] = this.get(models[i]);
- if (!model) continue;
- delete this._byId[model.id];
- delete this._byId[model.cid];
- index = this.indexOf(model);
- this.models.splice(index, 1);
- this.length--;
- if (!options.silent) {
- options.index = index;
- model.trigger('remove', model, this, options);
- }
- this._removeReference(model);
- }
- return singular ? models[0] : models;
- },
-
- // Update a collection by `set`-ing a new list of models, adding new ones,
- // removing models that are no longer present, and merging models that
- // already exist in the collection, as necessary. Similar to **Model#set**,
- // the core operation for updating the data contained by the collection.
- set: function(models, options) {
- options = _.defaults({}, options, setOptions);
- if (options.parse) models = this.parse(models, options);
- var singular = !_.isArray(models);
- models = singular ? (models ? [models] : []) : _.clone(models);
- var i, l, id, model, attrs, existing, sort;
- var at = options.at;
- var targetModel = this.model;
- var sortable = this.comparator && (at == null) && options.sort !== false;
- var sortAttr = _.isString(this.comparator) ? this.comparator : null;
- var toAdd = [], toRemove = [], modelMap = {};
- var add = options.add, merge = options.merge, remove = options.remove;
- var order = !sortable && add && remove ? [] : false;
-
- // Turn bare objects into model references, and prevent invalid models
- // from being added.
- for (i = 0, l = models.length; i < l; i++) {
- attrs = models[i];
- if (attrs instanceof Model) {
- id = model = attrs;
- } else {
- id = attrs[targetModel.prototype.idAttribute];
- }
-
- // If a duplicate is found, prevent it from being added and
- // optionally merge it into the existing model.
- if (existing = this.get(id)) {
- if (remove) modelMap[existing.cid] = true;
- if (merge) {
- attrs = attrs === model ? model.attributes : attrs;
- if (options.parse) attrs = existing.parse(attrs, options);
- existing.set(attrs, options);
- if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
- }
- models[i] = existing;
-
- // If this is a new, valid model, push it to the `toAdd` list.
- } else if (add) {
- model = models[i] = this._prepareModel(attrs, options);
- if (!model) continue;
- toAdd.push(model);
-
- // Listen to added models' events, and index models for lookup by
- // `id` and by `cid`.
- model.on('all', this._onModelEvent, this);
- this._byId[model.cid] = model;
- if (model.id != null) this._byId[model.id] = model;
- }
- if (order) order.push(existing || model);
- }
-
- // Remove nonexistent models if appropriate.
- if (remove) {
- for (i = 0, l = this.length; i < l; ++i) {
- if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
- }
- if (toRemove.length) this.remove(toRemove, options);
- }
-
- // See if sorting is needed, update `length` and splice in new models.
- if (toAdd.length || (order && order.length)) {
- if (sortable) sort = true;
- this.length += toAdd.length;
- if (at != null) {
- for (i = 0, l = toAdd.length; i < l; i++) {
- this.models.splice(at + i, 0, toAdd[i]);
- }
- } else {
- if (order) this.models.length = 0;
- var orderedModels = order || toAdd;
- for (i = 0, l = orderedModels.length; i < l; i++) {
- this.models.push(orderedModels[i]);
- }
- }
- }
-
- // Silently sort the collection if appropriate.
- if (sort) this.sort({silent: true});
-
- // Unless silenced, it's time to fire all appropriate add/sort events.
- if (!options.silent) {
- for (i = 0, l = toAdd.length; i < l; i++) {
- (model = toAdd[i]).trigger('add', model, this, options);
- }
- if (sort || (order && order.length)) this.trigger('sort', this, options);
- }
-
- // Return the added (or merged) model (or models).
- return singular ? models[0] : models;
- },
-
- // When you have more items than you want to add or remove individually,
- // you can reset the entire set with a new list of models, without firing
- // any granular `add` or `remove` events. Fires `reset` when finished.
- // Useful for bulk operations and optimizations.
- reset: function(models, options) {
- options || (options = {});
- for (var i = 0, l = this.models.length; i < l; i++) {
- this._removeReference(this.models[i]);
- }
- options.previousModels = this.models;
- this._reset();
- models = this.add(models, _.extend({silent: true}, options));
- if (!options.silent) this.trigger('reset', this, options);
- return models;
- },
-
- // Add a model to the end of the collection.
- push: function(model, options) {
- return this.add(model, _.extend({at: this.length}, options));
- },
-
- // Remove a model from the end of the collection.
- pop: function(options) {
- var model = this.at(this.length - 1);
- this.remove(model, options);
- return model;
- },
-
- // Add a model to the beginning of the collection.
- unshift: function(model, options) {
- return this.add(model, _.extend({at: 0}, options));
- },
-
- // Remove a model from the beginning of the collection.
- shift: function(options) {
- var model = this.at(0);
- this.remove(model, options);
- return model;
- },
-
- // Slice out a sub-array of models from the collection.
- slice: function() {
- return slice.apply(this.models, arguments);
- },
-
- // Get a model from the set by id.
- get: function(obj) {
- if (obj == null) return void 0;
- return this._byId[obj.id] || this._byId[obj.cid] || this._byId[obj];
- },
-
- // Get the model at the given index.
- at: function(index) {
- return this.models[index];
- },
-
- // Return models with matching attributes. Useful for simple cases of
- // `filter`.
- where: function(attrs, first) {
- if (_.isEmpty(attrs)) return first ? void 0 : [];
- return this[first ? 'find' : 'filter'](function(model) {
- for (var key in attrs) {
- if (attrs[key] !== model.get(key)) return false;
- }
- return true;
- });
- },
-
- // Return the first model with matching attributes. Useful for simple cases
- // of `find`.
- findWhere: function(attrs) {
- return this.where(attrs, true);
- },
-
- // Force the collection to re-sort itself. You don't need to call this under
- // normal circumstances, as the set will maintain sort order as each item
- // is added.
- sort: function(options) {
- if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
- options || (options = {});
-
- // Run sort based on type of `comparator`.
- if (_.isString(this.comparator) || this.comparator.length === 1) {
- this.models = this.sortBy(this.comparator, this);
- } else {
- this.models.sort(_.bind(this.comparator, this));
- }
-
- if (!options.silent) this.trigger('sort', this, options);
- return this;
- },
-
- // Pluck an attribute from each model in the collection.
- pluck: function(attr) {
- return _.invoke(this.models, 'get', attr);
- },
-
- // Fetch the default set of models for this collection, resetting the
- // collection when they arrive. If `reset: true` is passed, the response
- // data will be passed through the `reset` method instead of `set`.
- fetch: function(options) {
- options = options ? _.clone(options) : {};
- if (options.parse === void 0) options.parse = true;
- var success = options.success;
- var collection = this;
- options.success = function(resp) {
- var method = options.reset ? 'reset' : 'set';
- collection[method](resp, options);
- if (success) success(collection, resp, options);
- collection.trigger('sync', collection, resp, options);
- };
- wrapError(this, options);
- return this.sync('read', this, options);
- },
-
- // Create a new instance of a model in this collection. Add the model to the
- // collection immediately, unless `wait: true` is passed, in which case we
- // wait for the server to agree.
- create: function(model, options) {
- options = options ? _.clone(options) : {};
- if (!(model = this._prepareModel(model, options))) return false;
- if (!options.wait) this.add(model, options);
- var collection = this;
- var success = options.success;
- options.success = function(model, resp, options) {
- if (options.wait) collection.add(model, options);
- if (success) success(model, resp, options);
- };
- model.save(null, options);
- return model;
- },
-
- // **parse** converts a response into a list of models to be added to the
- // collection. The default implementation is just to pass it through.
- parse: function(resp, options) {
- return resp;
- },
-
- // Create a new collection with an identical list of models as this one.
- clone: function() {
- return new this.constructor(this.models);
- },
-
- // Private method to reset all internal state. Called when the collection
- // is first initialized or reset.
- _reset: function() {
- this.length = 0;
- this.models = [];
- this._byId = {};
- },
-
- // Prepare a hash of attributes (or other model) to be added to this
- // collection.
- _prepareModel: function(attrs, options) {
- if (attrs instanceof Model) {
- if (!attrs.collection) attrs.collection = this;
- return attrs;
- }
- options = options ? _.clone(options) : {};
- options.collection = this;
- var model = new this.model(attrs, options);
- if (!model.validationError) return model;
- this.trigger('invalid', this, model.validationError, options);
- return false;
- },
-
- // Internal method to sever a model's ties to a collection.
- _removeReference: function(model) {
- if (this === model.collection) delete model.collection;
- model.off('all', this._onModelEvent, this);
- },
-
- // Internal method called every time a model in the set fires an event.
- // Sets need to update their indexes when models change ids. All other
- // events simply proxy through. "add" and "remove" events that originate
- // in other collections are ignored.
- _onModelEvent: function(event, model, collection, options) {
- if ((event === 'add' || event === 'remove') && collection !== this) return;
- if (event === 'destroy') this.remove(model, options);
- if (model && event === 'change:' + model.idAttribute) {
- delete this._byId[model.previous(model.idAttribute)];
- if (model.id != null) this._byId[model.id] = model;
- }
- this.trigger.apply(this, arguments);
- }
-
- });
-
- // Underscore methods that we want to implement on the Collection.
- // 90% of the core usefulness of Backbone Collections is actually implemented
- // right here:
- var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
- 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
- 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
- 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
- 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
- 'lastIndexOf', 'isEmpty', 'chain'];
-
- // Mix in each Underscore method as a proxy to `Collection#models`.
- _.each(methods, function(method) {
- Collection.prototype[method] = function() {
- var args = slice.call(arguments);
- args.unshift(this.models);
- return _[method].apply(_, args);
- };
- });
-
- // Underscore methods that take a property name as an argument.
- var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
-
- // Use attributes instead of properties.
- _.each(attributeMethods, function(method) {
- Collection.prototype[method] = function(value, context) {
- var iterator = _.isFunction(value) ? value : function(model) {
- return model.get(value);
- };
- return _[method](this.models, iterator, context);
- };
- });
-
- // Backbone.View
- // -------------
-
- // Backbone Views are almost more convention than they are actual code. A View
- // is simply a JavaScript object that represents a logical chunk of UI in the
- // DOM. This might be a single item, an entire list, a sidebar or panel, or
- // even the surrounding frame which wraps your whole app. Defining a chunk of
- // UI as a **View** allows you to define your DOM events declaratively, without
- // having to worry about render order ... and makes it easy for the view to
- // react to specific changes in the state of your models.
-
- // Creating a Backbone.View creates its initial element outside of the DOM,
- // if an existing element is not provided...
- var View = Backbone.View = function(options) {
- this.cid = _.uniqueId('view');
- options || (options = {});
- _.extend(this, _.pick(options, viewOptions));
- this._ensureElement();
- this.initialize.apply(this, arguments);
- this.delegateEvents();
- };
-
- // Cached regex to split keys for `delegate`.
- var delegateEventSplitter = /^(\S+)\s*(.*)$/;
-
- // List of view options to be merged as properties.
- var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
-
- // Set up all inheritable **Backbone.View** properties and methods.
- _.extend(View.prototype, Events, {
-
- // The default `tagName` of a View's element is `"div"`.
- tagName: 'div',
-
- // jQuery delegate for element lookup, scoped to DOM elements within the
- // current view. This should be preferred to global lookups where possible.
- $: function(selector) {
- return this.$el.find(selector);
- },
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // **render** is the core function that your view should override, in order
- // to populate its element (`this.el`), with the appropriate HTML. The
- // convention is for **render** to always return `this`.
- render: function() {
- return this;
- },
-
- // Remove this view by taking the element out of the DOM, and removing any
- // applicable Backbone.Events listeners.
- remove: function() {
- this.$el.remove();
- this.stopListening();
- return this;
- },
-
- // Change the view's element (`this.el` property), including event
- // re-delegation.
- setElement: function(element, delegate) {
- if (this.$el) this.undelegateEvents();
- this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
- this.el = this.$el[0];
- if (delegate !== false) this.delegateEvents();
- return this;
- },
-
- // Set callbacks, where `this.events` is a hash of
- //
- // *{"event selector": "callback"}*
- //
- // {
- // 'mousedown .title': 'edit',
- // 'click .button': 'save',
- // 'click .open': function(e) { ... }
- // }
- //
- // pairs. Callbacks will be bound to the view, with `this` set properly.
- // Uses event delegation for efficiency.
- // Omitting the selector binds the event to `this.el`.
- // This only works for delegate-able events: not `focus`, `blur`, and
- // not `change`, `submit`, and `reset` in Internet Explorer.
- delegateEvents: function(events) {
- if (!(events || (events = _.result(this, 'events')))) return this;
- this.undelegateEvents();
- for (var key in events) {
- var method = events[key];
- if (!_.isFunction(method)) method = this[events[key]];
- if (!method) continue;
-
- var match = key.match(delegateEventSplitter);
- var eventName = match[1], selector = match[2];
- method = _.bind(method, this);
- eventName += '.delegateEvents' + this.cid;
- if (selector === '') {
- this.$el.on(eventName, method);
- } else {
- this.$el.on(eventName, selector, method);
- }
- }
- return this;
- },
-
- // Clears all callbacks previously bound to the view with `delegateEvents`.
- // You usually don't need to use this, but may wish to if you have multiple
- // Backbone views attached to the same DOM element.
- undelegateEvents: function() {
- this.$el.off('.delegateEvents' + this.cid);
- return this;
- },
-
- // Ensure that the View has a DOM element to render into.
- // If `this.el` is a string, pass it through `$()`, take the first
- // matching element, and re-assign it to `el`. Otherwise, create
- // an element from the `id`, `className` and `tagName` properties.
- _ensureElement: function() {
- if (!this.el) {
- var attrs = _.extend({}, _.result(this, 'attributes'));
- if (this.id) attrs.id = _.result(this, 'id');
- if (this.className) attrs['class'] = _.result(this, 'className');
- var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
- this.setElement($el, false);
- } else {
- this.setElement(_.result(this, 'el'), false);
- }
- }
-
- });
-
- // Backbone.sync
- // -------------
-
- // Override this function to change the manner in which Backbone persists
- // models to the server. You will be passed the type of request, and the
- // model in question. By default, makes a RESTful Ajax request
- // to the model's `url()`. Some possible customizations could be:
- //
- // * Use `setTimeout` to batch rapid-fire updates into a single request.
- // * Send up the models as XML instead of JSON.
- // * Persist models via WebSockets instead of Ajax.
- //
- // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
- // as `POST`, with a `_method` parameter containing the true HTTP method,
- // as well as all requests with the body as `application/x-www-form-urlencoded`
- // instead of `application/json` with the model in a param named `model`.
- // Useful when interfacing with server-side languages like **PHP** that make
- // it difficult to read the body of `PUT` requests.
- Backbone.sync = function(method, model, options) {
- var type = methodMap[method];
-
- // Default options, unless specified.
- _.defaults(options || (options = {}), {
- emulateHTTP: Backbone.emulateHTTP,
- emulateJSON: Backbone.emulateJSON
- });
-
- // Default JSON-request options.
- var params = {type: type, dataType: 'json'};
-
- // Ensure that we have a URL.
- if (!options.url) {
- params.url = _.result(model, 'url') || urlError();
- }
-
- // Ensure that we have the appropriate request data.
- if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
- params.contentType = 'application/json';
- params.data = JSON.stringify(options.attrs || model.toJSON(options));
- }
-
- // For older servers, emulate JSON by encoding the request into an HTML-form.
- if (options.emulateJSON) {
- params.contentType = 'application/x-www-form-urlencoded';
- params.data = params.data ? {model: params.data} : {};
- }
-
- // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
- // And an `X-HTTP-Method-Override` header.
- if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
- params.type = 'POST';
- if (options.emulateJSON) params.data._method = type;
- var beforeSend = options.beforeSend;
- options.beforeSend = function(xhr) {
- xhr.setRequestHeader('X-HTTP-Method-Override', type);
- if (beforeSend) return beforeSend.apply(this, arguments);
- };
- }
-
- // Don't process data on a non-GET request.
- if (params.type !== 'GET' && !options.emulateJSON) {
- params.processData = false;
- }
-
- // If we're sending a `PATCH` request, and we're in an old Internet Explorer
- // that still has ActiveX enabled by default, override jQuery to use that
- // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
- if (params.type === 'PATCH' && noXhrPatch) {
- params.xhr = function() {
- return new ActiveXObject("Microsoft.XMLHTTP");
- };
- }
-
- // Make the request, allowing the user to override any Ajax options.
- var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
- model.trigger('request', model, xhr, options);
- return xhr;
- };
-
- var noXhrPatch = typeof window !== 'undefined' && !!window.ActiveXObject && !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
-
- // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
- var methodMap = {
- 'create': 'POST',
- 'update': 'PUT',
- 'patch': 'PATCH',
- 'delete': 'DELETE',
- 'read': 'GET'
- };
-
- // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
- // Override this if you'd like to use a different library.
- Backbone.ajax = function() {
- return Backbone.$.ajax.apply(Backbone.$, arguments);
- };
-
- // Backbone.Router
- // ---------------
-
- // Routers map faux-URLs to actions, and fire events when routes are
- // matched. Creating a new one sets its `routes` hash, if not set statically.
- var Router = Backbone.Router = function(options) {
- options || (options = {});
- if (options.routes) this.routes = options.routes;
- this._bindRoutes();
- this.initialize.apply(this, arguments);
- };
-
- // Cached regular expressions for matching named param parts and splatted
- // parts of route strings.
- var optionalParam = /\((.*?)\)/g;
- var namedParam = /(\(\?)?:\w+/g;
- var splatParam = /\*\w+/g;
- var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g;
-
- // Set up all inheritable **Backbone.Router** properties and methods.
- _.extend(Router.prototype, Events, {
-
- // Initialize is an empty function by default. Override it with your own
- // initialization logic.
- initialize: function(){},
-
- // Manually bind a single named route to a callback. For example:
- //
- // this.route('search/:query/p:num', 'search', function(query, num) {
- // ...
- // });
- //
- route: function(route, name, callback) {
- if (!_.isRegExp(route)) route = this._routeToRegExp(route);
- if (_.isFunction(name)) {
- callback = name;
- name = '';
- }
- if (!callback) callback = this[name];
- var router = this;
- Backbone.history.route(route, function(fragment) {
- var args = router._extractParameters(route, fragment);
- callback && callback.apply(router, args);
- router.trigger.apply(router, ['route:' + name].concat(args));
- router.trigger('route', name, args);
- Backbone.history.trigger('route', router, name, args);
- });
- return this;
- },
-
- // Simple proxy to `Backbone.history` to save a fragment into the history.
- navigate: function(fragment, options) {
- Backbone.history.navigate(fragment, options);
- return this;
- },
-
- // Bind all defined routes to `Backbone.history`. We have to reverse the
- // order of the routes here to support behavior where the most general
- // routes can be defined at the bottom of the route map.
- _bindRoutes: function() {
- if (!this.routes) return;
- this.routes = _.result(this, 'routes');
- var route, routes = _.keys(this.routes);
- while ((route = routes.pop()) != null) {
- this.route(route, this.routes[route]);
- }
- },
-
- // Convert a route string into a regular expression, suitable for matching
- // against the current location hash.
- _routeToRegExp: function(route) {
- route = route.replace(escapeRegExp, '\\$&')
- .replace(optionalParam, '(?:$1)?')
- .replace(namedParam, function(match, optional) {
- return optional ? match : '([^\/]+)';
- })
- .replace(splatParam, '(.*?)');
- return new RegExp('^' + route + '$');
- },
-
- // Given a route, and a URL fragment that it matches, return the array of
- // extracted decoded parameters. Empty or unmatched parameters will be
- // treated as `null` to normalize cross-browser behavior.
- _extractParameters: function(route, fragment) {
- var params = route.exec(fragment).slice(1);
- return _.map(params, function(param) {
- return param ? decodeURIComponent(param) : null;
- });
- }
-
- });
-
- // Backbone.History
- // ----------------
-
- // Handles cross-browser history management, based on either
- // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
- // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
- // and URL fragments. If the browser supports neither (old IE, natch),
- // falls back to polling.
- var History = Backbone.History = function() {
- this.handlers = [];
- _.bindAll(this, 'checkUrl');
-
- // Ensure that `History` can be used outside of the browser.
- if (typeof window !== 'undefined') {
- this.location = window.location;
- this.history = window.history;
- }
- };
-
- // Cached regex for stripping a leading hash/slash and trailing space.
- var routeStripper = /^[#\/]|\s+$/g;
-
- // Cached regex for stripping leading and trailing slashes.
- var rootStripper = /^\/+|\/+$/g;
-
- // Cached regex for detecting MSIE.
- var isExplorer = /msie [\w.]+/;
-
- // Cached regex for removing a trailing slash.
- var trailingSlash = /\/$/;
-
- // Cached regex for stripping urls of hash and query.
- var pathStripper = /[?#].*$/;
-
- // Has the history handling already been started?
- History.started = false;
-
- // Set up all inheritable **Backbone.History** properties and methods.
- _.extend(History.prototype, Events, {
-
- // The default interval to poll for hash changes, if necessary, is
- // twenty times a second.
- interval: 50,
-
- // Gets the true hash value. Cannot use location.hash directly due to bug
- // in Firefox where location.hash will always be decoded.
- getHash: function(window) {
- var match = (window || this).location.href.match(/#(.*)$/);
- return match ? match[1] : '';
- },
-
- // Get the cross-browser normalized URL fragment, either from the URL,
- // the hash, or the override.
- getFragment: function(fragment, forcePushState) {
- if (fragment == null) {
- if (this._hasPushState || !this._wantsHashChange || forcePushState) {
- fragment = this.location.pathname;
- var root = this.root.replace(trailingSlash, '');
- if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
- } else {
- fragment = this.getHash();
- }
- }
- return fragment.replace(routeStripper, '');
- },
-
- // Start the hash change handling, returning `true` if the current URL matches
- // an existing route, and `false` otherwise.
- start: function(options) {
- if (History.started) throw new Error("Backbone.history has already been started");
- History.started = true;
-
- // Figure out the initial configuration. Do we need an iframe?
- // Is pushState desired ... is it available?
- this.options = _.extend({root: '/'}, this.options, options);
- this.root = this.options.root;
- this._wantsHashChange = this.options.hashChange !== false;
- this._wantsPushState = !!this.options.pushState;
- this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState);
- var fragment = this.getFragment();
- var docMode = document.documentMode;
- var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
-
- // Normalize root to always include a leading and trailing slash.
- this.root = ('/' + this.root + '/').replace(rootStripper, '/');
-
- if (oldIE && this._wantsHashChange) {
- this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
- this.navigate(fragment);
- }
-
- // Depending on whether we're using pushState or hashes, and whether
- // 'onhashchange' is supported, determine how we check the URL state.
- if (this._hasPushState) {
- Backbone.$(window).on('popstate', this.checkUrl);
- } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
- Backbone.$(window).on('hashchange', this.checkUrl);
- } else if (this._wantsHashChange) {
- this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
- }
-
- // Determine if we need to change the base url, for a pushState link
- // opened by a non-pushState browser.
- this.fragment = fragment;
- var loc = this.location;
- var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
-
- // Transition from hashChange to pushState or vice versa if both are
- // requested.
- if (this._wantsHashChange && this._wantsPushState) {
-
- // If we've started off with a route from a `pushState`-enabled
- // browser, but we're currently in a browser that doesn't support it...
- if (!this._hasPushState && !atRoot) {
- this.fragment = this.getFragment(null, true);
- this.location.replace(this.root + this.location.search + '#' + this.fragment);
- // Return immediately as browser will do redirect to new url
- return true;
-
- // Or if we've started out with a hash-based route, but we're currently
- // in a browser where it could be `pushState`-based instead...
- } else if (this._hasPushState && atRoot && loc.hash) {
- this.fragment = this.getHash().replace(routeStripper, '');
- this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
- }
-
- }
-
- if (!this.options.silent) return this.loadUrl();
- },
-
- // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
- // but possibly useful for unit testing Routers.
- stop: function() {
- Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
- clearInterval(this._checkUrlInterval);
- History.started = false;
- },
-
- // Add a route to be tested when the fragment changes. Routes added later
- // may override previous routes.
- route: function(route, callback) {
- this.handlers.unshift({route: route, callback: callback});
- },
-
- // Checks the current URL to see if it has changed, and if it has,
- // calls `loadUrl`, normalizing across the hidden iframe.
- checkUrl: function(e) {
- var current = this.getFragment();
- if (current === this.fragment && this.iframe) {
- current = this.getFragment(this.getHash(this.iframe));
- }
- if (current === this.fragment) return false;
- if (this.iframe) this.navigate(current);
- this.loadUrl();
- },
-
- // Attempt to load the current URL fragment. If a route succeeds with a
- // match, returns `true`. If no defined routes matches the fragment,
- // returns `false`.
- loadUrl: function(fragment) {
- fragment = this.fragment = this.getFragment(fragment);
- return _.any(this.handlers, function(handler) {
- if (handler.route.test(fragment)) {
- handler.callback(fragment);
- return true;
- }
- });
- },
-
- // Save a fragment into the hash history, or replace the URL state if the
- // 'replace' option is passed. You are responsible for properly URL-encoding
- // the fragment in advance.
- //
- // The options object can contain `trigger: true` if you wish to have the
- // route callback be fired (not usually desirable), or `replace: true`, if
- // you wish to modify the current URL without adding an entry to the history.
- navigate: function(fragment, options) {
- if (!History.started) return false;
- if (!options || options === true) options = {trigger: !!options};
-
- var url = this.root + (fragment = this.getFragment(fragment || ''));
-
- // Strip the fragment of the query and hash for matching.
- fragment = fragment.replace(pathStripper, '');
-
- if (this.fragment === fragment) return;
- this.fragment = fragment;
-
- // Don't include a trailing slash on the root.
- if (fragment === '' && url !== '/') url = url.slice(0, -1);
-
- // If pushState is available, we use it to set the fragment as a real URL.
- if (this._hasPushState) {
- this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
-
- // If hash changes haven't been explicitly disabled, update the hash
- // fragment to store history.
- } else if (this._wantsHashChange) {
- this._updateHash(this.location, fragment, options.replace);
- if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
- // Opening and closing the iframe tricks IE7 and earlier to push a
- // history entry on hash-tag change. When replace is true, we don't
- // want this.
- if(!options.replace) this.iframe.document.open().close();
- this._updateHash(this.iframe.location, fragment, options.replace);
- }
-
- // If you've told us that you explicitly don't want fallback hashchange-
- // based history, then `navigate` becomes a page refresh.
- } else {
- return this.location.assign(url);
- }
- if (options.trigger) return this.loadUrl(fragment);
- },
-
- // Update the hash location, either replacing the current entry, or adding
- // a new one to the browser history.
- _updateHash: function(location, fragment, replace) {
- if (replace) {
- var href = location.href.replace(/(javascript:|#).*$/, '');
- location.replace(href + '#' + fragment);
- } else {
- // Some browsers require that `hash` contains a leading #.
- location.hash = '#' + fragment;
- }
- }
-
- });
-
- // Create the default Backbone.history.
- Backbone.history = new History;
-
- // Helpers
- // -------
-
- // Helper function to correctly set up the prototype chain, for subclasses.
- // Similar to `goog.inherits`, but uses a hash of prototype properties and
- // class properties to be extended.
- var extend = function(protoProps, staticProps) {
- var parent = this;
- var child;
-
- // The constructor function for the new subclass is either defined by you
- // (the "constructor" property in your `extend` definition), or defaulted
- // by us to simply call the parent's constructor.
- if (protoProps && _.has(protoProps, 'constructor')) {
- child = protoProps.constructor;
- } else {
- child = function(){ return parent.apply(this, arguments); };
- }
-
- // Add static properties to the constructor function, if supplied.
- _.extend(child, parent, staticProps);
-
- // Set the prototype chain to inherit from `parent`, without calling
- // `parent`'s constructor function.
- var Surrogate = function(){ this.constructor = child; };
- Surrogate.prototype = parent.prototype;
- child.prototype = new Surrogate;
-
- // Add prototype properties (instance properties) to the subclass,
- // if supplied.
- if (protoProps) _.extend(child.prototype, protoProps);
-
- // Set a convenience property in case the parent's prototype is needed
- // later.
- child.__super__ = parent.prototype;
-
- return child;
- };
-
- // Set up inheritance for the model, collection, router, view and history.
- Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
-
- // Throw an error when a URL is needed, and none is supplied.
- var urlError = function() {
- throw new Error('A "url" property or function must be specified');
- };
-
- // Wrap an optional error callback with a fallback error event.
- var wrapError = function(model, options) {
- var error = options.error;
- options.error = function(resp) {
- if (error) error(model, resp, options);
- model.trigger('error', model, resp, options);
- };
- };
-
-}).call(this);
deleted file mode 100644
index 3be8ab08667e944c9ead117cef669a2e19884ce6..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/benchmark.js
+++ /dev/null
@@ -1,3918 +0,0 @@
-/*!
- * Benchmark.js v1.0.0 <http://benchmarkjs.com/>
- * Copyright 2010-2012 Mathias Bynens <http://mths.be/>
- * Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/>
- * Modified by John-David Dalton <http://allyoucanleet.com/>
- * Available under MIT license <http://mths.be/mit>
- */
-;(function(window, undefined) {
- 'use strict';
-
- /** Used to assign each benchmark an incrimented id */
- var counter = 0;
-
- /** Detect DOM document object */
- var doc = isHostType(window, 'document') && document;
-
- /** Detect free variable `define` */
- var freeDefine = typeof define == 'function' &&
- typeof define.amd == 'object' && define.amd && define;
-
- /** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports &&
- (typeof global == 'object' && global && global == global.global && (window = global), exports);
-
- /** Detect free variable `require` */
- var freeRequire = typeof require == 'function' && require;
-
- /** Used to crawl all properties regardless of enumerability */
- var getAllKeys = Object.getOwnPropertyNames;
-
- /** Used to get property descriptors */
- var getDescriptor = Object.getOwnPropertyDescriptor;
-
- /** Used in case an object doesn't have its own method */
- var hasOwnProperty = {}.hasOwnProperty;
-
- /** Used to check if an object is extensible */
- var isExtensible = Object.isExtensible || function() { return true; };
-
- /** Used to access Wade Simmons' Node microtime module */
- var microtimeObject = req('microtime');
-
- /** Used to access the browser's high resolution timer */
- var perfObject = isHostType(window, 'performance') && performance;
-
- /** Used to call the browser's high resolution timer */
- var perfName = perfObject && (
- perfObject.now && 'now' ||
- perfObject.webkitNow && 'webkitNow'
- );
-
- /** Used to access Node's high resolution timer */
- var processObject = isHostType(window, 'process') && process;
-
- /** Used to check if an own property is enumerable */
- var propertyIsEnumerable = {}.propertyIsEnumerable;
-
- /** Used to set property descriptors */
- var setDescriptor = Object.defineProperty;
-
- /** Used to resolve a value's internal [[Class]] */
- var toString = {}.toString;
-
- /** Used to prevent a `removeChild` memory leak in IE < 9 */
- var trash = doc && doc.createElement('div');
-
- /** Used to integrity check compiled tests */
- var uid = 'uid' + (+new Date);
-
- /** Used to avoid infinite recursion when methods call each other */
- var calledBy = {};
-
- /** Used to avoid hz of Infinity */
- var divisors = {
- '1': 4096,
- '2': 512,
- '3': 64,
- '4': 8,
- '5': 0
- };
-
- /**
- * T-Distribution two-tailed critical values for 95% confidence
- * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm
- */
- var tTable = {
- '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447,
- '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179,
- '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101,
- '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064,
- '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042,
- 'infinity': 1.96
- };
-
- /**
- * Critical Mann-Whitney U-values for 95% confidence
- * http://www.saburchill.com/IBbiology/stats/003.html
- */
- var uTable = {
- '5': [0, 1, 2],
- '6': [1, 2, 3, 5],
- '7': [1, 3, 5, 6, 8],
- '8': [2, 4, 6, 8, 10, 13],
- '9': [2, 4, 7, 10, 12, 15, 17],
- '10': [3, 5, 8, 11, 14, 17, 20, 23],
- '11': [3, 6, 9, 13, 16, 19, 23, 26, 30],
- '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37],
- '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45],
- '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55],
- '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64],
- '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75],
- '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87],
- '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99],
- '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113],
- '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127],
- '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142],
- '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158],
- '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175],
- '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192],
- '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211],
- '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230],
- '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250],
- '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272],
- '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294],
- '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317]
- };
-
- /**
- * An object used to flag environments/features.
- *
- * @static
- * @memberOf Benchmark
- * @type Object
- */
- var support = {};
-
- (function() {
-
- /**
- * Detect Adobe AIR.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject');
-
- /**
- * Detect if `arguments` objects have the correct internal [[Class]] value.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.argumentsClass = isClassOf(arguments, 'Arguments');
-
- /**
- * Detect if in a browser environment.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.browser = doc && isHostType(window, 'navigator');
-
- /**
- * Detect if strings support accessing characters by index.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.charByIndex =
- // IE 8 supports indexes on string literals but not string objects
- ('x'[0] + Object('x')[0]) == 'xx';
-
- /**
- * Detect if strings have indexes as own properties.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.charByOwnIndex =
- // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on
- // strings but don't detect them as own properties
- support.charByIndex && hasKey('x', '0');
-
- /**
- * Detect if Java is enabled/exposed.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.java = isClassOf(window.java, 'JavaPackage');
-
- /**
- * Detect if the Timers API exists.
- *
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout');
-
- /**
- * Detect if functions support decompilation.
- *
- * @name decompilation
- * @memberOf Benchmark.support
- * @type Boolean
- */
- try {
- // Safari 2.x removes commas in object literals
- // from Function#toString results
- // http://webk.it/11609
- // Firefox 3.6 and Opera 9.25 strip grouping
- // parentheses from Function#toString results
- // http://bugzil.la/559438
- support.decompilation = Function(
- 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')'
- )()(0).x === '1';
- } catch(e) {
- support.decompilation = false;
- }
-
- /**
- * Detect ES5+ property descriptor API.
- *
- * @name descriptors
- * @memberOf Benchmark.support
- * @type Boolean
- */
- try {
- var o = {};
- support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o));
- } catch(e) {
- support.descriptors = false;
- }
-
- /**
- * Detect ES5+ Object.getOwnPropertyNames().
- *
- * @name getAllKeys
- * @memberOf Benchmark.support
- * @type Boolean
- */
- try {
- support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype));
- } catch(e) {
- support.getAllKeys = false;
- }
-
- /**
- * Detect if own properties are iterated before inherited properties (all but IE < 9).
- *
- * @name iteratesOwnLast
- * @memberOf Benchmark.support
- * @type Boolean
- */
- support.iteratesOwnFirst = (function() {
- var props = [];
- function ctor() { this.x = 1; }
- ctor.prototype = { 'y': 1 };
- for (var prop in new ctor) { props.push(prop); }
- return props[0] == 'x';
- }());
-
- /**
- * Detect if a node's [[Class]] is resolvable (all but IE < 9)
- * and that the JS engine errors when attempting to coerce an object to a
- * string without a `toString` property value of `typeof` "function".
- *
- * @name nodeClass
- * @memberOf Benchmark.support
- * @type Boolean
- */
- try {
- support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]');
- } catch(e) {
- support.nodeClass = true;
- }
- }());
-
- /**
- * Timer object used by `clock()` and `Deferred#resolve`.
- *
- * @private
- * @type Object
- */
- var timer = {
-
- /**
- * The timer namespace object or constructor.
- *
- * @private
- * @memberOf timer
- * @type Function|Object
- */
- 'ns': Date,
-
- /**
- * Starts the deferred timer.
- *
- * @private
- * @memberOf timer
- * @param {Object} deferred The deferred instance.
- */
- 'start': null, // lazy defined in `clock()`
-
- /**
- * Stops the deferred timer.
- *
- * @private
- * @memberOf timer
- * @param {Object} deferred The deferred instance.
- */
- 'stop': null // lazy defined in `clock()`
- };
-
- /** Shortcut for inverse results */
- var noArgumentsClass = !support.argumentsClass,
- noCharByIndex = !support.charByIndex,
- noCharByOwnIndex = !support.charByOwnIndex;
-
- /** Math shortcuts */
- var abs = Math.abs,
- floor = Math.floor,
- max = Math.max,
- min = Math.min,
- pow = Math.pow,
- sqrt = Math.sqrt;
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The Benchmark constructor.
- *
- * @constructor
- * @param {String} name A name to identify the benchmark.
- * @param {Function|String} fn The test to benchmark.
- * @param {Object} [options={}] Options object.
- * @example
- *
- * // basic usage (the `new` operator is optional)
- * var bench = new Benchmark(fn);
- *
- * // or using a name first
- * var bench = new Benchmark('foo', fn);
- *
- * // or with options
- * var bench = new Benchmark('foo', fn, {
- *
- * // displayed by Benchmark#toString if `name` is not available
- * 'id': 'xyz',
- *
- * // called when the benchmark starts running
- * 'onStart': onStart,
- *
- * // called after each run cycle
- * 'onCycle': onCycle,
- *
- * // called when aborted
- * 'onAbort': onAbort,
- *
- * // called when a test errors
- * 'onError': onError,
- *
- * // called when reset
- * 'onReset': onReset,
- *
- * // called when the benchmark completes running
- * 'onComplete': onComplete,
- *
- * // compiled/called before the test loop
- * 'setup': setup,
- *
- * // compiled/called after the test loop
- * 'teardown': teardown
- * });
- *
- * // or name and options
- * var bench = new Benchmark('foo', {
- *
- * // a flag to indicate the benchmark is deferred
- * 'defer': true,
- *
- * // benchmark test function
- * 'fn': function(deferred) {
- * // call resolve() when the deferred test is finished
- * deferred.resolve();
- * }
- * });
- *
- * // or options only
- * var bench = new Benchmark({
- *
- * // benchmark name
- * 'name': 'foo',
- *
- * // benchmark test as a string
- * 'fn': '[1,2,3,4].sort()'
- * });
- *
- * // a test's `this` binding is set to the benchmark instance
- * var bench = new Benchmark('foo', function() {
- * 'My name is '.concat(this.name); // My name is foo
- * });
- */
- function Benchmark(name, fn, options) {
- var me = this;
-
- // allow instance creation without the `new` operator
- if (me == null || me.constructor != Benchmark) {
- return new Benchmark(name, fn, options);
- }
- // juggle arguments
- if (isClassOf(name, 'Object')) {
- // 1 argument (options)
- options = name;
- }
- else if (isClassOf(name, 'Function')) {
- // 2 arguments (fn, options)
- options = fn;
- fn = name;
- }
- else if (isClassOf(fn, 'Object')) {
- // 2 arguments (name, options)
- options = fn;
- fn = null;
- me.name = name;
- }
- else {
- // 3 arguments (name, fn [, options])
- me.name = name;
- }
- setOptions(me, options);
- me.id || (me.id = ++counter);
- me.fn == null && (me.fn = fn);
- me.stats = deepClone(me.stats);
- me.times = deepClone(me.times);
- }
-
- /**
- * The Deferred constructor.
- *
- * @constructor
- * @memberOf Benchmark
- * @param {Object} clone The cloned benchmark instance.
- */
- function Deferred(clone) {
- var me = this;
- if (me == null || me.constructor != Deferred) {
- return new Deferred(clone);
- }
- me.benchmark = clone;
- clock(me);
- }
-
- /**
- * The Event constructor.
- *
- * @constructor
- * @memberOf Benchmark
- * @param {String|Object} type The event type.
- */
- function Event(type) {
- var me = this;
- return (me == null || me.constructor != Event)
- ? new Event(type)
- : (type instanceof Event)
- ? type
- : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type);
- }
-
- /**
- * The Suite constructor.
- *
- * @constructor
- * @memberOf Benchmark
- * @param {String} name A name to identify the suite.
- * @param {Object} [options={}] Options object.
- * @example
- *
- * // basic usage (the `new` operator is optional)
- * var suite = new Benchmark.Suite;
- *
- * // or using a name first
- * var suite = new Benchmark.Suite('foo');
- *
- * // or with options
- * var suite = new Benchmark.Suite('foo', {
- *
- * // called when the suite starts running
- * 'onStart': onStart,
- *
- * // called between running benchmarks
- * 'onCycle': onCycle,
- *
- * // called when aborted
- * 'onAbort': onAbort,
- *
- * // called when a test errors
- * 'onError': onError,
- *
- * // called when reset
- * 'onReset': onReset,
- *
- * // called when the suite completes running
- * 'onComplete': onComplete
- * });
- */
- function Suite(name, options) {
- var me = this;
-
- // allow instance creation without the `new` operator
- if (me == null || me.constructor != Suite) {
- return new Suite(name, options);
- }
- // juggle arguments
- if (isClassOf(name, 'Object')) {
- // 1 argument (options)
- options = name;
- } else {
- // 2 arguments (name [, options])
- me.name = name;
- }
- setOptions(me, options);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Note: Some array methods have been implemented in plain JavaScript to avoid
- * bugs in IE, Opera, Rhino, and Mobile Safari.
- *
- * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()`
- * functions that fail to remove the last element, `object[0]`, of
- * array-like-objects even though the `length` property is set to `0`.
- * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()`
- * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9.
- *
- * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()`
- * generically to augment the `arguments` object will pave the value at index 0
- * without incrimenting the other values's indexes.
- * https://github.com/documentcloud/underscore/issues/9
- *
- * Rhino and environments it powers, like Narwhal and RingoJS, may have
- * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and
- * `unshift()` functions that make sparse arrays non-sparse by assigning the
- * undefined indexes a value of undefined.
- * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd
- */
-
- /**
- * Creates an array containing the elements of the host array followed by the
- * elements of each argument in order.
- *
- * @memberOf Benchmark.Suite
- * @returns {Array} The new array.
- */
- function concat() {
- var value,
- j = -1,
- length = arguments.length,
- result = slice.call(this),
- index = result.length;
-
- while (++j < length) {
- value = arguments[j];
- if (isClassOf(value, 'Array')) {
- for (var k = 0, l = value.length; k < l; k++, index++) {
- if (k in value) {
- result[index] = value[k];
- }
- }
- } else {
- result[index++] = value;
- }
- }
- return result;
- }
-
- /**
- * Utility function used by `shift()`, `splice()`, and `unshift()`.
- *
- * @private
- * @param {Number} start The index to start inserting elements.
- * @param {Number} deleteCount The number of elements to delete from the insert point.
- * @param {Array} elements The elements to insert.
- * @returns {Array} An array of deleted elements.
- */
- function insert(start, deleteCount, elements) {
- // `result` should have its length set to the `deleteCount`
- // see https://bugs.ecmascript.org/show_bug.cgi?id=332
- var deleteEnd = start + deleteCount,
- elementCount = elements ? elements.length : 0,
- index = start - 1,
- length = start + elementCount,
- object = this,
- result = Array(deleteCount),
- tail = slice.call(object, deleteEnd);
-
- // delete elements from the array
- while (++index < deleteEnd) {
- if (index in object) {
- result[index - start] = object[index];
- delete object[index];
- }
- }
- // insert elements
- index = start - 1;
- while (++index < length) {
- object[index] = elements[index - start];
- }
- // append tail elements
- start = index--;
- length = max(0, (object.length >>> 0) - deleteCount + elementCount);
- while (++index < length) {
- if ((index - start) in tail) {
- object[index] = tail[index - start];
- } else if (index in object) {
- delete object[index];
- }
- }
- // delete excess elements
- deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0;
- while (deleteCount--) {
- index = length + deleteCount;
- if (index in object) {
- delete object[index];
- }
- }
- object.length = length;
- return result;
- }
-
- /**
- * Rearrange the host array's elements in reverse order.
- *
- * @memberOf Benchmark.Suite
- * @returns {Array} The reversed array.
- */
- function reverse() {
- var upperIndex,
- value,
- index = -1,
- object = Object(this),
- length = object.length >>> 0,
- middle = floor(length / 2);
-
- if (length > 1) {
- while (++index < middle) {
- upperIndex = length - index - 1;
- value = upperIndex in object ? object[upperIndex] : uid;
- if (index in object) {
- object[upperIndex] = object[index];
- } else {
- delete object[upperIndex];
- }
- if (value != uid) {
- object[index] = value;
- } else {
- delete object[index];
- }
- }
- }
- return object;
- }
-
- /**
- * Removes the first element of the host array and returns it.
- *
- * @memberOf Benchmark.Suite
- * @returns {Mixed} The first element of the array.
- */
- function shift() {
- return insert.call(this, 0, 1)[0];
- }
-
- /**
- * Creates an array of the host array's elements from the start index up to,
- * but not including, the end index.
- *
- * @memberOf Benchmark.Suite
- * @param {Number} start The starting index.
- * @param {Number} end The end index.
- * @returns {Array} The new array.
- */
- function slice(start, end) {
- var index = -1,
- object = Object(this),
- length = object.length >>> 0,
- result = [];
-
- start = toInteger(start);
- start = start < 0 ? max(length + start, 0) : min(start, length);
- start--;
- end = end == null ? length : toInteger(end);
- end = end < 0 ? max(length + end, 0) : min(end, length);
-
- while ((++index, ++start) < end) {
- if (start in object) {
- result[index] = object[start];
- }
- }
- return result;
- }
-
- /**
- * Allows removing a range of elements and/or inserting elements into the
- * host array.
- *
- * @memberOf Benchmark.Suite
- * @param {Number} start The start index.
- * @param {Number} deleteCount The number of elements to delete.
- * @param {Mixed} [val1, val2, ...] values to insert at the `start` index.
- * @returns {Array} An array of removed elements.
- */
- function splice(start, deleteCount) {
- var object = Object(this),
- length = object.length >>> 0;
-
- start = toInteger(start);
- start = start < 0 ? max(length + start, 0) : min(start, length);
-
- // support the de-facto SpiderMonkey extension
- // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters
- // https://bugs.ecmascript.org/show_bug.cgi?id=429
- deleteCount = arguments.length == 1
- ? length - start
- : min(max(toInteger(deleteCount), 0), length - start);
-
- return insert.call(object, start, deleteCount, slice.call(arguments, 2));
- }
-
- /**
- * Converts the specified `value` to an integer.
- *
- * @private
- * @param {Mixed} value The value to convert.
- * @returns {Number} The resulting integer.
- */
- function toInteger(value) {
- value = +value;
- return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1);
- }
-
- /**
- * Appends arguments to the host array.
- *
- * @memberOf Benchmark.Suite
- * @returns {Number} The new length.
- */
- function unshift() {
- var object = Object(this);
- insert.call(object, 0, 0, arguments);
- return object.length;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * A generic `Function#bind` like method.
- *
- * @private
- * @param {Function} fn The function to be bound to `thisArg`.
- * @param {Mixed} thisArg The `this` binding for the given function.
- * @returns {Function} The bound function.
- */
- function bind(fn, thisArg) {
- return function() { fn.apply(thisArg, arguments); };
- }
-
- /**
- * Creates a function from the given arguments string and body.
- *
- * @private
- * @param {String} args The comma separated function arguments.
- * @param {String} body The function body.
- * @returns {Function} The new function.
- */
- function createFunction() {
- // lazy define
- createFunction = function(args, body) {
- var result,
- anchor = freeDefine ? define.amd : Benchmark,
- prop = uid + 'createFunction';
-
- runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}');
- result = anchor[prop];
- delete anchor[prop];
- return result;
- };
- // fix JaegerMonkey bug
- // http://bugzil.la/639720
- createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function;
- return createFunction.apply(null, arguments);
- }
-
- /**
- * Delay the execution of a function based on the benchmark's `delay` property.
- *
- * @private
- * @param {Object} bench The benchmark instance.
- * @param {Object} fn The function to execute.
- */
- function delay(bench, fn) {
- bench._timerId = setTimeout(fn, bench.delay * 1e3);
- }
-
- /**
- * Destroys the given element.
- *
- * @private
- * @param {Element} element The element to destroy.
- */
- function destroyElement(element) {
- trash.appendChild(element);
- trash.innerHTML = '';
- }
-
- /**
- * Iterates over an object's properties, executing the `callback` for each.
- * Callbacks may terminate the loop by explicitly returning `false`.
- *
- * @private
- * @param {Object} object The object to iterate over.
- * @param {Function} callback The function executed per own property.
- * @param {Object} options The options object.
- * @returns {Object} Returns the object iterated over.
- */
- function forProps() {
- var forShadowed,
- skipSeen,
- forArgs = true,
- shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf'];
-
- (function(enumFlag, key) {
- // must use a non-native constructor to catch the Safari 2 issue
- function Klass() { this.valueOf = 0; };
- Klass.prototype.valueOf = 0;
- // check various for-in bugs
- for (key in new Klass) {
- enumFlag += key == 'valueOf' ? 1 : 0;
- }
- // check if `arguments` objects have non-enumerable indexes
- for (key in arguments) {
- key == '0' && (forArgs = false);
- }
- // Safari 2 iterates over shadowed properties twice
- // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/
- skipSeen = enumFlag == 2;
- // IE < 9 incorrectly makes an object's properties non-enumerable if they have
- // the same name as other non-enumerable properties in its prototype chain.
- forShadowed = !enumFlag;
- }(0));
-
- // lazy define
- forProps = function(object, callback, options) {
- options || (options = {});
-
- var result = object;
- object = Object(object);
-
- var ctor,
- key,
- keys,
- skipCtor,
- done = !result,
- which = options.which,
- allFlag = which == 'all',
- index = -1,
- iteratee = object,
- length = object.length,
- ownFlag = allFlag || which == 'own',
- seen = {},
- skipProto = isClassOf(object, 'Function'),
- thisArg = options.bind;
-
- if (thisArg !== undefined) {
- callback = bind(callback, thisArg);
- }
- // iterate all properties
- if (allFlag && support.getAllKeys) {
- for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) {
- key = keys[index];
- if (callback(object[key], key, object) === false) {
- break;
- }
- }
- }
- // else iterate only enumerable properties
- else {
- for (key in object) {
- // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
- // (if the prototype or a property on the prototype has been set)
- // incorrectly set a function's `prototype` property [[Enumerable]] value
- // to `true`. Because of this we standardize on skipping the `prototype`
- // property of functions regardless of their [[Enumerable]] value.
- if ((done =
- !(skipProto && key == 'prototype') &&
- !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) &&
- (!ownFlag || ownFlag && hasKey(object, key)) &&
- callback(object[key], key, object) === false)) {
- break;
- }
- }
- // in IE < 9 strings don't support accessing characters by index
- if (!done && (forArgs && isArguments(object) ||
- ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') &&
- (iteratee = noCharByIndex ? object.split('') : object)))) {
- while (++index < length) {
- if ((done =
- callback(iteratee[index], String(index), object) === false)) {
- break;
- }
- }
- }
- if (!done && forShadowed) {
- // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing
- // property and the `constructor` property of a prototype defaults to
- // non-enumerable, we manually skip the `constructor` property when we
- // think we are iterating over a `prototype` object.
- ctor = object.constructor;
- skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor;
- for (index = 0; index < 7; index++) {
- key = shadowed[index];
- if (!(skipCtor && key == 'constructor') &&
- hasKey(object, key) &&
- callback(object[key], key, object) === false) {
- break;
- }
- }
- }
- }
- return result;
- };
- return forProps.apply(null, arguments);
- }
-
- /**
- * Gets the name of the first argument from a function's source.
- *
- * @private
- * @param {Function} fn The function.
- * @returns {String} The argument name.
- */
- function getFirstArgument(fn) {
- return (!hasKey(fn, 'toString') &&
- (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || '';
- }
-
- /**
- * Computes the arithmetic mean of a sample.
- *
- * @private
- * @param {Array} sample The sample.
- * @returns {Number} The mean.
- */
- function getMean(sample) {
- return reduce(sample, function(sum, x) {
- return sum + x;
- }) / sample.length || 0;
- }
-
- /**
- * Gets the source code of a function.
- *
- * @private
- * @param {Function} fn The function.
- * @param {String} altSource A string used when a function's source code is unretrievable.
- * @returns {String} The function's source code.
- */
- function getSource(fn, altSource) {
- var result = altSource;
- if (isStringable(fn)) {
- result = String(fn);
- } else if (support.decompilation) {
- // escape the `{` for Firefox 1
- result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1];
- }
- // trim string
- result = (result || '').replace(/^\s+|\s+$/g, '');
-
- // detect strings containing only the "use strict" directive
- return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result)
- ? ''
- : result;
- }
-
- /**
- * Checks if a value is an `arguments` object.
- *
- * @private
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`.
- */
- function isArguments() {
- // lazy define
- isArguments = function(value) {
- return toString.call(value) == '[object Arguments]';
- };
- if (noArgumentsClass) {
- isArguments = function(value) {
- return hasKey(value, 'callee') &&
- !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee'));
- };
- }
- return isArguments(arguments[0]);
- }
-
- /**
- * Checks if an object is of the specified class.
- *
- * @private
- * @param {Mixed} value The value to check.
- * @param {String} name The name of the class.
- * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`.
- */
- function isClassOf(value, name) {
- return value != null && toString.call(value) == '[object ' + name + ']';
- }
-
- /**
- * Host objects can return type values that are different from their actual
- * data type. The objects we are concerned with usually return non-primitive
- * types of object, function, or unknown.
- *
- * @private
- * @param {Mixed} object The owner of the property.
- * @param {String} property The property to check.
- * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`.
- */
- function isHostType(object, property) {
- var type = object != null ? typeof object[property] : 'number';
- return !/^(?:boolean|number|string|undefined)$/.test(type) &&
- (type == 'object' ? !!object[property] : true);
- }
-
- /**
- * Checks if a given `value` is an object created by the `Object` constructor
- * assuming objects created by the `Object` constructor have no inherited
- * enumerable properties and that there are no `Object.prototype` extensions.
- *
- * @private
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`.
- */
- function isPlainObject(value) {
- // avoid non-objects and false positives for `arguments` objects in IE < 9
- var result = false;
- if (!(value && typeof value == 'object') || (noArgumentsClass && isArguments(value))) {
- return result;
- }
- // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
- // methods that are `typeof` "string" and still can coerce nodes to strings.
- // Also check that the constructor is `Object` (i.e. `Object instanceof Object`)
- var ctor = value.constructor;
- if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) &&
- (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) {
- // In most environments an object's own properties are iterated before
- // its inherited properties. If the last iterated property is an object's
- // own property then there are no inherited enumerable properties.
- if (support.iteratesOwnFirst) {
- forProps(value, function(subValue, subKey) {
- result = subKey;
- });
- return result === false || hasKey(value, result);
- }
- // IE < 9 iterates inherited properties before own properties. If the first
- // iterated property is an object's own property then there are no inherited
- // enumerable properties.
- forProps(value, function(subValue, subKey) {
- result = !hasKey(value, subKey);
- return false;
- });
- return result === false;
- }
- return result;
- }
-
- /**
- * Checks if a value can be safely coerced to a string.
- *
- * @private
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the value can be coerced, else `false`.
- */
- function isStringable(value) {
- return hasKey(value, 'toString') || isClassOf(value, 'String');
- }
-
- /**
- * Wraps a function and passes `this` to the original function as the
- * first argument.
- *
- * @private
- * @param {Function} fn The function to be wrapped.
- * @returns {Function} The new function.
- */
- function methodize(fn) {
- return function() {
- var args = [this];
- args.push.apply(args, arguments);
- return fn.apply(null, args);
- };
- }
-
- /**
- * A no-operation function.
- *
- * @private
- */
- function noop() {
- // no operation performed
- }
-
- /**
- * A wrapper around require() to suppress `module missing` errors.
- *
- * @private
- * @param {String} id The module id.
- * @returns {Mixed} The exported module or `null`.
- */
- function req(id) {
- try {
- var result = freeExports && freeRequire(id);
- } catch(e) { }
- return result || null;
- }
-
- /**
- * Runs a snippet of JavaScript via script injection.
- *
- * @private
- * @param {String} code The code to run.
- */
- function runScript(code) {
- var anchor = freeDefine ? define.amd : Benchmark,
- script = doc.createElement('script'),
- sibling = doc.getElementsByTagName('script')[0],
- parent = sibling.parentNode,
- prop = uid + 'runScript',
- prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();';
-
- // Firefox 2.0.0.2 cannot use script injection as intended because it executes
- // asynchronously, but that's OK because script injection is only used to avoid
- // the previously commented JaegerMonkey bug.
- try {
- // remove the inserted script *before* running the code to avoid differences
- // in the expected script element count/order of the document.
- script.appendChild(doc.createTextNode(prefix + code));
- anchor[prop] = function() { destroyElement(script); };
- } catch(e) {
- parent = parent.cloneNode(false);
- sibling = null;
- script.text = code;
- }
- parent.insertBefore(script, sibling);
- delete anchor[prop];
- }
-
- /**
- * A helper function for setting options/event handlers.
- *
- * @private
- * @param {Object} bench The benchmark instance.
- * @param {Object} [options={}] Options object.
- */
- function setOptions(bench, options) {
- options = extend({}, bench.constructor.options, options);
- bench.options = forOwn(options, function(value, key) {
- if (value != null) {
- // add event listeners
- if (/^on[A-Z]/.test(key)) {
- forEach(key.split(' '), function(key) {
- bench.on(key.slice(2).toLowerCase(), value);
- });
- } else if (!hasKey(bench, key)) {
- bench[key] = deepClone(value);
- }
- }
- });
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Handles cycling/completing the deferred benchmark.
- *
- * @memberOf Benchmark.Deferred
- */
- function resolve() {
- var me = this,
- clone = me.benchmark,
- bench = clone._original;
-
- if (bench.aborted) {
- // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete
- me.teardown();
- clone.running = false;
- cycle(me);
- }
- else if (++me.cycles < clone.count) {
- // continue the test loop
- if (support.timeout) {
- // use setTimeout to avoid a call stack overflow if called recursively
- setTimeout(function() { clone.compiled.call(me, timer); }, 0);
- } else {
- clone.compiled.call(me, timer);
- }
- }
- else {
- timer.stop(me);
- me.teardown();
- delay(clone, function() { cycle(me); });
- }
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * A deep clone utility.
- *
- * @static
- * @memberOf Benchmark
- * @param {Mixed} value The value to clone.
- * @returns {Mixed} The cloned value.
- */
- function deepClone(value) {
- var accessor,
- circular,
- clone,
- ctor,
- descriptor,
- extensible,
- key,
- length,
- markerKey,
- parent,
- result,
- source,
- subIndex,
- data = { 'value': value },
- index = 0,
- marked = [],
- queue = { 'length': 0 },
- unmarked = [];
-
- /**
- * An easily detectable decorator for cloned values.
- */
- function Marker(object) {
- this.raw = object;
- }
-
- /**
- * The callback used by `forProps()`.
- */
- function forPropsCallback(subValue, subKey) {
- // exit early to avoid cloning the marker
- if (subValue && subValue.constructor == Marker) {
- return;
- }
- // add objects to the queue
- if (subValue === Object(subValue)) {
- queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value };
- }
- // assign non-objects
- else {
- try {
- // will throw an error in strict mode if the property is read-only
- clone[subKey] = subValue;
- } catch(e) { }
- }
- }
-
- /**
- * Gets an available marker key for the given object.
- */
- function getMarkerKey(object) {
- // avoid collisions with existing keys
- var result = uid;
- while (object[result] && object[result].constructor != Marker) {
- result += 1;
- }
- return result;
- }
-
- do {
- key = data.key;
- parent = data.parent;
- source = data.source;
- clone = value = source ? source[key] : data.value;
- accessor = circular = descriptor = false;
-
- // create a basic clone to filter out functions, DOM elements, and
- // other non `Object` objects
- if (value === Object(value)) {
- // use custom deep clone function if available
- if (isClassOf(value.deepClone, 'Function')) {
- clone = value.deepClone();
- } else {
- ctor = value.constructor;
- switch (toString.call(value)) {
- case '[object Array]':
- clone = new ctor(value.length);
- break;
-
- case '[object Boolean]':
- clone = new ctor(value == true);
- break;
-
- case '[object Date]':
- clone = new ctor(+value);
- break;
-
- case '[object Object]':
- isPlainObject(value) && (clone = {});
- break;
-
- case '[object Number]':
- case '[object String]':
- clone = new ctor(value);
- break;
-
- case '[object RegExp]':
- clone = ctor(value.source,
- (value.global ? 'g' : '') +
- (value.ignoreCase ? 'i' : '') +
- (value.multiline ? 'm' : ''));
- }
- }
- // continue clone if `value` doesn't have an accessor descriptor
- // http://es5.github.com/#x8.10.1
- if (clone && clone != value &&
- !(descriptor = source && support.descriptors && getDescriptor(source, key),
- accessor = descriptor && (descriptor.get || descriptor.set))) {
- // use an existing clone (circular reference)
- if ((extensible = isExtensible(value))) {
- markerKey = getMarkerKey(value);
- if (value[markerKey]) {
- circular = clone = value[markerKey].raw;
- }
- } else {
- // for frozen/sealed objects
- for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) {
- data = unmarked[subIndex];
- if (data.object === value) {
- circular = clone = data.clone;
- break;
- }
- }
- }
- if (!circular) {
- // mark object to allow quickly detecting circular references and tie it to its clone
- if (extensible) {
- value[markerKey] = new Marker(clone);
- marked.push({ 'key': markerKey, 'object': value });
- } else {
- // for frozen/sealed objects
- unmarked.push({ 'clone': clone, 'object': value });
- }
- // iterate over object properties
- forProps(value, forPropsCallback, { 'which': 'all' });
- }
- }
- }
- if (parent) {
- // for custom property descriptors
- if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) {
- if ('value' in descriptor) {
- descriptor.value = clone;
- }
- setDescriptor(parent, key, descriptor);
- }
- // for default property descriptors
- else {
- parent[key] = clone;
- }
- } else {
- result = clone;
- }
- } while ((data = queue[index++]));
-
- // remove markers
- for (index = 0, length = marked.length; index < length; index++) {
- data = marked[index];
- delete data.object[data.key];
- }
- return result;
- }
-
- /**
- * An iteration utility for arrays and objects.
- * Callbacks may terminate the loop by explicitly returning `false`.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array|Object} object The object to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} thisArg The `this` binding for the callback.
- * @returns {Array|Object} Returns the object iterated over.
- */
- function each(object, callback, thisArg) {
- var result = object;
- object = Object(object);
-
- var fn = callback,
- index = -1,
- length = object.length,
- isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)),
- isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'),
- isConvertable = isSnapshot || isSplittable || 'item' in object,
- origObject = object;
-
- // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists
- if (length === length >>> 0) {
- if (isConvertable) {
- // the third argument of the callback is the original non-array object
- callback = function(value, index) {
- return fn.call(this, value, index, origObject);
- };
- // in IE < 9 strings don't support accessing characters by index
- if (isSplittable) {
- object = object.split('');
- } else {
- object = [];
- while (++index < length) {
- // in Safari 2 `index in object` is always `false` for NodeLists
- object[index] = isSnapshot ? result.snapshotItem(index) : result[index];
- }
- }
- }
- forEach(object, callback, thisArg);
- } else {
- forOwn(object, callback, thisArg);
- }
- return result;
- }
-
- /**
- * Copies enumerable properties from the source(s) object to the destination object.
- *
- * @static
- * @memberOf Benchmark
- * @param {Object} destination The destination object.
- * @param {Object} [source={}] The source object.
- * @returns {Object} The destination object.
- */
- function extend(destination, source) {
- // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]`
- // http://code.google.com/p/v8/issues/detail?id=839
- var result = destination;
- delete arguments[0];
-
- forEach(arguments, function(source) {
- forProps(source, function(value, key) {
- result[key] = value;
- });
- });
- return result;
- }
-
- /**
- * A generic `Array#filter` like method.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {Function|String} callback The function/alias called per iteration.
- * @param {Mixed} thisArg The `this` binding for the callback.
- * @returns {Array} A new array of values that passed callback filter.
- * @example
- *
- * // get odd numbers
- * Benchmark.filter([1, 2, 3, 4, 5], function(n) {
- * return n % 2;
- * }); // -> [1, 3, 5];
- *
- * // get fastest benchmarks
- * Benchmark.filter(benches, 'fastest');
- *
- * // get slowest benchmarks
- * Benchmark.filter(benches, 'slowest');
- *
- * // get benchmarks that completed without erroring
- * Benchmark.filter(benches, 'successful');
- */
- function filter(array, callback, thisArg) {
- var result;
-
- if (callback == 'successful') {
- // callback to exclude those that are errored, unrun, or have hz of Infinity
- callback = function(bench) { return bench.cycles && isFinite(bench.hz); };
- }
- else if (callback == 'fastest' || callback == 'slowest') {
- // get successful, sort by period + margin of error, and filter fastest/slowest
- result = filter(array, 'successful').sort(function(a, b) {
- a = a.stats; b = b.stats;
- return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1);
- });
- result = filter(result, function(bench) {
- return result[0].compare(bench) == 0;
- });
- }
- return result || reduce(array, function(result, value, index) {
- return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result;
- }, []);
- }
-
- /**
- * A generic `Array#forEach` like method.
- * Callbacks may terminate the loop by explicitly returning `false`.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} thisArg The `this` binding for the callback.
- * @returns {Array} Returns the array iterated over.
- */
- function forEach(array, callback, thisArg) {
- var index = -1,
- length = (array = Object(array)).length >>> 0;
-
- if (thisArg !== undefined) {
- callback = bind(callback, thisArg);
- }
- while (++index < length) {
- if (index in array &&
- callback(array[index], index, array) === false) {
- break;
- }
- }
- return array;
- }
-
- /**
- * Iterates over an object's own properties, executing the `callback` for each.
- * Callbacks may terminate the loop by explicitly returning `false`.
- *
- * @static
- * @memberOf Benchmark
- * @param {Object} object The object to iterate over.
- * @param {Function} callback The function executed per own property.
- * @param {Mixed} thisArg The `this` binding for the callback.
- * @returns {Object} Returns the object iterated over.
- */
- function forOwn(object, callback, thisArg) {
- return forProps(object, callback, { 'bind': thisArg, 'which': 'own' });
- }
-
- /**
- * Converts a number to a more readable comma-separated string representation.
- *
- * @static
- * @memberOf Benchmark
- * @param {Number} number The number to convert.
- * @returns {String} The more readable string representation.
- */
- function formatNumber(number) {
- number = String(number).split('.');
- return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
- (number[1] ? '.' + number[1] : '');
- }
-
- /**
- * Checks if an object has the specified key as a direct property.
- *
- * @static
- * @memberOf Benchmark
- * @param {Object} object The object to check.
- * @param {String} key The key to check for.
- * @returns {Boolean} Returns `true` if key is a direct property, else `false`.
- */
- function hasKey() {
- // lazy define for worst case fallback (not as accurate)
- hasKey = function(object, key) {
- var parent = object != null && (object.constructor || Object).prototype;
- return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]);
- };
- // for modern browsers
- if (isClassOf(hasOwnProperty, 'Function')) {
- hasKey = function(object, key) {
- return object != null && hasOwnProperty.call(object, key);
- };
- }
- // for Safari 2
- else if ({}.__proto__ == Object.prototype) {
- hasKey = function(object, key) {
- var result = false;
- if (object != null) {
- object = Object(object);
- object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0];
- }
- return result;
- };
- }
- return hasKey.apply(this, arguments);
- }
-
- /**
- * A generic `Array#indexOf` like method.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {Mixed} value The value to search for.
- * @param {Number} [fromIndex=0] The index to start searching from.
- * @returns {Number} The index of the matched value or `-1`.
- */
- function indexOf(array, value, fromIndex) {
- var index = toInteger(fromIndex),
- length = (array = Object(array)).length >>> 0;
-
- index = (index < 0 ? max(0, length + index) : index) - 1;
- while (++index < length) {
- if (index in array && value === array[index]) {
- return index;
- }
- }
- return -1;
- }
-
- /**
- * Modify a string by replacing named tokens with matching object property values.
- *
- * @static
- * @memberOf Benchmark
- * @param {String} string The string to modify.
- * @param {Object} object The template object.
- * @returns {String} The modified string.
- */
- function interpolate(string, object) {
- forOwn(object, function(value, key) {
- // escape regexp special characters in `key`
- string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value);
- });
- return string;
- }
-
- /**
- * Invokes a method on all items in an array.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} benches Array of benchmarks to iterate over.
- * @param {String|Object} name The name of the method to invoke OR options object.
- * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
- * @returns {Array} A new array of values returned from each method invoked.
- * @example
- *
- * // invoke `reset` on all benchmarks
- * Benchmark.invoke(benches, 'reset');
- *
- * // invoke `emit` with arguments
- * Benchmark.invoke(benches, 'emit', 'complete', listener);
- *
- * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks
- * Benchmark.invoke(benches, {
- *
- * // invoke the `run` method
- * 'name': 'run',
- *
- * // pass a single argument
- * 'args': true,
- *
- * // treat as queue, removing benchmarks from front of `benches` until empty
- * 'queued': true,
- *
- * // called before any benchmarks have been invoked.
- * 'onStart': onStart,
- *
- * // called between invoking benchmarks
- * 'onCycle': onCycle,
- *
- * // called after all benchmarks have been invoked.
- * 'onComplete': onComplete
- * });
- */
- function invoke(benches, name) {
- var args,
- bench,
- queued,
- index = -1,
- eventProps = { 'currentTarget': benches },
- options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop },
- result = map(benches, function(bench) { return bench; });
-
- /**
- * Invokes the method of the current object and if synchronous, fetches the next.
- */
- function execute() {
- var listeners,
- async = isAsync(bench);
-
- if (async) {
- // use `getNext` as the first listener
- bench.on('complete', getNext);
- listeners = bench.events.complete;
- listeners.splice(0, 0, listeners.pop());
- }
- // execute method
- result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined;
- // if synchronous return true until finished
- return !async && getNext();
- }
-
- /**
- * Fetches the next bench or executes `onComplete` callback.
- */
- function getNext(event) {
- var cycleEvent,
- last = bench,
- async = isAsync(last);
-
- if (async) {
- last.off('complete', getNext);
- last.emit('complete');
- }
- // emit "cycle" event
- eventProps.type = 'cycle';
- eventProps.target = last;
- cycleEvent = Event(eventProps);
- options.onCycle.call(benches, cycleEvent);
-
- // choose next benchmark if not exiting early
- if (!cycleEvent.aborted && raiseIndex() !== false) {
- bench = queued ? benches[0] : result[index];
- if (isAsync(bench)) {
- delay(bench, execute);
- }
- else if (async) {
- // resume execution if previously asynchronous but now synchronous
- while (execute()) { }
- }
- else {
- // continue synchronous execution
- return true;
- }
- } else {
- // emit "complete" event
- eventProps.type = 'complete';
- options.onComplete.call(benches, Event(eventProps));
- }
- // When used as a listener `event.aborted = true` will cancel the rest of
- // the "complete" listeners because they were already called above and when
- // used as part of `getNext` the `return false` will exit the execution while-loop.
- if (event) {
- event.aborted = true;
- } else {
- return false;
- }
- }
-
- /**
- * Checks if invoking `Benchmark#run` with asynchronous cycles.
- */
- function isAsync(object) {
- // avoid using `instanceof` here because of IE memory leak issues with host objects
- var async = args[0] && args[0].async;
- return Object(object).constructor == Benchmark && name == 'run' &&
- ((async == null ? object.options.async : async) && support.timeout || object.defer);
- }
-
- /**
- * Raises `index` to the next defined index or returns `false`.
- */
- function raiseIndex() {
- var length = result.length;
- if (queued) {
- // if queued remove the previous bench and subsequent skipped non-entries
- do {
- ++index > 0 && shift.call(benches);
- } while ((length = benches.length) && !('0' in benches));
- }
- else {
- while (++index < length && !(index in result)) { }
- }
- // if we reached the last index then return `false`
- return (queued ? length : index < length) ? index : (index = false);
- }
-
- // juggle arguments
- if (isClassOf(name, 'String')) {
- // 2 arguments (array, name)
- args = slice.call(arguments, 2);
- } else {
- // 2 arguments (array, options)
- options = extend(options, name);
- name = options.name;
- args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args];
- queued = options.queued;
- }
-
- // start iterating over the array
- if (raiseIndex() !== false) {
- // emit "start" event
- bench = result[index];
- eventProps.type = 'start';
- eventProps.target = bench;
- options.onStart.call(benches, Event(eventProps));
-
- // end early if the suite was aborted in an "onStart" listener
- if (benches.aborted && benches.constructor == Suite && name == 'run') {
- // emit "cycle" event
- eventProps.type = 'cycle';
- options.onCycle.call(benches, Event(eventProps));
- // emit "complete" event
- eventProps.type = 'complete';
- options.onComplete.call(benches, Event(eventProps));
- }
- // else start
- else {
- if (isAsync(bench)) {
- delay(bench, execute);
- } else {
- while (execute()) { }
- }
- }
- }
- return result;
- }
-
- /**
- * Creates a string of joined array values or object key-value pairs.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array|Object} object The object to operate on.
- * @param {String} [separator1=','] The separator used between key-value pairs.
- * @param {String} [separator2=': '] The separator used between keys and values.
- * @returns {String} The joined result.
- */
- function join(object, separator1, separator2) {
- var result = [],
- length = (object = Object(object)).length,
- arrayLike = length === length >>> 0;
-
- separator2 || (separator2 = ': ');
- each(object, function(value, key) {
- result.push(arrayLike ? value : key + separator2 + value);
- });
- return result.join(separator1 || ',');
- }
-
- /**
- * A generic `Array#map` like method.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} thisArg The `this` binding for the callback.
- * @returns {Array} A new array of values returned by the callback.
- */
- function map(array, callback, thisArg) {
- return reduce(array, function(result, value, index) {
- result[index] = callback.call(thisArg, value, index, array);
- return result;
- }, Array(Object(array).length >>> 0));
- }
-
- /**
- * Retrieves the value of a specified property from all items in an array.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {String} property The property to pluck.
- * @returns {Array} A new array of property values.
- */
- function pluck(array, property) {
- return map(array, function(object) {
- return object == null ? undefined : object[property];
- });
- }
-
- /**
- * A generic `Array#reduce` like method.
- *
- * @static
- * @memberOf Benchmark
- * @param {Array} array The array to iterate over.
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} accumulator Initial value of the accumulator.
- * @returns {Mixed} The accumulator.
- */
- function reduce(array, callback, accumulator) {
- var noaccum = arguments.length < 3;
- forEach(array, function(value, index) {
- accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array);
- });
- return accumulator;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Aborts all benchmarks in the suite.
- *
- * @name abort
- * @memberOf Benchmark.Suite
- * @returns {Object} The suite instance.
- */
- function abortSuite() {
- var event,
- me = this,
- resetting = calledBy.resetSuite;
-
- if (me.running) {
- event = Event('abort');
- me.emit(event);
- if (!event.cancelled || resetting) {
- // avoid infinite recursion
- calledBy.abortSuite = true;
- me.reset();
- delete calledBy.abortSuite;
-
- if (!resetting) {
- me.aborted = true;
- invoke(me, 'abort');
- }
- }
- }
- return me;
- }
-
- /**
- * Adds a test to the benchmark suite.
- *
- * @memberOf Benchmark.Suite
- * @param {String} name A name to identify the benchmark.
- * @param {Function|String} fn The test to benchmark.
- * @param {Object} [options={}] Options object.
- * @returns {Object} The benchmark instance.
- * @example
- *
- * // basic usage
- * suite.add(fn);
- *
- * // or using a name first
- * suite.add('foo', fn);
- *
- * // or with options
- * suite.add('foo', fn, {
- * 'onCycle': onCycle,
- * 'onComplete': onComplete
- * });
- *
- * // or name and options
- * suite.add('foo', {
- * 'fn': fn,
- * 'onCycle': onCycle,
- * 'onComplete': onComplete
- * });
- *
- * // or options only
- * suite.add({
- * 'name': 'foo',
- * 'fn': fn,
- * 'onCycle': onCycle,
- * 'onComplete': onComplete
- * });
- */
- function add(name, fn, options) {
- var me = this,
- bench = Benchmark(name, fn, options),
- event = Event({ 'type': 'add', 'target': bench });
-
- if (me.emit(event), !event.cancelled) {
- me.push(bench);
- }
- return me;
- }
-
- /**
- * Creates a new suite with cloned benchmarks.
- *
- * @name clone
- * @memberOf Benchmark.Suite
- * @param {Object} options Options object to overwrite cloned options.
- * @returns {Object} The new suite instance.
- */
- function cloneSuite(options) {
- var me = this,
- result = new me.constructor(extend({}, me.options, options));
-
- // copy own properties
- forOwn(me, function(value, key) {
- if (!hasKey(result, key)) {
- result[key] = value && isClassOf(value.clone, 'Function')
- ? value.clone()
- : deepClone(value);
- }
- });
- return result;
- }
-
- /**
- * An `Array#filter` like method.
- *
- * @name filter
- * @memberOf Benchmark.Suite
- * @param {Function|String} callback The function/alias called per iteration.
- * @returns {Object} A new suite of benchmarks that passed callback filter.
- */
- function filterSuite(callback) {
- var me = this,
- result = new me.constructor;
-
- result.push.apply(result, filter(me, callback));
- return result;
- }
-
- /**
- * Resets all benchmarks in the suite.
- *
- * @name reset
- * @memberOf Benchmark.Suite
- * @returns {Object} The suite instance.
- */
- function resetSuite() {
- var event,
- me = this,
- aborting = calledBy.abortSuite;
-
- if (me.running && !aborting) {
- // no worries, `resetSuite()` is called within `abortSuite()`
- calledBy.resetSuite = true;
- me.abort();
- delete calledBy.resetSuite;
- }
- // reset if the state has changed
- else if ((me.aborted || me.running) &&
- (me.emit(event = Event('reset')), !event.cancelled)) {
- me.running = false;
- if (!aborting) {
- invoke(me, 'reset');
- }
- }
- return me;
- }
-
- /**
- * Runs the suite.
- *
- * @name run
- * @memberOf Benchmark.Suite
- * @param {Object} [options={}] Options object.
- * @returns {Object} The suite instance.
- * @example
- *
- * // basic usage
- * suite.run();
- *
- * // or with options
- * suite.run({ 'async': true, 'queued': true });
- */
- function runSuite(options) {
- var me = this;
-
- me.reset();
- me.running = true;
- options || (options = {});
-
- invoke(me, {
- 'name': 'run',
- 'args': options,
- 'queued': options.queued,
- 'onStart': function(event) {
- me.emit(event);
- },
- 'onCycle': function(event) {
- var bench = event.target;
- if (bench.error) {
- me.emit({ 'type': 'error', 'target': bench });
- }
- me.emit(event);
- event.aborted = me.aborted;
- },
- 'onComplete': function(event) {
- me.running = false;
- me.emit(event);
- }
- });
- return me;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Executes all registered listeners of the specified event type.
- *
- * @memberOf Benchmark, Benchmark.Suite
- * @param {String|Object} type The event type or object.
- * @returns {Mixed} Returns the return value of the last listener executed.
- */
- function emit(type) {
- var listeners,
- me = this,
- event = Event(type),
- events = me.events,
- args = (arguments[0] = event, arguments);
-
- event.currentTarget || (event.currentTarget = me);
- event.target || (event.target = me);
- delete event.result;
-
- if (events && (listeners = hasKey(events, event.type) && events[event.type])) {
- forEach(listeners.slice(), function(listener) {
- if ((event.result = listener.apply(me, args)) === false) {
- event.cancelled = true;
- }
- return !event.aborted;
- });
- }
- return event.result;
- }
-
- /**
- * Returns an array of event listeners for a given type that can be manipulated
- * to add or remove listeners.
- *
- * @memberOf Benchmark, Benchmark.Suite
- * @param {String} type The event type.
- * @returns {Array} The listeners array.
- */
- function listeners(type) {
- var me = this,
- events = me.events || (me.events = {});
-
- return hasKey(events, type) ? events[type] : (events[type] = []);
- }
-
- /**
- * Unregisters a listener for the specified event type(s),
- * or unregisters all listeners for the specified event type(s),
- * or unregisters all listeners for all event types.
- *
- * @memberOf Benchmark, Benchmark.Suite
- * @param {String} [type] The event type.
- * @param {Function} [listener] The function to unregister.
- * @returns {Object} The benchmark instance.
- * @example
- *
- * // unregister a listener for an event type
- * bench.off('cycle', listener);
- *
- * // unregister a listener for multiple event types
- * bench.off('start cycle', listener);
- *
- * // unregister all listeners for an event type
- * bench.off('cycle');
- *
- * // unregister all listeners for multiple event types
- * bench.off('start cycle complete');
- *
- * // unregister all listeners for all event types
- * bench.off();
- */
- function off(type, listener) {
- var me = this,
- events = me.events;
-
- events && each(type ? type.split(' ') : events, function(listeners, type) {
- var index;
- if (typeof listeners == 'string') {
- type = listeners;
- listeners = hasKey(events, type) && events[type];
- }
- if (listeners) {
- if (listener) {
- index = indexOf(listeners, listener);
- if (index > -1) {
- listeners.splice(index, 1);
- }
- } else {
- listeners.length = 0;
- }
- }
- });
- return me;
- }
-
- /**
- * Registers a listener for the specified event type(s).
- *
- * @memberOf Benchmark, Benchmark.Suite
- * @param {String} type The event type.
- * @param {Function} listener The function to register.
- * @returns {Object} The benchmark instance.
- * @example
- *
- * // register a listener for an event type
- * bench.on('cycle', listener);
- *
- * // register a listener for multiple event types
- * bench.on('start cycle', listener);
- */
- function on(type, listener) {
- var me = this,
- events = me.events || (me.events = {});
-
- forEach(type.split(' '), function(type) {
- (hasKey(events, type)
- ? events[type]
- : (events[type] = [])
- ).push(listener);
- });
- return me;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Aborts the benchmark without recording times.
- *
- * @memberOf Benchmark
- * @returns {Object} The benchmark instance.
- */
- function abort() {
- var event,
- me = this,
- resetting = calledBy.reset;
-
- if (me.running) {
- event = Event('abort');
- me.emit(event);
- if (!event.cancelled || resetting) {
- // avoid infinite recursion
- calledBy.abort = true;
- me.reset();
- delete calledBy.abort;
-
- if (support.timeout) {
- clearTimeout(me._timerId);
- delete me._timerId;
- }
- if (!resetting) {
- me.aborted = true;
- me.running = false;
- }
- }
- }
- return me;
- }
-
- /**
- * Creates a new benchmark using the same test and options.
- *
- * @memberOf Benchmark
- * @param {Object} options Options object to overwrite cloned options.
- * @returns {Object} The new benchmark instance.
- * @example
- *
- * var bizarro = bench.clone({
- * 'name': 'doppelganger'
- * });
- */
- function clone(options) {
- var me = this,
- result = new me.constructor(extend({}, me, options));
-
- // correct the `options` object
- result.options = extend({}, me.options, options);
-
- // copy own custom properties
- forOwn(me, function(value, key) {
- if (!hasKey(result, key)) {
- result[key] = deepClone(value);
- }
- });
- return result;
- }
-
- /**
- * Determines if a benchmark is faster than another.
- *
- * @memberOf Benchmark
- * @param {Object} other The benchmark to compare.
- * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate.
- */
- function compare(other) {
- var critical,
- zStat,
- me = this,
- sample1 = me.stats.sample,
- sample2 = other.stats.sample,
- size1 = sample1.length,
- size2 = sample2.length,
- maxSize = max(size1, size2),
- minSize = min(size1, size2),
- u1 = getU(sample1, sample2),
- u2 = getU(sample2, sample1),
- u = min(u1, u2);
-
- function getScore(xA, sampleB) {
- return reduce(sampleB, function(total, xB) {
- return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5);
- }, 0);
- }
-
- function getU(sampleA, sampleB) {
- return reduce(sampleA, function(total, xA) {
- return total + getScore(xA, sampleB);
- }, 0);
- }
-
- function getZ(u) {
- return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12);
- }
-
- // exit early if comparing the same benchmark
- if (me == other) {
- return 0;
- }
- // reject the null hyphothesis the two samples come from the
- // same population (i.e. have the same median) if...
- if (size1 + size2 > 30) {
- // ...the z-stat is greater than 1.96 or less than -1.96
- // http://www.statisticslectures.com/topics/mannwhitneyu/
- zStat = getZ(u);
- return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0;
- }
- // ...the U value is less than or equal the critical U value
- // http://www.geoib.com/mann-whitney-u-test.html
- critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3];
- return u <= critical ? (u == u1 ? 1 : -1) : 0;
- }
-
- /**
- * Reset properties and abort if running.
- *
- * @memberOf Benchmark
- * @returns {Object} The benchmark instance.
- */
- function reset() {
- var data,
- event,
- me = this,
- index = 0,
- changes = { 'length': 0 },
- queue = { 'length': 0 };
-
- if (me.running && !calledBy.abort) {
- // no worries, `reset()` is called within `abort()`
- calledBy.reset = true;
- me.abort();
- delete calledBy.reset;
- }
- else {
- // a non-recursive solution to check if properties have changed
- // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4
- data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) };
- do {
- forOwn(data.source, function(value, key) {
- var changed,
- destination = data.destination,
- currValue = destination[key];
-
- if (value && typeof value == 'object') {
- if (isClassOf(value, 'Array')) {
- // check if an array value has changed to a non-array value
- if (!isClassOf(currValue, 'Array')) {
- changed = currValue = [];
- }
- // or has changed its length
- if (currValue.length != value.length) {
- changed = currValue = currValue.slice(0, value.length);
- currValue.length = value.length;
- }
- }
- // check if an object has changed to a non-object value
- else if (!currValue || typeof currValue != 'object') {
- changed = currValue = {};
- }
- // register a changed object
- if (changed) {
- changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue };
- }
- queue[queue.length++] = { 'destination': currValue, 'source': value };
- }
- // register a changed primitive
- else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) {
- changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value };
- }
- });
- }
- while ((data = queue[index++]));
-
- // if changed emit the `reset` event and if it isn't cancelled reset the benchmark
- if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) {
- forEach(changes, function(data) {
- data.destination[data.key] = data.value;
- });
- }
- }
- return me;
- }
-
- /**
- * Displays relevant benchmark information when coerced to a string.
- *
- * @name toString
- * @memberOf Benchmark
- * @returns {String} A string representation of the benchmark instance.
- */
- function toStringBench() {
- var me = this,
- error = me.error,
- hz = me.hz,
- id = me.id,
- stats = me.stats,
- size = stats.sample.length,
- pm = support.java ? '+/-' : '\xb1',
- result = me.name || (isNaN(id) ? id : '<Test #' + id + '>');
-
- if (error) {
- result += ': ' + join(error);
- } else {
- result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm +
- stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)';
- }
- return result;
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Clocks the time taken to execute a test per cycle (secs).
- *
- * @private
- * @param {Object} bench The benchmark instance.
- * @returns {Number} The time taken.
- */
- function clock() {
- var applet,
- options = Benchmark.options,
- template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid },
- timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }];
-
- // lazy define for hi-res timers
- clock = function(clone) {
- var deferred;
- if (clone instanceof Deferred) {
- deferred = clone;
- clone = deferred.benchmark;
- }
-
- var bench = clone._original,
- fn = bench.fn,
- fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '',
- stringable = isStringable(fn);
-
- var source = {
- 'setup': getSource(bench.setup, preprocess('m$.setup()')),
- 'fn': getSource(fn, preprocess('m$.fn(' + fnArg + ')')),
- 'fnArg': fnArg,
- 'teardown': getSource(bench.teardown, preprocess('m$.teardown()'))
- };
-
- var count = bench.count = clone.count,
- decompilable = support.decompilation || stringable,
- id = bench.id,
- isEmpty = !(source.fn || stringable),
- name = bench.name || (typeof id == 'number' ? '<Test #' + id + '>' : id),
- ns = timer.ns,
- result = 0;
-
- // init `minTime` if needed
- clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime);
-
- // repair nanosecond timer
- // (some Chrome builds erase the `ns` variable after millions of executions)
- if (applet) {
- try {
- ns.nanoTime();
- } catch(e) {
- // use non-element to avoid issues with libs that augment them
- ns = timer.ns = new applet.Packages.nano;
- }
- }
-
- // Compile in setup/teardown functions and the test loop.
- // Create a new compiled test, instead of using the cached `bench.compiled`,
- // to avoid potential engine optimizations enabled over the life of the test.
- var compiled = bench.compiled = createFunction(preprocess('t$'), interpolate(
- preprocess(deferred
- ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' +
- // when `deferred.cycles` is `0` then...
- 'if(!d$.cycles){' +
- // set `deferred.fn`
- 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' +
- // set `deferred.teardown`
- 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' +
- // execute the benchmark's `setup`
- 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' +
- // start timer
- 't$.start(d$);' +
- // execute `deferred.fn` and return a dummy object
- '}d$.fn();return{}'
-
- : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' +
- 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'),
- source
- ));
-
- try {
- if (isEmpty) {
- // Firefox may remove dead code from Function#toString results
- // http://bugzil.la/536085
- throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.');
- }
- else if (!deferred) {
- // pretest to determine if compiled code is exits early, usually by a
- // rogue `return` statement, by checking for a return object with the uid
- bench.count = 1;
- compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled;
- bench.count = count;
- }
- } catch(e) {
- compiled = null;
- clone.error = e || new Error(String(e));
- bench.count = count;
- }
- // fallback when a test exits early or errors during pretest
- if (decompilable && !compiled && !deferred && !isEmpty) {
- compiled = createFunction(preprocess('t$'), interpolate(
- preprocess(
- (clone.error && !stringable
- ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count'
- : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count'
- ) +
- ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' +
- 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}'
- ),
- source
- ));
-
- try {
- // pretest one more time to check for errors
- bench.count = 1;
- compiled.call(bench, timer);
- bench.compiled = compiled;
- bench.count = count;
- delete clone.error;
- }
- catch(e) {
- bench.count = count;
- if (clone.error) {
- compiled = null;
- } else {
- bench.compiled = compiled;
- clone.error = e || new Error(String(e));
- }
- }
- }
- // assign `compiled` to `clone` before calling in case a deferred benchmark
- // immediately calls `deferred.resolve()`
- clone.compiled = compiled;
- // if no errors run the full test loop
- if (!clone.error) {
- result = compiled.call(deferred || bench, timer).elapsed;
- }
- return result;
- };
-
- /*------------------------------------------------------------------------*/
-
- /**
- * Gets the current timer's minimum resolution (secs).
- */
- function getRes(unit) {
- var measured,
- begin,
- count = 30,
- divisor = 1e3,
- ns = timer.ns,
- sample = [];
-
- // get average smallest measurable time
- while (count--) {
- if (unit == 'us') {
- divisor = 1e6;
- if (ns.stop) {
- ns.start();
- while (!(measured = ns.microseconds())) { }
- } else if (ns[perfName]) {
- divisor = 1e3;
- measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns);
- } else {
- begin = ns();
- while (!(measured = ns() - begin)) { }
- }
- }
- else if (unit == 'ns') {
- divisor = 1e9;
- if (ns.nanoTime) {
- begin = ns.nanoTime();
- while (!(measured = ns.nanoTime() - begin)) { }
- } else {
- begin = (begin = ns())[0] + (begin[1] / divisor);
- while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { }
- divisor = 1;
- }
- }
- else {
- begin = new ns;
- while (!(measured = new ns - begin)) { }
- }
- // check for broken timers (nanoTime may have issues)
- // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/
- if (measured > 0) {
- sample.push(measured);
- } else {
- sample.push(Infinity);
- break;
- }
- }
- // convert to seconds
- return getMean(sample) / divisor;
- }
-
- /**
- * Replaces all occurrences of `$` with a unique number and
- * template tokens with content.
- */
- function preprocess(code) {
- return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid));
- }
-
- /*------------------------------------------------------------------------*/
-
- // detect nanosecond support from a Java applet
- each(doc && doc.applets || [], function(element) {
- return !(timer.ns = applet = 'nanoTime' in element && element);
- });
-
- // check type in case Safari returns an object instead of a number
- try {
- if (typeof timer.ns.nanoTime() == 'number') {
- timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
- }
- } catch(e) { }
-
- // detect Chrome's microsecond timer:
- // enable benchmarking via the --enable-benchmarking command
- // line switch in at least Chrome 7 to use chrome.Interval
- try {
- if ((timer.ns = new (window.chrome || window.chromium).Interval)) {
- timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
- }
- } catch(e) { }
-
- // detect `performance.now` microsecond resolution timer
- if ((timer.ns = perfName && perfObject)) {
- timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
- }
-
- // detect Node's nanosecond resolution timer available in Node >= 0.8
- if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') {
- timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' });
- }
-
- // detect Wade Simmons' Node microtime module
- if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') {
- timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' });
- }
-
- // pick timer with highest resolution
- timer = reduce(timers, function(timer, other) {
- return other.res < timer.res ? other : timer;
- });
-
- // remove unused applet
- if (timer.unit != 'ns' && applet) {
- applet = destroyElement(applet);
- }
- // error if there are no working timers
- if (timer.res == Infinity) {
- throw new Error('Benchmark.js was unable to find a working timer.');
- }
- // use API of chosen timer
- if (timer.unit == 'ns') {
- if (timer.ns.nanoTime) {
- extend(template, {
- 'begin': 's$=n$.nanoTime()',
- 'end': 'r$=(n$.nanoTime()-s$)/1e9'
- });
- } else {
- extend(template, {
- 'begin': 's$=n$()',
- 'end': 'r$=n$(s$);r$=r$[0]+(r$[1]/1e9)'
- });
- }
- }
- else if (timer.unit == 'us') {
- if (timer.ns.stop) {
- extend(template, {
- 'begin': 's$=n$.start()',
- 'end': 'r$=n$.microseconds()/1e6'
- });
- } else if (perfName) {
- extend(template, {
- 'begin': 's$=n$.' + perfName + '()',
- 'end': 'r$=(n$.' + perfName + '()-s$)/1e3'
- });
- } else {
- extend(template, {
- 'begin': 's$=n$()',
- 'end': 'r$=(n$()-s$)/1e6'
- });
- }
- }
-
- // define `timer` methods
- timer.start = createFunction(preprocess('o$'),
- preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$'));
-
- timer.stop = createFunction(preprocess('o$'),
- preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$'));
-
- // resolve time span required to achieve a percent uncertainty of at most 1%
- // http://spiff.rit.edu/classes/phys273/uncert/uncert.html
- options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05));
- return clock.apply(null, arguments);
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Computes stats on benchmark results.
- *
- * @private
- * @param {Object} bench The benchmark instance.
- * @param {Object} options The options object.
- */
- function compute(bench, options) {
- options || (options = {});
-
- var async = options.async,
- elapsed = 0,
- initCount = bench.initCount,
- minSamples = bench.minSamples,
- queue = [],
- sample = bench.stats.sample;
-
- /**
- * Adds a clone to the queue.
- */
- function enqueue() {
- queue.push(bench.clone({
- '_original': bench,
- 'events': {
- 'abort': [update],
- 'cycle': [update],
- 'error': [update],
- 'start': [update]
- }
- }));
- }
-
- /**
- * Updates the clone/original benchmarks to keep their data in sync.
- */
- function update(event) {
- var clone = this,
- type = event.type;
-
- if (bench.running) {
- if (type == 'start') {
- // Note: `clone.minTime` prop is inited in `clock()`
- clone.count = bench.initCount;
- }
- else {
- if (type == 'error') {
- bench.error = clone.error;
- }
- if (type == 'abort') {
- bench.abort();
- bench.emit('cycle');
- } else {
- event.currentTarget = event.target = bench;
- bench.emit(event);
- }
- }
- } else if (bench.aborted) {
- // clear abort listeners to avoid triggering bench's abort/cycle again
- clone.events.abort.length = 0;
- clone.abort();
- }
- }
-
- /**
- * Determines if more clones should be queued or if cycling should stop.
- */
- function evaluate(event) {
- var critical,
- df,
- mean,
- moe,
- rme,
- sd,
- sem,
- variance,
- clone = event.target,
- done = bench.aborted,
- now = +new Date,
- size = sample.push(clone.times.period),
- maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime,
- times = bench.times,
- varOf = function(sum, x) { return sum + pow(x - mean, 2); };
-
- // exit early for aborted or unclockable tests
- if (done || clone.hz == Infinity) {
- maxedOut = !(size = sample.length = queue.length = 0);
- }
-
- if (!done) {
- // sample mean (estimate of the population mean)
- mean = getMean(sample);
- // sample variance (estimate of the population variance)
- variance = reduce(sample, varOf, 0) / (size - 1) || 0;
- // sample standard deviation (estimate of the population standard deviation)
- sd = sqrt(variance);
- // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean)
- sem = sd / sqrt(size);
- // degrees of freedom
- df = size - 1;
- // critical value
- critical = tTable[Math.round(df) || 1] || tTable.infinity;
- // margin of error
- moe = sem * critical;
- // relative margin of error
- rme = (moe / mean) * 100 || 0;
-
- extend(bench.stats, {
- 'deviation': sd,
- 'mean': mean,
- 'moe': moe,
- 'rme': rme,
- 'sem': sem,
- 'variance': variance
- });
-
- // Abort the cycle loop when the minimum sample size has been collected
- // and the elapsed time exceeds the maximum time allowed per benchmark.
- // We don't count cycle delays toward the max time because delays may be
- // increased by browsers that clamp timeouts for inactive tabs.
- // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs
- if (maxedOut) {
- // reset the `initCount` in case the benchmark is rerun
- bench.initCount = initCount;
- bench.running = false;
- done = true;
- times.elapsed = (now - times.timeStamp) / 1e3;
- }
- if (bench.hz != Infinity) {
- bench.hz = 1 / mean;
- times.cycle = mean * bench.count;
- times.period = mean;
- }
- }
- // if time permits, increase sample size to reduce the margin of error
- if (queue.length < 2 && !maxedOut) {
- enqueue();
- }
- // abort the invoke cycle when done
- event.aborted = done;
- }
-
- // init queue and begin
- enqueue();
- invoke(queue, {
- 'name': 'run',
- 'args': { 'async': async },
- 'queued': true,
- 'onCycle': evaluate,
- 'onComplete': function() { bench.emit('complete'); }
- });
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Cycles a benchmark until a run `count` can be established.
- *
- * @private
- * @param {Object} clone The cloned benchmark instance.
- * @param {Object} options The options object.
- */
- function cycle(clone, options) {
- options || (options = {});
-
- var deferred;
- if (clone instanceof Deferred) {
- deferred = clone;
- clone = clone.benchmark;
- }
-
- var clocked,
- cycles,
- divisor,
- event,
- minTime,
- period,
- async = options.async,
- bench = clone._original,
- count = clone.count,
- times = clone.times;
-
- // continue, if not aborted between cycles
- if (clone.running) {
- // `minTime` is set to `Benchmark.options.minTime` in `clock()`
- cycles = ++clone.cycles;
- clocked = deferred ? deferred.elapsed : clock(clone);
- minTime = clone.minTime;
-
- if (cycles > bench.cycles) {
- bench.cycles = cycles;
- }
- if (clone.error) {
- event = Event('error');
- event.message = clone.error;
- clone.emit(event);
- if (!event.cancelled) {
- clone.abort();
- }
- }
- }
-
- // continue, if not errored
- if (clone.running) {
- // time taken to complete last test cycle
- bench.times.cycle = times.cycle = clocked;
- // seconds per operation
- period = bench.times.period = times.period = clocked / count;
- // ops per second
- bench.hz = clone.hz = 1 / period;
- // avoid working our way up to this next time
- bench.initCount = clone.initCount = count;
- // do we need to do another cycle?
- clone.running = clocked < minTime;
-
- if (clone.running) {
- // tests may clock at `0` when `initCount` is a small number,
- // to avoid that we set its count to something a bit higher
- if (!clocked && (divisor = divisors[clone.cycles]) != null) {
- count = floor(4e6 / divisor);
- }
- // calculate how many more iterations it will take to achive the `minTime`
- if (count <= clone.count) {
- count += Math.ceil((minTime - clocked) / period);
- }
- clone.running = count != Infinity;
- }
- }
- // should we exit early?
- event = Event('cycle');
- clone.emit(event);
- if (event.aborted) {
- clone.abort();
- }
- // figure out what to do next
- if (clone.running) {
- // start a new cycle
- clone.count = count;
- if (deferred) {
- clone.compiled.call(deferred, timer);
- } else if (async) {
- delay(clone, function() { cycle(clone, options); });
- } else {
- cycle(clone);
- }
- }
- else {
- // fix TraceMonkey bug associated with clock fallbacks
- // http://bugzil.la/509069
- if (support.browser) {
- runScript(uid + '=1;delete ' + uid);
- }
- // done
- clone.emit('complete');
- }
- }
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * Runs the benchmark.
- *
- * @memberOf Benchmark
- * @param {Object} [options={}] Options object.
- * @returns {Object} The benchmark instance.
- * @example
- *
- * // basic usage
- * bench.run();
- *
- * // or with options
- * bench.run({ 'async': true });
- */
- function run(options) {
- var me = this,
- event = Event('start');
-
- // set `running` to `false` so `reset()` won't call `abort()`
- me.running = false;
- me.reset();
- me.running = true;
-
- me.count = me.initCount;
- me.times.timeStamp = +new Date;
- me.emit(event);
-
- if (!event.cancelled) {
- options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout };
-
- // for clones created within `compute()`
- if (me._original) {
- if (me.defer) {
- Deferred(me);
- } else {
- cycle(me, options);
- }
- }
- // for original benchmarks
- else {
- compute(me, options);
- }
- }
- return me;
- }
-
- /*--------------------------------------------------------------------------*/
-
- // Firefox 1 erroneously defines variable and argument names of functions on
- // the function itself as non-configurable properties with `undefined` values.
- // The bugginess continues as the `Benchmark` constructor has an argument
- // named `options` and Firefox 1 will not assign a value to `Benchmark.options`,
- // making it non-writable in the process, unless it is the first property
- // assigned by for-in loop of `extend()`.
- extend(Benchmark, {
-
- /**
- * The default options copied by benchmark instances.
- *
- * @static
- * @memberOf Benchmark
- * @type Object
- */
- 'options': {
-
- /**
- * A flag to indicate that benchmark cycles will execute asynchronously
- * by default.
- *
- * @memberOf Benchmark.options
- * @type Boolean
- */
- 'async': false,
-
- /**
- * A flag to indicate that the benchmark clock is deferred.
- *
- * @memberOf Benchmark.options
- * @type Boolean
- */
- 'defer': false,
-
- /**
- * The delay between test cycles (secs).
- * @memberOf Benchmark.options
- * @type Number
- */
- 'delay': 0.005,
-
- /**
- * Displayed by Benchmark#toString when a `name` is not available
- * (auto-generated if absent).
- *
- * @memberOf Benchmark.options
- * @type String
- */
- 'id': undefined,
-
- /**
- * The default number of times to execute a test on a benchmark's first cycle.
- *
- * @memberOf Benchmark.options
- * @type Number
- */
- 'initCount': 1,
-
- /**
- * The maximum time a benchmark is allowed to run before finishing (secs).
- * Note: Cycle delays aren't counted toward the maximum time.
- *
- * @memberOf Benchmark.options
- * @type Number
- */
- 'maxTime': 5,
-
- /**
- * The minimum sample size required to perform statistical analysis.
- *
- * @memberOf Benchmark.options
- * @type Number
- */
- 'minSamples': 5,
-
- /**
- * The time needed to reduce the percent uncertainty of measurement to 1% (secs).
- *
- * @memberOf Benchmark.options
- * @type Number
- */
- 'minTime': 0,
-
- /**
- * The name of the benchmark.
- *
- * @memberOf Benchmark.options
- * @type String
- */
- 'name': undefined,
-
- /**
- * An event listener called when the benchmark is aborted.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onAbort': undefined,
-
- /**
- * An event listener called when the benchmark completes running.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onComplete': undefined,
-
- /**
- * An event listener called after each run cycle.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onCycle': undefined,
-
- /**
- * An event listener called when a test errors.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onError': undefined,
-
- /**
- * An event listener called when the benchmark is reset.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onReset': undefined,
-
- /**
- * An event listener called when the benchmark starts running.
- *
- * @memberOf Benchmark.options
- * @type Function
- */
- 'onStart': undefined
- },
-
- /**
- * Platform object with properties describing things like browser name,
- * version, and operating system.
- *
- * @static
- * @memberOf Benchmark
- * @type Object
- */
- 'platform': req('platform') || window.platform || {
-
- /**
- * The platform description.
- *
- * @memberOf Benchmark.platform
- * @type String
- */
- 'description': window.navigator && navigator.userAgent || null,
-
- /**
- * The name of the browser layout engine.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'layout': null,
-
- /**
- * The name of the product hosting the browser.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'product': null,
-
- /**
- * The name of the browser/environment.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'name': null,
-
- /**
- * The name of the product's manufacturer.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'manufacturer': null,
-
- /**
- * The name of the operating system.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'os': null,
-
- /**
- * The alpha/beta release indicator.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'prerelease': null,
-
- /**
- * The browser/environment version.
- *
- * @memberOf Benchmark.platform
- * @type String|Null
- */
- 'version': null,
-
- /**
- * Return platform description when the platform object is coerced to a string.
- *
- * @memberOf Benchmark.platform
- * @type Function
- * @returns {String} The platform description.
- */
- 'toString': function() {
- return this.description || '';
- }
- },
-
- /**
- * The semantic version number.
- *
- * @static
- * @memberOf Benchmark
- * @type String
- */
- 'version': '1.0.0',
-
- // an object of environment/feature detection flags
- 'support': support,
-
- // clone objects
- 'deepClone': deepClone,
-
- // iteration utility
- 'each': each,
-
- // augment objects
- 'extend': extend,
-
- // generic Array#filter
- 'filter': filter,
-
- // generic Array#forEach
- 'forEach': forEach,
-
- // generic own property iteration utility
- 'forOwn': forOwn,
-
- // converts a number to a comma-separated string
- 'formatNumber': formatNumber,
-
- // generic Object#hasOwnProperty
- // (trigger hasKey's lazy define before assigning it to Benchmark)
- 'hasKey': (hasKey(Benchmark, ''), hasKey),
-
- // generic Array#indexOf
- 'indexOf': indexOf,
-
- // template utility
- 'interpolate': interpolate,
-
- // invokes a method on each item in an array
- 'invoke': invoke,
-
- // generic Array#join for arrays and objects
- 'join': join,
-
- // generic Array#map
- 'map': map,
-
- // retrieves a property value from each item in an array
- 'pluck': pluck,
-
- // generic Array#reduce
- 'reduce': reduce
- });
-
- /*--------------------------------------------------------------------------*/
-
- extend(Benchmark.prototype, {
-
- /**
- * The number of times a test was executed.
- *
- * @memberOf Benchmark
- * @type Number
- */
- 'count': 0,
-
- /**
- * The number of cycles performed while benchmarking.
- *
- * @memberOf Benchmark
- * @type Number
- */
- 'cycles': 0,
-
- /**
- * The number of executions per second.
- *
- * @memberOf Benchmark
- * @type Number
- */
- 'hz': 0,
-
- /**
- * The compiled test function.
- *
- * @memberOf Benchmark
- * @type Function|String
- */
- 'compiled': undefined,
-
- /**
- * The error object if the test failed.
- *
- * @memberOf Benchmark
- * @type Object
- */
- 'error': undefined,
-
- /**
- * The test to benchmark.
- *
- * @memberOf Benchmark
- * @type Function|String
- */
- 'fn': undefined,
-
- /**
- * A flag to indicate if the benchmark is aborted.
- *
- * @memberOf Benchmark
- * @type Boolean
- */
- 'aborted': false,
-
- /**
- * A flag to indicate if the benchmark is running.
- *
- * @memberOf Benchmark
- * @type Boolean
- */
- 'running': false,
-
- /**
- * Compiled into the test and executed immediately **before** the test loop.
- *
- * @memberOf Benchmark
- * @type Function|String
- * @example
- *
- * // basic usage
- * var bench = Benchmark({
- * 'setup': function() {
- * var c = this.count,
- * element = document.getElementById('container');
- * while (c--) {
- * element.appendChild(document.createElement('div'));
- * }
- * },
- * 'fn': function() {
- * element.removeChild(element.lastChild);
- * }
- * });
- *
- * // compiles to something like:
- * var c = this.count,
- * element = document.getElementById('container');
- * while (c--) {
- * element.appendChild(document.createElement('div'));
- * }
- * var start = new Date;
- * while (count--) {
- * element.removeChild(element.lastChild);
- * }
- * var end = new Date - start;
- *
- * // or using strings
- * var bench = Benchmark({
- * 'setup': '\
- * var a = 0;\n\
- * (function() {\n\
- * (function() {\n\
- * (function() {',
- * 'fn': 'a += 1;',
- * 'teardown': '\
- * }())\n\
- * }())\n\
- * }())'
- * });
- *
- * // compiles to something like:
- * var a = 0;
- * (function() {
- * (function() {
- * (function() {
- * var start = new Date;
- * while (count--) {
- * a += 1;
- * }
- * var end = new Date - start;
- * }())
- * }())
- * }())
- */
- 'setup': noop,
-
- /**
- * Compiled into the test and executed immediately **after** the test loop.
- *
- * @memberOf Benchmark
- * @type Function|String
- */
- 'teardown': noop,
-
- /**
- * An object of stats including mean, margin or error, and standard deviation.
- *
- * @memberOf Benchmark
- * @type Object
- */
- 'stats': {
-
- /**
- * The margin of error.
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'moe': 0,
-
- /**
- * The relative margin of error (expressed as a percentage of the mean).
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'rme': 0,
-
- /**
- * The standard error of the mean.
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'sem': 0,
-
- /**
- * The sample standard deviation.
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'deviation': 0,
-
- /**
- * The sample arithmetic mean.
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'mean': 0,
-
- /**
- * The array of sampled periods.
- *
- * @memberOf Benchmark#stats
- * @type Array
- */
- 'sample': [],
-
- /**
- * The sample variance.
- *
- * @memberOf Benchmark#stats
- * @type Number
- */
- 'variance': 0
- },
-
- /**
- * An object of timing data including cycle, elapsed, period, start, and stop.
- *
- * @memberOf Benchmark
- * @type Object
- */
- 'times': {
-
- /**
- * The time taken to complete the last cycle (secs).
- *
- * @memberOf Benchmark#times
- * @type Number
- */
- 'cycle': 0,
-
- /**
- * The time taken to complete the benchmark (secs).
- *
- * @memberOf Benchmark#times
- * @type Number
- */
- 'elapsed': 0,
-
- /**
- * The time taken to execute the test once (secs).
- *
- * @memberOf Benchmark#times
- * @type Number
- */
- 'period': 0,
-
- /**
- * A timestamp of when the benchmark started (ms).
- *
- * @memberOf Benchmark#times
- * @type Number
- */
- 'timeStamp': 0
- },
-
- // aborts benchmark (does not record times)
- 'abort': abort,
-
- // creates a new benchmark using the same test and options
- 'clone': clone,
-
- // compares benchmark's hertz with another
- 'compare': compare,
-
- // executes listeners
- 'emit': emit,
-
- // get listeners
- 'listeners': listeners,
-
- // unregister listeners
- 'off': off,
-
- // register listeners
- 'on': on,
-
- // reset benchmark properties
- 'reset': reset,
-
- // runs the benchmark
- 'run': run,
-
- // pretty print benchmark info
- 'toString': toStringBench
- });
-
- /*--------------------------------------------------------------------------*/
-
- extend(Deferred.prototype, {
-
- /**
- * The deferred benchmark instance.
- *
- * @memberOf Benchmark.Deferred
- * @type Object
- */
- 'benchmark': null,
-
- /**
- * The number of deferred cycles performed while benchmarking.
- *
- * @memberOf Benchmark.Deferred
- * @type Number
- */
- 'cycles': 0,
-
- /**
- * The time taken to complete the deferred benchmark (secs).
- *
- * @memberOf Benchmark.Deferred
- * @type Number
- */
- 'elapsed': 0,
-
- /**
- * A timestamp of when the deferred benchmark started (ms).
- *
- * @memberOf Benchmark.Deferred
- * @type Number
- */
- 'timeStamp': 0,
-
- // cycles/completes the deferred benchmark
- 'resolve': resolve
- });
-
- /*--------------------------------------------------------------------------*/
-
- extend(Event.prototype, {
-
- /**
- * A flag to indicate if the emitters listener iteration is aborted.
- *
- * @memberOf Benchmark.Event
- * @type Boolean
- */
- 'aborted': false,
-
- /**
- * A flag to indicate if the default action is cancelled.
- *
- * @memberOf Benchmark.Event
- * @type Boolean
- */
- 'cancelled': false,
-
- /**
- * The object whose listeners are currently being processed.
- *
- * @memberOf Benchmark.Event
- * @type Object
- */
- 'currentTarget': undefined,
-
- /**
- * The return value of the last executed listener.
- *
- * @memberOf Benchmark.Event
- * @type Mixed
- */
- 'result': undefined,
-
- /**
- * The object to which the event was originally emitted.
- *
- * @memberOf Benchmark.Event
- * @type Object
- */
- 'target': undefined,
-
- /**
- * A timestamp of when the event was created (ms).
- *
- * @memberOf Benchmark.Event
- * @type Number
- */
- 'timeStamp': 0,
-
- /**
- * The event type.
- *
- * @memberOf Benchmark.Event
- * @type String
- */
- 'type': ''
- });
-
- /*--------------------------------------------------------------------------*/
-
- /**
- * The default options copied by suite instances.
- *
- * @static
- * @memberOf Benchmark.Suite
- * @type Object
- */
- Suite.options = {
-
- /**
- * The name of the suite.
- *
- * @memberOf Benchmark.Suite.options
- * @type String
- */
- 'name': undefined
- };
-
- /*--------------------------------------------------------------------------*/
-
- extend(Suite.prototype, {
-
- /**
- * The number of benchmarks in the suite.
- *
- * @memberOf Benchmark.Suite
- * @type Number
- */
- 'length': 0,
-
- /**
- * A flag to indicate if the suite is aborted.
- *
- * @memberOf Benchmark.Suite
- * @type Boolean
- */
- 'aborted': false,
-
- /**
- * A flag to indicate if the suite is running.
- *
- * @memberOf Benchmark.Suite
- * @type Boolean
- */
- 'running': false,
-
- /**
- * An `Array#forEach` like method.
- * Callbacks may terminate the loop by explicitly returning `false`.
- *
- * @memberOf Benchmark.Suite
- * @param {Function} callback The function called per iteration.
- * @returns {Object} The suite iterated over.
- */
- 'forEach': methodize(forEach),
-
- /**
- * An `Array#indexOf` like method.
- *
- * @memberOf Benchmark.Suite
- * @param {Mixed} value The value to search for.
- * @returns {Number} The index of the matched value or `-1`.
- */
- 'indexOf': methodize(indexOf),
-
- /**
- * Invokes a method on all benchmarks in the suite.
- *
- * @memberOf Benchmark.Suite
- * @param {String|Object} name The name of the method to invoke OR options object.
- * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
- * @returns {Array} A new array of values returned from each method invoked.
- */
- 'invoke': methodize(invoke),
-
- /**
- * Converts the suite of benchmarks to a string.
- *
- * @memberOf Benchmark.Suite
- * @param {String} [separator=','] A string to separate each element of the array.
- * @returns {String} The string.
- */
- 'join': [].join,
-
- /**
- * An `Array#map` like method.
- *
- * @memberOf Benchmark.Suite
- * @param {Function} callback The function called per iteration.
- * @returns {Array} A new array of values returned by the callback.
- */
- 'map': methodize(map),
-
- /**
- * Retrieves the value of a specified property from all benchmarks in the suite.
- *
- * @memberOf Benchmark.Suite
- * @param {String} property The property to pluck.
- * @returns {Array} A new array of property values.
- */
- 'pluck': methodize(pluck),
-
- /**
- * Removes the last benchmark from the suite and returns it.
- *
- * @memberOf Benchmark.Suite
- * @returns {Mixed} The removed benchmark.
- */
- 'pop': [].pop,
-
- /**
- * Appends benchmarks to the suite.
- *
- * @memberOf Benchmark.Suite
- * @returns {Number} The suite's new length.
- */
- 'push': [].push,
-
- /**
- * Sorts the benchmarks of the suite.
- *
- * @memberOf Benchmark.Suite
- * @param {Function} [compareFn=null] A function that defines the sort order.
- * @returns {Object} The sorted suite.
- */
- 'sort': [].sort,
-
- /**
- * An `Array#reduce` like method.
- *
- * @memberOf Benchmark.Suite
- * @param {Function} callback The function called per iteration.
- * @param {Mixed} accumulator Initial value of the accumulator.
- * @returns {Mixed} The accumulator.
- */
- 'reduce': methodize(reduce),
-
- // aborts all benchmarks in the suite
- 'abort': abortSuite,
-
- // adds a benchmark to the suite
- 'add': add,
-
- // creates a new suite with cloned benchmarks
- 'clone': cloneSuite,
-
- // executes listeners of a specified type
- 'emit': emit,
-
- // creates a new suite of filtered benchmarks
- 'filter': filterSuite,
-
- // get listeners
- 'listeners': listeners,
-
- // unregister listeners
- 'off': off,
-
- // register listeners
- 'on': on,
-
- // resets all benchmarks in the suite
- 'reset': resetSuite,
-
- // runs all benchmarks in the suite
- 'run': runSuite,
-
- // array methods
- 'concat': concat,
-
- 'reverse': reverse,
-
- 'shift': shift,
-
- 'slice': slice,
-
- 'splice': splice,
-
- 'unshift': unshift
- });
-
- /*--------------------------------------------------------------------------*/
-
- // expose Deferred, Event and Suite
- extend(Benchmark, {
- 'Deferred': Deferred,
- 'Event': Event,
- 'Suite': Suite
- });
-
- // expose Benchmark
- // some AMD build optimizers, like r.js, check for specific condition patterns like the following:
- if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
- // define as an anonymous module so, through path mapping, it can be aliased
- define(function() {
- return Benchmark;
- });
- }
- // check for `exports` after `define` in case a build optimizer adds an `exports` object
- else if (freeExports) {
- // in Node.js or RingoJS v0.8.0+
- if (typeof module == 'object' && module && module.exports == freeExports) {
- (module.exports = Benchmark).Benchmark = Benchmark;
- }
- // in Narwhal or RingoJS v0.7.0-
- else {
- freeExports.Benchmark = Benchmark;
- }
- }
- // in a browser or Rhino
- else {
- // use square bracket notation so Closure Compiler won't munge `Benchmark`
- // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
- window['Benchmark'] = Benchmark;
- }
-
- // trigger clock's lazy define early to avoid a security error
- if (support.air) {
- clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } });
- }
-}(this));
deleted file mode 100644
index cadaa100a068c9f48552aa9b5cedbf7dd6ba7d39..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/jquery-1.9.js
+++ /dev/null
@@ -1,9597 +0,0 @@
-/*!
- * jQuery JavaScript Library v1.9.1
- * http://jquery.com/
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- *
- * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2013-2-4
- */
-(function( window, undefined ) {
-
-// Can't do this because several apps including ASP.NET trace
-// the stack via arguments.caller.callee and Firefox dies if
-// you try to trace through "use strict" call chains. (#13335)
-// Support: Firefox 18+
-//"use strict";
-var
- // The deferred used on DOM ready
- readyList,
-
- // A central reference to the root jQuery(document)
- rootjQuery,
-
- // Support: IE<9
- // For `typeof node.method` instead of `node.method !== undefined`
- core_strundefined = typeof undefined,
-
- // Use the correct document accordingly with window argument (sandbox)
- document = window.document,
- location = window.location,
-
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$,
-
- // [[Class]] -> type pairs
- class2type = {},
-
- // List of deleted data cache ids, so we can reuse them
- core_deletedIds = [],
-
- core_version = "1.9.1",
-
- // Save a reference to some core methods
- core_concat = core_deletedIds.concat,
- core_push = core_deletedIds.push,
- core_slice = core_deletedIds.slice,
- core_indexOf = core_deletedIds.indexOf,
- core_toString = class2type.toString,
- core_hasOwn = class2type.hasOwnProperty,
- core_trim = core_version.trim,
-
- // Define a local copy of jQuery
- jQuery = function( selector, context ) {
- // The jQuery object is actually just the init constructor 'enhanced'
- return new jQuery.fn.init( selector, context, rootjQuery );
- },
-
- // Used for matching numbers
- core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,
-
- // Used for splitting on whitespace
- core_rnotwhite = /\S+/g,
-
- // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE)
- rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
-
- // A simple way to check for HTML strings
- // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
- // Strict HTML recognition (#11290: must start with <)
- rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,
-
- // Match a standalone tag
- rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/,
-
- // JSON RegExp
- rvalidchars = /^[\],:{}\s]*$/,
- rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
- rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,
- rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,
-
- // Matches dashed string for camelizing
- rmsPrefix = /^-ms-/,
- rdashAlpha = /-([\da-z])/gi,
-
- // Used by jQuery.camelCase as callback to replace()
- fcamelCase = function( all, letter ) {
- return letter.toUpperCase();
- },
-
- // The ready event handler
- completed = function( event ) {
-
- // readyState === "complete" is good enough for us to call the dom ready in oldIE
- if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
- detach();
- jQuery.ready();
- }
- },
- // Clean-up method for dom ready events
- detach = function() {
- if ( document.addEventListener ) {
- document.removeEventListener( "DOMContentLoaded", completed, false );
- window.removeEventListener( "load", completed, false );
-
- } else {
- document.detachEvent( "onreadystatechange", completed );
- window.detachEvent( "onload", completed );
- }
- };
-
-jQuery.fn = jQuery.prototype = {
- // The current version of jQuery being used
- jquery: core_version,
-
- constructor: jQuery,
- init: function( selector, context, rootjQuery ) {
- var match, elem;
-
- // HANDLE: $(""), $(null), $(undefined), $(false)
- if ( !selector ) {
- return this;
- }
-
- // Handle HTML strings
- if ( typeof selector === "string" ) {
- if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
- // Assume that strings that start and end with <> are HTML and skip the regex check
- match = [ null, selector, null ];
-
- } else {
- match = rquickExpr.exec( selector );
- }
-
- // Match html or make sure no context is specified for #id
- if ( match && (match[1] || !context) ) {
-
- // HANDLE: $(html) -> $(array)
- if ( match[1] ) {
- context = context instanceof jQuery ? context[0] : context;
-
- // scripts is true for back-compat
- jQuery.merge( this, jQuery.parseHTML(
- match[1],
- context && context.nodeType ? context.ownerDocument || context : document,
- true
- ) );
-
- // HANDLE: $(html, props)
- if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
- for ( match in context ) {
- // Properties of context are called as methods if possible
- if ( jQuery.isFunction( this[ match ] ) ) {
- this[ match ]( context[ match ] );
-
- // ...and otherwise set as attributes
- } else {
- this.attr( match, context[ match ] );
- }
- }
- }
-
- return this;
-
- // HANDLE: $(#id)
- } else {
- elem = document.getElementById( match[2] );
-
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE and Opera return items
- // by name instead of ID
- if ( elem.id !== match[2] ) {
- return rootjQuery.find( selector );
- }
-
- // Otherwise, we inject the element directly into the jQuery object
- this.length = 1;
- this[0] = elem;
- }
-
- this.context = document;
- this.selector = selector;
- return this;
- }
-
- // HANDLE: $(expr, $(...))
- } else if ( !context || context.jquery ) {
- return ( context || rootjQuery ).find( selector );
-
- // HANDLE: $(expr, context)
- // (which is just equivalent to: $(context).find(expr)
- } else {
- return this.constructor( context ).find( selector );
- }
-
- // HANDLE: $(DOMElement)
- } else if ( selector.nodeType ) {
- this.context = this[0] = selector;
- this.length = 1;
- return this;
-
- // HANDLE: $(function)
- // Shortcut for document ready
- } else if ( jQuery.isFunction( selector ) ) {
- return rootjQuery.ready( selector );
- }
-
- if ( selector.selector !== undefined ) {
- this.selector = selector.selector;
- this.context = selector.context;
- }
-
- return jQuery.makeArray( selector, this );
- },
-
- // Start with an empty selector
- selector: "",
-
- // The default length of a jQuery object is 0
- length: 0,
-
- // The number of elements contained in the matched element set
- size: function() {
- return this.length;
- },
-
- toArray: function() {
- return core_slice.call( this );
- },
-
- // Get the Nth element in the matched element set OR
- // Get the whole matched element set as a clean array
- get: function( num ) {
- return num == null ?
-
- // Return a 'clean' array
- this.toArray() :
-
- // Return just the object
- ( num < 0 ? this[ this.length + num ] : this[ num ] );
- },
-
- // Take an array of elements and push it onto the stack
- // (returning the new matched element set)
- pushStack: function( elems ) {
-
- // Build a new jQuery matched element set
- var ret = jQuery.merge( this.constructor(), elems );
-
- // Add the old object onto the stack (as a reference)
- ret.prevObject = this;
- ret.context = this.context;
-
- // Return the newly-formed element set
- return ret;
- },
-
- // Execute a callback for every element in the matched set.
- // (You can seed the arguments with an array of args, but this is
- // only used internally.)
- each: function( callback, args ) {
- return jQuery.each( this, callback, args );
- },
-
- ready: function( fn ) {
- // Add the callback
- jQuery.ready.promise().done( fn );
-
- return this;
- },
-
- slice: function() {
- return this.pushStack( core_slice.apply( this, arguments ) );
- },
-
- first: function() {
- return this.eq( 0 );
- },
-
- last: function() {
- return this.eq( -1 );
- },
-
- eq: function( i ) {
- var len = this.length,
- j = +i + ( i < 0 ? len : 0 );
- return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
- },
-
- map: function( callback ) {
- return this.pushStack( jQuery.map(this, function( elem, i ) {
- return callback.call( elem, i, elem );
- }));
- },
-
- end: function() {
- return this.prevObject || this.constructor(null);
- },
-
- // For internal use only.
- // Behaves like an Array's method, not like a jQuery method.
- push: core_push,
- sort: [].sort,
- splice: [].splice
-};
-
-// Give the init function the jQuery prototype for later instantiation
-jQuery.fn.init.prototype = jQuery.fn;
-
-jQuery.extend = jQuery.fn.extend = function() {
- var src, copyIsArray, copy, name, options, clone,
- target = arguments[0] || {},
- i = 1,
- length = arguments.length,
- deep = false;
-
- // Handle a deep copy situation
- if ( typeof target === "boolean" ) {
- deep = target;
- target = arguments[1] || {};
- // skip the boolean and the target
- i = 2;
- }
-
- // Handle case when target is a string or something (possible in deep copy)
- if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
- target = {};
- }
-
- // extend jQuery itself if only one argument is passed
- if ( length === i ) {
- target = this;
- --i;
- }
-
- for ( ; i < length; i++ ) {
- // Only deal with non-null/undefined values
- if ( (options = arguments[ i ]) != null ) {
- // Extend the base object
- for ( name in options ) {
- src = target[ name ];
- copy = options[ name ];
-
- // Prevent never-ending loop
- if ( target === copy ) {
- continue;
- }
-
- // Recurse if we're merging plain objects or arrays
- if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
- if ( copyIsArray ) {
- copyIsArray = false;
- clone = src && jQuery.isArray(src) ? src : [];
-
- } else {
- clone = src && jQuery.isPlainObject(src) ? src : {};
- }
-
- // Never move original objects, clone them
- target[ name ] = jQuery.extend( deep, clone, copy );
-
- // Don't bring in undefined values
- } else if ( copy !== undefined ) {
- target[ name ] = copy;
- }
- }
- }
- }
-
- // Return the modified object
- return target;
-};
-
-jQuery.extend({
- noConflict: function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
- },
-
- // Is the DOM ready to be used? Set to true once it occurs.
- isReady: false,
-
- // A counter to track how many items to wait for before
- // the ready event fires. See #6781
- readyWait: 1,
-
- // Hold (or release) the ready event
- holdReady: function( hold ) {
- if ( hold ) {
- jQuery.readyWait++;
- } else {
- jQuery.ready( true );
- }
- },
-
- // Handle when the DOM is ready
- ready: function( wait ) {
-
- // Abort if there are pending holds or we're already ready
- if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
- return;
- }
-
- // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
- if ( !document.body ) {
- return setTimeout( jQuery.ready );
- }
-
- // Remember that the DOM is ready
- jQuery.isReady = true;
-
- // If a normal DOM Ready event fired, decrement, and wait if need be
- if ( wait !== true && --jQuery.readyWait > 0 ) {
- return;
- }
-
- // If there are functions bound, to execute
- readyList.resolveWith( document, [ jQuery ] );
-
- // Trigger any bound ready events
- if ( jQuery.fn.trigger ) {
- jQuery( document ).trigger("ready").off("ready");
- }
- },
-
- // See test/unit/core.js for details concerning isFunction.
- // Since version 1.3, DOM methods and functions like alert
- // aren't supported. They return false on IE (#2968).
- isFunction: function( obj ) {
- return jQuery.type(obj) === "function";
- },
-
- isArray: Array.isArray || function( obj ) {
- return jQuery.type(obj) === "array";
- },
-
- isWindow: function( obj ) {
- return obj != null && obj == obj.window;
- },
-
- isNumeric: function( obj ) {
- return !isNaN( parseFloat(obj) ) && isFinite( obj );
- },
-
- type: function( obj ) {
- if ( obj == null ) {
- return String( obj );
- }
- return typeof obj === "object" || typeof obj === "function" ?
- class2type[ core_toString.call(obj) ] || "object" :
- typeof obj;
- },
-
- isPlainObject: function( obj ) {
- // Must be an Object.
- // Because of IE, we also have to check the presence of the constructor property.
- // Make sure that DOM nodes and window objects don't pass through, as well
- if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
- return false;
- }
-
- try {
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !core_hasOwn.call(obj, "constructor") &&
- !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
- } catch ( e ) {
- // IE8,9 Will throw exceptions on certain host objects #9897
- return false;
- }
-
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
-
- var key;
- for ( key in obj ) {}
-
- return key === undefined || core_hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- var name;
- for ( name in obj ) {
- return false;
- }
- return true;
- },
-
- error: function( msg ) {
- throw new Error( msg );
- },
-
- // data: string of html
- // context (optional): If specified, the fragment will be created in this context, defaults to document
- // keepScripts (optional): If true, will include scripts passed in the html string
- parseHTML: function( data, context, keepScripts ) {
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- if ( typeof context === "boolean" ) {
- keepScripts = context;
- context = false;
- }
- context = context || document;
-
- var parsed = rsingleTag.exec( data ),
- scripts = !keepScripts && [];
-
- // Single tag
- if ( parsed ) {
- return [ context.createElement( parsed[1] ) ];
- }
-
- parsed = jQuery.buildFragment( [ data ], context, scripts );
- if ( scripts ) {
- jQuery( scripts ).remove();
- }
- return jQuery.merge( [], parsed.childNodes );
- },
-
- parseJSON: function( data ) {
- // Attempt to parse using the native JSON parser first
- if ( window.JSON && window.JSON.parse ) {
- return window.JSON.parse( data );
- }
-
- if ( data === null ) {
- return data;
- }
-
- if ( typeof data === "string" ) {
-
- // Make sure leading/trailing whitespace is removed (IE can't handle it)
- data = jQuery.trim( data );
-
- if ( data ) {
- // Make sure the incoming data is actual JSON
- // Logic borrowed from http://json.org/json2.js
- if ( rvalidchars.test( data.replace( rvalidescape, "@" )
- .replace( rvalidtokens, "]" )
- .replace( rvalidbraces, "")) ) {
-
- return ( new Function( "return " + data ) )();
- }
- }
- }
-
- jQuery.error( "Invalid JSON: " + data );
- },
-
- // Cross-browser xml parsing
- parseXML: function( data ) {
- var xml, tmp;
- if ( !data || typeof data !== "string" ) {
- return null;
- }
- try {
- if ( window.DOMParser ) { // Standard
- tmp = new DOMParser();
- xml = tmp.parseFromString( data , "text/xml" );
- } else { // IE
- xml = new ActiveXObject( "Microsoft.XMLDOM" );
- xml.async = "false";
- xml.loadXML( data );
- }
- } catch( e ) {
- xml = undefined;
- }
- if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
- jQuery.error( "Invalid XML: " + data );
- }
- return xml;
- },
-
- noop: function() {},
-
- // Evaluates a script in a global context
- // Workarounds based on findings by Jim Driscoll
- // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
- globalEval: function( data ) {
- if ( data && jQuery.trim( data ) ) {
- // We use execScript on Internet Explorer
- // We use an anonymous function so that context is window
- // rather than jQuery in Firefox
- ( window.execScript || function( data ) {
- window[ "eval" ].call( window, data );
- } )( data );
- }
- },
-
- // Convert dashed to camelCase; used by the css and data modules
- // Microsoft forgot to hump their vendor prefix (#9572)
- camelCase: function( string ) {
- return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
- },
-
- nodeName: function( elem, name ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
- },
-
- // args is for internal usage only
- each: function( obj, callback, args ) {
- var value,
- i = 0,
- length = obj.length,
- isArray = isArraylike( obj );
-
- if ( args ) {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.apply( obj[ i ], args );
-
- if ( value === false ) {
- break;
- }
- }
- }
-
- // A special, fast, case for the most common use of each
- } else {
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- } else {
- for ( i in obj ) {
- value = callback.call( obj[ i ], i, obj[ i ] );
-
- if ( value === false ) {
- break;
- }
- }
- }
- }
-
- return obj;
- },
-
- // Use native String.trim function wherever possible
- trim: core_trim && !core_trim.call("\uFEFF\xA0") ?
- function( text ) {
- return text == null ?
- "" :
- core_trim.call( text );
- } :
-
- // Otherwise use our own trimming functionality
- function( text ) {
- return text == null ?
- "" :
- ( text + "" ).replace( rtrim, "" );
- },
-
- // results is for internal usage only
- makeArray: function( arr, results ) {
- var ret = results || [];
-
- if ( arr != null ) {
- if ( isArraylike( Object(arr) ) ) {
- jQuery.merge( ret,
- typeof arr === "string" ?
- [ arr ] : arr
- );
- } else {
- core_push.call( ret, arr );
- }
- }
-
- return ret;
- },
-
- inArray: function( elem, arr, i ) {
- var len;
-
- if ( arr ) {
- if ( core_indexOf ) {
- return core_indexOf.call( arr, elem, i );
- }
-
- len = arr.length;
- i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
-
- for ( ; i < len; i++ ) {
- // Skip accessing in sparse arrays
- if ( i in arr && arr[ i ] === elem ) {
- return i;
- }
- }
- }
-
- return -1;
- },
-
- merge: function( first, second ) {
- var l = second.length,
- i = first.length,
- j = 0;
-
- if ( typeof l === "number" ) {
- for ( ; j < l; j++ ) {
- first[ i++ ] = second[ j ];
- }
- } else {
- while ( second[j] !== undefined ) {
- first[ i++ ] = second[ j++ ];
- }
- }
-
- first.length = i;
-
- return first;
- },
-
- grep: function( elems, callback, inv ) {
- var retVal,
- ret = [],
- i = 0,
- length = elems.length;
- inv = !!inv;
-
- // Go through the array, only saving the items
- // that pass the validator function
- for ( ; i < length; i++ ) {
- retVal = !!callback( elems[ i ], i );
- if ( inv !== retVal ) {
- ret.push( elems[ i ] );
- }
- }
-
- return ret;
- },
-
- // arg is for internal usage only
- map: function( elems, callback, arg ) {
- var value,
- i = 0,
- length = elems.length,
- isArray = isArraylike( elems ),
- ret = [];
-
- // Go through the array, translating each of the items to their
- if ( isArray ) {
- for ( ; i < length; i++ ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
-
- // Go through every key on the object,
- } else {
- for ( i in elems ) {
- value = callback( elems[ i ], i, arg );
-
- if ( value != null ) {
- ret[ ret.length ] = value;
- }
- }
- }
-
- // Flatten any nested arrays
- return core_concat.apply( [], ret );
- },
-
- // A global GUID counter for objects
- guid: 1,
-
- // Bind a function to a context, optionally partially applying any
- // arguments.
- proxy: function( fn, context ) {
- var args, proxy, tmp;
-
- if ( typeof context === "string" ) {
- tmp = fn[ context ];
- context = fn;
- fn = tmp;
- }
-
- // Quick check to determine if target is callable, in the spec
- // this throws a TypeError, but we will just return undefined.
- if ( !jQuery.isFunction( fn ) ) {
- return undefined;
- }
-
- // Simulated bind
- args = core_slice.call( arguments, 2 );
- proxy = function() {
- return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) );
- };
-
- // Set the guid of unique handler to the same of original handler, so it can be removed
- proxy.guid = fn.guid = fn.guid || jQuery.guid++;
-
- return proxy;
- },
-
- // Multifunctional method to get and set values of a collection
- // The value/s can optionally be executed if it's a function
- access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
- var i = 0,
- length = elems.length,
- bulk = key == null;
-
- // Sets many values
- if ( jQuery.type( key ) === "object" ) {
- chainable = true;
- for ( i in key ) {
- jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
- }
-
- // Sets one value
- } else if ( value !== undefined ) {
- chainable = true;
-
- if ( !jQuery.isFunction( value ) ) {
- raw = true;
- }
-
- if ( bulk ) {
- // Bulk operations run against the entire set
- if ( raw ) {
- fn.call( elems, value );
- fn = null;
-
- // ...except when executing function values
- } else {
- bulk = fn;
- fn = function( elem, key, value ) {
- return bulk.call( jQuery( elem ), value );
- };
- }
- }
-
- if ( fn ) {
- for ( ; i < length; i++ ) {
- fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
- }
- }
- }
-
- return chainable ?
- elems :
-
- // Gets
- bulk ?
- fn.call( elems ) :
- length ? fn( elems[0], key ) : emptyGet;
- },
-
- now: function() {
- return ( new Date() ).getTime();
- }
-});
-
-jQuery.ready.promise = function( obj ) {
- if ( !readyList ) {
-
- readyList = jQuery.Deferred();
-
- // Catch cases where $(document).ready() is called after the browser event has already occurred.
- // we once tried to use readyState "interactive" here, but it caused issues like the one
- // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
- if ( document.readyState === "complete" ) {
- // Handle it asynchronously to allow scripts the opportunity to delay ready
- setTimeout( jQuery.ready );
-
- // Standards-based browsers support DOMContentLoaded
- } else if ( document.addEventListener ) {
- // Use the handy event callback
- document.addEventListener( "DOMContentLoaded", completed, false );
-
- // A fallback to window.onload, that will always work
- window.addEventListener( "load", completed, false );
-
- // If IE event model is used
- } else {
- // Ensure firing before onload, maybe late but safe also for iframes
- document.attachEvent( "onreadystatechange", completed );
-
- // A fallback to window.onload, that will always work
- window.attachEvent( "onload", completed );
-
- // If IE and not a frame
- // continually check to see if the document is ready
- var top = false;
-
- try {
- top = window.frameElement == null && document.documentElement;
- } catch(e) {}
-
- if ( top && top.doScroll ) {
- (function doScrollCheck() {
- if ( !jQuery.isReady ) {
-
- try {
- // Use the trick by Diego Perini
- // http://javascript.nwbox.com/IEContentLoaded/
- top.doScroll("left");
- } catch(e) {
- return setTimeout( doScrollCheck, 50 );
- }
-
- // detach all dom ready events
- detach();
-
- // and execute any waiting functions
- jQuery.ready();
- }
- })();
- }
- }
- }
- return readyList.promise( obj );
-};
-
-// Populate the class2type map
-jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
- class2type[ "[object " + name + "]" ] = name.toLowerCase();
-});
-
-function isArraylike( obj ) {
- var length = obj.length,
- type = jQuery.type( obj );
-
- if ( jQuery.isWindow( obj ) ) {
- return false;
- }
-
- if ( obj.nodeType === 1 && length ) {
- return true;
- }
-
- return type === "array" || type !== "function" &&
- ( length === 0 ||
- typeof length === "number" && length > 0 && ( length - 1 ) in obj );
-}
-
-// All jQuery objects should point back to these
-rootjQuery = jQuery(document);
-// String to Object options format cache
-var optionsCache = {};
-
-// Convert String-formatted options into Object-formatted ones and store in cache
-function createOptions( options ) {
- var object = optionsCache[ options ] = {};
- jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
- object[ flag ] = true;
- });
- return object;
-}
-
-/*
- * Create a callback list using the following parameters:
- *
- * options: an optional list of space-separated options that will change how
- * the callback list behaves or a more traditional option object
- *
- * By default a callback list will act like an event callback list and can be
- * "fired" multiple times.
- *
- * Possible options:
- *
- * once: will ensure the callback list can only be fired once (like a Deferred)
- *
- * memory: will keep track of previous values and will call any callback added
- * after the list has been fired right away with the latest "memorized"
- * values (like a Deferred)
- *
- * unique: will ensure a callback can only be added once (no duplicate in the list)
- *
- * stopOnFalse: interrupt callings when a callback returns false
- *
- */
-jQuery.Callbacks = function( options ) {
-
- // Convert options from String-formatted to Object-formatted if needed
- // (we check in cache first)
- options = typeof options === "string" ?
- ( optionsCache[ options ] || createOptions( options ) ) :
- jQuery.extend( {}, options );
-
- var // Flag to know if list is currently firing
- firing,
- // Last fire value (for non-forgettable lists)
- memory,
- // Flag to know if list was already fired
- fired,
- // End of the loop when firing
- firingLength,
- // Index of currently firing callback (modified by remove if needed)
- firingIndex,
- // First callback to fire (used internally by add and fireWith)
- firingStart,
- // Actual callback list
- list = [],
- // Stack of fire calls for repeatable lists
- stack = !options.once && [],
- // Fire callbacks
- fire = function( data ) {
- memory = options.memory && data;
- fired = true;
- firingIndex = firingStart || 0;
- firingStart = 0;
- firingLength = list.length;
- firing = true;
- for ( ; list && firingIndex < firingLength; firingIndex++ ) {
- if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
- memory = false; // To prevent further calls using add
- break;
- }
- }
- firing = false;
- if ( list ) {
- if ( stack ) {
- if ( stack.length ) {
- fire( stack.shift() );
- }
- } else if ( memory ) {
- list = [];
- } else {
- self.disable();
- }
- }
- },
- // Actual Callbacks object
- self = {
- // Add a callback or a collection of callbacks to the list
- add: function() {
- if ( list ) {
- // First, we save the current length
- var start = list.length;
- (function add( args ) {
- jQuery.each( args, function( _, arg ) {
- var type = jQuery.type( arg );
- if ( type === "function" ) {
- if ( !options.unique || !self.has( arg ) ) {
- list.push( arg );
- }
- } else if ( arg && arg.length && type !== "string" ) {
- // Inspect recursively
- add( arg );
- }
- });
- })( arguments );
- // Do we need to add the callbacks to the
- // current firing batch?
- if ( firing ) {
- firingLength = list.length;
- // With memory, if we're not firing then
- // we should call right away
- } else if ( memory ) {
- firingStart = start;
- fire( memory );
- }
- }
- return this;
- },
- // Remove a callback from the list
- remove: function() {
- if ( list ) {
- jQuery.each( arguments, function( _, arg ) {
- var index;
- while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
- list.splice( index, 1 );
- // Handle firing indexes
- if ( firing ) {
- if ( index <= firingLength ) {
- firingLength--;
- }
- if ( index <= firingIndex ) {
- firingIndex--;
- }
- }
- }
- });
- }
- return this;
- },
- // Check if a given callback is in the list.
- // If no argument is given, return whether or not list has callbacks attached.
- has: function( fn ) {
- return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
- },
- // Remove all callbacks from the list
- empty: function() {
- list = [];
- return this;
- },
- // Have the list do nothing anymore
- disable: function() {
- list = stack = memory = undefined;
- return this;
- },
- // Is it disabled?
- disabled: function() {
- return !list;
- },
- // Lock the list in its current state
- lock: function() {
- stack = undefined;
- if ( !memory ) {
- self.disable();
- }
- return this;
- },
- // Is it locked?
- locked: function() {
- return !stack;
- },
- // Call all callbacks with the given context and arguments
- fireWith: function( context, args ) {
- args = args || [];
- args = [ context, args.slice ? args.slice() : args ];
- if ( list && ( !fired || stack ) ) {
- if ( firing ) {
- stack.push( args );
- } else {
- fire( args );
- }
- }
- return this;
- },
- // Call all the callbacks with the given arguments
- fire: function() {
- self.fireWith( this, arguments );
- return this;
- },
- // To know if the callbacks have already been called at least once
- fired: function() {
- return !!fired;
- }
- };
-
- return self;
-};
-jQuery.extend({
-
- Deferred: function( func ) {
- var tuples = [
- // action, add listener, listener list, final state
- [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
- [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
- [ "notify", "progress", jQuery.Callbacks("memory") ]
- ],
- state = "pending",
- promise = {
- state: function() {
- return state;
- },
- always: function() {
- deferred.done( arguments ).fail( arguments );
- return this;
- },
- then: function( /* fnDone, fnFail, fnProgress */ ) {
- var fns = arguments;
- return jQuery.Deferred(function( newDefer ) {
- jQuery.each( tuples, function( i, tuple ) {
- var action = tuple[ 0 ],
- fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
- // deferred[ done | fail | progress ] for forwarding actions to newDefer
- deferred[ tuple[1] ](function() {
- var returned = fn && fn.apply( this, arguments );
- if ( returned && jQuery.isFunction( returned.promise ) ) {
- returned.promise()
- .done( newDefer.resolve )
- .fail( newDefer.reject )
- .progress( newDefer.notify );
- } else {
- newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
- }
- });
- });
- fns = null;
- }).promise();
- },
- // Get a promise for this deferred
- // If obj is provided, the promise aspect is added to the object
- promise: function( obj ) {
- return obj != null ? jQuery.extend( obj, promise ) : promise;
- }
- },
- deferred = {};
-
- // Keep pipe for back-compat
- promise.pipe = promise.then;
-
- // Add list-specific methods
- jQuery.each( tuples, function( i, tuple ) {
- var list = tuple[ 2 ],
- stateString = tuple[ 3 ];
-
- // promise[ done | fail | progress ] = list.add
- promise[ tuple[1] ] = list.add;
-
- // Handle state
- if ( stateString ) {
- list.add(function() {
- // state = [ resolved | rejected ]
- state = stateString;
-
- // [ reject_list | resolve_list ].disable; progress_list.lock
- }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
- }
-
- // deferred[ resolve | reject | notify ]
- deferred[ tuple[0] ] = function() {
- deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
- return this;
- };
- deferred[ tuple[0] + "With" ] = list.fireWith;
- });
-
- // Make the deferred a promise
- promise.promise( deferred );
-
- // Call given func if any
- if ( func ) {
- func.call( deferred, deferred );
- }
-
- // All done!
- return deferred;
- },
-
- // Deferred helper
- when: function( subordinate /* , ..., subordinateN */ ) {
- var i = 0,
- resolveValues = core_slice.call( arguments ),
- length = resolveValues.length,
-
- // the count of uncompleted subordinates
- remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
-
- // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
- deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
-
- // Update function for both resolve and progress values
- updateFunc = function( i, contexts, values ) {
- return function( value ) {
- contexts[ i ] = this;
- values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
- if( values === progressValues ) {
- deferred.notifyWith( contexts, values );
- } else if ( !( --remaining ) ) {
- deferred.resolveWith( contexts, values );
- }
- };
- },
-
- progressValues, progressContexts, resolveContexts;
-
- // add listeners to Deferred subordinates; treat others as resolved
- if ( length > 1 ) {
- progressValues = new Array( length );
- progressContexts = new Array( length );
- resolveContexts = new Array( length );
- for ( ; i < length; i++ ) {
- if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
- resolveValues[ i ].promise()
- .done( updateFunc( i, resolveContexts, resolveValues ) )
- .fail( deferred.reject )
- .progress( updateFunc( i, progressContexts, progressValues ) );
- } else {
- --remaining;
- }
- }
- }
-
- // if we're not waiting on anything, resolve the master
- if ( !remaining ) {
- deferred.resolveWith( resolveContexts, resolveValues );
- }
-
- return deferred.promise();
- }
-});
-jQuery.support = (function() {
-
- var support, all, a,
- input, select, fragment,
- opt, eventName, isSupported, i,
- div = document.createElement("div");
-
- // Setup
- div.setAttribute( "className", "t" );
- div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
-
- // Support tests won't run in some limited or non-browser environments
- all = div.getElementsByTagName("*");
- a = div.getElementsByTagName("a")[ 0 ];
- if ( !all || !a || !all.length ) {
- return {};
- }
-
- // First batch of tests
- select = document.createElement("select");
- opt = select.appendChild( document.createElement("option") );
- input = div.getElementsByTagName("input")[ 0 ];
-
- a.style.cssText = "top:1px;float:left;opacity:.5";
- support = {
- // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
- getSetAttribute: div.className !== "t",
-
- // IE strips leading whitespace when .innerHTML is used
- leadingWhitespace: div.firstChild.nodeType === 3,
-
- // Make sure that tbody elements aren't automatically inserted
- // IE will insert them into empty tables
- tbody: !div.getElementsByTagName("tbody").length,
-
- // Make sure that link elements get serialized correctly by innerHTML
- // This requires a wrapper element in IE
- htmlSerialize: !!div.getElementsByTagName("link").length,
-
- // Get the style information from getAttribute
- // (IE uses .cssText instead)
- style: /top/.test( a.getAttribute("style") ),
-
- // Make sure that URLs aren't manipulated
- // (IE normalizes it by default)
- hrefNormalized: a.getAttribute("href") === "/a",
-
- // Make sure that element opacity exists
- // (IE uses filter instead)
- // Use a regex to work around a WebKit issue. See #5145
- opacity: /^0.5/.test( a.style.opacity ),
-
- // Verify style float existence
- // (IE uses styleFloat instead of cssFloat)
- cssFloat: !!a.style.cssFloat,
-
- // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
- checkOn: !!input.value,
-
- // Make sure that a selected-by-default option has a working selected property.
- // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
- optSelected: opt.selected,
-
- // Tests for enctype support on a form (#6743)
- enctype: !!document.createElement("form").enctype,
-
- // Makes sure cloning an html5 element does not cause problems
- // Where outerHTML is undefined, this still works
- html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
-
- // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode
- boxModel: document.compatMode === "CSS1Compat",
-
- // Will be defined later
- deleteExpando: true,
- noCloneEvent: true,
- inlineBlockNeedsLayout: false,
- shrinkWrapBlocks: false,
- reliableMarginRight: true,
- boxSizingReliable: true,
- pixelPosition: false
- };
-
- // Make sure checked status is properly cloned
- input.checked = true;
- support.noCloneChecked = input.cloneNode( true ).checked;
-
- // Make sure that the options inside disabled selects aren't marked as disabled
- // (WebKit marks them as disabled)
- select.disabled = true;
- support.optDisabled = !opt.disabled;
-
- // Support: IE<9
- try {
- delete div.test;
- } catch( e ) {
- support.deleteExpando = false;
- }
-
- // Check if we can trust getAttribute("value")
- input = document.createElement("input");
- input.setAttribute( "value", "" );
- support.input = input.getAttribute( "value" ) === "";
-
- // Check if an input maintains its value after becoming a radio
- input.value = "t";
- input.setAttribute( "type", "radio" );
- support.radioValue = input.value === "t";
-
- // #11217 - WebKit loses check when the name is after the checked attribute
- input.setAttribute( "checked", "t" );
- input.setAttribute( "name", "t" );
-
- fragment = document.createDocumentFragment();
- fragment.appendChild( input );
-
- // Check if a disconnected checkbox will retain its checked
- // value of true after appended to the DOM (IE6/7)
- support.appendChecked = input.checked;
-
- // WebKit doesn't clone checked state correctly in fragments
- support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
-
- // Support: IE<9
- // Opera does not clone events (and typeof div.attachEvent === undefined).
- // IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
- if ( div.attachEvent ) {
- div.attachEvent( "onclick", function() {
- support.noCloneEvent = false;
- });
-
- div.cloneNode( true ).click();
- }
-
- // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
- // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
- for ( i in { submit: true, change: true, focusin: true }) {
- div.setAttribute( eventName = "on" + i, "t" );
-
- support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
- }
-
- div.style.backgroundClip = "content-box";
- div.cloneNode( true ).style.backgroundClip = "";
- support.clearCloneStyle = div.style.backgroundClip === "content-box";
-
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, marginDiv, tds,
- divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
- body = document.getElementsByTagName("body")[0];
-
- if ( !body ) {
- // Return for frameset docs that don't have a body
- return;
- }
-
- container = document.createElement("div");
- container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
-
- body.appendChild( container ).appendChild( div );
-
- // Support: IE8
- // Check if table cells still have offsetWidth/Height when they are set
- // to display:none and there are still other visible table cells in a
- // table row; if so, offsetWidth/Height are not reliable for use when
- // determining if an element has been hidden directly using
- // display:none (it is still safe to use offsets if a parent element is
- // hidden; don safety goggles and see bug #4512 for more information).
- div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
- tds = div.getElementsByTagName("td");
- tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
- isSupported = ( tds[ 0 ].offsetHeight === 0 );
-
- tds[ 0 ].style.display = "";
- tds[ 1 ].style.display = "none";
-
- // Support: IE8
- // Check if empty table cells still have offsetWidth/Height
- support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
-
- // Check box-sizing and margin behavior
- div.innerHTML = "";
- div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;";
- support.boxSizing = ( div.offsetWidth === 4 );
- support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
-
- // Use window.getComputedStyle because jsdom on node.js will break without it.
- if ( window.getComputedStyle ) {
- support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
- support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
-
- // Check if div with explicit width and no margin-right incorrectly
- // gets computed margin-right based on width of container. (#3333)
- // Fails in WebKit before Feb 2011 nightlies
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = div.appendChild( document.createElement("div") );
- marginDiv.style.cssText = div.style.cssText = divReset;
- marginDiv.style.marginRight = marginDiv.style.width = "0";
- div.style.width = "1px";
-
- support.reliableMarginRight =
- !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
- }
-
- if ( typeof div.style.zoom !== core_strundefined ) {
- // Support: IE<8
- // Check if natively block-level elements act like inline-block
- // elements when setting their display to 'inline' and giving
- // them layout
- div.innerHTML = "";
- div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
- support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
-
- // Support: IE6
- // Check if elements with layout shrink-wrap their children
- div.style.display = "block";
- div.innerHTML = "<div></div>";
- div.firstChild.style.width = "5px";
- support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
-
- if ( support.inlineBlockNeedsLayout ) {
- // Prevent IE 6 from affecting layout for positioned elements #11048
- // Prevent IE from shrinking the body in IE 7 mode #12869
- // Support: IE<8
- body.style.zoom = 1;
- }
- }
-
- body.removeChild( container );
-
- // Null elements to avoid leaks in IE
- container = div = tds = marginDiv = null;
- });
-
- // Null elements to avoid leaks in IE
- all = select = fragment = opt = a = input = null;
-
- return support;
-})();
-
-var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- rmultiDash = /([A-Z])/g;
-
-function internalData( elem, name, data, pvt /* Internal Use Only */ ){
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var thisCache, ret,
- internalKey = jQuery.expando,
- getByName = typeof name === "string",
-
- // We have to handle DOM nodes and JS objects differently because IE6-7
- // can't GC object references properly across the DOM-JS boundary
- isNode = elem.nodeType,
-
- // Only DOM nodes need the global jQuery cache; JS object data is
- // attached directly to the object so GC can occur automatically
- cache = isNode ? jQuery.cache : elem,
-
- // Only defining an ID for JS objects if its cache already exists allows
- // the code to shortcut on the same path as a DOM node with no cache
- id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
-
- // Avoid doing any more work than we need to when trying to get data on an
- // object that has no data at all
- if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) {
- return;
- }
-
- if ( !id ) {
- // Only DOM nodes need a new unique ID for each element since their data
- // ends up in the global cache
- if ( isNode ) {
- elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++;
- } else {
- id = internalKey;
- }
- }
-
- if ( !cache[ id ] ) {
- cache[ id ] = {};
-
- // Avoids exposing jQuery metadata on plain JS objects when the object
- // is serialized using JSON.stringify
- if ( !isNode ) {
- cache[ id ].toJSON = jQuery.noop;
- }
- }
-
- // An object can be passed to jQuery.data instead of a key/value pair; this gets
- // shallow copied over onto the existing cache
- if ( typeof name === "object" || typeof name === "function" ) {
- if ( pvt ) {
- cache[ id ] = jQuery.extend( cache[ id ], name );
- } else {
- cache[ id ].data = jQuery.extend( cache[ id ].data, name );
- }
- }
-
- thisCache = cache[ id ];
-
- // jQuery data() is stored in a separate object inside the object's internal data
- // cache in order to avoid key collisions between internal data and user-defined
- // data.
- if ( !pvt ) {
- if ( !thisCache.data ) {
- thisCache.data = {};
- }
-
- thisCache = thisCache.data;
- }
-
- if ( data !== undefined ) {
- thisCache[ jQuery.camelCase( name ) ] = data;
- }
-
- // Check for both converted-to-camel and non-converted data property names
- // If a data property was specified
- if ( getByName ) {
-
- // First Try to find as-is property data
- ret = thisCache[ name ];
-
- // Test for null|undefined property data
- if ( ret == null ) {
-
- // Try to find the camelCased property
- ret = thisCache[ jQuery.camelCase( name ) ];
- }
- } else {
- ret = thisCache;
- }
-
- return ret;
-}
-
-function internalRemoveData( elem, name, pvt ) {
- if ( !jQuery.acceptData( elem ) ) {
- return;
- }
-
- var i, l, thisCache,
- isNode = elem.nodeType,
-
- // See jQuery.data for more information
- cache = isNode ? jQuery.cache : elem,
- id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
-
- // If there is already no cache entry for this object, there is no
- // purpose in continuing
- if ( !cache[ id ] ) {
- return;
- }
-
- if ( name ) {
-
- thisCache = pvt ? cache[ id ] : cache[ id ].data;
-
- if ( thisCache ) {
-
- // Support array or space separated string names for data keys
- if ( !jQuery.isArray( name ) ) {
-
- // try the string as a key before any manipulation
- if ( name in thisCache ) {
- name = [ name ];
- } else {
-
- // split the camel cased version by spaces unless a key with the spaces exists
- name = jQuery.camelCase( name );
- if ( name in thisCache ) {
- name = [ name ];
- } else {
- name = name.split(" ");
- }
- }
- } else {
- // If "name" is an array of keys...
- // When data is initially created, via ("key", "val") signature,
- // keys will be converted to camelCase.
- // Since there is no way to tell _how_ a key was added, remove
- // both plain key and camelCase key. #12786
- // This will only penalize the array argument path.
- name = name.concat( jQuery.map( name, jQuery.camelCase ) );
- }
-
- for ( i = 0, l = name.length; i < l; i++ ) {
- delete thisCache[ name[i] ];
- }
-
- // If there is no data left in the cache, we want to continue
- // and let the cache object itself get destroyed
- if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
- return;
- }
- }
- }
-
- // See jQuery.data for more information
- if ( !pvt ) {
- delete cache[ id ].data;
-
- // Don't destroy the parent cache unless the internal data object
- // had been the only thing left in it
- if ( !isEmptyDataObject( cache[ id ] ) ) {
- return;
- }
- }
-
- // Destroy the cache
- if ( isNode ) {
- jQuery.cleanData( [ elem ], true );
-
- // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
- } else if ( jQuery.support.deleteExpando || cache != cache.window ) {
- delete cache[ id ];
-
- // When all else fails, null
- } else {
- cache[ id ] = null;
- }
-}
-
-jQuery.extend({
- cache: {},
-
- // Unique for each copy of jQuery on the page
- // Non-digits removed to match rinlinejQuery
- expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ),
-
- // The following elements throw uncatchable exceptions if you
- // attempt to add expando properties to them.
- noData: {
- "embed": true,
- // Ban all objects except for Flash (which handle expandos)
- "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
- "applet": true
- },
-
- hasData: function( elem ) {
- elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
- return !!elem && !isEmptyDataObject( elem );
- },
-
- data: function( elem, name, data ) {
- return internalData( elem, name, data );
- },
-
- removeData: function( elem, name ) {
- return internalRemoveData( elem, name );
- },
-
- // For internal use only.
- _data: function( elem, name, data ) {
- return internalData( elem, name, data, true );
- },
-
- _removeData: function( elem, name ) {
- return internalRemoveData( elem, name, true );
- },
-
- // A method for determining if a DOM node can handle the data expando
- acceptData: function( elem ) {
- // Do not set data on non-element because it will not be cleared (#8335).
- if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
- return false;
- }
-
- var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
-
- // nodes accept data unless otherwise specified; rejection can be conditional
- return !noData || noData !== true && elem.getAttribute("classid") === noData;
- }
-});
-
-jQuery.fn.extend({
- data: function( key, value ) {
- var attrs, name,
- elem = this[0],
- i = 0,
- data = null;
-
- // Gets all values
- if ( key === undefined ) {
- if ( this.length ) {
- data = jQuery.data( elem );
-
- if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
- attrs = elem.attributes;
- for ( ; i < attrs.length; i++ ) {
- name = attrs[i].name;
-
- if ( !name.indexOf( "data-" ) ) {
- name = jQuery.camelCase( name.slice(5) );
-
- dataAttr( elem, name, data[ name ] );
- }
- }
- jQuery._data( elem, "parsedAttrs", true );
- }
- }
-
- return data;
- }
-
- // Sets multiple values
- if ( typeof key === "object" ) {
- return this.each(function() {
- jQuery.data( this, key );
- });
- }
-
- return jQuery.access( this, function( value ) {
-
- if ( value === undefined ) {
- // Try to fetch any internally stored data first
- return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null;
- }
-
- this.each(function() {
- jQuery.data( this, key, value );
- });
- }, null, value, arguments.length > 1, null, true );
- },
-
- removeData: function( key ) {
- return this.each(function() {
- jQuery.removeData( this, key );
- });
- }
-});
-
-function dataAttr( elem, key, data ) {
- // If nothing was found internally, try to fetch any
- // data from the HTML5 data-* attribute
- if ( data === undefined && elem.nodeType === 1 ) {
-
- var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
-
- data = elem.getAttribute( name );
-
- if ( typeof data === "string" ) {
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? jQuery.parseJSON( data ) :
- data;
- } catch( e ) {}
-
- // Make sure we set the data so it isn't changed later
- jQuery.data( elem, key, data );
-
- } else {
- data = undefined;
- }
- }
-
- return data;
-}
-
-// checks a cache object for emptiness
-function isEmptyDataObject( obj ) {
- var name;
- for ( name in obj ) {
-
- // if the public data object is empty, the private is still empty
- if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
- continue;
- }
- if ( name !== "toJSON" ) {
- return false;
- }
- }
-
- return true;
-}
-jQuery.extend({
- queue: function( elem, type, data ) {
- var queue;
-
- if ( elem ) {
- type = ( type || "fx" ) + "queue";
- queue = jQuery._data( elem, type );
-
- // Speed up dequeue by getting out quickly if this is just a lookup
- if ( data ) {
- if ( !queue || jQuery.isArray(data) ) {
- queue = jQuery._data( elem, type, jQuery.makeArray(data) );
- } else {
- queue.push( data );
- }
- }
- return queue || [];
- }
- },
-
- dequeue: function( elem, type ) {
- type = type || "fx";
-
- var queue = jQuery.queue( elem, type ),
- startLength = queue.length,
- fn = queue.shift(),
- hooks = jQuery._queueHooks( elem, type ),
- next = function() {
- jQuery.dequeue( elem, type );
- };
-
- // If the fx queue is dequeued, always remove the progress sentinel
- if ( fn === "inprogress" ) {
- fn = queue.shift();
- startLength--;
- }
-
- hooks.cur = fn;
- if ( fn ) {
-
- // Add a progress sentinel to prevent the fx queue from being
- // automatically dequeued
- if ( type === "fx" ) {
- queue.unshift( "inprogress" );
- }
-
- // clear up the last queue stop function
- delete hooks.stop;
- fn.call( elem, next, hooks );
- }
-
- if ( !startLength && hooks ) {
- hooks.empty.fire();
- }
- },
-
- // not intended for public consumption - generates a queueHooks object, or returns the current one
- _queueHooks: function( elem, type ) {
- var key = type + "queueHooks";
- return jQuery._data( elem, key ) || jQuery._data( elem, key, {
- empty: jQuery.Callbacks("once memory").add(function() {
- jQuery._removeData( elem, type + "queue" );
- jQuery._removeData( elem, key );
- })
- });
- }
-});
-
-jQuery.fn.extend({
- queue: function( type, data ) {
- var setter = 2;
-
- if ( typeof type !== "string" ) {
- data = type;
- type = "fx";
- setter--;
- }
-
- if ( arguments.length < setter ) {
- return jQuery.queue( this[0], type );
- }
-
- return data === undefined ?
- this :
- this.each(function() {
- var queue = jQuery.queue( this, type, data );
-
- // ensure a hooks for this queue
- jQuery._queueHooks( this, type );
-
- if ( type === "fx" && queue[0] !== "inprogress" ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- dequeue: function( type ) {
- return this.each(function() {
- jQuery.dequeue( this, type );
- });
- },
- // Based off of the plugin by Clint Helfers, with permission.
- // http://blindsignals.com/index.php/2009/07/jquery-delay/
- delay: function( time, type ) {
- time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
- type = type || "fx";
-
- return this.queue( type, function( next, hooks ) {
- var timeout = setTimeout( next, time );
- hooks.stop = function() {
- clearTimeout( timeout );
- };
- });
- },
- clearQueue: function( type ) {
- return this.queue( type || "fx", [] );
- },
- // Get a promise resolved when queues of a certain type
- // are emptied (fx is the type by default)
- promise: function( type, obj ) {
- var tmp,
- count = 1,
- defer = jQuery.Deferred(),
- elements = this,
- i = this.length,
- resolve = function() {
- if ( !( --count ) ) {
- defer.resolveWith( elements, [ elements ] );
- }
- };
-
- if ( typeof type !== "string" ) {
- obj = type;
- type = undefined;
- }
- type = type || "fx";
-
- while( i-- ) {
- tmp = jQuery._data( elements[ i ], type + "queueHooks" );
- if ( tmp && tmp.empty ) {
- count++;
- tmp.empty.add( resolve );
- }
- }
- resolve();
- return defer.promise( obj );
- }
-});
-var nodeHook, boolHook,
- rclass = /[\t\r\n]/g,
- rreturn = /\r/g,
- rfocusable = /^(?:input|select|textarea|button|object)$/i,
- rclickable = /^(?:a|area)$/i,
- rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i,
- ruseDefault = /^(?:checked|selected)$/i,
- getSetAttribute = jQuery.support.getSetAttribute,
- getSetInput = jQuery.support.input;
-
-jQuery.fn.extend({
- attr: function( name, value ) {
- return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
- },
-
- removeAttr: function( name ) {
- return this.each(function() {
- jQuery.removeAttr( this, name );
- });
- },
-
- prop: function( name, value ) {
- return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
- },
-
- removeProp: function( name ) {
- name = jQuery.propFix[ name ] || name;
- return this.each(function() {
- // try/catch handles cases where IE balks (such as removing a property on window)
- try {
- this[ name ] = undefined;
- delete this[ name ];
- } catch( e ) {}
- });
- },
-
- addClass: function( value ) {
- var classes, elem, cur, clazz, j,
- i = 0,
- len = this.length,
- proceed = typeof value === "string" && value;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).addClass( value.call( this, j, this.className ) );
- });
- }
-
- if ( proceed ) {
- // The disjunction here is for better compressibility (see removeClass)
- classes = ( value || "" ).match( core_rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- " "
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
- cur += clazz + " ";
- }
- }
- elem.className = jQuery.trim( cur );
-
- }
- }
- }
-
- return this;
- },
-
- removeClass: function( value ) {
- var classes, elem, cur, clazz, j,
- i = 0,
- len = this.length,
- proceed = arguments.length === 0 || typeof value === "string" && value;
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( j ) {
- jQuery( this ).removeClass( value.call( this, j, this.className ) );
- });
- }
- if ( proceed ) {
- classes = ( value || "" ).match( core_rnotwhite ) || [];
-
- for ( ; i < len; i++ ) {
- elem = this[ i ];
- // This expression is here for better compressibility (see addClass)
- cur = elem.nodeType === 1 && ( elem.className ?
- ( " " + elem.className + " " ).replace( rclass, " " ) :
- ""
- );
-
- if ( cur ) {
- j = 0;
- while ( (clazz = classes[j++]) ) {
- // Remove *all* instances
- while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
- cur = cur.replace( " " + clazz + " ", " " );
- }
- }
- elem.className = value ? jQuery.trim( cur ) : "";
- }
- }
- }
-
- return this;
- },
-
- toggleClass: function( value, stateVal ) {
- var type = typeof value,
- isBool = typeof stateVal === "boolean";
-
- if ( jQuery.isFunction( value ) ) {
- return this.each(function( i ) {
- jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
- });
- }
-
- return this.each(function() {
- if ( type === "string" ) {
- // toggle individual class names
- var className,
- i = 0,
- self = jQuery( this ),
- state = stateVal,
- classNames = value.match( core_rnotwhite ) || [];
-
- while ( (className = classNames[ i++ ]) ) {
- // check each className given, space separated list
- state = isBool ? state : !self.hasClass( className );
- self[ state ? "addClass" : "removeClass" ]( className );
- }
-
- // Toggle whole class name
- } else if ( type === core_strundefined || type === "boolean" ) {
- if ( this.className ) {
- // store className if set
- jQuery._data( this, "__className__", this.className );
- }
-
- // If the element has a class name or if we're passed "false",
- // then remove the whole classname (if there was one, the above saved it).
- // Otherwise bring back whatever was previously saved (if anything),
- // falling back to the empty string if nothing was stored.
- this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
- }
- });
- },
-
- hasClass: function( selector ) {
- var className = " " + selector + " ",
- i = 0,
- l = this.length;
- for ( ; i < l; i++ ) {
- if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
- return true;
- }
- }
-
- return false;
- },
-
- val: function( value ) {
- var ret, hooks, isFunction,
- elem = this[0];
-
- if ( !arguments.length ) {
- if ( elem ) {
- hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
-
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
- return ret;
- }
-
- ret = elem.value;
-
- return typeof ret === "string" ?
- // handle most common string cases
- ret.replace(rreturn, "") :
- // handle cases where value is null/undef or number
- ret == null ? "" : ret;
- }
-
- return;
- }
-
- isFunction = jQuery.isFunction( value );
-
- return this.each(function( i ) {
- var val,
- self = jQuery(this);
-
- if ( this.nodeType !== 1 ) {
- return;
- }
-
- if ( isFunction ) {
- val = value.call( this, i, self.val() );
- } else {
- val = value;
- }
-
- // Treat null/undefined as ""; convert numbers to string
- if ( val == null ) {
- val = "";
- } else if ( typeof val === "number" ) {
- val += "";
- } else if ( jQuery.isArray( val ) ) {
- val = jQuery.map(val, function ( value ) {
- return value == null ? "" : value + "";
- });
- }
-
- hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
-
- // If set returns undefined, fall back to normal setting
- if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
- this.value = val;
- }
- });
- }
-});
-
-jQuery.extend({
- valHooks: {
- option: {
- get: function( elem ) {
- // attributes.value is undefined in Blackberry 4.7 but
- // uses .value. See #6932
- var val = elem.attributes.value;
- return !val || val.specified ? elem.value : elem.text;
- }
- },
- select: {
- get: function( elem ) {
- var value, option,
- options = elem.options,
- index = elem.selectedIndex,
- one = elem.type === "select-one" || index < 0,
- values = one ? null : [],
- max = one ? index + 1 : options.length,
- i = index < 0 ?
- max :
- one ? index : 0;
-
- // Loop through all the selected options
- for ( ; i < max; i++ ) {
- option = options[ i ];
-
- // oldIE doesn't update selected after form reset (#2551)
- if ( ( option.selected || i === index ) &&
- // Don't return options that are disabled or in a disabled optgroup
- ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
- ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
-
- // Get the specific value for the option
- value = jQuery( option ).val();
-
- // We don't need an array for one selects
- if ( one ) {
- return value;
- }
-
- // Multi-Selects return an array
- values.push( value );
- }
- }
-
- return values;
- },
-
- set: function( elem, value ) {
- var values = jQuery.makeArray( value );
-
- jQuery(elem).find("option").each(function() {
- this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
- });
-
- if ( !values.length ) {
- elem.selectedIndex = -1;
- }
- return values;
- }
- }
- },
-
- attr: function( elem, name, value ) {
- var hooks, notxml, ret,
- nType = elem.nodeType;
-
- // don't get/set attributes on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- // Fallback to prop when attributes are not supported
- if ( typeof elem.getAttribute === core_strundefined ) {
- return jQuery.prop( elem, name, value );
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- // All attributes are lowercase
- // Grab necessary hook if one is defined
- if ( notxml ) {
- name = name.toLowerCase();
- hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
- }
-
- if ( value !== undefined ) {
-
- if ( value === null ) {
- jQuery.removeAttr( elem, name );
-
- } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- elem.setAttribute( name, value + "" );
- return value;
- }
-
- } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
-
- // In IE9+, Flash objects don't have .getAttribute (#12945)
- // Support: IE9+
- if ( typeof elem.getAttribute !== core_strundefined ) {
- ret = elem.getAttribute( name );
- }
-
- // Non-existent attributes return null, we normalize to undefined
- return ret == null ?
- undefined :
- ret;
- }
- },
-
- removeAttr: function( elem, value ) {
- var name, propName,
- i = 0,
- attrNames = value && value.match( core_rnotwhite );
-
- if ( attrNames && elem.nodeType === 1 ) {
- while ( (name = attrNames[i++]) ) {
- propName = jQuery.propFix[ name ] || name;
-
- // Boolean attributes get special treatment (#10870)
- if ( rboolean.test( name ) ) {
- // Set corresponding property to false for boolean attributes
- // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8
- if ( !getSetAttribute && ruseDefault.test( name ) ) {
- elem[ jQuery.camelCase( "default-" + name ) ] =
- elem[ propName ] = false;
- } else {
- elem[ propName ] = false;
- }
-
- // See #9699 for explanation of this approach (setting first, then removal)
- } else {
- jQuery.attr( elem, name, "" );
- }
-
- elem.removeAttribute( getSetAttribute ? name : propName );
- }
- }
- },
-
- attrHooks: {
- type: {
- set: function( elem, value ) {
- if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
- // Setting the type on a radio button after the value resets the value in IE6-9
- // Reset value to default in case type is set after value during creation
- var val = elem.value;
- elem.setAttribute( "type", value );
- if ( val ) {
- elem.value = val;
- }
- return value;
- }
- }
- }
- },
-
- propFix: {
- tabindex: "tabIndex",
- readonly: "readOnly",
- "for": "htmlFor",
- "class": "className",
- maxlength: "maxLength",
- cellspacing: "cellSpacing",
- cellpadding: "cellPadding",
- rowspan: "rowSpan",
- colspan: "colSpan",
- usemap: "useMap",
- frameborder: "frameBorder",
- contenteditable: "contentEditable"
- },
-
- prop: function( elem, name, value ) {
- var ret, hooks, notxml,
- nType = elem.nodeType;
-
- // don't get/set properties on text, comment and attribute nodes
- if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
- return;
- }
-
- notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
-
- if ( notxml ) {
- // Fix name and attach hooks
- name = jQuery.propFix[ name ] || name;
- hooks = jQuery.propHooks[ name ];
- }
-
- if ( value !== undefined ) {
- if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
- return ret;
-
- } else {
- return ( elem[ name ] = value );
- }
-
- } else {
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
- return ret;
-
- } else {
- return elem[ name ];
- }
- }
- },
-
- propHooks: {
- tabIndex: {
- get: function( elem ) {
- // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
- // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
- var attributeNode = elem.getAttributeNode("tabindex");
-
- return attributeNode && attributeNode.specified ?
- parseInt( attributeNode.value, 10 ) :
- rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
- 0 :
- undefined;
- }
- }
- }
-});
-
-// Hook for boolean attributes
-boolHook = {
- get: function( elem, name ) {
- var
- // Use .prop to determine if this attribute is understood as boolean
- prop = jQuery.prop( elem, name ),
-
- // Fetch it accordingly
- attr = typeof prop === "boolean" && elem.getAttribute( name ),
- detail = typeof prop === "boolean" ?
-
- getSetInput && getSetAttribute ?
- attr != null :
- // oldIE fabricates an empty string for missing boolean attributes
- // and conflates checked/selected into attroperties
- ruseDefault.test( name ) ?
- elem[ jQuery.camelCase( "default-" + name ) ] :
- !!attr :
-
- // fetch an attribute node for properties not recognized as boolean
- elem.getAttributeNode( name );
-
- return detail && detail.value !== false ?
- name.toLowerCase() :
- undefined;
- },
- set: function( elem, value, name ) {
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
- // IE<8 needs the *property* name
- elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
-
- // Use defaultChecked and defaultSelected for oldIE
- } else {
- elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
- }
-
- return name;
- }
-};
-
-// fix oldIE value attroperty
-if ( !getSetInput || !getSetAttribute ) {
- jQuery.attrHooks.value = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return jQuery.nodeName( elem, "input" ) ?
-
- // Ignore the value *property* by using defaultValue
- elem.defaultValue :
-
- ret && ret.specified ? ret.value : undefined;
- },
- set: function( elem, value, name ) {
- if ( jQuery.nodeName( elem, "input" ) ) {
- // Does not return so that setAttribute is also used
- elem.defaultValue = value;
- } else {
- // Use nodeHook if defined (#1954); otherwise setAttribute is fine
- return nodeHook && nodeHook.set( elem, value, name );
- }
- }
- };
-}
-
-// IE6/7 do not support getting/setting some attributes with get/setAttribute
-if ( !getSetAttribute ) {
-
- // Use this for any attribute in IE6/7
- // This fixes almost every IE6/7 issue
- nodeHook = jQuery.valHooks.button = {
- get: function( elem, name ) {
- var ret = elem.getAttributeNode( name );
- return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ?
- ret.value :
- undefined;
- },
- set: function( elem, value, name ) {
- // Set the existing or create a new attribute node
- var ret = elem.getAttributeNode( name );
- if ( !ret ) {
- elem.setAttributeNode(
- (ret = elem.ownerDocument.createAttribute( name ))
- );
- }
-
- ret.value = value += "";
-
- // Break association with cloned elements by also using setAttribute (#9646)
- return name === "value" || value === elem.getAttribute( name ) ?
- value :
- undefined;
- }
- };
-
- // Set contenteditable to false on removals(#10429)
- // Setting to empty string throws an error as an invalid value
- jQuery.attrHooks.contenteditable = {
- get: nodeHook.get,
- set: function( elem, value, name ) {
- nodeHook.set( elem, value === "" ? false : value, name );
- }
- };
-
- // Set width and height to auto instead of 0 on empty string( Bug #8150 )
- // This is for removals
- jQuery.each([ "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- set: function( elem, value ) {
- if ( value === "" ) {
- elem.setAttribute( name, "auto" );
- return value;
- }
- }
- });
- });
-}
-
-
-// Some attributes require a special call on IE
-// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
-if ( !jQuery.support.hrefNormalized ) {
- jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
- jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
- get: function( elem ) {
- var ret = elem.getAttribute( name, 2 );
- return ret == null ? undefined : ret;
- }
- });
- });
-
- // href/src property should get the full normalized URL (#10299/#12915)
- jQuery.each([ "href", "src" ], function( i, name ) {
- jQuery.propHooks[ name ] = {
- get: function( elem ) {
- return elem.getAttribute( name, 4 );
- }
- };
- });
-}
-
-if ( !jQuery.support.style ) {
- jQuery.attrHooks.style = {
- get: function( elem ) {
- // Return undefined in the case of empty string
- // Note: IE uppercases css property names, but if we were to .toLowerCase()
- // .cssText, that would destroy case senstitivity in URL's, like in "background"
- return elem.style.cssText || undefined;
- },
- set: function( elem, value ) {
- return ( elem.style.cssText = value + "" );
- }
- };
-}
-
-// Safari mis-reports the default selected property of an option
-// Accessing the parent's selectedIndex property fixes it
-if ( !jQuery.support.optSelected ) {
- jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
- get: function( elem ) {
- var parent = elem.parentNode;
-
- if ( parent ) {
- parent.selectedIndex;
-
- // Make sure that it also works with optgroups, see #5701
- if ( parent.parentNode ) {
- parent.parentNode.selectedIndex;
- }
- }
- return null;
- }
- });
-}
-
-// IE6/7 call enctype encoding
-if ( !jQuery.support.enctype ) {
- jQuery.propFix.enctype = "encoding";
-}
-
-// Radios and checkboxes getter/setter
-if ( !jQuery.support.checkOn ) {
- jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = {
- get: function( elem ) {
- // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
- return elem.getAttribute("value") === null ? "on" : elem.value;
- }
- };
- });
-}
-jQuery.each([ "radio", "checkbox" ], function() {
- jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
- set: function( elem, value ) {
- if ( jQuery.isArray( value ) ) {
- return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
- }
- }
- });
-});
-var rformElems = /^(?:input|select|textarea)$/i,
- rkeyEvent = /^key/,
- rmouseEvent = /^(?:mouse|contextmenu)|click/,
- rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
-
-function returnTrue() {
- return true;
-}
-
-function returnFalse() {
- return false;
-}
-
-/*
- * Helper functions for managing events -- not part of the public interface.
- * Props to Dean Edwards' addEvent library for many of the ideas.
- */
-jQuery.event = {
-
- global: {},
-
- add: function( elem, types, handler, data, selector ) {
- var tmp, events, t, handleObjIn,
- special, eventHandle, handleObj,
- handlers, type, namespaces, origType,
- elemData = jQuery._data( elem );
-
- // Don't attach events to noData or text/comment nodes (but allow plain objects)
- if ( !elemData ) {
- return;
- }
-
- // Caller can pass in an object of custom data in lieu of the handler
- if ( handler.handler ) {
- handleObjIn = handler;
- handler = handleObjIn.handler;
- selector = handleObjIn.selector;
- }
-
- // Make sure that the handler has a unique ID, used to find/remove it later
- if ( !handler.guid ) {
- handler.guid = jQuery.guid++;
- }
-
- // Init the element's event structure and main handler, if this is the first
- if ( !(events = elemData.events) ) {
- events = elemData.events = {};
- }
- if ( !(eventHandle = elemData.handle) ) {
- eventHandle = elemData.handle = function( e ) {
- // Discard the second event of a jQuery.event.trigger() and
- // when an event is called after a page has unloaded
- return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ?
- jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
- undefined;
- };
- // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
- eventHandle.elem = elem;
- }
-
- // Handle multiple events separated by a space
- // jQuery(...).bind("mouseover mouseout", fn);
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // If event changes its type, use the special event handlers for the changed type
- special = jQuery.event.special[ type ] || {};
-
- // If selector defined, determine special event api type, otherwise given type
- type = ( selector ? special.delegateType : special.bindType ) || type;
-
- // Update special based on newly reset type
- special = jQuery.event.special[ type ] || {};
-
- // handleObj is passed to all event handlers
- handleObj = jQuery.extend({
- type: type,
- origType: origType,
- data: data,
- handler: handler,
- guid: handler.guid,
- selector: selector,
- needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
- namespace: namespaces.join(".")
- }, handleObjIn );
-
- // Init the event handler queue if we're the first
- if ( !(handlers = events[ type ]) ) {
- handlers = events[ type ] = [];
- handlers.delegateCount = 0;
-
- // Only use addEventListener/attachEvent if the special events handler returns false
- if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
- // Bind the global event handler to the element
- if ( elem.addEventListener ) {
- elem.addEventListener( type, eventHandle, false );
-
- } else if ( elem.attachEvent ) {
- elem.attachEvent( "on" + type, eventHandle );
- }
- }
- }
-
- if ( special.add ) {
- special.add.call( elem, handleObj );
-
- if ( !handleObj.handler.guid ) {
- handleObj.handler.guid = handler.guid;
- }
- }
-
- // Add to the element's handler list, delegates in front
- if ( selector ) {
- handlers.splice( handlers.delegateCount++, 0, handleObj );
- } else {
- handlers.push( handleObj );
- }
-
- // Keep track of which events have ever been used, for event optimization
- jQuery.event.global[ type ] = true;
- }
-
- // Nullify elem to prevent memory leaks in IE
- elem = null;
- },
-
- // Detach an event or set of events from an element
- remove: function( elem, types, handler, selector, mappedTypes ) {
- var j, handleObj, tmp,
- origCount, t, events,
- special, handlers, type,
- namespaces, origType,
- elemData = jQuery.hasData( elem ) && jQuery._data( elem );
-
- if ( !elemData || !(events = elemData.events) ) {
- return;
- }
-
- // Once for each type.namespace in types; type may be omitted
- types = ( types || "" ).match( core_rnotwhite ) || [""];
- t = types.length;
- while ( t-- ) {
- tmp = rtypenamespace.exec( types[t] ) || [];
- type = origType = tmp[1];
- namespaces = ( tmp[2] || "" ).split( "." ).sort();
-
- // Unbind all events (on this namespace, if provided) for the element
- if ( !type ) {
- for ( type in events ) {
- jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
- }
- continue;
- }
-
- special = jQuery.event.special[ type ] || {};
- type = ( selector ? special.delegateType : special.bindType ) || type;
- handlers = events[ type ] || [];
- tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
-
- // Remove matching events
- origCount = j = handlers.length;
- while ( j-- ) {
- handleObj = handlers[ j ];
-
- if ( ( mappedTypes || origType === handleObj.origType ) &&
- ( !handler || handler.guid === handleObj.guid ) &&
- ( !tmp || tmp.test( handleObj.namespace ) ) &&
- ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
- handlers.splice( j, 1 );
-
- if ( handleObj.selector ) {
- handlers.delegateCount--;
- }
- if ( special.remove ) {
- special.remove.call( elem, handleObj );
- }
- }
- }
-
- // Remove generic event handler if we removed something and no more handlers exist
- // (avoids potential for endless recursion during removal of special event handlers)
- if ( origCount && !handlers.length ) {
- if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
- jQuery.removeEvent( elem, type, elemData.handle );
- }
-
- delete events[ type ];
- }
- }
-
- // Remove the expando if it's no longer used
- if ( jQuery.isEmptyObject( events ) ) {
- delete elemData.handle;
-
- // removeData also checks for emptiness and clears the expando if empty
- // so use it instead of delete
- jQuery._removeData( elem, "events" );
- }
- },
-
- trigger: function( event, data, elem, onlyHandlers ) {
- var handle, ontype, cur,
- bubbleType, special, tmp, i,
- eventPath = [ elem || document ],
- type = core_hasOwn.call( event, "type" ) ? event.type : event,
- namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
-
- cur = tmp = elem = elem || document;
-
- // Don't do events on text and comment nodes
- if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
- return;
- }
-
- // focus/blur morphs to focusin/out; ensure we're not firing them right now
- if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
- return;
- }
-
- if ( type.indexOf(".") >= 0 ) {
- // Namespaced trigger; create a regexp to match event type in handle()
- namespaces = type.split(".");
- type = namespaces.shift();
- namespaces.sort();
- }
- ontype = type.indexOf(":") < 0 && "on" + type;
-
- // Caller can pass in a jQuery.Event object, Object, or just an event type string
- event = event[ jQuery.expando ] ?
- event :
- new jQuery.Event( type, typeof event === "object" && event );
-
- event.isTrigger = true;
- event.namespace = namespaces.join(".");
- event.namespace_re = event.namespace ?
- new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
- null;
-
- // Clean up the event in case it is being reused
- event.result = undefined;
- if ( !event.target ) {
- event.target = elem;
- }
-
- // Clone any incoming data and prepend the event, creating the handler arg list
- data = data == null ?
- [ event ] :
- jQuery.makeArray( data, [ event ] );
-
- // Allow special events to draw outside the lines
- special = jQuery.event.special[ type ] || {};
- if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
- return;
- }
-
- // Determine event propagation path in advance, per W3C events spec (#9951)
- // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
- if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
-
- bubbleType = special.delegateType || type;
- if ( !rfocusMorph.test( bubbleType + type ) ) {
- cur = cur.parentNode;
- }
- for ( ; cur; cur = cur.parentNode ) {
- eventPath.push( cur );
- tmp = cur;
- }
-
- // Only add window if we got to document (e.g., not plain obj or detached DOM)
- if ( tmp === (elem.ownerDocument || document) ) {
- eventPath.push( tmp.defaultView || tmp.parentWindow || window );
- }
- }
-
- // Fire handlers on the event path
- i = 0;
- while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
-
- event.type = i > 1 ?
- bubbleType :
- special.bindType || type;
-
- // jQuery handler
- handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
- if ( handle ) {
- handle.apply( cur, data );
- }
-
- // Native handler
- handle = ontype && cur[ ontype ];
- if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) {
- event.preventDefault();
- }
- }
- event.type = type;
-
- // If nobody prevented the default action, do it now
- if ( !onlyHandlers && !event.isDefaultPrevented() ) {
-
- if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
- !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
-
- // Call a native DOM method on the target with the same name name as the event.
- // Can't use an .isFunction() check here because IE6/7 fails that test.
- // Don't do default actions on window, that's where global variables be (#6170)
- if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
-
- // Don't re-trigger an onFOO event when we call its FOO() method
- tmp = elem[ ontype ];
-
- if ( tmp ) {
- elem[ ontype ] = null;
- }
-
- // Prevent re-triggering of the same event, since we already bubbled it above
- jQuery.event.triggered = type;
- try {
- elem[ type ]();
- } catch ( e ) {
- // IE<9 dies on focus/blur to hidden element (#1486,#12518)
- // only reproducible on winXP IE8 native, not IE9 in IE8 mode
- }
- jQuery.event.triggered = undefined;
-
- if ( tmp ) {
- elem[ ontype ] = tmp;
- }
- }
- }
- }
-
- return event.result;
- },
-
- dispatch: function( event ) {
-
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event );
-
- var i, ret, handleObj, matched, j,
- handlerQueue = [],
- args = core_slice.call( arguments ),
- handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
- special = jQuery.event.special[ event.type ] || {};
-
- // Use the fix-ed jQuery.Event rather than the (read-only) native event
- args[0] = event;
- event.delegateTarget = this;
-
- // Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
- return;
- }
-
- // Determine handlers
- handlerQueue = jQuery.event.handlers.call( this, event, handlers );
-
- // Run delegates first; they may want to stop propagation beneath us
- i = 0;
- while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
- event.currentTarget = matched.elem;
-
- j = 0;
- while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
-
- // Triggered event must either 1) have no namespace, or
- // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
- if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
-
- event.handleObj = handleObj;
- event.data = handleObj.data;
-
- ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
- .apply( matched.elem, args );
-
- if ( ret !== undefined ) {
- if ( (event.result = ret) === false ) {
- event.preventDefault();
- event.stopPropagation();
- }
- }
- }
- }
- }
-
- // Call the postDispatch hook for the mapped type
- if ( special.postDispatch ) {
- special.postDispatch.call( this, event );
- }
-
- return event.result;
- },
-
- handlers: function( event, handlers ) {
- var sel, handleObj, matches, i,
- handlerQueue = [],
- delegateCount = handlers.delegateCount,
- cur = event.target;
-
- // Find delegate handlers
- // Black-hole SVG <use> instance trees (#13180)
- // Avoid non-left-click bubbling in Firefox (#3861)
- if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
-
- for ( ; cur != this; cur = cur.parentNode || this ) {
-
- // Don't check non-elements (#13208)
- // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
- if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
- matches = [];
- for ( i = 0; i < delegateCount; i++ ) {
- handleObj = handlers[ i ];
-
- // Don't conflict with Object.prototype properties (#13203)
- sel = handleObj.selector + " ";
-
- if ( matches[ sel ] === undefined ) {
- matches[ sel ] = handleObj.needsContext ?
- jQuery( sel, this ).index( cur ) >= 0 :
- jQuery.find( sel, this, null, [ cur ] ).length;
- }
- if ( matches[ sel ] ) {
- matches.push( handleObj );
- }
- }
- if ( matches.length ) {
- handlerQueue.push({ elem: cur, handlers: matches });
- }
- }
- }
- }
-
- // Add the remaining (directly-bound) handlers
- if ( delegateCount < handlers.length ) {
- handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
- }
-
- return handlerQueue;
- },
-
- fix: function( event ) {
- if ( event[ jQuery.expando ] ) {
- return event;
- }
-
- // Create a writable copy of the event object and normalize some properties
- var i, prop, copy,
- type = event.type,
- originalEvent = event,
- fixHook = this.fixHooks[ type ];
-
- if ( !fixHook ) {
- this.fixHooks[ type ] = fixHook =
- rmouseEvent.test( type ) ? this.mouseHooks :
- rkeyEvent.test( type ) ? this.keyHooks :
- {};
- }
- copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
-
- event = new jQuery.Event( originalEvent );
-
- i = copy.length;
- while ( i-- ) {
- prop = copy[ i ];
- event[ prop ] = originalEvent[ prop ];
- }
-
- // Support: IE<9
- // Fix target property (#1925)
- if ( !event.target ) {
- event.target = originalEvent.srcElement || document;
- }
-
- // Support: Chrome 23+, Safari?
- // Target should not be a text node (#504, #13143)
- if ( event.target.nodeType === 3 ) {
- event.target = event.target.parentNode;
- }
-
- // Support: IE<9
- // For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
- event.metaKey = !!event.metaKey;
-
- return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
- },
-
- // Includes some event props shared by KeyEvent and MouseEvent
- props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
-
- fixHooks: {},
-
- keyHooks: {
- props: "char charCode key keyCode".split(" "),
- filter: function( event, original ) {
-
- // Add which for key events
- if ( event.which == null ) {
- event.which = original.charCode != null ? original.charCode : original.keyCode;
- }
-
- return event;
- }
- },
-
- mouseHooks: {
- props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
- filter: function( event, original ) {
- var body, eventDoc, doc,
- button = original.button,
- fromElement = original.fromElement;
-
- // Calculate pageX/Y if missing and clientX/Y available
- if ( event.pageX == null && original.clientX != null ) {
- eventDoc = event.target.ownerDocument || document;
- doc = eventDoc.documentElement;
- body = eventDoc.body;
-
- event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
- event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
- }
-
- // Add relatedTarget, if necessary
- if ( !event.relatedTarget && fromElement ) {
- event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
- }
-
- // Add which for click: 1 === left; 2 === middle; 3 === right
- // Note: button is not normalized, so don't use it
- if ( !event.which && button !== undefined ) {
- event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
- }
-
- return event;
- }
- },
-
- special: {
- load: {
- // Prevent triggered image.load events from bubbling to window.load
- noBubble: true
- },
- click: {
- // For checkbox, fire native event so checked state will be right
- trigger: function() {
- if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
- this.click();
- return false;
- }
- }
- },
- focus: {
- // Fire native event if possible so blur/focus sequence is correct
- trigger: function() {
- if ( this !== document.activeElement && this.focus ) {
- try {
- this.focus();
- return false;
- } catch ( e ) {
- // Support: IE<9
- // If we error on focus to hidden element (#1486, #12518),
- // let .trigger() run the handlers
- }
- }
- },
- delegateType: "focusin"
- },
- blur: {
- trigger: function() {
- if ( this === document.activeElement && this.blur ) {
- this.blur();
- return false;
- }
- },
- delegateType: "focusout"
- },
-
- beforeunload: {
- postDispatch: function( event ) {
-
- // Even when returnValue equals to undefined Firefox will still show alert
- if ( event.result !== undefined ) {
- event.originalEvent.returnValue = event.result;
- }
- }
- }
- },
-
- simulate: function( type, elem, event, bubble ) {
- // Piggyback on a donor event to simulate a different one.
- // Fake originalEvent to avoid donor's stopPropagation, but if the
- // simulated event prevents default then we do the same on the donor.
- var e = jQuery.extend(
- new jQuery.Event(),
- event,
- { type: type,
- isSimulated: true,
- originalEvent: {}
- }
- );
- if ( bubble ) {
- jQuery.event.trigger( e, null, elem );
- } else {
- jQuery.event.dispatch.call( elem, e );
- }
- if ( e.isDefaultPrevented() ) {
- event.preventDefault();
- }
- }
-};
-
-jQuery.removeEvent = document.removeEventListener ?
- function( elem, type, handle ) {
- if ( elem.removeEventListener ) {
- elem.removeEventListener( type, handle, false );
- }
- } :
- function( elem, type, handle ) {
- var name = "on" + type;
-
- if ( elem.detachEvent ) {
-
- // #8545, #7054, preventing memory leaks for custom events in IE6-8
- // detachEvent needed property on element, by name of that event, to properly expose it to GC
- if ( typeof elem[ name ] === core_strundefined ) {
- elem[ name ] = null;
- }
-
- elem.detachEvent( name, handle );
- }
- };
-
-jQuery.Event = function( src, props ) {
- // Allow instantiation without the 'new' keyword
- if ( !(this instanceof jQuery.Event) ) {
- return new jQuery.Event( src, props );
- }
-
- // Event object
- if ( src && src.type ) {
- this.originalEvent = src;
- this.type = src.type;
-
- // Events bubbling up the document may have been marked as prevented
- // by a handler lower down the tree; reflect the correct value.
- this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
- src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
-
- // Event type
- } else {
- this.type = src;
- }
-
- // Put explicitly provided properties onto the event object
- if ( props ) {
- jQuery.extend( this, props );
- }
-
- // Create a timestamp if incoming event doesn't have one
- this.timeStamp = src && src.timeStamp || jQuery.now();
-
- // Mark it as fixed
- this[ jQuery.expando ] = true;
-};
-
-// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
-// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
-jQuery.Event.prototype = {
- isDefaultPrevented: returnFalse,
- isPropagationStopped: returnFalse,
- isImmediatePropagationStopped: returnFalse,
-
- preventDefault: function() {
- var e = this.originalEvent;
-
- this.isDefaultPrevented = returnTrue;
- if ( !e ) {
- return;
- }
-
- // If preventDefault exists, run it on the original event
- if ( e.preventDefault ) {
- e.preventDefault();
-
- // Support: IE
- // Otherwise set the returnValue property of the original event to false
- } else {
- e.returnValue = false;
- }
- },
- stopPropagation: function() {
- var e = this.originalEvent;
-
- this.isPropagationStopped = returnTrue;
- if ( !e ) {
- return;
- }
- // If stopPropagation exists, run it on the original event
- if ( e.stopPropagation ) {
- e.stopPropagation();
- }
-
- // Support: IE
- // Set the cancelBubble property of the original event to true
- e.cancelBubble = true;
- },
- stopImmediatePropagation: function() {
- this.isImmediatePropagationStopped = returnTrue;
- this.stopPropagation();
- }
-};
-
-// Create mouseenter/leave events using mouseover/out and event-time checks
-jQuery.each({
- mouseenter: "mouseover",
- mouseleave: "mouseout"
-}, function( orig, fix ) {
- jQuery.event.special[ orig ] = {
- delegateType: fix,
- bindType: fix,
-
- handle: function( event ) {
- var ret,
- target = this,
- related = event.relatedTarget,
- handleObj = event.handleObj;
-
- // For mousenter/leave call the handler if related is outside the target.
- // NB: No relatedTarget if the mouse left/entered the browser window
- if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
- event.type = handleObj.origType;
- ret = handleObj.handler.apply( this, arguments );
- event.type = fix;
- }
- return ret;
- }
- };
-});
-
-// IE submit delegation
-if ( !jQuery.support.submitBubbles ) {
-
- jQuery.event.special.submit = {
- setup: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Lazy-add a submit handler when a descendant form may potentially be submitted
- jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
- // Node name check avoids a VML-related crash in IE (#9807)
- var elem = e.target,
- form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
- if ( form && !jQuery._data( form, "submitBubbles" ) ) {
- jQuery.event.add( form, "submit._submit", function( event ) {
- event._submit_bubble = true;
- });
- jQuery._data( form, "submitBubbles", true );
- }
- });
- // return undefined since we don't need an event listener
- },
-
- postDispatch: function( event ) {
- // If form was submitted by the user, bubble the event up the tree
- if ( event._submit_bubble ) {
- delete event._submit_bubble;
- if ( this.parentNode && !event.isTrigger ) {
- jQuery.event.simulate( "submit", this.parentNode, event, true );
- }
- }
- },
-
- teardown: function() {
- // Only need this for delegated form submit events
- if ( jQuery.nodeName( this, "form" ) ) {
- return false;
- }
-
- // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
- jQuery.event.remove( this, "._submit" );
- }
- };
-}
-
-// IE change delegation and checkbox/radio fix
-if ( !jQuery.support.changeBubbles ) {
-
- jQuery.event.special.change = {
-
- setup: function() {
-
- if ( rformElems.test( this.nodeName ) ) {
- // IE doesn't fire change on a check/radio until blur; trigger it on click
- // after a propertychange. Eat the blur-change in special.change.handle.
- // This still fires onchange a second time for check/radio after blur.
- if ( this.type === "checkbox" || this.type === "radio" ) {
- jQuery.event.add( this, "propertychange._change", function( event ) {
- if ( event.originalEvent.propertyName === "checked" ) {
- this._just_changed = true;
- }
- });
- jQuery.event.add( this, "click._change", function( event ) {
- if ( this._just_changed && !event.isTrigger ) {
- this._just_changed = false;
- }
- // Allow triggered, simulated change events (#11500)
- jQuery.event.simulate( "change", this, event, true );
- });
- }
- return false;
- }
- // Delegated event; lazy-add a change handler on descendant inputs
- jQuery.event.add( this, "beforeactivate._change", function( e ) {
- var elem = e.target;
-
- if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
- jQuery.event.add( elem, "change._change", function( event ) {
- if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
- jQuery.event.simulate( "change", this.parentNode, event, true );
- }
- });
- jQuery._data( elem, "changeBubbles", true );
- }
- });
- },
-
- handle: function( event ) {
- var elem = event.target;
-
- // Swallow native change events from checkbox/radio, we already triggered them above
- if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
- return event.handleObj.handler.apply( this, arguments );
- }
- },
-
- teardown: function() {
- jQuery.event.remove( this, "._change" );
-
- return !rformElems.test( this.nodeName );
- }
- };
-}
-
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
-}
-
-jQuery.fn.extend({
-
- on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
- var type, origFn;
-
- // Types can be a map of types/handlers
- if ( typeof types === "object" ) {
- // ( types-Object, selector, data )
- if ( typeof selector !== "string" ) {
- // ( types-Object, data )
- data = data || selector;
- selector = undefined;
- }
- for ( type in types ) {
- this.on( type, selector, data, types[ type ], one );
- }
- return this;
- }
-
- if ( data == null && fn == null ) {
- // ( types, fn )
- fn = selector;
- data = selector = undefined;
- } else if ( fn == null ) {
- if ( typeof selector === "string" ) {
- // ( types, selector, fn )
- fn = data;
- data = undefined;
- } else {
- // ( types, data, fn )
- fn = data;
- data = selector;
- selector = undefined;
- }
- }
- if ( fn === false ) {
- fn = returnFalse;
- } else if ( !fn ) {
- return this;
- }
-
- if ( one === 1 ) {
- origFn = fn;
- fn = function( event ) {
- // Can use an empty set, since event contains the info
- jQuery().off( event );
- return origFn.apply( this, arguments );
- };
- // Use same guid so caller can remove using origFn
- fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
- }
- return this.each( function() {
- jQuery.event.add( this, types, fn, data, selector );
- });
- },
- one: function( types, selector, data, fn ) {
- return this.on( types, selector, data, fn, 1 );
- },
- off: function( types, selector, fn ) {
- var handleObj, type;
- if ( types && types.preventDefault && types.handleObj ) {
- // ( event ) dispatched jQuery.Event
- handleObj = types.handleObj;
- jQuery( types.delegateTarget ).off(
- handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
- handleObj.selector,
- handleObj.handler
- );
- return this;
- }
- if ( typeof types === "object" ) {
- // ( types-object [, selector] )
- for ( type in types ) {
- this.off( type, selector, types[ type ] );
- }
- return this;
- }
- if ( selector === false || typeof selector === "function" ) {
- // ( types [, fn] )
- fn = selector;
- selector = undefined;
- }
- if ( fn === false ) {
- fn = returnFalse;
- }
- return this.each(function() {
- jQuery.event.remove( this, types, fn, selector );
- });
- },
-
- bind: function( types, data, fn ) {
- return this.on( types, null, data, fn );
- },
- unbind: function( types, fn ) {
- return this.off( types, null, fn );
- },
-
- delegate: function( selector, types, data, fn ) {
- return this.on( types, selector, data, fn );
- },
- undelegate: function( selector, types, fn ) {
- // ( namespace ) or ( selector, types [, fn] )
- return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
- },
-
- trigger: function( type, data ) {
- return this.each(function() {
- jQuery.event.trigger( type, data, this );
- });
- },
- triggerHandler: function( type, data ) {
- var elem = this[0];
- if ( elem ) {
- return jQuery.event.trigger( type, data, elem, true );
- }
- }
-});
-/*!
- * Sizzle CSS Selector Engine
- * Copyright 2012 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://sizzlejs.com/
- */
-(function( window, undefined ) {
-
-var i,
- cachedruns,
- Expr,
- getText,
- isXML,
- compile,
- hasDuplicate,
- outermostContext,
-
- // Local document vars
- setDocument,
- document,
- docElem,
- documentIsXML,
- rbuggyQSA,
- rbuggyMatches,
- matches,
- contains,
- sortOrder,
-
- // Instance-specific data
- expando = "sizzle" + -(new Date()),
- preferredDoc = window.document,
- support = {},
- dirruns = 0,
- done = 0,
- classCache = createCache(),
- tokenCache = createCache(),
- compilerCache = createCache(),
-
- // General-purpose constants
- strundefined = typeof undefined,
- MAX_NEGATIVE = 1 << 31,
-
- // Array methods
- arr = [],
- pop = arr.pop,
- push = arr.push,
- slice = arr.slice,
- // Use a stripped-down indexOf if we can't use a native one
- indexOf = arr.indexOf || function( elem ) {
- var i = 0,
- len = this.length;
- for ( ; i < len; i++ ) {
- if ( this[i] === elem ) {
- return i;
- }
- }
- return -1;
- },
-
-
- // Regular expressions
-
- // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
- whitespace = "[\\x20\\t\\r\\n\\f]",
- // http://www.w3.org/TR/css3-syntax/#characters
- characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
-
- // Loosely modeled on CSS identifier characters
- // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
- // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
- identifier = characterEncoding.replace( "w", "w#" ),
-
- // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors
- operators = "([*^$|!~]?=)",
- attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
- "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
-
- // Prefer arguments quoted,
- // then not containing pseudos/brackets,
- // then attribute selectors/non-parenthetical expressions,
- // then anything else
- // These preferences are here to reduce the number of selectors
- // needing tokenize in the PSEUDO preFilter
- pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
-
- // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
- rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
-
- rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
- rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ),
- rpseudo = new RegExp( pseudos ),
- ridentifier = new RegExp( "^" + identifier + "$" ),
-
- matchExpr = {
- "ID": new RegExp( "^#(" + characterEncoding + ")" ),
- "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
- "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ),
- "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
- "ATTR": new RegExp( "^" + attributes ),
- "PSEUDO": new RegExp( "^" + pseudos ),
- "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
- "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
- "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
- // For use in libraries implementing .is()
- // We use this for POS matching in `select`
- "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
- whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
- },
-
- rsibling = /[\x20\t\r\n\f]*[+~]/,
-
- rnative = /^[^{]+\{\s*\[native code/,
-
- // Easily-parseable/retrievable ID or TAG or CLASS selectors
- rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
-
- rinputs = /^(?:input|select|textarea|button)$/i,
- rheader = /^h\d$/i,
-
- rescape = /'|\\/g,
- rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,
-
- // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
- runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,
- funescape = function( _, escaped ) {
- var high = "0x" + escaped - 0x10000;
- // NaN means non-codepoint
- return high !== high ?
- escaped :
- // BMP codepoint
- high < 0 ?
- String.fromCharCode( high + 0x10000 ) :
- // Supplemental Plane codepoint (surrogate pair)
- String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
- };
-
-// Use a stripped-down slice if we can't use a native one
-try {
- slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType;
-} catch ( e ) {
- slice = function( i ) {
- var elem,
- results = [];
- while ( (elem = this[i++]) ) {
- results.push( elem );
- }
- return results;
- };
-}
-
-/**
- * For feature detection
- * @param {Function} fn The function to test for native support
- */
-function isNative( fn ) {
- return rnative.test( fn + "" );
-}
-
-/**
- * Create key-value caches of limited size
- * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
- * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
- * deleting the oldest entry
- */
-function createCache() {
- var cache,
- keys = [];
-
- return (cache = function( key, value ) {
- // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
- if ( keys.push( key += " " ) > Expr.cacheLength ) {
- // Only keep the most recent entries
- delete cache[ keys.shift() ];
- }
- return (cache[ key ] = value);
- });
-}
-
-/**
- * Mark a function for special use by Sizzle
- * @param {Function} fn The function to mark
- */
-function markFunction( fn ) {
- fn[ expando ] = true;
- return fn;
-}
-
-/**
- * Support testing using an element
- * @param {Function} fn Passed the created div and expects a boolean result
- */
-function assert( fn ) {
- var div = document.createElement("div");
-
- try {
- return fn( div );
- } catch (e) {
- return false;
- } finally {
- // release memory in IE
- div = null;
- }
-}
-
-function Sizzle( selector, context, results, seed ) {
- var match, elem, m, nodeType,
- // QSA vars
- i, groups, old, nid, newContext, newSelector;
-
- if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
- setDocument( context );
- }
-
- context = context || document;
- results = results || [];
-
- if ( !selector || typeof selector !== "string" ) {
- return results;
- }
-
- if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
- return [];
- }
-
- if ( !documentIsXML && !seed ) {
-
- // Shortcuts
- if ( (match = rquickExpr.exec( selector )) ) {
- // Speed-up: Sizzle("#ID")
- if ( (m = match[1]) ) {
- if ( nodeType === 9 ) {
- elem = context.getElementById( m );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- if ( elem && elem.parentNode ) {
- // Handle the case where IE, Opera, and Webkit return items
- // by name instead of ID
- if ( elem.id === m ) {
- results.push( elem );
- return results;
- }
- } else {
- return results;
- }
- } else {
- // Context is not a document
- if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
- contains( context, elem ) && elem.id === m ) {
- results.push( elem );
- return results;
- }
- }
-
- // Speed-up: Sizzle("TAG")
- } else if ( match[2] ) {
- push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) );
- return results;
-
- // Speed-up: Sizzle(".CLASS")
- } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) {
- push.apply( results, slice.call(context.getElementsByClassName( m ), 0) );
- return results;
- }
- }
-
- // QSA path
- if ( support.qsa && !rbuggyQSA.test(selector) ) {
- old = true;
- nid = expando;
- newContext = context;
- newSelector = nodeType === 9 && selector;
-
- // qSA works strangely on Element-rooted queries
- // We can work around this by specifying an extra ID on the root
- // and working up from there (Thanks to Andrew Dupont for the technique)
- // IE 8 doesn't work on object elements
- if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
- groups = tokenize( selector );
-
- if ( (old = context.getAttribute("id")) ) {
- nid = old.replace( rescape, "\\$&" );
- } else {
- context.setAttribute( "id", nid );
- }
- nid = "[id='" + nid + "'] ";
-
- i = groups.length;
- while ( i-- ) {
- groups[i] = nid + toSelector( groups[i] );
- }
- newContext = rsibling.test( selector ) && context.parentNode || context;
- newSelector = groups.join(",");
- }
-
- if ( newSelector ) {
- try {
- push.apply( results, slice.call( newContext.querySelectorAll(
- newSelector
- ), 0 ) );
- return results;
- } catch(qsaError) {
- } finally {
- if ( !old ) {
- context.removeAttribute("id");
- }
- }
- }
- }
- }
-
- // All others
- return select( selector.replace( rtrim, "$1" ), context, results, seed );
-}
-
-/**
- * Detect xml
- * @param {Element|Object} elem An element or a document
- */
-isXML = Sizzle.isXML = function( elem ) {
- // documentElement is verified for cases where it doesn't yet exist
- // (such as loading iframes in IE - #4833)
- var documentElement = elem && (elem.ownerDocument || elem).documentElement;
- return documentElement ? documentElement.nodeName !== "HTML" : false;
-};
-
-/**
- * Sets document-related variables once based on the current document
- * @param {Element|Object} [doc] An element or document object to use to set the document
- * @returns {Object} Returns the current document
- */
-setDocument = Sizzle.setDocument = function( node ) {
- var doc = node ? node.ownerDocument || node : preferredDoc;
-
- // If no document and documentElement is available, return
- if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
- return document;
- }
-
- // Set our document
- document = doc;
- docElem = doc.documentElement;
-
- // Support tests
- documentIsXML = isXML( doc );
-
- // Check if getElementsByTagName("*") returns only elements
- support.tagNameNoComments = assert(function( div ) {
- div.appendChild( doc.createComment("") );
- return !div.getElementsByTagName("*").length;
- });
-
- // Check if attributes should be retrieved by attribute nodes
- support.attributes = assert(function( div ) {
- div.innerHTML = "<select></select>";
- var type = typeof div.lastChild.getAttribute("multiple");
- // IE8 returns a string for some attributes even when not present
- return type !== "boolean" && type !== "string";
- });
-
- // Check if getElementsByClassName can be trusted
- support.getByClassName = assert(function( div ) {
- // Opera can't find a second classname (in 9.6)
- div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>";
- if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) {
- return false;
- }
-
- // Safari 3.2 caches class attributes and doesn't catch changes
- div.lastChild.className = "e";
- return div.getElementsByClassName("e").length === 2;
- });
-
- // Check if getElementById returns elements by name
- // Check if getElementsByName privileges form controls or returns elements by ID
- support.getByName = assert(function( div ) {
- // Inject content
- div.id = expando + 0;
- div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>";
- docElem.insertBefore( div, docElem.firstChild );
-
- // Test
- var pass = doc.getElementsByName &&
- // buggy browsers will return fewer than the correct 2
- doc.getElementsByName( expando ).length === 2 +
- // buggy browsers will return more than the correct 0
- doc.getElementsByName( expando + 0 ).length;
- support.getIdNotName = !doc.getElementById( expando );
-
- // Cleanup
- docElem.removeChild( div );
-
- return pass;
- });
-
- // IE6/7 return modified attributes
- Expr.attrHandle = assert(function( div ) {
- div.innerHTML = "<a href='#'></a>";
- return div.firstChild && typeof div.firstChild.getAttribute !== strundefined &&
- div.firstChild.getAttribute("href") === "#";
- }) ?
- {} :
- {
- "href": function( elem ) {
- return elem.getAttribute( "href", 2 );
- },
- "type": function( elem ) {
- return elem.getAttribute("type");
- }
- };
-
- // ID find and filter
- if ( support.getIdNotName ) {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- var m = context.getElementById( id );
- // Check parentNode to catch when Blackberry 4.6 returns
- // nodes that are no longer in the document #6963
- return m && m.parentNode ? [m] : [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- return elem.getAttribute("id") === attrId;
- };
- };
- } else {
- Expr.find["ID"] = function( id, context ) {
- if ( typeof context.getElementById !== strundefined && !documentIsXML ) {
- var m = context.getElementById( id );
-
- return m ?
- m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ?
- [m] :
- undefined :
- [];
- }
- };
- Expr.filter["ID"] = function( id ) {
- var attrId = id.replace( runescape, funescape );
- return function( elem ) {
- var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
- return node && node.value === attrId;
- };
- };
- }
-
- // Tag
- Expr.find["TAG"] = support.tagNameNoComments ?
- function( tag, context ) {
- if ( typeof context.getElementsByTagName !== strundefined ) {
- return context.getElementsByTagName( tag );
- }
- } :
- function( tag, context ) {
- var elem,
- tmp = [],
- i = 0,
- results = context.getElementsByTagName( tag );
-
- // Filter out possible comments
- if ( tag === "*" ) {
- while ( (elem = results[i++]) ) {
- if ( elem.nodeType === 1 ) {
- tmp.push( elem );
- }
- }
-
- return tmp;
- }
- return results;
- };
-
- // Name
- Expr.find["NAME"] = support.getByName && function( tag, context ) {
- if ( typeof context.getElementsByName !== strundefined ) {
- return context.getElementsByName( name );
- }
- };
-
- // Class
- Expr.find["CLASS"] = support.getByClassName && function( className, context ) {
- if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) {
- return context.getElementsByClassName( className );
- }
- };
-
- // QSA and matchesSelector support
-
- // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
- rbuggyMatches = [];
-
- // qSa(:focus) reports false when true (Chrome 21),
- // no need to also add to buggyMatches since matches checks buggyQSA
- // A support test would require too much code (would include document ready)
- rbuggyQSA = [ ":focus" ];
-
- if ( (support.qsa = isNative(doc.querySelectorAll)) ) {
- // Build QSA regex
- // Regex strategy adopted from Diego Perini
- assert(function( div ) {
- // Select is set to empty string on purpose
- // This is to test IE's treatment of not explictly
- // setting a boolean content attribute,
- // since its presence should be enough
- // http://bugs.jquery.com/ticket/12359
- div.innerHTML = "<select><option selected=''></option></select>";
-
- // IE8 - Some boolean attributes are not treated correctly
- if ( !div.querySelectorAll("[selected]").length ) {
- rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" );
- }
-
- // Webkit/Opera - :checked should return selected option elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":checked").length ) {
- rbuggyQSA.push(":checked");
- }
- });
-
- assert(function( div ) {
-
- // Opera 10-12/IE8 - ^= $= *= and empty values
- // Should not select anything
- div.innerHTML = "<input type='hidden' i=''/>";
- if ( div.querySelectorAll("[i^='']").length ) {
- rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" );
- }
-
- // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
- // IE8 throws error here and will not see later tests
- if ( !div.querySelectorAll(":enabled").length ) {
- rbuggyQSA.push( ":enabled", ":disabled" );
- }
-
- // Opera 10-11 does not throw on post-comma invalid pseudos
- div.querySelectorAll("*,:x");
- rbuggyQSA.push(",.*:");
- });
- }
-
- if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector ||
- docElem.mozMatchesSelector ||
- docElem.webkitMatchesSelector ||
- docElem.oMatchesSelector ||
- docElem.msMatchesSelector) )) ) {
-
- assert(function( div ) {
- // Check to see if it's possible to do matchesSelector
- // on a disconnected node (IE 9)
- support.disconnectedMatch = matches.call( div, "div" );
-
- // This should fail with an exception
- // Gecko does not error, returns false instead
- matches.call( div, "[s!='']:x" );
- rbuggyMatches.push( "!=", pseudos );
- });
- }
-
- rbuggyQSA = new RegExp( rbuggyQSA.join("|") );
- rbuggyMatches = new RegExp( rbuggyMatches.join("|") );
-
- // Element contains another
- // Purposefully does not implement inclusive descendent
- // As in, an element does not contain itself
- contains = isNative(docElem.contains) || docElem.compareDocumentPosition ?
- function( a, b ) {
- var adown = a.nodeType === 9 ? a.documentElement : a,
- bup = b && b.parentNode;
- return a === bup || !!( bup && bup.nodeType === 1 && (
- adown.contains ?
- adown.contains( bup ) :
- a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
- ));
- } :
- function( a, b ) {
- if ( b ) {
- while ( (b = b.parentNode) ) {
- if ( b === a ) {
- return true;
- }
- }
- }
- return false;
- };
-
- // Document order sorting
- sortOrder = docElem.compareDocumentPosition ?
- function( a, b ) {
- var compare;
-
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
- }
-
- if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) {
- if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) {
- if ( a === doc || contains( preferredDoc, a ) ) {
- return -1;
- }
- if ( b === doc || contains( preferredDoc, b ) ) {
- return 1;
- }
- return 0;
- }
- return compare & 4 ? -1 : 1;
- }
-
- return a.compareDocumentPosition ? -1 : 1;
- } :
- function( a, b ) {
- var cur,
- i = 0,
- aup = a.parentNode,
- bup = b.parentNode,
- ap = [ a ],
- bp = [ b ];
-
- // Exit early if the nodes are identical
- if ( a === b ) {
- hasDuplicate = true;
- return 0;
-
- // Parentless nodes are either documents or disconnected
- } else if ( !aup || !bup ) {
- return a === doc ? -1 :
- b === doc ? 1 :
- aup ? -1 :
- bup ? 1 :
- 0;
-
- // If the nodes are siblings, we can do a quick check
- } else if ( aup === bup ) {
- return siblingCheck( a, b );
- }
-
- // Otherwise we need full lists of their ancestors for comparison
- cur = a;
- while ( (cur = cur.parentNode) ) {
- ap.unshift( cur );
- }
- cur = b;
- while ( (cur = cur.parentNode) ) {
- bp.unshift( cur );
- }
-
- // Walk down the tree looking for a discrepancy
- while ( ap[i] === bp[i] ) {
- i++;
- }
-
- return i ?
- // Do a sibling check if the nodes have a common ancestor
- siblingCheck( ap[i], bp[i] ) :
-
- // Otherwise nodes in our document sort first
- ap[i] === preferredDoc ? -1 :
- bp[i] === preferredDoc ? 1 :
- 0;
- };
-
- // Always assume the presence of duplicates if sort doesn't
- // pass them to our comparison function (as in Google Chrome).
- hasDuplicate = false;
- [0, 0].sort( sortOrder );
- support.detectDuplicates = hasDuplicate;
-
- return document;
-};
-
-Sizzle.matches = function( expr, elements ) {
- return Sizzle( expr, null, null, elements );
-};
-
-Sizzle.matchesSelector = function( elem, expr ) {
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- // Make sure that attribute selectors are quoted
- expr = expr.replace( rattributeQuotes, "='$1']" );
-
- // rbuggyQSA always contains :focus, so no need for an existence check
- if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) {
- try {
- var ret = matches.call( elem, expr );
-
- // IE 9's matchesSelector returns false on disconnected nodes
- if ( ret || support.disconnectedMatch ||
- // As well, disconnected nodes are said to be in a document
- // fragment in IE 9
- elem.document && elem.document.nodeType !== 11 ) {
- return ret;
- }
- } catch(e) {}
- }
-
- return Sizzle( expr, document, null, [elem] ).length > 0;
-};
-
-Sizzle.contains = function( context, elem ) {
- // Set document vars if needed
- if ( ( context.ownerDocument || context ) !== document ) {
- setDocument( context );
- }
- return contains( context, elem );
-};
-
-Sizzle.attr = function( elem, name ) {
- var val;
-
- // Set document vars if needed
- if ( ( elem.ownerDocument || elem ) !== document ) {
- setDocument( elem );
- }
-
- if ( !documentIsXML ) {
- name = name.toLowerCase();
- }
- if ( (val = Expr.attrHandle[ name ]) ) {
- return val( elem );
- }
- if ( documentIsXML || support.attributes ) {
- return elem.getAttribute( name );
- }
- return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ?
- name :
- val && val.specified ? val.value : null;
-};
-
-Sizzle.error = function( msg ) {
- throw new Error( "Syntax error, unrecognized expression: " + msg );
-};
-
-// Document sorting and removing duplicates
-Sizzle.uniqueSort = function( results ) {
- var elem,
- duplicates = [],
- i = 1,
- j = 0;
-
- // Unless we *know* we can detect duplicates, assume their presence
- hasDuplicate = !support.detectDuplicates;
- results.sort( sortOrder );
-
- if ( hasDuplicate ) {
- for ( ; (elem = results[i]); i++ ) {
- if ( elem === results[ i - 1 ] ) {
- j = duplicates.push( i );
- }
- }
- while ( j-- ) {
- results.splice( duplicates[ j ], 1 );
- }
- }
-
- return results;
-};
-
-function siblingCheck( a, b ) {
- var cur = b && a,
- diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE );
-
- // Use IE sourceIndex if available on both nodes
- if ( diff ) {
- return diff;
- }
-
- // Check if b follows a
- if ( cur ) {
- while ( (cur = cur.nextSibling) ) {
- if ( cur === b ) {
- return -1;
- }
- }
- }
-
- return a ? 1 : -1;
-}
-
-// Returns a function to use in pseudos for input types
-function createInputPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === type;
- };
-}
-
-// Returns a function to use in pseudos for buttons
-function createButtonPseudo( type ) {
- return function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return (name === "input" || name === "button") && elem.type === type;
- };
-}
-
-// Returns a function to use in pseudos for positionals
-function createPositionalPseudo( fn ) {
- return markFunction(function( argument ) {
- argument = +argument;
- return markFunction(function( seed, matches ) {
- var j,
- matchIndexes = fn( [], seed.length, argument ),
- i = matchIndexes.length;
-
- // Match elements found at the specified indexes
- while ( i-- ) {
- if ( seed[ (j = matchIndexes[i]) ] ) {
- seed[j] = !(matches[j] = seed[j]);
- }
- }
- });
- });
-}
-
-/**
- * Utility function for retrieving the text value of an array of DOM nodes
- * @param {Array|Element} elem
- */
-getText = Sizzle.getText = function( elem ) {
- var node,
- ret = "",
- i = 0,
- nodeType = elem.nodeType;
-
- if ( !nodeType ) {
- // If no nodeType, this is expected to be an array
- for ( ; (node = elem[i]); i++ ) {
- // Do not traverse comment nodes
- ret += getText( node );
- }
- } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
- // Use textContent for elements
- // innerText usage removed for consistency of new lines (see #11153)
- if ( typeof elem.textContent === "string" ) {
- return elem.textContent;
- } else {
- // Traverse its children
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- ret += getText( elem );
- }
- }
- } else if ( nodeType === 3 || nodeType === 4 ) {
- return elem.nodeValue;
- }
- // Do not include comment or processing instruction nodes
-
- return ret;
-};
-
-Expr = Sizzle.selectors = {
-
- // Can be adjusted by the user
- cacheLength: 50,
-
- createPseudo: markFunction,
-
- match: matchExpr,
-
- find: {},
-
- relative: {
- ">": { dir: "parentNode", first: true },
- " ": { dir: "parentNode" },
- "+": { dir: "previousSibling", first: true },
- "~": { dir: "previousSibling" }
- },
-
- preFilter: {
- "ATTR": function( match ) {
- match[1] = match[1].replace( runescape, funescape );
-
- // Move the given value to match[3] whether quoted or unquoted
- match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
-
- if ( match[2] === "~=" ) {
- match[3] = " " + match[3] + " ";
- }
-
- return match.slice( 0, 4 );
- },
-
- "CHILD": function( match ) {
- /* matches from matchExpr["CHILD"]
- 1 type (only|nth|...)
- 2 what (child|of-type)
- 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
- 4 xn-component of xn+y argument ([+-]?\d*n|)
- 5 sign of xn-component
- 6 x of xn-component
- 7 sign of y-component
- 8 y of y-component
- */
- match[1] = match[1].toLowerCase();
-
- if ( match[1].slice( 0, 3 ) === "nth" ) {
- // nth-* requires argument
- if ( !match[3] ) {
- Sizzle.error( match[0] );
- }
-
- // numeric x and y parameters for Expr.filter.CHILD
- // remember that false/true cast respectively to 0/1
- match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
- match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
-
- // other types prohibit arguments
- } else if ( match[3] ) {
- Sizzle.error( match[0] );
- }
-
- return match;
- },
-
- "PSEUDO": function( match ) {
- var excess,
- unquoted = !match[5] && match[2];
-
- if ( matchExpr["CHILD"].test( match[0] ) ) {
- return null;
- }
-
- // Accept quoted arguments as-is
- if ( match[4] ) {
- match[2] = match[4];
-
- // Strip excess characters from unquoted arguments
- } else if ( unquoted && rpseudo.test( unquoted ) &&
- // Get excess from tokenize (recursively)
- (excess = tokenize( unquoted, true )) &&
- // advance to the next closing parenthesis
- (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
-
- // excess is a negative index
- match[0] = match[0].slice( 0, excess );
- match[2] = unquoted.slice( 0, excess );
- }
-
- // Return only captures needed by the pseudo filter method (type and argument)
- return match.slice( 0, 3 );
- }
- },
-
- filter: {
-
- "TAG": function( nodeName ) {
- if ( nodeName === "*" ) {
- return function() { return true; };
- }
-
- nodeName = nodeName.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
- };
- },
-
- "CLASS": function( className ) {
- var pattern = classCache[ className + " " ];
-
- return pattern ||
- (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
- classCache( className, function( elem ) {
- return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" );
- });
- },
-
- "ATTR": function( name, operator, check ) {
- return function( elem ) {
- var result = Sizzle.attr( elem, name );
-
- if ( result == null ) {
- return operator === "!=";
- }
- if ( !operator ) {
- return true;
- }
-
- result += "";
-
- return operator === "=" ? result === check :
- operator === "!=" ? result !== check :
- operator === "^=" ? check && result.indexOf( check ) === 0 :
- operator === "*=" ? check && result.indexOf( check ) > -1 :
- operator === "$=" ? check && result.slice( -check.length ) === check :
- operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
- operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
- false;
- };
- },
-
- "CHILD": function( type, what, argument, first, last ) {
- var simple = type.slice( 0, 3 ) !== "nth",
- forward = type.slice( -4 ) !== "last",
- ofType = what === "of-type";
-
- return first === 1 && last === 0 ?
-
- // Shortcut for :nth-*(n)
- function( elem ) {
- return !!elem.parentNode;
- } :
-
- function( elem, context, xml ) {
- var cache, outerCache, node, diff, nodeIndex, start,
- dir = simple !== forward ? "nextSibling" : "previousSibling",
- parent = elem.parentNode,
- name = ofType && elem.nodeName.toLowerCase(),
- useCache = !xml && !ofType;
-
- if ( parent ) {
-
- // :(first|last|only)-(child|of-type)
- if ( simple ) {
- while ( dir ) {
- node = elem;
- while ( (node = node[ dir ]) ) {
- if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
- return false;
- }
- }
- // Reverse direction for :only-* (if we haven't yet done so)
- start = dir = type === "only" && !start && "nextSibling";
- }
- return true;
- }
-
- start = [ forward ? parent.firstChild : parent.lastChild ];
-
- // non-xml :nth-child(...) stores cache data on `parent`
- if ( forward && useCache ) {
- // Seek `elem` from a previously-cached index
- outerCache = parent[ expando ] || (parent[ expando ] = {});
- cache = outerCache[ type ] || [];
- nodeIndex = cache[0] === dirruns && cache[1];
- diff = cache[0] === dirruns && cache[2];
- node = nodeIndex && parent.childNodes[ nodeIndex ];
-
- while ( (node = ++nodeIndex && node && node[ dir ] ||
-
- // Fallback to seeking `elem` from the start
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- // When found, cache indexes on `parent` and break
- if ( node.nodeType === 1 && ++diff && node === elem ) {
- outerCache[ type ] = [ dirruns, nodeIndex, diff ];
- break;
- }
- }
-
- // Use previously-cached element index if available
- } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
- diff = cache[1];
-
- // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
- } else {
- // Use the same loop as above to seek `elem` from the start
- while ( (node = ++nodeIndex && node && node[ dir ] ||
- (diff = nodeIndex = 0) || start.pop()) ) {
-
- if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
- // Cache the index of each encountered element
- if ( useCache ) {
- (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
- }
-
- if ( node === elem ) {
- break;
- }
- }
- }
- }
-
- // Incorporate the offset, then check against cycle size
- diff -= last;
- return diff === first || ( diff % first === 0 && diff / first >= 0 );
- }
- };
- },
-
- "PSEUDO": function( pseudo, argument ) {
- // pseudo-class names are case-insensitive
- // http://www.w3.org/TR/selectors/#pseudo-classes
- // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
- // Remember that setFilters inherits from pseudos
- var args,
- fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
- Sizzle.error( "unsupported pseudo: " + pseudo );
-
- // The user may use createPseudo to indicate that
- // arguments are needed to create the filter function
- // just as Sizzle does
- if ( fn[ expando ] ) {
- return fn( argument );
- }
-
- // But maintain support for old signatures
- if ( fn.length > 1 ) {
- args = [ pseudo, pseudo, "", argument ];
- return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
- markFunction(function( seed, matches ) {
- var idx,
- matched = fn( seed, argument ),
- i = matched.length;
- while ( i-- ) {
- idx = indexOf.call( seed, matched[i] );
- seed[ idx ] = !( matches[ idx ] = matched[i] );
- }
- }) :
- function( elem ) {
- return fn( elem, 0, args );
- };
- }
-
- return fn;
- }
- },
-
- pseudos: {
- // Potentially complex pseudos
- "not": markFunction(function( selector ) {
- // Trim the selector passed to compile
- // to avoid treating leading and trailing
- // spaces as combinators
- var input = [],
- results = [],
- matcher = compile( selector.replace( rtrim, "$1" ) );
-
- return matcher[ expando ] ?
- markFunction(function( seed, matches, context, xml ) {
- var elem,
- unmatched = matcher( seed, null, xml, [] ),
- i = seed.length;
-
- // Match elements unmatched by `matcher`
- while ( i-- ) {
- if ( (elem = unmatched[i]) ) {
- seed[i] = !(matches[i] = elem);
- }
- }
- }) :
- function( elem, context, xml ) {
- input[0] = elem;
- matcher( input, null, xml, results );
- return !results.pop();
- };
- }),
-
- "has": markFunction(function( selector ) {
- return function( elem ) {
- return Sizzle( selector, elem ).length > 0;
- };
- }),
-
- "contains": markFunction(function( text ) {
- return function( elem ) {
- return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
- };
- }),
-
- // "Whether an element is represented by a :lang() selector
- // is based solely on the element's language value
- // being equal to the identifier C,
- // or beginning with the identifier C immediately followed by "-".
- // The matching of C against the element's language value is performed case-insensitively.
- // The identifier C does not have to be a valid language name."
- // http://www.w3.org/TR/selectors/#lang-pseudo
- "lang": markFunction( function( lang ) {
- // lang value must be a valid identifider
- if ( !ridentifier.test(lang || "") ) {
- Sizzle.error( "unsupported lang: " + lang );
- }
- lang = lang.replace( runescape, funescape ).toLowerCase();
- return function( elem ) {
- var elemLang;
- do {
- if ( (elemLang = documentIsXML ?
- elem.getAttribute("xml:lang") || elem.getAttribute("lang") :
- elem.lang) ) {
-
- elemLang = elemLang.toLowerCase();
- return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
- }
- } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
- return false;
- };
- }),
-
- // Miscellaneous
- "target": function( elem ) {
- var hash = window.location && window.location.hash;
- return hash && hash.slice( 1 ) === elem.id;
- },
-
- "root": function( elem ) {
- return elem === docElem;
- },
-
- "focus": function( elem ) {
- return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
- },
-
- // Boolean properties
- "enabled": function( elem ) {
- return elem.disabled === false;
- },
-
- "disabled": function( elem ) {
- return elem.disabled === true;
- },
-
- "checked": function( elem ) {
- // In CSS3, :checked should return both checked and selected elements
- // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
- var nodeName = elem.nodeName.toLowerCase();
- return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
- },
-
- "selected": function( elem ) {
- // Accessing this property makes selected-by-default
- // options in Safari work properly
- if ( elem.parentNode ) {
- elem.parentNode.selectedIndex;
- }
-
- return elem.selected === true;
- },
-
- // Contents
- "empty": function( elem ) {
- // http://www.w3.org/TR/selectors/#empty-pseudo
- // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)),
- // not comment, processing instructions, or others
- // Thanks to Diego Perini for the nodeName shortcut
- // Greater than "@" means alpha characters (specifically not starting with "#" or "?")
- for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
- if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) {
- return false;
- }
- }
- return true;
- },
-
- "parent": function( elem ) {
- return !Expr.pseudos["empty"]( elem );
- },
-
- // Element/input types
- "header": function( elem ) {
- return rheader.test( elem.nodeName );
- },
-
- "input": function( elem ) {
- return rinputs.test( elem.nodeName );
- },
-
- "button": function( elem ) {
- var name = elem.nodeName.toLowerCase();
- return name === "input" && elem.type === "button" || name === "button";
- },
-
- "text": function( elem ) {
- var attr;
- // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
- // use getAttribute instead to test this case
- return elem.nodeName.toLowerCase() === "input" &&
- elem.type === "text" &&
- ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type );
- },
-
- // Position-in-collection
- "first": createPositionalPseudo(function() {
- return [ 0 ];
- }),
-
- "last": createPositionalPseudo(function( matchIndexes, length ) {
- return [ length - 1 ];
- }),
-
- "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
- return [ argument < 0 ? argument + length : argument ];
- }),
-
- "even": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 0;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "odd": createPositionalPseudo(function( matchIndexes, length ) {
- var i = 1;
- for ( ; i < length; i += 2 ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; --i >= 0; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- }),
-
- "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
- var i = argument < 0 ? argument + length : argument;
- for ( ; ++i < length; ) {
- matchIndexes.push( i );
- }
- return matchIndexes;
- })
- }
-};
-
-// Add button/input type pseudos
-for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
- Expr.pseudos[ i ] = createInputPseudo( i );
-}
-for ( i in { submit: true, reset: true } ) {
- Expr.pseudos[ i ] = createButtonPseudo( i );
-}
-
-function tokenize( selector, parseOnly ) {
- var matched, match, tokens, type,
- soFar, groups, preFilters,
- cached = tokenCache[ selector + " " ];
-
- if ( cached ) {
- return parseOnly ? 0 : cached.slice( 0 );
- }
-
- soFar = selector;
- groups = [];
- preFilters = Expr.preFilter;
-
- while ( soFar ) {
-
- // Comma and first run
- if ( !matched || (match = rcomma.exec( soFar )) ) {
- if ( match ) {
- // Don't consume trailing commas as valid
- soFar = soFar.slice( match[0].length ) || soFar;
- }
- groups.push( tokens = [] );
- }
-
- matched = false;
-
- // Combinators
- if ( (match = rcombinators.exec( soFar )) ) {
- matched = match.shift();
- tokens.push( {
- value: matched,
- // Cast descendant combinators to space
- type: match[0].replace( rtrim, " " )
- } );
- soFar = soFar.slice( matched.length );
- }
-
- // Filters
- for ( type in Expr.filter ) {
- if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
- (match = preFilters[ type ]( match ))) ) {
- matched = match.shift();
- tokens.push( {
- value: matched,
- type: type,
- matches: match
- } );
- soFar = soFar.slice( matched.length );
- }
- }
-
- if ( !matched ) {
- break;
- }
- }
-
- // Return the length of the invalid excess
- // if we're just parsing
- // Otherwise, throw an error or return tokens
- return parseOnly ?
- soFar.length :
- soFar ?
- Sizzle.error( selector ) :
- // Cache the tokens
- tokenCache( selector, groups ).slice( 0 );
-}
-
-function toSelector( tokens ) {
- var i = 0,
- len = tokens.length,
- selector = "";
- for ( ; i < len; i++ ) {
- selector += tokens[i].value;
- }
- return selector;
-}
-
-function addCombinator( matcher, combinator, base ) {
- var dir = combinator.dir,
- checkNonElements = base && dir === "parentNode",
- doneName = done++;
-
- return combinator.first ?
- // Check against closest ancestor/preceding element
- function( elem, context, xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- return matcher( elem, context, xml );
- }
- }
- } :
-
- // Check against all ancestor/preceding elements
- function( elem, context, xml ) {
- var data, cache, outerCache,
- dirkey = dirruns + " " + doneName;
-
- // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
- if ( xml ) {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- if ( matcher( elem, context, xml ) ) {
- return true;
- }
- }
- }
- } else {
- while ( (elem = elem[ dir ]) ) {
- if ( elem.nodeType === 1 || checkNonElements ) {
- outerCache = elem[ expando ] || (elem[ expando ] = {});
- if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) {
- if ( (data = cache[1]) === true || data === cachedruns ) {
- return data === true;
- }
- } else {
- cache = outerCache[ dir ] = [ dirkey ];
- cache[1] = matcher( elem, context, xml ) || cachedruns;
- if ( cache[1] === true ) {
- return true;
- }
- }
- }
- }
- }
- };
-}
-
-function elementMatcher( matchers ) {
- return matchers.length > 1 ?
- function( elem, context, xml ) {
- var i = matchers.length;
- while ( i-- ) {
- if ( !matchers[i]( elem, context, xml ) ) {
- return false;
- }
- }
- return true;
- } :
- matchers[0];
-}
-
-function condense( unmatched, map, filter, context, xml ) {
- var elem,
- newUnmatched = [],
- i = 0,
- len = unmatched.length,
- mapped = map != null;
-
- for ( ; i < len; i++ ) {
- if ( (elem = unmatched[i]) ) {
- if ( !filter || filter( elem, context, xml ) ) {
- newUnmatched.push( elem );
- if ( mapped ) {
- map.push( i );
- }
- }
- }
- }
-
- return newUnmatched;
-}
-
-function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
- if ( postFilter && !postFilter[ expando ] ) {
- postFilter = setMatcher( postFilter );
- }
- if ( postFinder && !postFinder[ expando ] ) {
- postFinder = setMatcher( postFinder, postSelector );
- }
- return markFunction(function( seed, results, context, xml ) {
- var temp, i, elem,
- preMap = [],
- postMap = [],
- preexisting = results.length,
-
- // Get initial elements from seed or context
- elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
-
- // Prefilter to get matcher input, preserving a map for seed-results synchronization
- matcherIn = preFilter && ( seed || !selector ) ?
- condense( elems, preMap, preFilter, context, xml ) :
- elems,
-
- matcherOut = matcher ?
- // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
- postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
-
- // ...intermediate processing is necessary
- [] :
-
- // ...otherwise use results directly
- results :
- matcherIn;
-
- // Find primary matches
- if ( matcher ) {
- matcher( matcherIn, matcherOut, context, xml );
- }
-
- // Apply postFilter
- if ( postFilter ) {
- temp = condense( matcherOut, postMap );
- postFilter( temp, [], context, xml );
-
- // Un-match failing elements by moving them back to matcherIn
- i = temp.length;
- while ( i-- ) {
- if ( (elem = temp[i]) ) {
- matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
- }
- }
- }
-
- if ( seed ) {
- if ( postFinder || preFilter ) {
- if ( postFinder ) {
- // Get the final matcherOut by condensing this intermediate into postFinder contexts
- temp = [];
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) ) {
- // Restore matcherIn since elem is not yet a final match
- temp.push( (matcherIn[i] = elem) );
- }
- }
- postFinder( null, (matcherOut = []), temp, xml );
- }
-
- // Move matched elements from seed to results to keep them synchronized
- i = matcherOut.length;
- while ( i-- ) {
- if ( (elem = matcherOut[i]) &&
- (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
-
- seed[temp] = !(results[temp] = elem);
- }
- }
- }
-
- // Add elements to results, through postFinder if defined
- } else {
- matcherOut = condense(
- matcherOut === results ?
- matcherOut.splice( preexisting, matcherOut.length ) :
- matcherOut
- );
- if ( postFinder ) {
- postFinder( null, results, matcherOut, xml );
- } else {
- push.apply( results, matcherOut );
- }
- }
- });
-}
-
-function matcherFromTokens( tokens ) {
- var checkContext, matcher, j,
- len = tokens.length,
- leadingRelative = Expr.relative[ tokens[0].type ],
- implicitRelative = leadingRelative || Expr.relative[" "],
- i = leadingRelative ? 1 : 0,
-
- // The foundational matcher ensures that elements are reachable from top-level context(s)
- matchContext = addCombinator( function( elem ) {
- return elem === checkContext;
- }, implicitRelative, true ),
- matchAnyContext = addCombinator( function( elem ) {
- return indexOf.call( checkContext, elem ) > -1;
- }, implicitRelative, true ),
- matchers = [ function( elem, context, xml ) {
- return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
- (checkContext = context).nodeType ?
- matchContext( elem, context, xml ) :
- matchAnyContext( elem, context, xml ) );
- } ];
-
- for ( ; i < len; i++ ) {
- if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
- matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
- } else {
- matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
-
- // Return special upon seeing a positional matcher
- if ( matcher[ expando ] ) {
- // Find the next relative operator (if any) for proper handling
- j = ++i;
- for ( ; j < len; j++ ) {
- if ( Expr.relative[ tokens[j].type ] ) {
- break;
- }
- }
- return setMatcher(
- i > 1 && elementMatcher( matchers ),
- i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ),
- matcher,
- i < j && matcherFromTokens( tokens.slice( i, j ) ),
- j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
- j < len && toSelector( tokens )
- );
- }
- matchers.push( matcher );
- }
- }
-
- return elementMatcher( matchers );
-}
-
-function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
- // A counter to specify which element is currently being matched
- var matcherCachedRuns = 0,
- bySet = setMatchers.length > 0,
- byElement = elementMatchers.length > 0,
- superMatcher = function( seed, context, xml, results, expandContext ) {
- var elem, j, matcher,
- setMatched = [],
- matchedCount = 0,
- i = "0",
- unmatched = seed && [],
- outermost = expandContext != null,
- contextBackup = outermostContext,
- // We must always have either seed elements or context
- elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ),
- // Use integer dirruns iff this is the outermost matcher
- dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1);
-
- if ( outermost ) {
- outermostContext = context !== document && context;
- cachedruns = matcherCachedRuns;
- }
-
- // Add elements passing elementMatchers directly to results
- // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
- for ( ; (elem = elems[i]) != null; i++ ) {
- if ( byElement && elem ) {
- j = 0;
- while ( (matcher = elementMatchers[j++]) ) {
- if ( matcher( elem, context, xml ) ) {
- results.push( elem );
- break;
- }
- }
- if ( outermost ) {
- dirruns = dirrunsUnique;
- cachedruns = ++matcherCachedRuns;
- }
- }
-
- // Track unmatched elements for set filters
- if ( bySet ) {
- // They will have gone through all possible matchers
- if ( (elem = !matcher && elem) ) {
- matchedCount--;
- }
-
- // Lengthen the array for every element, matched or not
- if ( seed ) {
- unmatched.push( elem );
- }
- }
- }
-
- // Apply set filters to unmatched elements
- matchedCount += i;
- if ( bySet && i !== matchedCount ) {
- j = 0;
- while ( (matcher = setMatchers[j++]) ) {
- matcher( unmatched, setMatched, context, xml );
- }
-
- if ( seed ) {
- // Reintegrate element matches to eliminate the need for sorting
- if ( matchedCount > 0 ) {
- while ( i-- ) {
- if ( !(unmatched[i] || setMatched[i]) ) {
- setMatched[i] = pop.call( results );
- }
- }
- }
-
- // Discard index placeholder values to get only actual matches
- setMatched = condense( setMatched );
- }
-
- // Add matches to results
- push.apply( results, setMatched );
-
- // Seedless set matches succeeding multiple successful matchers stipulate sorting
- if ( outermost && !seed && setMatched.length > 0 &&
- ( matchedCount + setMatchers.length ) > 1 ) {
-
- Sizzle.uniqueSort( results );
- }
- }
-
- // Override manipulation of globals by nested matchers
- if ( outermost ) {
- dirruns = dirrunsUnique;
- outermostContext = contextBackup;
- }
-
- return unmatched;
- };
-
- return bySet ?
- markFunction( superMatcher ) :
- superMatcher;
-}
-
-compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) {
- var i,
- setMatchers = [],
- elementMatchers = [],
- cached = compilerCache[ selector + " " ];
-
- if ( !cached ) {
- // Generate a function of recursive functions that can be used to check each element
- if ( !group ) {
- group = tokenize( selector );
- }
- i = group.length;
- while ( i-- ) {
- cached = matcherFromTokens( group[i] );
- if ( cached[ expando ] ) {
- setMatchers.push( cached );
- } else {
- elementMatchers.push( cached );
- }
- }
-
- // Cache the compiled function
- cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
- }
- return cached;
-};
-
-function multipleContexts( selector, contexts, results ) {
- var i = 0,
- len = contexts.length;
- for ( ; i < len; i++ ) {
- Sizzle( selector, contexts[i], results );
- }
- return results;
-}
-
-function select( selector, context, results, seed ) {
- var i, tokens, token, type, find,
- match = tokenize( selector );
-
- if ( !seed ) {
- // Try to minimize operations if there is only one group
- if ( match.length === 1 ) {
-
- // Take a shortcut and set the context if the root selector is an ID
- tokens = match[0] = match[0].slice( 0 );
- if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
- context.nodeType === 9 && !documentIsXML &&
- Expr.relative[ tokens[1].type ] ) {
-
- context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0];
- if ( !context ) {
- return results;
- }
-
- selector = selector.slice( tokens.shift().value.length );
- }
-
- // Fetch a seed set for right-to-left matching
- i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
- while ( i-- ) {
- token = tokens[i];
-
- // Abort if we hit a combinator
- if ( Expr.relative[ (type = token.type) ] ) {
- break;
- }
- if ( (find = Expr.find[ type ]) ) {
- // Search, expanding context for leading sibling combinators
- if ( (seed = find(
- token.matches[0].replace( runescape, funescape ),
- rsibling.test( tokens[0].type ) && context.parentNode || context
- )) ) {
-
- // If seed is empty or no tokens remain, we can return early
- tokens.splice( i, 1 );
- selector = seed.length && toSelector( tokens );
- if ( !selector ) {
- push.apply( results, slice.call( seed, 0 ) );
- return results;
- }
-
- break;
- }
- }
- }
- }
- }
-
- // Compile and execute a filtering function
- // Provide `match` to avoid retokenization if we modified the selector above
- compile( selector, match )(
- seed,
- context,
- documentIsXML,
- results,
- rsibling.test( selector )
- );
- return results;
-}
-
-// Deprecated
-Expr.pseudos["nth"] = Expr.pseudos["eq"];
-
-// Easy API for creating new setFilters
-function setFilters() {}
-Expr.filters = setFilters.prototype = Expr.pseudos;
-Expr.setFilters = new setFilters();
-
-// Initialize with the default document
-setDocument();
-
-// Override sizzle attribute retrieval
-Sizzle.attr = jQuery.attr;
-jQuery.find = Sizzle;
-jQuery.expr = Sizzle.selectors;
-jQuery.expr[":"] = jQuery.expr.pseudos;
-jQuery.unique = Sizzle.uniqueSort;
-jQuery.text = Sizzle.getText;
-jQuery.isXMLDoc = Sizzle.isXML;
-jQuery.contains = Sizzle.contains;
-
-
-})( window );
-var runtil = /Until$/,
- rparentsprev = /^(?:parents|prev(?:Until|All))/,
- isSimple = /^.[^:#\[\.,]*$/,
- rneedsContext = jQuery.expr.match.needsContext,
- // methods guaranteed to produce a unique set when starting from a unique set
- guaranteedUnique = {
- children: true,
- contents: true,
- next: true,
- prev: true
- };
-
-jQuery.fn.extend({
- find: function( selector ) {
- var i, ret, self,
- len = this.length;
-
- if ( typeof selector !== "string" ) {
- self = this;
- return this.pushStack( jQuery( selector ).filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( self[ i ], this ) ) {
- return true;
- }
- }
- }) );
- }
-
- ret = [];
- for ( i = 0; i < len; i++ ) {
- jQuery.find( selector, this[ i ], ret );
- }
-
- // Needed because $( selector, context ) becomes $( context ).find( selector )
- ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
- ret.selector = ( this.selector ? this.selector + " " : "" ) + selector;
- return ret;
- },
-
- has: function( target ) {
- var i,
- targets = jQuery( target, this ),
- len = targets.length;
-
- return this.filter(function() {
- for ( i = 0; i < len; i++ ) {
- if ( jQuery.contains( this, targets[i] ) ) {
- return true;
- }
- }
- });
- },
-
- not: function( selector ) {
- return this.pushStack( winnow(this, selector, false) );
- },
-
- filter: function( selector ) {
- return this.pushStack( winnow(this, selector, true) );
- },
-
- is: function( selector ) {
- return !!selector && (
- typeof selector === "string" ?
- // If this is a positional/relative selector, check membership in the returned set
- // so $("p:first").is("p:last") won't return true for a doc with two "p".
- rneedsContext.test( selector ) ?
- jQuery( selector, this.context ).index( this[0] ) >= 0 :
- jQuery.filter( selector, this ).length > 0 :
- this.filter( selector ).length > 0 );
- },
-
- closest: function( selectors, context ) {
- var cur,
- i = 0,
- l = this.length,
- ret = [],
- pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
- jQuery( selectors, context || this.context ) :
- 0;
-
- for ( ; i < l; i++ ) {
- cur = this[i];
-
- while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) {
- if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
- ret.push( cur );
- break;
- }
- cur = cur.parentNode;
- }
- }
-
- return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret );
- },
-
- // Determine the position of an element within
- // the matched set of elements
- index: function( elem ) {
-
- // No argument, return index in parent
- if ( !elem ) {
- return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
- }
-
- // index in selector
- if ( typeof elem === "string" ) {
- return jQuery.inArray( this[0], jQuery( elem ) );
- }
-
- // Locate the position of the desired element
- return jQuery.inArray(
- // If it receives a jQuery object, the first element is used
- elem.jquery ? elem[0] : elem, this );
- },
-
- add: function( selector, context ) {
- var set = typeof selector === "string" ?
- jQuery( selector, context ) :
- jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
- all = jQuery.merge( this.get(), set );
-
- return this.pushStack( jQuery.unique(all) );
- },
-
- addBack: function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter(selector)
- );
- }
-});
-
-jQuery.fn.andSelf = jQuery.fn.addBack;
-
-function sibling( cur, dir ) {
- do {
- cur = cur[ dir ];
- } while ( cur && cur.nodeType !== 1 );
-
- return cur;
-}
-
-jQuery.each({
- parent: function( elem ) {
- var parent = elem.parentNode;
- return parent && parent.nodeType !== 11 ? parent : null;
- },
- parents: function( elem ) {
- return jQuery.dir( elem, "parentNode" );
- },
- parentsUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "parentNode", until );
- },
- next: function( elem ) {
- return sibling( elem, "nextSibling" );
- },
- prev: function( elem ) {
- return sibling( elem, "previousSibling" );
- },
- nextAll: function( elem ) {
- return jQuery.dir( elem, "nextSibling" );
- },
- prevAll: function( elem ) {
- return jQuery.dir( elem, "previousSibling" );
- },
- nextUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "nextSibling", until );
- },
- prevUntil: function( elem, i, until ) {
- return jQuery.dir( elem, "previousSibling", until );
- },
- siblings: function( elem ) {
- return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
- },
- children: function( elem ) {
- return jQuery.sibling( elem.firstChild );
- },
- contents: function( elem ) {
- return jQuery.nodeName( elem, "iframe" ) ?
- elem.contentDocument || elem.contentWindow.document :
- jQuery.merge( [], elem.childNodes );
- }
-}, function( name, fn ) {
- jQuery.fn[ name ] = function( until, selector ) {
- var ret = jQuery.map( this, fn, until );
-
- if ( !runtil.test( name ) ) {
- selector = until;
- }
-
- if ( selector && typeof selector === "string" ) {
- ret = jQuery.filter( selector, ret );
- }
-
- ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
-
- if ( this.length > 1 && rparentsprev.test( name ) ) {
- ret = ret.reverse();
- }
-
- return this.pushStack( ret );
- };
-});
-
-jQuery.extend({
- filter: function( expr, elems, not ) {
- if ( not ) {
- expr = ":not(" + expr + ")";
- }
-
- return elems.length === 1 ?
- jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
- jQuery.find.matches(expr, elems);
- },
-
- dir: function( elem, dir, until ) {
- var matched = [],
- cur = elem[ dir ];
-
- while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
- if ( cur.nodeType === 1 ) {
- matched.push( cur );
- }
- cur = cur[dir];
- }
- return matched;
- },
-
- sibling: function( n, elem ) {
- var r = [];
-
- for ( ; n; n = n.nextSibling ) {
- if ( n.nodeType === 1 && n !== elem ) {
- r.push( n );
- }
- }
-
- return r;
- }
-});
-
-// Implement the identical functionality for filter and not
-function winnow( elements, qualifier, keep ) {
-
- // Can't pass null or undefined to indexOf in Firefox 4
- // Set to 0 to skip string check
- qualifier = qualifier || 0;
-
- if ( jQuery.isFunction( qualifier ) ) {
- return jQuery.grep(elements, function( elem, i ) {
- var retVal = !!qualifier.call( elem, i, elem );
- return retVal === keep;
- });
-
- } else if ( qualifier.nodeType ) {
- return jQuery.grep(elements, function( elem ) {
- return ( elem === qualifier ) === keep;
- });
-
- } else if ( typeof qualifier === "string" ) {
- var filtered = jQuery.grep(elements, function( elem ) {
- return elem.nodeType === 1;
- });
-
- if ( isSimple.test( qualifier ) ) {
- return jQuery.filter(qualifier, filtered, !keep);
- } else {
- qualifier = jQuery.filter( qualifier, filtered );
- }
- }
-
- return jQuery.grep(elements, function( elem ) {
- return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
- });
-}
-function createSafeFragment( document ) {
- var list = nodeNames.split( "|" ),
- safeFrag = document.createDocumentFragment();
-
- if ( safeFrag.createElement ) {
- while ( list.length ) {
- safeFrag.createElement(
- list.pop()
- );
- }
- }
- return safeFrag;
-}
-
-var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
- "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
- rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
- rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
- rleadingWhitespace = /^\s+/,
- rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
- rtagName = /<([\w:]+)/,
- rtbody = /<tbody/i,
- rhtml = /<|&#?\w+;/,
- rnoInnerhtml = /<(?:script|style|link)/i,
- manipulation_rcheckableType = /^(?:checkbox|radio)$/i,
- // checked="checked" or checked
- rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
- rscriptType = /^$|\/(?:java|ecma)script/i,
- rscriptTypeMasked = /^true\/(.*)/,
- rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
-
- // We have to close these tags to support XHTML (#13200)
- wrapMap = {
- option: [ 1, "<select multiple='multiple'>", "</select>" ],
- legend: [ 1, "<fieldset>", "</fieldset>" ],
- area: [ 1, "<map>", "</map>" ],
- param: [ 1, "<object>", "</object>" ],
- thead: [ 1, "<table>", "</table>" ],
- tr: [ 2, "<table><tbody>", "</tbody></table>" ],
- col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
- td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
-
- // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
- // unless wrapped in a div with non-breaking characters in front of it.
- _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
- },
- safeFragment = createSafeFragment( document ),
- fragmentDiv = safeFragment.appendChild( document.createElement("div") );
-
-wrapMap.optgroup = wrapMap.option;
-wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
-wrapMap.th = wrapMap.td;
-
-jQuery.fn.extend({
- text: function( value ) {
- return jQuery.access( this, function( value ) {
- return value === undefined ?
- jQuery.text( this ) :
- this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
- }, null, value, arguments.length );
- },
-
- wrapAll: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapAll( html.call(this, i) );
- });
- }
-
- if ( this[0] ) {
- // The elements to wrap the target around
- var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
-
- if ( this[0].parentNode ) {
- wrap.insertBefore( this[0] );
- }
-
- wrap.map(function() {
- var elem = this;
-
- while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
- elem = elem.firstChild;
- }
-
- return elem;
- }).append( this );
- }
-
- return this;
- },
-
- wrapInner: function( html ) {
- if ( jQuery.isFunction( html ) ) {
- return this.each(function(i) {
- jQuery(this).wrapInner( html.call(this, i) );
- });
- }
-
- return this.each(function() {
- var self = jQuery( this ),
- contents = self.contents();
-
- if ( contents.length ) {
- contents.wrapAll( html );
-
- } else {
- self.append( html );
- }
- });
- },
-
- wrap: function( html ) {
- var isFunction = jQuery.isFunction( html );
-
- return this.each(function(i) {
- jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
- });
- },
-
- unwrap: function() {
- return this.parent().each(function() {
- if ( !jQuery.nodeName( this, "body" ) ) {
- jQuery( this ).replaceWith( this.childNodes );
- }
- }).end();
- },
-
- append: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.appendChild( elem );
- }
- });
- },
-
- prepend: function() {
- return this.domManip(arguments, true, function( elem ) {
- if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
- this.insertBefore( elem, this.firstChild );
- }
- });
- },
-
- before: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this );
- }
- });
- },
-
- after: function() {
- return this.domManip( arguments, false, function( elem ) {
- if ( this.parentNode ) {
- this.parentNode.insertBefore( elem, this.nextSibling );
- }
- });
- },
-
- // keepData is for internal use only--do not document
- remove: function( selector, keepData ) {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
- if ( !keepData && elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem ) );
- }
-
- if ( elem.parentNode ) {
- if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
- setGlobalEval( getAll( elem, "script" ) );
- }
- elem.parentNode.removeChild( elem );
- }
- }
- }
-
- return this;
- },
-
- empty: function() {
- var elem,
- i = 0;
-
- for ( ; (elem = this[i]) != null; i++ ) {
- // Remove element nodes and prevent memory leaks
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem, false ) );
- }
-
- // Remove any remaining nodes
- while ( elem.firstChild ) {
- elem.removeChild( elem.firstChild );
- }
-
- // If this is a select, ensure that it displays empty (#12336)
- // Support: IE<9
- if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
- elem.options.length = 0;
- }
- }
-
- return this;
- },
-
- clone: function( dataAndEvents, deepDataAndEvents ) {
- dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
- deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
-
- return this.map( function () {
- return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
- });
- },
-
- html: function( value ) {
- return jQuery.access( this, function( value ) {
- var elem = this[0] || {},
- i = 0,
- l = this.length;
-
- if ( value === undefined ) {
- return elem.nodeType === 1 ?
- elem.innerHTML.replace( rinlinejQuery, "" ) :
- undefined;
- }
-
- // See if we can take a shortcut and just use innerHTML
- if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
- ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) &&
- ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
- !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
-
- value = value.replace( rxhtmlTag, "<$1></$2>" );
-
- try {
- for (; i < l; i++ ) {
- // Remove element nodes and prevent memory leaks
- elem = this[i] || {};
- if ( elem.nodeType === 1 ) {
- jQuery.cleanData( getAll( elem, false ) );
- elem.innerHTML = value;
- }
- }
-
- elem = 0;
-
- // If using innerHTML throws an exception, use the fallback method
- } catch(e) {}
- }
-
- if ( elem ) {
- this.empty().append( value );
- }
- }, null, value, arguments.length );
- },
-
- replaceWith: function( value ) {
- var isFunc = jQuery.isFunction( value );
-
- // Make sure that the elements are removed from the DOM before they are inserted
- // this can help fix replacing a parent with child elements
- if ( !isFunc && typeof value !== "string" ) {
- value = jQuery( value ).not( this ).detach();
- }
-
- return this.domManip( [ value ], true, function( elem ) {
- var next = this.nextSibling,
- parent = this.parentNode;
-
- if ( parent ) {
- jQuery( this ).remove();
- parent.insertBefore( elem, next );
- }
- });
- },
-
- detach: function( selector ) {
- return this.remove( selector, true );
- },
-
- domManip: function( args, table, callback ) {
-
- // Flatten any nested arrays
- args = core_concat.apply( [], args );
-
- var first, node, hasScripts,
- scripts, doc, fragment,
- i = 0,
- l = this.length,
- set = this,
- iNoClone = l - 1,
- value = args[0],
- isFunction = jQuery.isFunction( value );
-
- // We can't cloneNode fragments that contain checked, in WebKit
- if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
- return this.each(function( index ) {
- var self = set.eq( index );
- if ( isFunction ) {
- args[0] = value.call( this, index, table ? self.html() : undefined );
- }
- self.domManip( args, table, callback );
- });
- }
-
- if ( l ) {
- fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
- first = fragment.firstChild;
-
- if ( fragment.childNodes.length === 1 ) {
- fragment = first;
- }
-
- if ( first ) {
- table = table && jQuery.nodeName( first, "tr" );
- scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
- hasScripts = scripts.length;
-
- // Use the original fragment for the last item instead of the first because it can end up
- // being emptied incorrectly in certain situations (#8070).
- for ( ; i < l; i++ ) {
- node = fragment;
-
- if ( i !== iNoClone ) {
- node = jQuery.clone( node, true, true );
-
- // Keep references to cloned scripts for later restoration
- if ( hasScripts ) {
- jQuery.merge( scripts, getAll( node, "script" ) );
- }
- }
-
- callback.call(
- table && jQuery.nodeName( this[i], "table" ) ?
- findOrAppend( this[i], "tbody" ) :
- this[i],
- node,
- i
- );
- }
-
- if ( hasScripts ) {
- doc = scripts[ scripts.length - 1 ].ownerDocument;
-
- // Reenable scripts
- jQuery.map( scripts, restoreScript );
-
- // Evaluate executable scripts on first document insertion
- for ( i = 0; i < hasScripts; i++ ) {
- node = scripts[ i ];
- if ( rscriptType.test( node.type || "" ) &&
- !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
-
- if ( node.src ) {
- // Hope ajax is available...
- jQuery.ajax({
- url: node.src,
- type: "GET",
- dataType: "script",
- async: false,
- global: false,
- "throws": true
- });
- } else {
- jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
- }
- }
- }
- }
-
- // Fix #11809: Avoid leaking memory
- fragment = first = null;
- }
- }
-
- return this;
- }
-});
-
-function findOrAppend( elem, tag ) {
- return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) );
-}
-
-// Replace/restore the type attribute of script elements for safe DOM manipulation
-function disableScript( elem ) {
- var attr = elem.getAttributeNode("type");
- elem.type = ( attr && attr.specified ) + "/" + elem.type;
- return elem;
-}
-function restoreScript( elem ) {
- var match = rscriptTypeMasked.exec( elem.type );
- if ( match ) {
- elem.type = match[1];
- } else {
- elem.removeAttribute("type");
- }
- return elem;
-}
-
-// Mark scripts as having already been evaluated
-function setGlobalEval( elems, refElements ) {
- var elem,
- i = 0;
- for ( ; (elem = elems[i]) != null; i++ ) {
- jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
- }
-}
-
-function cloneCopyEvent( src, dest ) {
-
- if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
- return;
- }
-
- var type, i, l,
- oldData = jQuery._data( src ),
- curData = jQuery._data( dest, oldData ),
- events = oldData.events;
-
- if ( events ) {
- delete curData.handle;
- curData.events = {};
-
- for ( type in events ) {
- for ( i = 0, l = events[ type ].length; i < l; i++ ) {
- jQuery.event.add( dest, type, events[ type ][ i ] );
- }
- }
- }
-
- // make the cloned public data object a copy from the original
- if ( curData.data ) {
- curData.data = jQuery.extend( {}, curData.data );
- }
-}
-
-function fixCloneNodeIssues( src, dest ) {
- var nodeName, e, data;
-
- // We do not need to do anything for non-Elements
- if ( dest.nodeType !== 1 ) {
- return;
- }
-
- nodeName = dest.nodeName.toLowerCase();
-
- // IE6-8 copies events bound via attachEvent when using cloneNode.
- if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) {
- data = jQuery._data( dest );
-
- for ( e in data.events ) {
- jQuery.removeEvent( dest, e, data.handle );
- }
-
- // Event data gets referenced instead of copied if the expando gets copied too
- dest.removeAttribute( jQuery.expando );
- }
-
- // IE blanks contents when cloning scripts, and tries to evaluate newly-set text
- if ( nodeName === "script" && dest.text !== src.text ) {
- disableScript( dest ).text = src.text;
- restoreScript( dest );
-
- // IE6-10 improperly clones children of object elements using classid.
- // IE10 throws NoModificationAllowedError if parent is null, #12132.
- } else if ( nodeName === "object" ) {
- if ( dest.parentNode ) {
- dest.outerHTML = src.outerHTML;
- }
-
- // This path appears unavoidable for IE9. When cloning an object
- // element in IE9, the outerHTML strategy above is not sufficient.
- // If the src has innerHTML and the destination does not,
- // copy the src.innerHTML into the dest.innerHTML. #10324
- if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
- dest.innerHTML = src.innerHTML;
- }
-
- } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) {
- // IE6-8 fails to persist the checked state of a cloned checkbox
- // or radio button. Worse, IE6-7 fail to give the cloned element
- // a checked appearance if the defaultChecked value isn't also set
-
- dest.defaultChecked = dest.checked = src.checked;
-
- // IE6-7 get confused and end up setting the value of a cloned
- // checkbox/radio button to an empty string instead of "on"
- if ( dest.value !== src.value ) {
- dest.value = src.value;
- }
-
- // IE6-8 fails to return the selected option to the default selected
- // state when cloning options
- } else if ( nodeName === "option" ) {
- dest.defaultSelected = dest.selected = src.defaultSelected;
-
- // IE6-8 fails to set the defaultValue to the correct value when
- // cloning other types of input fields
- } else if ( nodeName === "input" || nodeName === "textarea" ) {
- dest.defaultValue = src.defaultValue;
- }
-}
-
-jQuery.each({
- appendTo: "append",
- prependTo: "prepend",
- insertBefore: "before",
- insertAfter: "after",
- replaceAll: "replaceWith"
-}, function( name, original ) {
- jQuery.fn[ name ] = function( selector ) {
- var elems,
- i = 0,
- ret = [],
- insert = jQuery( selector ),
- last = insert.length - 1;
-
- for ( ; i <= last; i++ ) {
- elems = i === last ? this : this.clone(true);
- jQuery( insert[i] )[ original ]( elems );
-
- // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
- core_push.apply( ret, elems.get() );
- }
-
- return this.pushStack( ret );
- };
-});
-
-function getAll( context, tag ) {
- var elems, elem,
- i = 0,
- found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) :
- typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) :
- undefined;
-
- if ( !found ) {
- for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
- if ( !tag || jQuery.nodeName( elem, tag ) ) {
- found.push( elem );
- } else {
- jQuery.merge( found, getAll( elem, tag ) );
- }
- }
- }
-
- return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
- jQuery.merge( [ context ], found ) :
- found;
-}
-
-// Used in buildFragment, fixes the defaultChecked property
-function fixDefaultChecked( elem ) {
- if ( manipulation_rcheckableType.test( elem.type ) ) {
- elem.defaultChecked = elem.checked;
- }
-}
-
-jQuery.extend({
- clone: function( elem, dataAndEvents, deepDataAndEvents ) {
- var destElements, node, clone, i, srcElements,
- inPage = jQuery.contains( elem.ownerDocument, elem );
-
- if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
- clone = elem.cloneNode( true );
-
- // IE<=8 does not properly clone detached, unknown element nodes
- } else {
- fragmentDiv.innerHTML = elem.outerHTML;
- fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
- }
-
- if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
- (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
-
- // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
- destElements = getAll( clone );
- srcElements = getAll( elem );
-
- // Fix all IE cloning issues
- for ( i = 0; (node = srcElements[i]) != null; ++i ) {
- // Ensure that the destination node is not null; Fixes #9587
- if ( destElements[i] ) {
- fixCloneNodeIssues( node, destElements[i] );
- }
- }
- }
-
- // Copy the events from the original to the clone
- if ( dataAndEvents ) {
- if ( deepDataAndEvents ) {
- srcElements = srcElements || getAll( elem );
- destElements = destElements || getAll( clone );
-
- for ( i = 0; (node = srcElements[i]) != null; i++ ) {
- cloneCopyEvent( node, destElements[i] );
- }
- } else {
- cloneCopyEvent( elem, clone );
- }
- }
-
- // Preserve script evaluation history
- destElements = getAll( clone, "script" );
- if ( destElements.length > 0 ) {
- setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
- }
-
- destElements = srcElements = node = null;
-
- // Return the cloned set
- return clone;
- },
-
- buildFragment: function( elems, context, scripts, selection ) {
- var j, elem, contains,
- tmp, tag, tbody, wrap,
- l = elems.length,
-
- // Ensure a safe fragment
- safe = createSafeFragment( context ),
-
- nodes = [],
- i = 0;
-
- for ( ; i < l; i++ ) {
- elem = elems[ i ];
-
- if ( elem || elem === 0 ) {
-
- // Add nodes directly
- if ( jQuery.type( elem ) === "object" ) {
- jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
-
- // Convert non-html into a text node
- } else if ( !rhtml.test( elem ) ) {
- nodes.push( context.createTextNode( elem ) );
-
- // Convert html into DOM nodes
- } else {
- tmp = tmp || safe.appendChild( context.createElement("div") );
-
- // Deserialize a standard representation
- tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
- wrap = wrapMap[ tag ] || wrapMap._default;
-
- tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
-
- // Descend through wrappers to the right content
- j = wrap[0];
- while ( j-- ) {
- tmp = tmp.lastChild;
- }
-
- // Manually add leading whitespace removed by IE
- if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
- nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
- }
-
- // Remove IE's autoinserted <tbody> from table fragments
- if ( !jQuery.support.tbody ) {
-
- // String was a <table>, *may* have spurious <tbody>
- elem = tag === "table" && !rtbody.test( elem ) ?
- tmp.firstChild :
-
- // String was a bare <thead> or <tfoot>
- wrap[1] === "<table>" && !rtbody.test( elem ) ?
- tmp :
- 0;
-
- j = elem && elem.childNodes.length;
- while ( j-- ) {
- if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
- elem.removeChild( tbody );
- }
- }
- }
-
- jQuery.merge( nodes, tmp.childNodes );
-
- // Fix #12392 for WebKit and IE > 9
- tmp.textContent = "";
-
- // Fix #12392 for oldIE
- while ( tmp.firstChild ) {
- tmp.removeChild( tmp.firstChild );
- }
-
- // Remember the top-level container for proper cleanup
- tmp = safe.lastChild;
- }
- }
- }
-
- // Fix #11356: Clear elements from fragment
- if ( tmp ) {
- safe.removeChild( tmp );
- }
-
- // Reset defaultChecked for any radios and checkboxes
- // about to be appended to the DOM in IE 6/7 (#8060)
- if ( !jQuery.support.appendChecked ) {
- jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
- }
-
- i = 0;
- while ( (elem = nodes[ i++ ]) ) {
-
- // #4087 - If origin and destination elements are the same, and this is
- // that element, do not do anything
- if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
- continue;
- }
-
- contains = jQuery.contains( elem.ownerDocument, elem );
-
- // Append to fragment
- tmp = getAll( safe.appendChild( elem ), "script" );
-
- // Preserve script evaluation history
- if ( contains ) {
- setGlobalEval( tmp );
- }
-
- // Capture executables
- if ( scripts ) {
- j = 0;
- while ( (elem = tmp[ j++ ]) ) {
- if ( rscriptType.test( elem.type || "" ) ) {
- scripts.push( elem );
- }
- }
- }
- }
-
- tmp = null;
-
- return safe;
- },
-
- cleanData: function( elems, /* internal */ acceptData ) {
- var elem, type, id, data,
- i = 0,
- internalKey = jQuery.expando,
- cache = jQuery.cache,
- deleteExpando = jQuery.support.deleteExpando,
- special = jQuery.event.special;
-
- for ( ; (elem = elems[i]) != null; i++ ) {
-
- if ( acceptData || jQuery.acceptData( elem ) ) {
-
- id = elem[ internalKey ];
- data = id && cache[ id ];
-
- if ( data ) {
- if ( data.events ) {
- for ( type in data.events ) {
- if ( special[ type ] ) {
- jQuery.event.remove( elem, type );
-
- // This is a shortcut to avoid jQuery.event.remove's overhead
- } else {
- jQuery.removeEvent( elem, type, data.handle );
- }
- }
- }
-
- // Remove cache only if it was not already removed by jQuery.event.remove
- if ( cache[ id ] ) {
-
- delete cache[ id ];
-
- // IE does not allow us to delete expando properties from nodes,
- // nor does it have a removeAttribute function on Document nodes;
- // we must handle all of these cases
- if ( deleteExpando ) {
- delete elem[ internalKey ];
-
- } else if ( typeof elem.removeAttribute !== core_strundefined ) {
- elem.removeAttribute( internalKey );
-
- } else {
- elem[ internalKey ] = null;
- }
-
- core_deletedIds.push( id );
- }
- }
- }
- }
- }
-});
-var iframe, getStyles, curCSS,
- ralpha = /alpha\([^)]*\)/i,
- ropacity = /opacity\s*=\s*([^)]*)/,
- rposition = /^(top|right|bottom|left)$/,
- // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
- // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
- rdisplayswap = /^(none|table(?!-c[ea]).+)/,
- rmargin = /^margin/,
- rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ),
- rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ),
- rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ),
- elemdisplay = { BODY: "block" },
-
- cssShow = { position: "absolute", visibility: "hidden", display: "block" },
- cssNormalTransform = {
- letterSpacing: 0,
- fontWeight: 400
- },
-
- cssExpand = [ "Top", "Right", "Bottom", "Left" ],
- cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
-
-// return a css property mapped to a potentially vendor prefixed property
-function vendorPropName( style, name ) {
-
- // shortcut for names that are not vendor prefixed
- if ( name in style ) {
- return name;
- }
-
- // check for vendor prefixed names
- var capName = name.charAt(0).toUpperCase() + name.slice(1),
- origName = name,
- i = cssPrefixes.length;
-
- while ( i-- ) {
- name = cssPrefixes[ i ] + capName;
- if ( name in style ) {
- return name;
- }
- }
-
- return origName;
-}
-
-function isHidden( elem, el ) {
- // isHidden might be called from jQuery#filter function;
- // in that case, element will be second argument
- elem = el || elem;
- return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
-}
-
-function showHide( elements, show ) {
- var display, elem, hidden,
- values = [],
- index = 0,
- length = elements.length;
-
- for ( ; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
-
- values[ index ] = jQuery._data( elem, "olddisplay" );
- display = elem.style.display;
- if ( show ) {
- // Reset the inline display of this element to learn if it is
- // being hidden by cascaded rules or not
- if ( !values[ index ] && display === "none" ) {
- elem.style.display = "";
- }
-
- // Set elements which have been overridden with display: none
- // in a stylesheet to whatever the default browser style is
- // for such an element
- if ( elem.style.display === "" && isHidden( elem ) ) {
- values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) );
- }
- } else {
-
- if ( !values[ index ] ) {
- hidden = isHidden( elem );
-
- if ( display && display !== "none" || !hidden ) {
- jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
- }
- }
- }
- }
-
- // Set the display of most of the elements in a second loop
- // to avoid the constant reflow
- for ( index = 0; index < length; index++ ) {
- elem = elements[ index ];
- if ( !elem.style ) {
- continue;
- }
- if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
- elem.style.display = show ? values[ index ] || "" : "none";
- }
- }
-
- return elements;
-}
-
-jQuery.fn.extend({
- css: function( name, value ) {
- return jQuery.access( this, function( elem, name, value ) {
- var len, styles,
- map = {},
- i = 0;
-
- if ( jQuery.isArray( name ) ) {
- styles = getStyles( elem );
- len = name.length;
-
- for ( ; i < len; i++ ) {
- map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
- }
-
- return map;
- }
-
- return value !== undefined ?
- jQuery.style( elem, name, value ) :
- jQuery.css( elem, name );
- }, name, value, arguments.length > 1 );
- },
- show: function() {
- return showHide( this, true );
- },
- hide: function() {
- return showHide( this );
- },
- toggle: function( state ) {
- var bool = typeof state === "boolean";
-
- return this.each(function() {
- if ( bool ? state : isHidden( this ) ) {
- jQuery( this ).show();
- } else {
- jQuery( this ).hide();
- }
- });
- }
-});
-
-jQuery.extend({
- // Add in style property hooks for overriding the default
- // behavior of getting and setting a style property
- cssHooks: {
- opacity: {
- get: function( elem, computed ) {
- if ( computed ) {
- // We should always get a number back from opacity
- var ret = curCSS( elem, "opacity" );
- return ret === "" ? "1" : ret;
- }
- }
- }
- },
-
- // Exclude the following css properties to add px
- cssNumber: {
- "columnCount": true,
- "fillOpacity": true,
- "fontWeight": true,
- "lineHeight": true,
- "opacity": true,
- "orphans": true,
- "widows": true,
- "zIndex": true,
- "zoom": true
- },
-
- // Add in properties whose names you wish to fix before
- // setting or getting the value
- cssProps: {
- // normalize float css property
- "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
- },
-
- // Get and set the style property on a DOM Node
- style: function( elem, name, value, extra ) {
- // Don't set styles on text and comment nodes
- if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
- return;
- }
-
- // Make sure that we're working with the right name
- var ret, type, hooks,
- origName = jQuery.camelCase( name ),
- style = elem.style;
-
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // Check if we're setting a value
- if ( value !== undefined ) {
- type = typeof value;
-
- // convert relative number strings (+= or -=) to relative numbers. #7345
- if ( type === "string" && (ret = rrelNum.exec( value )) ) {
- value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
- // Fixes bug #9237
- type = "number";
- }
-
- // Make sure that NaN and null values aren't set. See: #7116
- if ( value == null || type === "number" && isNaN( value ) ) {
- return;
- }
-
- // If a number was passed in, add 'px' to the (except for certain CSS properties)
- if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
- value += "px";
- }
-
- // Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
- // but it would mean to define eight (for every problematic property) identical functions
- if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
- style[ name ] = "inherit";
- }
-
- // If a hook was provided, use that value, otherwise just set the specified value
- if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
-
- // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
- // Fixes bug #5509
- try {
- style[ name ] = value;
- } catch(e) {}
- }
-
- } else {
- // If a hook was provided get the non-computed value from there
- if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
- return ret;
- }
-
- // Otherwise just get the value from the style object
- return style[ name ];
- }
- },
-
- css: function( elem, name, extra, styles ) {
- var num, val, hooks,
- origName = jQuery.camelCase( name );
-
- // Make sure that we're working with the right name
- name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
-
- // gets hook for the prefixed version
- // followed by the unprefixed version
- hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
-
- // If a hook was provided get the computed value from there
- if ( hooks && "get" in hooks ) {
- val = hooks.get( elem, true, extra );
- }
-
- // Otherwise, if a way to get the computed value exists, use that
- if ( val === undefined ) {
- val = curCSS( elem, name, styles );
- }
-
- //convert "normal" to computed value
- if ( val === "normal" && name in cssNormalTransform ) {
- val = cssNormalTransform[ name ];
- }
-
- // Return, converting to number if forced or a qualifier was provided and val looks numeric
- if ( extra === "" || extra ) {
- num = parseFloat( val );
- return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
- }
- return val;
- },
-
- // A method for quickly swapping in/out CSS properties to get correct calculations
- swap: function( elem, options, callback, args ) {
- var ret, name,
- old = {};
-
- // Remember the old values, and insert the new ones
- for ( name in options ) {
- old[ name ] = elem.style[ name ];
- elem.style[ name ] = options[ name ];
- }
-
- ret = callback.apply( elem, args || [] );
-
- // Revert the old values
- for ( name in options ) {
- elem.style[ name ] = old[ name ];
- }
-
- return ret;
- }
-});
-
-// NOTE: we've included the "window" in window.getComputedStyle
-// because jsdom on node.js will break without it.
-if ( window.getComputedStyle ) {
- getStyles = function( elem ) {
- return window.getComputedStyle( elem, null );
- };
-
- curCSS = function( elem, name, _computed ) {
- var width, minWidth, maxWidth,
- computed = _computed || getStyles( elem ),
-
- // getPropertyValue is only needed for .css('filter') in IE9, see #12537
- ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined,
- style = elem.style;
-
- if ( computed ) {
-
- if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
- ret = jQuery.style( elem, name );
- }
-
- // A tribute to the "awesome hack by Dean Edwards"
- // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
- // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
- // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
- if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
-
- // Remember the original values
- width = style.width;
- minWidth = style.minWidth;
- maxWidth = style.maxWidth;
-
- // Put in the new values to get a computed value out
- style.minWidth = style.maxWidth = style.width = ret;
- ret = computed.width;
-
- // Revert the changed values
- style.width = width;
- style.minWidth = minWidth;
- style.maxWidth = maxWidth;
- }
- }
-
- return ret;
- };
-} else if ( document.documentElement.currentStyle ) {
- getStyles = function( elem ) {
- return elem.currentStyle;
- };
-
- curCSS = function( elem, name, _computed ) {
- var left, rs, rsLeft,
- computed = _computed || getStyles( elem ),
- ret = computed ? computed[ name ] : undefined,
- style = elem.style;
-
- // Avoid setting ret to empty string here
- // so we don't default to auto
- if ( ret == null && style && style[ name ] ) {
- ret = style[ name ];
- }
-
- // From the awesome hack by Dean Edwards
- // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
-
- // If we're not dealing with a regular pixel number
- // but a number that has a weird ending, we need to convert it to pixels
- // but not position css attributes, as those are proportional to the parent element instead
- // and we can't measure the parent instead because it might trigger a "stacking dolls" problem
- if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
-
- // Remember the original values
- left = style.left;
- rs = elem.runtimeStyle;
- rsLeft = rs && rs.left;
-
- // Put in the new values to get a computed value out
- if ( rsLeft ) {
- rs.left = elem.currentStyle.left;
- }
- style.left = name === "fontSize" ? "1em" : ret;
- ret = style.pixelLeft + "px";
-
- // Revert the changed values
- style.left = left;
- if ( rsLeft ) {
- rs.left = rsLeft;
- }
- }
-
- return ret === "" ? "auto" : ret;
- };
-}
-
-function setPositiveNumber( elem, value, subtract ) {
- var matches = rnumsplit.exec( value );
- return matches ?
- // Guard against undefined "subtract", e.g., when used as in cssHooks
- Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
- value;
-}
-
-function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
- var i = extra === ( isBorderBox ? "border" : "content" ) ?
- // If we already have the right measurement, avoid augmentation
- 4 :
- // Otherwise initialize for horizontal or vertical properties
- name === "width" ? 1 : 0,
-
- val = 0;
-
- for ( ; i < 4; i += 2 ) {
- // both box models exclude margin, so add it if we want it
- if ( extra === "margin" ) {
- val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
- }
-
- if ( isBorderBox ) {
- // border-box includes padding, so remove it if we want content
- if ( extra === "content" ) {
- val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
- }
-
- // at this point, extra isn't border nor margin, so remove border
- if ( extra !== "margin" ) {
- val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
- }
- } else {
- // at this point, extra isn't content, so add padding
- val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
-
- // at this point, extra isn't content nor padding, so add border
- if ( extra !== "padding" ) {
- val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
- }
- }
- }
-
- return val;
-}
-
-function getWidthOrHeight( elem, name, extra ) {
-
- // Start with offset property, which is equivalent to the border-box value
- var valueIsBorderBox = true,
- val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
- styles = getStyles( elem ),
- isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
-
- // some non-html elements return undefined for offsetWidth, so check for null/undefined
- // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
- // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
- if ( val <= 0 || val == null ) {
- // Fall back to computed then uncomputed css if necessary
- val = curCSS( elem, name, styles );
- if ( val < 0 || val == null ) {
- val = elem.style[ name ];
- }
-
- // Computed unit is not pixels. Stop here and return.
- if ( rnumnonpx.test(val) ) {
- return val;
- }
-
- // we need the check for style in case a browser which returns unreliable values
- // for getComputedStyle silently falls back to the reliable elem.style
- valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] );
-
- // Normalize "", auto, and prepare for extra
- val = parseFloat( val ) || 0;
- }
-
- // use the active box-sizing model to add/subtract irrelevant styles
- return ( val +
- augmentWidthOrHeight(
- elem,
- name,
- extra || ( isBorderBox ? "border" : "content" ),
- valueIsBorderBox,
- styles
- )
- ) + "px";
-}
-
-// Try to determine the default display value of an element
-function css_defaultDisplay( nodeName ) {
- var doc = document,
- display = elemdisplay[ nodeName ];
-
- if ( !display ) {
- display = actualDisplay( nodeName, doc );
-
- // If the simple way fails, read from inside an iframe
- if ( display === "none" || !display ) {
- // Use the already-created iframe if possible
- iframe = ( iframe ||
- jQuery("<iframe frameborder='0' width='0' height='0'/>")
- .css( "cssText", "display:block !important" )
- ).appendTo( doc.documentElement );
-
- // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
- doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document;
- doc.write("<!doctype html><html><body>");
- doc.close();
-
- display = actualDisplay( nodeName, doc );
- iframe.detach();
- }
-
- // Store the correct default display
- elemdisplay[ nodeName ] = display;
- }
-
- return display;
-}
-
-// Called ONLY from within css_defaultDisplay
-function actualDisplay( name, doc ) {
- var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
- display = jQuery.css( elem[0], "display" );
- elem.remove();
- return display;
-}
-
-jQuery.each([ "height", "width" ], function( i, name ) {
- jQuery.cssHooks[ name ] = {
- get: function( elem, computed, extra ) {
- if ( computed ) {
- // certain elements can have dimension info if we invisibly show them
- // however, it must have a current display style that would benefit from this
- return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?
- jQuery.swap( elem, cssShow, function() {
- return getWidthOrHeight( elem, name, extra );
- }) :
- getWidthOrHeight( elem, name, extra );
- }
- },
-
- set: function( elem, value, extra ) {
- var styles = extra && getStyles( elem );
- return setPositiveNumber( elem, value, extra ?
- augmentWidthOrHeight(
- elem,
- name,
- extra,
- jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
- styles
- ) : 0
- );
- }
- };
-});
-
-if ( !jQuery.support.opacity ) {
- jQuery.cssHooks.opacity = {
- get: function( elem, computed ) {
- // IE uses filters for opacity
- return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
- ( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
- computed ? "1" : "";
- },
-
- set: function( elem, value ) {
- var style = elem.style,
- currentStyle = elem.currentStyle,
- opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
- filter = currentStyle && currentStyle.filter || style.filter || "";
-
- // IE has trouble with opacity if it does not have layout
- // Force it by setting the zoom level
- style.zoom = 1;
-
- // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
- // if value === "", then remove inline opacity #12685
- if ( ( value >= 1 || value === "" ) &&
- jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
- style.removeAttribute ) {
-
- // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
- // if "filter:" is present at all, clearType is disabled, we want to avoid this
- // style.removeAttribute is IE Only, but so apparently is this code path...
- style.removeAttribute( "filter" );
-
- // if there is no filter style applied in a css rule or unset inline opacity, we are done
- if ( value === "" || currentStyle && !currentStyle.filter ) {
- return;
- }
- }
-
- // otherwise, set new filter values
- style.filter = ralpha.test( filter ) ?
- filter.replace( ralpha, opacity ) :
- filter + " " + opacity;
- }
- };
-}
-
-// These hooks cannot be added until DOM ready because the support test
-// for it is not run until after DOM ready
-jQuery(function() {
- if ( !jQuery.support.reliableMarginRight ) {
- jQuery.cssHooks.marginRight = {
- get: function( elem, computed ) {
- if ( computed ) {
- // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- // Work around by temporarily setting element display to inline-block
- return jQuery.swap( elem, { "display": "inline-block" },
- curCSS, [ elem, "marginRight" ] );
- }
- }
- };
- }
-
- // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
- // getComputedStyle returns percent when specified for top/left/bottom/right
- // rather than make the css module depend on the offset module, we just check for it here
- if ( !jQuery.support.pixelPosition && jQuery.fn.position ) {
- jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = {
- get: function( elem, computed ) {
- if ( computed ) {
- computed = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
- return rnumnonpx.test( computed ) ?
- jQuery( elem ).position()[ prop ] + "px" :
- computed;
- }
- }
- };
- });
- }
-
-});
-
-if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.hidden = function( elem ) {
- // Support: Opera <= 12.12
- // Opera reports offsetWidths and offsetHeights less than zero on some elements
- return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
- (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
- };
-
- jQuery.expr.filters.visible = function( elem ) {
- return !jQuery.expr.filters.hidden( elem );
- };
-}
-
-// These hooks are used by animate to expand properties
-jQuery.each({
- margin: "",
- padding: "",
- border: "Width"
-}, function( prefix, suffix ) {
- jQuery.cssHooks[ prefix + suffix ] = {
- expand: function( value ) {
- var i = 0,
- expanded = {},
-
- // assumes a single number if not a string
- parts = typeof value === "string" ? value.split(" ") : [ value ];
-
- for ( ; i < 4; i++ ) {
- expanded[ prefix + cssExpand[ i ] + suffix ] =
- parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
- }
-
- return expanded;
- }
- };
-
- if ( !rmargin.test( prefix ) ) {
- jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
- }
-});
-var r20 = /%20/g,
- rbracket = /\[\]$/,
- rCRLF = /\r?\n/g,
- rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
- rsubmittable = /^(?:input|select|textarea|keygen)/i;
-
-jQuery.fn.extend({
- serialize: function() {
- return jQuery.param( this.serializeArray() );
- },
- serializeArray: function() {
- return this.map(function(){
- // Can add propHook for "elements" to filter or add form elements
- var elements = jQuery.prop( this, "elements" );
- return elements ? jQuery.makeArray( elements ) : this;
- })
- .filter(function(){
- var type = this.type;
- // Use .is(":disabled") so that fieldset[disabled] works
- return this.name && !jQuery( this ).is( ":disabled" ) &&
- rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
- ( this.checked || !manipulation_rcheckableType.test( type ) );
- })
- .map(function( i, elem ){
- var val = jQuery( this ).val();
-
- return val == null ?
- null :
- jQuery.isArray( val ) ?
- jQuery.map( val, function( val ){
- return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }) :
- { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
- }).get();
- }
-});
-
-//Serialize an array of form elements or a set of
-//key/values into a query string
-jQuery.param = function( a, traditional ) {
- var prefix,
- s = [],
- add = function( key, value ) {
- // If value is a function, invoke it and return its value
- value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
- s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
- };
-
- // Set traditional to true for jQuery <= 1.3.2 behavior.
- if ( traditional === undefined ) {
- traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
- }
-
- // If an array was passed in, assume that it is an array of form elements.
- if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
- // Serialize the form elements
- jQuery.each( a, function() {
- add( this.name, this.value );
- });
-
- } else {
- // If traditional, encode the "old" way (the way 1.3.2 or older
- // did it), otherwise encode params recursively.
- for ( prefix in a ) {
- buildParams( prefix, a[ prefix ], traditional, add );
- }
- }
-
- // Return the resulting serialization
- return s.join( "&" ).replace( r20, "+" );
-};
-
-function buildParams( prefix, obj, traditional, add ) {
- var name;
-
- if ( jQuery.isArray( obj ) ) {
- // Serialize array item.
- jQuery.each( obj, function( i, v ) {
- if ( traditional || rbracket.test( prefix ) ) {
- // Treat each array item as a scalar.
- add( prefix, v );
-
- } else {
- // Item is non-scalar (array or object), encode its numeric index.
- buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
- }
- });
-
- } else if ( !traditional && jQuery.type( obj ) === "object" ) {
- // Serialize object item.
- for ( name in obj ) {
- buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
- }
-
- } else {
- // Serialize scalar item.
- add( prefix, obj );
- }
-}
-jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
- "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
- "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
-
- // Handle event binding
- jQuery.fn[ name ] = function( data, fn ) {
- return arguments.length > 0 ?
- this.on( name, null, data, fn ) :
- this.trigger( name );
- };
-});
-
-jQuery.fn.hover = function( fnOver, fnOut ) {
- return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
-};
-var
- // Document location
- ajaxLocParts,
- ajaxLocation,
- ajax_nonce = jQuery.now(),
-
- ajax_rquery = /\?/,
- rhash = /#.*$/,
- rts = /([?&])_=[^&]*/,
- rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
- // #7653, #8125, #8152: local protocol detection
- rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
- rnoContent = /^(?:GET|HEAD)$/,
- rprotocol = /^\/\//,
- rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,
-
- // Keep a copy of the old load method
- _load = jQuery.fn.load,
-
- /* Prefilters
- * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
- * 2) These are called:
- * - BEFORE asking for a transport
- * - AFTER param serialization (s.data is a string if s.processData is true)
- * 3) key is the dataType
- * 4) the catchall symbol "*" can be used
- * 5) execution will start with transport dataType and THEN continue down to "*" if needed
- */
- prefilters = {},
-
- /* Transports bindings
- * 1) key is the dataType
- * 2) the catchall symbol "*" can be used
- * 3) selection will start with transport dataType and THEN go to "*" if needed
- */
- transports = {},
-
- // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
- allTypes = "*/".concat("*");
-
-// #8138, IE may throw an exception when accessing
-// a field from window.location if document.domain has been set
-try {
- ajaxLocation = location.href;
-} catch( e ) {
- // Use the href attribute of an A element
- // since IE will modify it given document.location
- ajaxLocation = document.createElement( "a" );
- ajaxLocation.href = "";
- ajaxLocation = ajaxLocation.href;
-}
-
-// Segment location into parts
-ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
-
-// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
-function addToPrefiltersOrTransports( structure ) {
-
- // dataTypeExpression is optional and defaults to "*"
- return function( dataTypeExpression, func ) {
-
- if ( typeof dataTypeExpression !== "string" ) {
- func = dataTypeExpression;
- dataTypeExpression = "*";
- }
-
- var dataType,
- i = 0,
- dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || [];
-
- if ( jQuery.isFunction( func ) ) {
- // For each dataType in the dataTypeExpression
- while ( (dataType = dataTypes[i++]) ) {
- // Prepend if requested
- if ( dataType[0] === "+" ) {
- dataType = dataType.slice( 1 ) || "*";
- (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
-
- // Otherwise append
- } else {
- (structure[ dataType ] = structure[ dataType ] || []).push( func );
- }
- }
- }
- };
-}
-
-// Base inspection function for prefilters and transports
-function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
-
- var inspected = {},
- seekingTransport = ( structure === transports );
-
- function inspect( dataType ) {
- var selected;
- inspected[ dataType ] = true;
- jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
- var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
- if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
- options.dataTypes.unshift( dataTypeOrTransport );
- inspect( dataTypeOrTransport );
- return false;
- } else if ( seekingTransport ) {
- return !( selected = dataTypeOrTransport );
- }
- });
- return selected;
- }
-
- return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
-}
-
-// A special extend for ajax options
-// that takes "flat" options (not to be deep extended)
-// Fixes #9887
-function ajaxExtend( target, src ) {
- var deep, key,
- flatOptions = jQuery.ajaxSettings.flatOptions || {};
-
- for ( key in src ) {
- if ( src[ key ] !== undefined ) {
- ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
- }
- }
- if ( deep ) {
- jQuery.extend( true, target, deep );
- }
-
- return target;
-}
-
-jQuery.fn.load = function( url, params, callback ) {
- if ( typeof url !== "string" && _load ) {
- return _load.apply( this, arguments );
- }
-
- var selector, response, type,
- self = this,
- off = url.indexOf(" ");
-
- if ( off >= 0 ) {
- selector = url.slice( off, url.length );
- url = url.slice( 0, off );
- }
-
- // If it's a function
- if ( jQuery.isFunction( params ) ) {
-
- // We assume that it's the callback
- callback = params;
- params = undefined;
-
- // Otherwise, build a param string
- } else if ( params && typeof params === "object" ) {
- type = "POST";
- }
-
- // If we have elements to modify, make the request
- if ( self.length > 0 ) {
- jQuery.ajax({
- url: url,
-
- // if "type" variable is undefined, then "GET" method will be used
- type: type,
- dataType: "html",
- data: params
- }).done(function( responseText ) {
-
- // Save response for use in complete callback
- response = arguments;
-
- self.html( selector ?
-
- // If a selector was specified, locate the right elements in a dummy div
- // Exclude scripts to avoid IE 'Permission Denied' errors
- jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
-
- // Otherwise use the full result
- responseText );
-
- }).complete( callback && function( jqXHR, status ) {
- self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
- });
- }
-
- return this;
-};
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){
- jQuery.fn[ type ] = function( fn ){
- return this.on( type, fn );
- };
-});
-
-jQuery.each( [ "get", "post" ], function( i, method ) {
- jQuery[ method ] = function( url, data, callback, type ) {
- // shift arguments if data argument was omitted
- if ( jQuery.isFunction( data ) ) {
- type = type || callback;
- callback = data;
- data = undefined;
- }
-
- return jQuery.ajax({
- url: url,
- type: method,
- dataType: type,
- data: data,
- success: callback
- });
- };
-});
-
-jQuery.extend({
-
- // Counter for holding the number of active queries
- active: 0,
-
- // Last-Modified header cache for next request
- lastModified: {},
- etag: {},
-
- ajaxSettings: {
- url: ajaxLocation,
- type: "GET",
- isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
- global: true,
- processData: true,
- async: true,
- contentType: "application/x-www-form-urlencoded; charset=UTF-8",
- /*
- timeout: 0,
- data: null,
- dataType: null,
- username: null,
- password: null,
- cache: null,
- throws: false,
- traditional: false,
- headers: {},
- */
-
- accepts: {
- "*": allTypes,
- text: "text/plain",
- html: "text/html",
- xml: "application/xml, text/xml",
- json: "application/json, text/javascript"
- },
-
- contents: {
- xml: /xml/,
- html: /html/,
- json: /json/
- },
-
- responseFields: {
- xml: "responseXML",
- text: "responseText"
- },
-
- // Data converters
- // Keys separate source (or catchall "*") and destination types with a single space
- converters: {
-
- // Convert anything to text
- "* text": window.String,
-
- // Text to html (true = no transformation)
- "text html": true,
-
- // Evaluate text as a json expression
- "text json": jQuery.parseJSON,
-
- // Parse text as xml
- "text xml": jQuery.parseXML
- },
-
- // For options that shouldn't be deep extended:
- // you can add your own custom options here if
- // and when you create one that shouldn't be
- // deep extended (see ajaxExtend)
- flatOptions: {
- url: true,
- context: true
- }
- },
-
- // Creates a full fledged settings object into target
- // with both ajaxSettings and settings fields.
- // If target is omitted, writes into ajaxSettings.
- ajaxSetup: function( target, settings ) {
- return settings ?
-
- // Building a settings object
- ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
-
- // Extending ajaxSettings
- ajaxExtend( jQuery.ajaxSettings, target );
- },
-
- ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
- ajaxTransport: addToPrefiltersOrTransports( transports ),
-
- // Main method
- ajax: function( url, options ) {
-
- // If url is an object, simulate pre-1.5 signature
- if ( typeof url === "object" ) {
- options = url;
- url = undefined;
- }
-
- // Force options to be an object
- options = options || {};
-
- var // Cross-domain detection vars
- parts,
- // Loop variable
- i,
- // URL without anti-cache param
- cacheURL,
- // Response headers as string
- responseHeadersString,
- // timeout handle
- timeoutTimer,
-
- // To know if global events are to be dispatched
- fireGlobals,
-
- transport,
- // Response headers
- responseHeaders,
- // Create the final options object
- s = jQuery.ajaxSetup( {}, options ),
- // Callbacks context
- callbackContext = s.context || s,
- // Context for global events is callbackContext if it is a DOM node or jQuery collection
- globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
- jQuery( callbackContext ) :
- jQuery.event,
- // Deferreds
- deferred = jQuery.Deferred(),
- completeDeferred = jQuery.Callbacks("once memory"),
- // Status-dependent callbacks
- statusCode = s.statusCode || {},
- // Headers (they are sent all at once)
- requestHeaders = {},
- requestHeadersNames = {},
- // The jqXHR state
- state = 0,
- // Default abort message
- strAbort = "canceled",
- // Fake xhr
- jqXHR = {
- readyState: 0,
-
- // Builds headers hashtable if needed
- getResponseHeader: function( key ) {
- var match;
- if ( state === 2 ) {
- if ( !responseHeaders ) {
- responseHeaders = {};
- while ( (match = rheaders.exec( responseHeadersString )) ) {
- responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
- }
- }
- match = responseHeaders[ key.toLowerCase() ];
- }
- return match == null ? null : match;
- },
-
- // Raw string
- getAllResponseHeaders: function() {
- return state === 2 ? responseHeadersString : null;
- },
-
- // Caches the header
- setRequestHeader: function( name, value ) {
- var lname = name.toLowerCase();
- if ( !state ) {
- name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
- requestHeaders[ name ] = value;
- }
- return this;
- },
-
- // Overrides response content-type header
- overrideMimeType: function( type ) {
- if ( !state ) {
- s.mimeType = type;
- }
- return this;
- },
-
- // Status-dependent callbacks
- statusCode: function( map ) {
- var code;
- if ( map ) {
- if ( state < 2 ) {
- for ( code in map ) {
- // Lazy-add the new callback in a way that preserves old ones
- statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
- }
- } else {
- // Execute the appropriate callbacks
- jqXHR.always( map[ jqXHR.status ] );
- }
- }
- return this;
- },
-
- // Cancel the request
- abort: function( statusText ) {
- var finalText = statusText || strAbort;
- if ( transport ) {
- transport.abort( finalText );
- }
- done( 0, finalText );
- return this;
- }
- };
-
- // Attach deferreds
- deferred.promise( jqXHR ).complete = completeDeferred.add;
- jqXHR.success = jqXHR.done;
- jqXHR.error = jqXHR.fail;
-
- // Remove hash character (#7531: and string promotion)
- // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
- // Handle falsy url in the settings object (#10093: consistency with old signature)
- // We also use the url parameter if available
- s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
-
- // Alias method option to type as per ticket #12004
- s.type = options.method || options.type || s.method || s.type;
-
- // Extract dataTypes list
- s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""];
-
- // A cross-domain request is in order when we have a protocol:host:port mismatch
- if ( s.crossDomain == null ) {
- parts = rurl.exec( s.url.toLowerCase() );
- s.crossDomain = !!( parts &&
- ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
- ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
- ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
- );
- }
-
- // Convert data if not already a string
- if ( s.data && s.processData && typeof s.data !== "string" ) {
- s.data = jQuery.param( s.data, s.traditional );
- }
-
- // Apply prefilters
- inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
-
- // If request was aborted inside a prefilter, stop there
- if ( state === 2 ) {
- return jqXHR;
- }
-
- // We can fire global events as of now if asked to
- fireGlobals = s.global;
-
- // Watch for a new set of requests
- if ( fireGlobals && jQuery.active++ === 0 ) {
- jQuery.event.trigger("ajaxStart");
- }
-
- // Uppercase the type
- s.type = s.type.toUpperCase();
-
- // Determine if request has content
- s.hasContent = !rnoContent.test( s.type );
-
- // Save the URL in case we're toying with the If-Modified-Since
- // and/or If-None-Match header later on
- cacheURL = s.url;
-
- // More options handling for requests with no content
- if ( !s.hasContent ) {
-
- // If data is available, append data to url
- if ( s.data ) {
- cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
- // #9682: remove data so that it's not used in an eventual retry
- delete s.data;
- }
-
- // Add anti-cache in url if needed
- if ( s.cache === false ) {
- s.url = rts.test( cacheURL ) ?
-
- // If there is already a '_' parameter, set its value
- cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) :
-
- // Otherwise add one to the end
- cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++;
- }
- }
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- if ( jQuery.lastModified[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
- }
- if ( jQuery.etag[ cacheURL ] ) {
- jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
- }
- }
-
- // Set the correct header, if data is being sent
- if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
- jqXHR.setRequestHeader( "Content-Type", s.contentType );
- }
-
- // Set the Accepts header for the server, depending on the dataType
- jqXHR.setRequestHeader(
- "Accept",
- s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
- s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
- s.accepts[ "*" ]
- );
-
- // Check for headers option
- for ( i in s.headers ) {
- jqXHR.setRequestHeader( i, s.headers[ i ] );
- }
-
- // Allow custom headers/mimetypes and early abort
- if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
- // Abort if not done already and return
- return jqXHR.abort();
- }
-
- // aborting is no longer a cancellation
- strAbort = "abort";
-
- // Install callbacks on deferreds
- for ( i in { success: 1, error: 1, complete: 1 } ) {
- jqXHR[ i ]( s[ i ] );
- }
-
- // Get transport
- transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
-
- // If no transport, we auto-abort
- if ( !transport ) {
- done( -1, "No Transport" );
- } else {
- jqXHR.readyState = 1;
-
- // Send global event
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
- }
- // Timeout
- if ( s.async && s.timeout > 0 ) {
- timeoutTimer = setTimeout(function() {
- jqXHR.abort("timeout");
- }, s.timeout );
- }
-
- try {
- state = 1;
- transport.send( requestHeaders, done );
- } catch ( e ) {
- // Propagate exception as error if not done
- if ( state < 2 ) {
- done( -1, e );
- // Simply rethrow otherwise
- } else {
- throw e;
- }
- }
- }
-
- // Callback for when everything is done
- function done( status, nativeStatusText, responses, headers ) {
- var isSuccess, success, error, response, modified,
- statusText = nativeStatusText;
-
- // Called once
- if ( state === 2 ) {
- return;
- }
-
- // State is "done" now
- state = 2;
-
- // Clear timeout if it exists
- if ( timeoutTimer ) {
- clearTimeout( timeoutTimer );
- }
-
- // Dereference transport for early garbage collection
- // (no matter how long the jqXHR object will be used)
- transport = undefined;
-
- // Cache response headers
- responseHeadersString = headers || "";
-
- // Set readyState
- jqXHR.readyState = status > 0 ? 4 : 0;
-
- // Get response data
- if ( responses ) {
- response = ajaxHandleResponses( s, jqXHR, responses );
- }
-
- // If successful, handle type chaining
- if ( status >= 200 && status < 300 || status === 304 ) {
-
- // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
- if ( s.ifModified ) {
- modified = jqXHR.getResponseHeader("Last-Modified");
- if ( modified ) {
- jQuery.lastModified[ cacheURL ] = modified;
- }
- modified = jqXHR.getResponseHeader("etag");
- if ( modified ) {
- jQuery.etag[ cacheURL ] = modified;
- }
- }
-
- // if no content
- if ( status === 204 ) {
- isSuccess = true;
- statusText = "nocontent";
-
- // if not modified
- } else if ( status === 304 ) {
- isSuccess = true;
- statusText = "notmodified";
-
- // If we have data, let's convert it
- } else {
- isSuccess = ajaxConvert( s, response );
- statusText = isSuccess.state;
- success = isSuccess.data;
- error = isSuccess.error;
- isSuccess = !error;
- }
- } else {
- // We extract error from statusText
- // then normalize statusText and status for non-aborts
- error = statusText;
- if ( status || !statusText ) {
- statusText = "error";
- if ( status < 0 ) {
- status = 0;
- }
- }
- }
-
- // Set data for the fake xhr object
- jqXHR.status = status;
- jqXHR.statusText = ( nativeStatusText || statusText ) + "";
-
- // Success/Error
- if ( isSuccess ) {
- deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
- } else {
- deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
- }
-
- // Status-dependent callbacks
- jqXHR.statusCode( statusCode );
- statusCode = undefined;
-
- if ( fireGlobals ) {
- globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
- [ jqXHR, s, isSuccess ? success : error ] );
- }
-
- // Complete
- completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
-
- if ( fireGlobals ) {
- globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
- // Handle the global AJAX counter
- if ( !( --jQuery.active ) ) {
- jQuery.event.trigger("ajaxStop");
- }
- }
- }
-
- return jqXHR;
- },
-
- getScript: function( url, callback ) {
- return jQuery.get( url, undefined, callback, "script" );
- },
-
- getJSON: function( url, data, callback ) {
- return jQuery.get( url, data, callback, "json" );
- }
-});
-
-/* Handles responses to an ajax request:
- * - sets all responseXXX fields accordingly
- * - finds the right dataType (mediates between content-type and expected dataType)
- * - returns the corresponding response
- */
-function ajaxHandleResponses( s, jqXHR, responses ) {
- var firstDataType, ct, finalDataType, type,
- contents = s.contents,
- dataTypes = s.dataTypes,
- responseFields = s.responseFields;
-
- // Fill responseXXX fields
- for ( type in responseFields ) {
- if ( type in responses ) {
- jqXHR[ responseFields[type] ] = responses[ type ];
- }
- }
-
- // Remove auto dataType and get content-type in the process
- while( dataTypes[ 0 ] === "*" ) {
- dataTypes.shift();
- if ( ct === undefined ) {
- ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
- }
- }
-
- // Check if we're dealing with a known content-type
- if ( ct ) {
- for ( type in contents ) {
- if ( contents[ type ] && contents[ type ].test( ct ) ) {
- dataTypes.unshift( type );
- break;
- }
- }
- }
-
- // Check to see if we have a response for the expected dataType
- if ( dataTypes[ 0 ] in responses ) {
- finalDataType = dataTypes[ 0 ];
- } else {
- // Try convertible dataTypes
- for ( type in responses ) {
- if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
- finalDataType = type;
- break;
- }
- if ( !firstDataType ) {
- firstDataType = type;
- }
- }
- // Or just use first one
- finalDataType = finalDataType || firstDataType;
- }
-
- // If we found a dataType
- // We add the dataType to the list if needed
- // and return the corresponding response
- if ( finalDataType ) {
- if ( finalDataType !== dataTypes[ 0 ] ) {
- dataTypes.unshift( finalDataType );
- }
- return responses[ finalDataType ];
- }
-}
-
-// Chain conversions given the request and the original response
-function ajaxConvert( s, response ) {
- var conv2, current, conv, tmp,
- converters = {},
- i = 0,
- // Work with a copy of dataTypes in case we need to modify it for conversion
- dataTypes = s.dataTypes.slice(),
- prev = dataTypes[ 0 ];
-
- // Apply the dataFilter if provided
- if ( s.dataFilter ) {
- response = s.dataFilter( response, s.dataType );
- }
-
- // Create converters map with lowercased keys
- if ( dataTypes[ 1 ] ) {
- for ( conv in s.converters ) {
- converters[ conv.toLowerCase() ] = s.converters[ conv ];
- }
- }
-
- // Convert to each sequential dataType, tolerating list modification
- for ( ; (current = dataTypes[++i]); ) {
-
- // There's only work to do if current dataType is non-auto
- if ( current !== "*" ) {
-
- // Convert response if prev dataType is non-auto and differs from current
- if ( prev !== "*" && prev !== current ) {
-
- // Seek a direct converter
- conv = converters[ prev + " " + current ] || converters[ "* " + current ];
-
- // If none found, seek a pair
- if ( !conv ) {
- for ( conv2 in converters ) {
-
- // If conv2 outputs current
- tmp = conv2.split(" ");
- if ( tmp[ 1 ] === current ) {
-
- // If prev can be converted to accepted input
- conv = converters[ prev + " " + tmp[ 0 ] ] ||
- converters[ "* " + tmp[ 0 ] ];
- if ( conv ) {
- // Condense equivalence converters
- if ( conv === true ) {
- conv = converters[ conv2 ];
-
- // Otherwise, insert the intermediate dataType
- } else if ( converters[ conv2 ] !== true ) {
- current = tmp[ 0 ];
- dataTypes.splice( i--, 0, current );
- }
-
- break;
- }
- }
- }
- }
-
- // Apply converter (if not an equivalence)
- if ( conv !== true ) {
-
- // Unless errors are allowed to bubble, catch and return them
- if ( conv && s["throws"] ) {
- response = conv( response );
- } else {
- try {
- response = conv( response );
- } catch ( e ) {
- return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
- }
- }
- }
- }
-
- // Update prev for next iteration
- prev = current;
- }
- }
-
- return { state: "success", data: response };
-}
-// Install script dataType
-jQuery.ajaxSetup({
- accepts: {
- script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
- },
- contents: {
- script: /(?:java|ecma)script/
- },
- converters: {
- "text script": function( text ) {
- jQuery.globalEval( text );
- return text;
- }
- }
-});
-
-// Handle cache's special case and global
-jQuery.ajaxPrefilter( "script", function( s ) {
- if ( s.cache === undefined ) {
- s.cache = false;
- }
- if ( s.crossDomain ) {
- s.type = "GET";
- s.global = false;
- }
-});
-
-// Bind script tag hack transport
-jQuery.ajaxTransport( "script", function(s) {
-
- // This transport only deals with cross domain requests
- if ( s.crossDomain ) {
-
- var script,
- head = document.head || jQuery("head")[0] || document.documentElement;
-
- return {
-
- send: function( _, callback ) {
-
- script = document.createElement("script");
-
- script.async = true;
-
- if ( s.scriptCharset ) {
- script.charset = s.scriptCharset;
- }
-
- script.src = s.url;
-
- // Attach handlers for all browsers
- script.onload = script.onreadystatechange = function( _, isAbort ) {
-
- if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
-
- // Handle memory leak in IE
- script.onload = script.onreadystatechange = null;
-
- // Remove the script
- if ( script.parentNode ) {
- script.parentNode.removeChild( script );
- }
-
- // Dereference the script
- script = null;
-
- // Callback if not abort
- if ( !isAbort ) {
- callback( 200, "success" );
- }
- }
- };
-
- // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
- // Use native DOM manipulation to avoid our domManip AJAX trickery
- head.insertBefore( script, head.firstChild );
- },
-
- abort: function() {
- if ( script ) {
- script.onload( undefined, true );
- }
- }
- };
- }
-});
-var oldCallbacks = [],
- rjsonp = /(=)\?(?=&|$)|\?\?/;
-
-// Default jsonp settings
-jQuery.ajaxSetup({
- jsonp: "callback",
- jsonpCallback: function() {
- var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) );
- this[ callback ] = true;
- return callback;
- }
-});
-
-// Detect, normalize options and install callbacks for jsonp requests
-jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
-
- var callbackName, overwritten, responseContainer,
- jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
- "url" :
- typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
- );
-
- // Handle iff the expected data type is "jsonp" or we have a parameter to set
- if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
-
- // Get callback name, remembering preexisting value associated with it
- callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
- s.jsonpCallback() :
- s.jsonpCallback;
-
- // Insert callback into url or form data
- if ( jsonProp ) {
- s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
- } else if ( s.jsonp !== false ) {
- s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
- }
-
- // Use data converter to retrieve json after script execution
- s.converters["script json"] = function() {
- if ( !responseContainer ) {
- jQuery.error( callbackName + " was not called" );
- }
- return responseContainer[ 0 ];
- };
-
- // force json dataType
- s.dataTypes[ 0 ] = "json";
-
- // Install callback
- overwritten = window[ callbackName ];
- window[ callbackName ] = function() {
- responseContainer = arguments;
- };
-
- // Clean-up function (fires after converters)
- jqXHR.always(function() {
- // Restore preexisting value
- window[ callbackName ] = overwritten;
-
- // Save back as free
- if ( s[ callbackName ] ) {
- // make sure that re-using the options doesn't screw things around
- s.jsonpCallback = originalSettings.jsonpCallback;
-
- // save the callback name for future use
- oldCallbacks.push( callbackName );
- }
-
- // Call if it was a function and we have a response
- if ( responseContainer && jQuery.isFunction( overwritten ) ) {
- overwritten( responseContainer[ 0 ] );
- }
-
- responseContainer = overwritten = undefined;
- });
-
- // Delegate to script
- return "script";
- }
-});
-var xhrCallbacks, xhrSupported,
- xhrId = 0,
- // #5280: Internet Explorer will keep connections alive if we don't abort on unload
- xhrOnUnloadAbort = window.ActiveXObject && function() {
- // Abort all pending requests
- var key;
- for ( key in xhrCallbacks ) {
- xhrCallbacks[ key ]( undefined, true );
- }
- };
-
-// Functions to create xhrs
-function createStandardXHR() {
- try {
- return new window.XMLHttpRequest();
- } catch( e ) {}
-}
-
-function createActiveXHR() {
- try {
- return new window.ActiveXObject("Microsoft.XMLHTTP");
- } catch( e ) {}
-}
-
-// Create the request object
-// (This is still attached to ajaxSettings for backward compatibility)
-jQuery.ajaxSettings.xhr = window.ActiveXObject ?
- /* Microsoft failed to properly
- * implement the XMLHttpRequest in IE7 (can't request local files),
- * so we use the ActiveXObject when it is available
- * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
- * we need a fallback.
- */
- function() {
- return !this.isLocal && createStandardXHR() || createActiveXHR();
- } :
- // For all other browsers, use the standard XMLHttpRequest object
- createStandardXHR;
-
-// Determine support properties
-xhrSupported = jQuery.ajaxSettings.xhr();
-jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
-xhrSupported = jQuery.support.ajax = !!xhrSupported;
-
-// Create transport if the browser can provide an xhr
-if ( xhrSupported ) {
-
- jQuery.ajaxTransport(function( s ) {
- // Cross domain only allowed if supported through XMLHttpRequest
- if ( !s.crossDomain || jQuery.support.cors ) {
-
- var callback;
-
- return {
- send: function( headers, complete ) {
-
- // Get a new xhr
- var handle, i,
- xhr = s.xhr();
-
- // Open the socket
- // Passing null username, generates a login popup on Opera (#2865)
- if ( s.username ) {
- xhr.open( s.type, s.url, s.async, s.username, s.password );
- } else {
- xhr.open( s.type, s.url, s.async );
- }
-
- // Apply custom fields if provided
- if ( s.xhrFields ) {
- for ( i in s.xhrFields ) {
- xhr[ i ] = s.xhrFields[ i ];
- }
- }
-
- // Override mime type if needed
- if ( s.mimeType && xhr.overrideMimeType ) {
- xhr.overrideMimeType( s.mimeType );
- }
-
- // X-Requested-With header
- // For cross-domain requests, seeing as conditions for a preflight are
- // akin to a jigsaw puzzle, we simply never set it to be sure.
- // (it can always be set on a per-request basis or even using ajaxSetup)
- // For same-domain requests, won't change header if already provided.
- if ( !s.crossDomain && !headers["X-Requested-With"] ) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- // Need an extra try/catch for cross domain requests in Firefox 3
- try {
- for ( i in headers ) {
- xhr.setRequestHeader( i, headers[ i ] );
- }
- } catch( err ) {}
-
- // Do send the request
- // This may raise an exception which is actually
- // handled in jQuery.ajax (so no try/catch here)
- xhr.send( ( s.hasContent && s.data ) || null );
-
- // Listener
- callback = function( _, isAbort ) {
- var status, responseHeaders, statusText, responses;
-
- // Firefox throws exceptions when accessing properties
- // of an xhr when a network error occurred
- // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
- try {
-
- // Was never called and is aborted or complete
- if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
-
- // Only called once
- callback = undefined;
-
- // Do not keep as active anymore
- if ( handle ) {
- xhr.onreadystatechange = jQuery.noop;
- if ( xhrOnUnloadAbort ) {
- delete xhrCallbacks[ handle ];
- }
- }
-
- // If it's an abort
- if ( isAbort ) {
- // Abort it manually if needed
- if ( xhr.readyState !== 4 ) {
- xhr.abort();
- }
- } else {
- responses = {};
- status = xhr.status;
- responseHeaders = xhr.getAllResponseHeaders();
-
- // When requesting binary data, IE6-9 will throw an exception
- // on any attempt to access responseText (#11426)
- if ( typeof xhr.responseText === "string" ) {
- responses.text = xhr.responseText;
- }
-
- // Firefox throws an exception when accessing
- // statusText for faulty cross-domain requests
- try {
- statusText = xhr.statusText;
- } catch( e ) {
- // We normalize with Webkit giving an empty statusText
- statusText = "";
- }
-
- // Filter status for non standard behaviors
-
- // If the request is local and we have data: assume a success
- // (success with no data won't get notified, that's the best we
- // can do given current implementations)
- if ( !status && s.isLocal && !s.crossDomain ) {
- status = responses.text ? 200 : 404;
- // IE - #1450: sometimes returns 1223 when it should be 204
- } else if ( status === 1223 ) {
- status = 204;
- }
- }
- }
- } catch( firefoxAccessException ) {
- if ( !isAbort ) {
- complete( -1, firefoxAccessException );
- }
- }
-
- // Call complete if needed
- if ( responses ) {
- complete( status, statusText, responses, responseHeaders );
- }
- };
-
- if ( !s.async ) {
- // if we're in sync mode we fire the callback
- callback();
- } else if ( xhr.readyState === 4 ) {
- // (IE6 & IE7) if it's in cache and has been
- // retrieved directly we need to fire the callback
- setTimeout( callback );
- } else {
- handle = ++xhrId;
- if ( xhrOnUnloadAbort ) {
- // Create the active xhrs callbacks list if needed
- // and attach the unload handler
- if ( !xhrCallbacks ) {
- xhrCallbacks = {};
- jQuery( window ).unload( xhrOnUnloadAbort );
- }
- // Add to list of active xhrs callbacks
- xhrCallbacks[ handle ] = callback;
- }
- xhr.onreadystatechange = callback;
- }
- },
-
- abort: function() {
- if ( callback ) {
- callback( undefined, true );
- }
- }
- };
- }
- });
-}
-var fxNow, timerId,
- rfxtypes = /^(?:toggle|show|hide)$/,
- rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ),
- rrun = /queueHooks$/,
- animationPrefilters = [ defaultPrefilter ],
- tweeners = {
- "*": [function( prop, value ) {
- var end, unit,
- tween = this.createTween( prop, value ),
- parts = rfxnum.exec( value ),
- target = tween.cur(),
- start = +target || 0,
- scale = 1,
- maxIterations = 20;
-
- if ( parts ) {
- end = +parts[2];
- unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" );
-
- // We need to compute starting value
- if ( unit !== "px" && start ) {
- // Iteratively approximate from a nonzero starting point
- // Prefer the current property, because this process will be trivial if it uses the same units
- // Fallback to end or a simple constant
- start = jQuery.css( tween.elem, prop, true ) || end || 1;
-
- do {
- // If previous iteration zeroed out, double until we get *something*
- // Use a string for doubling factor so we don't accidentally see scale as unchanged below
- scale = scale || ".5";
-
- // Adjust and apply
- start = start / scale;
- jQuery.style( tween.elem, prop, start + unit );
-
- // Update scale, tolerating zero or NaN from tween.cur()
- // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
- } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
- }
-
- tween.unit = unit;
- tween.start = start;
- // If a +=/-= token was provided, we're doing a relative animation
- tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end;
- }
- return tween;
- }]
- };
-
-// Animations created synchronously will run synchronously
-function createFxNow() {
- setTimeout(function() {
- fxNow = undefined;
- });
- return ( fxNow = jQuery.now() );
-}
-
-function createTweens( animation, props ) {
- jQuery.each( props, function( prop, value ) {
- var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
- index = 0,
- length = collection.length;
- for ( ; index < length; index++ ) {
- if ( collection[ index ].call( animation, prop, value ) ) {
-
- // we're done with this property
- return;
- }
- }
- });
-}
-
-function Animation( elem, properties, options ) {
- var result,
- stopped,
- index = 0,
- length = animationPrefilters.length,
- deferred = jQuery.Deferred().always( function() {
- // don't match elem in the :animated selector
- delete tick.elem;
- }),
- tick = function() {
- if ( stopped ) {
- return false;
- }
- var currentTime = fxNow || createFxNow(),
- remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
- // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
- temp = remaining / animation.duration || 0,
- percent = 1 - temp,
- index = 0,
- length = animation.tweens.length;
-
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( percent );
- }
-
- deferred.notifyWith( elem, [ animation, percent, remaining ]);
-
- if ( percent < 1 && length ) {
- return remaining;
- } else {
- deferred.resolveWith( elem, [ animation ] );
- return false;
- }
- },
- animation = deferred.promise({
- elem: elem,
- props: jQuery.extend( {}, properties ),
- opts: jQuery.extend( true, { specialEasing: {} }, options ),
- originalProperties: properties,
- originalOptions: options,
- startTime: fxNow || createFxNow(),
- duration: options.duration,
- tweens: [],
- createTween: function( prop, end ) {
- var tween = jQuery.Tween( elem, animation.opts, prop, end,
- animation.opts.specialEasing[ prop ] || animation.opts.easing );
- animation.tweens.push( tween );
- return tween;
- },
- stop: function( gotoEnd ) {
- var index = 0,
- // if we are going to the end, we want to run all the tweens
- // otherwise we skip this part
- length = gotoEnd ? animation.tweens.length : 0;
- if ( stopped ) {
- return this;
- }
- stopped = true;
- for ( ; index < length ; index++ ) {
- animation.tweens[ index ].run( 1 );
- }
-
- // resolve when we played the last frame
- // otherwise, reject
- if ( gotoEnd ) {
- deferred.resolveWith( elem, [ animation, gotoEnd ] );
- } else {
- deferred.rejectWith( elem, [ animation, gotoEnd ] );
- }
- return this;
- }
- }),
- props = animation.props;
-
- propFilter( props, animation.opts.specialEasing );
-
- for ( ; index < length ; index++ ) {
- result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
- if ( result ) {
- return result;
- }
- }
-
- createTweens( animation, props );
-
- if ( jQuery.isFunction( animation.opts.start ) ) {
- animation.opts.start.call( elem, animation );
- }
-
- jQuery.fx.timer(
- jQuery.extend( tick, {
- elem: elem,
- anim: animation,
- queue: animation.opts.queue
- })
- );
-
- // attach callbacks from options
- return animation.progress( animation.opts.progress )
- .done( animation.opts.done, animation.opts.complete )
- .fail( animation.opts.fail )
- .always( animation.opts.always );
-}
-
-function propFilter( props, specialEasing ) {
- var value, name, index, easing, hooks;
-
- // camelCase, specialEasing and expand cssHook pass
- for ( index in props ) {
- name = jQuery.camelCase( index );
- easing = specialEasing[ name ];
- value = props[ index ];
- if ( jQuery.isArray( value ) ) {
- easing = value[ 1 ];
- value = props[ index ] = value[ 0 ];
- }
-
- if ( index !== name ) {
- props[ name ] = value;
- delete props[ index ];
- }
-
- hooks = jQuery.cssHooks[ name ];
- if ( hooks && "expand" in hooks ) {
- value = hooks.expand( value );
- delete props[ name ];
-
- // not quite $.extend, this wont overwrite keys already present.
- // also - reusing 'index' from above because we have the correct "name"
- for ( index in value ) {
- if ( !( index in props ) ) {
- props[ index ] = value[ index ];
- specialEasing[ index ] = easing;
- }
- }
- } else {
- specialEasing[ name ] = easing;
- }
- }
-}
-
-jQuery.Animation = jQuery.extend( Animation, {
-
- tweener: function( props, callback ) {
- if ( jQuery.isFunction( props ) ) {
- callback = props;
- props = [ "*" ];
- } else {
- props = props.split(" ");
- }
-
- var prop,
- index = 0,
- length = props.length;
-
- for ( ; index < length ; index++ ) {
- prop = props[ index ];
- tweeners[ prop ] = tweeners[ prop ] || [];
- tweeners[ prop ].unshift( callback );
- }
- },
-
- prefilter: function( callback, prepend ) {
- if ( prepend ) {
- animationPrefilters.unshift( callback );
- } else {
- animationPrefilters.push( callback );
- }
- }
-});
-
-function defaultPrefilter( elem, props, opts ) {
- /*jshint validthis:true */
- var prop, index, length,
- value, dataShow, toggle,
- tween, hooks, oldfire,
- anim = this,
- style = elem.style,
- orig = {},
- handled = [],
- hidden = elem.nodeType && isHidden( elem );
-
- // handle queue: false promises
- if ( !opts.queue ) {
- hooks = jQuery._queueHooks( elem, "fx" );
- if ( hooks.unqueued == null ) {
- hooks.unqueued = 0;
- oldfire = hooks.empty.fire;
- hooks.empty.fire = function() {
- if ( !hooks.unqueued ) {
- oldfire();
- }
- };
- }
- hooks.unqueued++;
-
- anim.always(function() {
- // doing this makes sure that the complete handler will be called
- // before this completes
- anim.always(function() {
- hooks.unqueued--;
- if ( !jQuery.queue( elem, "fx" ).length ) {
- hooks.empty.fire();
- }
- });
- });
- }
-
- // height/width overflow pass
- if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
- // Make sure that nothing sneaks out
- // Record all 3 overflow attributes because IE does not
- // change the overflow attribute when overflowX and
- // overflowY are set to the same value
- opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
-
- // Set display property to inline-block for height/width
- // animations on inline elements that are having width/height animated
- if ( jQuery.css( elem, "display" ) === "inline" &&
- jQuery.css( elem, "float" ) === "none" ) {
-
- // inline-level elements accept inline-block;
- // block-level elements need to be inline with layout
- if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) {
- style.display = "inline-block";
-
- } else {
- style.zoom = 1;
- }
- }
- }
-
- if ( opts.overflow ) {
- style.overflow = "hidden";
- if ( !jQuery.support.shrinkWrapBlocks ) {
- anim.always(function() {
- style.overflow = opts.overflow[ 0 ];
- style.overflowX = opts.overflow[ 1 ];
- style.overflowY = opts.overflow[ 2 ];
- });
- }
- }
-
-
- // show/hide pass
- for ( index in props ) {
- value = props[ index ];
- if ( rfxtypes.exec( value ) ) {
- delete props[ index ];
- toggle = toggle || value === "toggle";
- if ( value === ( hidden ? "hide" : "show" ) ) {
- continue;
- }
- handled.push( index );
- }
- }
-
- length = handled.length;
- if ( length ) {
- dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} );
- if ( "hidden" in dataShow ) {
- hidden = dataShow.hidden;
- }
-
- // store state if its toggle - enables .stop().toggle() to "reverse"
- if ( toggle ) {
- dataShow.hidden = !hidden;
- }
- if ( hidden ) {
- jQuery( elem ).show();
- } else {
- anim.done(function() {
- jQuery( elem ).hide();
- });
- }
- anim.done(function() {
- var prop;
- jQuery._removeData( elem, "fxshow" );
- for ( prop in orig ) {
- jQuery.style( elem, prop, orig[ prop ] );
- }
- });
- for ( index = 0 ; index < length ; index++ ) {
- prop = handled[ index ];
- tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 );
- orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop );
-
- if ( !( prop in dataShow ) ) {
- dataShow[ prop ] = tween.start;
- if ( hidden ) {
- tween.end = tween.start;
- tween.start = prop === "width" || prop === "height" ? 1 : 0;
- }
- }
- }
- }
-}
-
-function Tween( elem, options, prop, end, easing ) {
- return new Tween.prototype.init( elem, options, prop, end, easing );
-}
-jQuery.Tween = Tween;
-
-Tween.prototype = {
- constructor: Tween,
- init: function( elem, options, prop, end, easing, unit ) {
- this.elem = elem;
- this.prop = prop;
- this.easing = easing || "swing";
- this.options = options;
- this.start = this.now = this.cur();
- this.end = end;
- this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
- },
- cur: function() {
- var hooks = Tween.propHooks[ this.prop ];
-
- return hooks && hooks.get ?
- hooks.get( this ) :
- Tween.propHooks._default.get( this );
- },
- run: function( percent ) {
- var eased,
- hooks = Tween.propHooks[ this.prop ];
-
- if ( this.options.duration ) {
- this.pos = eased = jQuery.easing[ this.easing ](
- percent, this.options.duration * percent, 0, 1, this.options.duration
- );
- } else {
- this.pos = eased = percent;
- }
- this.now = ( this.end - this.start ) * eased + this.start;
-
- if ( this.options.step ) {
- this.options.step.call( this.elem, this.now, this );
- }
-
- if ( hooks && hooks.set ) {
- hooks.set( this );
- } else {
- Tween.propHooks._default.set( this );
- }
- return this;
- }
-};
-
-Tween.prototype.init.prototype = Tween.prototype;
-
-Tween.propHooks = {
- _default: {
- get: function( tween ) {
- var result;
-
- if ( tween.elem[ tween.prop ] != null &&
- (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
- return tween.elem[ tween.prop ];
- }
-
- // passing an empty string as a 3rd parameter to .css will automatically
- // attempt a parseFloat and fallback to a string if the parse fails
- // so, simple values such as "10px" are parsed to Float.
- // complex values such as "rotate(1rad)" are returned as is.
- result = jQuery.css( tween.elem, tween.prop, "" );
- // Empty strings, null, undefined and "auto" are converted to 0.
- return !result || result === "auto" ? 0 : result;
- },
- set: function( tween ) {
- // use step hook for back compat - use cssHook if its there - use .style if its
- // available and use plain properties where available
- if ( jQuery.fx.step[ tween.prop ] ) {
- jQuery.fx.step[ tween.prop ]( tween );
- } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
- jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
- } else {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
- }
-};
-
-// Remove in 2.0 - this supports IE8's panic based approach
-// to setting things on disconnected nodes
-
-Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
- set: function( tween ) {
- if ( tween.elem.nodeType && tween.elem.parentNode ) {
- tween.elem[ tween.prop ] = tween.now;
- }
- }
-};
-
-jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
- var cssFn = jQuery.fn[ name ];
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return speed == null || typeof speed === "boolean" ?
- cssFn.apply( this, arguments ) :
- this.animate( genFx( name, true ), speed, easing, callback );
- };
-});
-
-jQuery.fn.extend({
- fadeTo: function( speed, to, easing, callback ) {
-
- // show any hidden elements after setting opacity to 0
- return this.filter( isHidden ).css( "opacity", 0 ).show()
-
- // animate to the value specified
- .end().animate({ opacity: to }, speed, easing, callback );
- },
- animate: function( prop, speed, easing, callback ) {
- var empty = jQuery.isEmptyObject( prop ),
- optall = jQuery.speed( speed, easing, callback ),
- doAnimation = function() {
- // Operate on a copy of prop so per-property easing won't be lost
- var anim = Animation( this, jQuery.extend( {}, prop ), optall );
- doAnimation.finish = function() {
- anim.stop( true );
- };
- // Empty animations, or finishing resolves immediately
- if ( empty || jQuery._data( this, "finish" ) ) {
- anim.stop( true );
- }
- };
- doAnimation.finish = doAnimation;
-
- return empty || optall.queue === false ?
- this.each( doAnimation ) :
- this.queue( optall.queue, doAnimation );
- },
- stop: function( type, clearQueue, gotoEnd ) {
- var stopQueue = function( hooks ) {
- var stop = hooks.stop;
- delete hooks.stop;
- stop( gotoEnd );
- };
-
- if ( typeof type !== "string" ) {
- gotoEnd = clearQueue;
- clearQueue = type;
- type = undefined;
- }
- if ( clearQueue && type !== false ) {
- this.queue( type || "fx", [] );
- }
-
- return this.each(function() {
- var dequeue = true,
- index = type != null && type + "queueHooks",
- timers = jQuery.timers,
- data = jQuery._data( this );
-
- if ( index ) {
- if ( data[ index ] && data[ index ].stop ) {
- stopQueue( data[ index ] );
- }
- } else {
- for ( index in data ) {
- if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
- stopQueue( data[ index ] );
- }
- }
- }
-
- for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
- timers[ index ].anim.stop( gotoEnd );
- dequeue = false;
- timers.splice( index, 1 );
- }
- }
-
- // start the next in the queue if the last step wasn't forced
- // timers currently will call their complete callbacks, which will dequeue
- // but only if they were gotoEnd
- if ( dequeue || !gotoEnd ) {
- jQuery.dequeue( this, type );
- }
- });
- },
- finish: function( type ) {
- if ( type !== false ) {
- type = type || "fx";
- }
- return this.each(function() {
- var index,
- data = jQuery._data( this ),
- queue = data[ type + "queue" ],
- hooks = data[ type + "queueHooks" ],
- timers = jQuery.timers,
- length = queue ? queue.length : 0;
-
- // enable finishing flag on private data
- data.finish = true;
-
- // empty the queue first
- jQuery.queue( this, type, [] );
-
- if ( hooks && hooks.cur && hooks.cur.finish ) {
- hooks.cur.finish.call( this );
- }
-
- // look for any active animations, and finish them
- for ( index = timers.length; index--; ) {
- if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
- timers[ index ].anim.stop( true );
- timers.splice( index, 1 );
- }
- }
-
- // look for any animations in the old queue and finish them
- for ( index = 0; index < length; index++ ) {
- if ( queue[ index ] && queue[ index ].finish ) {
- queue[ index ].finish.call( this );
- }
- }
-
- // turn off finishing flag
- delete data.finish;
- });
- }
-});
-
-// Generate parameters to create a standard animation
-function genFx( type, includeWidth ) {
- var which,
- attrs = { height: type },
- i = 0;
-
- // if we include width, step value is 1 to do all cssExpand values,
- // if we don't include width, step value is 2 to skip over Left and Right
- includeWidth = includeWidth? 1 : 0;
- for( ; i < 4 ; i += 2 - includeWidth ) {
- which = cssExpand[ i ];
- attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
- }
-
- if ( includeWidth ) {
- attrs.opacity = attrs.width = type;
- }
-
- return attrs;
-}
-
-// Generate shortcuts for custom animations
-jQuery.each({
- slideDown: genFx("show"),
- slideUp: genFx("hide"),
- slideToggle: genFx("toggle"),
- fadeIn: { opacity: "show" },
- fadeOut: { opacity: "hide" },
- fadeToggle: { opacity: "toggle" }
-}, function( name, props ) {
- jQuery.fn[ name ] = function( speed, easing, callback ) {
- return this.animate( props, speed, easing, callback );
- };
-});
-
-jQuery.speed = function( speed, easing, fn ) {
- var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
- complete: fn || !fn && easing ||
- jQuery.isFunction( speed ) && speed,
- duration: speed,
- easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
- };
-
- opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
- opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
-
- // normalize opt.queue - true/undefined/null -> "fx"
- if ( opt.queue == null || opt.queue === true ) {
- opt.queue = "fx";
- }
-
- // Queueing
- opt.old = opt.complete;
-
- opt.complete = function() {
- if ( jQuery.isFunction( opt.old ) ) {
- opt.old.call( this );
- }
-
- if ( opt.queue ) {
- jQuery.dequeue( this, opt.queue );
- }
- };
-
- return opt;
-};
-
-jQuery.easing = {
- linear: function( p ) {
- return p;
- },
- swing: function( p ) {
- return 0.5 - Math.cos( p*Math.PI ) / 2;
- }
-};
-
-jQuery.timers = [];
-jQuery.fx = Tween.prototype.init;
-jQuery.fx.tick = function() {
- var timer,
- timers = jQuery.timers,
- i = 0;
-
- fxNow = jQuery.now();
-
- for ( ; i < timers.length; i++ ) {
- timer = timers[ i ];
- // Checks the timer has not already been removed
- if ( !timer() && timers[ i ] === timer ) {
- timers.splice( i--, 1 );
- }
- }
-
- if ( !timers.length ) {
- jQuery.fx.stop();
- }
- fxNow = undefined;
-};
-
-jQuery.fx.timer = function( timer ) {
- if ( timer() && jQuery.timers.push( timer ) ) {
- jQuery.fx.start();
- }
-};
-
-jQuery.fx.interval = 13;
-
-jQuery.fx.start = function() {
- if ( !timerId ) {
- timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
- }
-};
-
-jQuery.fx.stop = function() {
- clearInterval( timerId );
- timerId = null;
-};
-
-jQuery.fx.speeds = {
- slow: 600,
- fast: 200,
- // Default speed
- _default: 400
-};
-
-// Back Compat <1.8 extension point
-jQuery.fx.step = {};
-
-if ( jQuery.expr && jQuery.expr.filters ) {
- jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
- };
-}
-jQuery.fn.offset = function( options ) {
- if ( arguments.length ) {
- return options === undefined ?
- this :
- this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- var docElem, win,
- box = { top: 0, left: 0 },
- elem = this[ 0 ],
- doc = elem && elem.ownerDocument;
-
- if ( !doc ) {
- return;
- }
-
- docElem = doc.documentElement;
-
- // Make sure it's not a disconnected DOM node
- if ( !jQuery.contains( docElem, elem ) ) {
- return box;
- }
-
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof elem.getBoundingClientRect !== core_strundefined ) {
- box = elem.getBoundingClientRect();
- }
- win = getWindow( doc );
- return {
- top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
- left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
- };
-};
-
-jQuery.offset = {
-
- setOffset: function( elem, options, i ) {
- var position = jQuery.css( elem, "position" );
-
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- var curElem = jQuery( elem ),
- curOffset = curElem.offset(),
- curCSSTop = jQuery.css( elem, "top" ),
- curCSSLeft = jQuery.css( elem, "left" ),
- calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
- props = {}, curPosition = {}, curTop, curLeft;
-
- // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
- if ( calculatePosition ) {
- curPosition = curElem.position();
- curTop = curPosition.top;
- curLeft = curPosition.left;
- } else {
- curTop = parseFloat( curCSSTop ) || 0;
- curLeft = parseFloat( curCSSLeft ) || 0;
- }
-
- if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
- }
-
- if ( options.top != null ) {
- props.top = ( options.top - curOffset.top ) + curTop;
- }
- if ( options.left != null ) {
- props.left = ( options.left - curOffset.left ) + curLeft;
- }
-
- if ( "using" in options ) {
- options.using.call( elem, props );
- } else {
- curElem.css( props );
- }
- }
-};
-
-
-jQuery.fn.extend({
-
- position: function() {
- if ( !this[ 0 ] ) {
- return;
- }
-
- var offsetParent, offset,
- parentOffset = { top: 0, left: 0 },
- elem = this[ 0 ];
-
- // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent
- if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // we assume that getBoundingClientRect is available when computed position is fixed
- offset = elem.getBoundingClientRect();
- } else {
- // Get *real* offsetParent
- offsetParent = this.offsetParent();
-
- // Get correct offsets
- offset = this.offset();
- if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
- parentOffset = offsetParent.offset();
- }
-
- // Add offsetParent borders
- parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
- parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
- }
-
- // Subtract parent offsets and element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
- return {
- top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
- left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
- };
- },
-
- offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || document.documentElement;
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent || document.documentElement;
- });
- }
-});
-
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
- var top = /Y/.test( prop );
-
- jQuery.fn[ method ] = function( val ) {
- return jQuery.access( this, function( elem, method, val ) {
- var win = getWindow( elem );
-
- if ( val === undefined ) {
- return win ? (prop in win) ? win[ prop ] :
- win.document.documentElement[ method ] :
- elem[ method ];
- }
-
- if ( win ) {
- win.scrollTo(
- !top ? val : jQuery( win ).scrollLeft(),
- top ? val : jQuery( win ).scrollTop()
- );
-
- } else {
- elem[ method ] = val;
- }
- }, method, val, arguments.length, null );
- };
-});
-
-function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
-}
-// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
-jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
- jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
- jQuery.fn[ funcName ] = function( margin, value ) {
- var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
- extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
-
- return jQuery.access( this, function( elem, type, value ) {
- var doc;
-
- if ( jQuery.isWindow( elem ) ) {
- // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
- // isn't a whole lot we can do. See pull request at this URL for discussion:
- // https://github.com/jquery/jquery/pull/764
- return elem.document.documentElement[ "client" + name ];
- }
-
- // Get document width or height
- if ( elem.nodeType === 9 ) {
- doc = elem.documentElement;
-
- // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
- // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
- return Math.max(
- elem.body[ "scroll" + name ], doc[ "scroll" + name ],
- elem.body[ "offset" + name ], doc[ "offset" + name ],
- doc[ "client" + name ]
- );
- }
-
- return value === undefined ?
- // Get width or height on the element, requesting but not forcing parseFloat
- jQuery.css( elem, type, extra ) :
-
- // Set width or height on the element
- jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable, null );
- };
- });
-});
-// Limit scope pollution from any deprecated API
-// (function() {
-
-// })();
-// Expose jQuery to the global object
-window.jQuery = window.$ = jQuery;
-
-// Expose jQuery as an AMD module, but only for AMD loaders that
-// understand the issues with loading multiple versions of jQuery
-// in a page that all might call define(). The loader will indicate
-// they have special allowances for multiple jQuery versions by
-// specifying define.amd.jQuery = true. Register as a named module,
-// since jQuery can be concatenated with other files that may use define,
-// but not use a proper concatenation script that understands anonymous
-// AMD modules. A named AMD is safest and most robust way to register.
-// Lowercase jquery is used because AMD module names are derived from
-// file names, and jQuery is normally delivered in a lowercase file name.
-// Do this after creating the global so that if an AMD module wants to call
-// noConflict to hide this version of jQuery, it will work.
-if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
- define( "jquery", [], function () { return jQuery; } );
-}
-
-})( window );
deleted file mode 100644
index 75cdf246af2ce175e72b45314052203fd04a4428..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/jquery.mobile-1.4.js
+++ /dev/null
@@ -1,15056 +0,0 @@
-/*!
-* jQuery Mobile 1.4.2
-* Git HEAD hash: 9d9a42a27d0c693e8b5569c3a10d771916af5045 <> Date: Fri Feb 28 2014 17:32:01 UTC
-* http://jquerymobile.com
-*
-* Copyright 2010, 2014 jQuery Foundation, Inc. and other contributors
-* Released under the MIT license.
-* http://jquery.org/license
-*
-*/
-
-
-(function ( root, doc, factory ) {
- if ( typeof define === "function" && define.amd ) {
- // AMD. Register as an anonymous module.
- define( [ "jquery" ], function ( $ ) {
- factory( $, root, doc );
- return $.mobile;
- });
- } else {
- // Browser globals
- factory( root.jQuery, root, doc );
- }
-}( this, document, function ( jQuery, window, document, undefined ) {
-(function( $ ) {
- $.mobile = {};
-}( jQuery ));
-
-(function( $, window, undefined ) {
- $.extend( $.mobile, {
-
- // Version of the jQuery Mobile Framework
- version: "1.4.2",
-
- // Deprecated and no longer used in 1.4 remove in 1.5
- // Define the url parameter used for referencing widget-generated sub-pages.
- // Translates to example.html&ui-page=subpageIdentifier
- // hash segment before &ui-page= is used to make Ajax request
- subPageUrlKey: "ui-page",
-
- hideUrlBar: true,
-
- // Keepnative Selector
- keepNative: ":jqmData(role='none'), :jqmData(role='nojs')",
-
- // Deprecated in 1.4 remove in 1.5
- // Class assigned to page currently in view, and during transitions
- activePageClass: "ui-page-active",
-
- // Deprecated in 1.4 remove in 1.5
- // Class used for "active" button state, from CSS framework
- activeBtnClass: "ui-btn-active",
-
- // Deprecated in 1.4 remove in 1.5
- // Class used for "focus" form element state, from CSS framework
- focusClass: "ui-focus",
-
- // Automatically handle clicks and form submissions through Ajax, when same-domain
- ajaxEnabled: true,
-
- // Automatically load and show pages based on location.hash
- hashListeningEnabled: true,
-
- // disable to prevent jquery from bothering with links
- linkBindingEnabled: true,
-
- // Set default page transition - 'none' for no transitions
- defaultPageTransition: "fade",
-
- // Set maximum window width for transitions to apply - 'false' for no limit
- maxTransitionWidth: false,
-
- // Minimum scroll distance that will be remembered when returning to a page
- // Deprecated remove in 1.5
- minScrollBack: 0,
-
- // Set default dialog transition - 'none' for no transitions
- defaultDialogTransition: "pop",
-
- // Error response message - appears when an Ajax page request fails
- pageLoadErrorMessage: "Error Loading Page",
-
- // For error messages, which theme does the box uses?
- pageLoadErrorMessageTheme: "a",
-
- // replace calls to window.history.back with phonegaps navigation helper
- // where it is provided on the window object
- phonegapNavigationEnabled: false,
-
- //automatically initialize the DOM when it's ready
- autoInitializePage: true,
-
- pushStateEnabled: true,
-
- // allows users to opt in to ignoring content by marking a parent element as
- // data-ignored
- ignoreContentEnabled: false,
-
- buttonMarkup: {
- hoverDelay: 200
- },
-
- // disable the alteration of the dynamic base tag or links in the case
- // that a dynamic base tag isn't supported
- dynamicBaseEnabled: true,
-
- // default the property to remove dependency on assignment in init module
- pageContainer: $(),
-
- //enable cross-domain page support
- allowCrossDomainPages: false,
-
- dialogHashKey: "&ui-state=dialog"
- });
-})( jQuery, this );
-
-(function( $, window, undefined ) {
- var nsNormalizeDict = {},
- oldFind = $.find,
- rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/,
- jqmDataRE = /:jqmData\(([^)]*)\)/g;
-
- $.extend( $.mobile, {
-
- // Namespace used framework-wide for data-attrs. Default is no namespace
-
- ns: "",
-
- // Retrieve an attribute from an element and perform some massaging of the value
-
- getAttribute: function( element, key ) {
- var data;
-
- element = element.jquery ? element[0] : element;
-
- if ( element && element.getAttribute ) {
- data = element.getAttribute( "data-" + $.mobile.ns + key );
- }
-
- // Copied from core's src/data.js:dataAttr()
- // Convert from a string to a proper data type
- try {
- data = data === "true" ? true :
- data === "false" ? false :
- data === "null" ? null :
- // Only convert to a number if it doesn't change the string
- +data + "" === data ? +data :
- rbrace.test( data ) ? JSON.parse( data ) :
- data;
- } catch( err ) {}
-
- return data;
- },
-
- // Expose our cache for testing purposes.
- nsNormalizeDict: nsNormalizeDict,
-
- // Take a data attribute property, prepend the namespace
- // and then camel case the attribute string. Add the result
- // to our nsNormalizeDict so we don't have to do this again.
- nsNormalize: function( prop ) {
- return nsNormalizeDict[ prop ] ||
- ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) );
- },
-
- // Find the closest javascript page element to gather settings data jsperf test
- // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit
- // possibly naive, but it shows that the parsing overhead for *just* the page selector vs
- // the page and dialog selector is negligable. This could probably be speed up by
- // doing a similar parent node traversal to the one found in the inherited theme code above
- closestPageData: function( $target ) {
- return $target
- .closest( ":jqmData(role='page'), :jqmData(role='dialog')" )
- .data( "mobile-page" );
- }
-
- });
-
- // Mobile version of data and removeData and hasData methods
- // ensures all data is set and retrieved using jQuery Mobile's data namespace
- $.fn.jqmData = function( prop, value ) {
- var result;
- if ( typeof prop !== "undefined" ) {
- if ( prop ) {
- prop = $.mobile.nsNormalize( prop );
- }
-
- // undefined is permitted as an explicit input for the second param
- // in this case it returns the value and does not set it to undefined
- if ( arguments.length < 2 || value === undefined ) {
- result = this.data( prop );
- } else {
- result = this.data( prop, value );
- }
- }
- return result;
- };
-
- $.jqmData = function( elem, prop, value ) {
- var result;
- if ( typeof prop !== "undefined" ) {
- result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
- }
- return result;
- };
-
- $.fn.jqmRemoveData = function( prop ) {
- return this.removeData( $.mobile.nsNormalize( prop ) );
- };
-
- $.jqmRemoveData = function( elem, prop ) {
- return $.removeData( elem, $.mobile.nsNormalize( prop ) );
- };
-
- $.find = function( selector, context, ret, extra ) {
- if ( selector.indexOf( ":jqmData" ) > -1 ) {
- selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" );
- }
-
- return oldFind.call( this, selector, context, ret, extra );
- };
-
- $.extend( $.find, oldFind );
-
-})( jQuery, this );
-
-/*!
- * jQuery UI Core c0ab71056b936627e8a7821f03c044aec6280a40
- * http://jqueryui.com
- *
- * Copyright 2013 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/category/ui-core/
- */
-(function( $, undefined ) {
-
-var uuid = 0,
- runiqueId = /^ui-id-\d+$/;
-
-// $.ui might exist from components with no dependencies, e.g., $.ui.position
-$.ui = $.ui || {};
-
-$.extend( $.ui, {
- version: "c0ab71056b936627e8a7821f03c044aec6280a40",
-
- keyCode: {
- BACKSPACE: 8,
- COMMA: 188,
- DELETE: 46,
- DOWN: 40,
- END: 35,
- ENTER: 13,
- ESCAPE: 27,
- HOME: 36,
- LEFT: 37,
- PAGE_DOWN: 34,
- PAGE_UP: 33,
- PERIOD: 190,
- RIGHT: 39,
- SPACE: 32,
- TAB: 9,
- UP: 38
- }
-});
-
-// plugins
-$.fn.extend({
- focus: (function( orig ) {
- return function( delay, fn ) {
- return typeof delay === "number" ?
- this.each(function() {
- var elem = this;
- setTimeout(function() {
- $( elem ).focus();
- if ( fn ) {
- fn.call( elem );
- }
- }, delay );
- }) :
- orig.apply( this, arguments );
- };
- })( $.fn.focus ),
-
- scrollParent: function() {
- var scrollParent;
- if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
- scrollParent = this.parents().filter(function() {
- return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
- }).eq(0);
- } else {
- scrollParent = this.parents().filter(function() {
- return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
- }).eq(0);
- }
-
- return ( /fixed/ ).test( this.css( "position") ) || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
- },
-
- uniqueId: function() {
- return this.each(function() {
- if ( !this.id ) {
- this.id = "ui-id-" + (++uuid);
- }
- });
- },
-
- removeUniqueId: function() {
- return this.each(function() {
- if ( runiqueId.test( this.id ) ) {
- $( this ).removeAttr( "id" );
- }
- });
- }
-});
-
-// selectors
-function focusable( element, isTabIndexNotNaN ) {
- var map, mapName, img,
- nodeName = element.nodeName.toLowerCase();
- if ( "area" === nodeName ) {
- map = element.parentNode;
- mapName = map.name;
- if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
- return false;
- }
- img = $( "img[usemap=#" + mapName + "]" )[0];
- return !!img && visible( img );
- }
- return ( /input|select|textarea|button|object/.test( nodeName ) ?
- !element.disabled :
- "a" === nodeName ?
- element.href || isTabIndexNotNaN :
- isTabIndexNotNaN) &&
- // the element and all of its ancestors must be visible
- visible( element );
-}
-
-function visible( element ) {
- return $.expr.filters.visible( element ) &&
- !$( element ).parents().addBack().filter(function() {
- return $.css( this, "visibility" ) === "hidden";
- }).length;
-}
-
-$.extend( $.expr[ ":" ], {
- data: $.expr.createPseudo ?
- $.expr.createPseudo(function( dataName ) {
- return function( elem ) {
- return !!$.data( elem, dataName );
- };
- }) :
- // support: jQuery <1.8
- function( elem, i, match ) {
- return !!$.data( elem, match[ 3 ] );
- },
-
- focusable: function( element ) {
- return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
- },
-
- tabbable: function( element ) {
- var tabIndex = $.attr( element, "tabindex" ),
- isTabIndexNaN = isNaN( tabIndex );
- return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
- }
-});
-
-// support: jQuery <1.8
-if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
- $.each( [ "Width", "Height" ], function( i, name ) {
- var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
- type = name.toLowerCase(),
- orig = {
- innerWidth: $.fn.innerWidth,
- innerHeight: $.fn.innerHeight,
- outerWidth: $.fn.outerWidth,
- outerHeight: $.fn.outerHeight
- };
-
- function reduce( elem, size, border, margin ) {
- $.each( side, function() {
- size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
- if ( border ) {
- size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
- }
- if ( margin ) {
- size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
- }
- });
- return size;
- }
-
- $.fn[ "inner" + name ] = function( size ) {
- if ( size === undefined ) {
- return orig[ "inner" + name ].call( this );
- }
-
- return this.each(function() {
- $( this ).css( type, reduce( this, size ) + "px" );
- });
- };
-
- $.fn[ "outer" + name] = function( size, margin ) {
- if ( typeof size !== "number" ) {
- return orig[ "outer" + name ].call( this, size );
- }
-
- return this.each(function() {
- $( this).css( type, reduce( this, size, true, margin ) + "px" );
- });
- };
- });
-}
-
-// support: jQuery <1.8
-if ( !$.fn.addBack ) {
- $.fn.addBack = function( selector ) {
- return this.add( selector == null ?
- this.prevObject : this.prevObject.filter( selector )
- );
- };
-}
-
-// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
-if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
- $.fn.removeData = (function( removeData ) {
- return function( key ) {
- if ( arguments.length ) {
- return removeData.call( this, $.camelCase( key ) );
- } else {
- return removeData.call( this );
- }
- };
- })( $.fn.removeData );
-}
-
-
-
-
-
-// deprecated
-$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
-
-$.support.selectstart = "onselectstart" in document.createElement( "div" );
-$.fn.extend({
- disableSelection: function() {
- return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
- ".ui-disableSelection", function( event ) {
- event.preventDefault();
- });
- },
-
- enableSelection: function() {
- return this.unbind( ".ui-disableSelection" );
- },
-
- zIndex: function( zIndex ) {
- if ( zIndex !== undefined ) {
- return this.css( "zIndex", zIndex );
- }
-
- if ( this.length ) {
- var elem = $( this[ 0 ] ), position, value;
- while ( elem.length && elem[ 0 ] !== document ) {
- // Ignore z-index if position is set to a value where z-index is ignored by the browser
- // This makes behavior of this function consistent across browsers
- // WebKit always returns auto if the element is positioned
- position = elem.css( "position" );
- if ( position === "absolute" || position === "relative" || position === "fixed" ) {
- // IE returns 0 when zIndex is not specified
- // other browsers return a string
- // we ignore the case of nested elements with an explicit value of 0
- // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
- value = parseInt( elem.css( "zIndex" ), 10 );
- if ( !isNaN( value ) && value !== 0 ) {
- return value;
- }
- }
- elem = elem.parent();
- }
- }
-
- return 0;
- }
-});
-
-// $.ui.plugin is deprecated. Use $.widget() extensions instead.
-$.ui.plugin = {
- add: function( module, option, set ) {
- var i,
- proto = $.ui[ module ].prototype;
- for ( i in set ) {
- proto.plugins[ i ] = proto.plugins[ i ] || [];
- proto.plugins[ i ].push( [ option, set[ i ] ] );
- }
- },
- call: function( instance, name, args, allowDisconnected ) {
- var i,
- set = instance.plugins[ name ];
-
- if ( !set ) {
- return;
- }
-
- if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
- return;
- }
-
- for ( i = 0; i < set.length; i++ ) {
- if ( instance.options[ set[ i ][ 0 ] ] ) {
- set[ i ][ 1 ].apply( instance.element, args );
- }
- }
- }
-};
-
-})( jQuery );
-
-(function( $, window, undefined ) {
-
- // Subtract the height of external toolbars from the page height, if the page does not have
- // internal toolbars of the same type
- var compensateToolbars = function( page, desiredHeight ) {
- var pageParent = page.parent(),
- toolbarsAffectingHeight = [],
- externalHeaders = pageParent.children( ":jqmData(role='header')" ),
- internalHeaders = page.children( ":jqmData(role='header')" ),
- externalFooters = pageParent.children( ":jqmData(role='footer')" ),
- internalFooters = page.children( ":jqmData(role='footer')" );
-
- // If we have no internal headers, but we do have external headers, then their height
- // reduces the page height
- if ( internalHeaders.length === 0 && externalHeaders.length > 0 ) {
- toolbarsAffectingHeight = toolbarsAffectingHeight.concat( externalHeaders.toArray() );
- }
-
- // If we have no internal footers, but we do have external footers, then their height
- // reduces the page height
- if ( internalFooters.length === 0 && externalFooters.length > 0 ) {
- toolbarsAffectingHeight = toolbarsAffectingHeight.concat( externalFooters.toArray() );
- }
-
- $.each( toolbarsAffectingHeight, function( index, value ) {
- desiredHeight -= $( value ).outerHeight();
- });
-
- // Height must be at least zero
- return Math.max( 0, desiredHeight );
- };
-
- $.extend( $.mobile, {
- // define the window and the document objects
- window: $( window ),
- document: $( document ),
-
- // TODO: Remove and use $.ui.keyCode directly
- keyCode: $.ui.keyCode,
-
- // Place to store various widget extensions
- behaviors: {},
-
- // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
- silentScroll: function( ypos ) {
- if ( $.type( ypos ) !== "number" ) {
- ypos = $.mobile.defaultHomeScroll;
- }
-
- // prevent scrollstart and scrollstop events
- $.event.special.scrollstart.enabled = false;
-
- setTimeout(function() {
- window.scrollTo( 0, ypos );
- $.mobile.document.trigger( "silentscroll", { x: 0, y: ypos });
- }, 20 );
-
- setTimeout(function() {
- $.event.special.scrollstart.enabled = true;
- }, 150 );
- },
-
- getClosestBaseUrl: function( ele ) {
- // Find the closest page and extract out its url.
- var url = $( ele ).closest( ".ui-page" ).jqmData( "url" ),
- base = $.mobile.path.documentBase.hrefNoHash;
-
- if ( !$.mobile.dynamicBaseEnabled || !url || !$.mobile.path.isPath( url ) ) {
- url = base;
- }
-
- return $.mobile.path.makeUrlAbsolute( url, base );
- },
- removeActiveLinkClass: function( forceRemoval ) {
- if ( !!$.mobile.activeClickedLink &&
- ( !$.mobile.activeClickedLink.closest( "." + $.mobile.activePageClass ).length ||
- forceRemoval ) ) {
-
- $.mobile.activeClickedLink.removeClass( $.mobile.activeBtnClass );
- }
- $.mobile.activeClickedLink = null;
- },
-
- // DEPRECATED in 1.4
- // Find the closest parent with a theme class on it. Note that
- // we are not using $.fn.closest() on purpose here because this
- // method gets called quite a bit and we need it to be as fast
- // as possible.
- getInheritedTheme: function( el, defaultTheme ) {
- var e = el[ 0 ],
- ltr = "",
- re = /ui-(bar|body|overlay)-([a-z])\b/,
- c, m;
- while ( e ) {
- c = e.className || "";
- if ( c && ( m = re.exec( c ) ) && ( ltr = m[ 2 ] ) ) {
- // We found a parent with a theme class
- // on it so bail from this loop.
- break;
- }
-
- e = e.parentNode;
- }
- // Return the theme letter we found, if none, return the
- // specified default.
- return ltr || defaultTheme || "a";
- },
-
- enhanceable: function( elements ) {
- return this.haveParents( elements, "enhance" );
- },
-
- hijackable: function( elements ) {
- return this.haveParents( elements, "ajax" );
- },
-
- haveParents: function( elements, attr ) {
- if ( !$.mobile.ignoreContentEnabled ) {
- return elements;
- }
-
- var count = elements.length,
- $newSet = $(),
- e, $element, excluded,
- i, c;
-
- for ( i = 0; i < count; i++ ) {
- $element = elements.eq( i );
- excluded = false;
- e = elements[ i ];
-
- while ( e ) {
- c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : "";
-
- if ( c === "false" ) {
- excluded = true;
- break;
- }
-
- e = e.parentNode;
- }
-
- if ( !excluded ) {
- $newSet = $newSet.add( $element );
- }
- }
-
- return $newSet;
- },
-
- getScreenHeight: function() {
- // Native innerHeight returns more accurate value for this across platforms,
- // jQuery version is here as a normalized fallback for platforms like Symbian
- return window.innerHeight || $.mobile.window.height();
- },
-
- //simply set the active page's minimum height to screen height, depending on orientation
- resetActivePageHeight: function( height ) {
- var page = $( "." + $.mobile.activePageClass ),
- pageHeight = page.height(),
- pageOuterHeight = page.outerHeight( true );
-
- height = compensateToolbars( page,
- ( typeof height === "number" ) ? height : $.mobile.getScreenHeight() );
-
- page.css( "min-height", height - ( pageOuterHeight - pageHeight ) );
- },
-
- loading: function() {
- // If this is the first call to this function, instantiate a loader widget
- var loader = this.loading._widget || $( $.mobile.loader.prototype.defaultHtml ).loader(),
-
- // Call the appropriate method on the loader
- returnValue = loader.loader.apply( loader, arguments );
-
- // Make sure the loader is retained for future calls to this function.
- this.loading._widget = loader;
-
- return returnValue;
- }
- });
-
- $.addDependents = function( elem, newDependents ) {
- var $elem = $( elem ),
- dependents = $elem.jqmData( "dependents" ) || $();
-
- $elem.jqmData( "dependents", $( dependents ).add( newDependents ) );
- };
-
- // plugins
- $.fn.extend({
- removeWithDependents: function() {
- $.removeWithDependents( this );
- },
-
- // Enhance child elements
- enhanceWithin: function() {
- var index,
- widgetElements = {},
- keepNative = $.mobile.page.prototype.keepNativeSelector(),
- that = this;
-
- // Add no js class to elements
- if ( $.mobile.nojs ) {
- $.mobile.nojs( this );
- }
-
- // Bind links for ajax nav
- if ( $.mobile.links ) {
- $.mobile.links( this );
- }
-
- // Degrade inputs for styleing
- if ( $.mobile.degradeInputsWithin ) {
- $.mobile.degradeInputsWithin( this );
- }
-
- // Run buttonmarkup
- if ( $.fn.buttonMarkup ) {
- this.find( $.fn.buttonMarkup.initSelector ).not( keepNative )
- .jqmEnhanceable().buttonMarkup();
- }
-
- // Add classes for fieldContain
- if ( $.fn.fieldcontain ) {
- this.find( ":jqmData(role='fieldcontain')" ).not( keepNative )
- .jqmEnhanceable().fieldcontain();
- }
-
- // Enhance widgets
- $.each( $.mobile.widgets, function( name, constructor ) {
-
- // If initSelector not false find elements
- if ( constructor.initSelector ) {
-
- // Filter elements that should not be enhanced based on parents
- var elements = $.mobile.enhanceable( that.find( constructor.initSelector ) );
-
- // If any matching elements remain filter ones with keepNativeSelector
- if ( elements.length > 0 ) {
-
- // $.mobile.page.prototype.keepNativeSelector is deprecated this is just for backcompat
- // Switch to $.mobile.keepNative in 1.5 which is just a value not a function
- elements = elements.not( keepNative );
- }
-
- // Enhance whatever is left
- if ( elements.length > 0 ) {
- widgetElements[ constructor.prototype.widgetName ] = elements;
- }
- }
- });
-
- for ( index in widgetElements ) {
- widgetElements[ index ][ index ]();
- }
-
- return this;
- },
-
- addDependents: function( newDependents ) {
- $.addDependents( this, newDependents );
- },
-
- // note that this helper doesn't attempt to handle the callback
- // or setting of an html element's text, its only purpose is
- // to return the html encoded version of the text in all cases. (thus the name)
- getEncodedText: function() {
- return $( "<a>" ).text( this.text() ).html();
- },
-
- // fluent helper function for the mobile namespaced equivalent
- jqmEnhanceable: function() {
- return $.mobile.enhanceable( this );
- },
-
- jqmHijackable: function() {
- return $.mobile.hijackable( this );
- }
- });
-
- $.removeWithDependents = function( nativeElement ) {
- var element = $( nativeElement );
-
- ( element.jqmData( "dependents" ) || $() ).remove();
- element.remove();
- };
- $.addDependents = function( nativeElement, newDependents ) {
- var element = $( nativeElement ),
- dependents = element.jqmData( "dependents" ) || $();
-
- element.jqmData( "dependents", $( dependents ).add( newDependents ) );
- };
-
- $.find.matches = function( expr, set ) {
- return $.find( expr, null, null, set );
- };
-
- $.find.matchesSelector = function( node, expr ) {
- return $.find( expr, null, null, [ node ] ).length > 0;
- };
-
-})( jQuery, this );
-
-
-/*!
- * jQuery UI Widget c0ab71056b936627e8a7821f03c044aec6280a40
- * http://jqueryui.com
- *
- * Copyright 2013 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/jQuery.widget/
- */
-(function( $, undefined ) {
-
-var uuid = 0,
- slice = Array.prototype.slice,
- _cleanData = $.cleanData;
-$.cleanData = function( elems ) {
- for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
- try {
- $( elem ).triggerHandler( "remove" );
- // http://bugs.jquery.com/ticket/8235
- } catch( e ) {}
- }
- _cleanData( elems );
-};
-
-$.widget = function( name, base, prototype ) {
- var fullName, existingConstructor, constructor, basePrototype,
- // proxiedPrototype allows the provided prototype to remain unmodified
- // so that it can be used as a mixin for multiple widgets (#8876)
- proxiedPrototype = {},
- namespace = name.split( "." )[ 0 ];
-
- name = name.split( "." )[ 1 ];
- fullName = namespace + "-" + name;
-
- if ( !prototype ) {
- prototype = base;
- base = $.Widget;
- }
-
- // create selector for plugin
- $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
- return !!$.data( elem, fullName );
- };
-
- $[ namespace ] = $[ namespace ] || {};
- existingConstructor = $[ namespace ][ name ];
- constructor = $[ namespace ][ name ] = function( options, element ) {
- // allow instantiation without "new" keyword
- if ( !this._createWidget ) {
- return new constructor( options, element );
- }
-
- // allow instantiation without initializing for simple inheritance
- // must use "new" keyword (the code above always passes args)
- if ( arguments.length ) {
- this._createWidget( options, element );
- }
- };
- // extend with the existing constructor to carry over any static properties
- $.extend( constructor, existingConstructor, {
- version: prototype.version,
- // copy the object used to create the prototype in case we need to
- // redefine the widget later
- _proto: $.extend( {}, prototype ),
- // track widgets that inherit from this widget in case this widget is
- // redefined after a widget inherits from it
- _childConstructors: []
- });
-
- basePrototype = new base();
- // we need to make the options hash a property directly on the new instance
- // otherwise we'll modify the options hash on the prototype that we're
- // inheriting from
- basePrototype.options = $.widget.extend( {}, basePrototype.options );
- $.each( prototype, function( prop, value ) {
- if ( !$.isFunction( value ) ) {
- proxiedPrototype[ prop ] = value;
- return;
- }
- proxiedPrototype[ prop ] = (function() {
- var _super = function() {
- return base.prototype[ prop ].apply( this, arguments );
- },
- _superApply = function( args ) {
- return base.prototype[ prop ].apply( this, args );
- };
- return function() {
- var __super = this._super,
- __superApply = this._superApply,
- returnValue;
-
- this._super = _super;
- this._superApply = _superApply;
-
- returnValue = value.apply( this, arguments );
-
- this._super = __super;
- this._superApply = __superApply;
-
- return returnValue;
- };
- })();
- });
- constructor.prototype = $.widget.extend( basePrototype, {
- // TODO: remove support for widgetEventPrefix
- // always use the name + a colon as the prefix, e.g., draggable:start
- // don't prefix for widgets that aren't DOM-based
- widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
- }, proxiedPrototype, {
- constructor: constructor,
- namespace: namespace,
- widgetName: name,
- widgetFullName: fullName
- });
-
- // If this widget is being redefined then we need to find all widgets that
- // are inheriting from it and redefine all of them so that they inherit from
- // the new version of this widget. We're essentially trying to replace one
- // level in the prototype chain.
- if ( existingConstructor ) {
- $.each( existingConstructor._childConstructors, function( i, child ) {
- var childPrototype = child.prototype;
-
- // redefine the child widget using the same prototype that was
- // originally used, but inherit from the new version of the base
- $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
- });
- // remove the list of existing child constructors from the old constructor
- // so the old child constructors can be garbage collected
- delete existingConstructor._childConstructors;
- } else {
- base._childConstructors.push( constructor );
- }
-
- $.widget.bridge( name, constructor );
-
- return constructor;
-};
-
-$.widget.extend = function( target ) {
- var input = slice.call( arguments, 1 ),
- inputIndex = 0,
- inputLength = input.length,
- key,
- value;
- for ( ; inputIndex < inputLength; inputIndex++ ) {
- for ( key in input[ inputIndex ] ) {
- value = input[ inputIndex ][ key ];
- if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
- // Clone objects
- if ( $.isPlainObject( value ) ) {
- target[ key ] = $.isPlainObject( target[ key ] ) ?
- $.widget.extend( {}, target[ key ], value ) :
- // Don't extend strings, arrays, etc. with objects
- $.widget.extend( {}, value );
- // Copy everything else by reference
- } else {
- target[ key ] = value;
- }
- }
- }
- }
- return target;
-};
-
-$.widget.bridge = function( name, object ) {
- var fullName = object.prototype.widgetFullName || name;
- $.fn[ name ] = function( options ) {
- var isMethodCall = typeof options === "string",
- args = slice.call( arguments, 1 ),
- returnValue = this;
-
- // allow multiple hashes to be passed on init
- options = !isMethodCall && args.length ?
- $.widget.extend.apply( null, [ options ].concat(args) ) :
- options;
-
- if ( isMethodCall ) {
- this.each(function() {
- var methodValue,
- instance = $.data( this, fullName );
- if ( options === "instance" ) {
- returnValue = instance;
- return false;
- }
- if ( !instance ) {
- return $.error( "cannot call methods on " + name + " prior to initialization; " +
- "attempted to call method '" + options + "'" );
- }
- if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
- return $.error( "no such method '" + options + "' for " + name + " widget instance" );
- }
- methodValue = instance[ options ].apply( instance, args );
- if ( methodValue !== instance && methodValue !== undefined ) {
- returnValue = methodValue && methodValue.jquery ?
- returnValue.pushStack( methodValue.get() ) :
- methodValue;
- return false;
- }
- });
- } else {
- this.each(function() {
- var instance = $.data( this, fullName );
- if ( instance ) {
- instance.option( options || {} )._init();
- } else {
- $.data( this, fullName, new object( options, this ) );
- }
- });
- }
-
- return returnValue;
- };
-};
-
-$.Widget = function( /* options, element */ ) {};
-$.Widget._childConstructors = [];
-
-$.Widget.prototype = {
- widgetName: "widget",
- widgetEventPrefix: "",
- defaultElement: "<div>",
- options: {
- disabled: false,
-
- // callbacks
- create: null
- },
- _createWidget: function( options, element ) {
- element = $( element || this.defaultElement || this )[ 0 ];
- this.element = $( element );
- this.uuid = uuid++;
- this.eventNamespace = "." + this.widgetName + this.uuid;
- this.options = $.widget.extend( {},
- this.options,
- this._getCreateOptions(),
- options );
-
- this.bindings = $();
- this.hoverable = $();
- this.focusable = $();
-
- if ( element !== this ) {
- $.data( element, this.widgetFullName, this );
- this._on( true, this.element, {
- remove: function( event ) {
- if ( event.target === element ) {
- this.destroy();
- }
- }
- });
- this.document = $( element.style ?
- // element within the document
- element.ownerDocument :
- // element is window or document
- element.document || element );
- this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
- }
-
- this._create();
- this._trigger( "create", null, this._getCreateEventData() );
- this._init();
- },
- _getCreateOptions: $.noop,
- _getCreateEventData: $.noop,
- _create: $.noop,
- _init: $.noop,
-
- destroy: function() {
- this._destroy();
- // we can probably remove the unbind calls in 2.0
- // all event bindings should go through this._on()
- this.element
- .unbind( this.eventNamespace )
- .removeData( this.widgetFullName )
- // support: jquery <1.6.3
- // http://bugs.jquery.com/ticket/9413
- .removeData( $.camelCase( this.widgetFullName ) );
- this.widget()
- .unbind( this.eventNamespace )
- .removeAttr( "aria-disabled" )
- .removeClass(
- this.widgetFullName + "-disabled " +
- "ui-state-disabled" );
-
- // clean up events and states
- this.bindings.unbind( this.eventNamespace );
- this.hoverable.removeClass( "ui-state-hover" );
- this.focusable.removeClass( "ui-state-focus" );
- },
- _destroy: $.noop,
-
- widget: function() {
- return this.element;
- },
-
- option: function( key, value ) {
- var options = key,
- parts,
- curOption,
- i;
-
- if ( arguments.length === 0 ) {
- // don't return a reference to the internal hash
- return $.widget.extend( {}, this.options );
- }
-
- if ( typeof key === "string" ) {
- // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
- options = {};
- parts = key.split( "." );
- key = parts.shift();
- if ( parts.length ) {
- curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
- for ( i = 0; i < parts.length - 1; i++ ) {
- curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
- curOption = curOption[ parts[ i ] ];
- }
- key = parts.pop();
- if ( value === undefined ) {
- return curOption[ key ] === undefined ? null : curOption[ key ];
- }
- curOption[ key ] = value;
- } else {
- if ( value === undefined ) {
- return this.options[ key ] === undefined ? null : this.options[ key ];
- }
- options[ key ] = value;
- }
- }
-
- this._setOptions( options );
-
- return this;
- },
- _setOptions: function( options ) {
- var key;
-
- for ( key in options ) {
- this._setOption( key, options[ key ] );
- }
-
- return this;
- },
- _setOption: function( key, value ) {
- this.options[ key ] = value;
-
- if ( key === "disabled" ) {
- this.widget()
- .toggleClass( this.widgetFullName + "-disabled", !!value );
- this.hoverable.removeClass( "ui-state-hover" );
- this.focusable.removeClass( "ui-state-focus" );
- }
-
- return this;
- },
-
- enable: function() {
- return this._setOptions({ disabled: false });
- },
- disable: function() {
- return this._setOptions({ disabled: true });
- },
-
- _on: function( suppressDisabledCheck, element, handlers ) {
- var delegateElement,
- instance = this;
-
- // no suppressDisabledCheck flag, shuffle arguments
- if ( typeof suppressDisabledCheck !== "boolean" ) {
- handlers = element;
- element = suppressDisabledCheck;
- suppressDisabledCheck = false;
- }
-
- // no element argument, shuffle and use this.element
- if ( !handlers ) {
- handlers = element;
- element = this.element;
- delegateElement = this.widget();
- } else {
- // accept selectors, DOM elements
- element = delegateElement = $( element );
- this.bindings = this.bindings.add( element );
- }
-
- $.each( handlers, function( event, handler ) {
- function handlerProxy() {
- // allow widgets to customize the disabled handling
- // - disabled as an array instead of boolean
- // - disabled class as method for disabling individual parts
- if ( !suppressDisabledCheck &&
- ( instance.options.disabled === true ||
- $( this ).hasClass( "ui-state-disabled" ) ) ) {
- return;
- }
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
-
- // copy the guid so direct unbinding works
- if ( typeof handler !== "string" ) {
- handlerProxy.guid = handler.guid =
- handler.guid || handlerProxy.guid || $.guid++;
- }
-
- var match = event.match( /^(\w+)\s*(.*)$/ ),
- eventName = match[1] + instance.eventNamespace,
- selector = match[2];
- if ( selector ) {
- delegateElement.delegate( selector, eventName, handlerProxy );
- } else {
- element.bind( eventName, handlerProxy );
- }
- });
- },
-
- _off: function( element, eventName ) {
- eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
- element.unbind( eventName ).undelegate( eventName );
- },
-
- _delay: function( handler, delay ) {
- function handlerProxy() {
- return ( typeof handler === "string" ? instance[ handler ] : handler )
- .apply( instance, arguments );
- }
- var instance = this;
- return setTimeout( handlerProxy, delay || 0 );
- },
-
- _hoverable: function( element ) {
- this.hoverable = this.hoverable.add( element );
- this._on( element, {
- mouseenter: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-hover" );
- },
- mouseleave: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-hover" );
- }
- });
- },
-
- _focusable: function( element ) {
- this.focusable = this.focusable.add( element );
- this._on( element, {
- focusin: function( event ) {
- $( event.currentTarget ).addClass( "ui-state-focus" );
- },
- focusout: function( event ) {
- $( event.currentTarget ).removeClass( "ui-state-focus" );
- }
- });
- },
-
- _trigger: function( type, event, data ) {
- var prop, orig,
- callback = this.options[ type ];
-
- data = data || {};
- event = $.Event( event );
- event.type = ( type === this.widgetEventPrefix ?
- type :
- this.widgetEventPrefix + type ).toLowerCase();
- // the original event may come from any element
- // so we need to reset the target on the new event
- event.target = this.element[ 0 ];
-
- // copy original event properties over to the new event
- orig = event.originalEvent;
- if ( orig ) {
- for ( prop in orig ) {
- if ( !( prop in event ) ) {
- event[ prop ] = orig[ prop ];
- }
- }
- }
-
- this.element.trigger( event, data );
- return !( $.isFunction( callback ) &&
- callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
- event.isDefaultPrevented() );
- }
-};
-
-$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
- $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
- if ( typeof options === "string" ) {
- options = { effect: options };
- }
- var hasOptions,
- effectName = !options ?
- method :
- options === true || typeof options === "number" ?
- defaultEffect :
- options.effect || defaultEffect;
- options = options || {};
- if ( typeof options === "number" ) {
- options = { duration: options };
- }
- hasOptions = !$.isEmptyObject( options );
- options.complete = callback;
- if ( options.delay ) {
- element.delay( options.delay );
- }
- if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
- element[ method ]( options );
- } else if ( effectName !== method && element[ effectName ] ) {
- element[ effectName ]( options.duration, options.easing, callback );
- } else {
- element.queue(function( next ) {
- $( this )[ method ]();
- if ( callback ) {
- callback.call( element[ 0 ] );
- }
- next();
- });
- }
- };
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-var rcapitals = /[A-Z]/g,
- replaceFunction = function( c ) {
- return "-" + c.toLowerCase();
- };
-
-$.extend( $.Widget.prototype, {
- _getCreateOptions: function() {
- var option, value,
- elem = this.element[ 0 ],
- options = {};
-
- //
- if ( !$.mobile.getAttribute( elem, "defaults" ) ) {
- for ( option in this.options ) {
- value = $.mobile.getAttribute( elem, option.replace( rcapitals, replaceFunction ) );
-
- if ( value != null ) {
- options[ option ] = value;
- }
- }
- }
-
- return options;
- }
-});
-
-//TODO: Remove in 1.5 for backcompat only
-$.mobile.widget = $.Widget;
-
-})( jQuery );
-
-
-(function( $ ) {
- // TODO move loader class down into the widget settings
- var loaderClass = "ui-loader", $html = $( "html" );
-
- $.widget( "mobile.loader", {
- // NOTE if the global config settings are defined they will override these
- // options
- options: {
- // the theme for the loading message
- theme: "a",
-
- // whether the text in the loading message is shown
- textVisible: false,
-
- // custom html for the inner content of the loading message
- html: "",
-
- // the text to be displayed when the popup is shown
- text: "loading"
- },
-
- defaultHtml: "<div class='" + loaderClass + "'>" +
- "<span class='ui-icon-loading'></span>" +
- "<h1></h1>" +
- "</div>",
-
- // For non-fixed supportin browsers. Position at y center (if scrollTop supported), above the activeBtn (if defined), or just 100px from top
- fakeFixLoader: function() {
- var activeBtn = $( "." + $.mobile.activeBtnClass ).first();
-
- this.element
- .css({
- top: $.support.scrollTop && this.window.scrollTop() + this.window.height() / 2 ||
- activeBtn.length && activeBtn.offset().top || 100
- });
- },
-
- // check position of loader to see if it appears to be "fixed" to center
- // if not, use abs positioning
- checkLoaderPosition: function() {
- var offset = this.element.offset(),
- scrollTop = this.window.scrollTop(),
- screenHeight = $.mobile.getScreenHeight();
-
- if ( offset.top < scrollTop || ( offset.top - scrollTop ) > screenHeight ) {
- this.element.addClass( "ui-loader-fakefix" );
- this.fakeFixLoader();
- this.window
- .unbind( "scroll", this.checkLoaderPosition )
- .bind( "scroll", $.proxy( this.fakeFixLoader, this ) );
- }
- },
-
- resetHtml: function() {
- this.element.html( $( this.defaultHtml ).html() );
- },
-
- // Turn on/off page loading message. Theme doubles as an object argument
- // with the following shape: { theme: '', text: '', html: '', textVisible: '' }
- // NOTE that the $.mobile.loading* settings and params past the first are deprecated
- // TODO sweet jesus we need to break some of this out
- show: function( theme, msgText, textonly ) {
- var textVisible, message, loadSettings;
-
- this.resetHtml();
-
- // use the prototype options so that people can set them globally at
- // mobile init. Consistency, it's what's for dinner
- if ( $.type( theme ) === "object" ) {
- loadSettings = $.extend( {}, this.options, theme );
-
- theme = loadSettings.theme;
- } else {
- loadSettings = this.options;
-
- // here we prefer the theme value passed as a string argument, then
- // we prefer the global option because we can't use undefined default
- // prototype options, then the prototype option
- theme = theme || loadSettings.theme;
- }
-
- // set the message text, prefer the param, then the settings object
- // then loading message
- message = msgText || ( loadSettings.text === false ? "" : loadSettings.text );
-
- // prepare the dom
- $html.addClass( "ui-loading" );
-
- textVisible = loadSettings.textVisible;
-
- // add the proper css given the options (theme, text, etc)
- // Force text visibility if the second argument was supplied, or
- // if the text was explicitly set in the object args
- this.element.attr("class", loaderClass +
- " ui-corner-all ui-body-" + theme +
- " ui-loader-" + ( textVisible || msgText || theme.text ? "verbose" : "default" ) +
- ( loadSettings.textonly || textonly ? " ui-loader-textonly" : "" ) );
-
- // TODO verify that jquery.fn.html is ok to use in both cases here
- // this might be overly defensive in preventing unknowing xss
- // if the html attribute is defined on the loading settings, use that
- // otherwise use the fallbacks from above
- if ( loadSettings.html ) {
- this.element.html( loadSettings.html );
- } else {
- this.element.find( "h1" ).text( message );
- }
-
- // attach the loader to the DOM
- this.element.appendTo( $.mobile.pageContainer );
-
- // check that the loader is visible
- this.checkLoaderPosition();
-
- // on scroll check the loader position
- this.window.bind( "scroll", $.proxy( this.checkLoaderPosition, this ) );
- },
-
- hide: function() {
- $html.removeClass( "ui-loading" );
-
- if ( this.options.text ) {
- this.element.removeClass( "ui-loader-fakefix" );
- }
-
- $.mobile.window.unbind( "scroll", this.fakeFixLoader );
- $.mobile.window.unbind( "scroll", this.checkLoaderPosition );
- }
- });
-
-})(jQuery, this);
-
-
-/*!
- * jQuery hashchange event - v1.3 - 7/21/2010
- * http://benalman.com/projects/jquery-hashchange-plugin/
- *
- * Copyright (c) 2010 "Cowboy" Ben Alman
- * Dual licensed under the MIT and GPL licenses.
- * http://benalman.com/about/license/
- */
-
-// Script: jQuery hashchange event
-//
-// *Version: 1.3, Last updated: 7/21/2010*
-//
-// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
-// GitHub - http://github.com/cowboy/jquery-hashchange/
-// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
-// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
-//
-// About: License
-//
-// Copyright (c) 2010 "Cowboy" Ben Alman,
-// Dual licensed under the MIT and GPL licenses.
-// http://benalman.com/about/license/
-//
-// About: Examples
-//
-// These working examples, complete with fully commented code, illustrate a few
-// ways in which this plugin can be used.
-//
-// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
-// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
-//
-// About: Support and Testing
-//
-// Information about what version or versions of jQuery this plugin has been
-// tested with, what browsers it has been tested in, and where the unit tests
-// reside (so you can test it yourself).
-//
-// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
-// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
-// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
-// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
-//
-// About: Known issues
-//
-// While this jQuery hashchange event implementation is quite stable and
-// robust, there are a few unfortunate browser bugs surrounding expected
-// hashchange event-based behaviors, independent of any JavaScript
-// window.onhashchange abstraction. See the following examples for more
-// information:
-//
-// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
-// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
-// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
-// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
-//
-// Also note that should a browser natively support the window.onhashchange
-// event, but not report that it does, the fallback polling loop will be used.
-//
-// About: Release History
-//
-// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
-// "removable" for mobile-only development. Added IE6/7 document.title
-// support. Attempted to make Iframe as hidden as possible by using
-// techniques from http://www.paciellogroup.com/blog/?p=604. Added
-// support for the "shortcut" format $(window).hashchange( fn ) and
-// $(window).hashchange() like jQuery provides for built-in events.
-// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
-// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
-// and <jQuery.fn.hashchange.src> properties plus document-domain.html
-// file to address access denied issues when setting document.domain in
-// IE6/7.
-// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
-// from a page on another domain would cause an error in Safari 4. Also,
-// IE6/7 Iframe is now inserted after the body (this actually works),
-// which prevents the page from scrolling when the event is first bound.
-// Event can also now be bound before DOM ready, but it won't be usable
-// before then in IE6/7.
-// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
-// where browser version is incorrectly reported as 8.0, despite
-// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
-// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
-// window.onhashchange functionality into a separate plugin for users
-// who want just the basic event & back button support, without all the
-// extra awesomeness that BBQ provides. This plugin will be included as
-// part of jQuery BBQ, but also be available separately.
-
-(function($,window,undefined){
- '$:nomunge'; // Used by YUI compressor.
-
- // Reused string.
- var str_hashchange = 'hashchange',
-
- // Method / object references.
- doc = document,
- fake_onhashchange,
- special = $.event.special,
-
- // Does the browser support window.onhashchange? Note that IE8 running in
- // IE7 compatibility mode reports true for 'onhashchange' in window, even
- // though the event isn't supported, so also test document.documentMode.
- doc_mode = doc.documentMode,
- supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
-
- // Get location.hash (or what you'd expect location.hash to be) sans any
- // leading #. Thanks for making this necessary, Firefox!
- function get_fragment( url ) {
- url = url || location.href;
- return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
- };
-
- // Method: jQuery.fn.hashchange
- //
- // Bind a handler to the window.onhashchange event or trigger all bound
- // window.onhashchange event handlers. This behavior is consistent with
- // jQuery's built-in event handlers.
- //
- // Usage:
- //
- // > jQuery(window).hashchange( [ handler ] );
- //
- // Arguments:
- //
- // handler - (Function) Optional handler to be bound to the hashchange
- // event. This is a "shortcut" for the more verbose form:
- // jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
- // all bound window.onhashchange event handlers will be triggered. This
- // is a shortcut for the more verbose
- // jQuery(window).trigger( 'hashchange' ). These forms are described in
- // the <hashchange event> section.
- //
- // Returns:
- //
- // (jQuery) The initial jQuery collection of elements.
-
- // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
- // $(elem).hashchange() for triggering, like jQuery does for built-in events.
- $.fn[ str_hashchange ] = function( fn ) {
- return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
- };
-
- // Property: jQuery.fn.hashchange.delay
- //
- // The numeric interval (in milliseconds) at which the <hashchange event>
- // polling loop executes. Defaults to 50.
-
- // Property: jQuery.fn.hashchange.domain
- //
- // If you're setting document.domain in your JavaScript, and you want hash
- // history to work in IE6/7, not only must this property be set, but you must
- // also set document.domain BEFORE jQuery is loaded into the page. This
- // property is only applicable if you are supporting IE6/7 (or IE8 operating
- // in "IE7 compatibility" mode).
- //
- // In addition, the <jQuery.fn.hashchange.src> property must be set to the
- // path of the included "document-domain.html" file, which can be renamed or
- // modified if necessary (note that the document.domain specified must be the
- // same in both your main JavaScript as well as in this file).
- //
- // Usage:
- //
- // jQuery.fn.hashchange.domain = document.domain;
-
- // Property: jQuery.fn.hashchange.src
- //
- // If, for some reason, you need to specify an Iframe src file (for example,
- // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
- // do so using this property. Note that when using this property, history
- // won't be recorded in IE6/7 until the Iframe src file loads. This property
- // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
- // compatibility" mode).
- //
- // Usage:
- //
- // jQuery.fn.hashchange.src = 'path/to/file.html';
-
- $.fn[ str_hashchange ].delay = 50;
- /*
- $.fn[ str_hashchange ].domain = null;
- $.fn[ str_hashchange ].src = null;
- */
-
- // Event: hashchange event
- //
- // Fired when location.hash changes. In browsers that support it, the native
- // HTML5 window.onhashchange event is used, otherwise a polling loop is
- // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
- // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
- // compatibility" mode), a hidden Iframe is created to allow the back button
- // and hash-based history to work.
- //
- // Usage as described in <jQuery.fn.hashchange>:
- //
- // > // Bind an event handler.
- // > jQuery(window).hashchange( function(e) {
- // > var hash = location.hash;
- // > ...
- // > });
- // >
- // > // Manually trigger the event handler.
- // > jQuery(window).hashchange();
- //
- // A more verbose usage that allows for event namespacing:
- //
- // > // Bind an event handler.
- // > jQuery(window).bind( 'hashchange', function(e) {
- // > var hash = location.hash;
- // > ...
- // > });
- // >
- // > // Manually trigger the event handler.
- // > jQuery(window).trigger( 'hashchange' );
- //
- // Additional Notes:
- //
- // * The polling loop and Iframe are not created until at least one handler
- // is actually bound to the 'hashchange' event.
- // * If you need the bound handler(s) to execute immediately, in cases where
- // a location.hash exists on page load, via bookmark or page refresh for
- // example, use jQuery(window).hashchange() or the more verbose
- // jQuery(window).trigger( 'hashchange' ).
- // * The event can be bound before DOM ready, but since it won't be usable
- // before then in IE6/7 (due to the necessary Iframe), recommended usage is
- // to bind it inside a DOM ready handler.
-
- // Override existing $.event.special.hashchange methods (allowing this plugin
- // to be defined after jQuery BBQ in BBQ's source code).
- special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
-
- // Called only when the first 'hashchange' event is bound to window.
- setup: function() {
- // If window.onhashchange is supported natively, there's nothing to do..
- if ( supports_onhashchange ) { return false; }
-
- // Otherwise, we need to create our own. And we don't want to call this
- // until the user binds to the event, just in case they never do, since it
- // will create a polling loop and possibly even a hidden Iframe.
- $( fake_onhashchange.start );
- },
-
- // Called only when the last 'hashchange' event is unbound from window.
- teardown: function() {
- // If window.onhashchange is supported natively, there's nothing to do..
- if ( supports_onhashchange ) { return false; }
-
- // Otherwise, we need to stop ours (if possible).
- $( fake_onhashchange.stop );
- }
-
- });
-
- // fake_onhashchange does all the work of triggering the window.onhashchange
- // event for browsers that don't natively support it, including creating a
- // polling loop to watch for hash changes and in IE 6/7 creating a hidden
- // Iframe to enable back and forward.
- fake_onhashchange = (function(){
- var self = {},
- timeout_id,
-
- // Remember the initial hash so it doesn't get triggered immediately.
- last_hash = get_fragment(),
-
- fn_retval = function(val){ return val; },
- history_set = fn_retval,
- history_get = fn_retval;
-
- // Start the polling loop.
- self.start = function() {
- timeout_id || poll();
- };
-
- // Stop the polling loop.
- self.stop = function() {
- timeout_id && clearTimeout( timeout_id );
- timeout_id = undefined;
- };
-
- // This polling loop checks every $.fn.hashchange.delay milliseconds to see
- // if location.hash has changed, and triggers the 'hashchange' event on
- // window when necessary.
- function poll() {
- var hash = get_fragment(),
- history_hash = history_get( last_hash );
-
- if ( hash !== last_hash ) {
- history_set( last_hash = hash, history_hash );
-
- $(window).trigger( str_hashchange );
-
- } else if ( history_hash !== last_hash ) {
- location.href = location.href.replace( /#.*/, '' ) + history_hash;
- }
-
- timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
- };
-
- // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
- // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
- window.attachEvent && !window.addEventListener && !supports_onhashchange && (function(){
- // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
- // when running in "IE7 compatibility" mode.
-
- var iframe,
- iframe_src;
-
- // When the event is bound and polling starts in IE 6/7, create a hidden
- // Iframe for history handling.
- self.start = function(){
- if ( !iframe ) {
- iframe_src = $.fn[ str_hashchange ].src;
- iframe_src = iframe_src && iframe_src + get_fragment();
-
- // Create hidden Iframe. Attempt to make Iframe as hidden as possible
- // by using techniques from http://www.paciellogroup.com/blog/?p=604.
- iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
-
- // When Iframe has completely loaded, initialize the history and
- // start polling.
- .one( 'load', function(){
- iframe_src || history_set( get_fragment() );
- poll();
- })
-
- // Load Iframe src if specified, otherwise nothing.
- .attr( 'src', iframe_src || 'javascript:0' )
-
- // Append Iframe after the end of the body to prevent unnecessary
- // initial page scrolling (yes, this works).
- .insertAfter( 'body' )[0].contentWindow;
-
- // Whenever `document.title` changes, update the Iframe's title to
- // prettify the back/next history menu entries. Since IE sometimes
- // errors with "Unspecified error" the very first time this is set
- // (yes, very useful) wrap this with a try/catch block.
- doc.onpropertychange = function(){
- try {
- if ( event.propertyName === 'title' ) {
- iframe.document.title = doc.title;
- }
- } catch(e) {}
- };
-
- }
- };
-
- // Override the "stop" method since an IE6/7 Iframe was created. Even
- // if there are no longer any bound event handlers, the polling loop
- // is still necessary for back/next to work at all!
- self.stop = fn_retval;
-
- // Get history by looking at the hidden Iframe's location.hash.
- history_get = function() {
- return get_fragment( iframe.location.href );
- };
-
- // Set a new history item by opening and then closing the Iframe
- // document, *then* setting its location.hash. If document.domain has
- // been set, update that as well.
- history_set = function( hash, history_hash ) {
- var iframe_doc = iframe.document,
- domain = $.fn[ str_hashchange ].domain;
-
- if ( hash !== history_hash ) {
- // Update Iframe with any initial `document.title` that might be set.
- iframe_doc.title = doc.title;
-
- // Opening the Iframe's document after it has been closed is what
- // actually adds a history entry.
- iframe_doc.open();
-
- // Set document.domain for the Iframe document as well, if necessary.
- domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
-
- iframe_doc.close();
-
- // Update the Iframe's hash, for great justice.
- iframe.location.hash = hash;
- }
- };
-
- })();
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
- return self;
- })();
-
-})(jQuery,this);
-
-(function( $, undefined ) {
-
- /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
- window.matchMedia = window.matchMedia || (function( doc, undefined ) {
-
- var bool,
- docElem = doc.documentElement,
- refNode = docElem.firstElementChild || docElem.firstChild,
- // fakeBody required for <FF4 when executed in <head>
- fakeBody = doc.createElement( "body" ),
- div = doc.createElement( "div" );
-
- div.id = "mq-test-1";
- div.style.cssText = "position:absolute;top:-100em";
- fakeBody.style.background = "none";
- fakeBody.appendChild(div);
-
- return function(q){
-
- div.innerHTML = "­<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";
-
- docElem.insertBefore( fakeBody, refNode );
- bool = div.offsetWidth === 42;
- docElem.removeChild( fakeBody );
-
- return {
- matches: bool,
- media: q
- };
-
- };
-
- }( document ));
-
- // $.mobile.media uses matchMedia to return a boolean.
- $.mobile.media = function( q ) {
- return window.matchMedia( q ).matches;
- };
-
-})(jQuery);
-
- (function( $, undefined ) {
- var support = {
- touch: "ontouchend" in document
- };
-
- $.mobile.support = $.mobile.support || {};
- $.extend( $.support, support );
- $.extend( $.mobile.support, support );
- }( jQuery ));
-
- (function( $, undefined ) {
- $.extend( $.support, {
- orientation: "orientation" in window && "onorientationchange" in window
- });
- }( jQuery ));
-
-(function( $, undefined ) {
-
-// thx Modernizr
-function propExists( prop ) {
- var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
- props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " ),
- v;
-
- for ( v in props ) {
- if ( fbCSS[ props[ v ] ] !== undefined ) {
- return true;
- }
- }
-}
-
-var fakeBody = $( "<body>" ).prependTo( "html" ),
- fbCSS = fakeBody[ 0 ].style,
- vendors = [ "Webkit", "Moz", "O" ],
- webos = "palmGetResource" in window, //only used to rule out scrollTop
- operamini = window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]",
- bb = window.blackberry && !propExists( "-webkit-transform" ), //only used to rule out box shadow, as it's filled opaque on BB 5 and lower
- nokiaLTE7_3;
-
-// inline SVG support test
-function inlineSVG() {
- // Thanks Modernizr & Erik Dahlstrom
- var w = window,
- svg = !!w.document.createElementNS && !!w.document.createElementNS( "http://www.w3.org/2000/svg", "svg" ).createSVGRect && !( w.opera && navigator.userAgent.indexOf( "Chrome" ) === -1 ),
- support = function( data ) {
- if ( !( data && svg ) ) {
- $( "html" ).addClass( "ui-nosvg" );
- }
- },
- img = new w.Image();
-
- img.onerror = function() {
- support( false );
- };
- img.onload = function() {
- support( img.width === 1 && img.height === 1 );
- };
- img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
-}
-
-function transform3dTest() {
- var mqProp = "transform-3d",
- // Because the `translate3d` test below throws false positives in Android:
- ret = $.mobile.media( "(-" + vendors.join( "-" + mqProp + "),(-" ) + "-" + mqProp + "),(" + mqProp + ")" ),
- el, transforms, t;
-
- if ( ret ) {
- return !!ret;
- }
-
- el = document.createElement( "div" );
- transforms = {
- // We’re omitting Opera for the time being; MS uses unprefixed.
- "MozTransform": "-moz-transform",
- "transform": "transform"
- };
-
- fakeBody.append( el );
-
- for ( t in transforms ) {
- if ( el.style[ t ] !== undefined ) {
- el.style[ t ] = "translate3d( 100px, 1px, 1px )";
- ret = window.getComputedStyle( el ).getPropertyValue( transforms[ t ] );
- }
- }
- return ( !!ret && ret !== "none" );
-}
-
-// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
-function baseTagTest() {
- var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
- base = $( "head base" ),
- fauxEle = null,
- href = "",
- link, rebase;
-
- if ( !base.length ) {
- base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
- } else {
- href = base.attr( "href" );
- }
-
- link = $( "<a href='testurl' />" ).prependTo( fakeBody );
- rebase = link[ 0 ].href;
- base[ 0 ].href = href || location.pathname;
-
- if ( fauxEle ) {
- fauxEle.remove();
- }
- return rebase.indexOf( fauxBase ) === 0;
-}
-
-// Thanks Modernizr
-function cssPointerEventsTest() {
- var element = document.createElement( "x" ),
- documentElement = document.documentElement,
- getComputedStyle = window.getComputedStyle,
- supports;
-
- if ( !( "pointerEvents" in element.style ) ) {
- return false;
- }
-
- element.style.pointerEvents = "auto";
- element.style.pointerEvents = "x";
- documentElement.appendChild( element );
- supports = getComputedStyle &&
- getComputedStyle( element, "" ).pointerEvents === "auto";
- documentElement.removeChild( element );
- return !!supports;
-}
-
-function boundingRect() {
- var div = document.createElement( "div" );
- return typeof div.getBoundingClientRect !== "undefined";
-}
-
-// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
-// allows for inclusion of IE 6+, including Windows Mobile 7
-$.extend( $.mobile, { browser: {} } );
-$.mobile.browser.oldIE = (function() {
- var v = 3,
- div = document.createElement( "div" ),
- a = div.all || [];
-
- do {
- div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->";
- } while( a[0] );
-
- return v > 4 ? v : !v;
-})();
-
-function fixedPosition() {
- var w = window,
- ua = navigator.userAgent,
- platform = navigator.platform,
- // Rendering engine is Webkit, and capture major version
- wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
- wkversion = !!wkmatch && wkmatch[ 1 ],
- ffmatch = ua.match( /Fennec\/([0-9]+)/ ),
- ffversion = !!ffmatch && ffmatch[ 1 ],
- operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ),
- omversion = !!operammobilematch && operammobilematch[ 1 ];
-
- if (
- // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
- ( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 ) ||
- // Opera Mini
- ( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" ) ||
- ( operammobilematch && omversion < 7458 ) ||
- //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
- ( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 ) ||
- // Firefox Mobile before 6.0 -
- ( ffversion && ffversion < 6 ) ||
- // WebOS less than 3
- ( "palmGetResource" in window && wkversion && wkversion < 534 ) ||
- // MeeGo
- ( ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1 ) ) {
- return false;
- }
-
- return true;
-}
-
-$.extend( $.support, {
- // Note, Chrome for iOS has an extremely quirky implementation of popstate.
- // We've chosen to take the shortest path to a bug fix here for issue #5426
- // See the following link for information about the regex chosen
- // https://developers.google.com/chrome/mobile/docs/user-agent#chrome_for_ios_user-agent
- pushState: "pushState" in history &&
- "replaceState" in history &&
- // When running inside a FF iframe, calling replaceState causes an error
- !( window.navigator.userAgent.indexOf( "Firefox" ) >= 0 && window.top !== window ) &&
- ( window.navigator.userAgent.search(/CriOS/) === -1 ),
-
- mediaquery: $.mobile.media( "only all" ),
- cssPseudoElement: !!propExists( "content" ),
- touchOverflow: !!propExists( "overflowScrolling" ),
- cssTransform3d: transform3dTest(),
- boxShadow: !!propExists( "boxShadow" ) && !bb,
- fixedPosition: fixedPosition(),
- scrollTop: ("pageXOffset" in window ||
- "scrollTop" in document.documentElement ||
- "scrollTop" in fakeBody[ 0 ]) && !webos && !operamini,
-
- dynamicBaseTag: baseTagTest(),
- cssPointerEvents: cssPointerEventsTest(),
- boundingRect: boundingRect(),
- inlineSVG: inlineSVG
-});
-
-fakeBody.remove();
-
-// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
-// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
-// Note: This detection below is used as a last resort.
-// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
-nokiaLTE7_3 = (function() {
-
- var ua = window.navigator.userAgent;
-
- //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
- return ua.indexOf( "Nokia" ) > -1 &&
- ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
- ua.indexOf( "AppleWebKit" ) > -1 &&
- ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
-})();
-
-// Support conditions that must be met in order to proceed
-// default enhanced qualifications are media query support OR IE 7+
-
-$.mobile.gradeA = function() {
- return ( ( $.support.mediaquery && $.support.cssPseudoElement ) || $.mobile.browser.oldIE && $.mobile.browser.oldIE >= 8 ) && ( $.support.boundingRect || $.fn.jquery.match(/1\.[0-7+]\.[0-9+]?/) !== null );
-};
-
-$.mobile.ajaxBlacklist =
- // BlackBerry browsers, pre-webkit
- window.blackberry && !window.WebKitPoint ||
- // Opera Mini
- operamini ||
- // Symbian webkits pre 7.3
- nokiaLTE7_3;
-
-// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
-// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
-// This simply reappends the CSS in place, which for some reason makes it apply
-if ( nokiaLTE7_3 ) {
- $(function() {
- $( "head link[rel='stylesheet']" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
- });
-}
-
-// For ruling out shadows via css
-if ( !$.support.boxShadow ) {
- $( "html" ).addClass( "ui-noboxshadow" );
-}
-
-})( jQuery );
-
-
-(function( $, undefined ) {
- var $win = $.mobile.window, self,
- dummyFnToInitNavigate = function() {
- };
-
- $.event.special.beforenavigate = {
- setup: function() {
- $win.on( "navigate", dummyFnToInitNavigate );
- },
-
- teardown: function() {
- $win.off( "navigate", dummyFnToInitNavigate );
- }
- };
-
- $.event.special.navigate = self = {
- bound: false,
-
- pushStateEnabled: true,
-
- originalEventName: undefined,
-
- // If pushstate support is present and push state support is defined to
- // be true on the mobile namespace.
- isPushStateEnabled: function() {
- return $.support.pushState &&
- $.mobile.pushStateEnabled === true &&
- this.isHashChangeEnabled();
- },
-
- // !! assumes mobile namespace is present
- isHashChangeEnabled: function() {
- return $.mobile.hashListeningEnabled === true;
- },
-
- // TODO a lot of duplication between popstate and hashchange
- popstate: function( event ) {
- var newEvent = new $.Event( "navigate" ),
- beforeNavigate = new $.Event( "beforenavigate" ),
- state = event.originalEvent.state || {};
-
- beforeNavigate.originalEvent = event;
- $win.trigger( beforeNavigate );
-
- if ( beforeNavigate.isDefaultPrevented() ) {
- return;
- }
-
- if ( event.historyState ) {
- $.extend(state, event.historyState);
- }
-
- // Make sure the original event is tracked for the end
- // user to inspect incase they want to do something special
- newEvent.originalEvent = event;
-
- // NOTE we let the current stack unwind because any assignment to
- // location.hash will stop the world and run this event handler. By
- // doing this we create a similar behavior to hashchange on hash
- // assignment
- setTimeout(function() {
- $win.trigger( newEvent, {
- state: state
- });
- }, 0);
- },
-
- hashchange: function( event /*, data */ ) {
- var newEvent = new $.Event( "navigate" ),
- beforeNavigate = new $.Event( "beforenavigate" );
-
- beforeNavigate.originalEvent = event;
- $win.trigger( beforeNavigate );
-
- if ( beforeNavigate.isDefaultPrevented() ) {
- return;
- }
-
- // Make sure the original event is tracked for the end
- // user to inspect incase they want to do something special
- newEvent.originalEvent = event;
-
- // Trigger the hashchange with state provided by the user
- // that altered the hash
- $win.trigger( newEvent, {
- // Users that want to fully normalize the two events
- // will need to do history management down the stack and
- // add the state to the event before this binding is fired
- // TODO consider allowing for the explicit addition of callbacks
- // to be fired before this value is set to avoid event timing issues
- state: event.hashchangeState || {}
- });
- },
-
- // TODO We really only want to set this up once
- // but I'm not clear if there's a beter way to achieve
- // this with the jQuery special event structure
- setup: function( /* data, namespaces */ ) {
- if ( self.bound ) {
- return;
- }
-
- self.bound = true;
-
- if ( self.isPushStateEnabled() ) {
- self.originalEventName = "popstate";
- $win.bind( "popstate.navigate", self.popstate );
- } else if ( self.isHashChangeEnabled() ) {
- self.originalEventName = "hashchange";
- $win.bind( "hashchange.navigate", self.hashchange );
- }
- }
- };
-})( jQuery );
-
-
-
-(function( $, undefined ) {
- var path, $base, dialogHashKey = "&ui-state=dialog";
-
- $.mobile.path = path = {
- uiStateKey: "&ui-state",
-
- // This scary looking regular expression parses an absolute URL or its relative
- // variants (protocol, site, document, query, and hash), into the various
- // components (protocol, host, path, query, fragment, etc that make up the
- // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
- // or String.match, it parses the URL into a results array that looks like this:
- //
- // [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
- // [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
- // [2]: http://jblas:password@mycompany.com:8080/mail/inbox
- // [3]: http://jblas:password@mycompany.com:8080
- // [4]: http:
- // [5]: //
- // [6]: jblas:password@mycompany.com:8080
- // [7]: jblas:password
- // [8]: jblas
- // [9]: password
- // [10]: mycompany.com:8080
- // [11]: mycompany.com
- // [12]: 8080
- // [13]: /mail/inbox
- // [14]: /mail/
- // [15]: inbox
- // [16]: ?msg=1234&type=unread
- // [17]: #msg-content
- //
- urlParseRE: /^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,
-
- // Abstraction to address xss (Issue #4787) by removing the authority in
- // browsers that auto decode it. All references to location.href should be
- // replaced with a call to this method so that it can be dealt with properly here
- getLocation: function( url ) {
- var uri = url ? this.parseUrl( url ) : location,
- hash = this.parseUrl( url || location.href ).hash;
-
- // mimic the browser with an empty string when the hash is empty
- hash = hash === "#" ? "" : hash;
-
- // Make sure to parse the url or the location object for the hash because using location.hash
- // is autodecoded in firefox, the rest of the url should be from the object (location unless
- // we're testing) to avoid the inclusion of the authority
- return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
- },
-
- //return the original document url
- getDocumentUrl: function( asParsedObject ) {
- return asParsedObject ? $.extend( {}, path.documentUrl ) : path.documentUrl.href;
- },
-
- parseLocation: function() {
- return this.parseUrl( this.getLocation() );
- },
-
- //Parse a URL into a structure that allows easy access to
- //all of the URL components by name.
- parseUrl: function( url ) {
- // If we're passed an object, we'll assume that it is
- // a parsed url object and just return it back to the caller.
- if ( $.type( url ) === "object" ) {
- return url;
- }
-
- var matches = path.urlParseRE.exec( url || "" ) || [];
-
- // Create an object that allows the caller to access the sub-matches
- // by name. Note that IE returns an empty string instead of undefined,
- // like all other browsers do, so we normalize everything so its consistent
- // no matter what browser we're running on.
- return {
- href: matches[ 0 ] || "",
- hrefNoHash: matches[ 1 ] || "",
- hrefNoSearch: matches[ 2 ] || "",
- domain: matches[ 3 ] || "",
- protocol: matches[ 4 ] || "",
- doubleSlash: matches[ 5 ] || "",
- authority: matches[ 6 ] || "",
- username: matches[ 8 ] || "",
- password: matches[ 9 ] || "",
- host: matches[ 10 ] || "",
- hostname: matches[ 11 ] || "",
- port: matches[ 12 ] || "",
- pathname: matches[ 13 ] || "",
- directory: matches[ 14 ] || "",
- filename: matches[ 15 ] || "",
- search: matches[ 16 ] || "",
- hash: matches[ 17 ] || ""
- };
- },
-
- //Turn relPath into an asbolute path. absPath is
- //an optional absolute path which describes what
- //relPath is relative to.
- makePathAbsolute: function( relPath, absPath ) {
- var absStack,
- relStack,
- i, d;
-
- if ( relPath && relPath.charAt( 0 ) === "/" ) {
- return relPath;
- }
-
- relPath = relPath || "";
- absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";
-
- absStack = absPath ? absPath.split( "/" ) : [];
- relStack = relPath.split( "/" );
-
- for ( i = 0; i < relStack.length; i++ ) {
- d = relStack[ i ];
- switch ( d ) {
- case ".":
- break;
- case "..":
- if ( absStack.length ) {
- absStack.pop();
- }
- break;
- default:
- absStack.push( d );
- break;
- }
- }
- return "/" + absStack.join( "/" );
- },
-
- //Returns true if both urls have the same domain.
- isSameDomain: function( absUrl1, absUrl2 ) {
- return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
- },
-
- //Returns true for any relative variant.
- isRelativeUrl: function( url ) {
- // All relative Url variants have one thing in common, no protocol.
- return path.parseUrl( url ).protocol === "";
- },
-
- //Returns true for an absolute url.
- isAbsoluteUrl: function( url ) {
- return path.parseUrl( url ).protocol !== "";
- },
-
- //Turn the specified realtive URL into an absolute one. This function
- //can handle all relative variants (protocol, site, document, query, fragment).
- makeUrlAbsolute: function( relUrl, absUrl ) {
- if ( !path.isRelativeUrl( relUrl ) ) {
- return relUrl;
- }
-
- if ( absUrl === undefined ) {
- absUrl = this.documentBase;
- }
-
- var relObj = path.parseUrl( relUrl ),
- absObj = path.parseUrl( absUrl ),
- protocol = relObj.protocol || absObj.protocol,
- doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
- authority = relObj.authority || absObj.authority,
- hasPath = relObj.pathname !== "",
- pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
- search = relObj.search || ( !hasPath && absObj.search ) || "",
- hash = relObj.hash;
-
- return protocol + doubleSlash + authority + pathname + search + hash;
- },
-
- //Add search (aka query) params to the specified url.
- addSearchParams: function( url, params ) {
- var u = path.parseUrl( url ),
- p = ( typeof params === "object" ) ? $.param( params ) : params,
- s = u.search || "?";
- return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
- },
-
- convertUrlToDataUrl: function( absUrl ) {
- var u = path.parseUrl( absUrl );
- if ( path.isEmbeddedPage( u ) ) {
- // For embedded pages, remove the dialog hash key as in getFilePath(),
- // and remove otherwise the Data Url won't match the id of the embedded Page.
- return u.hash
- .split( dialogHashKey )[0]
- .replace( /^#/, "" )
- .replace( /\?.*$/, "" );
- } else if ( path.isSameDomain( u, this.documentBase ) ) {
- return u.hrefNoHash.replace( this.documentBase.domain, "" ).split( dialogHashKey )[0];
- }
-
- return window.decodeURIComponent(absUrl);
- },
-
- //get path from current hash, or from a file path
- get: function( newPath ) {
- if ( newPath === undefined ) {
- newPath = path.parseLocation().hash;
- }
- return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, "" );
- },
-
- //set location hash to path
- set: function( path ) {
- location.hash = path;
- },
-
- //test if a given url (string) is a path
- //NOTE might be exceptionally naive
- isPath: function( url ) {
- return ( /\// ).test( url );
- },
-
- //return a url path with the window's location protocol/hostname/pathname removed
- clean: function( url ) {
- return url.replace( this.documentBase.domain, "" );
- },
-
- //just return the url without an initial #
- stripHash: function( url ) {
- return url.replace( /^#/, "" );
- },
-
- stripQueryParams: function( url ) {
- return url.replace( /\?.*$/, "" );
- },
-
- //remove the preceding hash, any query params, and dialog notations
- cleanHash: function( hash ) {
- return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
- },
-
- isHashValid: function( hash ) {
- return ( /^#[^#]+$/ ).test( hash );
- },
-
- //check whether a url is referencing the same domain, or an external domain or different protocol
- //could be mailto, etc
- isExternal: function( url ) {
- var u = path.parseUrl( url );
- return u.protocol && u.domain !== this.documentUrl.domain ? true : false;
- },
-
- hasProtocol: function( url ) {
- return ( /^(:?\w+:)/ ).test( url );
- },
-
- isEmbeddedPage: function( url ) {
- var u = path.parseUrl( url );
-
- //if the path is absolute, then we need to compare the url against
- //both the this.documentUrl and the documentBase. The main reason for this
- //is that links embedded within external documents will refer to the
- //application document, whereas links embedded within the application
- //document will be resolved against the document base.
- if ( u.protocol !== "" ) {
- return ( !this.isPath(u.hash) && u.hash && ( u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ) ) );
- }
- return ( /^#/ ).test( u.href );
- },
-
- squash: function( url, resolutionUrl ) {
- var href, cleanedUrl, search, stateIndex,
- isPath = this.isPath( url ),
- uri = this.parseUrl( url ),
- preservedHash = uri.hash,
- uiState = "";
-
- // produce a url against which we can resole the provided path
- resolutionUrl = resolutionUrl || (path.isPath(url) ? path.getLocation() : path.getDocumentUrl());
-
- // If the url is anything but a simple string, remove any preceding hash
- // eg #foo/bar -> foo/bar
- // #foo -> #foo
- cleanedUrl = isPath ? path.stripHash( url ) : url;
-
- // If the url is a full url with a hash check if the parsed hash is a path
- // if it is, strip the #, and use it otherwise continue without change
- cleanedUrl = path.isPath( uri.hash ) ? path.stripHash( uri.hash ) : cleanedUrl;
-
- // Split the UI State keys off the href
- stateIndex = cleanedUrl.indexOf( this.uiStateKey );
-
- // store the ui state keys for use
- if ( stateIndex > -1 ) {
- uiState = cleanedUrl.slice( stateIndex );
- cleanedUrl = cleanedUrl.slice( 0, stateIndex );
- }
-
- // make the cleanedUrl absolute relative to the resolution url
- href = path.makeUrlAbsolute( cleanedUrl, resolutionUrl );
-
- // grab the search from the resolved url since parsing from
- // the passed url may not yield the correct result
- search = this.parseUrl( href ).search;
-
- // TODO all this crap is terrible, clean it up
- if ( isPath ) {
- // reject the hash if it's a path or it's just a dialog key
- if ( path.isPath( preservedHash ) || preservedHash.replace("#", "").indexOf( this.uiStateKey ) === 0) {
- preservedHash = "";
- }
-
- // Append the UI State keys where it exists and it's been removed
- // from the url
- if ( uiState && preservedHash.indexOf( this.uiStateKey ) === -1) {
- preservedHash += uiState;
- }
-
- // make sure that pound is on the front of the hash
- if ( preservedHash.indexOf( "#" ) === -1 && preservedHash !== "" ) {
- preservedHash = "#" + preservedHash;
- }
-
- // reconstruct each of the pieces with the new search string and hash
- href = path.parseUrl( href );
- href = href.protocol + "//" + href.host + href.pathname + search + preservedHash;
- } else {
- href += href.indexOf( "#" ) > -1 ? uiState : "#" + uiState;
- }
-
- return href;
- },
-
- isPreservableHash: function( hash ) {
- return hash.replace( "#", "" ).indexOf( this.uiStateKey ) === 0;
- },
-
- // Escape weird characters in the hash if it is to be used as a selector
- hashToSelector: function( hash ) {
- var hasHash = ( hash.substring( 0, 1 ) === "#" );
- if ( hasHash ) {
- hash = hash.substring( 1 );
- }
- return ( hasHash ? "#" : "" ) + hash.replace( /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g, "\\$1" );
- },
-
- // return the substring of a filepath before the sub-page key, for making
- // a server request
- getFilePath: function( path ) {
- var splitkey = "&" + $.mobile.subPageUrlKey;
- return path && path.split( splitkey )[0].split( dialogHashKey )[0];
- },
-
- // check if the specified url refers to the first page in the main
- // application document.
- isFirstPageUrl: function( url ) {
- // We only deal with absolute paths.
- var u = path.parseUrl( path.makeUrlAbsolute( url, this.documentBase ) ),
-
- // Does the url have the same path as the document?
- samePath = u.hrefNoHash === this.documentUrl.hrefNoHash ||
- ( this.documentBaseDiffers &&
- u.hrefNoHash === this.documentBase.hrefNoHash ),
-
- // Get the first page element.
- fp = $.mobile.firstPage,
-
- // Get the id of the first page element if it has one.
- fpId = fp && fp[0] ? fp[0].id : undefined;
-
- // The url refers to the first page if the path matches the document and
- // it either has no hash value, or the hash is exactly equal to the id
- // of the first page element.
- return samePath &&
- ( !u.hash ||
- u.hash === "#" ||
- ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
- },
-
- // Some embedded browsers, like the web view in Phone Gap, allow
- // cross-domain XHR requests if the document doing the request was loaded
- // via the file:// protocol. This is usually to allow the application to
- // "phone home" and fetch app specific data. We normally let the browser
- // handle external/cross-domain urls, but if the allowCrossDomainPages
- // option is true, we will allow cross-domain http/https requests to go
- // through our page loading logic.
- isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
- return $.mobile.allowCrossDomainPages &&
- (docUrl.protocol === "file:" || docUrl.protocol === "content:") &&
- reqUrl.search( /^https?:/ ) !== -1;
- }
- };
-
- path.documentUrl = path.parseLocation();
-
- $base = $( "head" ).find( "base" );
-
- path.documentBase = $base.length ?
- path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), path.documentUrl.href ) ) :
- path.documentUrl;
-
- path.documentBaseDiffers = (path.documentUrl.hrefNoHash !== path.documentBase.hrefNoHash);
-
- //return the original document base url
- path.getDocumentBase = function( asParsedObject ) {
- return asParsedObject ? $.extend( {}, path.documentBase ) : path.documentBase.href;
- };
-
- // DEPRECATED as of 1.4.0 - remove in 1.5.0
- $.extend( $.mobile, {
-
- //return the original document url
- getDocumentUrl: path.getDocumentUrl,
-
- //return the original document base url
- getDocumentBase: path.getDocumentBase
- });
-})( jQuery );
-
-
-
-(function( $, undefined ) {
- $.mobile.History = function( stack, index ) {
- this.stack = stack || [];
- this.activeIndex = index || 0;
- };
-
- $.extend($.mobile.History.prototype, {
- getActive: function() {
- return this.stack[ this.activeIndex ];
- },
-
- getLast: function() {
- return this.stack[ this.previousIndex ];
- },
-
- getNext: function() {
- return this.stack[ this.activeIndex + 1 ];
- },
-
- getPrev: function() {
- return this.stack[ this.activeIndex - 1 ];
- },
-
- // addNew is used whenever a new page is added
- add: function( url, data ) {
- data = data || {};
-
- //if there's forward history, wipe it
- if ( this.getNext() ) {
- this.clearForward();
- }
-
- // if the hash is included in the data make sure the shape
- // is consistent for comparison
- if ( data.hash && data.hash.indexOf( "#" ) === -1) {
- data.hash = "#" + data.hash;
- }
-
- data.url = url;
- this.stack.push( data );
- this.activeIndex = this.stack.length - 1;
- },
-
- //wipe urls ahead of active index
- clearForward: function() {
- this.stack = this.stack.slice( 0, this.activeIndex + 1 );
- },
-
- find: function( url, stack, earlyReturn ) {
- stack = stack || this.stack;
-
- var entry, i, length = stack.length, index;
-
- for ( i = 0; i < length; i++ ) {
- entry = stack[i];
-
- if ( decodeURIComponent(url) === decodeURIComponent(entry.url) ||
- decodeURIComponent(url) === decodeURIComponent(entry.hash) ) {
- index = i;
-
- if ( earlyReturn ) {
- return index;
- }
- }
- }
-
- return index;
- },
-
- closest: function( url ) {
- var closest, a = this.activeIndex;
-
- // First, take the slice of the history stack before the current index and search
- // for a url match. If one is found, we'll avoid avoid looking through forward history
- // NOTE the preference for backward history movement is driven by the fact that
- // most mobile browsers only have a dedicated back button, and users rarely use
- // the forward button in desktop browser anyhow
- closest = this.find( url, this.stack.slice(0, a) );
-
- // If nothing was found in backward history check forward. The `true`
- // value passed as the third parameter causes the find method to break
- // on the first match in the forward history slice. The starting index
- // of the slice must then be added to the result to get the element index
- // in the original history stack :( :(
- //
- // TODO this is hyper confusing and should be cleaned up (ugh so bad)
- if ( closest === undefined ) {
- closest = this.find( url, this.stack.slice(a), true );
- closest = closest === undefined ? closest : closest + a;
- }
-
- return closest;
- },
-
- direct: function( opts ) {
- var newActiveIndex = this.closest( opts.url ), a = this.activeIndex;
-
- // save new page index, null check to prevent falsey 0 result
- // record the previous index for reference
- if ( newActiveIndex !== undefined ) {
- this.activeIndex = newActiveIndex;
- this.previousIndex = a;
- }
-
- // invoke callbacks where appropriate
- //
- // TODO this is also convoluted and confusing
- if ( newActiveIndex < a ) {
- ( opts.present || opts.back || $.noop )( this.getActive(), "back" );
- } else if ( newActiveIndex > a ) {
- ( opts.present || opts.forward || $.noop )( this.getActive(), "forward" );
- } else if ( newActiveIndex === undefined && opts.missing ) {
- opts.missing( this.getActive() );
- }
- }
- });
-})( jQuery );
-
-
-
-(function( $, undefined ) {
- var path = $.mobile.path,
- initialHref = location.href;
-
- $.mobile.Navigator = function( history ) {
- this.history = history;
- this.ignoreInitialHashChange = true;
-
- $.mobile.window.bind({
- "popstate.history": $.proxy( this.popstate, this ),
- "hashchange.history": $.proxy( this.hashchange, this )
- });
- };
-
- $.extend($.mobile.Navigator.prototype, {
- squash: function( url, data ) {
- var state, href, hash = path.isPath(url) ? path.stripHash(url) : url;
-
- href = path.squash( url );
-
- // make sure to provide this information when it isn't explicitly set in the
- // data object that was passed to the squash method
- state = $.extend({
- hash: hash,
- url: href
- }, data);
-
- // replace the current url with the new href and store the state
- // Note that in some cases we might be replacing an url with the
- // same url. We do this anyways because we need to make sure that
- // all of our history entries have a state object associated with
- // them. This allows us to work around the case where $.mobile.back()
- // is called to transition from an external page to an embedded page.
- // In that particular case, a hashchange event is *NOT* generated by the browser.
- // Ensuring each history entry has a state object means that onPopState()
- // will always trigger our hashchange callback even when a hashchange event
- // is not fired.
- window.history.replaceState( state, state.title || document.title, href );
-
- return state;
- },
-
- hash: function( url, href ) {
- var parsed, loc, hash, resolved;
-
- // Grab the hash for recording. If the passed url is a path
- // we used the parsed version of the squashed url to reconstruct,
- // otherwise we assume it's a hash and store it directly
- parsed = path.parseUrl( url );
- loc = path.parseLocation();
-
- if ( loc.pathname + loc.search === parsed.pathname + parsed.search ) {
- // If the pathname and search of the passed url is identical to the current loc
- // then we must use the hash. Otherwise there will be no event
- // eg, url = "/foo/bar?baz#bang", location.href = "http://example.com/foo/bar?baz"
- hash = parsed.hash ? parsed.hash : parsed.pathname + parsed.search;
- } else if ( path.isPath(url) ) {
- resolved = path.parseUrl( href );
- // If the passed url is a path, make it domain relative and remove any trailing hash
- hash = resolved.pathname + resolved.search + (path.isPreservableHash( resolved.hash )? resolved.hash.replace( "#", "" ) : "");
- } else {
- hash = url;
- }
-
- return hash;
- },
-
- // TODO reconsider name
- go: function( url, data, noEvents ) {
- var state, href, hash, popstateEvent,
- isPopStateEvent = $.event.special.navigate.isPushStateEnabled();
-
- // Get the url as it would look squashed on to the current resolution url
- href = path.squash( url );
-
- // sort out what the hash sould be from the url
- hash = this.hash( url, href );
-
- // Here we prevent the next hash change or popstate event from doing any
- // history management. In the case of hashchange we don't swallow it
- // if there will be no hashchange fired (since that won't reset the value)
- // and will swallow the following hashchange
- if ( noEvents && hash !== path.stripHash(path.parseLocation().hash) ) {
- this.preventNextHashChange = noEvents;
- }
-
- // IMPORTANT in the case where popstate is supported the event will be triggered
- // directly, stopping further execution - ie, interupting the flow of this
- // method call to fire bindings at this expression. Below the navigate method
- // there is a binding to catch this event and stop its propagation.
- //
- // We then trigger a new popstate event on the window with a null state
- // so that the navigate events can conclude their work properly
- //
- // if the url is a path we want to preserve the query params that are available on
- // the current url.
- this.preventHashAssignPopState = true;
- window.location.hash = hash;
-
- // If popstate is enabled and the browser triggers `popstate` events when the hash
- // is set (this often happens immediately in browsers like Chrome), then the
- // this flag will be set to false already. If it's a browser that does not trigger
- // a `popstate` on hash assignement or `replaceState` then we need avoid the branch
- // that swallows the event created by the popstate generated by the hash assignment
- // At the time of this writing this happens with Opera 12 and some version of IE
- this.preventHashAssignPopState = false;
-
- state = $.extend({
- url: href,
- hash: hash,
- title: document.title
- }, data);
-
- if ( isPopStateEvent ) {
- popstateEvent = new $.Event( "popstate" );
- popstateEvent.originalEvent = {
- type: "popstate",
- state: null
- };
-
- this.squash( url, state );
-
- // Trigger a new faux popstate event to replace the one that we
- // caught that was triggered by the hash setting above.
- if ( !noEvents ) {
- this.ignorePopState = true;
- $.mobile.window.trigger( popstateEvent );
- }
- }
-
- // record the history entry so that the information can be included
- // in hashchange event driven navigate events in a similar fashion to
- // the state that's provided by popstate
- this.history.add( state.url, state );
- },
-
- // This binding is intended to catch the popstate events that are fired
- // when execution of the `$.navigate` method stops at window.location.hash = url;
- // and completely prevent them from propagating. The popstate event will then be
- // retriggered after execution resumes
- //
- // TODO grab the original event here and use it for the synthetic event in the
- // second half of the navigate execution that will follow this binding
- popstate: function( event ) {
- var hash, state;
-
- // Partly to support our test suite which manually alters the support
- // value to test hashchange. Partly to prevent all around weirdness
- if ( !$.event.special.navigate.isPushStateEnabled() ) {
- return;
- }
-
- // If this is the popstate triggered by the actual alteration of the hash
- // prevent it completely. History is tracked manually
- if ( this.preventHashAssignPopState ) {
- this.preventHashAssignPopState = false;
- event.stopImmediatePropagation();
- return;
- }
-
- // if this is the popstate triggered after the `replaceState` call in the go
- // method, then simply ignore it. The history entry has already been captured
- if ( this.ignorePopState ) {
- this.ignorePopState = false;
- return;
- }
-
- // If there is no state, and the history stack length is one were
- // probably getting the page load popstate fired by browsers like chrome
- // avoid it and set the one time flag to false.
- // TODO: Do we really need all these conditions? Comparing location hrefs
- // should be sufficient.
- if ( !event.originalEvent.state &&
- this.history.stack.length === 1 &&
- this.ignoreInitialHashChange ) {
- this.ignoreInitialHashChange = false;
-
- if ( location.href === initialHref ) {
- event.preventDefault();
- return;
- }
- }
-
- // account for direct manipulation of the hash. That is, we will receive a popstate
- // when the hash is changed by assignment, and it won't have a state associated. We
- // then need to squash the hash. See below for handling of hash assignment that
- // matches an existing history entry
- // TODO it might be better to only add to the history stack
- // when the hash is adjacent to the active history entry
- hash = path.parseLocation().hash;
- if ( !event.originalEvent.state && hash ) {
- // squash the hash that's been assigned on the URL with replaceState
- // also grab the resulting state object for storage
- state = this.squash( hash );
-
- // record the new hash as an additional history entry
- // to match the browser's treatment of hash assignment
- this.history.add( state.url, state );
-
- // pass the newly created state information
- // along with the event
- event.historyState = state;
-
- // do not alter history, we've added a new history entry
- // so we know where we are
- return;
- }
-
- // If all else fails this is a popstate that comes from the back or forward buttons
- // make sure to set the state of our history stack properly, and record the directionality
- this.history.direct({
- url: (event.originalEvent.state || {}).url || hash,
-
- // When the url is either forward or backward in history include the entry
- // as data on the event object for merging as data in the navigate event
- present: function( historyEntry, direction ) {
- // make sure to create a new object to pass down as the navigate event data
- event.historyState = $.extend({}, historyEntry);
- event.historyState.direction = direction;
- }
- });
- },
-
- // NOTE must bind before `navigate` special event hashchange binding otherwise the
- // navigation data won't be attached to the hashchange event in time for those
- // bindings to attach it to the `navigate` special event
- // TODO add a check here that `hashchange.navigate` is bound already otherwise it's
- // broken (exception?)
- hashchange: function( event ) {
- var history, hash;
-
- // If hashchange listening is explicitly disabled or pushstate is supported
- // avoid making use of the hashchange handler.
- if (!$.event.special.navigate.isHashChangeEnabled() ||
- $.event.special.navigate.isPushStateEnabled() ) {
- return;
- }
-
- // On occasion explicitly want to prevent the next hash from propogating because we only
- // with to alter the url to represent the new state do so here
- if ( this.preventNextHashChange ) {
- this.preventNextHashChange = false;
- event.stopImmediatePropagation();
- return;
- }
-
- history = this.history;
- hash = path.parseLocation().hash;
-
- // If this is a hashchange caused by the back or forward button
- // make sure to set the state of our history stack properly
- this.history.direct({
- url: hash,
-
- // When the url is either forward or backward in history include the entry
- // as data on the event object for merging as data in the navigate event
- present: function( historyEntry, direction ) {
- // make sure to create a new object to pass down as the navigate event data
- event.hashchangeState = $.extend({}, historyEntry);
- event.hashchangeState.direction = direction;
- },
-
- // When we don't find a hash in our history clearly we're aiming to go there
- // record the entry as new for future traversal
- //
- // NOTE it's not entirely clear that this is the right thing to do given that we
- // can't know the users intention. It might be better to explicitly _not_
- // support location.hash assignment in preference to $.navigate calls
- // TODO first arg to add should be the href, but it causes issues in identifying
- // embeded pages
- missing: function() {
- history.add( hash, {
- hash: hash,
- title: document.title
- });
- }
- });
- }
- });
-})( jQuery );
-
-
-
-(function( $, undefined ) {
- // TODO consider queueing navigation activity until previous activities have completed
- // so that end users don't have to think about it. Punting for now
- // TODO !! move the event bindings into callbacks on the navigate event
- $.mobile.navigate = function( url, data, noEvents ) {
- $.mobile.navigate.navigator.go( url, data, noEvents );
- };
-
- // expose the history on the navigate method in anticipation of full integration with
- // existing navigation functionalty that is tightly coupled to the history information
- $.mobile.navigate.history = new $.mobile.History();
-
- // instantiate an instance of the navigator for use within the $.navigate method
- $.mobile.navigate.navigator = new $.mobile.Navigator( $.mobile.navigate.history );
-
- var loc = $.mobile.path.parseLocation();
- $.mobile.navigate.history.add( loc.href, {hash: loc.hash} );
-})( jQuery );
-
-
-(function( $, undefined ) {
- var props = {
- "animation": {},
- "transition": {}
- },
- testElement = document.createElement( "a" ),
- vendorPrefixes = [ "", "webkit-", "moz-", "o-" ];
-
- $.each( [ "animation", "transition" ], function( i, test ) {
-
- // Get correct name for test
- var testName = ( i === 0 ) ? test + "-" + "name" : test;
-
- $.each( vendorPrefixes, function( j, prefix ) {
- if ( testElement.style[ $.camelCase( prefix + testName ) ] !== undefined ) {
- props[ test ][ "prefix" ] = prefix;
- return false;
- }
- });
-
- // Set event and duration names for later use
- props[ test ][ "duration" ] =
- $.camelCase( props[ test ][ "prefix" ] + test + "-" + "duration" );
- props[ test ][ "event" ] =
- $.camelCase( props[ test ][ "prefix" ] + test + "-" + "end" );
-
- // All lower case if not a vendor prop
- if ( props[ test ][ "prefix" ] === "" ) {
- props[ test ][ "event" ] = props[ test ][ "event" ].toLowerCase();
- }
- });
-
- // If a valid prefix was found then the it is supported by the browser
- $.support.cssTransitions = ( props[ "transition" ][ "prefix" ] !== undefined );
- $.support.cssAnimations = ( props[ "animation" ][ "prefix" ] !== undefined );
-
- // Remove the testElement
- $( testElement ).remove();
-
- // Animation complete callback
- $.fn.animationComplete = function( callback, type, fallbackTime ) {
- var timer, duration,
- that = this,
- animationType = ( !type || type === "animation" ) ? "animation" : "transition";
-
- // Make sure selected type is supported by browser
- if ( ( $.support.cssTransitions && animationType === "transition" ) ||
- ( $.support.cssAnimations && animationType === "animation" ) ) {
-
- // If a fallback time was not passed set one
- if ( fallbackTime === undefined ) {
-
- // Make sure the was not bound to document before checking .css
- if ( $( this ).context !== document ) {
-
- // Parse the durration since its in second multiple by 1000 for milliseconds
- // Multiply by 3 to make sure we give the animation plenty of time.
- duration = parseFloat(
- $( this ).css( props[ animationType ].duration )
- ) * 3000;
- }
-
- // If we could not read a duration use the default
- if ( duration === 0 || duration === undefined || isNaN( duration ) ) {
- duration = $.fn.animationComplete.defaultDuration;
- }
- }
-
- // Sets up the fallback if event never comes
- timer = setTimeout( function() {
- $( that ).off( props[ animationType ].event );
- callback.apply( that );
- }, duration );
-
- // Bind the event
- return $( this ).one( props[ animationType ].event, function() {
-
- // Clear the timer so we dont call callback twice
- clearTimeout( timer );
- callback.call( this, arguments );
- });
- } else {
-
- // CSS animation / transitions not supported
- // Defer execution for consistency between webkit/non webkit
- setTimeout( $.proxy( callback, this ), 0 );
- return $( this );
- }
- };
-
- // Allow default callback to be configured on mobileInit
- $.fn.animationComplete.defaultDuration = 1000;
-})( jQuery );
-
-// This plugin is an experiment for abstracting away the touch and mouse
-// events so that developers don't have to worry about which method of input
-// the device their document is loaded on supports.
-//
-// The idea here is to allow the developer to register listeners for the
-// basic mouse events, such as mousedown, mousemove, mouseup, and click,
-// and the plugin will take care of registering the correct listeners
-// behind the scenes to invoke the listener at the fastest possible time
-// for that device, while still retaining the order of event firing in
-// the traditional mouse environment, should multiple handlers be registered
-// on the same element for different events.
-//
-// The current version exposes the following virtual events to jQuery bind methods:
-// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
-
-(function( $, window, document, undefined ) {
-
-var dataPropertyName = "virtualMouseBindings",
- touchTargetPropertyName = "virtualTouchID",
- virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
- touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
- mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [],
- mouseEventProps = $.event.props.concat( mouseHookProps ),
- activeDocHandlers = {},
- resetTimerID = 0,
- startX = 0,
- startY = 0,
- didScroll = false,
- clickBlockList = [],
- blockMouseTriggers = false,
- blockTouchTriggers = false,
- eventCaptureSupported = "addEventListener" in document,
- $document = $( document ),
- nextTouchID = 1,
- lastTouchID = 0, threshold,
- i;
-
-$.vmouse = {
- moveDistanceThreshold: 10,
- clickDistanceThreshold: 10,
- resetTimerDuration: 1500
-};
-
-function getNativeEvent( event ) {
-
- while ( event && typeof event.originalEvent !== "undefined" ) {
- event = event.originalEvent;
- }
- return event;
-}
-
-function createVirtualEvent( event, eventType ) {
-
- var t = event.type,
- oe, props, ne, prop, ct, touch, i, j, len;
-
- event = $.Event( event );
- event.type = eventType;
-
- oe = event.originalEvent;
- props = $.event.props;
-
- // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
- // https://github.com/jquery/jquery-mobile/issues/3280
- if ( t.search( /^(mouse|click)/ ) > -1 ) {
- props = mouseEventProps;
- }
-
- // copy original event properties over to the new event
- // this would happen if we could call $.event.fix instead of $.Event
- // but we don't have a way to force an event to be fixed multiple times
- if ( oe ) {
- for ( i = props.length, prop; i; ) {
- prop = props[ --i ];
- event[ prop ] = oe[ prop ];
- }
- }
-
- // make sure that if the mouse and click virtual events are generated
- // without a .which one is defined
- if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) {
- event.which = 1;
- }
-
- if ( t.search(/^touch/) !== -1 ) {
- ne = getNativeEvent( oe );
- t = ne.touches;
- ct = ne.changedTouches;
- touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined );
-
- if ( touch ) {
- for ( j = 0, len = touchEventProps.length; j < len; j++) {
- prop = touchEventProps[ j ];
- event[ prop ] = touch[ prop ];
- }
- }
- }
-
- return event;
-}
-
-function getVirtualBindingFlags( element ) {
-
- var flags = {},
- b, k;
-
- while ( element ) {
-
- b = $.data( element, dataPropertyName );
-
- for ( k in b ) {
- if ( b[ k ] ) {
- flags[ k ] = flags.hasVirtualBinding = true;
- }
- }
- element = element.parentNode;
- }
- return flags;
-}
-
-function getClosestElementWithVirtualBinding( element, eventType ) {
- var b;
- while ( element ) {
-
- b = $.data( element, dataPropertyName );
-
- if ( b && ( !eventType || b[ eventType ] ) ) {
- return element;
- }
- element = element.parentNode;
- }
- return null;
-}
-
-function enableTouchBindings() {
- blockTouchTriggers = false;
-}
-
-function disableTouchBindings() {
- blockTouchTriggers = true;
-}
-
-function enableMouseBindings() {
- lastTouchID = 0;
- clickBlockList.length = 0;
- blockMouseTriggers = false;
-
- // When mouse bindings are enabled, our
- // touch bindings are disabled.
- disableTouchBindings();
-}
-
-function disableMouseBindings() {
- // When mouse bindings are disabled, our
- // touch bindings are enabled.
- enableTouchBindings();
-}
-
-function startResetTimer() {
- clearResetTimer();
- resetTimerID = setTimeout( function() {
- resetTimerID = 0;
- enableMouseBindings();
- }, $.vmouse.resetTimerDuration );
-}
-
-function clearResetTimer() {
- if ( resetTimerID ) {
- clearTimeout( resetTimerID );
- resetTimerID = 0;
- }
-}
-
-function triggerVirtualEvent( eventType, event, flags ) {
- var ve;
-
- if ( ( flags && flags[ eventType ] ) ||
- ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
-
- ve = createVirtualEvent( event, eventType );
-
- $( event.target).trigger( ve );
- }
-
- return ve;
-}
-
-function mouseEventCallback( event ) {
- var touchID = $.data( event.target, touchTargetPropertyName ),
- ve;
-
- if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) {
- ve = triggerVirtualEvent( "v" + event.type, event );
- if ( ve ) {
- if ( ve.isDefaultPrevented() ) {
- event.preventDefault();
- }
- if ( ve.isPropagationStopped() ) {
- event.stopPropagation();
- }
- if ( ve.isImmediatePropagationStopped() ) {
- event.stopImmediatePropagation();
- }
- }
- }
-}
-
-function handleTouchStart( event ) {
-
- var touches = getNativeEvent( event ).touches,
- target, flags, t;
-
- if ( touches && touches.length === 1 ) {
-
- target = event.target;
- flags = getVirtualBindingFlags( target );
-
- if ( flags.hasVirtualBinding ) {
-
- lastTouchID = nextTouchID++;
- $.data( target, touchTargetPropertyName, lastTouchID );
-
- clearResetTimer();
-
- disableMouseBindings();
- didScroll = false;
-
- t = getNativeEvent( event ).touches[ 0 ];
- startX = t.pageX;
- startY = t.pageY;
-
- triggerVirtualEvent( "vmouseover", event, flags );
- triggerVirtualEvent( "vmousedown", event, flags );
- }
- }
-}
-
-function handleScroll( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- if ( !didScroll ) {
- triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
- }
-
- didScroll = true;
- startResetTimer();
-}
-
-function handleTouchMove( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- var t = getNativeEvent( event ).touches[ 0 ],
- didCancel = didScroll,
- moveThreshold = $.vmouse.moveDistanceThreshold,
- flags = getVirtualBindingFlags( event.target );
-
- didScroll = didScroll ||
- ( Math.abs( t.pageX - startX ) > moveThreshold ||
- Math.abs( t.pageY - startY ) > moveThreshold );
-
- if ( didScroll && !didCancel ) {
- triggerVirtualEvent( "vmousecancel", event, flags );
- }
-
- triggerVirtualEvent( "vmousemove", event, flags );
- startResetTimer();
-}
-
-function handleTouchEnd( event ) {
- if ( blockTouchTriggers ) {
- return;
- }
-
- disableTouchBindings();
-
- var flags = getVirtualBindingFlags( event.target ),
- ve, t;
- triggerVirtualEvent( "vmouseup", event, flags );
-
- if ( !didScroll ) {
- ve = triggerVirtualEvent( "vclick", event, flags );
- if ( ve && ve.isDefaultPrevented() ) {
- // The target of the mouse events that follow the touchend
- // event don't necessarily match the target used during the
- // touch. This means we need to rely on coordinates for blocking
- // any click that is generated.
- t = getNativeEvent( event ).changedTouches[ 0 ];
- clickBlockList.push({
- touchID: lastTouchID,
- x: t.clientX,
- y: t.clientY
- });
-
- // Prevent any mouse events that follow from triggering
- // virtual event notifications.
- blockMouseTriggers = true;
- }
- }
- triggerVirtualEvent( "vmouseout", event, flags);
- didScroll = false;
-
- startResetTimer();
-}
-
-function hasVirtualBindings( ele ) {
- var bindings = $.data( ele, dataPropertyName ),
- k;
-
- if ( bindings ) {
- for ( k in bindings ) {
- if ( bindings[ k ] ) {
- return true;
- }
- }
- }
- return false;
-}
-
-function dummyMouseHandler() {}
-
-function getSpecialEventObject( eventType ) {
- var realType = eventType.substr( 1 );
-
- return {
- setup: function(/* data, namespace */) {
- // If this is the first virtual mouse binding for this element,
- // add a bindings object to its data.
-
- if ( !hasVirtualBindings( this ) ) {
- $.data( this, dataPropertyName, {} );
- }
-
- // If setup is called, we know it is the first binding for this
- // eventType, so initialize the count for the eventType to zero.
- var bindings = $.data( this, dataPropertyName );
- bindings[ eventType ] = true;
-
- // If this is the first virtual mouse event for this type,
- // register a global handler on the document.
-
- activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;
-
- if ( activeDocHandlers[ eventType ] === 1 ) {
- $document.bind( realType, mouseEventCallback );
- }
-
- // Some browsers, like Opera Mini, won't dispatch mouse/click events
- // for elements unless they actually have handlers registered on them.
- // To get around this, we register dummy handlers on the elements.
-
- $( this ).bind( realType, dummyMouseHandler );
-
- // For now, if event capture is not supported, we rely on mouse handlers.
- if ( eventCaptureSupported ) {
- // If this is the first virtual mouse binding for the document,
- // register our touchstart handler on the document.
-
- activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;
-
- if ( activeDocHandlers[ "touchstart" ] === 1 ) {
- $document.bind( "touchstart", handleTouchStart )
- .bind( "touchend", handleTouchEnd )
-
- // On touch platforms, touching the screen and then dragging your finger
- // causes the window content to scroll after some distance threshold is
- // exceeded. On these platforms, a scroll prevents a click event from being
- // dispatched, and on some platforms, even the touchend is suppressed. To
- // mimic the suppression of the click event, we need to watch for a scroll
- // event. Unfortunately, some platforms like iOS don't dispatch scroll
- // events until *AFTER* the user lifts their finger (touchend). This means
- // we need to watch both scroll and touchmove events to figure out whether
- // or not a scroll happenens before the touchend event is fired.
-
- .bind( "touchmove", handleTouchMove )
- .bind( "scroll", handleScroll );
- }
- }
- },
-
- teardown: function(/* data, namespace */) {
- // If this is the last virtual binding for this eventType,
- // remove its global handler from the document.
-
- --activeDocHandlers[ eventType ];
-
- if ( !activeDocHandlers[ eventType ] ) {
- $document.unbind( realType, mouseEventCallback );
- }
-
- if ( eventCaptureSupported ) {
- // If this is the last virtual mouse binding in existence,
- // remove our document touchstart listener.
-
- --activeDocHandlers[ "touchstart" ];
-
- if ( !activeDocHandlers[ "touchstart" ] ) {
- $document.unbind( "touchstart", handleTouchStart )
- .unbind( "touchmove", handleTouchMove )
- .unbind( "touchend", handleTouchEnd )
- .unbind( "scroll", handleScroll );
- }
- }
-
- var $this = $( this ),
- bindings = $.data( this, dataPropertyName );
-
- // teardown may be called when an element was
- // removed from the DOM. If this is the case,
- // jQuery core may have already stripped the element
- // of any data bindings so we need to check it before
- // using it.
- if ( bindings ) {
- bindings[ eventType ] = false;
- }
-
- // Unregister the dummy event handler.
-
- $this.unbind( realType, dummyMouseHandler );
-
- // If this is the last virtual mouse binding on the
- // element, remove the binding data from the element.
-
- if ( !hasVirtualBindings( this ) ) {
- $this.removeData( dataPropertyName );
- }
- }
- };
-}
-
-// Expose our custom events to the jQuery bind/unbind mechanism.
-
-for ( i = 0; i < virtualEventNames.length; i++ ) {
- $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
-}
-
-// Add a capture click handler to block clicks.
-// Note that we require event capture support for this so if the device
-// doesn't support it, we punt for now and rely solely on mouse events.
-if ( eventCaptureSupported ) {
- document.addEventListener( "click", function( e ) {
- var cnt = clickBlockList.length,
- target = e.target,
- x, y, ele, i, o, touchID;
-
- if ( cnt ) {
- x = e.clientX;
- y = e.clientY;
- threshold = $.vmouse.clickDistanceThreshold;
-
- // The idea here is to run through the clickBlockList to see if
- // the current click event is in the proximity of one of our
- // vclick events that had preventDefault() called on it. If we find
- // one, then we block the click.
- //
- // Why do we have to rely on proximity?
- //
- // Because the target of the touch event that triggered the vclick
- // can be different from the target of the click event synthesized
- // by the browser. The target of a mouse/click event that is synthesized
- // from a touch event seems to be implementation specific. For example,
- // some browsers will fire mouse/click events for a link that is near
- // a touch event, even though the target of the touchstart/touchend event
- // says the user touched outside the link. Also, it seems that with most
- // browsers, the target of the mouse/click event is not calculated until the
- // time it is dispatched, so if you replace an element that you touched
- // with another element, the target of the mouse/click will be the new
- // element underneath that point.
- //
- // Aside from proximity, we also check to see if the target and any
- // of its ancestors were the ones that blocked a click. This is necessary
- // because of the strange mouse/click target calculation done in the
- // Android 2.1 browser, where if you click on an element, and there is a
- // mouse/click handler on one of its ancestors, the target will be the
- // innermost child of the touched element, even if that child is no where
- // near the point of touch.
-
- ele = target;
-
- while ( ele ) {
- for ( i = 0; i < cnt; i++ ) {
- o = clickBlockList[ i ];
- touchID = 0;
-
- if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
- $.data( ele, touchTargetPropertyName ) === o.touchID ) {
- // XXX: We may want to consider removing matches from the block list
- // instead of waiting for the reset timer to fire.
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- }
- ele = ele.parentNode;
- }
- }
- }, true);
-}
-})( jQuery, window, document );
-
-
-(function( $, window, undefined ) {
- var $document = $( document ),
- supportTouch = $.mobile.support.touch,
- scrollEvent = "touchmove scroll",
- touchStartEvent = supportTouch ? "touchstart" : "mousedown",
- touchStopEvent = supportTouch ? "touchend" : "mouseup",
- touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
-
- // setup new event shortcuts
- $.each( ( "touchstart touchmove touchend " +
- "tap taphold " +
- "swipe swipeleft swiperight " +
- "scrollstart scrollstop" ).split( " " ), function( i, name ) {
-
- $.fn[ name ] = function( fn ) {
- return fn ? this.bind( name, fn ) : this.trigger( name );
- };
-
- // jQuery < 1.8
- if ( $.attrFn ) {
- $.attrFn[ name ] = true;
- }
- });
-
- function triggerCustomEvent( obj, eventType, event, bubble ) {
- var originalType = event.type;
- event.type = eventType;
- if ( bubble ) {
- $.event.trigger( event, undefined, obj );
- } else {
- $.event.dispatch.call( obj, event );
- }
- event.type = originalType;
- }
-
- // also handles scrollstop
- $.event.special.scrollstart = {
-
- enabled: true,
- setup: function() {
-
- var thisObject = this,
- $this = $( thisObject ),
- scrolling,
- timer;
-
- function trigger( event, state ) {
- scrolling = state;
- triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
- }
-
- // iPhone triggers scroll after a small delay; use touchmove instead
- $this.bind( scrollEvent, function( event ) {
-
- if ( !$.event.special.scrollstart.enabled ) {
- return;
- }
-
- if ( !scrolling ) {
- trigger( event, true );
- }
-
- clearTimeout( timer );
- timer = setTimeout( function() {
- trigger( event, false );
- }, 50 );
- });
- },
- teardown: function() {
- $( this ).unbind( scrollEvent );
- }
- };
-
- // also handles taphold
- $.event.special.tap = {
- tapholdThreshold: 750,
- emitTapOnTaphold: true,
- setup: function() {
- var thisObject = this,
- $this = $( thisObject ),
- isTaphold = false;
-
- $this.bind( "vmousedown", function( event ) {
- isTaphold = false;
- if ( event.which && event.which !== 1 ) {
- return false;
- }
-
- var origTarget = event.target,
- timer;
-
- function clearTapTimer() {
- clearTimeout( timer );
- }
-
- function clearTapHandlers() {
- clearTapTimer();
-
- $this.unbind( "vclick", clickHandler )
- .unbind( "vmouseup", clearTapTimer );
- $document.unbind( "vmousecancel", clearTapHandlers );
- }
-
- function clickHandler( event ) {
- clearTapHandlers();
-
- // ONLY trigger a 'tap' event if the start target is
- // the same as the stop target.
- if ( !isTaphold && origTarget === event.target ) {
- triggerCustomEvent( thisObject, "tap", event );
- } else if ( isTaphold ) {
- event.stopPropagation();
- }
- }
-
- $this.bind( "vmouseup", clearTapTimer )
- .bind( "vclick", clickHandler );
- $document.bind( "vmousecancel", clearTapHandlers );
-
- timer = setTimeout( function() {
- if ( !$.event.special.tap.emitTapOnTaphold ) {
- isTaphold = true;
- }
- triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) );
- }, $.event.special.tap.tapholdThreshold );
- });
- },
- teardown: function() {
- $( this ).unbind( "vmousedown" ).unbind( "vclick" ).unbind( "vmouseup" );
- $document.unbind( "vmousecancel" );
- }
- };
-
- // Also handles swipeleft, swiperight
- $.event.special.swipe = {
-
- // More than this horizontal displacement, and we will suppress scrolling.
- scrollSupressionThreshold: 30,
-
- // More time than this, and it isn't a swipe.
- durationThreshold: 1000,
-
- // Swipe horizontal displacement must be more than this.
- horizontalDistanceThreshold: 30,
-
- // Swipe vertical displacement must be less than this.
- verticalDistanceThreshold: 30,
-
- getLocation: function ( event ) {
- var winPageX = window.pageXOffset,
- winPageY = window.pageYOffset,
- x = event.clientX,
- y = event.clientY;
-
- if ( event.pageY === 0 && Math.floor( y ) > Math.floor( event.pageY ) ||
- event.pageX === 0 && Math.floor( x ) > Math.floor( event.pageX ) ) {
-
- // iOS4 clientX/clientY have the value that should have been
- // in pageX/pageY. While pageX/page/ have the value 0
- x = x - winPageX;
- y = y - winPageY;
- } else if ( y < ( event.pageY - winPageY) || x < ( event.pageX - winPageX ) ) {
-
- // Some Android browsers have totally bogus values for clientX/Y
- // when scrolling/zooming a page. Detectable since clientX/clientY
- // should never be smaller than pageX/pageY minus page scroll
- x = event.pageX - winPageX;
- y = event.pageY - winPageY;
- }
-
- return {
- x: x,
- y: y
- };
- },
-
- start: function( event ) {
- var data = event.originalEvent.touches ?
- event.originalEvent.touches[ 0 ] : event,
- location = $.event.special.swipe.getLocation( data );
- return {
- time: ( new Date() ).getTime(),
- coords: [ location.x, location.y ],
- origin: $( event.target )
- };
- },
-
- stop: function( event ) {
- var data = event.originalEvent.touches ?
- event.originalEvent.touches[ 0 ] : event,
- location = $.event.special.swipe.getLocation( data );
- return {
- time: ( new Date() ).getTime(),
- coords: [ location.x, location.y ]
- };
- },
-
- handleSwipe: function( start, stop, thisObject, origTarget ) {
- if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
- Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
- Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {
- var direction = start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight";
-
- triggerCustomEvent( thisObject, "swipe", $.Event( "swipe", { target: origTarget, swipestart: start, swipestop: stop }), true );
- triggerCustomEvent( thisObject, direction,$.Event( direction, { target: origTarget, swipestart: start, swipestop: stop } ), true );
- return true;
- }
- return false;
-
- },
-
- // This serves as a flag to ensure that at most one swipe event event is
- // in work at any given time
- eventInProgress: false,
-
- setup: function() {
- var events,
- thisObject = this,
- $this = $( thisObject ),
- context = {};
-
- // Retrieve the events data for this element and add the swipe context
- events = $.data( this, "mobile-events" );
- if ( !events ) {
- events = { length: 0 };
- $.data( this, "mobile-events", events );
- }
- events.length++;
- events.swipe = context;
-
- context.start = function( event ) {
-
- // Bail if we're already working on a swipe event
- if ( $.event.special.swipe.eventInProgress ) {
- return;
- }
- $.event.special.swipe.eventInProgress = true;
-
- var stop,
- start = $.event.special.swipe.start( event ),
- origTarget = event.target,
- emitted = false;
-
- context.move = function( event ) {
- if ( !start ) {
- return;
- }
-
- stop = $.event.special.swipe.stop( event );
- if ( !emitted ) {
- emitted = $.event.special.swipe.handleSwipe( start, stop, thisObject, origTarget );
- if ( emitted ) {
-
- // Reset the context to make way for the next swipe event
- $.event.special.swipe.eventInProgress = false;
- }
- }
- // prevent scrolling
- if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
- event.preventDefault();
- }
- };
-
- context.stop = function() {
- emitted = true;
-
- // Reset the context to make way for the next swipe event
- $.event.special.swipe.eventInProgress = false;
- $document.off( touchMoveEvent, context.move );
- context.move = null;
- };
-
- $document.on( touchMoveEvent, context.move )
- .one( touchStopEvent, context.stop );
- };
- $this.on( touchStartEvent, context.start );
- },
-
- teardown: function() {
- var events, context;
-
- events = $.data( this, "mobile-events" );
- if ( events ) {
- context = events.swipe;
- delete events.swipe;
- events.length--;
- if ( events.length === 0 ) {
- $.removeData( this, "mobile-events" );
- }
- }
-
- if ( context ) {
- if ( context.start ) {
- $( this ).off( touchStartEvent, context.start );
- }
- if ( context.move ) {
- $document.off( touchMoveEvent, context.move );
- }
- if ( context.stop ) {
- $document.off( touchStopEvent, context.stop );
- }
- }
- }
- };
- $.each({
- scrollstop: "scrollstart",
- taphold: "tap",
- swipeleft: "swipe",
- swiperight: "swipe"
- }, function( event, sourceEvent ) {
-
- $.event.special[ event ] = {
- setup: function() {
- $( this ).bind( sourceEvent, $.noop );
- },
- teardown: function() {
- $( this ).unbind( sourceEvent );
- }
- };
- });
-
-})( jQuery, this );
-
-
- // throttled resize event
- (function( $ ) {
- $.event.special.throttledresize = {
- setup: function() {
- $( this ).bind( "resize", handler );
- },
- teardown: function() {
- $( this ).unbind( "resize", handler );
- }
- };
-
- var throttle = 250,
- handler = function() {
- curr = ( new Date() ).getTime();
- diff = curr - lastCall;
-
- if ( diff >= throttle ) {
-
- lastCall = curr;
- $( this ).trigger( "throttledresize" );
-
- } else {
-
- if ( heldCall ) {
- clearTimeout( heldCall );
- }
-
- // Promise a held call will still execute
- heldCall = setTimeout( handler, throttle - diff );
- }
- },
- lastCall = 0,
- heldCall,
- curr,
- diff;
- })( jQuery );
-
-
-(function( $, window ) {
- var win = $( window ),
- event_name = "orientationchange",
- get_orientation,
- last_orientation,
- initial_orientation_is_landscape,
- initial_orientation_is_default,
- portrait_map = { "0": true, "180": true },
- ww, wh, landscape_threshold;
-
- // It seems that some device/browser vendors use window.orientation values 0 and 180 to
- // denote the "default" orientation. For iOS devices, and most other smart-phones tested,
- // the default orientation is always "portrait", but in some Android and RIM based tablets,
- // the default orientation is "landscape". The following code attempts to use the window
- // dimensions to figure out what the current orientation is, and then makes adjustments
- // to the to the portrait_map if necessary, so that we can properly decode the
- // window.orientation value whenever get_orientation() is called.
- //
- // Note that we used to use a media query to figure out what the orientation the browser
- // thinks it is in:
- //
- // initial_orientation_is_landscape = $.mobile.media("all and (orientation: landscape)");
- //
- // but there was an iPhone/iPod Touch bug beginning with iOS 4.2, up through iOS 5.1,
- // where the browser *ALWAYS* applied the landscape media query. This bug does not
- // happen on iPad.
-
- if ( $.support.orientation ) {
-
- // Check the window width and height to figure out what the current orientation
- // of the device is at this moment. Note that we've initialized the portrait map
- // values to 0 and 180, *AND* we purposely check for landscape so that if we guess
- // wrong, , we default to the assumption that portrait is the default orientation.
- // We use a threshold check below because on some platforms like iOS, the iPhone
- // form-factor can report a larger width than height if the user turns on the
- // developer console. The actual threshold value is somewhat arbitrary, we just
- // need to make sure it is large enough to exclude the developer console case.
-
- ww = window.innerWidth || win.width();
- wh = window.innerHeight || win.height();
- landscape_threshold = 50;
-
- initial_orientation_is_landscape = ww > wh && ( ww - wh ) > landscape_threshold;
-
- // Now check to see if the current window.orientation is 0 or 180.
- initial_orientation_is_default = portrait_map[ window.orientation ];
-
- // If the initial orientation is landscape, but window.orientation reports 0 or 180, *OR*
- // if the initial orientation is portrait, but window.orientation reports 90 or -90, we
- // need to flip our portrait_map values because landscape is the default orientation for
- // this device/browser.
- if ( ( initial_orientation_is_landscape && initial_orientation_is_default ) || ( !initial_orientation_is_landscape && !initial_orientation_is_default ) ) {
- portrait_map = { "-90": true, "90": true };
- }
- }
-
- $.event.special.orientationchange = $.extend( {}, $.event.special.orientationchange, {
- setup: function() {
- // If the event is supported natively, return false so that jQuery
- // will bind to the event using DOM methods.
- if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
- return false;
- }
-
- // Get the current orientation to avoid initial double-triggering.
- last_orientation = get_orientation();
-
- // Because the orientationchange event doesn't exist, simulate the
- // event by testing window dimensions on resize.
- win.bind( "throttledresize", handler );
- },
- teardown: function() {
- // If the event is not supported natively, return false so that
- // jQuery will unbind the event using DOM methods.
- if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
- return false;
- }
-
- // Because the orientationchange event doesn't exist, unbind the
- // resize event handler.
- win.unbind( "throttledresize", handler );
- },
- add: function( handleObj ) {
- // Save a reference to the bound event handler.
- var old_handler = handleObj.handler;
-
- handleObj.handler = function( event ) {
- // Modify event object, adding the .orientation property.
- event.orientation = get_orientation();
-
- // Call the originally-bound event handler and return its result.
- return old_handler.apply( this, arguments );
- };
- }
- });
-
- // If the event is not supported natively, this handler will be bound to
- // the window resize event to simulate the orientationchange event.
- function handler() {
- // Get the current orientation.
- var orientation = get_orientation();
-
- if ( orientation !== last_orientation ) {
- // The orientation has changed, so trigger the orientationchange event.
- last_orientation = orientation;
- win.trigger( event_name );
- }
- }
-
- // Get the current page orientation. This method is exposed publicly, should it
- // be needed, as jQuery.event.special.orientationchange.orientation()
- $.event.special.orientationchange.orientation = get_orientation = function() {
- var isPortrait = true, elem = document.documentElement;
-
- // prefer window orientation to the calculation based on screensize as
- // the actual screen resize takes place before or after the orientation change event
- // has been fired depending on implementation (eg android 2.3 is before, iphone after).
- // More testing is required to determine if a more reliable method of determining the new screensize
- // is possible when orientationchange is fired. (eg, use media queries + element + opacity)
- if ( $.support.orientation ) {
- // if the window orientation registers as 0 or 180 degrees report
- // portrait, otherwise landscape
- isPortrait = portrait_map[ window.orientation ];
- } else {
- isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
- }
-
- return isPortrait ? "portrait" : "landscape";
- };
-
- $.fn[ event_name ] = function( fn ) {
- return fn ? this.bind( event_name, fn ) : this.trigger( event_name );
- };
-
- // jQuery < 1.8
- if ( $.attrFn ) {
- $.attrFn[ event_name ] = true;
- }
-
-}( jQuery, this ));
-
-
-
-
-(function( $, undefined ) {
-
- // existing base tag?
- var baseElement = $( "head" ).children( "base" ),
-
- // base element management, defined depending on dynamic base tag support
- // TODO move to external widget
- base = {
-
- // define base element, for use in routing asset urls that are referenced
- // in Ajax-requested markup
- element: ( baseElement.length ? baseElement :
- $( "<base>", { href: $.mobile.path.documentBase.hrefNoHash } ).prependTo( $( "head" ) ) ),
-
- linkSelector: "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]",
-
- // set the generated BASE element's href to a new page's base path
- set: function( href ) {
-
- // we should do nothing if the user wants to manage their url base
- // manually
- if ( !$.mobile.dynamicBaseEnabled ) {
- return;
- }
-
- // we should use the base tag if we can manipulate it dynamically
- if ( $.support.dynamicBaseTag ) {
- base.element.attr( "href",
- $.mobile.path.makeUrlAbsolute( href, $.mobile.path.documentBase ) );
- }
- },
-
- rewrite: function( href, page ) {
- var newPath = $.mobile.path.get( href );
-
- page.find( base.linkSelector ).each(function( i, link ) {
- var thisAttr = $( link ).is( "[href]" ) ? "href" :
- $( link ).is( "[src]" ) ? "src" : "action",
- thisUrl = $( link ).attr( thisAttr );
-
- // XXX_jblas: We need to fix this so that it removes the document
- // base URL, and then prepends with the new page URL.
- // if full path exists and is same, chop it - helps IE out
- thisUrl = thisUrl.replace( location.protocol + "//" +
- location.host + location.pathname, "" );
-
- if ( !/^(\w+:|#|\/)/.test( thisUrl ) ) {
- $( link ).attr( thisAttr, newPath + thisUrl );
- }
- });
- },
-
- // set the generated BASE element's href to a new page's base path
- reset: function(/* href */) {
- base.element.attr( "href", $.mobile.path.documentBase.hrefNoSearch );
- }
- };
-
- $.mobile.base = base;
-
-})( jQuery );
-
-
-(function( $, undefined ) {
-$.mobile.widgets = {};
-
-var originalWidget = $.widget,
-
- // Record the original, non-mobileinit-modified version of $.mobile.keepNative
- // so we can later determine whether someone has modified $.mobile.keepNative
- keepNativeFactoryDefault = $.mobile.keepNative;
-
-$.widget = (function( orig ) {
- return function() {
- var constructor = orig.apply( this, arguments ),
- name = constructor.prototype.widgetName;
-
- constructor.initSelector = ( ( constructor.prototype.initSelector !== undefined ) ?
- constructor.prototype.initSelector : ":jqmData(role='" + name + "')" );
-
- $.mobile.widgets[ name ] = constructor;
-
- return constructor;
- };
-})( $.widget );
-
-// Make sure $.widget still has bridge and extend methods
-$.extend( $.widget, originalWidget );
-
-// For backcompat remove in 1.5
-$.mobile.document.on( "create", function( event ) {
- $( event.target ).enhanceWithin();
-});
-
-$.widget( "mobile.page", {
- options: {
- theme: "a",
- domCache: false,
-
- // Deprecated in 1.4 remove in 1.5
- keepNativeDefault: $.mobile.keepNative,
-
- // Deprecated in 1.4 remove in 1.5
- contentTheme: null,
- enhanced: false
- },
-
- // DEPRECATED for > 1.4
- // TODO remove at 1.5
- _createWidget: function() {
- $.Widget.prototype._createWidget.apply( this, arguments );
- this._trigger( "init" );
- },
-
- _create: function() {
- // If false is returned by the callbacks do not create the page
- if ( this._trigger( "beforecreate" ) === false ) {
- return false;
- }
-
- if ( !this.options.enhanced ) {
- this._enhance();
- }
-
- this._on( this.element, {
- pagebeforehide: "removeContainerBackground",
- pagebeforeshow: "_handlePageBeforeShow"
- });
-
- this.element.enhanceWithin();
- // Dialog widget is deprecated in 1.4 remove this in 1.5
- if ( $.mobile.getAttribute( this.element[0], "role" ) === "dialog" && $.mobile.dialog ) {
- this.element.dialog();
- }
- },
-
- _enhance: function () {
- var attrPrefix = "data-" + $.mobile.ns,
- self = this;
-
- if ( this.options.role ) {
- this.element.attr( "data-" + $.mobile.ns + "role", this.options.role );
- }
-
- this.element
- .attr( "tabindex", "0" )
- .addClass( "ui-page ui-page-theme-" + this.options.theme );
-
- // Manipulation of content os Deprecated as of 1.4 remove in 1.5
- this.element.find( "[" + attrPrefix + "role='content']" ).each( function() {
- var $this = $( this ),
- theme = this.getAttribute( attrPrefix + "theme" ) || undefined;
- self.options.contentTheme = theme || self.options.contentTheme || ( self.options.dialog && self.options.theme ) || ( self.element.jqmData("role") === "dialog" && self.options.theme );
- $this.addClass( "ui-content" );
- if ( self.options.contentTheme ) {
- $this.addClass( "ui-body-" + ( self.options.contentTheme ) );
- }
- // Add ARIA role
- $this.attr( "role", "main" ).addClass( "ui-content" );
- });
- },
-
- bindRemove: function( callback ) {
- var page = this.element;
-
- // when dom caching is not enabled or the page is embedded bind to remove the page on hide
- if ( !page.data( "mobile-page" ).options.domCache &&
- page.is( ":jqmData(external-page='true')" ) ) {
-
- // TODO use _on - that is, sort out why it doesn't work in this case
- page.bind( "pagehide.remove", callback || function( e, data ) {
-
- //check if this is a same page transition and if so don't remove the page
- if( !data.samePage ){
- var $this = $( this ),
- prEvent = new $.Event( "pageremove" );
-
- $this.trigger( prEvent );
-
- if ( !prEvent.isDefaultPrevented() ) {
- $this.removeWithDependents();
- }
- }
- });
- }
- },
-
- _setOptions: function( o ) {
- if ( o.theme !== undefined ) {
- this.element.removeClass( "ui-page-theme-" + this.options.theme ).addClass( "ui-page-theme-" + o.theme );
- }
-
- if ( o.contentTheme !== undefined ) {
- this.element.find( "[data-" + $.mobile.ns + "='content']" ).removeClass( "ui-body-" + this.options.contentTheme )
- .addClass( "ui-body-" + o.contentTheme );
- }
- },
-
- _handlePageBeforeShow: function(/* e */) {
- this.setContainerBackground();
- },
- // Deprecated in 1.4 remove in 1.5
- removeContainerBackground: function() {
- this.element.closest( ":mobile-pagecontainer" ).pagecontainer({ "theme": "none" });
- },
- // Deprecated in 1.4 remove in 1.5
- // set the page container background to the page theme
- setContainerBackground: function( theme ) {
- this.element.parent().pagecontainer( { "theme": theme || this.options.theme } );
- },
- // Deprecated in 1.4 remove in 1.5
- keepNativeSelector: function() {
- var options = this.options,
- keepNative = $.trim( options.keepNative || "" ),
- globalValue = $.trim( $.mobile.keepNative ),
- optionValue = $.trim( options.keepNativeDefault ),
-
- // Check if $.mobile.keepNative has changed from the factory default
- newDefault = ( keepNativeFactoryDefault === globalValue ?
- "" : globalValue ),
-
- // If $.mobile.keepNative has not changed, use options.keepNativeDefault
- oldDefault = ( newDefault === "" ? optionValue : "" );
-
- // Concatenate keepNative selectors from all sources where the value has
- // changed or, if nothing has changed, return the default
- return ( ( keepNative ? [ keepNative ] : [] )
- .concat( newDefault ? [ newDefault ] : [] )
- .concat( oldDefault ? [ oldDefault ] : [] )
- .join( ", " ) );
- }
-});
-})( jQuery );
-
-(function( $, undefined ) {
-
- $.widget( "mobile.pagecontainer", {
- options: {
- theme: "a"
- },
-
- initSelector: false,
-
- _create: function() {
- this.setLastScrollEnabled = true;
-
- this._on( this.window, {
- // disable an scroll setting when a hashchange has been fired,
- // this only works because the recording of the scroll position
- // is delayed for 100ms after the browser might have changed the
- // position because of the hashchange
- navigate: "_disableRecordScroll",
-
- // bind to scrollstop for the first page, "pagechange" won't be
- // fired in that case
- scrollstop: "_delayedRecordScroll"
- });
-
- // TODO consider moving the navigation handler OUT of widget into
- // some other object as glue between the navigate event and the
- // content widget load and change methods
- this._on( this.window, { navigate: "_filterNavigateEvents" });
-
- // TODO move from page* events to content* events
- this._on({ pagechange: "_afterContentChange" });
-
- // handle initial hashchange from chrome :(
- this.window.one( "navigate", $.proxy(function() {
- this.setLastScrollEnabled = true;
- }, this));
- },
-
- _setOptions: function( options ) {
- if ( options.theme !== undefined && options.theme !== "none" ) {
- this.element.removeClass( "ui-overlay-" + this.options.theme )
- .addClass( "ui-overlay-" + options.theme );
- } else if ( options.theme !== undefined ) {
- this.element.removeClass( "ui-overlay-" + this.options.theme );
- }
-
- this._super( options );
- },
-
- _disableRecordScroll: function() {
- this.setLastScrollEnabled = false;
- },
-
- _enableRecordScroll: function() {
- this.setLastScrollEnabled = true;
- },
-
- // TODO consider the name here, since it's purpose specific
- _afterContentChange: function() {
- // once the page has changed, re-enable the scroll recording
- this.setLastScrollEnabled = true;
-
- // remove any binding that previously existed on the get scroll
- // which may or may not be different than the scroll element
- // determined for this page previously
- this._off( this.window, "scrollstop" );
-
- // determine and bind to the current scoll element which may be the
- // window or in the case of touch overflow the element touch overflow
- this._on( this.window, { scrollstop: "_delayedRecordScroll" });
- },
-
- _recordScroll: function() {
- // this barrier prevents setting the scroll value based on
- // the browser scrolling the window based on a hashchange
- if ( !this.setLastScrollEnabled ) {
- return;
- }
-
- var active = this._getActiveHistory(),
- currentScroll, minScroll, defaultScroll;
-
- if ( active ) {
- currentScroll = this._getScroll();
- minScroll = this._getMinScroll();
- defaultScroll = this._getDefaultScroll();
-
- // Set active page's lastScroll prop. If the location we're
- // scrolling to is less than minScrollBack, let it go.
- active.lastScroll = currentScroll < minScroll ? defaultScroll : currentScroll;
- }
- },
-
- _delayedRecordScroll: function() {
- setTimeout( $.proxy(this, "_recordScroll"), 100 );
- },
-
- _getScroll: function() {
- return this.window.scrollTop();
- },
-
- _getMinScroll: function() {
- return $.mobile.minScrollBack;
- },
-
- _getDefaultScroll: function() {
- return $.mobile.defaultHomeScroll;
- },
-
- _filterNavigateEvents: function( e, data ) {
- var url;
-
- if ( e.originalEvent && e.originalEvent.isDefaultPrevented() ) {
- return;
- }
-
- url = e.originalEvent.type.indexOf( "hashchange" ) > -1 ? data.state.hash : data.state.url;
-
- if ( !url ) {
- url = this._getHash();
- }
-
- if ( !url || url === "#" || url.indexOf( "#" + $.mobile.path.uiStateKey ) === 0 ) {
- url = location.href;
- }
-
- this._handleNavigate( url, data.state );
- },
-
- _getHash: function() {
- return $.mobile.path.parseLocation().hash;
- },
-
- // TODO active page should be managed by the container (ie, it should be a property)
- getActivePage: function() {
- return this.activePage;
- },
-
- // TODO the first page should be a property set during _create using the logic
- // that currently resides in init
- _getInitialContent: function() {
- return $.mobile.firstPage;
- },
-
- // TODO each content container should have a history object
- _getHistory: function() {
- return $.mobile.navigate.history;
- },
-
- // TODO use _getHistory
- _getActiveHistory: function() {
- return $.mobile.navigate.history.getActive();
- },
-
- // TODO the document base should be determined at creation
- _getDocumentBase: function() {
- return $.mobile.path.documentBase;
- },
-
- back: function() {
- this.go( -1 );
- },
-
- forward: function() {
- this.go( 1 );
- },
-
- go: function( steps ) {
-
- //if hashlistening is enabled use native history method
- if ( $.mobile.hashListeningEnabled ) {
- window.history.go( steps );
- } else {
-
- //we are not listening to the hash so handle history internally
- var activeIndex = $.mobile.navigate.history.activeIndex,
- index = activeIndex + parseInt( steps, 10 ),
- url = $.mobile.navigate.history.stack[ index ].url,
- direction = ( steps >= 1 )? "forward" : "back";
-
- //update the history object
- $.mobile.navigate.history.activeIndex = index;
- $.mobile.navigate.history.previousIndex = activeIndex;
-
- //change to the new page
- this.change( url, { direction: direction, changeHash: false, fromHashChange: true } );
- }
- },
-
- // TODO rename _handleDestination
- _handleDestination: function( to ) {
- var history;
-
- // clean the hash for comparison if it's a url
- if ( $.type(to) === "string" ) {
- to = $.mobile.path.stripHash( to );
- }
-
- if ( to ) {
- history = this._getHistory();
-
- // At this point, 'to' can be one of 3 things, a cached page
- // element from a history stack entry, an id, or site-relative /
- // absolute URL. If 'to' is an id, we need to resolve it against
- // the documentBase, not the location.href, since the hashchange
- // could've been the result of a forward/backward navigation
- // that crosses from an external page/dialog to an internal
- // page/dialog.
- //
- // TODO move check to history object or path object?
- to = !$.mobile.path.isPath( to ) ? ( $.mobile.path.makeUrlAbsolute( "#" + to, this._getDocumentBase() ) ) : to;
-
- // If we're about to go to an initial URL that contains a
- // reference to a non-existent internal page, go to the first
- // page instead. We know that the initial hash refers to a
- // non-existent page, because the initial hash did not end
- // up in the initial history entry
- // TODO move check to history object?
- if ( to === $.mobile.path.makeUrlAbsolute( "#" + history.initialDst, this._getDocumentBase() ) &&
- history.stack.length &&
- history.stack[0].url !== history.initialDst.replace( $.mobile.dialogHashKey, "" ) ) {
- to = this._getInitialContent();
- }
- }
- return to || this._getInitialContent();
- },
-
- _handleDialog: function( changePageOptions, data ) {
- var to, active, activeContent = this.getActivePage();
-
- // If current active page is not a dialog skip the dialog and continue
- // in the same direction
- if ( activeContent && !activeContent.hasClass( "ui-dialog" ) ) {
- // determine if we're heading forward or backward and continue
- // accordingly past the current dialog
- if ( data.direction === "back" ) {
- this.back();
- } else {
- this.forward();
- }
-
- // prevent changePage call
- return false;
- } else {
- // if the current active page is a dialog and we're navigating
- // to a dialog use the dialog objected saved in the stack
- to = data.pageUrl;
- active = this._getActiveHistory();
-
- // make sure to set the role, transition and reversal
- // as most of this is lost by the domCache cleaning
- $.extend( changePageOptions, {
- role: active.role,
- transition: active.transition,
- reverse: data.direction === "back"
- });
- }
-
- return to;
- },
-
- _handleNavigate: function( url, data ) {
- //find first page via hash
- // TODO stripping the hash twice with handleUrl
- var to = $.mobile.path.stripHash( url ), history = this._getHistory(),
-
- // transition is false if it's the first page, undefined
- // otherwise (and may be overridden by default)
- transition = history.stack.length === 0 ? "none" : undefined,
-
- // default options for the changPage calls made after examining
- // the current state of the page and the hash, NOTE that the
- // transition is derived from the previous history entry
- changePageOptions = {
- changeHash: false,
- fromHashChange: true,
- reverse: data.direction === "back"
- };
-
- $.extend( changePageOptions, data, {
- transition: ( history.getLast() || {} ).transition || transition
- });
-
- // TODO move to _handleDestination ?
- // If this isn't the first page, if the current url is a dialog hash
- // key, and the initial destination isn't equal to the current target
- // page, use the special dialog handling
- if ( history.activeIndex > 0 &&
- to.indexOf( $.mobile.dialogHashKey ) > -1 &&
- history.initialDst !== to ) {
-
- to = this._handleDialog( changePageOptions, data );
-
- if ( to === false ) {
- return;
- }
- }
-
- this._changeContent( this._handleDestination( to ), changePageOptions );
- },
-
- _changeContent: function( to, opts ) {
- $.mobile.changePage( to, opts );
- },
-
- _getBase: function() {
- return $.mobile.base;
- },
-
- _getNs: function() {
- return $.mobile.ns;
- },
-
- _enhance: function( content, role ) {
- // TODO consider supporting a custom callback, and passing in
- // the settings which includes the role
- return content.page({ role: role });
- },
-
- _include: function( page, settings ) {
- // append to page and enhance
- page.appendTo( this.element );
-
- // use the page widget to enhance
- this._enhance( page, settings.role );
-
- // remove page on hide
- page.page( "bindRemove" );
- },
-
- _find: function( absUrl ) {
- // TODO consider supporting a custom callback
- var fileUrl = this._createFileUrl( absUrl ),
- dataUrl = this._createDataUrl( absUrl ),
- page, initialContent = this._getInitialContent();
-
- // Check to see if the page already exists in the DOM.
- // NOTE do _not_ use the :jqmData pseudo selector because parenthesis
- // are a valid url char and it breaks on the first occurence
- page = this.element
- .children( "[data-" + this._getNs() +"url='" + dataUrl + "']" );
-
- // If we failed to find the page, check to see if the url is a
- // reference to an embedded page. If so, it may have been dynamically
- // injected by a developer, in which case it would be lacking a
- // data-url attribute and in need of enhancement.
- if ( page.length === 0 && dataUrl && !$.mobile.path.isPath( dataUrl ) ) {
- page = this.element.children( $.mobile.path.hashToSelector("#" + dataUrl) )
- .attr( "data-" + this._getNs() + "url", dataUrl )
- .jqmData( "url", dataUrl );
- }
-
- // If we failed to find a page in the DOM, check the URL to see if it
- // refers to the first page in the application. Also check to make sure
- // our cached-first-page is actually in the DOM. Some user deployed
- // apps are pruning the first page from the DOM for various reasons.
- // We check for this case here because we don't want a first-page with
- // an id falling through to the non-existent embedded page error case.
- if ( page.length === 0 &&
- $.mobile.path.isFirstPageUrl( fileUrl ) &&
- initialContent &&
- initialContent.parent().length ) {
- page = $( initialContent );
- }
-
- return page;
- },
-
- _getLoader: function() {
- return $.mobile.loading();
- },
-
- _showLoading: function( delay, theme, msg, textonly ) {
- // This configurable timeout allows cached pages a brief
- // delay to load without showing a message
- if ( this._loadMsg ) {
- return;
- }
-
- this._loadMsg = setTimeout($.proxy(function() {
- this._getLoader().loader( "show", theme, msg, textonly );
- this._loadMsg = 0;
- }, this), delay );
- },
-
- _hideLoading: function() {
- // Stop message show timer
- clearTimeout( this._loadMsg );
- this._loadMsg = 0;
-
- // Hide loading message
- this._getLoader().loader( "hide" );
- },
-
- _showError: function() {
- // make sure to remove the current loading message
- this._hideLoading();
-
- // show the error message
- this._showLoading( 0, $.mobile.pageLoadErrorMessageTheme, $.mobile.pageLoadErrorMessage, true );
-
- // hide the error message after a delay
- // TODO configuration
- setTimeout( $.proxy(this, "_hideLoading"), 1500 );
- },
-
- _parse: function( html, fileUrl ) {
- // TODO consider allowing customization of this method. It's very JQM specific
- var page, all = $( "<div></div>" );
-
- //workaround to allow scripts to execute when included in page divs
- all.get( 0 ).innerHTML = html;
-
- page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();
-
- //if page elem couldn't be found, create one and insert the body element's contents
- if ( !page.length ) {
- page = $( "<div data-" + this._getNs() + "role='page'>" +
- ( html.split( /<\/?body[^>]*>/gmi )[1] || "" ) +
- "</div>" );
- }
-
- // TODO tagging a page with external to make sure that embedded pages aren't
- // removed by the various page handling code is bad. Having page handling code
- // in many places is bad. Solutions post 1.0
- page.attr( "data-" + this._getNs() + "url", $.mobile.path.convertUrlToDataUrl(fileUrl) )
- .attr( "data-" + this._getNs() + "external-page", true );
-
- return page;
- },
-
- _setLoadedTitle: function( page, html ) {
- //page title regexp
- var newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1;
-
- if ( newPageTitle && !page.jqmData("title") ) {
- newPageTitle = $( "<div>" + newPageTitle + "</div>" ).text();
- page.jqmData( "title", newPageTitle );
- }
- },
-
- _isRewritableBaseTag: function() {
- return $.mobile.dynamicBaseEnabled && !$.support.dynamicBaseTag;
- },
-
- _createDataUrl: function( absoluteUrl ) {
- return $.mobile.path.convertUrlToDataUrl( absoluteUrl );
- },
-
- _createFileUrl: function( absoluteUrl ) {
- return $.mobile.path.getFilePath( absoluteUrl );
- },
-
- _triggerWithDeprecated: function( name, data, page ) {
- var deprecatedEvent = $.Event( "page" + name ),
- newEvent = $.Event( this.widgetName + name );
-
- // DEPRECATED
- // trigger the old deprecated event on the page if it's provided
- ( page || this.element ).trigger( deprecatedEvent, data );
-
- // use the widget trigger method for the new content* event
- this.element.trigger( newEvent, data );
-
- return {
- deprecatedEvent: deprecatedEvent,
- event: newEvent
- };
- },
-
- // TODO it would be nice to split this up more but everything appears to be "one off"
- // or require ordering such that other bits are sprinkled in between parts that
- // could be abstracted out as a group
- _loadSuccess: function( absUrl, triggerData, settings, deferred ) {
- var fileUrl = this._createFileUrl( absUrl ),
- dataUrl = this._createDataUrl( absUrl );
-
- return $.proxy(function( html, textStatus, xhr ) {
- //pre-parse html to check for a data-url,
- //use it as the new fileUrl, base path, etc
- var content,
-
- // TODO handle dialogs again
- pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + this._getNs() + "role=[\"']?page[\"']?[^>]*>)" ),
-
- dataUrlRegex = new RegExp( "\\bdata-" + this._getNs() + "url=[\"']?([^\"'>]*)[\"']?" );
-
- // data-url must be provided for the base tag so resource requests
- // can be directed to the correct url. loading into a temprorary
- // element makes these requests immediately
- if ( pageElemRegex.test( html ) &&
- RegExp.$1 &&
- dataUrlRegex.test( RegExp.$1 ) &&
- RegExp.$1 ) {
- fileUrl = $.mobile.path.getFilePath( $("<div>" + RegExp.$1 + "</div>").text() );
- }
-
- //dont update the base tag if we are prefetching
- if ( settings.prefetch === undefined ) {
- this._getBase().set( fileUrl );
- }
-
- content = this._parse( html, fileUrl );
-
- this._setLoadedTitle( content, html );
-
- // Add the content reference and xhr to our triggerData.
- triggerData.xhr = xhr;
- triggerData.textStatus = textStatus;
-
- // DEPRECATED
- triggerData.page = content;
-
- triggerData.content = content;
-
- // If the default behavior is prevented, stop here!
- // Note that it is the responsibility of the listener/handler
- // that called preventDefault(), to resolve/reject the
- // deferred object within the triggerData.
- if ( !this._trigger( "load", undefined, triggerData ) ) {
- return;
- }
-
- // rewrite src and href attrs to use a base url if the base tag won't work
- if ( this._isRewritableBaseTag() && content ) {
- this._getBase().rewrite( fileUrl, content );
- }
-
- this._include( content, settings );
-
- // Enhancing the content may result in new dialogs/sub content being inserted
- // into the DOM. If the original absUrl refers to a sub-content, that is the
- // real content we are interested in.
- if ( absUrl.indexOf( "&" + $.mobile.subPageUrlKey ) > -1 ) {
- content = this.element.children( "[data-" + this._getNs() +"url='" + dataUrl + "']" );
- }
-
- // Remove loading message.
- if ( settings.showLoadMsg ) {
- this._hideLoading();
- }
-
- // BEGIN DEPRECATED ---------------------------------------------------
- // Let listeners know the content loaded successfully.
- this.element.trigger( "pageload" );
- // END DEPRECATED -----------------------------------------------------
-
- deferred.resolve( absUrl, settings, content );
- }, this);
- },
-
- _loadDefaults: {
- type: "get",
- data: undefined,
-
- // DEPRECATED
- reloadPage: false,
-
- reload: false,
-
- // By default we rely on the role defined by the @data-role attribute.
- role: undefined,
-
- showLoadMsg: false,
-
- // This delay allows loads that pull from browser cache to
- // occur without showing the loading message.
- loadMsgDelay: 50
- },
-
- load: function( url, options ) {
- // This function uses deferred notifications to let callers
- // know when the content is done loading, or if an error has occurred.
- var deferred = ( options && options.deferred ) || $.Deferred(),
-
- // The default load options with overrides specified by the caller.
- settings = $.extend( {}, this._loadDefaults, options ),
-
- // The DOM element for the content after it has been loaded.
- content = null,
-
- // The absolute version of the URL passed into the function. This
- // version of the URL may contain dialog/subcontent params in it.
- absUrl = $.mobile.path.makeUrlAbsolute( url, this._findBaseWithDefault() ),
- fileUrl, dataUrl, pblEvent, triggerData;
-
- // DEPRECATED reloadPage
- settings.reload = settings.reloadPage;
-
- // If the caller provided data, and we're using "get" request,
- // append the data to the URL.
- if ( settings.data && settings.type === "get" ) {
- absUrl = $.mobile.path.addSearchParams( absUrl, settings.data );
- settings.data = undefined;
- }
-
- // If the caller is using a "post" request, reload must be true
- if ( settings.data && settings.type === "post" ) {
- settings.reload = true;
- }
-
- // The absolute version of the URL minus any dialog/subcontent params.
- // In otherwords the real URL of the content to be loaded.
- fileUrl = this._createFileUrl( absUrl );
-
- // The version of the Url actually stored in the data-url attribute of
- // the content. For embedded content, it is just the id of the page. For
- // content within the same domain as the document base, it is the site
- // relative path. For cross-domain content (Phone Gap only) the entire
- // absolute Url is used to load the content.
- dataUrl = this._createDataUrl( absUrl );
-
- content = this._find( absUrl );
-
- // If it isn't a reference to the first content and refers to missing
- // embedded content reject the deferred and return
- if ( content.length === 0 &&
- $.mobile.path.isEmbeddedPage(fileUrl) &&
- !$.mobile.path.isFirstPageUrl(fileUrl) ) {
- deferred.reject( absUrl, settings );
- return;
- }
-
- // Reset base to the default document base
- // TODO figure out why we doe this
- this._getBase().reset();
-
- // If the content we are interested in is already in the DOM,
- // and the caller did not indicate that we should force a
- // reload of the file, we are done. Resolve the deferrred so that
- // users can bind to .done on the promise
- if ( content.length && !settings.reload ) {
- this._enhance( content, settings.role );
- deferred.resolve( absUrl, settings, content );
-
- //if we are reloading the content make sure we update
- // the base if its not a prefetch
- if ( !settings.prefetch ) {
- this._getBase().set(url);
- }
-
- return;
- }
-
- triggerData = {
- url: url,
- absUrl: absUrl,
- dataUrl: dataUrl,
- deferred: deferred,
- options: settings
- };
-
- // Let listeners know we're about to load content.
- pblEvent = this._triggerWithDeprecated( "beforeload", triggerData );
-
- // If the default behavior is prevented, stop here!
- if ( pblEvent.deprecatedEvent.isDefaultPrevented() ||
- pblEvent.event.isDefaultPrevented() ) {
- return;
- }
-
- if ( settings.showLoadMsg ) {
- this._showLoading( settings.loadMsgDelay );
- }
-
- // Reset base to the default document base.
- // only reset if we are not prefetching
- if ( settings.prefetch === undefined ) {
- this._getBase().reset();
- }
-
- if ( !( $.mobile.allowCrossDomainPages ||
- $.mobile.path.isSameDomain($.mobile.path.documentUrl, absUrl ) ) ) {
- deferred.reject( absUrl, settings );
- return;
- }
-
- // Load the new content.
- $.ajax({
- url: fileUrl,
- type: settings.type,
- data: settings.data,
- contentType: settings.contentType,
- dataType: "html",
- success: this._loadSuccess( absUrl, triggerData, settings, deferred ),
- error: this._loadError( absUrl, triggerData, settings, deferred )
- });
- },
-
- _loadError: function( absUrl, triggerData, settings, deferred ) {
- return $.proxy(function( xhr, textStatus, errorThrown ) {
- //set base back to current path
- this._getBase().set( $.mobile.path.get() );
-
- // Add error info to our triggerData.
- triggerData.xhr = xhr;
- triggerData.textStatus = textStatus;
- triggerData.errorThrown = errorThrown;
-
- // Let listeners know the page load failed.
- var plfEvent = this._triggerWithDeprecated( "loadfailed", triggerData );
-
- // If the default behavior is prevented, stop here!
- // Note that it is the responsibility of the listener/handler
- // that called preventDefault(), to resolve/reject the
- // deferred object within the triggerData.
- if ( plfEvent.deprecatedEvent.isDefaultPrevented() ||
- plfEvent.event.isDefaultPrevented() ) {
- return;
- }
-
- // Remove loading message.
- if ( settings.showLoadMsg ) {
- this._showError();
- }
-
- deferred.reject( absUrl, settings );
- }, this);
- },
-
- _getTransitionHandler: function( transition ) {
- transition = $.mobile._maybeDegradeTransition( transition );
-
- //find the transition handler for the specified transition. If there
- //isn't one in our transitionHandlers dictionary, use the default one.
- //call the handler immediately to kick-off the transition.
- return $.mobile.transitionHandlers[ transition ] || $.mobile.defaultTransitionHandler;
- },
-
- // TODO move into transition handlers?
- _triggerCssTransitionEvents: function( to, from, prefix ) {
- var samePage = false;
-
- prefix = prefix || "";
-
- // TODO decide if these events should in fact be triggered on the container
- if ( from ) {
-
- //Check if this is a same page transition and tell the handler in page
- if( to[0] === from[0] ){
- samePage = true;
- }
-
- //trigger before show/hide events
- // TODO deprecate nextPage in favor of next
- this._triggerWithDeprecated( prefix + "hide", { nextPage: to, samePage: samePage }, from );
- }
-
- // TODO deprecate prevPage in favor of previous
- this._triggerWithDeprecated( prefix + "show", { prevPage: from || $( "" ) }, to );
- },
-
- // TODO make private once change has been defined in the widget
- _cssTransition: function( to, from, options ) {
- var transition = options.transition,
- reverse = options.reverse,
- deferred = options.deferred,
- TransitionHandler,
- promise;
-
- this._triggerCssTransitionEvents( to, from, "before" );
-
- // TODO put this in a binding to events *outside* the widget
- this._hideLoading();
-
- TransitionHandler = this._getTransitionHandler( transition );
-
- promise = ( new TransitionHandler( transition, reverse, to, from ) ).transition();
-
- // TODO temporary accomodation of argument deferred
- promise.done(function() {
- deferred.resolve.apply( deferred, arguments );
- });
-
- promise.done($.proxy(function() {
- this._triggerCssTransitionEvents( to, from );
- }, this));
- },
-
- _releaseTransitionLock: function() {
- //release transition lock so navigation is free again
- isPageTransitioning = false;
- if ( pageTransitionQueue.length > 0 ) {
- $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
- }
- },
-
- _removeActiveLinkClass: function( force ) {
- //clear out the active button state
- $.mobile.removeActiveLinkClass( force );
- },
-
- _loadUrl: function( to, triggerData, settings ) {
- // preserve the original target as the dataUrl value will be
- // simplified eg, removing ui-state, and removing query params
- // from the hash this is so that users who want to use query
- // params have access to them in the event bindings for the page
- // life cycle See issue #5085
- settings.target = to;
- settings.deferred = $.Deferred();
-
- this.load( to, settings );
-
- settings.deferred.done($.proxy(function( url, options, content ) {
- isPageTransitioning = false;
-
- // store the original absolute url so that it can be provided
- // to events in the triggerData of the subsequent changePage call
- options.absUrl = triggerData.absUrl;
-
- this.transition( content, triggerData, options );
- }, this));
-
- settings.deferred.fail($.proxy(function(/* url, options */) {
- this._removeActiveLinkClass( true );
- this._releaseTransitionLock();
- this._triggerWithDeprecated( "changefailed", triggerData );
- }, this));
- },
-
- _triggerPageBeforeChange: function( to, triggerData, settings ) {
- var pbcEvent = new $.Event( "pagebeforechange" );
-
- $.extend(triggerData, { toPage: to, options: settings });
-
- // NOTE: preserve the original target as the dataUrl value will be
- // simplified eg, removing ui-state, and removing query params from
- // the hash this is so that users who want to use query params have
- // access to them in the event bindings for the page life cycle
- // See issue #5085
- if ( $.type(to) === "string" ) {
- // if the toPage is a string simply convert it
- triggerData.absUrl = $.mobile.path.makeUrlAbsolute( to, this._findBaseWithDefault() );
- } else {
- // if the toPage is a jQuery object grab the absolute url stored
- // in the loadPage callback where it exists
- triggerData.absUrl = settings.absUrl;
- }
-
- // Let listeners know we're about to change the current page.
- this.element.trigger( pbcEvent, triggerData );
-
- // If the default behavior is prevented, stop here!
- if ( pbcEvent.isDefaultPrevented() ) {
- return false;
- }
-
- return true;
- },
-
- change: function( to, options ) {
- // If we are in the midst of a transition, queue the current request.
- // We'll call changePage() once we're done with the current transition
- // to service the request.
- if ( isPageTransitioning ) {
- pageTransitionQueue.unshift( arguments );
- return;
- }
-
- var settings = $.extend( {}, $.mobile.changePage.defaults, options ),
- triggerData = {};
-
- // Make sure we have a fromPage.
- settings.fromPage = settings.fromPage || this.activePage;
-
- // if the page beforechange default is prevented return early
- if ( !this._triggerPageBeforeChange(to, triggerData, settings) ) {
- return;
- }
-
- // We allow "pagebeforechange" observers to modify the to in
- // the trigger data to allow for redirects. Make sure our to is
- // updated. We also need to re-evaluate whether it is a string,
- // because an object can also be replaced by a string
- to = triggerData.toPage;
-
- // If the caller passed us a url, call loadPage()
- // to make sure it is loaded into the DOM. We'll listen
- // to the promise object it returns so we know when
- // it is done loading or if an error ocurred.
- if ( $.type(to) === "string" ) {
- // Set the isPageTransitioning flag to prevent any requests from
- // entering this method while we are in the midst of loading a page
- // or transitioning.
- isPageTransitioning = true;
-
- this._loadUrl( to, triggerData, settings );
- } else {
- this.transition( to, triggerData, settings );
- }
- },
-
- transition: function( toPage, triggerData, settings ) {
- var fromPage, url, pageUrl, fileUrl,
- active, activeIsInitialPage,
- historyDir, pageTitle, isDialog,
- alreadyThere, newPageTitle,
- params, cssTransitionDeferred,
- beforeTransition;
-
- // If we are in the midst of a transition, queue the current request.
- // We'll call changePage() once we're done with the current transition
- // to service the request.
- if ( isPageTransitioning ) {
- // make sure to only queue the to and settings values so the arguments
- // work with a call to the change method
- pageTransitionQueue.unshift( [toPage, settings] );
- return;
- }
-
- // DEPRECATED - this call only, in favor of the before transition
- // if the page beforechange default is prevented return early
- if ( !this._triggerPageBeforeChange(toPage, triggerData, settings) ) {
- return;
- }
-
- // if the (content|page)beforetransition default is prevented return early
- // Note, we have to check for both the deprecated and new events
- beforeTransition = this._triggerWithDeprecated( "beforetransition", triggerData );
- if (beforeTransition.deprecatedEvent.isDefaultPrevented() ||
- beforeTransition.event.isDefaultPrevented() ) {
- return;
- }
-
- // Set the isPageTransitioning flag to prevent any requests from
- // entering this method while we are in the midst of loading a page
- // or transitioning.
- isPageTransitioning = true;
-
- // If we are going to the first-page of the application, we need to make
- // sure settings.dataUrl is set to the application document url. This allows
- // us to avoid generating a document url with an id hash in the case where the
- // first-page of the document has an id attribute specified.
- if ( toPage[ 0 ] === $.mobile.firstPage[ 0 ] && !settings.dataUrl ) {
- settings.dataUrl = $.mobile.path.documentUrl.hrefNoHash;
- }
-
- // The caller passed us a real page DOM element. Update our
- // internal state and then trigger a transition to the page.
- fromPage = settings.fromPage;
- url = ( settings.dataUrl && $.mobile.path.convertUrlToDataUrl(settings.dataUrl) ) ||
- toPage.jqmData( "url" );
-
- // The pageUrl var is usually the same as url, except when url is obscured
- // as a dialog url. pageUrl always contains the file path
- pageUrl = url;
- fileUrl = $.mobile.path.getFilePath( url );
- active = $.mobile.navigate.history.getActive();
- activeIsInitialPage = $.mobile.navigate.history.activeIndex === 0;
- historyDir = 0;
- pageTitle = document.title;
- isDialog = ( settings.role === "dialog" ||
- toPage.jqmData( "role" ) === "dialog" ) &&
- toPage.jqmData( "dialog" ) !== true;
-
- // By default, we prevent changePage requests when the fromPage and toPage
- // are the same element, but folks that generate content
- // manually/dynamically and reuse pages want to be able to transition to
- // the same page. To allow this, they will need to change the default
- // value of allowSamePageTransition to true, *OR*, pass it in as an
- // option when they manually call changePage(). It should be noted that
- // our default transition animations assume that the formPage and toPage
- // are different elements, so they may behave unexpectedly. It is up to
- // the developer that turns on the allowSamePageTransitiona option to
- // either turn off transition animations, or make sure that an appropriate
- // animation transition is used.
- if ( fromPage && fromPage[0] === toPage[0] &&
- !settings.allowSamePageTransition ) {
-
- isPageTransitioning = false;
- this._triggerWithDeprecated( "transition", triggerData );
- this.element.trigger( "pagechange", triggerData );
-
- // Even if there is no page change to be done, we should keep the
- // urlHistory in sync with the hash changes
- if ( settings.fromHashChange ) {
- $.mobile.navigate.history.direct({ url: url });
- }
-
- return;
- }
-
- // We need to make sure the page we are given has already been enhanced.
- toPage.page({ role: settings.role });
-
- // If the changePage request was sent from a hashChange event, check to
- // see if the page is already within the urlHistory stack. If so, we'll
- // assume the user hit the forward/back button and will try to match the
- // transition accordingly.
- if ( settings.fromHashChange ) {
- historyDir = settings.direction === "back" ? -1 : 1;
- }
-
- // Kill the keyboard.
- // XXX_jblas: We need to stop crawling the entire document to kill focus.
- // Instead, we should be tracking focus with a delegate()
- // handler so we already have the element in hand at this
- // point.
- // Wrap this in a try/catch block since IE9 throw "Unspecified error" if
- // document.activeElement is undefined when we are in an IFrame.
- try {
- if ( document.activeElement &&
- document.activeElement.nodeName.toLowerCase() !== "body" ) {
-
- $( document.activeElement ).blur();
- } else {
- $( "input:focus, textarea:focus, select:focus" ).blur();
- }
- } catch( e ) {}
-
- // Record whether we are at a place in history where a dialog used to be -
- // if so, do not add a new history entry and do not change the hash either
- alreadyThere = false;
-
- // If we're displaying the page as a dialog, we don't want the url
- // for the dialog content to be used in the hash. Instead, we want
- // to append the dialogHashKey to the url of the current page.
- if ( isDialog && active ) {
- // on the initial page load active.url is undefined and in that case
- // should be an empty string. Moving the undefined -> empty string back
- // into urlHistory.addNew seemed imprudent given undefined better
- // represents the url state
-
- // If we are at a place in history that once belonged to a dialog, reuse
- // this state without adding to urlHistory and without modifying the
- // hash. However, if a dialog is already displayed at this point, and
- // we're about to display another dialog, then we must add another hash
- // and history entry on top so that one may navigate back to the
- // original dialog
- if ( active.url &&
- active.url.indexOf( $.mobile.dialogHashKey ) > -1 &&
- this.activePage &&
- !this.activePage.hasClass( "ui-dialog" ) &&
- $.mobile.navigate.history.activeIndex > 0 ) {
-
- settings.changeHash = false;
- alreadyThere = true;
- }
-
- // Normally, we tack on a dialog hash key, but if this is the location
- // of a stale dialog, we reuse the URL from the entry
- url = ( active.url || "" );
-
- // account for absolute urls instead of just relative urls use as hashes
- if ( !alreadyThere && url.indexOf("#") > -1 ) {
- url += $.mobile.dialogHashKey;
- } else {
- url += "#" + $.mobile.dialogHashKey;
- }
-
- // tack on another dialogHashKey if this is the same as the initial hash
- // this makes sure that a history entry is created for this dialog
- if ( $.mobile.navigate.history.activeIndex === 0 && url === $.mobile.navigate.history.initialDst ) {
- url += $.mobile.dialogHashKey;
- }
- }
-
- // if title element wasn't found, try the page div data attr too
- // If this is a deep-link or a reload ( active === undefined ) then just
- // use pageTitle
- newPageTitle = ( !active ) ? pageTitle : toPage.jqmData( "title" ) ||
- toPage.children( ":jqmData(role='header')" ).find( ".ui-title" ).text();
- if ( !!newPageTitle && pageTitle === document.title ) {
- pageTitle = newPageTitle;
- }
- if ( !toPage.jqmData( "title" ) ) {
- toPage.jqmData( "title", pageTitle );
- }
-
- // Make sure we have a transition defined.
- settings.transition = settings.transition ||
- ( ( historyDir && !activeIsInitialPage ) ? active.transition : undefined ) ||
- ( isDialog ? $.mobile.defaultDialogTransition : $.mobile.defaultPageTransition );
-
- //add page to history stack if it's not back or forward
- if ( !historyDir && alreadyThere ) {
- $.mobile.navigate.history.getActive().pageUrl = pageUrl;
- }
-
- // Set the location hash.
- if ( url && !settings.fromHashChange ) {
-
- // rebuilding the hash here since we loose it earlier on
- // TODO preserve the originally passed in path
- if ( !$.mobile.path.isPath( url ) && url.indexOf( "#" ) < 0 ) {
- url = "#" + url;
- }
-
- // TODO the property names here are just silly
- params = {
- transition: settings.transition,
- title: pageTitle,
- pageUrl: pageUrl,
- role: settings.role
- };
-
- if ( settings.changeHash !== false && $.mobile.hashListeningEnabled ) {
- $.mobile.navigate( url, params, true);
- } else if ( toPage[ 0 ] !== $.mobile.firstPage[ 0 ] ) {
- $.mobile.navigate.history.add( url, params );
- }
- }
-
- //set page title
- document.title = pageTitle;
-
- //set "toPage" as activePage deprecated in 1.4 remove in 1.5
- $.mobile.activePage = toPage;
-
- //new way to handle activePage
- this.activePage = toPage;
-
- // If we're navigating back in the URL history, set reverse accordingly.
- settings.reverse = settings.reverse || historyDir < 0;
-
- cssTransitionDeferred = $.Deferred();
-
- this._cssTransition(toPage, fromPage, {
- transition: settings.transition,
- reverse: settings.reverse,
- deferred: cssTransitionDeferred
- });
-
- cssTransitionDeferred.done($.proxy(function( name, reverse, $to, $from, alreadyFocused ) {
- $.mobile.removeActiveLinkClass();
-
- //if there's a duplicateCachedPage, remove it from the DOM now that it's hidden
- if ( settings.duplicateCachedPage ) {
- settings.duplicateCachedPage.remove();
- }
-
- // despite visibility: hidden addresses issue #2965
- // https://github.com/jquery/jquery-mobile/issues/2965
- if ( !alreadyFocused ) {
- $.mobile.focusPage( toPage );
- }
-
- this._releaseTransitionLock();
- this.element.trigger( "pagechange", triggerData );
- this._triggerWithDeprecated( "transition", triggerData );
- }, this));
- },
-
- // determine the current base url
- _findBaseWithDefault: function() {
- var closestBase = ( this.activePage &&
- $.mobile.getClosestBaseUrl( this.activePage ) );
- return closestBase || $.mobile.path.documentBase.hrefNoHash;
- }
- });
-
- // The following handlers should be bound after mobileinit has been triggered
- // the following deferred is resolved in the init file
- $.mobile.navreadyDeferred = $.Deferred();
-
- //these variables make all page containers use the same queue and only navigate one at a time
- // queue to hold simultanious page transitions
- var pageTransitionQueue = [],
-
- // indicates whether or not page is in process of transitioning
- isPageTransitioning = false;
-
-})( jQuery );
-
-(function( $, undefined ) {
-
- // resolved on domready
- var domreadyDeferred = $.Deferred(),
-
- // resolved and nulled on window.load()
- loadDeferred = $.Deferred(),
- documentUrl = $.mobile.path.documentUrl,
-
- // used to track last vclicked element to make sure its value is added to form data
- $lastVClicked = null;
-
- /* Event Bindings - hashchange, submit, and click */
- function findClosestLink( ele ) {
- while ( ele ) {
- // Look for the closest element with a nodeName of "a".
- // Note that we are checking if we have a valid nodeName
- // before attempting to access it. This is because the
- // node we get called with could have originated from within
- // an embedded SVG document where some symbol instance elements
- // don't have nodeName defined on them, or strings are of type
- // SVGAnimatedString.
- if ( ( typeof ele.nodeName === "string" ) && ele.nodeName.toLowerCase() === "a" ) {
- break;
- }
- ele = ele.parentNode;
- }
- return ele;
- }
-
- $.mobile.loadPage = function( url, opts ) {
- var container;
-
- opts = opts || {};
- container = ( opts.pageContainer || $.mobile.pageContainer );
-
- // create the deferred that will be supplied to loadPage callers
- // and resolved by the content widget's load method
- opts.deferred = $.Deferred();
-
- // Preferring to allow exceptions for uninitialized opts.pageContainer
- // widgets so we know if we need to force init here for users
- container.pagecontainer( "load", url, opts );
-
- // provide the deferred
- return opts.deferred.promise();
- };
-
- //define vars for interal use
-
- /* internal utility functions */
-
- // NOTE Issue #4950 Android phonegap doesn't navigate back properly
- // when a full page refresh has taken place. It appears that hashchange
- // and replacestate history alterations work fine but we need to support
- // both forms of history traversal in our code that uses backward history
- // movement
- $.mobile.back = function() {
- var nav = window.navigator;
-
- // if the setting is on and the navigator object is
- // available use the phonegap navigation capability
- if ( this.phonegapNavigationEnabled &&
- nav &&
- nav.app &&
- nav.app.backHistory ) {
- nav.app.backHistory();
- } else {
- $.mobile.pageContainer.pagecontainer( "back" );
- }
- };
-
- // Direct focus to the page title, or otherwise first focusable element
- $.mobile.focusPage = function ( page ) {
- var autofocus = page.find( "[autofocus]" ),
- pageTitle = page.find( ".ui-title:eq(0)" );
-
- if ( autofocus.length ) {
- autofocus.focus();
- return;
- }
-
- if ( pageTitle.length ) {
- pageTitle.focus();
- } else{
- page.focus();
- }
- };
-
- // No-op implementation of transition degradation
- $.mobile._maybeDegradeTransition = $.mobile._maybeDegradeTransition || function( transition ) {
- return transition;
- };
-
- // Exposed $.mobile methods
-
- $.mobile.changePage = function( to, options ) {
- $.mobile.pageContainer.pagecontainer( "change", to, options );
- };
-
- $.mobile.changePage.defaults = {
- transition: undefined,
- reverse: false,
- changeHash: true,
- fromHashChange: false,
- role: undefined, // By default we rely on the role defined by the @data-role attribute.
- duplicateCachedPage: undefined,
- pageContainer: undefined,
- showLoadMsg: true, //loading message shows by default when pages are being fetched during changePage
- dataUrl: undefined,
- fromPage: undefined,
- allowSamePageTransition: false
- };
-
- $.mobile._registerInternalEvents = function() {
- var getAjaxFormData = function( $form, calculateOnly ) {
- var url, ret = true, formData, vclickedName, method;
- if ( !$.mobile.ajaxEnabled ||
- // test that the form is, itself, ajax false
- $form.is( ":jqmData(ajax='false')" ) ||
- // test that $.mobile.ignoreContentEnabled is set and
- // the form or one of it's parents is ajax=false
- !$form.jqmHijackable().length ||
- $form.attr( "target" ) ) {
- return false;
- }
-
- url = ( $lastVClicked && $lastVClicked.attr( "formaction" ) ) ||
- $form.attr( "action" );
- method = ( $form.attr( "method" ) || "get" ).toLowerCase();
-
- // If no action is specified, browsers default to using the
- // URL of the document containing the form. Since we dynamically
- // pull in pages from external documents, the form should submit
- // to the URL for the source document of the page containing
- // the form.
- if ( !url ) {
- // Get the @data-url for the page containing the form.
- url = $.mobile.getClosestBaseUrl( $form );
-
- // NOTE: If the method is "get", we need to strip off the query string
- // because it will get replaced with the new form data. See issue #5710.
- if ( method === "get" ) {
- url = $.mobile.path.parseUrl( url ).hrefNoSearch;
- }
-
- if ( url === $.mobile.path.documentBase.hrefNoHash ) {
- // The url we got back matches the document base,
- // which means the page must be an internal/embedded page,
- // so default to using the actual document url as a browser
- // would.
- url = documentUrl.hrefNoSearch;
- }
- }
-
- url = $.mobile.path.makeUrlAbsolute( url, $.mobile.getClosestBaseUrl( $form ) );
-
- if ( ( $.mobile.path.isExternal( url ) && !$.mobile.path.isPermittedCrossDomainRequest( documentUrl, url ) ) ) {
- return false;
- }
-
- if ( !calculateOnly ) {
- formData = $form.serializeArray();
-
- if ( $lastVClicked && $lastVClicked[ 0 ].form === $form[ 0 ] ) {
- vclickedName = $lastVClicked.attr( "name" );
- if ( vclickedName ) {
- // Make sure the last clicked element is included in the form
- $.each( formData, function( key, value ) {
- if ( value.name === vclickedName ) {
- // Unset vclickedName - we've found it in the serialized data already
- vclickedName = "";
- return false;
- }
- });
- if ( vclickedName ) {
- formData.push( { name: vclickedName, value: $lastVClicked.attr( "value" ) } );
- }
- }
- }
-
- ret = {
- url: url,
- options: {
- type: method,
- data: $.param( formData ),
- transition: $form.jqmData( "transition" ),
- reverse: $form.jqmData( "direction" ) === "reverse",
- reloadPage: true
- }
- };
- }
-
- return ret;
- };
-
- //bind to form submit events, handle with Ajax
- $.mobile.document.delegate( "form", "submit", function( event ) {
- var formData;
-
- if ( !event.isDefaultPrevented() ) {
- formData = getAjaxFormData( $( this ) );
- if ( formData ) {
- $.mobile.changePage( formData.url, formData.options );
- event.preventDefault();
- }
- }
- });
-
- //add active state on vclick
- $.mobile.document.bind( "vclick", function( event ) {
- var $btn, btnEls, target = event.target, needClosest = false;
- // if this isn't a left click we don't care. Its important to note
- // that when the virtual event is generated it will create the which attr
- if ( event.which > 1 || !$.mobile.linkBindingEnabled ) {
- return;
- }
-
- // Record that this element was clicked, in case we need it for correct
- // form submission during the "submit" handler above
- $lastVClicked = $( target );
-
- // Try to find a target element to which the active class will be applied
- if ( $.data( target, "mobile-button" ) ) {
- // If the form will not be submitted via AJAX, do not add active class
- if ( !getAjaxFormData( $( target ).closest( "form" ), true ) ) {
- return;
- }
- // We will apply the active state to this button widget - the parent
- // of the input that was clicked will have the associated data
- if ( target.parentNode ) {
- target = target.parentNode;
- }
- } else {
- target = findClosestLink( target );
- if ( !( target && $.mobile.path.parseUrl( target.getAttribute( "href" ) || "#" ).hash !== "#" ) ) {
- return;
- }
-
- // TODO teach $.mobile.hijackable to operate on raw dom elements so the
- // link wrapping can be avoided
- if ( !$( target ).jqmHijackable().length ) {
- return;
- }
- }
-
- // Avoid calling .closest by using the data set during .buttonMarkup()
- // List items have the button data in the parent of the element clicked
- if ( !!~target.className.indexOf( "ui-link-inherit" ) ) {
- if ( target.parentNode ) {
- btnEls = $.data( target.parentNode, "buttonElements" );
- }
- // Otherwise, look for the data on the target itself
- } else {
- btnEls = $.data( target, "buttonElements" );
- }
- // If found, grab the button's outer element
- if ( btnEls ) {
- target = btnEls.outer;
- } else {
- needClosest = true;
- }
-
- $btn = $( target );
- // If the outer element wasn't found by the our heuristics, use .closest()
- if ( needClosest ) {
- $btn = $btn.closest( ".ui-btn" );
- }
-
- if ( $btn.length > 0 &&
- !( $btn.hasClass( "ui-state-disabled" ||
-
- // DEPRECATED as of 1.4.0 - remove after 1.4.0 release
- // only ui-state-disabled should be present thereafter
- $btn.hasClass( "ui-disabled" ) ) ) ) {
- $.mobile.removeActiveLinkClass( true );
- $.mobile.activeClickedLink = $btn;
- $.mobile.activeClickedLink.addClass( $.mobile.activeBtnClass );
- }
- });
-
- // click routing - direct to HTTP or Ajax, accordingly
- $.mobile.document.bind( "click", function( event ) {
- if ( !$.mobile.linkBindingEnabled || event.isDefaultPrevented() ) {
- return;
- }
-
- var link = findClosestLink( event.target ),
- $link = $( link ),
-
- //remove active link class if external (then it won't be there if you come back)
- httpCleanup = function() {
- window.setTimeout(function() { $.mobile.removeActiveLinkClass( true ); }, 200 );
- },
- baseUrl, href,
- useDefaultUrlHandling, isExternal,
- transition, reverse, role;
-
- // If a button was clicked, clean up the active class added by vclick above
- if ( $.mobile.activeClickedLink &&
- $.mobile.activeClickedLink[ 0 ] === event.target.parentNode ) {
- httpCleanup();
- }
-
- // If there is no link associated with the click or its not a left
- // click we want to ignore the click
- // TODO teach $.mobile.hijackable to operate on raw dom elements so the link wrapping
- // can be avoided
- if ( !link || event.which > 1 || !$link.jqmHijackable().length ) {
- return;
- }
-
- //if there's a data-rel=back attr, go back in history
- if ( $link.is( ":jqmData(rel='back')" ) ) {
- $.mobile.back();
- return false;
- }
-
- baseUrl = $.mobile.getClosestBaseUrl( $link );
-
- //get href, if defined, otherwise default to empty hash
- href = $.mobile.path.makeUrlAbsolute( $link.attr( "href" ) || "#", baseUrl );
-
- //if ajax is disabled, exit early
- if ( !$.mobile.ajaxEnabled && !$.mobile.path.isEmbeddedPage( href ) ) {
- httpCleanup();
- //use default click handling
- return;
- }
-
- // XXX_jblas: Ideally links to application pages should be specified as
- // an url to the application document with a hash that is either
- // the site relative path or id to the page. But some of the
- // internal code that dynamically generates sub-pages for nested
- // lists and select dialogs, just write a hash in the link they
- // create. This means the actual URL path is based on whatever
- // the current value of the base tag is at the time this code
- // is called. For now we are just assuming that any url with a
- // hash in it is an application page reference.
- if ( href.search( "#" ) !== -1 ) {
- href = href.replace( /[^#]*#/, "" );
- if ( !href ) {
- //link was an empty hash meant purely
- //for interaction, so we ignore it.
- event.preventDefault();
- return;
- } else if ( $.mobile.path.isPath( href ) ) {
- //we have apath so make it the href we want to load.
- href = $.mobile.path.makeUrlAbsolute( href, baseUrl );
- } else {
- //we have a simple id so use the documentUrl as its base.
- href = $.mobile.path.makeUrlAbsolute( "#" + href, documentUrl.hrefNoHash );
- }
- }
-
- // Should we handle this link, or let the browser deal with it?
- useDefaultUrlHandling = $link.is( "[rel='external']" ) || $link.is( ":jqmData(ajax='false')" ) || $link.is( "[target]" );
-
- // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
- // requests if the document doing the request was loaded via the file:// protocol.
- // This is usually to allow the application to "phone home" and fetch app specific
- // data. We normally let the browser handle external/cross-domain urls, but if the
- // allowCrossDomainPages option is true, we will allow cross-domain http/https
- // requests to go through our page loading logic.
-
- //check for protocol or rel and its not an embedded page
- //TODO overlap in logic from isExternal, rel=external check should be
- // moved into more comprehensive isExternalLink
- isExternal = useDefaultUrlHandling || ( $.mobile.path.isExternal( href ) && !$.mobile.path.isPermittedCrossDomainRequest( documentUrl, href ) );
-
- if ( isExternal ) {
- httpCleanup();
- //use default click handling
- return;
- }
-
- //use ajax
- transition = $link.jqmData( "transition" );
- reverse = $link.jqmData( "direction" ) === "reverse" ||
- // deprecated - remove by 1.0
- $link.jqmData( "back" );
-
- //this may need to be more specific as we use data-rel more
- role = $link.attr( "data-" + $.mobile.ns + "rel" ) || undefined;
-
- $.mobile.changePage( href, { transition: transition, reverse: reverse, role: role, link: $link } );
- event.preventDefault();
- });
-
- //prefetch pages when anchors with data-prefetch are encountered
- $.mobile.document.delegate( ".ui-page", "pageshow.prefetch", function() {
- var urls = [];
- $( this ).find( "a:jqmData(prefetch)" ).each(function() {
- var $link = $( this ),
- url = $link.attr( "href" );
-
- if ( url && $.inArray( url, urls ) === -1 ) {
- urls.push( url );
-
- $.mobile.loadPage( url, { role: $link.attr( "data-" + $.mobile.ns + "rel" ),prefetch: true } );
- }
- });
- });
-
- // TODO ensure that the navigate binding in the content widget happens at the right time
- $.mobile.pageContainer.pagecontainer();
-
- //set page min-heights to be device specific
- $.mobile.document.bind( "pageshow", function() {
-
- // We need to wait for window.load to make sure that styles have already been rendered,
- // otherwise heights of external toolbars will have the wrong value
- if ( loadDeferred ) {
- loadDeferred.done( $.mobile.resetActivePageHeight );
- } else {
- $.mobile.resetActivePageHeight();
- }
- });
- $.mobile.window.bind( "throttledresize", $.mobile.resetActivePageHeight );
-
- };//navreadyDeferred done callback
-
- $( function() { domreadyDeferred.resolve(); } );
-
- $.mobile.window.load( function() {
-
- // Resolve and null the deferred
- loadDeferred.resolve();
- loadDeferred = null;
- });
-
- $.when( domreadyDeferred, $.mobile.navreadyDeferred ).done( function() { $.mobile._registerInternalEvents(); } );
-})( jQuery );
-
-
-(function( $, window, undefined ) {
-
- // TODO remove direct references to $.mobile and properties, we should
- // favor injection with params to the constructor
- $.mobile.Transition = function() {
- this.init.apply( this, arguments );
- };
-
- $.extend($.mobile.Transition.prototype, {
- toPreClass: " ui-page-pre-in",
-
- init: function( name, reverse, $to, $from ) {
- $.extend(this, {
- name: name,
- reverse: reverse,
- $to: $to,
- $from: $from,
- deferred: new $.Deferred()
- });
- },
-
- cleanFrom: function() {
- this.$from
- .removeClass( $.mobile.activePageClass + " out in reverse " + this.name )
- .height( "" );
- },
-
- // NOTE overridden by child object prototypes, noop'd here as defaults
- beforeDoneIn: function() {},
- beforeDoneOut: function() {},
- beforeStartOut: function() {},
-
- doneIn: function() {
- this.beforeDoneIn();
-
- this.$to.removeClass( "out in reverse " + this.name ).height( "" );
-
- this.toggleViewportClass();
-
- // In some browsers (iOS5), 3D transitions block the ability to scroll to the desired location during transition
- // This ensures we jump to that spot after the fact, if we aren't there already.
- if ( $.mobile.window.scrollTop() !== this.toScroll ) {
- this.scrollPage();
- }
- if ( !this.sequential ) {
- this.$to.addClass( $.mobile.activePageClass );
- }
- this.deferred.resolve( this.name, this.reverse, this.$to, this.$from, true );
- },
-
- doneOut: function( screenHeight, reverseClass, none, preventFocus ) {
- this.beforeDoneOut();
- this.startIn( screenHeight, reverseClass, none, preventFocus );
- },
-
- hideIn: function( callback ) {
- // Prevent flickering in phonegap container: see comments at #4024 regarding iOS
- this.$to.css( "z-index", -10 );
- callback.call( this );
- this.$to.css( "z-index", "" );
- },
-
- scrollPage: function() {
- // By using scrollTo instead of silentScroll, we can keep things better in order
- // Just to be precautios, disable scrollstart listening like silentScroll would
- $.event.special.scrollstart.enabled = false;
- //if we are hiding the url bar or the page was previously scrolled scroll to hide or return to position
- if ( $.mobile.hideUrlBar || this.toScroll !== $.mobile.defaultHomeScroll ) {
- window.scrollTo( 0, this.toScroll );
- }
-
- // reenable scrollstart listening like silentScroll would
- setTimeout( function() {
- $.event.special.scrollstart.enabled = true;
- }, 150 );
- },
-
- startIn: function( screenHeight, reverseClass, none, preventFocus ) {
- this.hideIn(function() {
- this.$to.addClass( $.mobile.activePageClass + this.toPreClass );
-
- // Send focus to page as it is now display: block
- if ( !preventFocus ) {
- $.mobile.focusPage( this.$to );
- }
-
- // Set to page height
- this.$to.height( screenHeight + this.toScroll );
-
- if ( !none ) {
- this.scrollPage();
- }
- });
-
- this.$to
- .removeClass( this.toPreClass )
- .addClass( this.name + " in " + reverseClass );
-
- if ( !none ) {
- this.$to.animationComplete( $.proxy(function() {
- this.doneIn();
- }, this ));
- } else {
- this.doneIn();
- }
-
- },
-
- startOut: function( screenHeight, reverseClass, none ) {
- this.beforeStartOut( screenHeight, reverseClass, none );
-
- // Set the from page's height and start it transitioning out
- // Note: setting an explicit height helps eliminate tiling in the transitions
- this.$from
- .height( screenHeight + $.mobile.window.scrollTop() )
- .addClass( this.name + " out" + reverseClass );
- },
-
- toggleViewportClass: function() {
- $.mobile.pageContainer.toggleClass( "ui-mobile-viewport-transitioning viewport-" + this.name );
- },
-
- transition: function() {
- // NOTE many of these could be calculated/recorded in the constructor, it's my
- // opinion that binding them as late as possible has value with regards to
- // better transitions with fewer bugs. Ie, it's not guaranteed that the
- // object will be created and transition will be run immediately after as
- // it is today. So we wait until transition is invoked to gather the following
- var none,
- reverseClass = this.reverse ? " reverse" : "",
- screenHeight = $.mobile.getScreenHeight(),
- maxTransitionOverride = $.mobile.maxTransitionWidth !== false &&
- $.mobile.window.width() > $.mobile.maxTransitionWidth;
-
- this.toScroll = $.mobile.navigate.history.getActive().lastScroll || $.mobile.defaultHomeScroll;
-
- none = !$.support.cssTransitions || !$.support.cssAnimations ||
- maxTransitionOverride || !this.name || this.name === "none" ||
- Math.max( $.mobile.window.scrollTop(), this.toScroll ) >
- $.mobile.getMaxScrollForTransition();
-
- this.toggleViewportClass();
-
- if ( this.$from && !none ) {
- this.startOut( screenHeight, reverseClass, none );
- } else {
- this.doneOut( screenHeight, reverseClass, none, true );
- }
-
- return this.deferred.promise();
- }
- });
-})( jQuery, this );
-
-
-(function( $ ) {
-
- $.mobile.SerialTransition = function() {
- this.init.apply(this, arguments);
- };
-
- $.extend($.mobile.SerialTransition.prototype, $.mobile.Transition.prototype, {
- sequential: true,
-
- beforeDoneOut: function() {
- if ( this.$from ) {
- this.cleanFrom();
- }
- },
-
- beforeStartOut: function( screenHeight, reverseClass, none ) {
- this.$from.animationComplete($.proxy(function() {
- this.doneOut( screenHeight, reverseClass, none );
- }, this ));
- }
- });
-
-})( jQuery );
-
-
-(function( $ ) {
-
- $.mobile.ConcurrentTransition = function() {
- this.init.apply(this, arguments);
- };
-
- $.extend($.mobile.ConcurrentTransition.prototype, $.mobile.Transition.prototype, {
- sequential: false,
-
- beforeDoneIn: function() {
- if ( this.$from ) {
- this.cleanFrom();
- }
- },
-
- beforeStartOut: function( screenHeight, reverseClass, none ) {
- this.doneOut( screenHeight, reverseClass, none );
- }
- });
-
-})( jQuery );
-
-
-(function( $ ) {
-
- // generate the handlers from the above
- var defaultGetMaxScrollForTransition = function() {
- return $.mobile.getScreenHeight() * 3;
- };
-
- //transition handler dictionary for 3rd party transitions
- $.mobile.transitionHandlers = {
- "sequential": $.mobile.SerialTransition,
- "simultaneous": $.mobile.ConcurrentTransition
- };
-
- // Make our transition handler the public default.
- $.mobile.defaultTransitionHandler = $.mobile.transitionHandlers.sequential;
-
- $.mobile.transitionFallbacks = {};
-
- // If transition is defined, check if css 3D transforms are supported, and if not, if a fallback is specified
- $.mobile._maybeDegradeTransition = function( transition ) {
- if ( transition && !$.support.cssTransform3d && $.mobile.transitionFallbacks[ transition ] ) {
- transition = $.mobile.transitionFallbacks[ transition ];
- }
-
- return transition;
- };
-
- // Set the getMaxScrollForTransition to default if no implementation was set by user
- $.mobile.getMaxScrollForTransition = $.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition;
-
-})( jQuery );
-
-/*
-* fallback transition for flip in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.flip = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for flow in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.flow = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for pop in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.pop = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for slide in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-// Use the simultaneous transitions handler for slide transitions
-$.mobile.transitionHandlers.slide = $.mobile.transitionHandlers.simultaneous;
-
-// Set the slide transitions's fallback to "fade"
-$.mobile.transitionFallbacks.slide = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for slidedown in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.slidedown = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for slidefade in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-// Set the slide transitions's fallback to "fade"
-$.mobile.transitionFallbacks.slidefade = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for slideup in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.slideup = "fade";
-
-})( jQuery, this );
-
-/*
-* fallback transition for turn in non-3D supporting browsers (which tend to handle complex transitions poorly in general
-*/
-
-(function( $, window, undefined ) {
-
-$.mobile.transitionFallbacks.turn = "fade";
-
-})( jQuery, this );
-
-
-(function( $, undefined ) {
-
-$.mobile.degradeInputs = {
- color: false,
- date: false,
- datetime: false,
- "datetime-local": false,
- email: false,
- month: false,
- number: false,
- range: "number",
- search: "text",
- tel: false,
- time: false,
- url: false,
- week: false
-};
-// Backcompat remove in 1.5
-$.mobile.page.prototype.options.degradeInputs = $.mobile.degradeInputs;
-
-// Auto self-init widgets
-$.mobile.degradeInputsWithin = function( target ) {
-
- target = $( target );
-
- // Degrade inputs to avoid poorly implemented native functionality
- target.find( "input" ).not( $.mobile.page.prototype.keepNativeSelector() ).each(function() {
- var element = $( this ),
- type = this.getAttribute( "type" ),
- optType = $.mobile.degradeInputs[ type ] || "text",
- html, hasType, findstr, repstr;
-
- if ( $.mobile.degradeInputs[ type ] ) {
- html = $( "<div>" ).html( element.clone() ).html();
- // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
- hasType = html.indexOf( " type=" ) > -1;
- findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/;
- repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );
-
- element.replaceWith( html.replace( findstr, repstr ) );
- }
- });
-
-};
-
-})( jQuery );
-
-(function( $, window, undefined ) {
-
-$.widget( "mobile.page", $.mobile.page, {
- options: {
-
- // Accepts left, right and none
- closeBtn: "left",
- closeBtnText: "Close",
- overlayTheme: "a",
- corners: true,
- dialog: false
- },
-
- _create: function() {
- this._super();
- if ( this.options.dialog ) {
-
- $.extend( this, {
- _inner: this.element.children(),
- _headerCloseButton: null
- });
-
- if ( !this.options.enhanced ) {
- this._setCloseBtn( this.options.closeBtn );
- }
- }
- },
-
- _enhance: function() {
- this._super();
-
- // Class the markup for dialog styling and wrap interior
- if ( this.options.dialog ) {
- this.element.addClass( "ui-dialog" )
- .wrapInner( $( "<div/>", {
-
- // ARIA role
- "role" : "dialog",
- "class" : "ui-dialog-contain ui-overlay-shadow" +
- ( this.options.corners ? " ui-corner-all" : "" )
- }));
- }
- },
-
- _setOptions: function( options ) {
- var closeButtonLocation, closeButtonText,
- currentOpts = this.options;
-
- if ( options.corners !== undefined ) {
- this._inner.toggleClass( "ui-corner-all", !!options.corners );
- }
-
- if ( options.overlayTheme !== undefined ) {
- if ( $.mobile.activePage[ 0 ] === this.element[ 0 ] ) {
- currentOpts.overlayTheme = options.overlayTheme;
- this._handlePageBeforeShow();
- }
- }
-
- if ( options.closeBtnText !== undefined ) {
- closeButtonLocation = currentOpts.closeBtn;
- closeButtonText = options.closeBtnText;
- }
-
- if ( options.closeBtn !== undefined ) {
- closeButtonLocation = options.closeBtn;
- }
-
- if ( closeButtonLocation ) {
- this._setCloseBtn( closeButtonLocation, closeButtonText );
- }
-
- this._super( options );
- },
-
- _handlePageBeforeShow: function () {
- if ( this.options.overlayTheme && this.options.dialog ) {
- this.removeContainerBackground();
- this.setContainerBackground( this.options.overlayTheme );
- } else {
- this._super();
- }
- },
-
- _setCloseBtn: function( location, text ) {
- var dst,
- btn = this._headerCloseButton;
-
- // Sanitize value
- location = "left" === location ? "left" : "right" === location ? "right" : "none";
-
- if ( "none" === location ) {
- if ( btn ) {
- btn.remove();
- btn = null;
- }
- } else if ( btn ) {
- btn.removeClass( "ui-btn-left ui-btn-right" ).addClass( "ui-btn-" + location );
- if ( text ) {
- btn.text( text );
- }
- } else {
- dst = this._inner.find( ":jqmData(role='header')" ).first();
- btn = $( "<a></a>", {
- "href": "#",
- "class": "ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-" + location
- })
- .attr( "data-" + $.mobile.ns + "rel", "back" )
- .text( text || this.options.closeBtnText || "" )
- .prependTo( dst );
- }
-
- this._headerCloseButton = btn;
- }
-});
-
-})( jQuery, this );
-
-(function( $, window, undefined ) {
-
-$.widget( "mobile.dialog", {
- options: {
-
- // Accepts left, right and none
- closeBtn: "left",
- closeBtnText: "Close",
- overlayTheme: "a",
- corners: true
- },
-
- // Override the theme set by the page plugin on pageshow
- _handlePageBeforeShow: function() {
- this._isCloseable = true;
- if ( this.options.overlayTheme ) {
- this.element
- .page( "removeContainerBackground" )
- .page( "setContainerBackground", this.options.overlayTheme );
- }
- },
-
- _handlePageBeforeHide: function() {
- this._isCloseable = false;
- },
-
- // click and submit events:
- // - clicks and submits should use the closing transition that the dialog
- // opened with unless a data-transition is specified on the link/form
- // - if the click was on the close button, or the link has a data-rel="back"
- // it'll go back in history naturally
- _handleVClickSubmit: function( event ) {
- var attrs,
- $target = $( event.target ).closest( event.type === "vclick" ? "a" : "form" );
-
- if ( $target.length && !$target.jqmData( "transition" ) ) {
- attrs = {};
- attrs[ "data-" + $.mobile.ns + "transition" ] =
- ( $.mobile.navigate.history.getActive() || {} )[ "transition" ] ||
- $.mobile.defaultDialogTransition;
- attrs[ "data-" + $.mobile.ns + "direction" ] = "reverse";
- $target.attr( attrs );
- }
- },
-
- _create: function() {
- var elem = this.element,
- opts = this.options;
-
- // Class the markup for dialog styling and wrap interior
- elem.addClass( "ui-dialog" )
- .wrapInner( $( "<div/>", {
-
- // ARIA role
- "role" : "dialog",
- "class" : "ui-dialog-contain ui-overlay-shadow" +
- ( !!opts.corners ? " ui-corner-all" : "" )
- }));
-
- $.extend( this, {
- _isCloseable: false,
- _inner: elem.children(),
- _headerCloseButton: null
- });
-
- this._on( elem, {
- vclick: "_handleVClickSubmit",
- submit: "_handleVClickSubmit",
- pagebeforeshow: "_handlePageBeforeShow",
- pagebeforehide: "_handlePageBeforeHide"
- });
-
- this._setCloseBtn( opts.closeBtn );
- },
-
- _setOptions: function( options ) {
- var closeButtonLocation, closeButtonText,
- currentOpts = this.options;
-
- if ( options.corners !== undefined ) {
- this._inner.toggleClass( "ui-corner-all", !!options.corners );
- }
-
- if ( options.overlayTheme !== undefined ) {
- if ( $.mobile.activePage[ 0 ] === this.element[ 0 ] ) {
- currentOpts.overlayTheme = options.overlayTheme;
- this._handlePageBeforeShow();
- }
- }
-
- if ( options.closeBtnText !== undefined ) {
- closeButtonLocation = currentOpts.closeBtn;
- closeButtonText = options.closeBtnText;
- }
-
- if ( options.closeBtn !== undefined ) {
- closeButtonLocation = options.closeBtn;
- }
-
- if ( closeButtonLocation ) {
- this._setCloseBtn( closeButtonLocation, closeButtonText );
- }
-
- this._super( options );
- },
-
- _setCloseBtn: function( location, text ) {
- var dst,
- btn = this._headerCloseButton;
-
- // Sanitize value
- location = "left" === location ? "left" : "right" === location ? "right" : "none";
-
- if ( "none" === location ) {
- if ( btn ) {
- btn.remove();
- btn = null;
- }
- } else if ( btn ) {
- btn.removeClass( "ui-btn-left ui-btn-right" ).addClass( "ui-btn-" + location );
- if ( text ) {
- btn.text( text );
- }
- } else {
- dst = this._inner.find( ":jqmData(role='header')" ).first();
- btn = $( "<a></a>", {
- "role": "button",
- "href": "#",
- "class": "ui-btn ui-corner-all ui-icon-delete ui-btn-icon-notext ui-btn-" + location
- })
- .text( text || this.options.closeBtnText || "" )
- .prependTo( dst );
- this._on( btn, { click: "close" } );
- }
-
- this._headerCloseButton = btn;
- },
-
- // Close method goes back in history
- close: function() {
- var hist = $.mobile.navigate.history;
-
- if ( this._isCloseable ) {
- this._isCloseable = false;
- // If the hash listening is enabled and there is at least one preceding history
- // entry it's ok to go back. Initial pages with the dialog hash state are an example
- // where the stack check is necessary
- if ( $.mobile.hashListeningEnabled && hist.activeIndex > 0 ) {
- $.mobile.back();
- } else {
- $.mobile.pageContainer.pagecontainer( "back" );
- }
- }
- }
-});
-
-})( jQuery, this );
-
-(function( $, undefined ) {
-
-var rInitialLetter = /([A-Z])/g,
-
- // Construct iconpos class from iconpos value
- iconposClass = function( iconpos ) {
- return ( "ui-btn-icon-" + ( iconpos === null ? "left" : iconpos ) );
- };
-
-$.widget( "mobile.collapsible", {
- options: {
- enhanced: false,
- expandCueText: null,
- collapseCueText: null,
- collapsed: true,
- heading: "h1,h2,h3,h4,h5,h6,legend",
- collapsedIcon: null,
- expandedIcon: null,
- iconpos: null,
- theme: null,
- contentTheme: null,
- inset: null,
- corners: null,
- mini: null
- },
-
- _create: function() {
- var elem = this.element,
- ui = {
- accordion: elem
- .closest( ":jqmData(role='collapsible-set')," +
- ":jqmData(role='collapsibleset')" +
- ( $.mobile.collapsibleset ? ", :mobile-collapsibleset" :
- "" ) )
- .addClass( "ui-collapsible-set" )
- };
-
- this._ui = ui;
- this._renderedOptions = this._getOptions( this.options );
-
- if ( this.options.enhanced ) {
- ui.heading = $( ".ui-collapsible-heading", this.element[ 0 ] );
- ui.content = ui.heading.next();
- ui.anchor = $( "a", ui.heading[ 0 ] ).first();
- ui.status = ui.anchor.children( ".ui-collapsible-heading-status" );
- } else {
- this._enhance( elem, ui );
- }
-
- this._on( ui.heading, {
- "tap": function() {
- ui.heading.find( "a" ).first().addClass( $.mobile.activeBtnClass );
- },
-
- "click": function( event ) {
- this._handleExpandCollapse( !ui.heading.hasClass( "ui-collapsible-heading-collapsed" ) );
- event.preventDefault();
- event.stopPropagation();
- }
- });
- },
-
- // Adjust the keys inside options for inherited values
- _getOptions: function( options ) {
- var key,
- accordion = this._ui.accordion,
- accordionWidget = this._ui.accordionWidget;
-
- // Copy options
- options = $.extend( {}, options );
-
- if ( accordion.length && !accordionWidget ) {
- this._ui.accordionWidget =
- accordionWidget = accordion.data( "mobile-collapsibleset" );
- }
-
- for ( key in options ) {
-
- // Retrieve the option value first from the options object passed in and, if
- // null, from the parent accordion or, if that's null too, or if there's no
- // parent accordion, then from the defaults.
- options[ key ] =
- ( options[ key ] != null ) ? options[ key ] :
- ( accordionWidget ) ? accordionWidget.options[ key ] :
- accordion.length ? $.mobile.getAttribute( accordion[ 0 ],
- key.replace( rInitialLetter, "-$1" ).toLowerCase() ):
- null;
-
- if ( null == options[ key ] ) {
- options[ key ] = $.mobile.collapsible.defaults[ key ];
- }
- }
-
- return options;
- },
-
- _themeClassFromOption: function( prefix, value ) {
- return ( value ? ( value === "none" ? "" : prefix + value ) : "" );
- },
-
- _enhance: function( elem, ui ) {
- var iconclass,
- opts = this._renderedOptions,
- contentThemeClass = this._themeClassFromOption( "ui-body-", opts.contentTheme );
-
- elem.addClass( "ui-collapsible " +
- ( opts.inset ? "ui-collapsible-inset " : "" ) +
- ( opts.inset && opts.corners ? "ui-corner-all " : "" ) +
- ( contentThemeClass ? "ui-collapsible-themed-content " : "" ) );
- ui.originalHeading = elem.children( this.options.heading ).first(),
- ui.content = elem
- .wrapInner( "<div " +
- "class='ui-collapsible-content " +
- contentThemeClass + "'></div>" )
- .children( ".ui-collapsible-content" ),
- ui.heading = ui.originalHeading;
-
- // Replace collapsibleHeading if it's a legend
- if ( ui.heading.is( "legend" ) ) {
- ui.heading = $( "<div role='heading'>"+ ui.heading.html() +"</div>" );
- ui.placeholder = $( "<div><!-- placeholder for legend --></div>" ).insertBefore( ui.originalHeading );
- ui.originalHeading.remove();
- }
-
- iconclass = ( opts.collapsed ? ( opts.collapsedIcon ? "ui-icon-" + opts.collapsedIcon : "" ):
- ( opts.expandedIcon ? "ui-icon-" + opts.expandedIcon : "" ) );
-
- ui.status = $( "<span class='ui-collapsible-heading-status'></span>" );
- ui.anchor = ui.heading
- .detach()
- //modify markup & attributes
- .addClass( "ui-collapsible-heading" )
- .append( ui.status )
- .wrapInner( "<a href='#' class='ui-collapsible-heading-toggle'></a>" )
- .find( "a" )
- .first()
- .addClass( "ui-btn " +
- ( iconclass ? iconclass + " " : "" ) +
- ( iconclass ? iconposClass( opts.iconpos ) +
- " " : "" ) +
- this._themeClassFromOption( "ui-btn-", opts.theme ) + " " +
- ( opts.mini ? "ui-mini " : "" ) );
-
- //drop heading in before content
- ui.heading.insertBefore( ui.content );
-
- this._handleExpandCollapse( this.options.collapsed );
-
- return ui;
- },
-
- refresh: function() {
- this._applyOptions( this.options );
- this._renderedOptions = this._getOptions( this.options );
- },
-
- _applyOptions: function( options ) {
- var isCollapsed, newTheme, oldTheme, hasCorners, hasIcon,
- elem = this.element,
- currentOpts = this._renderedOptions,
- ui = this._ui,
- anchor = ui.anchor,
- status = ui.status,
- opts = this._getOptions( options );
-
- // First and foremost we need to make sure the collapsible is in the proper
- // state, in case somebody decided to change the collapsed option at the
- // same time as another option
- if ( options.collapsed !== undefined ) {
- this._handleExpandCollapse( options.collapsed );
- }
-
- isCollapsed = elem.hasClass( "ui-collapsible-collapsed" );
-
- // We only need to apply the cue text for the current state right away.
- // The cue text for the alternate state will be stored in the options
- // and applied the next time the collapsible's state is toggled
- if ( isCollapsed ) {
- if ( opts.expandCueText !== undefined ) {
- status.text( opts.expandCueText );
- }
- } else {
- if ( opts.collapseCueText !== undefined ) {
- status.text( opts.collapseCueText );
- }
- }
-
- // Update icon
-
- // Is it supposed to have an icon?
- hasIcon =
-
- // If the collapsedIcon is being set, consult that
- ( opts.collapsedIcon !== undefined ? opts.collapsedIcon !== false :
-
- // Otherwise consult the existing option value
- currentOpts.collapsedIcon !== false );
-
-
- // If any icon-related options have changed, make sure the new icon
- // state is reflected by first removing all icon-related classes
- // reflecting the current state and then adding all icon-related
- // classes for the new state
- if ( !( opts.iconpos === undefined &&
- opts.collapsedIcon === undefined &&
- opts.expandedIcon === undefined ) ) {
-
- // Remove all current icon-related classes
- anchor.removeClass( [ iconposClass( currentOpts.iconpos ) ]
- .concat( ( currentOpts.expandedIcon ?
- [ "ui-icon-" + currentOpts.expandedIcon ] : [] ) )
- .concat( ( currentOpts.collapsedIcon ?
- [ "ui-icon-" + currentOpts.collapsedIcon ] : [] ) )
- .join( " " ) );
-
- // Add new classes if an icon is supposed to be present
- if ( hasIcon ) {
- anchor.addClass(
- [ iconposClass( opts.iconpos !== undefined ?
- opts.iconpos : currentOpts.iconpos ) ]
- .concat( isCollapsed ?
- [ "ui-icon-" + ( opts.collapsedIcon !== undefined ?
- opts.collapsedIcon :
- currentOpts.collapsedIcon ) ] :
- [ "ui-icon-" + ( opts.expandedIcon !== undefined ?
- opts.expandedIcon :
- currentOpts.expandedIcon ) ] )
- .join( " " ) );
- }
- }
-
- if ( opts.theme !== undefined ) {
- oldTheme = this._themeClassFromOption( "ui-btn-", currentOpts.theme );
- newTheme = this._themeClassFromOption( "ui-btn-", opts.theme );
- anchor.removeClass( oldTheme ).addClass( newTheme );
- }
-
- if ( opts.contentTheme !== undefined ) {
- oldTheme = this._themeClassFromOption( "ui-body-",
- currentOpts.contentTheme );
- newTheme = this._themeClassFromOption( "ui-body-",
- opts.contentTheme );
- ui.content.removeClass( oldTheme ).addClass( newTheme );
- }
-
- if ( opts.inset !== undefined ) {
- elem.toggleClass( "ui-collapsible-inset", opts.inset );
- hasCorners = !!( opts.inset && ( opts.corners || currentOpts.corners ) );
- }
-
- if ( opts.corners !== undefined ) {
- hasCorners = !!( opts.corners && ( opts.inset || currentOpts.inset ) );
- }
-
- if ( hasCorners !== undefined ) {
- elem.toggleClass( "ui-corner-all", hasCorners );
- }
-
- if ( opts.mini !== undefined ) {
- anchor.toggleClass( "ui-mini", opts.mini );
- }
- },
-
- _setOptions: function( options ) {
- this._applyOptions( options );
- this._super( options );
- this._renderedOptions = this._getOptions( this.options );
- },
-
- _handleExpandCollapse: function( isCollapse ) {
- var opts = this._renderedOptions,
- ui = this._ui;
-
- ui.status.text( isCollapse ? opts.expandCueText : opts.collapseCueText );
- ui.heading
- .toggleClass( "ui-collapsible-heading-collapsed", isCollapse )
- .find( "a" ).first()
- .toggleClass( "ui-icon-" + opts.expandedIcon, !isCollapse )
-
- // logic or cause same icon for expanded/collapsed state would remove the ui-icon-class
- .toggleClass( "ui-icon-" + opts.collapsedIcon, ( isCollapse || opts.expandedIcon === opts.collapsedIcon ) )
- .removeClass( $.mobile.activeBtnClass );
-
- this.element.toggleClass( "ui-collapsible-collapsed", isCollapse );
- ui.content
- .toggleClass( "ui-collapsible-content-collapsed", isCollapse )
- .attr( "aria-hidden", isCollapse )
- .trigger( "updatelayout" );
- this.options.collapsed = isCollapse;
- this._trigger( isCollapse ? "collapse" : "expand" );
- },
-
- expand: function() {
- this._handleExpandCollapse( false );
- },
-
- collapse: function() {
- this._handleExpandCollapse( true );
- },
-
- _destroy: function() {
- var ui = this._ui,
- opts = this.options;
-
- if ( opts.enhanced ) {
- return;
- }
-
- if ( ui.placeholder ) {
- ui.originalHeading.insertBefore( ui.placeholder );
- ui.placeholder.remove();
- ui.heading.remove();
- } else {
- ui.status.remove();
- ui.heading
- .removeClass( "ui-collapsible-heading ui-collapsible-heading-collapsed" )
- .children()
- .contents()
- .unwrap();
- }
-
- ui.anchor.contents().unwrap();
- ui.content.contents().unwrap();
- this.element
- .removeClass( "ui-collapsible ui-collapsible-collapsed " +
- "ui-collapsible-themed-content ui-collapsible-inset ui-corner-all" );
- }
-});
-
-// Defaults to be used by all instances of collapsible if per-instance values
-// are unset or if nothing is specified by way of inheritance from an accordion.
-// Note that this hash does not contain options "collapsed" or "heading",
-// because those are not inheritable.
-$.mobile.collapsible.defaults = {
- expandCueText: " click to expand contents",
- collapseCueText: " click to collapse contents",
- collapsedIcon: "plus",
- contentTheme: "inherit",
- expandedIcon: "minus",
- iconpos: "left",
- inset: true,
- corners: true,
- theme: "inherit",
- mini: false
-};
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.mobile.behaviors.addFirstLastClasses = {
- _getVisibles: function( $els, create ) {
- var visibles;
-
- if ( create ) {
- visibles = $els.not( ".ui-screen-hidden" );
- } else {
- visibles = $els.filter( ":visible" );
- if ( visibles.length === 0 ) {
- visibles = $els.not( ".ui-screen-hidden" );
- }
- }
-
- return visibles;
- },
-
- _addFirstLastClasses: function( $els, $visibles, create ) {
- $els.removeClass( "ui-first-child ui-last-child" );
- $visibles.eq( 0 ).addClass( "ui-first-child" ).end().last().addClass( "ui-last-child" );
- if ( !create ) {
- this.element.trigger( "updatelayout" );
- }
- },
-
- _removeFirstLastClasses: function( $els ) {
- $els.removeClass( "ui-first-child ui-last-child" );
- }
-};
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-var childCollapsiblesSelector = ":mobile-collapsible, " + $.mobile.collapsible.initSelector;
-
-$.widget( "mobile.collapsibleset", $.extend( {
-
- // The initSelector is deprecated as of 1.4.0. In 1.5.0 we will use
- // :jqmData(role='collapsibleset') which will allow us to get rid of the line
- // below altogether, because the autoinit will generate such an initSelector
- initSelector: ":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')",
-
- options: $.extend( {
- enhanced: false
- }, $.mobile.collapsible.defaults ),
-
- _handleCollapsibleExpand: function( event ) {
- var closestCollapsible = $( event.target ).closest( ".ui-collapsible" );
-
- if ( closestCollapsible.parent().is( ":mobile-collapsibleset, :jqmData(role='collapsible-set')" ) ) {
- closestCollapsible
- .siblings( ".ui-collapsible:not(.ui-collapsible-collapsed)" )
- .collapsible( "collapse" );
- }
- },
-
- _create: function() {
- var elem = this.element,
- opts = this.options;
-
- $.extend( this, {
- _classes: ""
- });
-
- if ( !opts.enhanced ) {
- elem.addClass( "ui-collapsible-set " +
- this._themeClassFromOption( "ui-group-theme-", opts.theme ) + " " +
- ( opts.corners && opts.inset ? "ui-corner-all " : "" ) );
- this.element.find( $.mobile.collapsible.initSelector ).collapsible();
- }
-
- this._on( elem, { collapsibleexpand: "_handleCollapsibleExpand" } );
- },
-
- _themeClassFromOption: function( prefix, value ) {
- return ( value ? ( value === "none" ? "" : prefix + value ) : "" );
- },
-
- _init: function() {
- this._refresh( true );
-
- // Because the corners are handled by the collapsible itself and the default state is collapsed
- // That was causing https://github.com/jquery/jquery-mobile/issues/4116
- this.element
- .children( childCollapsiblesSelector )
- .filter( ":jqmData(collapsed='false')" )
- .collapsible( "expand" );
- },
-
- _setOptions: function( options ) {
- var ret, hasCorners,
- elem = this.element,
- themeClass = this._themeClassFromOption( "ui-group-theme-", options.theme );
-
- if ( themeClass ) {
- elem
- .removeClass( this._themeClassFromOption( "ui-group-theme-", this.options.theme ) )
- .addClass( themeClass );
- }
-
- if ( options.inset !== undefined ) {
- hasCorners = !!( options.inset && ( options.corners || this.options.corners ) );
- }
-
- if ( options.corners !== undefined ) {
- hasCorners = !!( options.corners && ( options.inset || this.options.inset ) );
- }
-
- if ( hasCorners !== undefined ) {
- elem.toggleClass( "ui-corner-all", hasCorners );
- }
-
- ret = this._super( options );
- this.element.children( ":mobile-collapsible" ).collapsible( "refresh" );
- return ret;
- },
-
- _destroy: function() {
- var el = this.element;
-
- this._removeFirstLastClasses( el.children( childCollapsiblesSelector ) );
- el
- .removeClass( "ui-collapsible-set ui-corner-all " +
- this._themeClassFromOption( "ui-group-theme-", this.options.theme ) )
- .children( ":mobile-collapsible" )
- .collapsible( "destroy" );
- },
-
- _refresh: function( create ) {
- var collapsiblesInSet = this.element.children( childCollapsiblesSelector );
-
- this.element.find( $.mobile.collapsible.initSelector ).not( ".ui-collapsible" ).collapsible();
-
- this._addFirstLastClasses( collapsiblesInSet, this._getVisibles( collapsiblesInSet, create ), create );
- },
-
- refresh: function() {
- this._refresh( false );
- }
-}, $.mobile.behaviors.addFirstLastClasses ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-// Deprecated in 1.4
-$.fn.fieldcontain = function(/* options */) {
- return this.addClass( "ui-field-contain" );
-};
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.fn.grid = function( options ) {
- return this.each(function() {
-
- var $this = $( this ),
- o = $.extend({
- grid: null
- }, options ),
- $kids = $this.children(),
- gridCols = { solo:1, a:2, b:3, c:4, d:5 },
- grid = o.grid,
- iterator,
- letter;
-
- if ( !grid ) {
- if ( $kids.length <= 5 ) {
- for ( letter in gridCols ) {
- if ( gridCols[ letter ] === $kids.length ) {
- grid = letter;
- }
- }
- } else {
- grid = "a";
- $this.addClass( "ui-grid-duo" );
- }
- }
- iterator = gridCols[grid];
-
- $this.addClass( "ui-grid-" + grid );
-
- $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );
-
- if ( iterator > 1 ) {
- $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
- }
- if ( iterator > 2 ) {
- $kids.filter( ":nth-child(" + iterator + "n+3)" ).addClass( "ui-block-c" );
- }
- if ( iterator > 3 ) {
- $kids.filter( ":nth-child(" + iterator + "n+4)" ).addClass( "ui-block-d" );
- }
- if ( iterator > 4 ) {
- $kids.filter( ":nth-child(" + iterator + "n+5)" ).addClass( "ui-block-e" );
- }
- });
-};
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.navbar", {
- options: {
- iconpos: "top",
- grid: null
- },
-
- _create: function() {
-
- var $navbar = this.element,
- $navbtns = $navbar.find( "a" ),
- iconpos = $navbtns.filter( ":jqmData(icon)" ).length ? this.options.iconpos : undefined;
-
- $navbar.addClass( "ui-navbar" )
- .attr( "role", "navigation" )
- .find( "ul" )
- .jqmEnhanceable()
- .grid({ grid: this.options.grid });
-
- $navbtns
- .each( function() {
- var icon = $.mobile.getAttribute( this, "icon" ),
- theme = $.mobile.getAttribute( this, "theme" ),
- classes = "ui-btn";
-
- if ( theme ) {
- classes += " ui-btn-" + theme;
- }
- if ( icon ) {
- classes += " ui-icon-" + icon + " ui-btn-icon-" + iconpos;
- }
- $( this ).addClass( classes );
- });
-
- $navbar.delegate( "a", "vclick", function( /* event */ ) {
- var activeBtn = $( this );
-
- if ( !( activeBtn.hasClass( "ui-state-disabled" ) ||
-
- // DEPRECATED as of 1.4.0 - remove after 1.4.0 release
- // only ui-state-disabled should be present thereafter
- activeBtn.hasClass( "ui-disabled" ) ||
- activeBtn.hasClass( $.mobile.activeBtnClass ) ) ) {
-
- $navbtns.removeClass( $.mobile.activeBtnClass );
- activeBtn.addClass( $.mobile.activeBtnClass );
-
- // The code below is a workaround to fix #1181
- $( document ).one( "pagehide", function() {
- activeBtn.removeClass( $.mobile.activeBtnClass );
- });
- }
- });
-
- // Buttons in the navbar with ui-state-persist class should regain their active state before page show
- $navbar.closest( ".ui-page" ).bind( "pagebeforeshow", function() {
- $navbtns.filter( ".ui-state-persist" ).addClass( $.mobile.activeBtnClass );
- });
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-var getAttr = $.mobile.getAttribute;
-
-$.widget( "mobile.listview", $.extend( {
-
- options: {
- theme: null,
- countTheme: null, /* Deprecated in 1.4 */
- dividerTheme: null,
- icon: "carat-r",
- splitIcon: "carat-r",
- splitTheme: null,
- corners: true,
- shadow: true,
- inset: false
- },
-
- _create: function() {
- var t = this,
- listviewClasses = "";
-
- listviewClasses += t.options.inset ? " ui-listview-inset" : "";
-
- if ( !!t.options.inset ) {
- listviewClasses += t.options.corners ? " ui-corner-all" : "";
- listviewClasses += t.options.shadow ? " ui-shadow" : "";
- }
-
- // create listview markup
- t.element.addClass( " ui-listview" + listviewClasses );
-
- t.refresh( true );
- },
-
- // TODO: Remove in 1.5
- _findFirstElementByTagName: function( ele, nextProp, lcName, ucName ) {
- var dict = {};
- dict[ lcName ] = dict[ ucName ] = true;
- while ( ele ) {
- if ( dict[ ele.nodeName ] ) {
- return ele;
- }
- ele = ele[ nextProp ];
- }
- return null;
- },
- // TODO: Remove in 1.5
- _addThumbClasses: function( containers ) {
- var i, img, len = containers.length;
- for ( i = 0; i < len; i++ ) {
- img = $( this._findFirstElementByTagName( containers[ i ].firstChild, "nextSibling", "img", "IMG" ) );
- if ( img.length ) {
- $( this._findFirstElementByTagName( img[ 0 ].parentNode, "parentNode", "li", "LI" ) ).addClass( img.hasClass( "ui-li-icon" ) ? "ui-li-has-icon" : "ui-li-has-thumb" );
- }
- }
- },
-
- _getChildrenByTagName: function( ele, lcName, ucName ) {
- var results = [],
- dict = {};
- dict[ lcName ] = dict[ ucName ] = true;
- ele = ele.firstChild;
- while ( ele ) {
- if ( dict[ ele.nodeName ] ) {
- results.push( ele );
- }
- ele = ele.nextSibling;
- }
- return $( results );
- },
-
- _beforeListviewRefresh: $.noop,
- _afterListviewRefresh: $.noop,
-
- refresh: function( create ) {
- var buttonClass, pos, numli, item, itemClass, itemTheme, itemIcon, icon, a,
- isDivider, startCount, newStartCount, value, last, splittheme, splitThemeClass, spliticon,
- altButtonClass, dividerTheme, li,
- o = this.options,
- $list = this.element,
- ol = !!$.nodeName( $list[ 0 ], "ol" ),
- start = $list.attr( "start" ),
- itemClassDict = {},
- countBubbles = $list.find( ".ui-li-count" ),
- countTheme = getAttr( $list[ 0 ], "counttheme" ) || this.options.countTheme,
- countThemeClass = countTheme ? "ui-body-" + countTheme : "ui-body-inherit";
-
- if ( o.theme ) {
- $list.addClass( "ui-group-theme-" + o.theme );
- }
-
- // Check if a start attribute has been set while taking a value of 0 into account
- if ( ol && ( start || start === 0 ) ) {
- startCount = parseInt( start, 10 ) - 1;
- $list.css( "counter-reset", "listnumbering " + startCount );
- }
-
- this._beforeListviewRefresh();
-
- li = this._getChildrenByTagName( $list[ 0 ], "li", "LI" );
-
- for ( pos = 0, numli = li.length; pos < numli; pos++ ) {
- item = li.eq( pos );
- itemClass = "";
-
- if ( create || item[ 0 ].className.search( /\bui-li-static\b|\bui-li-divider\b/ ) < 0 ) {
- a = this._getChildrenByTagName( item[ 0 ], "a", "A" );
- isDivider = ( getAttr( item[ 0 ], "role" ) === "list-divider" );
- value = item.attr( "value" );
- itemTheme = getAttr( item[ 0 ], "theme" );
-
- if ( a.length && a[ 0 ].className.search( /\bui-btn\b/ ) < 0 && !isDivider ) {
- itemIcon = getAttr( item[ 0 ], "icon" );
- icon = ( itemIcon === false ) ? false : ( itemIcon || o.icon );
-
- // TODO: Remove in 1.5 together with links.js (links.js / .ui-link deprecated in 1.4)
- a.removeClass( "ui-link" );
-
- buttonClass = "ui-btn";
-
- if ( itemTheme ) {
- buttonClass += " ui-btn-" + itemTheme;
- }
-
- if ( a.length > 1 ) {
- itemClass = "ui-li-has-alt";
-
- last = a.last();
- splittheme = getAttr( last[ 0 ], "theme" ) || o.splitTheme || getAttr( item[ 0 ], "theme", true );
- splitThemeClass = splittheme ? " ui-btn-" + splittheme : "";
- spliticon = getAttr( last[ 0 ], "icon" ) || getAttr( item[ 0 ], "icon" ) || o.splitIcon;
- altButtonClass = "ui-btn ui-btn-icon-notext ui-icon-" + spliticon + splitThemeClass;
-
- last
- .attr( "title", $.trim( last.getEncodedText() ) )
- .addClass( altButtonClass )
- .empty();
- } else if ( icon ) {
- buttonClass += " ui-btn-icon-right ui-icon-" + icon;
- }
-
- a.first().addClass( buttonClass );
- } else if ( isDivider ) {
- dividerTheme = ( getAttr( item[ 0 ], "theme" ) || o.dividerTheme || o.theme );
-
- itemClass = "ui-li-divider ui-bar-" + ( dividerTheme ? dividerTheme : "inherit" );
-
- item.attr( "role", "heading" );
- } else if ( a.length <= 0 ) {
- itemClass = "ui-li-static ui-body-" + ( itemTheme ? itemTheme : "inherit" );
- }
- if ( ol && value ) {
- newStartCount = parseInt( value , 10 ) - 1;
-
- item.css( "counter-reset", "listnumbering " + newStartCount );
- }
- }
-
- // Instead of setting item class directly on the list item
- // at this point in time, push the item into a dictionary
- // that tells us what class to set on it so we can do this after this
- // processing loop is finished.
-
- if ( !itemClassDict[ itemClass ] ) {
- itemClassDict[ itemClass ] = [];
- }
-
- itemClassDict[ itemClass ].push( item[ 0 ] );
- }
-
- // Set the appropriate listview item classes on each list item.
- // The main reason we didn't do this
- // in the for-loop above is because we can eliminate per-item function overhead
- // by calling addClass() and children() once or twice afterwards. This
- // can give us a significant boost on platforms like WP7.5.
-
- for ( itemClass in itemClassDict ) {
- $( itemClassDict[ itemClass ] ).addClass( itemClass );
- }
-
- countBubbles.each( function() {
- $( this ).closest( "li" ).addClass( "ui-li-has-count" );
- });
- if ( countThemeClass ) {
- countBubbles.addClass( countThemeClass );
- }
-
- // Deprecated in 1.4. From 1.5 you have to add class ui-li-has-thumb or ui-li-has-icon to the LI.
- this._addThumbClasses( li );
- this._addThumbClasses( li.find( ".ui-btn" ) );
-
- this._afterListviewRefresh();
-
- this._addFirstLastClasses( li, this._getVisibles( li, create ), create );
- }
-}, $.mobile.behaviors.addFirstLastClasses ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-function defaultAutodividersSelector( elt ) {
- // look for the text in the given element
- var text = $.trim( elt.text() ) || null;
-
- if ( !text ) {
- return null;
- }
-
- // create the text for the divider (first uppercased letter)
- text = text.slice( 0, 1 ).toUpperCase();
-
- return text;
-}
-
-$.widget( "mobile.listview", $.mobile.listview, {
- options: {
- autodividers: false,
- autodividersSelector: defaultAutodividersSelector
- },
-
- _beforeListviewRefresh: function() {
- if ( this.options.autodividers ) {
- this._replaceDividers();
- this._superApply( arguments );
- }
- },
-
- _replaceDividers: function() {
- var i, lis, li, dividerText,
- lastDividerText = null,
- list = this.element,
- divider;
-
- list.children( "li:jqmData(role='list-divider')" ).remove();
-
- lis = list.children( "li" );
-
- for ( i = 0; i < lis.length ; i++ ) {
- li = lis[ i ];
- dividerText = this.options.autodividersSelector( $( li ) );
-
- if ( dividerText && lastDividerText !== dividerText ) {
- divider = document.createElement( "li" );
- divider.appendChild( document.createTextNode( dividerText ) );
- divider.setAttribute( "data-" + $.mobile.ns + "role", "list-divider" );
- li.parentNode.insertBefore( divider, li );
- }
-
- lastDividerText = dividerText;
- }
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-var rdivider = /(^|\s)ui-li-divider($|\s)/,
- rhidden = /(^|\s)ui-screen-hidden($|\s)/;
-
-$.widget( "mobile.listview", $.mobile.listview, {
- options: {
- hideDividers: false
- },
-
- _afterListviewRefresh: function() {
- var items, idx, item, hideDivider = true;
-
- this._superApply( arguments );
-
- if ( this.options.hideDividers ) {
- items = this._getChildrenByTagName( this.element[ 0 ], "li", "LI" );
- for ( idx = items.length - 1 ; idx > -1 ; idx-- ) {
- item = items[ idx ];
- if ( item.className.match( rdivider ) ) {
- if ( hideDivider ) {
- item.className = item.className + " ui-screen-hidden";
- }
- hideDivider = true;
- } else {
- if ( !item.className.match( rhidden ) ) {
- hideDivider = false;
- }
- }
- }
- }
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.mobile.nojs = function( target ) {
- $( ":jqmData(role='nojs')", target ).addClass( "ui-nojs" );
-};
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.mobile.behaviors.formReset = {
- _handleFormReset: function() {
- this._on( this.element.closest( "form" ), {
- reset: function() {
- this._delay( "_reset" );
- }
- });
- }
-};
-
-})( jQuery );
-
-/*
-* "checkboxradio" plugin
-*/
-
-(function( $, undefined ) {
-
-var escapeId = $.mobile.path.hashToSelector;
-
-$.widget( "mobile.checkboxradio", $.extend( {
-
- initSelector: "input:not( :jqmData(role='flipswitch' ) )[type='checkbox'],input[type='radio']:not( :jqmData(role='flipswitch' ))",
-
- options: {
- theme: "inherit",
- mini: false,
- wrapperClass: null,
- enhanced: false,
- iconpos: "left"
-
- },
- _create: function() {
- var input = this.element,
- o = this.options,
- inheritAttr = function( input, dataAttr ) {
- return input.jqmData( dataAttr ) ||
- input.closest( "form, fieldset" ).jqmData( dataAttr );
- },
- // NOTE: Windows Phone could not find the label through a selector
- // filter works though.
- parentLabel = input.closest( "label" ),
- label = parentLabel.length ? parentLabel :
- input
- .closest( "form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')" )
- .find( "label" )
- .filter( "[for='" + escapeId( input[0].id ) + "']" )
- .first(),
- inputtype = input[0].type,
- checkedClass = "ui-" + inputtype + "-on",
- uncheckedClass = "ui-" + inputtype + "-off";
-
- if ( inputtype !== "checkbox" && inputtype !== "radio" ) {
- return;
- }
-
- if ( this.element[0].disabled ) {
- this.options.disabled = true;
- }
-
- o.iconpos = inheritAttr( input, "iconpos" ) || label.attr( "data-" + $.mobile.ns + "iconpos" ) || o.iconpos,
-
- // Establish options
- o.mini = inheritAttr( input, "mini" ) || o.mini;
-
- // Expose for other methods
- $.extend( this, {
- input: input,
- label: label,
- parentLabel: parentLabel,
- inputtype: inputtype,
- checkedClass: checkedClass,
- uncheckedClass: uncheckedClass
- });
-
- if ( !this.options.enhanced ) {
- this._enhance();
- }
-
- this._on( label, {
- vmouseover: "_handleLabelVMouseOver",
- vclick: "_handleLabelVClick"
- });
-
- this._on( input, {
- vmousedown: "_cacheVals",
- vclick: "_handleInputVClick",
- focus: "_handleInputFocus",
- blur: "_handleInputBlur"
- });
-
- this._handleFormReset();
- this.refresh();
- },
-
- _enhance: function() {
- this.label.addClass( "ui-btn ui-corner-all");
-
- if ( this.parentLabel.length > 0 ) {
- this.input.add( this.label ).wrapAll( this._wrapper() );
- } else {
- //this.element.replaceWith( this.input.add( this.label ).wrapAll( this._wrapper() ) );
- this.element.wrap( this._wrapper() );
- this.element.parent().prepend( this.label );
- }
-
- // Wrap the input + label in a div
-
- this._setOptions({
- "theme": this.options.theme,
- "iconpos": this.options.iconpos,
- "mini": this.options.mini
- });
-
- },
-
- _wrapper: function() {
- return $( "<div class='" +
- ( this.options.wrapperClass ? this.options.wrapperClass : "" ) +
- " ui-" + this.inputtype +
- ( this.options.disabled ? " ui-state-disabled" : "" ) + "' ></div>" );
- },
-
- _handleInputFocus: function() {
- this.label.addClass( $.mobile.focusClass );
- },
-
- _handleInputBlur: function() {
- this.label.removeClass( $.mobile.focusClass );
- },
-
- _handleInputVClick: function() {
- // Adds checked attribute to checked input when keyboard is used
- this.element.prop( "checked", this.element.is( ":checked" ) );
- this._getInputSet().not( this.element ).prop( "checked", false );
- this._updateAll();
- },
-
- _handleLabelVMouseOver: function( event ) {
- if ( this.label.parent().hasClass( "ui-state-disabled" ) ) {
- event.stopPropagation();
- }
- },
-
- _handleLabelVClick: function( event ) {
- var input = this.element;
-
- if ( input.is( ":disabled" ) ) {
- event.preventDefault();
- return;
- }
-
- this._cacheVals();
-
- input.prop( "checked", this.inputtype === "radio" && true || !input.prop( "checked" ) );
-
- // trigger click handler's bound directly to the input as a substitute for
- // how label clicks behave normally in the browsers
- // TODO: it would be nice to let the browser's handle the clicks and pass them
- // through to the associate input. we can swallow that click at the parent
- // wrapper element level
- input.triggerHandler( "click" );
-
- // Input set for common radio buttons will contain all the radio
- // buttons, but will not for checkboxes. clearing the checked status
- // of other radios ensures the active button state is applied properly
- this._getInputSet().not( input ).prop( "checked", false );
-
- this._updateAll();
- return false;
- },
-
- _cacheVals: function() {
- this._getInputSet().each( function() {
- $( this ).attr("data-" + $.mobile.ns + "cacheVal", this.checked );
- });
- },
-
- // Returns those radio buttons that are supposed to be in the same group as
- // this radio button. In the case of a checkbox or a radio lacking a name
- // attribute, it returns this.element.
- _getInputSet: function() {
- var selector, formId,
- radio = this.element[ 0 ],
- name = radio.name,
- form = radio.form,
- doc = this.element.parents().last().get( 0 ),
-
- // A radio is always a member of its own group
- radios = this.element;
-
- // Only start running selectors if this is an attached radio button with a name
- if ( name && this.inputtype === "radio" && doc ) {
- selector = "input[type='radio'][name='" + escapeId( name ) + "']";
-
- // If we're inside a form
- if ( form ) {
- formId = form.id;
-
- // If the form has an ID, collect radios scattered throught the document which
- // nevertheless are part of the form by way of the value of their form attribute
- if ( formId ) {
- radios = $( selector + "[form='" + escapeId( formId ) + "']", doc );
- }
-
- // Also add to those the radios in the form itself
- radios = $( form ).find( selector ).filter( function() {
-
- // Some radios inside the form may belong to some other form by virtue of
- // having a form attribute defined on them, so we must filter them out here
- return ( this.form === form );
- }).add( radios );
-
- // If we're outside a form
- } else {
-
- // Collect all those radios which are also outside of a form and match our name
- radios = $( selector, doc ).filter( function() {
- return !this.form;
- });
- }
- }
- return radios;
- },
-
- _updateAll: function() {
- var self = this;
-
- this._getInputSet().each( function() {
- var $this = $( this );
-
- if ( this.checked || self.inputtype === "checkbox" ) {
- $this.trigger( "change" );
- }
- })
- .checkboxradio( "refresh" );
- },
-
- _reset: function() {
- this.refresh();
- },
-
- // Is the widget supposed to display an icon?
- _hasIcon: function() {
- var controlgroup, controlgroupWidget,
- controlgroupConstructor = $.mobile.controlgroup;
-
- // If the controlgroup widget is defined ...
- if ( controlgroupConstructor ) {
- controlgroup = this.element.closest(
- ":mobile-controlgroup," +
- controlgroupConstructor.prototype.initSelector );
-
- // ... and the checkbox is in a controlgroup ...
- if ( controlgroup.length > 0 ) {
-
- // ... look for a controlgroup widget instance, and ...
- controlgroupWidget = $.data( controlgroup[ 0 ], "mobile-controlgroup" );
-
- // ... if found, decide based on the option value, ...
- return ( ( controlgroupWidget ? controlgroupWidget.options.type :
-
- // ... otherwise decide based on the "type" data attribute.
- controlgroup.attr( "data-" + $.mobile.ns + "type" ) ) !== "horizontal" );
- }
- }
-
- // Normally, the widget displays an icon.
- return true;
- },
-
- refresh: function() {
- var hasIcon = this._hasIcon(),
- isChecked = this.element[ 0 ].checked,
- active = $.mobile.activeBtnClass,
- iconposClass = "ui-btn-icon-" + this.options.iconpos,
- addClasses = [],
- removeClasses = [];
-
- if ( hasIcon ) {
- removeClasses.push( active );
- addClasses.push( iconposClass );
- } else {
- removeClasses.push( iconposClass );
- ( isChecked ? addClasses : removeClasses ).push( active );
- }
-
- if ( isChecked ) {
- addClasses.push( this.checkedClass );
- removeClasses.push( this.uncheckedClass );
- } else {
- addClasses.push( this.uncheckedClass );
- removeClasses.push( this.checkedClass );
- }
-
- this.label
- .addClass( addClasses.join( " " ) )
- .removeClass( removeClasses.join( " " ) );
- },
-
- widget: function() {
- return this.label.parent();
- },
-
- _setOptions: function( options ) {
- var label = this.label,
- currentOptions = this.options,
- outer = this.widget(),
- hasIcon = this._hasIcon();
-
- if ( options.disabled !== undefined ) {
- this.input.prop( "disabled", !!options.disabled );
- outer.toggleClass( "ui-state-disabled", !!options.disabled );
- }
- if ( options.mini !== undefined ) {
- outer.toggleClass( "ui-mini", !!options.mini );
- }
- if ( options.theme !== undefined ) {
- label
- .removeClass( "ui-btn-" + currentOptions.theme )
- .addClass( "ui-btn-" + options.theme );
- }
- if ( options.wrapperClass !== undefined ) {
- outer
- .removeClass( currentOptions.wrapperClass )
- .addClass( options.wrapperClass );
- }
- if ( options.iconpos !== undefined && hasIcon ) {
- label.removeClass( "ui-btn-icon-" + currentOptions.iconpos ).addClass( "ui-btn-icon-" + options.iconpos );
- } else if ( !hasIcon ) {
- label.removeClass( "ui-btn-icon-" + currentOptions.iconpos );
- }
- this._super( options );
- }
-
-}, $.mobile.behaviors.formReset ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.button", {
-
- initSelector: "input[type='button'], input[type='submit'], input[type='reset']",
-
- options: {
- theme: null,
- icon: null,
- iconpos: "left",
- iconshadow: false, /* TODO: Deprecated in 1.4, remove in 1.5. */
- corners: true,
- shadow: true,
- inline: null,
- mini: null,
- wrapperClass: null,
- enhanced: false
- },
-
- _create: function() {
-
- if ( this.element.is( ":disabled" ) ) {
- this.options.disabled = true;
- }
-
- if ( !this.options.enhanced ) {
- this._enhance();
- }
-
- $.extend( this, {
- wrapper: this.element.parent()
- });
-
- this._on( {
- focus: function() {
- this.widget().addClass( $.mobile.focusClass );
- },
-
- blur: function() {
- this.widget().removeClass( $.mobile.focusClass );
- }
- });
-
- this.refresh( true );
- },
-
- _enhance: function() {
- this.element.wrap( this._button() );
- },
-
- _button: function() {
- var options = this.options,
- iconClasses = this._getIconClasses( this.options );
-
- return $("<div class='ui-btn ui-input-btn" +
- ( options.wrapperClass ? " " + options.wrapperClass : "" ) +
- ( options.theme ? " ui-btn-" + options.theme : "" ) +
- ( options.corners ? " ui-corner-all" : "" ) +
- ( options.shadow ? " ui-shadow" : "" ) +
- ( options.inline ? " ui-btn-inline" : "" ) +
- ( options.mini ? " ui-mini" : "" ) +
- ( options.disabled ? " ui-state-disabled" : "" ) +
- ( iconClasses ? ( " " + iconClasses ) : "" ) +
- "' >" + this.element.val() + "</div>" );
- },
-
- widget: function() {
- return this.wrapper;
- },
-
- _destroy: function() {
- this.element.insertBefore( this.button );
- this.button.remove();
- },
-
- _getIconClasses: function( options ) {
- return ( options.icon ? ( "ui-icon-" + options.icon +
- ( options.iconshadow ? " ui-shadow-icon" : "" ) + /* TODO: Deprecated in 1.4, remove in 1.5. */
- " ui-btn-icon-" + options.iconpos ) : "" );
- },
-
- _setOptions: function( options ) {
- var outer = this.widget();
-
- if ( options.theme !== undefined ) {
- outer
- .removeClass( this.options.theme )
- .addClass( "ui-btn-" + options.theme );
- }
- if ( options.corners !== undefined ) {
- outer.toggleClass( "ui-corner-all", options.corners );
- }
- if ( options.shadow !== undefined ) {
- outer.toggleClass( "ui-shadow", options.shadow );
- }
- if ( options.inline !== undefined ) {
- outer.toggleClass( "ui-btn-inline", options.inline );
- }
- if ( options.mini !== undefined ) {
- outer.toggleClass( "ui-mini", options.mini );
- }
- if ( options.disabled !== undefined ) {
- this.element.prop( "disabled", options.disabled );
- outer.toggleClass( "ui-state-disabled", options.disabled );
- }
-
- if ( options.icon !== undefined ||
- options.iconshadow !== undefined || /* TODO: Deprecated in 1.4, remove in 1.5. */
- options.iconpos !== undefined ) {
- outer
- .removeClass( this._getIconClasses( this.options ) )
- .addClass( this._getIconClasses(
- $.extend( {}, this.options, options ) ) );
- }
-
- this._super( options );
- },
-
- refresh: function( create ) {
- var originalElement,
- isDisabled = this.element.prop( "disabled" );
-
- if ( this.options.icon && this.options.iconpos === "notext" && this.element.attr( "title" ) ) {
- this.element.attr( "title", this.element.val() );
- }
- if ( !create ) {
- originalElement = this.element.detach();
- $( this.wrapper ).text( this.element.val() ).append( originalElement );
- }
- if ( this.options.disabled !== isDisabled ) {
- this._setOptions({ disabled: isDisabled });
- }
- }
-});
-
-})( jQuery );
-
-(function( $ ) {
- var meta = $( "meta[name=viewport]" ),
- initialContent = meta.attr( "content" ),
- disabledZoom = initialContent + ",maximum-scale=1, user-scalable=no",
- enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes",
- disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test( initialContent );
-
- $.mobile.zoom = $.extend( {}, {
- enabled: !disabledInitially,
- locked: false,
- disable: function( lock ) {
- if ( !disabledInitially && !$.mobile.zoom.locked ) {
- meta.attr( "content", disabledZoom );
- $.mobile.zoom.enabled = false;
- $.mobile.zoom.locked = lock || false;
- }
- },
- enable: function( unlock ) {
- if ( !disabledInitially && ( !$.mobile.zoom.locked || unlock === true ) ) {
- meta.attr( "content", enabledZoom );
- $.mobile.zoom.enabled = true;
- $.mobile.zoom.locked = false;
- }
- },
- restore: function() {
- if ( !disabledInitially ) {
- meta.attr( "content", initialContent );
- $.mobile.zoom.enabled = true;
- }
- }
- });
-
-}( jQuery ));
-
-(function( $, undefined ) {
-
-$.widget( "mobile.textinput", {
- initSelector: "input[type='text']," +
- "input[type='search']," +
- ":jqmData(type='search')," +
- "input[type='number']," +
- ":jqmData(type='number')," +
- "input[type='password']," +
- "input[type='email']," +
- "input[type='url']," +
- "input[type='tel']," +
- "textarea," +
- "input[type='time']," +
- "input[type='date']," +
- "input[type='month']," +
- "input[type='week']," +
- "input[type='datetime']," +
- "input[type='datetime-local']," +
- "input[type='color']," +
- "input:not([type])," +
- "input[type='file']",
-
- options: {
- theme: null,
- corners: true,
- mini: false,
- // This option defaults to true on iOS devices.
- preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
- wrapperClass: "",
- enhanced: false
- },
-
- _create: function() {
-
- var options = this.options,
- isSearch = this.element.is( "[type='search'], :jqmData(type='search')" ),
- isTextarea = this.element[ 0 ].tagName === "TEXTAREA",
- isRange = this.element.is( "[data-" + ( $.mobile.ns || "" ) + "type='range']" ),
- inputNeedsWrap = ( (this.element.is( "input" ) ||
- this.element.is( "[data-" + ( $.mobile.ns || "" ) + "type='search']" ) ) &&
- !isRange );
-
- if ( this.element.prop( "disabled" ) ) {
- options.disabled = true;
- }
-
- $.extend( this, {
- classes: this._classesFromOptions(),
- isSearch: isSearch,
- isTextarea: isTextarea,
- isRange: isRange,
- inputNeedsWrap: inputNeedsWrap
- });
-
- this._autoCorrect();
-
- if ( !options.enhanced ) {
- this._enhance();
- }
-
- this._on( {
- "focus": "_handleFocus",
- "blur": "_handleBlur"
- });
-
- },
-
- refresh: function() {
- this.setOptions({
- "disabled" : this.element.is( ":disabled" )
- });
- },
-
- _enhance: function() {
- var elementClasses = [];
-
- if ( this.isTextarea ) {
- elementClasses.push( "ui-input-text" );
- }
-
- if ( this.isTextarea || this.isRange ) {
- elementClasses.push( "ui-shadow-inset" );
- }
-
- //"search" and "text" input widgets
- if ( this.inputNeedsWrap ) {
- this.element.wrap( this._wrap() );
- } else {
- elementClasses = elementClasses.concat( this.classes );
- }
-
- this.element.addClass( elementClasses.join( " " ) );
- },
-
- widget: function() {
- return ( this.inputNeedsWrap ) ? this.element.parent() : this.element;
- },
-
- _classesFromOptions: function() {
- var options = this.options,
- classes = [];
-
- classes.push( "ui-body-" + ( ( options.theme === null ) ? "inherit" : options.theme ) );
- if ( options.corners ) {
- classes.push( "ui-corner-all" );
- }
- if ( options.mini ) {
- classes.push( "ui-mini" );
- }
- if ( options.disabled ) {
- classes.push( "ui-state-disabled" );
- }
- if ( options.wrapperClass ) {
- classes.push( options.wrapperClass );
- }
-
- return classes;
- },
-
- _wrap: function() {
- return $( "<div class='" +
- ( this.isSearch ? "ui-input-search " : "ui-input-text " ) +
- this.classes.join( " " ) + " " +
- "ui-shadow-inset'></div>" );
- },
-
- _autoCorrect: function() {
- // XXX: Temporary workaround for issue 785 (Apple bug 8910589).
- // Turn off autocorrect and autocomplete on non-iOS 5 devices
- // since the popup they use can't be dismissed by the user. Note
- // that we test for the presence of the feature by looking for
- // the autocorrect property on the input element. We currently
- // have no test for iOS 5 or newer so we're temporarily using
- // the touchOverflow support flag for jQM 1.0. Yes, I feel dirty.
- // - jblas
- if ( typeof this.element[0].autocorrect !== "undefined" &&
- !$.support.touchOverflow ) {
-
- // Set the attribute instead of the property just in case there
- // is code that attempts to make modifications via HTML.
- this.element[0].setAttribute( "autocorrect", "off" );
- this.element[0].setAttribute( "autocomplete", "off" );
- }
- },
-
- _handleBlur: function() {
- this.widget().removeClass( $.mobile.focusClass );
- if ( this.options.preventFocusZoom ) {
- $.mobile.zoom.enable( true );
- }
- },
-
- _handleFocus: function() {
- // In many situations, iOS will zoom into the input upon tap, this
- // prevents that from happening
- if ( this.options.preventFocusZoom ) {
- $.mobile.zoom.disable( true );
- }
- this.widget().addClass( $.mobile.focusClass );
- },
-
- _setOptions: function ( options ) {
- var outer = this.widget();
-
- this._super( options );
-
- if ( !( options.disabled === undefined &&
- options.mini === undefined &&
- options.corners === undefined &&
- options.theme === undefined &&
- options.wrapperClass === undefined ) ) {
-
- outer.removeClass( this.classes.join( " " ) );
- this.classes = this._classesFromOptions();
- outer.addClass( this.classes.join( " " ) );
- }
-
- if ( options.disabled !== undefined ) {
- this.element.prop( "disabled", !!options.disabled );
- }
- },
-
- _destroy: function() {
- if ( this.options.enhanced ) {
- return;
- }
- if ( this.inputNeedsWrap ) {
- this.element.unwrap();
- }
- this.element.removeClass( "ui-input-text " + this.classes.join( " " ) );
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.slider", $.extend( {
- initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",
-
- widgetEventPrefix: "slide",
-
- options: {
- theme: null,
- trackTheme: null,
- corners: true,
- mini: false,
- highlight: false
- },
-
- _create: function() {
-
- // TODO: Each of these should have comments explain what they're for
- var self = this,
- control = this.element,
- trackTheme = this.options.trackTheme || $.mobile.getAttribute( control[ 0 ], "theme" ),
- trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
- cornerClass = ( this.options.corners || control.jqmData( "corners" ) ) ? " ui-corner-all" : "",
- miniClass = ( this.options.mini || control.jqmData( "mini" ) ) ? " ui-mini" : "",
- cType = control[ 0 ].nodeName.toLowerCase(),
- isToggleSwitch = ( cType === "select" ),
- isRangeslider = control.parent().is( ":jqmData(role='rangeslider')" ),
- selectClass = ( isToggleSwitch ) ? "ui-slider-switch" : "",
- controlID = control.attr( "id" ),
- $label = $( "[for='" + controlID + "']" ),
- labelID = $label.attr( "id" ) || controlID + "-label",
- min = !isToggleSwitch ? parseFloat( control.attr( "min" ) ) : 0,
- max = !isToggleSwitch ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
- step = window.parseFloat( control.attr( "step" ) || 1 ),
- domHandle = document.createElement( "a" ),
- handle = $( domHandle ),
- domSlider = document.createElement( "div" ),
- slider = $( domSlider ),
- valuebg = this.options.highlight && !isToggleSwitch ? (function() {
- var bg = document.createElement( "div" );
- bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
- return $( bg ).prependTo( slider );
- })() : false,
- options,
- wrapper,
- j, length,
- i, optionsCount, origTabIndex,
- side, activeClass, sliderImg;
-
- $label.attr( "id", labelID );
- this.isToggleSwitch = isToggleSwitch;
-
- domHandle.setAttribute( "href", "#" );
- domSlider.setAttribute( "role", "application" );
- domSlider.className = [ this.isToggleSwitch ? "ui-slider ui-slider-track ui-shadow-inset " : "ui-slider-track ui-shadow-inset ", selectClass, trackThemeClass, cornerClass, miniClass ].join( "" );
- domHandle.className = "ui-slider-handle";
- domSlider.appendChild( domHandle );
-
- handle.attr({
- "role": "slider",
- "aria-valuemin": min,
- "aria-valuemax": max,
- "aria-valuenow": this._value(),
- "aria-valuetext": this._value(),
- "title": this._value(),
- "aria-labelledby": labelID
- });
-
- $.extend( this, {
- slider: slider,
- handle: handle,
- control: control,
- type: cType,
- step: step,
- max: max,
- min: min,
- valuebg: valuebg,
- isRangeslider: isRangeslider,
- dragging: false,
- beforeStart: null,
- userModified: false,
- mouseMoved: false
- });
-
- if ( isToggleSwitch ) {
- // TODO: restore original tabindex (if any) in a destroy method
- origTabIndex = control.attr( "tabindex" );
- if ( origTabIndex ) {
- handle.attr( "tabindex", origTabIndex );
- }
- control.attr( "tabindex", "-1" ).focus(function() {
- $( this ).blur();
- handle.focus();
- });
-
- wrapper = document.createElement( "div" );
- wrapper.className = "ui-slider-inneroffset";
-
- for ( j = 0, length = domSlider.childNodes.length; j < length; j++ ) {
- wrapper.appendChild( domSlider.childNodes[j] );
- }
-
- domSlider.appendChild( wrapper );
-
- // slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
-
- // make the handle move with a smooth transition
- handle.addClass( "ui-slider-handle-snapping" );
-
- options = control.find( "option" );
-
- for ( i = 0, optionsCount = options.length; i < optionsCount; i++ ) {
- side = !i ? "b" : "a";
- activeClass = !i ? "" : " " + $.mobile.activeBtnClass;
- sliderImg = document.createElement( "span" );
-
- sliderImg.className = [ "ui-slider-label ui-slider-label-", side, activeClass ].join( "" );
- sliderImg.setAttribute( "role", "img" );
- sliderImg.appendChild( document.createTextNode( options[i].innerHTML ) );
- $( sliderImg ).prependTo( slider );
- }
-
- self._labels = $( ".ui-slider-label", slider );
-
- }
-
- // monitor the input for updated values
- control.addClass( isToggleSwitch ? "ui-slider-switch" : "ui-slider-input" );
-
- this._on( control, {
- "change": "_controlChange",
- "keyup": "_controlKeyup",
- "blur": "_controlBlur",
- "vmouseup": "_controlVMouseUp"
- });
-
- slider.bind( "vmousedown", $.proxy( this._sliderVMouseDown, this ) )
- .bind( "vclick", false );
-
- // We have to instantiate a new function object for the unbind to work properly
- // since the method itself is defined in the prototype (causing it to unbind everything)
- this._on( document, { "vmousemove": "_preventDocumentDrag" });
- this._on( slider.add( document ), { "vmouseup": "_sliderVMouseUp" });
-
- slider.insertAfter( control );
-
- // wrap in a div for styling purposes
- if ( !isToggleSwitch && !isRangeslider ) {
- wrapper = this.options.mini ? "<div class='ui-slider ui-mini'>" : "<div class='ui-slider'>";
-
- control.add( slider ).wrapAll( wrapper );
- }
-
- // bind the handle event callbacks and set the context to the widget instance
- this._on( this.handle, {
- "vmousedown": "_handleVMouseDown",
- "keydown": "_handleKeydown",
- "keyup": "_handleKeyup"
- });
-
- this.handle.bind( "vclick", false );
-
- this._handleFormReset();
-
- this.refresh( undefined, undefined, true );
- },
-
- _setOptions: function( options ) {
- if ( options.theme !== undefined ) {
- this._setTheme( options.theme );
- }
-
- if ( options.trackTheme !== undefined ) {
- this._setTrackTheme( options.trackTheme );
- }
-
- if ( options.corners !== undefined ) {
- this._setCorners( options.corners );
- }
-
- if ( options.mini !== undefined ) {
- this._setMini( options.mini );
- }
-
- if ( options.highlight !== undefined ) {
- this._setHighlight( options.highlight );
- }
-
- if ( options.disabled !== undefined ) {
- this._setDisabled( options.disabled );
- }
- this._super( options );
- },
-
- _controlChange: function( event ) {
- // if the user dragged the handle, the "change" event was triggered from inside refresh(); don't call refresh() again
- if ( this._trigger( "controlchange", event ) === false ) {
- return false;
- }
- if ( !this.mouseMoved ) {
- this.refresh( this._value(), true );
- }
- },
-
- _controlKeyup: function(/* event */) { // necessary?
- this.refresh( this._value(), true, true );
- },
-
- _controlBlur: function(/* event */) {
- this.refresh( this._value(), true );
- },
-
- // it appears the clicking the up and down buttons in chrome on
- // range/number inputs doesn't trigger a change until the field is
- // blurred. Here we check thif the value has changed and refresh
- _controlVMouseUp: function(/* event */) {
- this._checkedRefresh();
- },
-
- // NOTE force focus on handle
- _handleVMouseDown: function(/* event */) {
- this.handle.focus();
- },
-
- _handleKeydown: function( event ) {
- var index = this._value();
- if ( this.options.disabled ) {
- return;
- }
-
- // In all cases prevent the default and mark the handle as active
- switch ( event.keyCode ) {
- case $.mobile.keyCode.HOME:
- case $.mobile.keyCode.END:
- case $.mobile.keyCode.PAGE_UP:
- case $.mobile.keyCode.PAGE_DOWN:
- case $.mobile.keyCode.UP:
- case $.mobile.keyCode.RIGHT:
- case $.mobile.keyCode.DOWN:
- case $.mobile.keyCode.LEFT:
- event.preventDefault();
-
- if ( !this._keySliding ) {
- this._keySliding = true;
- this.handle.addClass( "ui-state-active" ); /* TODO: We don't use this class for styling. Do we need to add it? */
- }
-
- break;
- }
-
- // move the slider according to the keypress
- switch ( event.keyCode ) {
- case $.mobile.keyCode.HOME:
- this.refresh( this.min );
- break;
- case $.mobile.keyCode.END:
- this.refresh( this.max );
- break;
- case $.mobile.keyCode.PAGE_UP:
- case $.mobile.keyCode.UP:
- case $.mobile.keyCode.RIGHT:
- this.refresh( index + this.step );
- break;
- case $.mobile.keyCode.PAGE_DOWN:
- case $.mobile.keyCode.DOWN:
- case $.mobile.keyCode.LEFT:
- this.refresh( index - this.step );
- break;
- }
- }, // remove active mark
-
- _handleKeyup: function(/* event */) {
- if ( this._keySliding ) {
- this._keySliding = false;
- this.handle.removeClass( "ui-state-active" ); /* See comment above. */
- }
- },
-
- _sliderVMouseDown: function( event ) {
- // NOTE: we don't do this in refresh because we still want to
- // support programmatic alteration of disabled inputs
- if ( this.options.disabled || !( event.which === 1 || event.which === 0 || event.which === undefined ) ) {
- return false;
- }
- if ( this._trigger( "beforestart", event ) === false ) {
- return false;
- }
- this.dragging = true;
- this.userModified = false;
- this.mouseMoved = false;
-
- if ( this.isToggleSwitch ) {
- this.beforeStart = this.element[0].selectedIndex;
- }
-
- this.refresh( event );
- this._trigger( "start" );
- return false;
- },
-
- _sliderVMouseUp: function() {
- if ( this.dragging ) {
- this.dragging = false;
-
- if ( this.isToggleSwitch ) {
- // make the handle move with a smooth transition
- this.handle.addClass( "ui-slider-handle-snapping" );
-
- if ( this.mouseMoved ) {
- // this is a drag, change the value only if user dragged enough
- if ( this.userModified ) {
- this.refresh( this.beforeStart === 0 ? 1 : 0 );
- } else {
- this.refresh( this.beforeStart );
- }
- } else {
- // this is just a click, change the value
- this.refresh( this.beforeStart === 0 ? 1 : 0 );
- }
- }
-
- this.mouseMoved = false;
- this._trigger( "stop" );
- return false;
- }
- },
-
- _preventDocumentDrag: function( event ) {
- // NOTE: we don't do this in refresh because we still want to
- // support programmatic alteration of disabled inputs
- if ( this._trigger( "drag", event ) === false) {
- return false;
- }
- if ( this.dragging && !this.options.disabled ) {
-
- // this.mouseMoved must be updated before refresh() because it will be used in the control "change" event
- this.mouseMoved = true;
-
- if ( this.isToggleSwitch ) {
- // make the handle move in sync with the mouse
- this.handle.removeClass( "ui-slider-handle-snapping" );
- }
-
- this.refresh( event );
-
- // only after refresh() you can calculate this.userModified
- this.userModified = this.beforeStart !== this.element[0].selectedIndex;
- return false;
- }
- },
-
- _checkedRefresh: function() {
- if ( this.value !== this._value() ) {
- this.refresh( this._value() );
- }
- },
-
- _value: function() {
- return this.isToggleSwitch ? this.element[0].selectedIndex : parseFloat( this.element.val() ) ;
- },
-
- _reset: function() {
- this.refresh( undefined, false, true );
- },
-
- refresh: function( val, isfromControl, preventInputUpdate ) {
- // NOTE: we don't return here because we want to support programmatic
- // alteration of the input value, which should still update the slider
-
- var self = this,
- parentTheme = $.mobile.getAttribute( this.element[ 0 ], "theme" ),
- theme = this.options.theme || parentTheme,
- themeClass = theme ? " ui-btn-" + theme : "",
- trackTheme = this.options.trackTheme || parentTheme,
- trackThemeClass = trackTheme ? " ui-bar-" + trackTheme : " ui-bar-inherit",
- cornerClass = this.options.corners ? " ui-corner-all" : "",
- miniClass = this.options.mini ? " ui-mini" : "",
- left, width, data, tol,
- pxStep, percent,
- control, isInput, optionElements, min, max, step,
- newval, valModStep, alignValue, percentPerStep,
- handlePercent, aPercent, bPercent,
- valueChanged;
-
- self.slider[0].className = [ this.isToggleSwitch ? "ui-slider ui-slider-switch ui-slider-track ui-shadow-inset" : "ui-slider-track ui-shadow-inset", trackThemeClass, cornerClass, miniClass ].join( "" );
- if ( this.options.disabled || this.element.prop( "disabled" ) ) {
- this.disable();
- }
-
- // set the stored value for comparison later
- this.value = this._value();
- if ( this.options.highlight && !this.isToggleSwitch && this.slider.find( ".ui-slider-bg" ).length === 0 ) {
- this.valuebg = (function() {
- var bg = document.createElement( "div" );
- bg.className = "ui-slider-bg " + $.mobile.activeBtnClass;
- return $( bg ).prependTo( self.slider );
- })();
- }
- this.handle.addClass( "ui-btn" + themeClass + " ui-shadow" );
-
- control = this.element;
- isInput = !this.isToggleSwitch;
- optionElements = isInput ? [] : control.find( "option" );
- min = isInput ? parseFloat( control.attr( "min" ) ) : 0;
- max = isInput ? parseFloat( control.attr( "max" ) ) : optionElements.length - 1;
- step = ( isInput && parseFloat( control.attr( "step" ) ) > 0 ) ? parseFloat( control.attr( "step" ) ) : 1;
-
- if ( typeof val === "object" ) {
- data = val;
- // a slight tolerance helped get to the ends of the slider
- tol = 8;
-
- left = this.slider.offset().left;
- width = this.slider.width();
- pxStep = width/((max-min)/step);
- if ( !this.dragging ||
- data.pageX < left - tol ||
- data.pageX > left + width + tol ) {
- return;
- }
- if ( pxStep > 1 ) {
- percent = ( ( data.pageX - left ) / width ) * 100;
- } else {
- percent = Math.round( ( ( data.pageX - left ) / width ) * 100 );
- }
- } else {
- if ( val == null ) {
- val = isInput ? parseFloat( control.val() || 0 ) : control[0].selectedIndex;
- }
- percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
- }
-
- if ( isNaN( percent ) ) {
- return;
- }
-
- newval = ( percent / 100 ) * ( max - min ) + min;
-
- //from jQuery UI slider, the following source will round to the nearest step
- valModStep = ( newval - min ) % step;
- alignValue = newval - valModStep;
-
- if ( Math.abs( valModStep ) * 2 >= step ) {
- alignValue += ( valModStep > 0 ) ? step : ( -step );
- }
-
- percentPerStep = 100/((max-min)/step);
- // Since JavaScript has problems with large floats, round
- // the final value to 5 digits after the decimal point (see jQueryUI: #4124)
- newval = parseFloat( alignValue.toFixed(5) );
-
- if ( typeof pxStep === "undefined" ) {
- pxStep = width / ( (max-min) / step );
- }
- if ( pxStep > 1 && isInput ) {
- percent = ( newval - min ) * percentPerStep * ( 1 / step );
- }
- if ( percent < 0 ) {
- percent = 0;
- }
-
- if ( percent > 100 ) {
- percent = 100;
- }
-
- if ( newval < min ) {
- newval = min;
- }
-
- if ( newval > max ) {
- newval = max;
- }
-
- this.handle.css( "left", percent + "%" );
-
- this.handle[0].setAttribute( "aria-valuenow", isInput ? newval : optionElements.eq( newval ).attr( "value" ) );
-
- this.handle[0].setAttribute( "aria-valuetext", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
-
- this.handle[0].setAttribute( "title", isInput ? newval : optionElements.eq( newval ).getEncodedText() );
-
- if ( this.valuebg ) {
- this.valuebg.css( "width", percent + "%" );
- }
-
- // drag the label widths
- if ( this._labels ) {
- handlePercent = this.handle.width() / this.slider.width() * 100;
- aPercent = percent && handlePercent + ( 100 - handlePercent ) * percent / 100;
- bPercent = percent === 100 ? 0 : Math.min( handlePercent + 100 - aPercent, 100 );
-
- this._labels.each(function() {
- var ab = $( this ).hasClass( "ui-slider-label-a" );
- $( this ).width( ( ab ? aPercent : bPercent ) + "%" );
- });
- }
-
- if ( !preventInputUpdate ) {
- valueChanged = false;
-
- // update control"s value
- if ( isInput ) {
- valueChanged = control.val() !== newval;
- control.val( newval );
- } else {
- valueChanged = control[ 0 ].selectedIndex !== newval;
- control[ 0 ].selectedIndex = newval;
- }
- if ( this._trigger( "beforechange", val ) === false) {
- return false;
- }
- if ( !isfromControl && valueChanged ) {
- control.trigger( "change" );
- }
- }
- },
-
- _setHighlight: function( value ) {
- value = !!value;
- if ( value ) {
- this.options.highlight = !!value;
- this.refresh();
- } else if ( this.valuebg ) {
- this.valuebg.remove();
- this.valuebg = false;
- }
- },
-
- _setTheme: function( value ) {
- this.handle
- .removeClass( "ui-btn-" + this.options.theme )
- .addClass( "ui-btn-" + value );
-
- var currentTheme = this.options.theme ? this.options.theme : "inherit",
- newTheme = value ? value : "inherit";
-
- this.control
- .removeClass( "ui-body-" + currentTheme )
- .addClass( "ui-body-" + newTheme );
- },
-
- _setTrackTheme: function( value ) {
- var currentTrackTheme = this.options.trackTheme ? this.options.trackTheme : "inherit",
- newTrackTheme = value ? value : "inherit";
-
- this.slider
- .removeClass( "ui-body-" + currentTrackTheme )
- .addClass( "ui-body-" + newTrackTheme );
- },
-
- _setMini: function( value ) {
- value = !!value;
- if ( !this.isToggleSwitch && !this.isRangeslider ) {
- this.slider.parent().toggleClass( "ui-mini", value );
- this.element.toggleClass( "ui-mini", value );
- }
- this.slider.toggleClass( "ui-mini", value );
- },
-
- _setCorners: function( value ) {
- this.slider.toggleClass( "ui-corner-all", value );
-
- if ( !this.isToggleSwitch ) {
- this.control.toggleClass( "ui-corner-all", value );
- }
- },
-
- _setDisabled: function( value ) {
- value = !!value;
- this.element.prop( "disabled", value );
- this.slider
- .toggleClass( "ui-state-disabled", value )
- .attr( "aria-disabled", value );
- }
-
-}, $.mobile.behaviors.formReset ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-var popup;
-
-function getPopup() {
- if ( !popup ) {
- popup = $( "<div></div>", {
- "class": "ui-slider-popup ui-shadow ui-corner-all"
- });
- }
- return popup.clone();
-}
-
-$.widget( "mobile.slider", $.mobile.slider, {
- options: {
- popupEnabled: false,
- showValue: false
- },
-
- _create: function() {
- this._super();
-
- $.extend( this, {
- _currentValue: null,
- _popup: null,
- _popupVisible: false
- });
-
- this._setOption( "popupEnabled", this.options.popupEnabled );
-
- this._on( this.handle, { "vmousedown" : "_showPopup" } );
- this._on( this.slider.add( this.document ), { "vmouseup" : "_hidePopup" } );
- this._refresh();
- },
-
- // position the popup centered 5px above the handle
- _positionPopup: function() {
- var dstOffset = this.handle.offset();
-
- this._popup.offset( {
- left: dstOffset.left + ( this.handle.width() - this._popup.width() ) / 2,
- top: dstOffset.top - this._popup.outerHeight() - 5
- });
- },
-
- _setOption: function( key, value ) {
- this._super( key, value );
-
- if ( key === "showValue" ) {
- this.handle.html( value && !this.options.mini ? this._value() : "" );
- } else if ( key === "popupEnabled" ) {
- if ( value && !this._popup ) {
- this._popup = getPopup()
- .addClass( "ui-body-" + ( this.options.theme || "a" ) )
- .hide()
- .insertBefore( this.element );
- }
- }
- },
-
- // show value on the handle and in popup
- refresh: function() {
- this._super.apply( this, arguments );
- this._refresh();
- },
-
- _refresh: function() {
- var o = this.options, newValue;
-
- if ( o.popupEnabled ) {
- // remove the title attribute from the handle (which is
- // responsible for the annoying tooltip); NB we have
- // to do it here as the jqm slider sets it every time
- // the slider's value changes :(
- this.handle.removeAttr( "title" );
- }
-
- newValue = this._value();
- if ( newValue === this._currentValue ) {
- return;
- }
- this._currentValue = newValue;
-
- if ( o.popupEnabled && this._popup ) {
- this._positionPopup();
- this._popup.html( newValue );
- } else if ( o.showValue && !this.options.mini ) {
- this.handle.html( newValue );
- }
- },
-
- _showPopup: function() {
- if ( this.options.popupEnabled && !this._popupVisible ) {
- this.handle.html( "" );
- this._popup.show();
- this._positionPopup();
- this._popupVisible = true;
- }
- },
-
- _hidePopup: function() {
- var o = this.options;
-
- if ( o.popupEnabled && this._popupVisible ) {
- if ( o.showValue && !o.mini ) {
- this.handle.html( this._value() );
- }
- this._popup.hide();
- this._popupVisible = false;
- }
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.flipswitch", $.extend({
-
- options: {
- onText: "On",
- offText: "Off",
- theme: null,
- enhanced: false,
- wrapperClass: null,
- corners: true,
- mini: false
- },
-
- _create: function() {
- if ( !this.options.enhanced ) {
- this._enhance();
- } else {
- $.extend( this, {
- flipswitch: this.element.parent(),
- on: this.element.find( ".ui-flipswitch-on" ).eq( 0 ),
- off: this.element.find( ".ui-flipswitch-off" ).eq(0),
- type: this.element.get( 0 ).tagName
- });
- }
-
- this._handleFormReset();
-
- // Transfer tabindex to "on" element and make input unfocusable
- this._originalTabIndex = this.element.attr( "tabindex" );
- if ( this._originalTabIndex != null ) {
- this.on.attr( "tabindex", this._originalTabIndex );
- }
- this.element.attr( "tabindex", "-1" );
- this._on({
- "focus" : "_handleInputFocus"
- });
-
- if ( this.element.is( ":disabled" ) ) {
- this._setOptions({
- "disabled": true
- });
- }
-
- this._on( this.flipswitch, {
- "click": "_toggle",
- "swipeleft": "_left",
- "swiperight": "_right"
- });
-
- this._on( this.on, {
- "keydown": "_keydown"
- });
-
- this._on( {
- "change": "refresh"
- });
- },
-
- _handleInputFocus: function() {
- this.on.focus();
- },
-
- widget: function() {
- return this.flipswitch;
- },
-
- _left: function() {
- this.flipswitch.removeClass( "ui-flipswitch-active" );
- if ( this.type === "SELECT" ) {
- this.element.get( 0 ).selectedIndex = 0;
- } else {
- this.element.prop( "checked", false );
- }
- this.element.trigger( "change" );
- },
-
- _right: function() {
- this.flipswitch.addClass( "ui-flipswitch-active" );
- if ( this.type === "SELECT" ) {
- this.element.get( 0 ).selectedIndex = 1;
- } else {
- this.element.prop( "checked", true );
- }
- this.element.trigger( "change" );
- },
-
- _enhance: function() {
- var flipswitch = $( "<div>" ),
- options = this.options,
- element = this.element,
- theme = options.theme ? options.theme : "inherit",
-
- // The "on" button is an anchor so it's focusable
- on = $( "<a></a>", {
- "href": "#"
- }),
- off = $( "<span></span>" ),
- type = element.get( 0 ).tagName,
- onText = ( type === "INPUT" ) ?
- options.onText : element.find( "option" ).eq( 1 ).text(),
- offText = ( type === "INPUT" ) ?
- options.offText : element.find( "option" ).eq( 0 ).text();
-
- on
- .addClass( "ui-flipswitch-on ui-btn ui-shadow ui-btn-inherit" )
- .text( onText );
- off
- .addClass( "ui-flipswitch-off" )
- .text( offText );
-
- flipswitch
- .addClass( "ui-flipswitch ui-shadow-inset " +
- "ui-bar-" + theme + " " +
- ( options.wrapperClass ? options.wrapperClass : "" ) + " " +
- ( ( element.is( ":checked" ) ||
- element
- .find( "option" )
- .eq( 1 )
- .is( ":selected" ) ) ? "ui-flipswitch-active" : "" ) +
- ( element.is(":disabled") ? " ui-state-disabled": "") +
- ( options.corners ? " ui-corner-all": "" ) +
- ( options.mini ? " ui-mini": "" ) )
- .append( on, off );
-
- element
- .addClass( "ui-flipswitch-input" )
- .after( flipswitch )
- .appendTo( flipswitch );
-
- $.extend( this, {
- flipswitch: flipswitch,
- on: on,
- off: off,
- type: type
- });
- },
-
- _reset: function() {
- this.refresh();
- },
-
- refresh: function() {
- var direction,
- existingDirection = this.flipswitch.hasClass( "ui-flipswitch-active" ) ? "_right" : "_left";
-
- if ( this.type === "SELECT" ) {
- direction = ( this.element.get( 0 ).selectedIndex > 0 ) ? "_right": "_left";
- } else {
- direction = this.element.prop( "checked" ) ? "_right": "_left";
- }
-
- if ( direction !== existingDirection ) {
- this[ direction ]();
- }
- },
-
- _toggle: function() {
- var direction = this.flipswitch.hasClass( "ui-flipswitch-active" ) ? "_left" : "_right";
-
- this[ direction ]();
- },
-
- _keydown: function( e ) {
- if ( e.which === $.mobile.keyCode.LEFT ) {
- this._left();
- } else if ( e.which === $.mobile.keyCode.RIGHT ) {
- this._right();
- } else if ( e.which === $.mobile.keyCode.SPACE ) {
- this._toggle();
- e.preventDefault();
- }
- },
-
- _setOptions: function( options ) {
- if ( options.theme !== undefined ) {
- var currentTheme = options.theme ? options.theme : "inherit",
- newTheme = options.theme ? options.theme : "inherit";
-
- this.widget()
- .removeClass( "ui-bar-" + currentTheme )
- .addClass( "ui-bar-" + newTheme );
- }
- if ( options.onText !== undefined ) {
- this.on.text( options.onText );
- }
- if ( options.offText !== undefined ) {
- this.off.text( options.offText );
- }
- if ( options.disabled !== undefined ) {
- this.widget().toggleClass( "ui-state-disabled", options.disabled );
- }
- if ( options.mini !== undefined ) {
- this.widget().toggleClass( "ui-mini", options.mini );
- }
- if ( options.corners !== undefined ) {
- this.widget().toggleClass( "ui-corner-all", options.corners );
- }
-
- this._super( options );
- },
-
- _destroy: function() {
- if ( this.options.enhanced ) {
- return;
- }
- if ( this._originalTabIndex != null ) {
- this.element.attr( "tabindex", this._originalTabIndex );
- } else {
- this.element.removeAttr( "tabindex" );
- }
- this.on.remove();
- this.off.remove();
- this.element.unwrap();
- this.flipswitch.remove();
- this.removeClass( "ui-flipswitch-input" );
- }
-
-}, $.mobile.behaviors.formReset ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
- $.widget( "mobile.rangeslider", $.extend( {
-
- options: {
- theme: null,
- trackTheme: null,
- corners: true,
- mini: false,
- highlight: true
- },
-
- _create: function() {
- var $el = this.element,
- elClass = this.options.mini ? "ui-rangeslider ui-mini" : "ui-rangeslider",
- _inputFirst = $el.find( "input" ).first(),
- _inputLast = $el.find( "input" ).last(),
- _label = $el.find( "label" ).first(),
- _sliderWidgetFirst = $.data( _inputFirst.get( 0 ), "mobile-slider" ) ||
- $.data( _inputFirst.slider().get( 0 ), "mobile-slider" ),
- _sliderWidgetLast = $.data( _inputLast.get(0), "mobile-slider" ) ||
- $.data( _inputLast.slider().get( 0 ), "mobile-slider" ),
- _sliderFirst = _sliderWidgetFirst.slider,
- _sliderLast = _sliderWidgetLast.slider,
- firstHandle = _sliderWidgetFirst.handle,
- _sliders = $( "<div class='ui-rangeslider-sliders' />" ).appendTo( $el );
-
- _inputFirst.addClass( "ui-rangeslider-first" );
- _inputLast.addClass( "ui-rangeslider-last" );
- $el.addClass( elClass );
-
- _sliderFirst.appendTo( _sliders );
- _sliderLast.appendTo( _sliders );
- _label.insertBefore( $el );
- firstHandle.prependTo( _sliderLast );
-
- $.extend( this, {
- _inputFirst: _inputFirst,
- _inputLast: _inputLast,
- _sliderFirst: _sliderFirst,
- _sliderLast: _sliderLast,
- _label: _label,
- _targetVal: null,
- _sliderTarget: false,
- _sliders: _sliders,
- _proxy: false
- });
-
- this.refresh();
- this._on( this.element.find( "input.ui-slider-input" ), {
- "slidebeforestart": "_slidebeforestart",
- "slidestop": "_slidestop",
- "slidedrag": "_slidedrag",
- "slidebeforechange": "_change",
- "blur": "_change",
- "keyup": "_change"
- });
- this._on({
- "mousedown":"_change"
- });
- this._on( this.element.closest( "form" ), {
- "reset":"_handleReset"
- });
- this._on( firstHandle, {
- "vmousedown": "_dragFirstHandle"
- });
- },
- _handleReset: function() {
- var self = this;
- //we must wait for the stack to unwind before updateing other wise sliders will not have updated yet
- setTimeout( function() {
- self._updateHighlight();
- },0);
- },
-
- _dragFirstHandle: function( event ) {
- //if the first handle is dragged send the event to the first slider
- $.data( this._inputFirst.get(0), "mobile-slider" ).dragging = true;
- $.data( this._inputFirst.get(0), "mobile-slider" ).refresh( event );
- return false;
- },
-
- _slidedrag: function( event ) {
- var first = $( event.target ).is( this._inputFirst ),
- otherSlider = ( first ) ? this._inputLast : this._inputFirst;
-
- this._sliderTarget = false;
- //if the drag was initiated on an extreme and the other handle is focused send the events to
- //the closest handle
- if ( ( this._proxy === "first" && first ) || ( this._proxy === "last" && !first ) ) {
- $.data( otherSlider.get(0), "mobile-slider" ).dragging = true;
- $.data( otherSlider.get(0), "mobile-slider" ).refresh( event );
- return false;
- }
- },
-
- _slidestop: function( event ) {
- var first = $( event.target ).is( this._inputFirst );
-
- this._proxy = false;
- //this stops dragging of the handle and brings the active track to the front
- //this makes clicks on the track go the the last handle used
- this.element.find( "input" ).trigger( "vmouseup" );
- this._sliderFirst.css( "z-index", first ? 1 : "" );
- },
-
- _slidebeforestart: function( event ) {
- this._sliderTarget = false;
- //if the track is the target remember this and the original value
- if ( $( event.originalEvent.target ).hasClass( "ui-slider-track" ) ) {
- this._sliderTarget = true;
- this._targetVal = $( event.target ).val();
- }
- },
-
- _setOptions: function( options ) {
- if ( options.theme !== undefined ) {
- this._setTheme( options.theme );
- }
-
- if ( options.trackTheme !== undefined ) {
- this._setTrackTheme( options.trackTheme );
- }
-
- if ( options.mini !== undefined ) {
- this._setMini( options.mini );
- }
-
- if ( options.highlight !== undefined ) {
- this._setHighlight( options.highlight );
- }
- this._super( options );
- this.refresh();
- },
-
- refresh: function() {
- var $el = this.element,
- o = this.options;
-
- if ( this._inputFirst.is( ":disabled" ) || this._inputLast.is( ":disabled" ) ) {
- this.options.disabled = true;
- }
-
- $el.find( "input" ).slider({
- theme: o.theme,
- trackTheme: o.trackTheme,
- disabled: o.disabled,
- corners: o.corners,
- mini: o.mini,
- highlight: o.highlight
- }).slider( "refresh" );
- this._updateHighlight();
- },
-
- _change: function( event ) {
- if ( event.type === "keyup" ) {
- this._updateHighlight();
- return false;
- }
-
- var self = this,
- min = parseFloat( this._inputFirst.val(), 10 ),
- max = parseFloat( this._inputLast.val(), 10 ),
- first = $( event.target ).hasClass( "ui-rangeslider-first" ),
- thisSlider = first ? this._inputFirst : this._inputLast,
- otherSlider = first ? this._inputLast : this._inputFirst;
-
- if ( ( this._inputFirst.val() > this._inputLast.val() && event.type === "mousedown" && !$(event.target).hasClass("ui-slider-handle")) ) {
- thisSlider.blur();
- } else if ( event.type === "mousedown" ) {
- return;
- }
- if ( min > max && !this._sliderTarget ) {
- //this prevents min from being greater then max
- thisSlider.val( first ? max: min ).slider( "refresh" );
- this._trigger( "normalize" );
- } else if ( min > max ) {
- //this makes it so clicks on the target on either extreme go to the closest handle
- thisSlider.val( this._targetVal ).slider( "refresh" );
-
- //You must wait for the stack to unwind so first slider is updated before updating second
- setTimeout( function() {
- otherSlider.val( first ? min: max ).slider( "refresh" );
- $.data( otherSlider.get(0), "mobile-slider" ).handle.focus();
- self._sliderFirst.css( "z-index", first ? "" : 1 );
- self._trigger( "normalize" );
- }, 0 );
- this._proxy = ( first ) ? "first" : "last";
- }
- //fixes issue where when both _sliders are at min they cannot be adjusted
- if ( min === max ) {
- $.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", 1 );
- $.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", 0 );
- } else {
- $.data( otherSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
- $.data( thisSlider.get(0), "mobile-slider" ).handle.css( "z-index", "" );
- }
-
- this._updateHighlight();
-
- if ( min >= max ) {
- return false;
- }
- },
-
- _updateHighlight: function() {
- var min = parseInt( $.data( this._inputFirst.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
- max = parseInt( $.data( this._inputLast.get(0), "mobile-slider" ).handle.get(0).style.left, 10 ),
- width = (max - min);
-
- this.element.find( ".ui-slider-bg" ).css({
- "margin-left": min + "%",
- "width": width + "%"
- });
- },
-
- _setTheme: function( value ) {
- this._inputFirst.slider( "option", "theme", value );
- this._inputLast.slider( "option", "theme", value );
- },
-
- _setTrackTheme: function( value ) {
- this._inputFirst.slider( "option", "trackTheme", value );
- this._inputLast.slider( "option", "trackTheme", value );
- },
-
- _setMini: function( value ) {
- this._inputFirst.slider( "option", "mini", value );
- this._inputLast.slider( "option", "mini", value );
- this.element.toggleClass( "ui-mini", !!value );
- },
-
- _setHighlight: function( value ) {
- this._inputFirst.slider( "option", "highlight", value );
- this._inputLast.slider( "option", "highlight", value );
- },
-
- _destroy: function() {
- this._label.prependTo( this.element );
- this.element.removeClass( "ui-rangeslider ui-mini" );
- this._inputFirst.after( this._sliderFirst );
- this._inputLast.after( this._sliderLast );
- this._sliders.remove();
- this.element.find( "input" ).removeClass( "ui-rangeslider-first ui-rangeslider-last" ).slider( "destroy" );
- }
-
- }, $.mobile.behaviors.formReset ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
- $.widget( "mobile.textinput", $.mobile.textinput, {
- options: {
- clearBtn: false,
- clearBtnText: "Clear text"
- },
-
- _create: function() {
- this._super();
-
- if ( !!this.options.clearBtn || this.isSearch ) {
- this._addClearBtn();
- }
- },
-
- clearButton: function() {
-
- return $( "<a href='#' class='ui-input-clear ui-btn ui-icon-delete ui-btn-icon-notext ui-corner-all" +
- "' title='" + this.options.clearBtnText + "'>" + this.options.clearBtnText + "</a>" );
-
- },
-
- _clearBtnClick: function( event ) {
- this.element.val( "" )
- .focus()
- .trigger( "change" );
-
- this._clearBtn.addClass( "ui-input-clear-hidden" );
- event.preventDefault();
- },
-
- _addClearBtn: function() {
-
- if ( !this.options.enhanced ) {
- this._enhanceClear();
- }
-
- $.extend( this, {
- _clearBtn: this.widget().find("a.ui-input-clear")
- });
-
- this._bindClearEvents();
-
- this._toggleClear();
-
- },
-
- _enhanceClear: function() {
-
- this.clearButton().appendTo( this.widget() );
- this.widget().addClass( "ui-input-has-clear" );
-
- },
-
- _bindClearEvents: function() {
-
- this._on( this._clearBtn, {
- "click": "_clearBtnClick"
- });
-
- this._on({
- "keyup": "_toggleClear",
- "change": "_toggleClear",
- "input": "_toggleClear",
- "focus": "_toggleClear",
- "blur": "_toggleClear",
- "cut": "_toggleClear",
- "paste": "_toggleClear"
-
- });
-
- },
-
- _unbindClear: function() {
- this._off( this._clearBtn, "click");
- this._off( this.element, "keyup change input focus blur cut paste" );
- },
-
- _setOptions: function( options ) {
- this._super( options );
-
- if ( options.clearBtn !== undefined &&
- !this.element.is( "textarea, :jqmData(type='range')" ) ) {
- if ( options.clearBtn ) {
- this._addClearBtn();
- } else {
- this._destroyClear();
- }
- }
-
- if ( options.clearBtnText !== undefined && this._clearBtn !== undefined ) {
- this._clearBtn.text( options.clearBtnText )
- .attr("title", options.clearBtnText);
- }
- },
-
- _toggleClear: function() {
- this._delay( "_toggleClearClass", 0 );
- },
-
- _toggleClearClass: function() {
- this._clearBtn.toggleClass( "ui-input-clear-hidden", !this.element.val() );
- },
-
- _destroyClear: function() {
- this.widget().removeClass( "ui-input-has-clear" );
- this._unbindClear();
- this._clearBtn.remove();
- },
-
- _destroy: function() {
- this._super();
- this._destroyClear();
- }
-
- });
-
-})( jQuery );
-
-(function( $, undefined ) {
-
- $.widget( "mobile.textinput", $.mobile.textinput, {
- options: {
- autogrow:true,
- keyupTimeoutBuffer: 100
- },
-
- _create: function() {
- this._super();
-
- if ( this.options.autogrow && this.isTextarea ) {
- this._autogrow();
- }
- },
-
- _autogrow: function() {
- this.element.addClass( "ui-textinput-autogrow" );
-
- this._on({
- "keyup": "_timeout",
- "change": "_timeout",
- "input": "_timeout",
- "paste": "_timeout"
- });
-
- // Attach to the various you-have-become-visible notifications that the
- // various framework elements emit.
- // TODO: Remove all but the updatelayout handler once #6426 is fixed.
- this._on( true, this.document, {
-
- // TODO: Move to non-deprecated event
- "pageshow": "_handleShow",
- "popupbeforeposition": "_handleShow",
- "updatelayout": "_handleShow",
- "panelopen": "_handleShow"
- });
- },
-
- // Synchronously fix the widget height if this widget's parents are such
- // that they show/hide content at runtime. We still need to check whether
- // the widget is actually visible in case it is contained inside multiple
- // such containers. For example: panel contains collapsible contains
- // autogrow textinput. The panel may emit "panelopen" indicating that its
- // content has become visible, but the collapsible is still collapsed, so
- // the autogrow textarea is still not visible.
- _handleShow: function( event ) {
- if ( $.contains( event.target, this.element[ 0 ] ) &&
- this.element.is( ":visible" ) ) {
-
- if ( event.type !== "popupbeforeposition" ) {
- this.element
- .addClass( "ui-textinput-autogrow-resize" )
- .animationComplete(
- $.proxy( function() {
- this.element.removeClass( "ui-textinput-autogrow-resize" );
- }, this ),
- "transition" );
- }
- this._timeout();
- }
- },
-
- _unbindAutogrow: function() {
- this.element.removeClass( "ui-textinput-autogrow" );
- this._off( this.element, "keyup change input paste" );
- this._off( this.document,
- "pageshow popupbeforeposition updatelayout panelopen" );
- },
-
- keyupTimeout: null,
-
- _prepareHeightUpdate: function( delay ) {
- if ( this.keyupTimeout ) {
- clearTimeout( this.keyupTimeout );
- }
- if ( delay === undefined ) {
- this._updateHeight();
- } else {
- this.keyupTimeout = this._delay( "_updateHeight", delay );
- }
- },
-
- _timeout: function() {
- this._prepareHeightUpdate( this.options.keyupTimeoutBuffer );
- },
-
- _updateHeight: function() {
- var paddingTop, paddingBottom, paddingHeight, scrollHeight, clientHeight,
- borderTop, borderBottom, borderHeight, height,
- scrollTop = this.window.scrollTop();
- this.keyupTimeout = 0;
-
- // IE8 textareas have the onpage property - others do not
- if ( !( "onpage" in this.element[ 0 ] ) ) {
- this.element.css({
- "height": 0,
- "min-height": 0,
- "max-height": 0
- });
- }
-
- scrollHeight = this.element[ 0 ].scrollHeight;
- clientHeight = this.element[ 0 ].clientHeight;
- borderTop = parseFloat( this.element.css( "border-top-width" ) );
- borderBottom = parseFloat( this.element.css( "border-bottom-width" ) );
- borderHeight = borderTop + borderBottom;
- height = scrollHeight + borderHeight + 15;
-
- // Issue 6179: Padding is not included in scrollHeight and
- // clientHeight by Firefox if no scrollbar is visible. Because
- // textareas use the border-box box-sizing model, padding should be
- // included in the new (assigned) height. Because the height is set
- // to 0, clientHeight == 0 in Firefox. Therefore, we can use this to
- // check if padding must be added.
- if ( clientHeight === 0 ) {
- paddingTop = parseFloat( this.element.css( "padding-top" ) );
- paddingBottom = parseFloat( this.element.css( "padding-bottom" ) );
- paddingHeight = paddingTop + paddingBottom;
-
- height += paddingHeight;
- }
-
- this.element.css({
- "height": height,
- "min-height": "",
- "max-height": ""
- });
-
- this.window.scrollTop( scrollTop );
- },
-
- refresh: function() {
- if ( this.options.autogrow && this.isTextarea ) {
- this._updateHeight();
- }
- },
-
- _setOptions: function( options ) {
-
- this._super( options );
-
- if ( options.autogrow !== undefined && this.isTextarea ) {
- if ( options.autogrow ) {
- this._autogrow();
- } else {
- this._unbindAutogrow();
- }
- }
- }
-
- });
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.selectmenu", $.extend( {
- initSelector: "select:not( :jqmData(role='slider')):not( :jqmData(role='flipswitch') )",
-
- options: {
- theme: null,
- icon: "carat-d",
- iconpos: "right",
- inline: false,
- corners: true,
- shadow: true,
- iconshadow: false, /* TODO: Deprecated in 1.4, remove in 1.5. */
- overlayTheme: null,
- dividerTheme: null,
- hidePlaceholderMenuItems: true,
- closeText: "Close",
- nativeMenu: true,
- // This option defaults to true on iOS devices.
- preventFocusZoom: /iPhone|iPad|iPod/.test( navigator.platform ) && navigator.userAgent.indexOf( "AppleWebKit" ) > -1,
- mini: false
- },
-
- _button: function() {
- return $( "<div/>" );
- },
-
- _setDisabled: function( value ) {
- this.element.attr( "disabled", value );
- this.button.attr( "aria-disabled", value );
- return this._setOption( "disabled", value );
- },
-
- _focusButton : function() {
- var self = this;
-
- setTimeout( function() {
- self.button.focus();
- }, 40);
- },
-
- _selectOptions: function() {
- return this.select.find( "option" );
- },
-
- // setup items that are generally necessary for select menu extension
- _preExtension: function() {
- var inline = this.options.inline || this.element.jqmData( "inline" ),
- mini = this.options.mini || this.element.jqmData( "mini" ),
- classes = "";
- // TODO: Post 1.1--once we have time to test thoroughly--any classes manually applied to the original element should be carried over to the enhanced element, with an `-enhanced` suffix. See https://github.com/jquery/jquery-mobile/issues/3577
- /* if ( $el[0].className.length ) {
- classes = $el[0].className;
- } */
- if ( !!~this.element[0].className.indexOf( "ui-btn-left" ) ) {
- classes = " ui-btn-left";
- }
-
- if ( !!~this.element[0].className.indexOf( "ui-btn-right" ) ) {
- classes = " ui-btn-right";
- }
-
- if ( inline ) {
- classes += " ui-btn-inline";
- }
- if ( mini ) {
- classes += " ui-mini";
- }
-
- this.select = this.element.removeClass( "ui-btn-left ui-btn-right" ).wrap( "<div class='ui-select" + classes + "'>" );
- this.selectId = this.select.attr( "id" ) || ( "select-" + this.uuid );
- this.buttonId = this.selectId + "-button";
- this.label = $( "label[for='"+ this.selectId +"']" );
- this.isMultiple = this.select[ 0 ].multiple;
- },
-
- _destroy: function() {
- var wrapper = this.element.parents( ".ui-select" );
- if ( wrapper.length > 0 ) {
- if ( wrapper.is( ".ui-btn-left, .ui-btn-right" ) ) {
- this.element.addClass( wrapper.hasClass( "ui-btn-left" ) ? "ui-btn-left" : "ui-btn-right" );
- }
- this.element.insertAfter( wrapper );
- wrapper.remove();
- }
- },
-
- _create: function() {
- this._preExtension();
-
- this.button = this._button();
-
- var self = this,
-
- options = this.options,
-
- iconpos = options.icon ? ( options.iconpos || this.select.jqmData( "iconpos" ) ) : false,
-
- button = this.button
- .insertBefore( this.select )
- .attr( "id", this.buttonId )
- .addClass( "ui-btn" +
- ( options.icon ? ( " ui-icon-" + options.icon + " ui-btn-icon-" + iconpos +
- ( options.iconshadow ? " ui-shadow-icon" : "" ) ) : "" ) + /* TODO: Remove in 1.5. */
- ( options.theme ? " ui-btn-" + options.theme : "" ) +
- ( options.corners ? " ui-corner-all" : "" ) +
- ( options.shadow ? " ui-shadow" : "" ) );
-
- this.setButtonText();
-
- // Opera does not properly support opacity on select elements
- // In Mini, it hides the element, but not its text
- // On the desktop,it seems to do the opposite
- // for these reasons, using the nativeMenu option results in a full native select in Opera
- if ( options.nativeMenu && window.opera && window.opera.version ) {
- button.addClass( "ui-select-nativeonly" );
- }
-
- // Add counter for multi selects
- if ( this.isMultiple ) {
- this.buttonCount = $( "<span>" )
- .addClass( "ui-li-count ui-body-inherit" )
- .hide()
- .appendTo( button.addClass( "ui-li-has-count" ) );
- }
-
- // Disable if specified
- if ( options.disabled || this.element.attr( "disabled" )) {
- this.disable();
- }
-
- // Events on native select
- this.select.change(function() {
- self.refresh();
-
- if ( !!options.nativeMenu ) {
- this.blur();
- }
- });
-
- this._handleFormReset();
-
- this._on( this.button, {
- keydown: "_handleKeydown"
- });
-
- this.build();
- },
-
- build: function() {
- var self = this;
-
- this.select
- .appendTo( self.button )
- .bind( "vmousedown", function() {
- // Add active class to button
- self.button.addClass( $.mobile.activeBtnClass );
- })
- .bind( "focus", function() {
- self.button.addClass( $.mobile.focusClass );
- })
- .bind( "blur", function() {
- self.button.removeClass( $.mobile.focusClass );
- })
- .bind( "focus vmouseover", function() {
- self.button.trigger( "vmouseover" );
- })
- .bind( "vmousemove", function() {
- // Remove active class on scroll/touchmove
- self.button.removeClass( $.mobile.activeBtnClass );
- })
- .bind( "change blur vmouseout", function() {
- self.button.trigger( "vmouseout" )
- .removeClass( $.mobile.activeBtnClass );
- });
-
- // In many situations, iOS will zoom into the select upon tap, this prevents that from happening
- self.button.bind( "vmousedown", function() {
- if ( self.options.preventFocusZoom ) {
- $.mobile.zoom.disable( true );
- }
- });
- self.label.bind( "click focus", function() {
- if ( self.options.preventFocusZoom ) {
- $.mobile.zoom.disable( true );
- }
- });
- self.select.bind( "focus", function() {
- if ( self.options.preventFocusZoom ) {
- $.mobile.zoom.disable( true );
- }
- });
- self.button.bind( "mouseup", function() {
- if ( self.options.preventFocusZoom ) {
- setTimeout(function() {
- $.mobile.zoom.enable( true );
- }, 0 );
- }
- });
- self.select.bind( "blur", function() {
- if ( self.options.preventFocusZoom ) {
- $.mobile.zoom.enable( true );
- }
- });
-
- },
-
- selected: function() {
- return this._selectOptions().filter( ":selected" );
- },
-
- selectedIndices: function() {
- var self = this;
-
- return this.selected().map(function() {
- return self._selectOptions().index( this );
- }).get();
- },
-
- setButtonText: function() {
- var self = this,
- selected = this.selected(),
- text = this.placeholder,
- span = $( document.createElement( "span" ) );
-
- this.button.children( "span" ).not( ".ui-li-count" ).remove().end().end().prepend( (function() {
- if ( selected.length ) {
- text = selected.map(function() {
- return $( this ).text();
- }).get().join( ", " );
- } else {
- text = self.placeholder;
- }
-
- if ( text ) {
- span.text( text );
- } else {
-
- // Set the contents to which we write as   to be XHTML compliant - see gh-6699
- span.html( " " );
- }
-
- // TODO possibly aggregate multiple select option classes
- return span
- .addClass( self.select.attr( "class" ) )
- .addClass( selected.attr( "class" ) )
- .removeClass( "ui-screen-hidden" );
- })());
- },
-
- setButtonCount: function() {
- var selected = this.selected();
-
- // multiple count inside button
- if ( this.isMultiple ) {
- this.buttonCount[ selected.length > 1 ? "show" : "hide" ]().text( selected.length );
- }
- },
-
- _handleKeydown: function( /* event */ ) {
- this._delay( "_refreshButton" );
- },
-
- _reset: function() {
- this.refresh();
- },
-
- _refreshButton: function() {
- this.setButtonText();
- this.setButtonCount();
- },
-
- refresh: function() {
- this._refreshButton();
- },
-
- // open and close preserved in native selects
- // to simplify users code when looping over selects
- open: $.noop,
- close: $.noop,
-
- disable: function() {
- this._setDisabled( true );
- this.button.addClass( "ui-state-disabled" );
- },
-
- enable: function() {
- this._setDisabled( false );
- this.button.removeClass( "ui-state-disabled" );
- }
-}, $.mobile.behaviors.formReset ) );
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.mobile.links = function( target ) {
-
- //links within content areas, tests included with page
- $( target )
- .find( "a" )
- .jqmEnhanceable()
- .filter( ":jqmData(rel='popup')[href][href!='']" )
- .each( function() {
- // Accessibility info for popups
- var element = this,
- idref = element.getAttribute( "href" ).substring( 1 );
-
- if ( idref ) {
- element.setAttribute( "aria-haspopup", true );
- element.setAttribute( "aria-owns", idref );
- element.setAttribute( "aria-expanded", false );
- }
- })
- .end()
- .not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
- .addClass( "ui-link" );
-
-};
-
-})( jQuery );
-
-
-(function( $, undefined ) {
-
-function fitSegmentInsideSegment( windowSize, segmentSize, offset, desired ) {
- var returnValue = desired;
-
- if ( windowSize < segmentSize ) {
- // Center segment if it's bigger than the window
- returnValue = offset + ( windowSize - segmentSize ) / 2;
- } else {
- // Otherwise center it at the desired coordinate while keeping it completely inside the window
- returnValue = Math.min( Math.max( offset, desired - segmentSize / 2 ), offset + windowSize - segmentSize );
- }
-
- return returnValue;
-}
-
-function getWindowCoordinates( theWindow ) {
- return {
- x: theWindow.scrollLeft(),
- y: theWindow.scrollTop(),
- cx: ( theWindow[ 0 ].innerWidth || theWindow.width() ),
- cy: ( theWindow[ 0 ].innerHeight || theWindow.height() )
- };
-}
-
-$.widget( "mobile.popup", {
- options: {
- wrapperClass: null,
- theme: null,
- overlayTheme: null,
- shadow: true,
- corners: true,
- transition: "none",
- positionTo: "origin",
- tolerance: null,
- closeLinkSelector: "a:jqmData(rel='back')",
- closeLinkEvents: "click.popup",
- navigateEvents: "navigate.popup",
- closeEvents: "navigate.popup pagebeforechange.popup",
- dismissible: true,
- enhanced: false,
-
- // NOTE Windows Phone 7 has a scroll position caching issue that
- // requires us to disable popup history management by default
- // https://github.com/jquery/jquery-mobile/issues/4784
- //
- // NOTE this option is modified in _create!
- history: !$.mobile.browser.oldIE
- },
-
- _create: function() {
- var theElement = this.element,
- myId = theElement.attr( "id" ),
- currentOptions = this.options;
-
- // We need to adjust the history option to be false if there's no AJAX nav.
- // We can't do it in the option declarations because those are run before
- // it is determined whether there shall be AJAX nav.
- currentOptions.history = currentOptions.history && $.mobile.ajaxEnabled && $.mobile.hashListeningEnabled;
-
- // Define instance variables
- $.extend( this, {
- _scrollTop: 0,
- _page: theElement.closest( ".ui-page" ),
- _ui: null,
- _fallbackTransition: "",
- _currentTransition: false,
- _prerequisites: null,
- _isOpen: false,
- _tolerance: null,
- _resizeData: null,
- _ignoreResizeTo: 0,
- _orientationchangeInProgress: false
- });
-
- if ( this._page.length === 0 ) {
- this._page = $( "body" );
- }
-
- if ( currentOptions.enhanced ) {
- this._ui = {
- container: theElement.parent(),
- screen: theElement.parent().prev(),
- placeholder: $( this.document[ 0 ].getElementById( myId + "-placeholder" ) )
- };
- } else {
- this._ui = this._enhance( theElement, myId );
- this._applyTransition( currentOptions.transition );
- }
- this
- ._setTolerance( currentOptions.tolerance )
- ._ui.focusElement = this._ui.container;
-
- // Event handlers
- this._on( this._ui.screen, { "vclick": "_eatEventAndClose" } );
- this._on( this.window, {
- orientationchange: $.proxy( this, "_handleWindowOrientationchange" ),
- resize: $.proxy( this, "_handleWindowResize" ),
- keyup: $.proxy( this, "_handleWindowKeyUp" )
- });
- this._on( this.document, { "focusin": "_handleDocumentFocusIn" } );
- },
-
- _enhance: function( theElement, myId ) {
- var currentOptions = this.options,
- wrapperClass = currentOptions.wrapperClass,
- ui = {
- screen: $( "<div class='ui-screen-hidden ui-popup-screen " +
- this._themeClassFromOption( "ui-overlay-", currentOptions.overlayTheme ) + "'></div>" ),
- placeholder: $( "<div style='display: none;'><!-- placeholder --></div>" ),
- container: $( "<div class='ui-popup-container ui-popup-hidden ui-popup-truncate" +
- ( wrapperClass ? ( " " + wrapperClass ) : "" ) + "'></div>" )
- },
- fragment = this.document[ 0 ].createDocumentFragment();
-
- fragment.appendChild( ui.screen[ 0 ] );
- fragment.appendChild( ui.container[ 0 ] );
-
- if ( myId ) {
- ui.screen.attr( "id", myId + "-screen" );
- ui.container.attr( "id", myId + "-popup" );
- ui.placeholder
- .attr( "id", myId + "-placeholder" )
- .html( "<!-- placeholder for " + myId + " -->" );
- }
-
- // Apply the proto
- this._page[ 0 ].appendChild( fragment );
- // Leave a placeholder where the element used to be
- ui.placeholder.insertAfter( theElement );
- theElement
- .detach()
- .addClass( "ui-popup " +
- this._themeClassFromOption( "ui-body-", currentOptions.theme ) + " " +
- ( currentOptions.shadow ? "ui-overlay-shadow " : "" ) +
- ( currentOptions.corners ? "ui-corner-all " : "" ) )
- .appendTo( ui.container );
-
- return ui;
- },
-
- _eatEventAndClose: function( theEvent ) {
- theEvent.preventDefault();
- theEvent.stopImmediatePropagation();
- if ( this.options.dismissible ) {
- this.close();
- }
- return false;
- },
-
- // Make sure the screen covers the entire document - CSS is sometimes not
- // enough to accomplish this.
- _resizeScreen: function() {
- var screen = this._ui.screen,
- popupHeight = this._ui.container.outerHeight( true ),
- screenHeight = screen.removeAttr( "style" ).height(),
-
- // Subtracting 1 here is necessary for an obscure Andrdoid 4.0 bug where
- // the browser hangs if the screen covers the entire document :/
- documentHeight = this.document.height() - 1;
-
- if ( screenHeight < documentHeight ) {
- screen.height( documentHeight );
- } else if ( popupHeight > screenHeight ) {
- screen.height( popupHeight );
- }
- },
-
- _handleWindowKeyUp: function( theEvent ) {
- if ( this._isOpen && theEvent.keyCode === $.mobile.keyCode.ESCAPE ) {
- return this._eatEventAndClose( theEvent );
- }
- },
-
- _expectResizeEvent: function() {
- var windowCoordinates = getWindowCoordinates( this.window );
-
- if ( this._resizeData ) {
- if ( windowCoordinates.x === this._resizeData.windowCoordinates.x &&
- windowCoordinates.y === this._resizeData.windowCoordinates.y &&
- windowCoordinates.cx === this._resizeData.windowCoordinates.cx &&
- windowCoordinates.cy === this._resizeData.windowCoordinates.cy ) {
- // timeout not refreshed
- return false;
- } else {
- // clear existing timeout - it will be refreshed below
- clearTimeout( this._resizeData.timeoutId );
- }
- }
-
- this._resizeData = {
- timeoutId: this._delay( "_resizeTimeout", 200 ),
- windowCoordinates: windowCoordinates
- };
-
- return true;
- },
-
- _resizeTimeout: function() {
- if ( this._isOpen ) {
- if ( !this._expectResizeEvent() ) {
- if ( this._ui.container.hasClass( "ui-popup-hidden" ) ) {
- // effectively rapid-open the popup while leaving the screen intact
- this._ui.container.removeClass( "ui-popup-hidden ui-popup-truncate" );
- this.reposition( { positionTo: "window" } );
- this._ignoreResizeEvents();
- }
-
- this._resizeScreen();
- this._resizeData = null;
- this._orientationchangeInProgress = false;
- }
- } else {
- this._resizeData = null;
- this._orientationchangeInProgress = false;
- }
- },
-
- _stopIgnoringResizeEvents: function() {
- this._ignoreResizeTo = 0;
- },
-
- _ignoreResizeEvents: function() {
- if ( this._ignoreResizeTo ) {
- clearTimeout( this._ignoreResizeTo );
- }
- this._ignoreResizeTo = this._delay( "_stopIgnoringResizeEvents", 1000 );
- },
-
- _handleWindowResize: function(/* theEvent */) {
- if ( this._isOpen && this._ignoreResizeTo === 0 ) {
- if ( ( this._expectResizeEvent() || this._orientationchangeInProgress ) &&
- !this._ui.container.hasClass( "ui-popup-hidden" ) ) {
- // effectively rapid-close the popup while leaving the screen intact
- this._ui.container
- .addClass( "ui-popup-hidden ui-popup-truncate" )
- .removeAttr( "style" );
- }
- }
- },
-
- _handleWindowOrientationchange: function(/* theEvent */) {
- if ( !this._orientationchangeInProgress && this._isOpen && this._ignoreResizeTo === 0 ) {
- this._expectResizeEvent();
- this._orientationchangeInProgress = true;
- }
- },
-
- // When the popup is open, attempting to focus on an element that is not a
- // child of the popup will redirect focus to the popup
- _handleDocumentFocusIn: function( theEvent ) {
- var target,
- targetElement = theEvent.target,
- ui = this._ui;
-
- if ( !this._isOpen ) {
- return;
- }
-
- if ( targetElement !== ui.container[ 0 ] ) {
- target = $( targetElement );
- if ( 0 === target.parents().filter( ui.container[ 0 ] ).length ) {
- $( this.document[ 0 ].activeElement ).one( "focus", function(/* theEvent */) {
- target.blur();
- });
- ui.focusElement.focus();
- theEvent.preventDefault();
- theEvent.stopImmediatePropagation();
- return false;
- } else if ( ui.focusElement[ 0 ] === ui.container[ 0 ] ) {
- ui.focusElement = target;
- }
- }
-
- this._ignoreResizeEvents();
- },
-
- _themeClassFromOption: function( prefix, value ) {
- return ( value ? ( value === "none" ? "" : ( prefix + value ) ) : ( prefix + "inherit" ) );
- },
-
- _applyTransition: function( value ) {
- if ( value ) {
- this._ui.container.removeClass( this._fallbackTransition );
- if ( value !== "none" ) {
- this._fallbackTransition = $.mobile._maybeDegradeTransition( value );
- if ( this._fallbackTransition === "none" ) {
- this._fallbackTransition = "";
- }
- this._ui.container.addClass( this._fallbackTransition );
- }
- }
-
- return this;
- },
-
- _setOptions: function( newOptions ) {
- var currentOptions = this.options,
- theElement = this.element,
- screen = this._ui.screen;
-
- if ( newOptions.wrapperClass !== undefined ) {
- this._ui.container
- .removeClass( currentOptions.wrapperClass )
- .addClass( newOptions.wrapperClass );
- }
-
- if ( newOptions.theme !== undefined ) {
- theElement
- .removeClass( this._themeClassFromOption( "ui-body-", currentOptions.theme ) )
- .addClass( this._themeClassFromOption( "ui-body-", newOptions.theme ) );
- }
-
- if ( newOptions.overlayTheme !== undefined ) {
- screen
- .removeClass( this._themeClassFromOption( "ui-overlay-", currentOptions.overlayTheme ) )
- .addClass( this._themeClassFromOption( "ui-overlay-", newOptions.overlayTheme ) );
-
- if ( this._isOpen ) {
- screen.addClass( "in" );
- }
- }
-
- if ( newOptions.shadow !== undefined ) {
- theElement.toggleClass( "ui-overlay-shadow", newOptions.shadow );
- }
-
- if ( newOptions.corners !== undefined ) {
- theElement.toggleClass( "ui-corner-all", newOptions.corners );
- }
-
- if ( newOptions.transition !== undefined ) {
- if ( !this._currentTransition ) {
- this._applyTransition( newOptions.transition );
- }
- }
-
- if ( newOptions.tolerance !== undefined ) {
- this._setTolerance( newOptions.tolerance );
- }
-
- if ( newOptions.disabled !== undefined ) {
- if ( newOptions.disabled ) {
- this.close();
- }
- }
-
- return this._super( newOptions );
- },
-
- _setTolerance: function( value ) {
- var tol = { t: 30, r: 15, b: 30, l: 15 },
- ar;
-
- if ( value !== undefined ) {
- ar = String( value ).split( "," );
-
- $.each( ar, function( idx, val ) { ar[ idx ] = parseInt( val, 10 ); } );
-
- switch( ar.length ) {
- // All values are to be the same
- case 1:
- if ( !isNaN( ar[ 0 ] ) ) {
- tol.t = tol.r = tol.b = tol.l = ar[ 0 ];
- }
- break;
-
- // The first value denotes top/bottom tolerance, and the second value denotes left/right tolerance
- case 2:
- if ( !isNaN( ar[ 0 ] ) ) {
- tol.t = tol.b = ar[ 0 ];
- }
- if ( !isNaN( ar[ 1 ] ) ) {
- tol.l = tol.r = ar[ 1 ];
- }
- break;
-
- // The array contains values in the order top, right, bottom, left
- case 4:
- if ( !isNaN( ar[ 0 ] ) ) {
- tol.t = ar[ 0 ];
- }
- if ( !isNaN( ar[ 1 ] ) ) {
- tol.r = ar[ 1 ];
- }
- if ( !isNaN( ar[ 2 ] ) ) {
- tol.b = ar[ 2 ];
- }
- if ( !isNaN( ar[ 3 ] ) ) {
- tol.l = ar[ 3 ];
- }
- break;
-
- default:
- break;
- }
- }
-
- this._tolerance = tol;
- return this;
- },
-
- _clampPopupWidth: function( infoOnly ) {
- var menuSize,
- windowCoordinates = getWindowCoordinates( this.window ),
- // rectangle within which the popup must fit
- rectangle = {
- x: this._tolerance.l,
- y: windowCoordinates.y + this._tolerance.t,
- cx: windowCoordinates.cx - this._tolerance.l - this._tolerance.r,
- cy: windowCoordinates.cy - this._tolerance.t - this._tolerance.b
- };
-
- if ( !infoOnly ) {
- // Clamp the width of the menu before grabbing its size
- this._ui.container.css( "max-width", rectangle.cx );
- }
-
- menuSize = {
- cx: this._ui.container.outerWidth( true ),
- cy: this._ui.container.outerHeight( true )
- };
-
- return { rc: rectangle, menuSize: menuSize };
- },
-
- _calculateFinalLocation: function( desired, clampInfo ) {
- var returnValue,
- rectangle = clampInfo.rc,
- menuSize = clampInfo.menuSize;
-
- // Center the menu over the desired coordinates, while not going outside
- // the window tolerances. This will center wrt. the window if the popup is
- // too large.
- returnValue = {
- left: fitSegmentInsideSegment( rectangle.cx, menuSize.cx, rectangle.x, desired.x ),
- top: fitSegmentInsideSegment( rectangle.cy, menuSize.cy, rectangle.y, desired.y )
- };
-
- // Make sure the top of the menu is visible
- returnValue.top = Math.max( 0, returnValue.top );
-
- // If the height of the menu is smaller than the height of the document
- // align the bottom with the bottom of the document
-
- returnValue.top -= Math.min( returnValue.top,
- Math.max( 0, returnValue.top + menuSize.cy - this.document.height() ) );
-
- return returnValue;
- },
-
- // Try and center the overlay over the given coordinates
- _placementCoords: function( desired ) {
- return this._calculateFinalLocation( desired, this._clampPopupWidth() );
- },
-
- _createPrerequisites: function( screenPrerequisite, containerPrerequisite, whenDone ) {
- var prerequisites,
- self = this;
-
- // It is important to maintain both the local variable prerequisites and
- // self._prerequisites. The local variable remains in the closure of the
- // functions which call the callbacks passed in. The comparison between the
- // local variable and self._prerequisites is necessary, because once a
- // function has been passed to .animationComplete() it will be called next
- // time an animation completes, even if that's not the animation whose end
- // the function was supposed to catch (for example, if an abort happens
- // during the opening animation, the .animationComplete handler is not
- // called for that animation anymore, but the handler remains attached, so
- // it is called the next time the popup is opened - making it stale.
- // Comparing the local variable prerequisites to the widget-level variable
- // self._prerequisites ensures that callbacks triggered by a stale
- // .animationComplete will be ignored.
-
- prerequisites = {
- screen: $.Deferred(),
- container: $.Deferred()
- };
-
- prerequisites.screen.then( function() {
- if ( prerequisites === self._prerequisites ) {
- screenPrerequisite();
- }
- });
-
- prerequisites.container.then( function() {
- if ( prerequisites === self._prerequisites ) {
- containerPrerequisite();
- }
- });
-
- $.when( prerequisites.screen, prerequisites.container ).done( function() {
- if ( prerequisites === self._prerequisites ) {
- self._prerequisites = null;
- whenDone();
- }
- });
-
- self._prerequisites = prerequisites;
- },
-
- _animate: function( args ) {
- // NOTE before removing the default animation of the screen
- // this had an animate callback that would resolve the deferred
- // now the deferred is resolved immediately
- // TODO remove the dependency on the screen deferred
- this._ui.screen
- .removeClass( args.classToRemove )
- .addClass( args.screenClassToAdd );
-
- args.prerequisites.screen.resolve();
-
- if ( args.transition && args.transition !== "none" ) {
- if ( args.applyTransition ) {
- this._applyTransition( args.transition );
- }
- if ( this._fallbackTransition ) {
- this._ui.container
- .addClass( args.containerClassToAdd )
- .removeClass( args.classToRemove )
- .animationComplete( $.proxy( args.prerequisites.container, "resolve" ) );
- return;
- }
- }
- this._ui.container.removeClass( args.classToRemove );
- args.prerequisites.container.resolve();
- },
-
- // The desired coordinates passed in will be returned untouched if no reference element can be identified via
- // desiredPosition.positionTo. Nevertheless, this function ensures that its return value always contains valid
- // x and y coordinates by specifying the center middle of the window if the coordinates are absent.
- // options: { x: coordinate, y: coordinate, positionTo: string: "origin", "window", or jQuery selector
- _desiredCoords: function( openOptions ) {
- var offset,
- dst = null,
- windowCoordinates = getWindowCoordinates( this.window ),
- x = openOptions.x,
- y = openOptions.y,
- pTo = openOptions.positionTo;
-
- // Establish which element will serve as the reference
- if ( pTo && pTo !== "origin" ) {
- if ( pTo === "window" ) {
- x = windowCoordinates.cx / 2 + windowCoordinates.x;
- y = windowCoordinates.cy / 2 + windowCoordinates.y;
- } else {
- try {
- dst = $( pTo );
- } catch( err ) {
- dst = null;
- }
- if ( dst ) {
- dst.filter( ":visible" );
- if ( dst.length === 0 ) {
- dst = null;
- }
- }
- }
- }
-
- // If an element was found, center over it
- if ( dst ) {
- offset = dst.offset();
- x = offset.left + dst.outerWidth() / 2;
- y = offset.top + dst.outerHeight() / 2;
- }
-
- // Make sure x and y are valid numbers - center over the window
- if ( $.type( x ) !== "number" || isNaN( x ) ) {
- x = windowCoordinates.cx / 2 + windowCoordinates.x;
- }
- if ( $.type( y ) !== "number" || isNaN( y ) ) {
- y = windowCoordinates.cy / 2 + windowCoordinates.y;
- }
-
- return { x: x, y: y };
- },
-
- _reposition: function( openOptions ) {
- // We only care about position-related parameters for repositioning
- openOptions = {
- x: openOptions.x,
- y: openOptions.y,
- positionTo: openOptions.positionTo
- };
- this._trigger( "beforeposition", undefined, openOptions );
- this._ui.container.offset( this._placementCoords( this._desiredCoords( openOptions ) ) );
- },
-
- reposition: function( openOptions ) {
- if ( this._isOpen ) {
- this._reposition( openOptions );
- }
- },
-
- _openPrerequisitesComplete: function() {
- var id = this.element.attr( "id" );
-
- this._ui.container.addClass( "ui-popup-active" );
- this._isOpen = true;
- this._resizeScreen();
- this._ui.container.attr( "tabindex", "0" ).focus();
- this._ignoreResizeEvents();
- if ( id ) {
- this.document.find( "[aria-haspopup='true'][aria-owns='" + id + "']" ).attr( "aria-expanded", true );
- }
- this._trigger( "afteropen" );
- },
-
- _open: function( options ) {
- var openOptions = $.extend( {}, this.options, options ),
- // TODO move blacklist to private method
- androidBlacklist = ( function() {
- var ua = navigator.userAgent,
- // Rendering engine is Webkit, and capture major version
- wkmatch = ua.match( /AppleWebKit\/([0-9\.]+)/ ),
- wkversion = !!wkmatch && wkmatch[ 1 ],
- androidmatch = ua.match( /Android (\d+(?:\.\d+))/ ),
- andversion = !!androidmatch && androidmatch[ 1 ],
- chromematch = ua.indexOf( "Chrome" ) > -1;
-
- // Platform is Android, WebKit version is greater than 534.13 ( Android 3.2.1 ) and not Chrome.
- if ( androidmatch !== null && andversion === "4.0" && wkversion && wkversion > 534.13 && !chromematch ) {
- return true;
- }
- return false;
- }());
-
- // Count down to triggering "popupafteropen" - we have two prerequisites:
- // 1. The popup window animation completes (container())
- // 2. The screen opacity animation completes (screen())
- this._createPrerequisites(
- $.noop,
- $.noop,
- $.proxy( this, "_openPrerequisitesComplete" ) );
-
- this._currentTransition = openOptions.transition;
- this._applyTransition( openOptions.transition );
-
- this._ui.screen.removeClass( "ui-screen-hidden" );
- this._ui.container.removeClass( "ui-popup-truncate" );
-
- // Give applications a chance to modify the contents of the container before it appears
- this._reposition( openOptions );
-
- this._ui.container.removeClass( "ui-popup-hidden" );
-
- if ( this.options.overlayTheme && androidBlacklist ) {
- /* TODO: The native browser on Android 4.0.X ("Ice Cream Sandwich") suffers from an issue where the popup overlay appears to be z-indexed above the popup itself when certain other styles exist on the same page -- namely, any element set to `position: fixed` and certain types of input. These issues are reminiscent of previously uncovered bugs in older versions of Android's native browser: https://github.com/scottjehl/Device-Bugs/issues/3
- This fix closes the following bugs ( I use "closes" with reluctance, and stress that this issue should be revisited as soon as possible ):
- https://github.com/jquery/jquery-mobile/issues/4816
- https://github.com/jquery/jquery-mobile/issues/4844
- https://github.com/jquery/jquery-mobile/issues/4874
- */
-
- // TODO sort out why this._page isn't working
- this.element.closest( ".ui-page" ).addClass( "ui-popup-open" );
- }
- this._animate({
- additionalCondition: true,
- transition: openOptions.transition,
- classToRemove: "",
- screenClassToAdd: "in",
- containerClassToAdd: "in",
- applyTransition: false,
- prerequisites: this._prerequisites
- });
- },
-
- _closePrerequisiteScreen: function() {
- this._ui.screen
- .removeClass( "out" )
- .addClass( "ui-screen-hidden" );
- },
-
- _closePrerequisiteContainer: function() {
- this._ui.container
- .removeClass( "reverse out" )
- .addClass( "ui-popup-hidden ui-popup-truncate" )
- .removeAttr( "style" );
- },
-
- _closePrerequisitesDone: function() {
- var container = this._ui.container,
- id = this.element.attr( "id" );
-
- container.removeAttr( "tabindex" );
-
- // remove the global mutex for popups
- $.mobile.popup.active = undefined;
-
- // Blur elements inside the container, including the container
- $( ":focus", container[ 0 ] ).add( container[ 0 ] ).blur();
-
- if ( id ) {
- this.document.find( "[aria-haspopup='true'][aria-owns='" + id + "']" ).attr( "aria-expanded", false );
- }
-
- // alert users that the popup is closed
- this._trigger( "afterclose" );
- },
-
- _close: function( immediate ) {
- this._ui.container.removeClass( "ui-popup-active" );
- this._page.removeClass( "ui-popup-open" );
-
- this._isOpen = false;
-
- // Count down to triggering "popupafterclose" - we have two prerequisites:
- // 1. The popup window reverse animation completes (container())
- // 2. The screen opacity animation completes (screen())
- this._createPrerequisites(
- $.proxy( this, "_closePrerequisiteScreen" ),
- $.proxy( this, "_closePrerequisiteContainer" ),
- $.proxy( this, "_closePrerequisitesDone" ) );
-
- this._animate( {
- additionalCondition: this._ui.screen.hasClass( "in" ),
- transition: ( immediate ? "none" : ( this._currentTransition ) ),
- classToRemove: "in",
- screenClassToAdd: "out",
- containerClassToAdd: "reverse out",
- applyTransition: true,
- prerequisites: this._prerequisites
- });
- },
-
- _unenhance: function() {
- if ( this.options.enhanced ) {
- return;
- }
-
- // Put the element back to where the placeholder was and remove the "ui-popup" class
- this._setOptions( { theme: $.mobile.popup.prototype.options.theme } );
- this.element
- // Cannot directly insertAfter() - we need to detach() first, because
- // insertAfter() will do nothing if the payload div was not attached
- // to the DOM at the time the widget was created, and so the payload
- // will remain inside the container even after we call insertAfter().
- // If that happens and we remove the container a few lines below, we
- // will cause an infinite recursion - #5244
- .detach()
- .insertAfter( this._ui.placeholder )
- .removeClass( "ui-popup ui-overlay-shadow ui-corner-all ui-body-inherit" );
- this._ui.screen.remove();
- this._ui.container.remove();
- this._ui.placeholder.remove();
- },
-
- _destroy: function() {
- if ( $.mobile.popup.active === this ) {
- this.element.one( "popupafterclose", $.proxy( this, "_unenhance" ) );
- this.close();
- } else {
- this._unenhance();
- }
-
- return this;
- },
-
- _closePopup: function( theEvent, data ) {
- var parsedDst, toUrl,
- currentOptions = this.options,
- immediate = false;
-
- if ( ( theEvent && theEvent.isDefaultPrevented() ) || $.mobile.popup.active !== this ) {
- return;
- }
-
- // restore location on screen
- window.scrollTo( 0, this._scrollTop );
-
- if ( theEvent && theEvent.type === "pagebeforechange" && data ) {
- // Determine whether we need to rapid-close the popup, or whether we can
- // take the time to run the closing transition
- if ( typeof data.toPage === "string" ) {
- parsedDst = data.toPage;
- } else {
- parsedDst = data.toPage.jqmData( "url" );
- }
- parsedDst = $.mobile.path.parseUrl( parsedDst );
- toUrl = parsedDst.pathname + parsedDst.search + parsedDst.hash;
-
- if ( this._myUrl !== $.mobile.path.makeUrlAbsolute( toUrl ) ) {
- // Going to a different page - close immediately
- immediate = true;
- } else {
- theEvent.preventDefault();
- }
- }
-
- // remove nav bindings
- this.window.off( currentOptions.closeEvents );
- // unbind click handlers added when history is disabled
- this.element.undelegate( currentOptions.closeLinkSelector, currentOptions.closeLinkEvents );
-
- this._close( immediate );
- },
-
- // any navigation event after a popup is opened should close the popup
- // NOTE the pagebeforechange is bound to catch navigation events that don't
- // alter the url (eg, dialogs from popups)
- _bindContainerClose: function() {
- this.window
- .on( this.options.closeEvents, $.proxy( this, "_closePopup" ) );
- },
-
- widget: function() {
- return this._ui.container;
- },
-
- // TODO no clear deliniation of what should be here and
- // what should be in _open. Seems to be "visual" vs "history" for now
- open: function( options ) {
- var url, hashkey, activePage, currentIsDialog, hasHash, urlHistory,
- self = this,
- currentOptions = this.options;
-
- // make sure open is idempotent
- if ( $.mobile.popup.active || currentOptions.disabled ) {
- return this;
- }
-
- // set the global popup mutex
- $.mobile.popup.active = this;
- this._scrollTop = this.window.scrollTop();
-
- // if history alteration is disabled close on navigate events
- // and leave the url as is
- if ( !( currentOptions.history ) ) {
- self._open( options );
- self._bindContainerClose();
-
- // When histoy is disabled we have to grab the data-rel
- // back link clicks so we can close the popup instead of
- // relying on history to do it for us
- self.element
- .delegate( currentOptions.closeLinkSelector, currentOptions.closeLinkEvents, function( theEvent ) {
- self.close();
- theEvent.preventDefault();
- });
-
- return this;
- }
-
- // cache some values for min/readability
- urlHistory = $.mobile.navigate.history;
- hashkey = $.mobile.dialogHashKey;
- activePage = $.mobile.activePage;
- currentIsDialog = ( activePage ? activePage.hasClass( "ui-dialog" ) : false );
- this._myUrl = url = urlHistory.getActive().url;
- hasHash = ( url.indexOf( hashkey ) > -1 ) && !currentIsDialog && ( urlHistory.activeIndex > 0 );
-
- if ( hasHash ) {
- self._open( options );
- self._bindContainerClose();
- return this;
- }
-
- // if the current url has no dialog hash key proceed as normal
- // otherwise, if the page is a dialog simply tack on the hash key
- if ( url.indexOf( hashkey ) === -1 && !currentIsDialog ) {
- url = url + (url.indexOf( "#" ) > -1 ? hashkey : "#" + hashkey);
- } else {
- url = $.mobile.path.parseLocation().hash + hashkey;
- }
-
- // Tack on an extra hashkey if this is the first page and we've just reconstructed the initial hash
- if ( urlHistory.activeIndex === 0 && url === urlHistory.initialDst ) {
- url += hashkey;
- }
-
- // swallow the the initial navigation event, and bind for the next
- this.window.one( "beforenavigate", function( theEvent ) {
- theEvent.preventDefault();
- self._open( options );
- self._bindContainerClose();
- });
-
- this.urlAltered = true;
- $.mobile.navigate( url, { role: "dialog" } );
-
- return this;
- },
-
- close: function() {
- // make sure close is idempotent
- if ( $.mobile.popup.active !== this ) {
- return this;
- }
-
- this._scrollTop = this.window.scrollTop();
-
- if ( this.options.history && this.urlAltered ) {
- $.mobile.back();
- this.urlAltered = false;
- } else {
- // simulate the nav bindings having fired
- this._closePopup();
- }
-
- return this;
- }
-});
-
-// TODO this can be moved inside the widget
-$.mobile.popup.handleLink = function( $link ) {
- var offset,
- path = $.mobile.path,
-
- // NOTE make sure to get only the hash from the href because ie7 (wp7)
- // returns the absolute href in this case ruining the element selection
- popup = $( path.hashToSelector( path.parseUrl( $link.attr( "href" ) ).hash ) ).first();
-
- if ( popup.length > 0 && popup.data( "mobile-popup" ) ) {
- offset = $link.offset();
- popup.popup( "open", {
- x: offset.left + $link.outerWidth() / 2,
- y: offset.top + $link.outerHeight() / 2,
- transition: $link.jqmData( "transition" ),
- positionTo: $link.jqmData( "position-to" )
- });
- }
-
- //remove after delay
- setTimeout( function() {
- $link.removeClass( $.mobile.activeBtnClass );
- }, 300 );
-};
-
-// TODO move inside _create
-$.mobile.document.on( "pagebeforechange", function( theEvent, data ) {
- if ( data.options.role === "popup" ) {
- $.mobile.popup.handleLink( data.options.link );
- theEvent.preventDefault();
- }
-});
-
-})( jQuery );
-
-/*
-* custom "selectmenu" plugin
-*/
-
-(function( $, undefined ) {
-
-var unfocusableItemSelector = ".ui-disabled,.ui-state-disabled,.ui-li-divider,.ui-screen-hidden,:jqmData(role='placeholder')",
- goToAdjacentItem = function( item, target, direction ) {
- var adjacent = item[ direction + "All" ]()
- .not( unfocusableItemSelector )
- .first();
-
- // if there's a previous option, focus it
- if ( adjacent.length ) {
- target
- .blur()
- .attr( "tabindex", "-1" );
-
- adjacent.find( "a" ).first().focus();
- }
- };
-
-$.widget( "mobile.selectmenu", $.mobile.selectmenu, {
- _create: function() {
- var o = this.options;
-
- // Custom selects cannot exist inside popups, so revert the "nativeMenu"
- // option to true if a parent is a popup
- o.nativeMenu = o.nativeMenu || ( this.element.parents( ":jqmData(role='popup'),:mobile-popup" ).length > 0 );
-
- return this._super();
- },
-
- _handleSelectFocus: function() {
- this.element.blur();
- this.button.focus();
- },
-
- _handleKeydown: function( event ) {
- this._super( event );
- this._handleButtonVclickKeydown( event );
- },
-
- _handleButtonVclickKeydown: function( event ) {
- if ( this.options.disabled || this.isOpen ) {
- return;
- }
-
- if (event.type === "vclick" ||
- event.keyCode && (event.keyCode === $.mobile.keyCode.ENTER || event.keyCode === $.mobile.keyCode.SPACE)) {
-
- this._decideFormat();
- if ( this.menuType === "overlay" ) {
- this.button.attr( "href", "#" + this.popupId ).attr( "data-" + ( $.mobile.ns || "" ) + "rel", "popup" );
- } else {
- this.button.attr( "href", "#" + this.dialogId ).attr( "data-" + ( $.mobile.ns || "" ) + "rel", "dialog" );
- }
- this.isOpen = true;
- // Do not prevent default, so the navigation may have a chance to actually open the chosen format
- }
- },
-
- _handleListFocus: function( e ) {
- var params = ( e.type === "focusin" ) ?
- { tabindex: "0", event: "vmouseover" }:
- { tabindex: "-1", event: "vmouseout" };
-
- $( e.target )
- .attr( "tabindex", params.tabindex )
- .trigger( params.event );
- },
-
- _handleListKeydown: function( event ) {
- var target = $( event.target ),
- li = target.closest( "li" );
-
- // switch logic based on which key was pressed
- switch ( event.keyCode ) {
- // up or left arrow keys
- case 38:
- goToAdjacentItem( li, target, "prev" );
- return false;
- // down or right arrow keys
- case 40:
- goToAdjacentItem( li, target, "next" );
- return false;
- // If enter or space is pressed, trigger click
- case 13:
- case 32:
- target.trigger( "click" );
- return false;
- }
- },
-
- _handleMenuPageHide: function() {
- // TODO centralize page removal binding / handling in the page plugin.
- // Suggestion from @jblas to do refcounting
- //
- // TODO extremely confusing dependency on the open method where the pagehide.remove
- // bindings are stripped to prevent the parent page from disappearing. The way
- // we're keeping pages in the DOM right now sucks
- //
- // rebind the page remove that was unbound in the open function
- // to allow for the parent page removal from actions other than the use
- // of a dialog sized custom select
- //
- // doing this here provides for the back button on the custom select dialog
- this.thisPage.page( "bindRemove" );
- },
-
- _handleHeaderCloseClick: function() {
- if ( this.menuType === "overlay" ) {
- this.close();
- return false;
- }
- },
-
- build: function() {
- var selectId, popupId, dialogId, label, thisPage, isMultiple, menuId,
- themeAttr, overlayTheme, overlayThemeAttr, dividerThemeAttr,
- menuPage, listbox, list, header, headerTitle, menuPageContent,
- menuPageClose, headerClose, self,
- o = this.options;
-
- if ( o.nativeMenu ) {
- return this._super();
- }
-
- self = this;
- selectId = this.selectId;
- popupId = selectId + "-listbox";
- dialogId = selectId + "-dialog";
- label = this.label;
- thisPage = this.element.closest( ".ui-page" );
- isMultiple = this.element[ 0 ].multiple;
- menuId = selectId + "-menu";
- themeAttr = o.theme ? ( " data-" + $.mobile.ns + "theme='" + o.theme + "'" ) : "";
- overlayTheme = o.overlayTheme || o.theme || null;
- overlayThemeAttr = overlayTheme ? ( " data-" + $.mobile.ns +
- "overlay-theme='" + overlayTheme + "'" ) : "";
- dividerThemeAttr = ( o.dividerTheme && isMultiple ) ? ( " data-" + $.mobile.ns + "divider-theme='" + o.dividerTheme + "'" ) : "";
- menuPage = $( "<div data-" + $.mobile.ns + "role='dialog' class='ui-selectmenu' id='" + dialogId + "'" + themeAttr + overlayThemeAttr + ">" +
- "<div data-" + $.mobile.ns + "role='header'>" +
- "<div class='ui-title'>" + label.getEncodedText() + "</div>"+
- "</div>"+
- "<div data-" + $.mobile.ns + "role='content'></div>"+
- "</div>" );
- listbox = $( "<div id='" + popupId + "' class='ui-selectmenu'></div>" ).insertAfter( this.select ).popup({ theme: o.overlayTheme });
- list = $( "<ul class='ui-selectmenu-list' id='" + menuId + "' role='listbox' aria-labelledby='" + this.buttonId + "'" + themeAttr + dividerThemeAttr + "></ul>" ).appendTo( listbox );
- header = $( "<div class='ui-header ui-bar-" + ( o.theme ? o.theme : "inherit" ) + "'></div>" ).prependTo( listbox );
- headerTitle = $( "<h1 class='ui-title'></h1>" ).appendTo( header );
-
- if ( this.isMultiple ) {
- headerClose = $( "<a>", {
- "role": "button",
- "text": o.closeText,
- "href": "#",
- "class": "ui-btn ui-corner-all ui-btn-left ui-btn-icon-notext ui-icon-delete"
- }).appendTo( header );
- }
-
- $.extend( this, {
- selectId: selectId,
- menuId: menuId,
- popupId: popupId,
- dialogId: dialogId,
- thisPage: thisPage,
- menuPage: menuPage,
- label: label,
- isMultiple: isMultiple,
- theme: o.theme,
- listbox: listbox,
- list: list,
- header: header,
- headerTitle: headerTitle,
- headerClose: headerClose,
- menuPageContent: menuPageContent,
- menuPageClose: menuPageClose,
- placeholder: ""
- });
-
- // Create list from select, update state
- this.refresh();
-
- if ( this._origTabIndex === undefined ) {
- // Map undefined to false, because this._origTabIndex === undefined
- // indicates that we have not yet checked whether the select has
- // originally had a tabindex attribute, whereas false indicates that
- // we have checked the select for such an attribute, and have found
- // none present.
- this._origTabIndex = ( this.select[ 0 ].getAttribute( "tabindex" ) === null ) ? false : this.select.attr( "tabindex" );
- }
- this.select.attr( "tabindex", "-1" );
- this._on( this.select, { focus : "_handleSelectFocus" } );
-
- // Button events
- this._on( this.button, {
- vclick: "_handleButtonVclickKeydown"
- });
-
- // Events for list items
- this.list.attr( "role", "listbox" );
- this._on( this.list, {
- focusin : "_handleListFocus",
- focusout : "_handleListFocus",
- keydown: "_handleListKeydown"
- });
- this.list
- .delegate( "li:not(.ui-disabled,.ui-state-disabled,.ui-li-divider)", "click", function( event ) {
-
- // index of option tag to be selected
- var oldIndex = self.select[ 0 ].selectedIndex,
- newIndex = $.mobile.getAttribute( this, "option-index" ),
- option = self._selectOptions().eq( newIndex )[ 0 ];
-
- // toggle selected status on the tag for multi selects
- option.selected = self.isMultiple ? !option.selected : true;
-
- // toggle checkbox class for multiple selects
- if ( self.isMultiple ) {
- $( this ).find( "a" )
- .toggleClass( "ui-checkbox-on", option.selected )
- .toggleClass( "ui-checkbox-off", !option.selected );
- }
-
- // trigger change if value changed
- if ( self.isMultiple || oldIndex !== newIndex ) {
- self.select.trigger( "change" );
- }
-
- // hide custom select for single selects only - otherwise focus clicked item
- // We need to grab the clicked item the hard way, because the list may have been rebuilt
- if ( self.isMultiple ) {
- self.list.find( "li:not(.ui-li-divider)" ).eq( newIndex )
- .find( "a" ).first().focus();
- }
- else {
- self.close();
- }
-
- event.preventDefault();
- });
-
- // button refocus ensures proper height calculation
- // by removing the inline style and ensuring page inclusion
- this._on( this.menuPage, { pagehide: "_handleMenuPageHide" } );
-
- // Events on the popup
- this._on( this.listbox, { popupafterclose: "close" } );
-
- // Close button on small overlays
- if ( this.isMultiple ) {
- this._on( this.headerClose, { click: "_handleHeaderCloseClick" } );
- }
-
- return this;
- },
-
- _isRebuildRequired: function() {
- var list = this.list.find( "li" ),
- options = this._selectOptions().not( ".ui-screen-hidden" );
-
- // TODO exceedingly naive method to determine difference
- // ignores value changes etc in favor of a forcedRebuild
- // from the user in the refresh method
- return options.text() !== list.text();
- },
-
- selected: function() {
- return this._selectOptions().filter( ":selected:not( :jqmData(placeholder='true') )" );
- },
-
- refresh: function( force ) {
- var self, indices;
-
- if ( this.options.nativeMenu ) {
- return this._super( force );
- }
-
- self = this;
- if ( force || this._isRebuildRequired() ) {
- self._buildList();
- }
-
- indices = this.selectedIndices();
-
- self.setButtonText();
- self.setButtonCount();
-
- self.list.find( "li:not(.ui-li-divider)" )
- .find( "a" ).removeClass( $.mobile.activeBtnClass ).end()
- .attr( "aria-selected", false )
- .each(function( i ) {
-
- if ( $.inArray( i, indices ) > -1 ) {
- var item = $( this );
-
- // Aria selected attr
- item.attr( "aria-selected", true );
-
- // Multiple selects: add the "on" checkbox state to the icon
- if ( self.isMultiple ) {
- item.find( "a" ).removeClass( "ui-checkbox-off" ).addClass( "ui-checkbox-on" );
- } else {
- if ( item.hasClass( "ui-screen-hidden" ) ) {
- item.next().find( "a" ).addClass( $.mobile.activeBtnClass );
- } else {
- item.find( "a" ).addClass( $.mobile.activeBtnClass );
- }
- }
- }
- });
- },
-
- close: function() {
- if ( this.options.disabled || !this.isOpen ) {
- return;
- }
-
- var self = this;
-
- if ( self.menuType === "page" ) {
- self.menuPage.dialog( "close" );
- self.list.appendTo( self.listbox );
- } else {
- self.listbox.popup( "close" );
- }
-
- self._focusButton();
- // allow the dialog to be closed again
- self.isOpen = false;
- },
-
- open: function() {
- this.button.click();
- },
-
- _focusMenuItem: function() {
- var selector = this.list.find( "a." + $.mobile.activeBtnClass );
- if ( selector.length === 0 ) {
- selector = this.list.find( "li:not(" + unfocusableItemSelector + ") a.ui-btn" );
- }
- selector.first().focus();
- },
-
- _decideFormat: function() {
- var self = this,
- $window = this.window,
- selfListParent = self.list.parent(),
- menuHeight = selfListParent.outerHeight(),
- scrollTop = $window.scrollTop(),
- btnOffset = self.button.offset().top,
- screenHeight = $window.height();
-
- if ( menuHeight > screenHeight - 80 || !$.support.scrollTop ) {
-
- self.menuPage.appendTo( $.mobile.pageContainer ).page();
- self.menuPageContent = self.menuPage.find( ".ui-content" );
- self.menuPageClose = self.menuPage.find( ".ui-header a" );
-
- // prevent the parent page from being removed from the DOM,
- // otherwise the results of selecting a list item in the dialog
- // fall into a black hole
- self.thisPage.unbind( "pagehide.remove" );
-
- //for WebOS/Opera Mini (set lastscroll using button offset)
- if ( scrollTop === 0 && btnOffset > screenHeight ) {
- self.thisPage.one( "pagehide", function() {
- $( this ).jqmData( "lastScroll", btnOffset );
- });
- }
-
- self.menuPage.one( {
- pageshow: $.proxy( this, "_focusMenuItem" ),
- pagehide: $.proxy( this, "close" )
- });
-
- self.menuType = "page";
- self.menuPageContent.append( self.list );
- self.menuPage.find( "div .ui-title" ).text( self.label.text() );
- } else {
- self.menuType = "overlay";
-
- self.listbox.one( { popupafteropen: $.proxy( this, "_focusMenuItem" ) } );
- }
- },
-
- _buildList: function() {
- var self = this,
- o = this.options,
- placeholder = this.placeholder,
- needPlaceholder = true,
- dataIcon = "false",
- $options, numOptions, select,
- dataPrefix = "data-" + $.mobile.ns,
- dataIndexAttr = dataPrefix + "option-index",
- dataIconAttr = dataPrefix + "icon",
- dataRoleAttr = dataPrefix + "role",
- dataPlaceholderAttr = dataPrefix + "placeholder",
- fragment = document.createDocumentFragment(),
- isPlaceholderItem = false,
- optGroup,
- i,
- option, $option, parent, text, anchor, classes,
- optLabel, divider, item;
-
- self.list.empty().filter( ".ui-listview" ).listview( "destroy" );
- $options = this._selectOptions();
- numOptions = $options.length;
- select = this.select[ 0 ];
-
- for ( i = 0; i < numOptions;i++, isPlaceholderItem = false) {
- option = $options[i];
- $option = $( option );
-
- // Do not create options based on ui-screen-hidden select options
- if ( $option.hasClass( "ui-screen-hidden" ) ) {
- continue;
- }
-
- parent = option.parentNode;
- text = $option.text();
- anchor = document.createElement( "a" );
- classes = [];
-
- anchor.setAttribute( "href", "#" );
- anchor.appendChild( document.createTextNode( text ) );
-
- // Are we inside an optgroup?
- if ( parent !== select && parent.nodeName.toLowerCase() === "optgroup" ) {
- optLabel = parent.getAttribute( "label" );
- if ( optLabel !== optGroup ) {
- divider = document.createElement( "li" );
- divider.setAttribute( dataRoleAttr, "list-divider" );
- divider.setAttribute( "role", "option" );
- divider.setAttribute( "tabindex", "-1" );
- divider.appendChild( document.createTextNode( optLabel ) );
- fragment.appendChild( divider );
- optGroup = optLabel;
- }
- }
-
- if ( needPlaceholder && ( !option.getAttribute( "value" ) || text.length === 0 || $option.jqmData( "placeholder" ) ) ) {
- needPlaceholder = false;
- isPlaceholderItem = true;
-
- // If we have identified a placeholder, record the fact that it was
- // us who have added the placeholder to the option and mark it
- // retroactively in the select as well
- if ( null === option.getAttribute( dataPlaceholderAttr ) ) {
- this._removePlaceholderAttr = true;
- }
- option.setAttribute( dataPlaceholderAttr, true );
- if ( o.hidePlaceholderMenuItems ) {
- classes.push( "ui-screen-hidden" );
- }
- if ( placeholder !== text ) {
- placeholder = self.placeholder = text;
- }
- }
-
- item = document.createElement( "li" );
- if ( option.disabled ) {
- classes.push( "ui-state-disabled" );
- item.setAttribute( "aria-disabled", true );
- }
- item.setAttribute( dataIndexAttr, i );
- item.setAttribute( dataIconAttr, dataIcon );
- if ( isPlaceholderItem ) {
- item.setAttribute( dataPlaceholderAttr, true );
- }
- item.className = classes.join( " " );
- item.setAttribute( "role", "option" );
- anchor.setAttribute( "tabindex", "-1" );
- if ( this.isMultiple ) {
- $( anchor ).addClass( "ui-btn ui-checkbox-off ui-btn-icon-right" );
- }
-
- item.appendChild( anchor );
- fragment.appendChild( item );
- }
-
- self.list[0].appendChild( fragment );
-
- // Hide header if it's not a multiselect and there's no placeholder
- if ( !this.isMultiple && !placeholder.length ) {
- this.header.addClass( "ui-screen-hidden" );
- } else {
- this.headerTitle.text( this.placeholder );
- }
-
- // Now populated, create listview
- self.list.listview();
- },
-
- _button: function() {
- return this.options.nativeMenu ?
- this._super() :
- $( "<a>", {
- "href": "#",
- "role": "button",
- // TODO value is undefined at creation
- "id": this.buttonId,
- "aria-haspopup": "true",
-
- // TODO value is undefined at creation
- "aria-owns": this.menuId
- });
- },
-
- _destroy: function() {
-
- if ( !this.options.nativeMenu ) {
- this.close();
-
- // Restore the tabindex attribute to its original value
- if ( this._origTabIndex !== undefined ) {
- if ( this._origTabIndex !== false ) {
- this.select.attr( "tabindex", this._origTabIndex );
- } else {
- this.select.removeAttr( "tabindex" );
- }
- }
-
- // Remove the placeholder attribute if we were the ones to add it
- if ( this._removePlaceholderAttr ) {
- this._selectOptions().removeAttr( "data-" + $.mobile.ns + "placeholder" );
- }
-
- // Remove the popup
- this.listbox.remove();
-
- // Remove the dialog
- this.menuPage.remove();
- }
-
- // Chain up
- this._super();
- }
-});
-
-})( jQuery );
-
-
-// buttonMarkup is deprecated as of 1.4.0 and will be removed in 1.5.0.
-
-(function( $, undefined ) {
-
-// General policy: Do not access data-* attributes except during enhancement.
-// In all other cases we determine the state of the button exclusively from its
-// className. That's why optionsToClasses expects a full complement of options,
-// and the jQuery plugin completes the set of options from the default values.
-
-// Map classes to buttonMarkup boolean options - used in classNameToOptions()
-var reverseBoolOptionMap = {
- "ui-shadow" : "shadow",
- "ui-corner-all" : "corners",
- "ui-btn-inline" : "inline",
- "ui-shadow-icon" : "iconshadow", /* TODO: Remove in 1.5 */
- "ui-mini" : "mini"
- },
- getAttrFixed = function() {
- var ret = $.mobile.getAttribute.apply( this, arguments );
-
- return ( ret == null ? undefined : ret );
- },
- capitalLettersRE = /[A-Z]/g;
-
-// optionsToClasses:
-// @options: A complete set of options to convert to class names.
-// @existingClasses: extra classes to add to the result
-//
-// Converts @options to buttonMarkup classes and returns the result as an array
-// that can be converted to an element's className with .join( " " ). All
-// possible options must be set inside @options. Use $.fn.buttonMarkup.defaults
-// to get a complete set and use $.extend to override your choice of options
-// from that set.
-function optionsToClasses( options, existingClasses ) {
- var classes = existingClasses ? existingClasses : [];
-
- // Add classes to the array - first ui-btn
- classes.push( "ui-btn" );
-
- // If there is a theme
- if ( options.theme ) {
- classes.push( "ui-btn-" + options.theme );
- }
-
- // If there's an icon, add the icon-related classes
- if ( options.icon ) {
- classes = classes.concat([
- "ui-icon-" + options.icon,
- "ui-btn-icon-" + options.iconpos
- ]);
- if ( options.iconshadow ) {
- classes.push( "ui-shadow-icon" ); /* TODO: Remove in 1.5 */
- }
- }
-
- // Add the appropriate class for each boolean option
- if ( options.inline ) {
- classes.push( "ui-btn-inline" );
- }
- if ( options.shadow ) {
- classes.push( "ui-shadow" );
- }
- if ( options.corners ) {
- classes.push( "ui-corner-all" );
- }
- if ( options.mini ) {
- classes.push( "ui-mini" );
- }
-
- // Create a string from the array and return it
- return classes;
-}
-
-// classNameToOptions:
-// @classes: A string containing a .className-style space-separated class list
-//
-// Loops over @classes and calculates an options object based on the
-// buttonMarkup-related classes it finds. It records unrecognized classes in an
-// array.
-//
-// Returns: An object containing the following items:
-//
-// "options": buttonMarkup options found to be present because of the
-// presence/absence of corresponding classes
-//
-// "unknownClasses": a string containing all the non-buttonMarkup-related
-// classes found in @classes
-//
-// "alreadyEnhanced": A boolean indicating whether the ui-btn class was among
-// those found to be present
-function classNameToOptions( classes ) {
- var idx, map, unknownClass,
- alreadyEnhanced = false,
- noIcon = true,
- o = {
- icon: "",
- inline: false,
- shadow: false,
- corners: false,
- iconshadow: false,
- mini: false
- },
- unknownClasses = [];
-
- classes = classes.split( " " );
-
- // Loop over the classes
- for ( idx = 0 ; idx < classes.length ; idx++ ) {
-
- // Assume it's an unrecognized class
- unknownClass = true;
-
- // Recognize boolean options from the presence of classes
- map = reverseBoolOptionMap[ classes[ idx ] ];
- if ( map !== undefined ) {
- unknownClass = false;
- o[ map ] = true;
-
- // Recognize the presence of an icon and establish the icon position
- } else if ( classes[ idx ].indexOf( "ui-btn-icon-" ) === 0 ) {
- unknownClass = false;
- noIcon = false;
- o.iconpos = classes[ idx ].substring( 12 );
-
- // Establish which icon is present
- } else if ( classes[ idx ].indexOf( "ui-icon-" ) === 0 ) {
- unknownClass = false;
- o.icon = classes[ idx ].substring( 8 );
-
- // Establish the theme - this recognizes one-letter theme swatch names
- } else if ( classes[ idx ].indexOf( "ui-btn-" ) === 0 && classes[ idx ].length === 8 ) {
- unknownClass = false;
- o.theme = classes[ idx ].substring( 7 );
-
- // Recognize that this element has already been buttonMarkup-enhanced
- } else if ( classes[ idx ] === "ui-btn" ) {
- unknownClass = false;
- alreadyEnhanced = true;
- }
-
- // If this class has not been recognized, add it to the list
- if ( unknownClass ) {
- unknownClasses.push( classes[ idx ] );
- }
- }
-
- // If a "ui-btn-icon-*" icon position class is absent there cannot be an icon
- if ( noIcon ) {
- o.icon = "";
- }
-
- return {
- options: o,
- unknownClasses: unknownClasses,
- alreadyEnhanced: alreadyEnhanced
- };
-}
-
-function camelCase2Hyphenated( c ) {
- return "-" + c.toLowerCase();
-}
-
-// $.fn.buttonMarkup:
-// DOM: gets/sets .className
-//
-// @options: options to apply to the elements in the jQuery object
-// @overwriteClasses: boolean indicating whether to honour existing classes
-//
-// Calculates the classes to apply to the elements in the jQuery object based on
-// the options passed in. If @overwriteClasses is true, it sets the className
-// property of each element in the jQuery object to the buttonMarkup classes
-// it calculates based on the options passed in.
-//
-// If you wish to preserve any classes that are already present on the elements
-// inside the jQuery object, including buttonMarkup-related classes that were
-// added by a previous call to $.fn.buttonMarkup() or during page enhancement
-// then you should omit @overwriteClasses or set it to false.
-$.fn.buttonMarkup = function( options, overwriteClasses ) {
- var idx, data, el, retrievedOptions, optionKey,
- defaults = $.fn.buttonMarkup.defaults;
-
- for ( idx = 0 ; idx < this.length ; idx++ ) {
- el = this[ idx ];
- data = overwriteClasses ?
-
- // Assume this element is not enhanced and ignore its classes
- { alreadyEnhanced: false, unknownClasses: [] } :
-
- // Otherwise analyze existing classes to establish existing options and
- // classes
- classNameToOptions( el.className );
-
- retrievedOptions = $.extend( {},
-
- // If the element already has the class ui-btn, then we assume that
- // it has passed through buttonMarkup before - otherwise, the options
- // returned by classNameToOptions do not correctly reflect the state of
- // the element
- ( data.alreadyEnhanced ? data.options : {} ),
-
- // Finally, apply the options passed in
- options );
-
- // If this is the first call on this element, retrieve remaining options
- // from the data-attributes
- if ( !data.alreadyEnhanced ) {
- for ( optionKey in defaults ) {
- if ( retrievedOptions[ optionKey ] === undefined ) {
- retrievedOptions[ optionKey ] = getAttrFixed( el,
- optionKey.replace( capitalLettersRE, camelCase2Hyphenated )
- );
- }
- }
- }
-
- el.className = optionsToClasses(
-
- // Merge all the options and apply them as classes
- $.extend( {},
-
- // The defaults form the basis
- defaults,
-
- // Add the computed options
- retrievedOptions
- ),
-
- // ... and re-apply any unrecognized classes that were found
- data.unknownClasses ).join( " " );
- if ( el.tagName.toLowerCase() !== "button" ) {
- el.setAttribute( "role", "button" );
- }
- }
-
- return this;
-};
-
-// buttonMarkup defaults. This must be a complete set, i.e., a value must be
-// given here for all recognized options
-$.fn.buttonMarkup.defaults = {
- icon: "",
- iconpos: "left",
- theme: null,
- inline: false,
- shadow: true,
- corners: true,
- iconshadow: false, /* TODO: Remove in 1.5. Option deprecated in 1.4. */
- mini: false
-};
-
-$.extend( $.fn.buttonMarkup, {
- initSelector: "a:jqmData(role='button'), .ui-bar > a, .ui-bar > :jqmData(role='controlgroup') > a, button"
-});
-
-})( jQuery );
-
-
-(function( $, undefined ) {
-
-$.widget( "mobile.controlgroup", $.extend( {
- options: {
- enhanced: false,
- theme: null,
- shadow: false,
- corners: true,
- excludeInvisible: true,
- type: "vertical",
- mini: false
- },
-
- _create: function() {
- var elem = this.element,
- opts = this.options;
-
- // Run buttonmarkup
- if ( $.fn.buttonMarkup ) {
- this.element.find( $.fn.buttonMarkup.initSelector ).buttonMarkup();
- }
- // Enhance child widgets
- $.each( this._childWidgets, $.proxy( function( number, widgetName ) {
- if ( $.mobile[ widgetName ] ) {
- this.element.find( $.mobile[ widgetName ].initSelector ).not( $.mobile.page.prototype.keepNativeSelector() )[ widgetName ]();
- }
- }, this ));
-
- $.extend( this, {
- _ui: null,
- _initialRefresh: true
- });
-
- if ( opts.enhanced ) {
- this._ui = {
- groupLegend: elem.children( ".ui-controlgroup-label" ).children(),
- childWrapper: elem.children( ".ui-controlgroup-controls" )
- };
- } else {
- this._ui = this._enhance();
- }
-
- },
-
- _childWidgets: [ "checkboxradio", "selectmenu", "button" ],
-
- _themeClassFromOption: function( value ) {
- return ( value ? ( value === "none" ? "" : "ui-group-theme-" + value ) : "" );
- },
-
- _enhance: function() {
- var elem = this.element,
- opts = this.options,
- ui = {
- groupLegend: elem.children( "legend" ),
- childWrapper: elem
- .addClass( "ui-controlgroup " +
- "ui-controlgroup-" +
- ( opts.type === "horizontal" ? "horizontal" : "vertical" ) + " " +
- this._themeClassFromOption( opts.theme ) + " " +
- ( opts.corners ? "ui-corner-all " : "" ) +
- ( opts.mini ? "ui-mini " : "" ) )
- .wrapInner( "<div " +
- "class='ui-controlgroup-controls " +
- ( opts.shadow === true ? "ui-shadow" : "" ) + "'></div>" )
- .children()
- };
-
- if ( ui.groupLegend.length > 0 ) {
- $( "<div role='heading' class='ui-controlgroup-label'></div>" )
- .append( ui.groupLegend )
- .prependTo( elem );
- }
-
- return ui;
- },
-
- _init: function() {
- this.refresh();
- },
-
- _setOptions: function( options ) {
- var callRefresh, returnValue,
- elem = this.element;
-
- // Must have one of horizontal or vertical
- if ( options.type !== undefined ) {
- elem
- .removeClass( "ui-controlgroup-horizontal ui-controlgroup-vertical" )
- .addClass( "ui-controlgroup-" + ( options.type === "horizontal" ? "horizontal" : "vertical" ) );
- callRefresh = true;
- }
-
- if ( options.theme !== undefined ) {
- elem
- .removeClass( this._themeClassFromOption( this.options.theme ) )
- .addClass( this._themeClassFromOption( options.theme ) );
- }
-
- if ( options.corners !== undefined ) {
- elem.toggleClass( "ui-corner-all", options.corners );
- }
-
- if ( options.mini !== undefined ) {
- elem.toggleClass( "ui-mini", options.mini );
- }
-
- if ( options.shadow !== undefined ) {
- this._ui.childWrapper.toggleClass( "ui-shadow", options.shadow );
- }
-
- if ( options.excludeInvisible !== undefined ) {
- this.options.excludeInvisible = options.excludeInvisible;
- callRefresh = true;
- }
-
- returnValue = this._super( options );
-
- if ( callRefresh ) {
- this.refresh();
- }
-
- return returnValue;
- },
-
- container: function() {
- return this._ui.childWrapper;
- },
-
- refresh: function() {
- var $el = this.container(),
- els = $el.find( ".ui-btn" ).not( ".ui-slider-handle" ),
- create = this._initialRefresh;
- if ( $.mobile.checkboxradio ) {
- $el.find( ":mobile-checkboxradio" ).checkboxradio( "refresh" );
- }
- this._addFirstLastClasses( els,
- this.options.excludeInvisible ? this._getVisibles( els, create ) : els,
- create );
- this._initialRefresh = false;
- },
-
- // Caveat: If the legend is not the first child of the controlgroup at enhance
- // time, it will be after _destroy().
- _destroy: function() {
- var ui, buttons,
- opts = this.options;
-
- if ( opts.enhanced ) {
- return this;
- }
-
- ui = this._ui;
- buttons = this.element
- .removeClass( "ui-controlgroup " +
- "ui-controlgroup-horizontal ui-controlgroup-vertical ui-corner-all ui-mini " +
- this._themeClassFromOption( opts.theme ) )
- .find( ".ui-btn" )
- .not( ".ui-slider-handle" );
-
- this._removeFirstLastClasses( buttons );
-
- ui.groupLegend.unwrap();
- ui.childWrapper.children().unwrap();
- }
-}, $.mobile.behaviors.addFirstLastClasses ) );
-
-})(jQuery);
-
-(function( $, undefined ) {
-
- $.widget( "mobile.toolbar", {
- initSelector: ":jqmData(role='footer'), :jqmData(role='header')",
-
- options: {
- theme: null,
- addBackBtn: false,
- backBtnTheme: null,
- backBtnText: "Back"
- },
-
- _create: function() {
- var leftbtn, rightbtn,
- role = this.element.is( ":jqmData(role='header')" ) ? "header" : "footer",
- page = this.element.closest( ".ui-page" );
- if ( page.length === 0 ) {
- page = false;
- this._on( this.document, {
- "pageshow": "refresh"
- });
- }
- $.extend( this, {
- role: role,
- page: page,
- leftbtn: leftbtn,
- rightbtn: rightbtn
- });
- this.element.attr( "role", role === "header" ? "banner" : "contentinfo" ).addClass( "ui-" + role );
- this.refresh();
- this._setOptions( this.options );
- },
- _setOptions: function( o ) {
- if ( o.addBackBtn !== undefined ) {
- if ( this.options.addBackBtn &&
- this.role === "header" &&
- $( ".ui-page" ).length > 1 &&
- this.page[ 0 ].getAttribute( "data-" + $.mobile.ns + "url" ) !== $.mobile.path.stripHash( location.hash ) &&
- !this.leftbtn ) {
- this._addBackButton();
- } else {
- this.element.find( ".ui-toolbar-back-btn" ).remove();
- }
- }
- if ( o.backBtnTheme != null ) {
- this.element
- .find( ".ui-toolbar-back-btn" )
- .addClass( "ui-btn ui-btn-" + o.backBtnTheme );
- }
- if ( o.backBtnText !== undefined ) {
- this.element.find( ".ui-toolbar-back-btn .ui-btn-text" ).text( o.backBtnText );
- }
- if ( o.theme !== undefined ) {
- var currentTheme = this.options.theme ? this.options.theme : "inherit",
- newTheme = o.theme ? o.theme : "inherit";
-
- this.element.removeClass( "ui-bar-" + currentTheme ).addClass( "ui-bar-" + newTheme );
- }
-
- this._super( o );
- },
- refresh: function() {
- if ( this.role === "header" ) {
- this._addHeaderButtonClasses();
- }
- if ( !this.page ) {
- this._setRelative();
- if ( this.role === "footer" ) {
- this.element.appendTo( "body" );
- }
- }
- this._addHeadingClasses();
- this._btnMarkup();
- },
-
- //we only want this to run on non fixed toolbars so make it easy to override
- _setRelative: function() {
- $( "[data-"+ $.mobile.ns + "role='page']" ).css({ "position": "relative" });
- },
-
- // Deprecated in 1.4. As from 1.5 button classes have to be present in the markup.
- _btnMarkup: function() {
- this.element
- .children( "a" )
- .filter( ":not([data-" + $.mobile.ns + "role='none'])" )
- .attr( "data-" + $.mobile.ns + "role", "button" );
- this.element.trigger( "create" );
- },
- // Deprecated in 1.4. As from 1.5 ui-btn-left/right classes have to be present in the markup.
- _addHeaderButtonClasses: function() {
- var $headeranchors = this.element.children( "a, button" );
- this.leftbtn = $headeranchors.hasClass( "ui-btn-left" );
- this.rightbtn = $headeranchors.hasClass( "ui-btn-right" );
-
- this.leftbtn = this.leftbtn || $headeranchors.eq( 0 ).not( ".ui-btn-right" ).addClass( "ui-btn-left" ).length;
-
- this.rightbtn = this.rightbtn || $headeranchors.eq( 1 ).addClass( "ui-btn-right" ).length;
-
- },
- _addBackButton: function() {
- var options = this.options,
- theme = options.backBtnTheme || options.theme;
-
- $( "<a role='button' href='javascript:void(0);' " +
- "class='ui-btn ui-corner-all ui-shadow ui-btn-left " +
- ( theme ? "ui-btn-" + theme + " " : "" ) +
- "ui-toolbar-back-btn ui-icon-carat-l ui-btn-icon-left' " +
- "data-" + $.mobile.ns + "rel='back'>" + options.backBtnText + "</a>" )
- .prependTo( this.element );
- },
- _addHeadingClasses: function() {
- this.element.children( "h1, h2, h3, h4, h5, h6" )
- .addClass( "ui-title" )
- // Regardless of h element number in src, it becomes h1 for the enhanced page
- .attr({
- "role": "heading",
- "aria-level": "1"
- });
- }
- });
-
-})( jQuery );
-
-(function( $, undefined ) {
-
- $.widget( "mobile.toolbar", $.mobile.toolbar, {
- options: {
- position:null,
- visibleOnPageShow: true,
- disablePageZoom: true,
- transition: "slide", //can be none, fade, slide (slide maps to slideup or slidedown)
- fullscreen: false,
- tapToggle: true,
- tapToggleBlacklist: "a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed, .ui-flipswitch, .ui-popup, .ui-panel, .ui-panel-dismiss-open",
- hideDuringFocus: "input, textarea, select",
- updatePagePadding: true,
- trackPersistentToolbars: true,
-
- // Browser detection! Weeee, here we go...
- // Unfortunately, position:fixed is costly, not to mention probably impossible, to feature-detect accurately.
- // Some tests exist, but they currently return false results in critical devices and browsers, which could lead to a broken experience.
- // Testing fixed positioning is also pretty obtrusive to page load, requiring injected elements and scrolling the window
- // The following function serves to rule out some popular browsers with known fixed-positioning issues
- // This is a plugin option like any other, so feel free to improve or overwrite it
- supportBlacklist: function() {
- return !$.support.fixedPosition;
- }
- },
-
- _create: function() {
- this._super();
- if ( this.options.position === "fixed" && !this.options.supportBlacklist() ) {
- this._makeFixed();
- }
- },
-
- _makeFixed: function() {
- this.element.addClass( "ui-"+ this.role +"-fixed" );
- this.updatePagePadding();
- this._addTransitionClass();
- this._bindPageEvents();
- this._bindToggleHandlers();
- },
-
- _setOptions: function( o ) {
- if ( o.position === "fixed" && this.options.position !== "fixed" ) {
- this._makeFixed();
- }
- if ( this.options.position === "fixed" && !this.options.supportBlacklist() ) {
- var $page = ( !!this.page )? this.page: ( $(".ui-page-active").length > 0 )? $(".ui-page-active"): $(".ui-page").eq(0);
-
- if ( o.fullscreen !== undefined) {
- if ( o.fullscreen ) {
- this.element.addClass( "ui-"+ this.role +"-fullscreen" );
- $page.addClass( "ui-page-" + this.role + "-fullscreen" );
- }
- // If not fullscreen, add class to page to set top or bottom padding
- else {
- this.element.removeClass( "ui-"+ this.role +"-fullscreen" );
- $page.removeClass( "ui-page-" + this.role + "-fullscreen" ).addClass( "ui-page-" + this.role+ "-fixed" );
- }
- }
- }
- this._super(o);
- },
-
- _addTransitionClass: function() {
- var tclass = this.options.transition;
-
- if ( tclass && tclass !== "none" ) {
- // use appropriate slide for header or footer
- if ( tclass === "slide" ) {
- tclass = this.element.hasClass( "ui-header" ) ? "slidedown" : "slideup";
- }
-
- this.element.addClass( tclass );
- }
- },
-
- _bindPageEvents: function() {
- var page = ( !!this.page )? this.element.closest( ".ui-page" ): this.document;
- //page event bindings
- // Fixed toolbars require page zoom to be disabled, otherwise usability issues crop up
- // This method is meant to disable zoom while a fixed-positioned toolbar page is visible
- this._on( page , {
- "pagebeforeshow": "_handlePageBeforeShow",
- "webkitAnimationStart":"_handleAnimationStart",
- "animationstart":"_handleAnimationStart",
- "updatelayout": "_handleAnimationStart",
- "pageshow": "_handlePageShow",
- "pagebeforehide": "_handlePageBeforeHide"
- });
- },
-
- _handlePageBeforeShow: function( ) {
- var o = this.options;
- if ( o.disablePageZoom ) {
- $.mobile.zoom.disable( true );
- }
- if ( !o.visibleOnPageShow ) {
- this.hide( true );
- }
- },
-
- _handleAnimationStart: function() {
- if ( this.options.updatePagePadding ) {
- this.updatePagePadding( ( !!this.page )? this.page: ".ui-page-active" );
- }
- },
-
- _handlePageShow: function() {
- this.updatePagePadding( ( !!this.page )? this.page: ".ui-page-active" );
- if ( this.options.updatePagePadding ) {
- this._on( this.window, { "throttledresize": "updatePagePadding" } );
- }
- },
-
- _handlePageBeforeHide: function( e, ui ) {
- var o = this.options,
- thisFooter, thisHeader, nextFooter, nextHeader;
-
- if ( o.disablePageZoom ) {
- $.mobile.zoom.enable( true );
- }
- if ( o.updatePagePadding ) {
- this._off( this.window, "throttledresize" );
- }
-
- if ( o.trackPersistentToolbars ) {
- thisFooter = $( ".ui-footer-fixed:jqmData(id)", this.page );
- thisHeader = $( ".ui-header-fixed:jqmData(id)", this.page );
- nextFooter = thisFooter.length && ui.nextPage && $( ".ui-footer-fixed:jqmData(id='" + thisFooter.jqmData( "id" ) + "')", ui.nextPage ) || $();
- nextHeader = thisHeader.length && ui.nextPage && $( ".ui-header-fixed:jqmData(id='" + thisHeader.jqmData( "id" ) + "')", ui.nextPage ) || $();
-
- if ( nextFooter.length || nextHeader.length ) {
-
- nextFooter.add( nextHeader ).appendTo( $.mobile.pageContainer );
-
- ui.nextPage.one( "pageshow", function() {
- nextHeader.prependTo( this );
- nextFooter.appendTo( this );
- });
- }
- }
- },
-
- _visible: true,
-
- // This will set the content element's top or bottom padding equal to the toolbar's height
- updatePagePadding: function( tbPage ) {
- var $el = this.element,
- header = ( this.role ==="header" ),
- pos = parseFloat( $el.css( header ? "top" : "bottom" ) );
-
- // This behavior only applies to "fixed", not "fullscreen"
- if ( this.options.fullscreen ) { return; }
- // tbPage argument can be a Page object or an event, if coming from throttled resize.
- tbPage = ( tbPage && tbPage.type === undefined && tbPage ) || this.page || $el.closest( ".ui-page" );
- tbPage = ( !!this.page )? this.page: ".ui-page-active";
- $( tbPage ).css( "padding-" + ( header ? "top" : "bottom" ), $el.outerHeight() + pos );
- },
-
- _useTransition: function( notransition ) {
- var $win = this.window,
- $el = this.element,
- scroll = $win.scrollTop(),
- elHeight = $el.height(),
- pHeight = ( !!this.page )? $el.closest( ".ui-page" ).height():$(".ui-page-active").height(),
- viewportHeight = $.mobile.getScreenHeight();
-
- return !notransition &&
- ( this.options.transition && this.options.transition !== "none" &&
- (
- ( this.role === "header" && !this.options.fullscreen && scroll > elHeight ) ||
- ( this.role === "footer" && !this.options.fullscreen && scroll + viewportHeight < pHeight - elHeight )
- ) || this.options.fullscreen
- );
- },
-
- show: function( notransition ) {
- var hideClass = "ui-fixed-hidden",
- $el = this.element;
-
- if ( this._useTransition( notransition ) ) {
- $el
- .removeClass( "out " + hideClass )
- .addClass( "in" )
- .animationComplete(function () {
- $el.removeClass( "in" );
- });
- }
- else {
- $el.removeClass( hideClass );
- }
- this._visible = true;
- },
-
- hide: function( notransition ) {
- var hideClass = "ui-fixed-hidden",
- $el = this.element,
- // if it's a slide transition, our new transitions need the reverse class as well to slide outward
- outclass = "out" + ( this.options.transition === "slide" ? " reverse" : "" );
-
- if ( this._useTransition( notransition ) ) {
- $el
- .addClass( outclass )
- .removeClass( "in" )
- .animationComplete(function() {
- $el.addClass( hideClass ).removeClass( outclass );
- });
- }
- else {
- $el.addClass( hideClass ).removeClass( outclass );
- }
- this._visible = false;
- },
-
- toggle: function() {
- this[ this._visible ? "hide" : "show" ]();
- },
-
- _bindToggleHandlers: function() {
- var self = this,
- o = self.options,
- delayShow, delayHide,
- isVisible = true,
- page = ( !!this.page )? this.page: $(".ui-page");
-
- // tap toggle
- page
- .bind( "vclick", function( e ) {
- if ( o.tapToggle && !$( e.target ).closest( o.tapToggleBlacklist ).length ) {
- self.toggle();
- }
- })
- .bind( "focusin focusout", function( e ) {
- //this hides the toolbars on a keyboard pop to give more screen room and prevent ios bug which
- //positions fixed toolbars in the middle of the screen on pop if the input is near the top or
- //bottom of the screen addresses issues #4410 Footer navbar moves up when clicking on a textbox in an Android environment
- //and issue #4113 Header and footer change their position after keyboard popup - iOS
- //and issue #4410 Footer navbar moves up when clicking on a textbox in an Android environment
- if ( screen.width < 1025 && $( e.target ).is( o.hideDuringFocus ) && !$( e.target ).closest( ".ui-header-fixed, .ui-footer-fixed" ).length ) {
- //Fix for issue #4724 Moving through form in Mobile Safari with "Next" and "Previous" system
- //controls causes fixed position, tap-toggle false Header to reveal itself
- // isVisible instead of self._visible because the focusin and focusout events fire twice at the same time
- // Also use a delay for hiding the toolbars because on Android native browser focusin is direclty followed
- // by a focusout when a native selects opens and the other way around when it closes.
- if ( e.type === "focusout" && !isVisible ) {
- isVisible = true;
- //wait for the stack to unwind and see if we have jumped to another input
- clearTimeout( delayHide );
- delayShow = setTimeout( function() {
- self.show();
- }, 0 );
- } else if ( e.type === "focusin" && !!isVisible ) {
- //if we have jumped to another input clear the time out to cancel the show.
- clearTimeout( delayShow );
- isVisible = false;
- delayHide = setTimeout( function() {
- self.hide();
- }, 0 );
- }
- }
- });
- },
-
- _setRelative: function() {
- if( this.options.position !== "fixed" ){
- $( "[data-"+ $.mobile.ns + "role='page']" ).css({ "position": "relative" });
- }
- },
-
- _destroy: function() {
- var $el = this.element,
- header = $el.hasClass( "ui-header" );
-
- $el.closest( ".ui-page" ).css( "padding-" + ( header ? "top" : "bottom" ), "" );
- $el.removeClass( "ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden" );
- $el.closest( ".ui-page" ).removeClass( "ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen" );
- }
-
- });
-})( jQuery );
-
-(function( $, undefined ) {
- $.widget( "mobile.toolbar", $.mobile.toolbar, {
-
- _makeFixed: function() {
- this._super();
- this._workarounds();
- },
-
- //check the browser and version and run needed workarounds
- _workarounds: function() {
- var ua = navigator.userAgent,
- platform = navigator.platform,
- // Rendering engine is Webkit, and capture major version
- wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
- wkversion = !!wkmatch && wkmatch[ 1 ],
- os = null,
- self = this;
- //set the os we are working in if it dosent match one with workarounds return
- if ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1 || platform.indexOf( "iPod" ) > -1 ) {
- os = "ios";
- } else if ( ua.indexOf( "Android" ) > -1 ) {
- os = "android";
- } else {
- return;
- }
- //check os version if it dosent match one with workarounds return
- if ( os === "ios" ) {
- //iOS workarounds
- self._bindScrollWorkaround();
- } else if ( os === "android" && wkversion && wkversion < 534 ) {
- //Android 2.3 run all Android 2.3 workaround
- self._bindScrollWorkaround();
- self._bindListThumbWorkaround();
- } else {
- return;
- }
- },
-
- //Utility class for checking header and footer positions relative to viewport
- _viewportOffset: function() {
- var $el = this.element,
- header = $el.hasClass( "ui-header" ),
- offset = Math.abs( $el.offset().top - this.window.scrollTop() );
- if ( !header ) {
- offset = Math.round( offset - this.window.height() + $el.outerHeight() ) - 60;
- }
- return offset;
- },
-
- //bind events for _triggerRedraw() function
- _bindScrollWorkaround: function() {
- var self = this;
- //bind to scrollstop and check if the toolbars are correctly positioned
- this._on( this.window, { scrollstop: function() {
- var viewportOffset = self._viewportOffset();
- //check if the header is visible and if its in the right place
- if ( viewportOffset > 2 && self._visible ) {
- self._triggerRedraw();
- }
- }});
- },
-
- //this addresses issue #4250 Persistent footer instability in v1.1 with long select lists in Android 2.3.3
- //and issue #3748 Android 2.x: Page transitions broken when fixed toolbars used
- //the absolutely positioned thumbnail in a list view causes problems with fixed position buttons above in a nav bar
- //setting the li's to -webkit-transform:translate3d(0,0,0); solves this problem to avoide potential issues in other
- //platforms we scope this with the class ui-android-2x-fix
- _bindListThumbWorkaround: function() {
- this.element.closest( ".ui-page" ).addClass( "ui-android-2x-fixed" );
- },
- //this addresses issues #4337 Fixed header problem after scrolling content on iOS and Android
- //and device bugs project issue #1 Form elements can lose click hit area in position: fixed containers.
- //this also addresses not on fixed toolbars page in docs
- //adding 1px of padding to the bottom then removing it causes a "redraw"
- //which positions the toolbars correctly (they will always be visually correct)
- _triggerRedraw: function() {
- var paddingBottom = parseFloat( $( ".ui-page-active" ).css( "padding-bottom" ) );
- //trigger page redraw to fix incorrectly positioned fixed elements
- $( ".ui-page-active" ).css( "padding-bottom", ( paddingBottom + 1 ) + "px" );
- //if the padding is reset with out a timeout the reposition will not occure.
- //this is independant of JQM the browser seems to need the time to react.
- setTimeout( function() {
- $( ".ui-page-active" ).css( "padding-bottom", paddingBottom + "px" );
- }, 0 );
- },
-
- destroy: function() {
- this._super();
- //Remove the class we added to the page previously in android 2.x
- this.element.closest( ".ui-page-active" ).removeClass( "ui-android-2x-fix" );
- }
- });
-
-})( jQuery );
-
-
-( function( $, undefined ) {
-
-var ieHack = ( $.mobile.browser.oldIE && $.mobile.browser.oldIE <= 8 ),
- uiTemplate = $(
- "<div class='ui-popup-arrow-guide'></div>" +
- "<div class='ui-popup-arrow-container" + ( ieHack ? " ie" : "" ) + "'>" +
- "<div class='ui-popup-arrow'></div>" +
- "</div>"
- );
-
-function getArrow() {
- var clone = uiTemplate.clone(),
- gd = clone.eq( 0 ),
- ct = clone.eq( 1 ),
- ar = ct.children();
-
- return { arEls: ct.add( gd ), gd: gd, ct: ct, ar: ar };
-}
-
-$.widget( "mobile.popup", $.mobile.popup, {
- options: {
-
- arrow: ""
- },
-
- _create: function() {
- var ar,
- ret = this._super();
-
- if ( this.options.arrow ) {
- this._ui.arrow = ar = this._addArrow();
- }
-
- return ret;
- },
-
- _addArrow: function() {
- var theme,
- opts = this.options,
- ar = getArrow();
-
- theme = this._themeClassFromOption( "ui-body-", opts.theme );
- ar.ar.addClass( theme + ( opts.shadow ? " ui-overlay-shadow" : "" ) );
- ar.arEls.hide().appendTo( this.element );
-
- return ar;
- },
-
- _unenhance: function() {
- var ar = this._ui.arrow;
-
- if ( ar ) {
- ar.arEls.remove();
- }
-
- return this._super();
- },
-
- // Pretend to show an arrow described by @p and @dir and calculate the
- // distance from the desired point. If a best-distance is passed in, return
- // the minimum of the one passed in and the one calculated.
- _tryAnArrow: function( p, dir, desired, s, best ) {
- var result, r, diff, desiredForArrow = {}, tip = {};
-
- // If the arrow has no wiggle room along the edge of the popup, it cannot
- // be displayed along the requested edge without it sticking out.
- if ( s.arFull[ p.dimKey ] > s.guideDims[ p.dimKey ] ) {
- return best;
- }
-
- desiredForArrow[ p.fst ] = desired[ p.fst ] +
- ( s.arHalf[ p.oDimKey ] + s.menuHalf[ p.oDimKey ] ) * p.offsetFactor -
- s.contentBox[ p.fst ] + ( s.clampInfo.menuSize[ p.oDimKey ] - s.contentBox[ p.oDimKey ] ) * p.arrowOffsetFactor;
- desiredForArrow[ p.snd ] = desired[ p.snd ];
-
- result = s.result || this._calculateFinalLocation( desiredForArrow, s.clampInfo );
- r = { x: result.left, y: result.top };
-
- tip[ p.fst ] = r[ p.fst ] + s.contentBox[ p.fst ] + p.tipOffset;
- tip[ p.snd ] = Math.max( result[ p.prop ] + s.guideOffset[ p.prop ] + s.arHalf[ p.dimKey ],
- Math.min( result[ p.prop ] + s.guideOffset[ p.prop ] + s.guideDims[ p.dimKey ] - s.arHalf[ p.dimKey ],
- desired[ p.snd ] ) );
-
- diff = Math.abs( desired.x - tip.x ) + Math.abs( desired.y - tip.y );
- if ( !best || diff < best.diff ) {
- // Convert tip offset to coordinates inside the popup
- tip[ p.snd ] -= s.arHalf[ p.dimKey ] + result[ p.prop ] + s.contentBox[ p.snd ];
- best = { dir: dir, diff: diff, result: result, posProp: p.prop, posVal: tip[ p.snd ] };
- }
-
- return best;
- },
-
- _getPlacementState: function( clamp ) {
- var offset, gdOffset,
- ar = this._ui.arrow,
- state = {
- clampInfo: this._clampPopupWidth( !clamp ),
- arFull: { cx: ar.ct.width(), cy: ar.ct.height() },
- guideDims: { cx: ar.gd.width(), cy: ar.gd.height() },
- guideOffset: ar.gd.offset()
- };
-
- offset = this.element.offset();
-
- ar.gd.css( { left: 0, top: 0, right: 0, bottom: 0 } );
- gdOffset = ar.gd.offset();
- state.contentBox = {
- x: gdOffset.left - offset.left,
- y: gdOffset.top - offset.top,
- cx: ar.gd.width(),
- cy: ar.gd.height()
- };
- ar.gd.removeAttr( "style" );
-
- // The arrow box moves between guideOffset and guideOffset + guideDims - arFull
- state.guideOffset = { left: state.guideOffset.left - offset.left, top: state.guideOffset.top - offset.top };
- state.arHalf = { cx: state.arFull.cx / 2, cy: state.arFull.cy / 2 };
- state.menuHalf = { cx: state.clampInfo.menuSize.cx / 2, cy: state.clampInfo.menuSize.cy / 2 };
-
- return state;
- },
-
- _placementCoords: function( desired ) {
- var state, best, params, elOffset, bgRef,
- optionValue = this.options.arrow,
- ar = this._ui.arrow;
-
- if ( !ar ) {
- return this._super( desired );
- }
-
- ar.arEls.show();
-
- bgRef = {};
- state = this._getPlacementState( true );
- params = {
- "l": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: 1, tipOffset: -state.arHalf.cx, arrowOffsetFactor: 0 },
- "r": { fst: "x", snd: "y", prop: "top", dimKey: "cy", oDimKey: "cx", offsetFactor: -1, tipOffset: state.arHalf.cx + state.contentBox.cx, arrowOffsetFactor: 1 },
- "b": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: -1, tipOffset: state.arHalf.cy + state.contentBox.cy, arrowOffsetFactor: 1 },
- "t": { fst: "y", snd: "x", prop: "left", dimKey: "cx", oDimKey: "cy", offsetFactor: 1, tipOffset: -state.arHalf.cy, arrowOffsetFactor: 0 }
- };
-
- // Try each side specified in the options to see on which one the arrow
- // should be placed such that the distance between the tip of the arrow and
- // the desired coordinates is the shortest.
- $.each( ( optionValue === true ? "l,t,r,b" : optionValue ).split( "," ),
- $.proxy( function( key, value ) {
- best = this._tryAnArrow( params[ value ], value, desired, state, best );
- }, this ) );
-
- // Could not place the arrow along any of the edges - behave as if showing
- // the arrow was turned off.
- if ( !best ) {
- ar.arEls.hide();
- return this._super( desired );
- }
-
- // Move the arrow into place
- ar.ct
- .removeClass( "ui-popup-arrow-l ui-popup-arrow-t ui-popup-arrow-r ui-popup-arrow-b" )
- .addClass( "ui-popup-arrow-" + best.dir )
- .removeAttr( "style" ).css( best.posProp, best.posVal )
- .show();
-
- // Do not move/size the background div on IE, because we use the arrow div for background as well.
- if ( !ieHack ) {
- elOffset = this.element.offset();
- bgRef[ params[ best.dir ].fst ] = ar.ct.offset();
- bgRef[ params[ best.dir ].snd ] = {
- left: elOffset.left + state.contentBox.x,
- top: elOffset.top + state.contentBox.y
- };
- }
-
- return best.result;
- },
-
- _setOptions: function( opts ) {
- var newTheme,
- oldTheme = this.options.theme,
- ar = this._ui.arrow,
- ret = this._super( opts );
-
- if ( opts.arrow !== undefined ) {
- if ( !ar && opts.arrow ) {
- this._ui.arrow = this._addArrow();
-
- // Important to return here so we don't set the same options all over
- // again below.
- return;
- } else if ( ar && !opts.arrow ) {
- ar.arEls.remove();
- this._ui.arrow = null;
- }
- }
-
- // Reassign with potentially new arrow
- ar = this._ui.arrow;
-
- if ( ar ) {
- if ( opts.theme !== undefined ) {
- oldTheme = this._themeClassFromOption( "ui-body-", oldTheme );
- newTheme = this._themeClassFromOption( "ui-body-", opts.theme );
- ar.ar.removeClass( oldTheme ).addClass( newTheme );
- }
-
- if ( opts.shadow !== undefined ) {
- ar.ar.toggleClass( "ui-overlay-shadow", opts.shadow );
- }
- }
-
- return ret;
- },
-
- _destroy: function() {
- var ar = this._ui.arrow;
-
- if ( ar ) {
- ar.arEls.remove();
- }
-
- return this._super();
- }
-});
-
-})( jQuery );
-
-
-(function( $, undefined ) {
-
-$.widget( "mobile.panel", {
- options: {
- classes: {
- panel: "ui-panel",
- panelOpen: "ui-panel-open",
- panelClosed: "ui-panel-closed",
- panelFixed: "ui-panel-fixed",
- panelInner: "ui-panel-inner",
- modal: "ui-panel-dismiss",
- modalOpen: "ui-panel-dismiss-open",
- pageContainer: "ui-panel-page-container",
- pageWrapper: "ui-panel-wrapper",
- pageFixedToolbar: "ui-panel-fixed-toolbar",
- pageContentPrefix: "ui-panel-page-content", /* Used for wrapper and fixed toolbars position, display and open classes. */
- animate: "ui-panel-animate"
- },
- animate: true,
- theme: null,
- position: "left",
- dismissible: true,
- display: "reveal", //accepts reveal, push, overlay
- swipeClose: true,
- positionFixed: false
- },
-
- _closeLink: null,
- _parentPage: null,
- _page: null,
- _modal: null,
- _panelInner: null,
- _wrapper: null,
- _fixedToolbars: null,
-
- _create: function() {
- var el = this.element,
- parentPage = el.closest( ".ui-page, :jqmData(role='page')" );
-
- // expose some private props to other methods
- $.extend( this, {
- _closeLink: el.find( ":jqmData(rel='close')" ),
- _parentPage: ( parentPage.length > 0 ) ? parentPage : false,
- _openedPage: null,
- _page: this._getPage,
- _panelInner: this._getPanelInner(),
- _fixedToolbars: this._getFixedToolbars
- });
- if ( this.options.display !== "overlay" ){
- this._getWrapper();
- }
- this._addPanelClasses();
-
- // if animating, add the class to do so
- if ( $.support.cssTransform3d && !!this.options.animate ) {
- this.element.addClass( this.options.classes.animate );
- }
-
- this._bindUpdateLayout();
- this._bindCloseEvents();
- this._bindLinkListeners();
- this._bindPageEvents();
-
- if ( !!this.options.dismissible ) {
- this._createModal();
- }
-
- this._bindSwipeEvents();
- },
-
- _getPanelInner: function() {
- var panelInner = this.element.find( "." + this.options.classes.panelInner );
-
- if ( panelInner.length === 0 ) {
- panelInner = this.element.children().wrapAll( "<div class='" + this.options.classes.panelInner + "' />" ).parent();
- }
-
- return panelInner;
- },
-
- _createModal: function() {
- var self = this,
- target = self._parentPage ? self._parentPage.parent() : self.element.parent();
-
- self._modal = $( "<div class='" + self.options.classes.modal + "'></div>" )
- .on( "mousedown", function() {
- self.close();
- })
- .appendTo( target );
- },
-
- _getPage: function() {
- var page = this._openedPage || this._parentPage || $( "." + $.mobile.activePageClass );
-
- return page;
- },
-
- _getWrapper: function() {
- var wrapper = this._page().find( "." + this.options.classes.pageWrapper );
- if ( wrapper.length === 0 ) {
- wrapper = this._page().children( ".ui-header:not(.ui-header-fixed), .ui-content:not(.ui-popup), .ui-footer:not(.ui-footer-fixed)" )
- .wrapAll( "<div class='" + this.options.classes.pageWrapper + "'></div>" )
- .parent();
- }
-
- this._wrapper = wrapper;
- },
-
- _getFixedToolbars: function() {
- var extFixedToolbars = $( "body" ).children( ".ui-header-fixed, .ui-footer-fixed" ),
- intFixedToolbars = this._page().find( ".ui-header-fixed, .ui-footer-fixed" ),
- fixedToolbars = extFixedToolbars.add( intFixedToolbars ).addClass( this.options.classes.pageFixedToolbar );
-
- return fixedToolbars;
- },
-
- _getPosDisplayClasses: function( prefix ) {
- return prefix + "-position-" + this.options.position + " " + prefix + "-display-" + this.options.display;
- },
-
- _getPanelClasses: function() {
- var panelClasses = this.options.classes.panel +
- " " + this._getPosDisplayClasses( this.options.classes.panel ) +
- " " + this.options.classes.panelClosed +
- " " + "ui-body-" + ( this.options.theme ? this.options.theme : "inherit" );
-
- if ( !!this.options.positionFixed ) {
- panelClasses += " " + this.options.classes.panelFixed;
- }
-
- return panelClasses;
- },
-
- _addPanelClasses: function() {
- this.element.addClass( this._getPanelClasses() );
- },
-
- _handleCloseClickAndEatEvent: function( event ) {
- if ( !event.isDefaultPrevented() ) {
- event.preventDefault();
- this.close();
- return false;
- }
- },
-
- _handleCloseClick: function( event ) {
- if ( !event.isDefaultPrevented() ) {
- this.close();
- }
- },
-
- _bindCloseEvents: function() {
- this._on( this._closeLink, {
- "click": "_handleCloseClick"
- });
-
- this._on({
- "click a:jqmData(ajax='false')": "_handleCloseClick"
- });
- },
-
- _positionPanel: function( scrollToTop ) {
- var self = this,
- panelInnerHeight = self._panelInner.outerHeight(),
- expand = panelInnerHeight > $.mobile.getScreenHeight();
-
- if ( expand || !self.options.positionFixed ) {
- if ( expand ) {
- self._unfixPanel();
- $.mobile.resetActivePageHeight( panelInnerHeight );
- }
- if ( scrollToTop ) {
- this.window[ 0 ].scrollTo( 0, $.mobile.defaultHomeScroll );
- }
- } else {
- self._fixPanel();
- }
- },
-
- _bindFixListener: function() {
- this._on( $( window ), { "throttledresize": "_positionPanel" });
- },
-
- _unbindFixListener: function() {
- this._off( $( window ), "throttledresize" );
- },
-
- _unfixPanel: function() {
- if ( !!this.options.positionFixed && $.support.fixedPosition ) {
- this.element.removeClass( this.options.classes.panelFixed );
- }
- },
-
- _fixPanel: function() {
- if ( !!this.options.positionFixed && $.support.fixedPosition ) {
- this.element.addClass( this.options.classes.panelFixed );
- }
- },
-
- _bindUpdateLayout: function() {
- var self = this;
-
- self.element.on( "updatelayout", function(/* e */) {
- if ( self._open ) {
- self._positionPanel();
- }
- });
- },
-
- _bindLinkListeners: function() {
- this._on( "body", {
- "click a": "_handleClick"
- });
-
- },
-
- _handleClick: function( e ) {
- var link,
- panelId = this.element.attr( "id" );
-
- if ( e.currentTarget.href.split( "#" )[ 1 ] === panelId && panelId !== undefined ) {
-
- e.preventDefault();
- link = $( e.target );
- if ( link.hasClass( "ui-btn" ) ) {
- link.addClass( $.mobile.activeBtnClass );
- this.element.one( "panelopen panelclose", function() {
- link.removeClass( $.mobile.activeBtnClass );
- });
- }
- this.toggle();
- return false;
- }
- },
-
- _bindSwipeEvents: function() {
- var self = this,
- area = self._modal ? self.element.add( self._modal ) : self.element;
-
- // on swipe, close the panel
- if ( !!self.options.swipeClose ) {
- if ( self.options.position === "left" ) {
- area.on( "swipeleft.panel", function(/* e */) {
- self.close();
- });
- } else {
- area.on( "swiperight.panel", function(/* e */) {
- self.close();
- });
- }
- }
- },
-
- _bindPageEvents: function() {
- var self = this;
-
- this.document
- // Close the panel if another panel on the page opens
- .on( "panelbeforeopen", function( e ) {
- if ( self._open && e.target !== self.element[ 0 ] ) {
- self.close();
- }
- })
- // On escape, close? might need to have a target check too...
- .on( "keyup.panel", function( e ) {
- if ( e.keyCode === 27 && self._open ) {
- self.close();
- }
- });
- if ( !this._parentPage && this.options.display !== "overlay" ) {
- this._on( this.document, {
- "pageshow": "_getWrapper"
- });
- }
- // Clean up open panels after page hide
- if ( self._parentPage ) {
- this.document.on( "pagehide", ":jqmData(role='page')", function() {
- if ( self._open ) {
- self.close( true );
- }
- });
- } else {
- this.document.on( "pagebeforehide", function() {
- if ( self._open ) {
- self.close( true );
- }
- });
- }
- },
-
- // state storage of open or closed
- _open: false,
- _pageContentOpenClasses: null,
- _modalOpenClasses: null,
-
- open: function( immediate ) {
- if ( !this._open ) {
- var self = this,
- o = self.options,
-
- _openPanel = function() {
- self.document.off( "panelclose" );
- self._page().jqmData( "panel", "open" );
-
- if ( $.support.cssTransform3d && !!o.animate && o.display !== "overlay" ) {
- self._wrapper.addClass( o.classes.animate );
- self._fixedToolbars().addClass( o.classes.animate );
- }
-
- if ( !immediate && $.support.cssTransform3d && !!o.animate ) {
- self.element.animationComplete( complete, "transition" );
- } else {
- setTimeout( complete, 0 );
- }
-
- if ( o.theme && o.display !== "overlay" ) {
- self._page().parent()
- .addClass( o.classes.pageContainer + "-themed " + o.classes.pageContainer + "-" + o.theme );
- }
-
- self.element
- .removeClass( o.classes.panelClosed )
- .addClass( o.classes.panelOpen );
-
- self._positionPanel( true );
-
- self._pageContentOpenClasses = self._getPosDisplayClasses( o.classes.pageContentPrefix );
-
- if ( o.display !== "overlay" ) {
- self._page().parent().addClass( o.classes.pageContainer );
- self._wrapper.addClass( self._pageContentOpenClasses );
- self._fixedToolbars().addClass( self._pageContentOpenClasses );
- }
-
- self._modalOpenClasses = self._getPosDisplayClasses( o.classes.modal ) + " " + o.classes.modalOpen;
- if ( self._modal ) {
- self._modal
- .addClass( self._modalOpenClasses )
- .height( Math.max( self._modal.height(), self.document.height() ) );
- }
- },
- complete = function() {
-
- if ( o.display !== "overlay" ) {
- self._wrapper.addClass( o.classes.pageContentPrefix + "-open" );
- self._fixedToolbars().addClass( o.classes.pageContentPrefix + "-open" );
- }
-
- self._bindFixListener();
-
- self._trigger( "open" );
-
- self._openedPage = self._page();
- };
-
- self._trigger( "beforeopen" );
-
- if ( self._page().jqmData( "panel" ) === "open" ) {
- self.document.on( "panelclose", function() {
- _openPanel();
- });
- } else {
- _openPanel();
- }
-
- self._open = true;
- }
- },
-
- close: function( immediate ) {
- if ( this._open ) {
- var self = this,
- o = this.options,
-
- _closePanel = function() {
-
- self.element.removeClass( o.classes.panelOpen );
-
- if ( o.display !== "overlay" ) {
- self._wrapper.removeClass( self._pageContentOpenClasses );
- self._fixedToolbars().removeClass( self._pageContentOpenClasses );
- }
-
- if ( !immediate && $.support.cssTransform3d && !!o.animate ) {
- self.element.animationComplete( complete, "transition" );
- } else {
- setTimeout( complete, 0 );
- }
-
- if ( self._modal ) {
- self._modal.removeClass( self._modalOpenClasses );
- }
- },
- complete = function() {
- if ( o.theme && o.display !== "overlay" ) {
- self._page().parent().removeClass( o.classes.pageContainer + "-themed " + o.classes.pageContainer + "-" + o.theme );
- }
-
- self.element.addClass( o.classes.panelClosed );
-
- if ( o.display !== "overlay" ) {
- self._page().parent().removeClass( o.classes.pageContainer );
- self._wrapper.removeClass( o.classes.pageContentPrefix + "-open" );
- self._fixedToolbars().removeClass( o.classes.pageContentPrefix + "-open" );
- }
-
- if ( $.support.cssTransform3d && !!o.animate && o.display !== "overlay" ) {
- self._wrapper.removeClass( o.classes.animate );
- self._fixedToolbars().removeClass( o.classes.animate );
- }
-
- self._fixPanel();
- self._unbindFixListener();
- $.mobile.resetActivePageHeight();
-
- self._page().jqmRemoveData( "panel" );
-
- self._trigger( "close" );
-
- self._openedPage = null;
- };
-
- self._trigger( "beforeclose" );
-
- _closePanel();
-
- self._open = false;
- }
- },
-
- toggle: function() {
- this[ this._open ? "close" : "open" ]();
- },
-
- _destroy: function() {
- var otherPanels,
- o = this.options,
- multiplePanels = ( $( "body > :mobile-panel" ).length + $.mobile.activePage.find( ":mobile-panel" ).length ) > 1;
-
- if ( o.display !== "overlay" ) {
-
- // remove the wrapper if not in use by another panel
- otherPanels = $( "body > :mobile-panel" ).add( $.mobile.activePage.find( ":mobile-panel" ) );
- if ( otherPanels.not( ".ui-panel-display-overlay" ).not( this.element ).length === 0 ) {
- this._wrapper.children().unwrap();
- }
-
- if ( this._open ) {
-
- this._fixedToolbars().removeClass( o.classes.pageContentPrefix + "-open" );
-
- if ( $.support.cssTransform3d && !!o.animate ) {
- this._fixedToolbars().removeClass( o.classes.animate );
- }
-
- this._page().parent().removeClass( o.classes.pageContainer );
-
- if ( o.theme ) {
- this._page().parent().removeClass( o.classes.pageContainer + "-themed " + o.classes.pageContainer + "-" + o.theme );
- }
- }
- }
-
- if ( !multiplePanels ) {
-
- this.document.off( "panelopen panelclose" );
-
- }
-
- if ( this._open ) {
- this._page().jqmRemoveData( "panel" );
- }
-
- this._panelInner.children().unwrap();
-
- this.element
- .removeClass( [ this._getPanelClasses(), o.classes.panelOpen, o.classes.animate ].join( " " ) )
- .off( "swipeleft.panel swiperight.panel" )
- .off( "panelbeforeopen" )
- .off( "panelhide" )
- .off( "keyup.panel" )
- .off( "updatelayout" );
-
- if ( this._modal ) {
- this._modal.remove();
- }
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.table", {
- options: {
- classes: {
- table: "ui-table"
- },
- enhanced: false
- },
-
- _create: function() {
- if ( !this.options.enhanced ) {
- this.element.addClass( this.options.classes.table );
- }
-
- // extend here, assign on refresh > _setHeaders
- $.extend( this, {
-
- // Expose headers and allHeaders properties on the widget
- // headers references the THs within the first TR in the table
- headers: undefined,
-
- // allHeaders references headers, plus all THs in the thead, which may
- // include several rows, or not
- allHeaders: undefined
- });
-
- this._refresh( true );
- },
-
- _setHeaders: function() {
- var trs = this.element.find( "thead tr" );
-
- this.headers = this.element.find( "tr:eq(0)" ).children();
- this.allHeaders = this.headers.add( trs.children() );
- },
-
- refresh: function() {
- this._refresh();
- },
-
- rebuild: $.noop,
-
- _refresh: function( /* create */ ) {
- var table = this.element,
- trs = table.find( "thead tr" );
-
- // updating headers on refresh (fixes #5880)
- this._setHeaders();
-
- // Iterate over the trs
- trs.each( function() {
- var columnCount = 0;
-
- // Iterate over the children of the tr
- $( this ).children().each( function() {
- var span = parseInt( this.getAttribute( "colspan" ), 10 ),
- selector = ":nth-child(" + ( columnCount + 1 ) + ")",
- j;
-
- this.setAttribute( "data-" + $.mobile.ns + "colstart", columnCount + 1 );
-
- if ( span ) {
- for( j = 0; j < span - 1; j++ ) {
- columnCount++;
- selector += ", :nth-child(" + ( columnCount + 1 ) + ")";
- }
- }
-
- // Store "cells" data on header as a reference to all cells in the
- // same column as this TH
- $( this ).jqmData( "cells", table.find( "tr" ).not( trs.eq( 0 ) ).not( this ).children( selector ) );
-
- columnCount++;
- });
- });
- }
-});
-
-})( jQuery );
-
-
-(function( $, undefined ) {
-
-$.widget( "mobile.table", $.mobile.table, {
- options: {
- mode: "columntoggle",
- columnBtnTheme: null,
- columnPopupTheme: null,
- columnBtnText: "Columns...",
- classes: $.extend( $.mobile.table.prototype.options.classes, {
- popup: "ui-table-columntoggle-popup",
- columnBtn: "ui-table-columntoggle-btn",
- priorityPrefix: "ui-table-priority-",
- columnToggleTable: "ui-table-columntoggle"
- })
- },
-
- _create: function() {
- this._super();
-
- if ( this.options.mode !== "columntoggle" ) {
- return;
- }
-
- $.extend( this, {
- _menu: null
- });
-
- if ( this.options.enhanced ) {
- this._menu = $( this.document[ 0 ].getElementById( this._id() + "-popup" ) ).children().first();
- this._addToggles( this._menu, true );
- } else {
- this._menu = this._enhanceColToggle();
- this.element.addClass( this.options.classes.columnToggleTable );
- }
-
- this._setupEvents();
-
- this._setToggleState();
- },
-
- _id: function() {
- return ( this.element.attr( "id" ) || ( this.widgetName + this.uuid ) );
- },
-
- _setupEvents: function() {
- //NOTE: inputs are bound in bindToggles,
- // so it can be called on refresh, too
-
- // update column toggles on resize
- this._on( this.window, {
- throttledresize: "_setToggleState"
- });
- this._on( this._menu, {
- "change input": "_menuInputChange"
- });
- },
-
- _addToggles: function( menu, keep ) {
- var inputs,
- checkboxIndex = 0,
- opts = this.options,
- container = menu.controlgroup( "container" );
-
- // allow update of menu on refresh (fixes #5880)
- if ( keep ) {
- inputs = menu.find( "input" );
- } else {
- container.empty();
- }
-
- // create the hide/show toggles
- this.headers.not( "td" ).each( function() {
- var header = $( this ),
- priority = $.mobile.getAttribute( this, "priority" ),
- cells = header.add( header.jqmData( "cells" ) );
-
- if ( priority ) {
- cells.addClass( opts.classes.priorityPrefix + priority );
-
- ( keep ? inputs.eq( checkboxIndex++ ) :
- $("<label><input type='checkbox' checked />" +
- ( header.children( "abbr" ).first().attr( "title" ) ||
- header.text() ) +
- "</label>" )
- .appendTo( container )
- .children( 0 )
- .checkboxradio( {
- theme: opts.columnPopupTheme
- }) )
- .jqmData( "cells", cells );
- }
- });
-
- // set bindings here
- if ( !keep ) {
- menu.controlgroup( "refresh" );
- }
- },
-
- _menuInputChange: function( evt ) {
- var input = $( evt.target ),
- checked = input[ 0 ].checked;
-
- input.jqmData( "cells" )
- .toggleClass( "ui-table-cell-hidden", !checked )
- .toggleClass( "ui-table-cell-visible", checked );
-
- if ( input[ 0 ].getAttribute( "locked" ) ) {
- input.removeAttr( "locked" );
-
- this._unlockCells( input.jqmData( "cells" ) );
- } else {
- input.attr( "locked", true );
- }
- },
-
- _unlockCells: function( cells ) {
- // allow hide/show via CSS only = remove all toggle-locks
- cells.removeClass( "ui-table-cell-hidden ui-table-cell-visible");
- },
-
- _enhanceColToggle: function() {
- var id , menuButton, popup, menu,
- table = this.element,
- opts = this.options,
- ns = $.mobile.ns,
- fragment = this.document[ 0 ].createDocumentFragment();
-
- id = this._id() + "-popup";
- menuButton = $( "<a href='#" + id + "' " +
- "class='" + opts.classes.columnBtn + " ui-btn " +
- "ui-btn-" + ( opts.columnBtnTheme || "a" ) +
- " ui-corner-all ui-shadow ui-mini' " +
- "data-" + ns + "rel='popup'>" + opts.columnBtnText + "</a>" );
- popup = $( "<div class='" + opts.classes.popup + "' id='" + id + "'></div>" );
- menu = $( "<fieldset></fieldset>" ).controlgroup();
-
- // set extension here, send "false" to trigger build/rebuild
- this._addToggles( menu, false );
-
- menu.appendTo( popup );
-
- fragment.appendChild( popup[ 0 ] );
- fragment.appendChild( menuButton[ 0 ] );
- table.before( fragment );
-
- popup.popup();
-
- return menu;
- },
-
- rebuild: function() {
- this._super();
-
- if ( this.options.mode === "columntoggle" ) {
- // NOTE: rebuild passes "false", while refresh passes "undefined"
- // both refresh the table, but inside addToggles, !false will be true,
- // so a rebuild call can be indentified
- this._refresh( false );
- }
- },
-
- _refresh: function( create ) {
- this._super( create );
-
- if ( !create && this.options.mode === "columntoggle" ) {
- // columns not being replaced must be cleared from input toggle-locks
- this._unlockCells( this.element.find( ".ui-table-cell-hidden, " +
- ".ui-table-cell-visible" ) );
-
- // update columntoggles and cells
- this._addToggles( this._menu, create );
-
- // check/uncheck
- this._setToggleState();
- }
- },
-
- _setToggleState: function() {
- this._menu.find( "input" ).each( function() {
- var checkbox = $( this );
-
- this.checked = checkbox.jqmData( "cells" ).eq( 0 ).css( "display" ) === "table-cell";
- checkbox.checkboxradio( "refresh" );
- });
- },
-
- _destroy: function() {
- this._super();
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-$.widget( "mobile.table", $.mobile.table, {
- options: {
- mode: "reflow",
- classes: $.extend( $.mobile.table.prototype.options.classes, {
- reflowTable: "ui-table-reflow",
- cellLabels: "ui-table-cell-label"
- })
- },
-
- _create: function() {
- this._super();
-
- // If it's not reflow mode, return here.
- if ( this.options.mode !== "reflow" ) {
- return;
- }
-
- if ( !this.options.enhanced ) {
- this.element.addClass( this.options.classes.reflowTable );
-
- this._updateReflow();
- }
- },
-
- rebuild: function() {
- this._super();
-
- if ( this.options.mode === "reflow" ) {
- this._refresh( false );
- }
- },
-
- _refresh: function( create ) {
- this._super( create );
- if ( !create && this.options.mode === "reflow" ) {
- this._updateReflow( );
- }
- },
-
- _updateReflow: function() {
- var table = this,
- opts = this.options;
-
- // get headers in reverse order so that top-level headers are appended last
- $( table.allHeaders.get().reverse() ).each( function() {
- var cells = $( this ).jqmData( "cells" ),
- colstart = $.mobile.getAttribute( this, "colstart" ),
- hierarchyClass = cells.not( this ).filter( "thead th" ).length && " ui-table-cell-label-top",
- text = $( this ).text(),
- iteration, filter;
-
- if ( text !== "" ) {
-
- if ( hierarchyClass ) {
- iteration = parseInt( this.getAttribute( "colspan" ), 10 );
- filter = "";
-
- if ( iteration ) {
- filter = "td:nth-child("+ iteration +"n + " + ( colstart ) +")";
- }
-
- table._addLabels( cells.filter( filter ), opts.classes.cellLabels + hierarchyClass, text );
- } else {
- table._addLabels( cells, opts.classes.cellLabels, text );
- }
-
- }
- });
- },
-
- _addLabels: function( cells, label, text ) {
- // .not fixes #6006
- cells.not( ":has(b." + label + ")" ).prepend( "<b class='" + label + "'>" + text + "</b>" );
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-// TODO rename filterCallback/deprecate and default to the item itself as the first argument
-var defaultFilterCallback = function( index, searchValue ) {
- return ( ( "" + ( $.mobile.getAttribute( this, "filtertext" ) || $( this ).text() ) )
- .toLowerCase().indexOf( searchValue ) === -1 );
-};
-
-$.widget( "mobile.filterable", {
-
- initSelector: ":jqmData(filter='true')",
-
- options: {
- filterReveal: false,
- filterCallback: defaultFilterCallback,
- enhanced: false,
- input: null,
- children: "> li, > option, > optgroup option, > tbody tr, > .ui-controlgroup-controls > .ui-btn, > .ui-controlgroup-controls > .ui-checkbox, > .ui-controlgroup-controls > .ui-radio"
- },
-
- _create: function() {
- var opts = this.options;
-
- $.extend( this, {
- _search: null,
- _timer: 0
- });
-
- this._setInput( opts.input );
- if ( !opts.enhanced ) {
- this._filterItems( ( ( this._search && this._search.val() ) || "" ).toLowerCase() );
- }
- },
-
- _onKeyUp: function() {
- var val, lastval,
- search = this._search;
-
- if ( search ) {
- val = search.val().toLowerCase(),
- lastval = $.mobile.getAttribute( search[ 0 ], "lastval" ) + "";
-
- if ( lastval && lastval === val ) {
- // Execute the handler only once per value change
- return;
- }
-
- if ( this._timer ) {
- window.clearTimeout( this._timer );
- this._timer = 0;
- }
-
- this._timer = this._delay( function() {
- this._trigger( "beforefilter", null, { input: search } );
-
- // Change val as lastval for next execution
- search[ 0 ].setAttribute( "data-" + $.mobile.ns + "lastval", val );
-
- this._filterItems( val );
- this._timer = 0;
- }, 250 );
- }
- },
-
- _getFilterableItems: function() {
- var elem = this.element,
- children = this.options.children,
- items = !children ? { length: 0 }:
- $.isFunction( children ) ? children():
- children.nodeName ? $( children ):
- children.jquery ? children:
- this.element.find( children );
-
- if ( items.length === 0 ) {
- items = elem.children();
- }
-
- return items;
- },
-
- _filterItems: function( val ) {
- var idx, callback, length, dst,
- show = [],
- hide = [],
- opts = this.options,
- filterItems = this._getFilterableItems();
-
- if ( val != null ) {
- callback = opts.filterCallback || defaultFilterCallback;
- length = filterItems.length;
-
- // Partition the items into those to be hidden and those to be shown
- for ( idx = 0 ; idx < length ; idx++ ) {
- dst = ( callback.call( filterItems[ idx ], idx, val ) ) ? hide : show;
- dst.push( filterItems[ idx ] );
- }
- }
-
- // If nothing is hidden, then the decision whether to hide or show the items
- // is based on the "filterReveal" option.
- if ( hide.length === 0 ) {
- filterItems[ opts.filterReveal ? "addClass" : "removeClass" ]( "ui-screen-hidden" );
- } else {
- $( hide ).addClass( "ui-screen-hidden" );
- $( show ).removeClass( "ui-screen-hidden" );
- }
-
- this._refreshChildWidget();
-
- this._trigger( "filter", null, {
- items: filterItems
- });
- },
-
- // The Default implementation of _refreshChildWidget attempts to call
- // refresh on collapsibleset, controlgroup, selectmenu, or listview
- _refreshChildWidget: function() {
- var widget, idx,
- recognizedWidgets = [ "collapsibleset", "selectmenu", "controlgroup", "listview" ];
-
- for ( idx = recognizedWidgets.length - 1 ; idx > -1 ; idx-- ) {
- widget = recognizedWidgets[ idx ];
- if ( $.mobile[ widget ] ) {
- widget = this.element.data( "mobile-" + widget );
- if ( widget && $.isFunction( widget.refresh ) ) {
- widget.refresh();
- }
- }
- }
- },
-
- // TODO: When the input is not internal, do not even store it in this._search
- _setInput: function ( selector ) {
- var search = this._search;
-
- // Stop a pending filter operation
- if ( this._timer ) {
- window.clearTimeout( this._timer );
- this._timer = 0;
- }
-
- if ( search ) {
- this._off( search, "keyup change input" );
- search = null;
- }
-
- if ( selector ) {
- search = selector.jquery ? selector:
- selector.nodeName ? $( selector ):
- this.document.find( selector );
-
- this._on( search, {
- keyup: "_onKeyUp",
- change: "_onKeyUp",
- input: "_onKeyUp"
- });
- }
-
- this._search = search;
- },
-
- _setOptions: function( options ) {
- var refilter = !( ( options.filterReveal === undefined ) &&
- ( options.filterCallback === undefined ) &&
- ( options.children === undefined ) );
-
- this._super( options );
-
- if ( options.input !== undefined ) {
- this._setInput( options.input );
- refilter = true;
- }
-
- if ( refilter ) {
- this.refresh();
- }
- },
-
- _destroy: function() {
- var opts = this.options,
- items = this._getFilterableItems();
-
- if ( opts.enhanced ) {
- items.toggleClass( "ui-screen-hidden", opts.filterReveal );
- } else {
- items.removeClass( "ui-screen-hidden" );
- }
- },
-
- refresh: function() {
- if ( this._timer ) {
- window.clearTimeout( this._timer );
- this._timer = 0;
- }
- this._filterItems( ( ( this._search && this._search.val() ) || "" ).toLowerCase() );
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-// Create a function that will replace the _setOptions function of a widget,
-// and will pass the options on to the input of the filterable.
-var replaceSetOptions = function( self, orig ) {
- return function( options ) {
- orig.call( this, options );
- self._syncTextInputOptions( options );
- };
- },
- rDividerListItem = /(^|\s)ui-li-divider(\s|$)/,
- origDefaultFilterCallback = $.mobile.filterable.prototype.options.filterCallback;
-
-// Override the default filter callback with one that does not hide list dividers
-$.mobile.filterable.prototype.options.filterCallback = function( index, searchValue ) {
- return !this.className.match( rDividerListItem ) &&
- origDefaultFilterCallback.call( this, index, searchValue );
-};
-
-$.widget( "mobile.filterable", $.mobile.filterable, {
- options: {
- filterPlaceholder: "Filter items...",
- filterTheme: null
- },
-
- _create: function() {
- var idx, widgetName,
- elem = this.element,
- recognizedWidgets = [ "collapsibleset", "selectmenu", "controlgroup", "listview" ],
- createHandlers = {};
-
- this._super();
-
- $.extend( this, {
- _widget: null
- });
-
- for ( idx = recognizedWidgets.length - 1 ; idx > -1 ; idx-- ) {
- widgetName = recognizedWidgets[ idx ];
- if ( $.mobile[ widgetName ] ) {
- if ( this._setWidget( elem.data( "mobile-" + widgetName ) ) ) {
- break;
- } else {
- createHandlers[ widgetName + "create" ] = "_handleCreate";
- }
- }
- }
-
- if ( !this._widget ) {
- this._on( elem, createHandlers );
- }
- },
-
- _handleCreate: function( evt ) {
- this._setWidget( this.element.data( "mobile-" + evt.type.substring( 0, evt.type.length - 6 ) ) );
- },
-
- _trigger: function( type, event, data ) {
- if ( this._widget && this._widget.widgetFullName === "mobile-listview" &&
- type === "beforefilter" ) {
-
- // Also trigger listviewbeforefilter if this widget is also a listview
- this._widget._trigger( "beforefilter", event, data );
- }
- this._super( type, event, data );
- },
-
- _setWidget: function( widget ) {
- if ( !this._widget && widget ) {
- this._widget = widget;
- this._widget._setOptions = replaceSetOptions( this, this._widget._setOptions );
- }
-
- if ( !!this._widget ) {
- this._syncTextInputOptions( this._widget.options );
- if ( this._widget.widgetName === "listview" ) {
- this._widget.options.hideDividers = true;
- this._widget.element.listview( "refresh" );
- }
- }
-
- return !!this._widget;
- },
-
- _isSearchInternal: function() {
- return ( this._search && this._search.jqmData( "ui-filterable-" + this.uuid + "-internal" ) );
- },
-
- _setInput: function( selector ) {
- var opts = this.options,
- updatePlaceholder = true,
- textinputOpts = {};
-
- if ( !selector ) {
- if ( this._isSearchInternal() ) {
-
- // Ignore the call to set a new input if the selector goes to falsy and
- // the current textinput is already of the internally generated variety.
- return;
- } else {
-
- // Generating a new textinput widget. No need to set the placeholder
- // further down the function.
- updatePlaceholder = false;
- selector = $( "<input " +
- "data-" + $.mobile.ns + "type='search' " +
- "placeholder='" + opts.filterPlaceholder + "'></input>" )
- .jqmData( "ui-filterable-" + this.uuid + "-internal", true );
- $( "<form class='ui-filterable'></form>" )
- .append( selector )
- .submit( function( evt ) {
- evt.preventDefault();
- selector.blur();
- })
- .insertBefore( this.element );
- if ( $.mobile.textinput ) {
- if ( this.options.filterTheme != null ) {
- textinputOpts[ "theme" ] = opts.filterTheme;
- }
-
- selector.textinput( textinputOpts );
- }
- }
- }
-
- this._super( selector );
-
- if ( this._isSearchInternal() && updatePlaceholder ) {
- this._search.attr( "placeholder", this.options.filterPlaceholder );
- }
- },
-
- _setOptions: function( options ) {
- var ret = this._super( options );
-
- // Need to set the filterPlaceholder after having established the search input
- if ( options.filterPlaceholder !== undefined ) {
- if ( this._isSearchInternal() ) {
- this._search.attr( "placeholder", options.filterPlaceholder );
- }
- }
-
- if ( options.filterTheme !== undefined && this._search && $.mobile.textinput ) {
- this._search.textinput( "option", "theme", options.filterTheme );
- }
-
- return ret;
- },
-
- _destroy: function() {
- if ( this._isSearchInternal() ) {
- this._search.remove();
- }
- this._super();
- },
-
- _syncTextInputOptions: function( options ) {
- var idx,
- textinputOptions = {};
-
- // We only sync options if the filterable's textinput is of the internally
- // generated variety, rather than one specified by the user.
- if ( this._isSearchInternal() && $.mobile.textinput ) {
-
- // Apply only the options understood by textinput
- for ( idx in $.mobile.textinput.prototype.options ) {
- if ( options[ idx ] !== undefined ) {
- if ( idx === "theme" && this.options.filterTheme != null ) {
- textinputOptions[ idx ] = this.options.filterTheme;
- } else {
- textinputOptions[ idx ] = options[ idx ];
- }
- }
- }
- this._search.textinput( "option", textinputOptions );
- }
- }
-});
-
-})( jQuery );
-
-/*!
- * jQuery UI Tabs fadf2b312a05040436451c64bbfaf4814bc62c56
- * http://jqueryui.com
- *
- * Copyright 2013 jQuery Foundation and other contributors
- * Released under the MIT license.
- * http://jquery.org/license
- *
- * http://api.jqueryui.com/tabs/
- *
- * Depends:
- * jquery.ui.core.js
- * jquery.ui.widget.js
- */
-(function( $, undefined ) {
-
-var tabId = 0,
- rhash = /#.*$/;
-
-function getNextTabId() {
- return ++tabId;
-}
-
-function isLocal( anchor ) {
- return anchor.hash.length > 1 &&
- decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
- decodeURIComponent( location.href.replace( rhash, "" ) );
-}
-
-$.widget( "ui.tabs", {
- version: "fadf2b312a05040436451c64bbfaf4814bc62c56",
- delay: 300,
- options: {
- active: null,
- collapsible: false,
- event: "click",
- heightStyle: "content",
- hide: null,
- show: null,
-
- // callbacks
- activate: null,
- beforeActivate: null,
- beforeLoad: null,
- load: null
- },
-
- _create: function() {
- var that = this,
- options = this.options;
-
- this.running = false;
-
- this.element
- .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
- .toggleClass( "ui-tabs-collapsible", options.collapsible )
- // Prevent users from focusing disabled tabs via click
- .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
- if ( $( this ).is( ".ui-state-disabled" ) ) {
- event.preventDefault();
- }
- })
- // support: IE <9
- // Preventing the default action in mousedown doesn't prevent IE
- // from focusing the element, so if the anchor gets focused, blur.
- // We don't have to worry about focusing the previously focused
- // element since clicking on a non-focusable element should focus
- // the body anyway.
- .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
- if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
- this.blur();
- }
- });
-
- this._processTabs();
- options.active = this._initialActive();
-
- // Take disabling tabs via class attribute from HTML
- // into account and update option properly.
- if ( $.isArray( options.disabled ) ) {
- options.disabled = $.unique( options.disabled.concat(
- $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
- return that.tabs.index( li );
- })
- ) ).sort();
- }
-
- // check for length avoids error when initializing empty list
- if ( this.options.active !== false && this.anchors.length ) {
- this.active = this._findActive( options.active );
- } else {
- this.active = $();
- }
-
- this._refresh();
-
- if ( this.active.length ) {
- this.load( options.active );
- }
- },
-
- _initialActive: function() {
- var active = this.options.active,
- collapsible = this.options.collapsible,
- locationHash = location.hash.substring( 1 );
-
- if ( active === null ) {
- // check the fragment identifier in the URL
- if ( locationHash ) {
- this.tabs.each(function( i, tab ) {
- if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
- active = i;
- return false;
- }
- });
- }
-
- // check for a tab marked active via a class
- if ( active === null ) {
- active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
- }
-
- // no active tab, set to false
- if ( active === null || active === -1 ) {
- active = this.tabs.length ? 0 : false;
- }
- }
-
- // handle numbers: negative, out of range
- if ( active !== false ) {
- active = this.tabs.index( this.tabs.eq( active ) );
- if ( active === -1 ) {
- active = collapsible ? false : 0;
- }
- }
-
- // don't allow collapsible: false and active: false
- if ( !collapsible && active === false && this.anchors.length ) {
- active = 0;
- }
-
- return active;
- },
-
- _getCreateEventData: function() {
- return {
- tab: this.active,
- panel: !this.active.length ? $() : this._getPanelForTab( this.active )
- };
- },
-
- _tabKeydown: function( event ) {
- var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
- selectedIndex = this.tabs.index( focusedTab ),
- goingForward = true;
-
- if ( this._handlePageNav( event ) ) {
- return;
- }
-
- switch ( event.keyCode ) {
- case $.ui.keyCode.RIGHT:
- case $.ui.keyCode.DOWN:
- selectedIndex++;
- break;
- case $.ui.keyCode.UP:
- case $.ui.keyCode.LEFT:
- goingForward = false;
- selectedIndex--;
- break;
- case $.ui.keyCode.END:
- selectedIndex = this.anchors.length - 1;
- break;
- case $.ui.keyCode.HOME:
- selectedIndex = 0;
- break;
- case $.ui.keyCode.SPACE:
- // Activate only, no collapsing
- event.preventDefault();
- clearTimeout( this.activating );
- this._activate( selectedIndex );
- return;
- case $.ui.keyCode.ENTER:
- // Toggle (cancel delayed activation, allow collapsing)
- event.preventDefault();
- clearTimeout( this.activating );
- // Determine if we should collapse or activate
- this._activate( selectedIndex === this.options.active ? false : selectedIndex );
- return;
- default:
- return;
- }
-
- // Focus the appropriate tab, based on which key was pressed
- event.preventDefault();
- clearTimeout( this.activating );
- selectedIndex = this._focusNextTab( selectedIndex, goingForward );
-
- // Navigating with control key will prevent automatic activation
- if ( !event.ctrlKey ) {
- // Update aria-selected immediately so that AT think the tab is already selected.
- // Otherwise AT may confuse the user by stating that they need to activate the tab,
- // but the tab will already be activated by the time the announcement finishes.
- focusedTab.attr( "aria-selected", "false" );
- this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
-
- this.activating = this._delay(function() {
- this.option( "active", selectedIndex );
- }, this.delay );
- }
- },
-
- _panelKeydown: function( event ) {
- if ( this._handlePageNav( event ) ) {
- return;
- }
-
- // Ctrl+up moves focus to the current tab
- if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
- event.preventDefault();
- this.active.focus();
- }
- },
-
- // Alt+page up/down moves focus to the previous/next tab (and activates)
- _handlePageNav: function( event ) {
- if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
- this._activate( this._focusNextTab( this.options.active - 1, false ) );
- return true;
- }
- if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
- this._activate( this._focusNextTab( this.options.active + 1, true ) );
- return true;
- }
- },
-
- _findNextTab: function( index, goingForward ) {
- var lastTabIndex = this.tabs.length - 1;
-
- function constrain() {
- if ( index > lastTabIndex ) {
- index = 0;
- }
- if ( index < 0 ) {
- index = lastTabIndex;
- }
- return index;
- }
-
- while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
- index = goingForward ? index + 1 : index - 1;
- }
-
- return index;
- },
-
- _focusNextTab: function( index, goingForward ) {
- index = this._findNextTab( index, goingForward );
- this.tabs.eq( index ).focus();
- return index;
- },
-
- _setOption: function( key, value ) {
- if ( key === "active" ) {
- // _activate() will handle invalid values and update this.options
- this._activate( value );
- return;
- }
-
- if ( key === "disabled" ) {
- // don't use the widget factory's disabled handling
- this._setupDisabled( value );
- return;
- }
-
- this._super( key, value);
-
- if ( key === "collapsible" ) {
- this.element.toggleClass( "ui-tabs-collapsible", value );
- // Setting collapsible: false while collapsed; open first panel
- if ( !value && this.options.active === false ) {
- this._activate( 0 );
- }
- }
-
- if ( key === "event" ) {
- this._setupEvents( value );
- }
-
- if ( key === "heightStyle" ) {
- this._setupHeightStyle( value );
- }
- },
-
- _tabId: function( tab ) {
- return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
- },
-
- _sanitizeSelector: function( hash ) {
- return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
- },
-
- refresh: function() {
- var options = this.options,
- lis = this.tablist.children( ":has(a[href])" );
-
- // get disabled tabs from class attribute from HTML
- // this will get converted to a boolean if needed in _refresh()
- options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
- return lis.index( tab );
- });
-
- this._processTabs();
-
- // was collapsed or no tabs
- if ( options.active === false || !this.anchors.length ) {
- options.active = false;
- this.active = $();
- // was active, but active tab is gone
- } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
- // all remaining tabs are disabled
- if ( this.tabs.length === options.disabled.length ) {
- options.active = false;
- this.active = $();
- // activate previous tab
- } else {
- this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
- }
- // was active, active tab still exists
- } else {
- // make sure active index is correct
- options.active = this.tabs.index( this.active );
- }
-
- this._refresh();
- },
-
- _refresh: function() {
- this._setupDisabled( this.options.disabled );
- this._setupEvents( this.options.event );
- this._setupHeightStyle( this.options.heightStyle );
-
- this.tabs.not( this.active ).attr({
- "aria-selected": "false",
- tabIndex: -1
- });
- this.panels.not( this._getPanelForTab( this.active ) )
- .hide()
- .attr({
- "aria-expanded": "false",
- "aria-hidden": "true"
- });
-
- // Make sure one tab is in the tab order
- if ( !this.active.length ) {
- this.tabs.eq( 0 ).attr( "tabIndex", 0 );
- } else {
- this.active
- .addClass( "ui-tabs-active ui-state-active" )
- .attr({
- "aria-selected": "true",
- tabIndex: 0
- });
- this._getPanelForTab( this.active )
- .show()
- .attr({
- "aria-expanded": "true",
- "aria-hidden": "false"
- });
- }
- },
-
- _processTabs: function() {
- var that = this;
-
- this.tablist = this._getList()
- .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
- .attr( "role", "tablist" );
-
- this.tabs = this.tablist.find( "> li:has(a[href])" )
- .addClass( "ui-state-default ui-corner-top" )
- .attr({
- role: "tab",
- tabIndex: -1
- });
-
- this.anchors = this.tabs.map(function() {
- return $( "a", this )[ 0 ];
- })
- .addClass( "ui-tabs-anchor" )
- .attr({
- role: "presentation",
- tabIndex: -1
- });
-
- this.panels = $();
-
- this.anchors.each(function( i, anchor ) {
- var selector, panel, panelId,
- anchorId = $( anchor ).uniqueId().attr( "id" ),
- tab = $( anchor ).closest( "li" ),
- originalAriaControls = tab.attr( "aria-controls" );
-
- // inline tab
- if ( isLocal( anchor ) ) {
- selector = anchor.hash;
- panel = that.element.find( that._sanitizeSelector( selector ) );
- // remote tab
- } else {
- panelId = that._tabId( tab );
- selector = "#" + panelId;
- panel = that.element.find( selector );
- if ( !panel.length ) {
- panel = that._createPanel( panelId );
- panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
- }
- panel.attr( "aria-live", "polite" );
- }
-
- if ( panel.length) {
- that.panels = that.panels.add( panel );
- }
- if ( originalAriaControls ) {
- tab.data( "ui-tabs-aria-controls", originalAriaControls );
- }
- tab.attr({
- "aria-controls": selector.substring( 1 ),
- "aria-labelledby": anchorId
- });
- panel.attr( "aria-labelledby", anchorId );
- });
-
- this.panels
- .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
- .attr( "role", "tabpanel" );
- },
-
- // allow overriding how to find the list for rare usage scenarios (#7715)
- _getList: function() {
- return this.element.find( "ol,ul" ).eq( 0 );
- },
-
- _createPanel: function( id ) {
- return $( "<div>" )
- .attr( "id", id )
- .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
- .data( "ui-tabs-destroy", true );
- },
-
- _setupDisabled: function( disabled ) {
- if ( $.isArray( disabled ) ) {
- if ( !disabled.length ) {
- disabled = false;
- } else if ( disabled.length === this.anchors.length ) {
- disabled = true;
- }
- }
-
- // disable tabs
- for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
- if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
- $( li )
- .addClass( "ui-state-disabled" )
- .attr( "aria-disabled", "true" );
- } else {
- $( li )
- .removeClass( "ui-state-disabled" )
- .removeAttr( "aria-disabled" );
- }
- }
-
- this.options.disabled = disabled;
- },
-
- _setupEvents: function( event ) {
- var events = {
- click: function( event ) {
- event.preventDefault();
- }
- };
- if ( event ) {
- $.each( event.split(" "), function( index, eventName ) {
- events[ eventName ] = "_eventHandler";
- });
- }
-
- this._off( this.anchors.add( this.tabs ).add( this.panels ) );
- this._on( this.anchors, events );
- this._on( this.tabs, { keydown: "_tabKeydown" } );
- this._on( this.panels, { keydown: "_panelKeydown" } );
-
- this._focusable( this.tabs );
- this._hoverable( this.tabs );
- },
-
- _setupHeightStyle: function( heightStyle ) {
- var maxHeight,
- parent = this.element.parent();
-
- if ( heightStyle === "fill" ) {
- maxHeight = parent.height();
- maxHeight -= this.element.outerHeight() - this.element.height();
-
- this.element.siblings( ":visible" ).each(function() {
- var elem = $( this ),
- position = elem.css( "position" );
-
- if ( position === "absolute" || position === "fixed" ) {
- return;
- }
- maxHeight -= elem.outerHeight( true );
- });
-
- this.element.children().not( this.panels ).each(function() {
- maxHeight -= $( this ).outerHeight( true );
- });
-
- this.panels.each(function() {
- $( this ).height( Math.max( 0, maxHeight -
- $( this ).innerHeight() + $( this ).height() ) );
- })
- .css( "overflow", "auto" );
- } else if ( heightStyle === "auto" ) {
- maxHeight = 0;
- this.panels.each(function() {
- maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
- }).height( maxHeight );
- }
- },
-
- _eventHandler: function( event ) {
- var options = this.options,
- active = this.active,
- anchor = $( event.currentTarget ),
- tab = anchor.closest( "li" ),
- clickedIsActive = tab[ 0 ] === active[ 0 ],
- collapsing = clickedIsActive && options.collapsible,
- toShow = collapsing ? $() : this._getPanelForTab( tab ),
- toHide = !active.length ? $() : this._getPanelForTab( active ),
- eventData = {
- oldTab: active,
- oldPanel: toHide,
- newTab: collapsing ? $() : tab,
- newPanel: toShow
- };
-
- event.preventDefault();
-
- if ( tab.hasClass( "ui-state-disabled" ) ||
- // tab is already loading
- tab.hasClass( "ui-tabs-loading" ) ||
- // can't switch durning an animation
- this.running ||
- // click on active header, but not collapsible
- ( clickedIsActive && !options.collapsible ) ||
- // allow canceling activation
- ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
- return;
- }
-
- options.active = collapsing ? false : this.tabs.index( tab );
-
- this.active = clickedIsActive ? $() : tab;
- if ( this.xhr ) {
- this.xhr.abort();
- }
-
- if ( !toHide.length && !toShow.length ) {
- $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
- }
-
- if ( toShow.length ) {
- this.load( this.tabs.index( tab ), event );
- }
- this._toggle( event, eventData );
- },
-
- // handles show/hide for selecting tabs
- _toggle: function( event, eventData ) {
- var that = this,
- toShow = eventData.newPanel,
- toHide = eventData.oldPanel;
-
- this.running = true;
-
- function complete() {
- that.running = false;
- that._trigger( "activate", event, eventData );
- }
-
- function show() {
- eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
-
- if ( toShow.length && that.options.show ) {
- that._show( toShow, that.options.show, complete );
- } else {
- toShow.show();
- complete();
- }
- }
-
- // start out by hiding, then showing, then completing
- if ( toHide.length && this.options.hide ) {
- this._hide( toHide, this.options.hide, function() {
- eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
- show();
- });
- } else {
- eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
- toHide.hide();
- show();
- }
-
- toHide.attr({
- "aria-expanded": "false",
- "aria-hidden": "true"
- });
- eventData.oldTab.attr( "aria-selected", "false" );
- // If we're switching tabs, remove the old tab from the tab order.
- // If we're opening from collapsed state, remove the previous tab from the tab order.
- // If we're collapsing, then keep the collapsing tab in the tab order.
- if ( toShow.length && toHide.length ) {
- eventData.oldTab.attr( "tabIndex", -1 );
- } else if ( toShow.length ) {
- this.tabs.filter(function() {
- return $( this ).attr( "tabIndex" ) === 0;
- })
- .attr( "tabIndex", -1 );
- }
-
- toShow.attr({
- "aria-expanded": "true",
- "aria-hidden": "false"
- });
- eventData.newTab.attr({
- "aria-selected": "true",
- tabIndex: 0
- });
- },
-
- _activate: function( index ) {
- var anchor,
- active = this._findActive( index );
-
- // trying to activate the already active panel
- if ( active[ 0 ] === this.active[ 0 ] ) {
- return;
- }
-
- // trying to collapse, simulate a click on the current active header
- if ( !active.length ) {
- active = this.active;
- }
-
- anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
- this._eventHandler({
- target: anchor,
- currentTarget: anchor,
- preventDefault: $.noop
- });
- },
-
- _findActive: function( index ) {
- return index === false ? $() : this.tabs.eq( index );
- },
-
- _getIndex: function( index ) {
- // meta-function to give users option to provide a href string instead of a numerical index.
- if ( typeof index === "string" ) {
- index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
- }
-
- return index;
- },
-
- _destroy: function() {
- if ( this.xhr ) {
- this.xhr.abort();
- }
-
- this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
-
- this.tablist
- .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
- .removeAttr( "role" );
-
- this.anchors
- .removeClass( "ui-tabs-anchor" )
- .removeAttr( "role" )
- .removeAttr( "tabIndex" )
- .removeUniqueId();
-
- this.tabs.add( this.panels ).each(function() {
- if ( $.data( this, "ui-tabs-destroy" ) ) {
- $( this ).remove();
- } else {
- $( this )
- .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
- "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
- .removeAttr( "tabIndex" )
- .removeAttr( "aria-live" )
- .removeAttr( "aria-busy" )
- .removeAttr( "aria-selected" )
- .removeAttr( "aria-labelledby" )
- .removeAttr( "aria-hidden" )
- .removeAttr( "aria-expanded" )
- .removeAttr( "role" );
- }
- });
-
- this.tabs.each(function() {
- var li = $( this ),
- prev = li.data( "ui-tabs-aria-controls" );
- if ( prev ) {
- li
- .attr( "aria-controls", prev )
- .removeData( "ui-tabs-aria-controls" );
- } else {
- li.removeAttr( "aria-controls" );
- }
- });
-
- this.panels.show();
-
- if ( this.options.heightStyle !== "content" ) {
- this.panels.css( "height", "" );
- }
- },
-
- enable: function( index ) {
- var disabled = this.options.disabled;
- if ( disabled === false ) {
- return;
- }
-
- if ( index === undefined ) {
- disabled = false;
- } else {
- index = this._getIndex( index );
- if ( $.isArray( disabled ) ) {
- disabled = $.map( disabled, function( num ) {
- return num !== index ? num : null;
- });
- } else {
- disabled = $.map( this.tabs, function( li, num ) {
- return num !== index ? num : null;
- });
- }
- }
- this._setupDisabled( disabled );
- },
-
- disable: function( index ) {
- var disabled = this.options.disabled;
- if ( disabled === true ) {
- return;
- }
-
- if ( index === undefined ) {
- disabled = true;
- } else {
- index = this._getIndex( index );
- if ( $.inArray( index, disabled ) !== -1 ) {
- return;
- }
- if ( $.isArray( disabled ) ) {
- disabled = $.merge( [ index ], disabled ).sort();
- } else {
- disabled = [ index ];
- }
- }
- this._setupDisabled( disabled );
- },
-
- load: function( index, event ) {
- index = this._getIndex( index );
- var that = this,
- tab = this.tabs.eq( index ),
- anchor = tab.find( ".ui-tabs-anchor" ),
- panel = this._getPanelForTab( tab ),
- eventData = {
- tab: tab,
- panel: panel
- };
-
- // not remote
- if ( isLocal( anchor[ 0 ] ) ) {
- return;
- }
-
- this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
-
- // support: jQuery <1.8
- // jQuery <1.8 returns false if the request is canceled in beforeSend,
- // but as of 1.8, $.ajax() always returns a jqXHR object.
- if ( this.xhr && this.xhr.statusText !== "canceled" ) {
- tab.addClass( "ui-tabs-loading" );
- panel.attr( "aria-busy", "true" );
-
- this.xhr
- .success(function( response ) {
- // support: jQuery <1.8
- // http://bugs.jquery.com/ticket/11778
- setTimeout(function() {
- panel.html( response );
- that._trigger( "load", event, eventData );
- }, 1 );
- })
- .complete(function( jqXHR, status ) {
- // support: jQuery <1.8
- // http://bugs.jquery.com/ticket/11778
- setTimeout(function() {
- if ( status === "abort" ) {
- that.panels.stop( false, true );
- }
-
- tab.removeClass( "ui-tabs-loading" );
- panel.removeAttr( "aria-busy" );
-
- if ( jqXHR === that.xhr ) {
- delete that.xhr;
- }
- }, 1 );
- });
- }
- },
-
- _ajaxSettings: function( anchor, event, eventData ) {
- var that = this;
- return {
- url: anchor.attr( "href" ),
- beforeSend: function( jqXHR, settings ) {
- return that._trigger( "beforeLoad", event,
- $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
- }
- };
- },
-
- _getPanelForTab: function( tab ) {
- var id = $( tab ).attr( "aria-controls" );
- return this.element.find( this._sanitizeSelector( "#" + id ) );
- }
-});
-
-})( jQuery );
-
-(function( $, undefined ) {
-
-})( jQuery );
-
-(function( $, window ) {
-
- $.mobile.iosorientationfixEnabled = true;
-
- // This fix addresses an iOS bug, so return early if the UA claims it's something else.
- var ua = navigator.userAgent,
- zoom,
- evt, x, y, z, aig;
- if ( !( /iPhone|iPad|iPod/.test( navigator.platform ) && /OS [1-5]_[0-9_]* like Mac OS X/i.test( ua ) && ua.indexOf( "AppleWebKit" ) > -1 ) ) {
- $.mobile.iosorientationfixEnabled = false;
- return;
- }
-
- zoom = $.mobile.zoom;
-
- function checkTilt( e ) {
- evt = e.originalEvent;
- aig = evt.accelerationIncludingGravity;
-
- x = Math.abs( aig.x );
- y = Math.abs( aig.y );
- z = Math.abs( aig.z );
-
- // If portrait orientation and in one of the danger zones
- if ( !window.orientation && ( x > 7 || ( ( z > 6 && y < 8 || z < 8 && y > 6 ) && x > 5 ) ) ) {
- if ( zoom.enabled ) {
- zoom.disable();
- }
- } else if ( !zoom.enabled ) {
- zoom.enable();
- }
- }
-
- $.mobile.document.on( "mobileinit", function() {
- if ( $.mobile.iosorientationfixEnabled ) {
- $.mobile.window
- .bind( "orientationchange.iosorientationfix", zoom.enable )
- .bind( "devicemotion.iosorientationfix", checkTilt );
- }
- });
-
-}( jQuery, this ));
-
-(function( $, window, undefined ) {
- var $html = $( "html" ),
- $window = $.mobile.window;
-
- //remove initial build class (only present on first pageshow)
- function hideRenderingClass() {
- $html.removeClass( "ui-mobile-rendering" );
- }
-
- // trigger mobileinit event - useful hook for configuring $.mobile settings before they're used
- $( window.document ).trigger( "mobileinit" );
-
- // support conditions
- // if device support condition(s) aren't met, leave things as they are -> a basic, usable experience,
- // otherwise, proceed with the enhancements
- if ( !$.mobile.gradeA() ) {
- return;
- }
-
- // override ajaxEnabled on platforms that have known conflicts with hash history updates
- // or generally work better browsing in regular http for full page refreshes (BB5, Opera Mini)
- if ( $.mobile.ajaxBlacklist ) {
- $.mobile.ajaxEnabled = false;
- }
-
- // Add mobile, initial load "rendering" classes to docEl
- $html.addClass( "ui-mobile ui-mobile-rendering" );
-
- // This is a fallback. If anything goes wrong (JS errors, etc), or events don't fire,
- // this ensures the rendering class is removed after 5 seconds, so content is visible and accessible
- setTimeout( hideRenderingClass, 5000 );
-
- $.extend( $.mobile, {
- // find and enhance the pages in the dom and transition to the first page.
- initializePage: function() {
- // find present pages
- var path = $.mobile.path,
- $pages = $( ":jqmData(role='page'), :jqmData(role='dialog')" ),
- hash = path.stripHash( path.stripQueryParams(path.parseLocation().hash) ),
- hashPage = document.getElementById( hash );
-
- // if no pages are found, create one with body's inner html
- if ( !$pages.length ) {
- $pages = $( "body" ).wrapInner( "<div data-" + $.mobile.ns + "role='page'></div>" ).children( 0 );
- }
-
- // add dialogs, set data-url attrs
- $pages.each(function() {
- var $this = $( this );
-
- // unless the data url is already set set it to the pathname
- if ( !$this[ 0 ].getAttribute( "data-" + $.mobile.ns + "url" ) ) {
- $this.attr( "data-" + $.mobile.ns + "url", $this.attr( "id" ) || location.pathname + location.search );
- }
- });
-
- // define first page in dom case one backs out to the directory root (not always the first page visited, but defined as fallback)
- $.mobile.firstPage = $pages.first();
-
- // define page container
- $.mobile.pageContainer = $.mobile.firstPage
- .parent()
- .addClass( "ui-mobile-viewport" )
- .pagecontainer();
-
- // initialize navigation events now, after mobileinit has occurred and the page container
- // has been created but before the rest of the library is alerted to that fact
- $.mobile.navreadyDeferred.resolve();
-
- // alert listeners that the pagecontainer has been determined for binding
- // to events triggered on it
- $window.trigger( "pagecontainercreate" );
-
- // cue page loading message
- $.mobile.loading( "show" );
-
- //remove initial build class (only present on first pageshow)
- hideRenderingClass();
-
- // if hashchange listening is disabled, there's no hash deeplink,
- // the hash is not valid (contains more than one # or does not start with #)
- // or there is no page with that hash, change to the first page in the DOM
- // Remember, however, that the hash can also be a path!
- if ( ! ( $.mobile.hashListeningEnabled &&
- $.mobile.path.isHashValid( location.hash ) &&
- ( $( hashPage ).is( ":jqmData(role='page')" ) ||
- $.mobile.path.isPath( hash ) ||
- hash === $.mobile.dialogHashKey ) ) ) {
-
- // Store the initial destination
- if ( $.mobile.path.isHashValid( location.hash ) ) {
- $.mobile.navigate.history.initialDst = hash.replace( "#", "" );
- }
-
- // make sure to set initial popstate state if it exists
- // so that navigation back to the initial page works properly
- if ( $.event.special.navigate.isPushStateEnabled() ) {
- $.mobile.navigate.navigator.squash( path.parseLocation().href );
- }
-
- $.mobile.changePage( $.mobile.firstPage, {
- transition: "none",
- reverse: true,
- changeHash: false,
- fromHashChange: true
- });
- } else {
- // trigger hashchange or navigate to squash and record the correct
- // history entry for an initial hash path
- if ( !$.event.special.navigate.isPushStateEnabled() ) {
- $window.trigger( "hashchange", [true] );
- } else {
- // TODO figure out how to simplify this interaction with the initial history entry
- // at the bottom js/navigate/navigate.js
- $.mobile.navigate.history.stack = [];
- $.mobile.navigate( $.mobile.path.isPath( location.hash ) ? location.hash : location.href );
- }
- }
- }
- });
-
- $(function() {
- //Run inlineSVG support test
- $.support.inlineSVG();
-
- // check which scrollTop value should be used by scrolling to 1 immediately at domready
- // then check what the scroll top is. Android will report 0... others 1
- // note that this initial scroll won't hide the address bar. It's just for the check.
-
- // hide iOS browser chrome on load if hideUrlBar is true this is to try and do it as soon as possible
- if ( $.mobile.hideUrlBar ) {
- window.scrollTo( 0, 1 );
- }
-
- // if defaultHomeScroll hasn't been set yet, see if scrollTop is 1
- // it should be 1 in most browsers, but android treats 1 as 0 (for hiding addr bar)
- // so if it's 1, use 0 from now on
- $.mobile.defaultHomeScroll = ( !$.support.scrollTop || $.mobile.window.scrollTop() === 1 ) ? 0 : 1;
-
- //dom-ready inits
- if ( $.mobile.autoInitializePage ) {
- $.mobile.initializePage();
- }
-
- // window load event
- // hide iOS browser chrome on load if hideUrlBar is true this is as fall back incase we were too early before
- if ( $.mobile.hideUrlBar ) {
- $window.load( $.mobile.silentScroll );
- }
-
- if ( !$.support.cssPointerEvents ) {
- // IE and Opera don't support CSS pointer-events: none that we use to disable link-based buttons
- // by adding the 'ui-disabled' class to them. Using a JavaScript workaround for those browser.
- // https://github.com/jquery/jquery-mobile/issues/3558
-
- // DEPRECATED as of 1.4.0 - remove ui-disabled after 1.4.0 release
- // only ui-state-disabled should be present thereafter
- $.mobile.document.delegate( ".ui-state-disabled,.ui-disabled", "vclick",
- function( e ) {
- e.preventDefault();
- e.stopImmediatePropagation();
- }
- );
- }
- });
-}( jQuery, this ));
-
-
-}));
deleted file mode 100644
index e1a98e1580e465b08ca547ee1466977eb084ef0a..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/mootools-1.4.js
+++ /dev/null
@@ -1,6447 +0,0 @@
-/*
----
-MooTools: the javascript framework
-
-web build:
- - http://mootools.net/core/76bf47062d6c1983d66ce47ad66aa0e0
-
-packager build:
- - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Delegation Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady Core/Swiff
-
-...
-*/
-
-/*
----
-
-name: Core
-
-description: The heart of MooTools.
-
-license: MIT-style license.
-
-copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
-
-authors: The MooTools production team (http://mootools.net/developers/)
-
-inspiration:
- - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
- - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
-
-provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
-
-...
-*/
-
-(function(){
-
-this.MooTools = {
- version: '1.4.5',
- build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0'
-};
-
-// typeOf, instanceOf
-
-var typeOf = this.typeOf = function(item){
- if (item == null) return 'null';
- if (item.$family != null) return item.$family();
-
- if (item.nodeName){
- if (item.nodeType == 1) return 'element';
- if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
- } else if (typeof item.length == 'number'){
- if (item.callee) return 'arguments';
- if ('item' in item) return 'collection';
- }
-
- return typeof item;
-};
-
-var instanceOf = this.instanceOf = function(item, object){
- if (item == null) return false;
- var constructor = item.$constructor || item.constructor;
- while (constructor){
- if (constructor === object) return true;
- constructor = constructor.parent;
- }
- /*<ltIE8>*/
- if (!item.hasOwnProperty) return false;
- /*</ltIE8>*/
- return item instanceof object;
-};
-
-// Function overloading
-
-var Function = this.Function;
-
-var enumerables = true;
-for (var i in {toString: 1}) enumerables = null;
-if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
-
-Function.prototype.overloadSetter = function(usePlural){
- var self = this;
- return function(a, b){
- if (a == null) return this;
- if (usePlural || typeof a != 'string'){
- for (var k in a) self.call(this, k, a[k]);
- if (enumerables) for (var i = enumerables.length; i--;){
- k = enumerables[i];
- if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
- }
- } else {
- self.call(this, a, b);
- }
- return this;
- };
-};
-
-Function.prototype.overloadGetter = function(usePlural){
- var self = this;
- return function(a){
- var args, result;
- if (typeof a != 'string') args = a;
- else if (arguments.length > 1) args = arguments;
- else if (usePlural) args = [a];
- if (args){
- result = {};
- for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
- } else {
- result = self.call(this, a);
- }
- return result;
- };
-};
-
-Function.prototype.extend = function(key, value){
- this[key] = value;
-}.overloadSetter();
-
-Function.prototype.implement = function(key, value){
- this.prototype[key] = value;
-}.overloadSetter();
-
-// From
-
-var slice = Array.prototype.slice;
-
-Function.from = function(item){
- return (typeOf(item) == 'function') ? item : function(){
- return item;
- };
-};
-
-Array.from = function(item){
- if (item == null) return [];
- return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
-};
-
-Number.from = function(item){
- var number = parseFloat(item);
- return isFinite(number) ? number : null;
-};
-
-String.from = function(item){
- return item + '';
-};
-
-// hide, protect
-
-Function.implement({
-
- hide: function(){
- this.$hidden = true;
- return this;
- },
-
- protect: function(){
- this.$protected = true;
- return this;
- }
-
-});
-
-// Type
-
-var Type = this.Type = function(name, object){
- if (name){
- var lower = name.toLowerCase();
- var typeCheck = function(item){
- return (typeOf(item) == lower);
- };
-
- Type['is' + name] = typeCheck;
- if (object != null){
- object.prototype.$family = (function(){
- return lower;
- }).hide();
- //<1.2compat>
- object.type = typeCheck;
- //</1.2compat>
- }
- }
-
- if (object == null) return null;
-
- object.extend(this);
- object.$constructor = Type;
- object.prototype.$constructor = object;
-
- return object;
-};
-
-var toString = Object.prototype.toString;
-
-Type.isEnumerable = function(item){
- return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
-};
-
-var hooks = {};
-
-var hooksOf = function(object){
- var type = typeOf(object.prototype);
- return hooks[type] || (hooks[type] = []);
-};
-
-var implement = function(name, method){
- if (method && method.$hidden) return;
-
- var hooks = hooksOf(this);
-
- for (var i = 0; i < hooks.length; i++){
- var hook = hooks[i];
- if (typeOf(hook) == 'type') implement.call(hook, name, method);
- else hook.call(this, name, method);
- }
-
- var previous = this.prototype[name];
- if (previous == null || !previous.$protected) this.prototype[name] = method;
-
- if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
- return method.apply(item, slice.call(arguments, 1));
- });
-};
-
-var extend = function(name, method){
- if (method && method.$hidden) return;
- var previous = this[name];
- if (previous == null || !previous.$protected) this[name] = method;
-};
-
-Type.implement({
-
- implement: implement.overloadSetter(),
-
- extend: extend.overloadSetter(),
-
- alias: function(name, existing){
- implement.call(this, name, this.prototype[existing]);
- }.overloadSetter(),
-
- mirror: function(hook){
- hooksOf(this).push(hook);
- return this;
- }
-
-});
-
-new Type('Type', Type);
-
-// Default Types
-
-var force = function(name, object, methods){
- var isType = (object != Object),
- prototype = object.prototype;
-
- if (isType) object = new Type(name, object);
-
- for (var i = 0, l = methods.length; i < l; i++){
- var key = methods[i],
- generic = object[key],
- proto = prototype[key];
-
- if (generic) generic.protect();
- if (isType && proto) object.implement(key, proto.protect());
- }
-
- if (isType){
- var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
- object.forEachMethod = function(fn){
- if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
- fn.call(prototype, prototype[methods[i]], methods[i]);
- }
- for (var key in prototype) fn.call(prototype, prototype[key], key)
- };
- }
-
- return force;
-};
-
-force('String', String, [
- 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
- 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
-])('Array', Array, [
- 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
- 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
-])('Number', Number, [
- 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
-])('Function', Function, [
- 'apply', 'call', 'bind'
-])('RegExp', RegExp, [
- 'exec', 'test'
-])('Object', Object, [
- 'create', 'defineProperty', 'defineProperties', 'keys',
- 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
- 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
-])('Date', Date, ['now']);
-
-Object.extend = extend.overloadSetter();
-
-Date.extend('now', function(){
- return +(new Date);
-});
-
-new Type('Boolean', Boolean);
-
-// fixes NaN returning as Number
-
-Number.prototype.$family = function(){
- return isFinite(this) ? 'number' : 'null';
-}.hide();
-
-// Number.random
-
-Number.extend('random', function(min, max){
- return Math.floor(Math.random() * (max - min + 1) + min);
-});
-
-// forEach, each
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-Object.extend('forEach', function(object, fn, bind){
- for (var key in object){
- if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
- }
-});
-
-Object.each = Object.forEach;
-
-Array.implement({
-
- forEach: function(fn, bind){
- for (var i = 0, l = this.length; i < l; i++){
- if (i in this) fn.call(bind, this[i], i, this);
- }
- },
-
- each: function(fn, bind){
- Array.forEach(this, fn, bind);
- return this;
- }
-
-});
-
-// Array & Object cloning, Object merging and appending
-
-var cloneOf = function(item){
- switch (typeOf(item)){
- case 'array': return item.clone();
- case 'object': return Object.clone(item);
- default: return item;
- }
-};
-
-Array.implement('clone', function(){
- var i = this.length, clone = new Array(i);
- while (i--) clone[i] = cloneOf(this[i]);
- return clone;
-});
-
-var mergeOne = function(source, key, current){
- switch (typeOf(current)){
- case 'object':
- if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
- else source[key] = Object.clone(current);
- break;
- case 'array': source[key] = current.clone(); break;
- default: source[key] = current;
- }
- return source;
-};
-
-Object.extend({
-
- merge: function(source, k, v){
- if (typeOf(k) == 'string') return mergeOne(source, k, v);
- for (var i = 1, l = arguments.length; i < l; i++){
- var object = arguments[i];
- for (var key in object) mergeOne(source, key, object[key]);
- }
- return source;
- },
-
- clone: function(object){
- var clone = {};
- for (var key in object) clone[key] = cloneOf(object[key]);
- return clone;
- },
-
- append: function(original){
- for (var i = 1, l = arguments.length; i < l; i++){
- var extended = arguments[i] || {};
- for (var key in extended) original[key] = extended[key];
- }
- return original;
- }
-
-});
-
-// Object-less types
-
-['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
- new Type(name);
-});
-
-// Unique ID
-
-var UID = Date.now();
-
-String.extend('uniqueID', function(){
- return (UID++).toString(36);
-});
-
-//<1.2compat>
-
-var Hash = this.Hash = new Type('Hash', function(object){
- if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
- for (var key in object) this[key] = object[key];
- return this;
-});
-
-Hash.implement({
-
- forEach: function(fn, bind){
- Object.forEach(this, fn, bind);
- },
-
- getClean: function(){
- var clean = {};
- for (var key in this){
- if (this.hasOwnProperty(key)) clean[key] = this[key];
- }
- return clean;
- },
-
- getLength: function(){
- var length = 0;
- for (var key in this){
- if (this.hasOwnProperty(key)) length++;
- }
- return length;
- }
-
-});
-
-Hash.alias('each', 'forEach');
-
-Object.type = Type.isObject;
-
-var Native = this.Native = function(properties){
- return new Type(properties.name, properties.initialize);
-};
-
-Native.type = Type.type;
-
-Native.implement = function(objects, methods){
- for (var i = 0; i < objects.length; i++) objects[i].implement(methods);
- return Native;
-};
-
-var arrayType = Array.type;
-Array.type = function(item){
- return instanceOf(item, Array) || arrayType(item);
-};
-
-this.$A = function(item){
- return Array.from(item).slice();
-};
-
-this.$arguments = function(i){
- return function(){
- return arguments[i];
- };
-};
-
-this.$chk = function(obj){
- return !!(obj || obj === 0);
-};
-
-this.$clear = function(timer){
- clearTimeout(timer);
- clearInterval(timer);
- return null;
-};
-
-this.$defined = function(obj){
- return (obj != null);
-};
-
-this.$each = function(iterable, fn, bind){
- var type = typeOf(iterable);
- ((type == 'arguments' || type == 'collection' || type == 'array' || type == 'elements') ? Array : Object).each(iterable, fn, bind);
-};
-
-this.$empty = function(){};
-
-this.$extend = function(original, extended){
- return Object.append(original, extended);
-};
-
-this.$H = function(object){
- return new Hash(object);
-};
-
-this.$merge = function(){
- var args = Array.slice(arguments);
- args.unshift({});
- return Object.merge.apply(null, args);
-};
-
-this.$lambda = Function.from;
-this.$mixin = Object.merge;
-this.$random = Number.random;
-this.$splat = Array.from;
-this.$time = Date.now;
-
-this.$type = function(object){
- var type = typeOf(object);
- if (type == 'elements') return 'array';
- return (type == 'null') ? false : type;
-};
-
-this.$unlink = function(object){
- switch (typeOf(object)){
- case 'object': return Object.clone(object);
- case 'array': return Array.clone(object);
- case 'hash': return new Hash(object);
- default: return object;
- }
-};
-
-//</1.2compat>
-
-})();
-
-
-/*
----
-
-name: Array
-
-description: Contains Array Prototypes like each, contains, and erase.
-
-license: MIT-style license.
-
-requires: Type
-
-provides: Array
-
-...
-*/
-
-Array.implement({
-
- /*<!ES5>*/
- every: function(fn, bind){
- for (var i = 0, l = this.length >>> 0; i < l; i++){
- if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
- }
- return true;
- },
-
- filter: function(fn, bind){
- var results = [];
- for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
- value = this[i];
- if (fn.call(bind, value, i, this)) results.push(value);
- }
- return results;
- },
-
- indexOf: function(item, from){
- var length = this.length >>> 0;
- for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
- if (this[i] === item) return i;
- }
- return -1;
- },
-
- map: function(fn, bind){
- var length = this.length >>> 0, results = Array(length);
- for (var i = 0; i < length; i++){
- if (i in this) results[i] = fn.call(bind, this[i], i, this);
- }
- return results;
- },
-
- some: function(fn, bind){
- for (var i = 0, l = this.length >>> 0; i < l; i++){
- if ((i in this) && fn.call(bind, this[i], i, this)) return true;
- }
- return false;
- },
- /*</!ES5>*/
-
- clean: function(){
- return this.filter(function(item){
- return item != null;
- });
- },
-
- invoke: function(methodName){
- var args = Array.slice(arguments, 1);
- return this.map(function(item){
- return item[methodName].apply(item, args);
- });
- },
-
- associate: function(keys){
- var obj = {}, length = Math.min(this.length, keys.length);
- for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
- return obj;
- },
-
- link: function(object){
- var result = {};
- for (var i = 0, l = this.length; i < l; i++){
- for (var key in object){
- if (object[key](this[i])){
- result[key] = this[i];
- delete object[key];
- break;
- }
- }
- }
- return result;
- },
-
- contains: function(item, from){
- return this.indexOf(item, from) != -1;
- },
-
- append: function(array){
- this.push.apply(this, array);
- return this;
- },
-
- getLast: function(){
- return (this.length) ? this[this.length - 1] : null;
- },
-
- getRandom: function(){
- return (this.length) ? this[Number.random(0, this.length - 1)] : null;
- },
-
- include: function(item){
- if (!this.contains(item)) this.push(item);
- return this;
- },
-
- combine: function(array){
- for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
- return this;
- },
-
- erase: function(item){
- for (var i = this.length; i--;){
- if (this[i] === item) this.splice(i, 1);
- }
- return this;
- },
-
- empty: function(){
- this.length = 0;
- return this;
- },
-
- flatten: function(){
- var array = [];
- for (var i = 0, l = this.length; i < l; i++){
- var type = typeOf(this[i]);
- if (type == 'null') continue;
- array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
- }
- return array;
- },
-
- pick: function(){
- for (var i = 0, l = this.length; i < l; i++){
- if (this[i] != null) return this[i];
- }
- return null;
- },
-
- hexToRgb: function(array){
- if (this.length != 3) return null;
- var rgb = this.map(function(value){
- if (value.length == 1) value += value;
- return value.toInt(16);
- });
- return (array) ? rgb : 'rgb(' + rgb + ')';
- },
-
- rgbToHex: function(array){
- if (this.length < 3) return null;
- if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
- var hex = [];
- for (var i = 0; i < 3; i++){
- var bit = (this[i] - 0).toString(16);
- hex.push((bit.length == 1) ? '0' + bit : bit);
- }
- return (array) ? hex : '#' + hex.join('');
- }
-
-});
-
-//<1.2compat>
-
-Array.alias('extend', 'append');
-
-var $pick = function(){
- return Array.from(arguments).pick();
-};
-
-//</1.2compat>
-
-
-/*
----
-
-name: String
-
-description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
-
-license: MIT-style license.
-
-requires: Type
-
-provides: String
-
-...
-*/
-
-String.implement({
-
- test: function(regex, params){
- return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
- },
-
- contains: function(string, separator){
- return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
- },
-
- trim: function(){
- return String(this).replace(/^\s+|\s+$/g, '');
- },
-
- clean: function(){
- return String(this).replace(/\s+/g, ' ').trim();
- },
-
- camelCase: function(){
- return String(this).replace(/-\D/g, function(match){
- return match.charAt(1).toUpperCase();
- });
- },
-
- hyphenate: function(){
- return String(this).replace(/[A-Z]/g, function(match){
- return ('-' + match.charAt(0).toLowerCase());
- });
- },
-
- capitalize: function(){
- return String(this).replace(/\b[a-z]/g, function(match){
- return match.toUpperCase();
- });
- },
-
- escapeRegExp: function(){
- return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
- },
-
- toInt: function(base){
- return parseInt(this, base || 10);
- },
-
- toFloat: function(){
- return parseFloat(this);
- },
-
- hexToRgb: function(array){
- var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
- return (hex) ? hex.slice(1).hexToRgb(array) : null;
- },
-
- rgbToHex: function(array){
- var rgb = String(this).match(/\d{1,3}/g);
- return (rgb) ? rgb.rgbToHex(array) : null;
- },
-
- substitute: function(object, regexp){
- return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
- if (match.charAt(0) == '\\') return match.slice(1);
- return (object[name] != null) ? object[name] : '';
- });
- }
-
-});
-
-
-/*
----
-
-name: Number
-
-description: Contains Number Prototypes like limit, round, times, and ceil.
-
-license: MIT-style license.
-
-requires: Type
-
-provides: Number
-
-...
-*/
-
-Number.implement({
-
- limit: function(min, max){
- return Math.min(max, Math.max(min, this));
- },
-
- round: function(precision){
- precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
- return Math.round(this * precision) / precision;
- },
-
- times: function(fn, bind){
- for (var i = 0; i < this; i++) fn.call(bind, i, this);
- },
-
- toFloat: function(){
- return parseFloat(this);
- },
-
- toInt: function(base){
- return parseInt(this, base || 10);
- }
-
-});
-
-Number.alias('each', 'times');
-
-(function(math){
- var methods = {};
- math.each(function(name){
- if (!Number[name]) methods[name] = function(){
- return Math[name].apply(null, [this].concat(Array.from(arguments)));
- };
- });
- Number.implement(methods);
-})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
-
-
-/*
----
-
-name: Function
-
-description: Contains Function Prototypes like create, bind, pass, and delay.
-
-license: MIT-style license.
-
-requires: Type
-
-provides: Function
-
-...
-*/
-
-Function.extend({
-
- attempt: function(){
- for (var i = 0, l = arguments.length; i < l; i++){
- try {
- return arguments[i]();
- } catch (e){}
- }
- return null;
- }
-
-});
-
-Function.implement({
-
- attempt: function(args, bind){
- try {
- return this.apply(bind, Array.from(args));
- } catch (e){}
-
- return null;
- },
-
- /*<!ES5-bind>*/
- bind: function(that){
- var self = this,
- args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
- F = function(){};
-
- var bound = function(){
- var context = that, length = arguments.length;
- if (this instanceof bound){
- F.prototype = self.prototype;
- context = new F;
- }
- var result = (!args && !length)
- ? self.call(context)
- : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
- return context == that ? result : context;
- };
- return bound;
- },
- /*</!ES5-bind>*/
-
- pass: function(args, bind){
- var self = this;
- if (args != null) args = Array.from(args);
- return function(){
- return self.apply(bind, args || arguments);
- };
- },
-
- delay: function(delay, bind, args){
- return setTimeout(this.pass((args == null ? [] : args), bind), delay);
- },
-
- periodical: function(periodical, bind, args){
- return setInterval(this.pass((args == null ? [] : args), bind), periodical);
- }
-
-});
-
-//<1.2compat>
-
-delete Function.prototype.bind;
-
-Function.implement({
-
- create: function(options){
- var self = this;
- options = options || {};
- return function(event){
- var args = options.arguments;
- args = (args != null) ? Array.from(args) : Array.slice(arguments, (options.event) ? 1 : 0);
- if (options.event) args = [event || window.event].extend(args);
- var returns = function(){
- return self.apply(options.bind || null, args);
- };
- if (options.delay) return setTimeout(returns, options.delay);
- if (options.periodical) return setInterval(returns, options.periodical);
- if (options.attempt) return Function.attempt(returns);
- return returns();
- };
- },
-
- bind: function(bind, args){
- var self = this;
- if (args != null) args = Array.from(args);
- return function(){
- return self.apply(bind, args || arguments);
- };
- },
-
- bindWithEvent: function(bind, args){
- var self = this;
- if (args != null) args = Array.from(args);
- return function(event){
- return self.apply(bind, (args == null) ? arguments : [event].concat(args));
- };
- },
-
- run: function(args, bind){
- return this.apply(bind, Array.from(args));
- }
-
-});
-
-if (Object.create == Function.prototype.create) Object.create = null;
-
-var $try = Function.attempt;
-
-//</1.2compat>
-
-
-/*
----
-
-name: Object
-
-description: Object generic methods
-
-license: MIT-style license.
-
-requires: Type
-
-provides: [Object, Hash]
-
-...
-*/
-
-(function(){
-
-var hasOwnProperty = Object.prototype.hasOwnProperty;
-
-Object.extend({
-
- subset: function(object, keys){
- var results = {};
- for (var i = 0, l = keys.length; i < l; i++){
- var k = keys[i];
- if (k in object) results[k] = object[k];
- }
- return results;
- },
-
- map: function(object, fn, bind){
- var results = {};
- for (var key in object){
- if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
- }
- return results;
- },
-
- filter: function(object, fn, bind){
- var results = {};
- for (var key in object){
- var value = object[key];
- if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
- }
- return results;
- },
-
- every: function(object, fn, bind){
- for (var key in object){
- if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
- }
- return true;
- },
-
- some: function(object, fn, bind){
- for (var key in object){
- if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
- }
- return false;
- },
-
- keys: function(object){
- var keys = [];
- for (var key in object){
- if (hasOwnProperty.call(object, key)) keys.push(key);
- }
- return keys;
- },
-
- values: function(object){
- var values = [];
- for (var key in object){
- if (hasOwnProperty.call(object, key)) values.push(object[key]);
- }
- return values;
- },
-
- getLength: function(object){
- return Object.keys(object).length;
- },
-
- keyOf: function(object, value){
- for (var key in object){
- if (hasOwnProperty.call(object, key) && object[key] === value) return key;
- }
- return null;
- },
-
- contains: function(object, value){
- return Object.keyOf(object, value) != null;
- },
-
- toQueryString: function(object, base){
- var queryString = [];
-
- Object.each(object, function(value, key){
- if (base) key = base + '[' + key + ']';
- var result;
- switch (typeOf(value)){
- case 'object': result = Object.toQueryString(value, key); break;
- case 'array':
- var qs = {};
- value.each(function(val, i){
- qs[i] = val;
- });
- result = Object.toQueryString(qs, key);
- break;
- default: result = key + '=' + encodeURIComponent(value);
- }
- if (value != null) queryString.push(result);
- });
-
- return queryString.join('&');
- }
-
-});
-
-})();
-
-//<1.2compat>
-
-Hash.implement({
-
- has: Object.prototype.hasOwnProperty,
-
- keyOf: function(value){
- return Object.keyOf(this, value);
- },
-
- hasValue: function(value){
- return Object.contains(this, value);
- },
-
- extend: function(properties){
- Hash.each(properties || {}, function(value, key){
- Hash.set(this, key, value);
- }, this);
- return this;
- },
-
- combine: function(properties){
- Hash.each(properties || {}, function(value, key){
- Hash.include(this, key, value);
- }, this);
- return this;
- },
-
- erase: function(key){
- if (this.hasOwnProperty(key)) delete this[key];
- return this;
- },
-
- get: function(key){
- return (this.hasOwnProperty(key)) ? this[key] : null;
- },
-
- set: function(key, value){
- if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
- return this;
- },
-
- empty: function(){
- Hash.each(this, function(value, key){
- delete this[key];
- }, this);
- return this;
- },
-
- include: function(key, value){
- if (this[key] == null) this[key] = value;
- return this;
- },
-
- map: function(fn, bind){
- return new Hash(Object.map(this, fn, bind));
- },
-
- filter: function(fn, bind){
- return new Hash(Object.filter(this, fn, bind));
- },
-
- every: function(fn, bind){
- return Object.every(this, fn, bind);
- },
-
- some: function(fn, bind){
- return Object.some(this, fn, bind);
- },
-
- getKeys: function(){
- return Object.keys(this);
- },
-
- getValues: function(){
- return Object.values(this);
- },
-
- toQueryString: function(base){
- return Object.toQueryString(this, base);
- }
-
-});
-
-Hash.extend = Object.append;
-
-Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
-
-//</1.2compat>
-
-
-/*
----
-
-name: Browser
-
-description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
-
-license: MIT-style license.
-
-requires: [Array, Function, Number, String]
-
-provides: [Browser, Window, Document]
-
-...
-*/
-
-(function(){
-
-var document = this.document;
-var window = document.window = this;
-
-var ua = navigator.userAgent.toLowerCase(),
- platform = navigator.platform.toLowerCase(),
- UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
- mode = UA[1] == 'ie' && document.documentMode;
-
-var Browser = this.Browser = {
-
- extend: Function.prototype.extend,
-
- name: (UA[1] == 'version') ? UA[3] : UA[1],
-
- version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
-
- Platform: {
- name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
- },
-
- Features: {
- xpath: !!(document.evaluate),
- air: !!(window.runtime),
- query: !!(document.querySelector),
- json: !!(window.JSON)
- },
-
- Plugins: {}
-
-};
-
-Browser[Browser.name] = true;
-Browser[Browser.name + parseInt(Browser.version, 10)] = true;
-Browser.Platform[Browser.Platform.name] = true;
-
-// Request
-
-Browser.Request = (function(){
-
- var XMLHTTP = function(){
- return new XMLHttpRequest();
- };
-
- var MSXML2 = function(){
- return new ActiveXObject('MSXML2.XMLHTTP');
- };
-
- var MSXML = function(){
- return new ActiveXObject('Microsoft.XMLHTTP');
- };
-
- return Function.attempt(function(){
- XMLHTTP();
- return XMLHTTP;
- }, function(){
- MSXML2();
- return MSXML2;
- }, function(){
- MSXML();
- return MSXML;
- });
-
-})();
-
-Browser.Features.xhr = !!(Browser.Request);
-
-// Flash detection
-
-var version = (Function.attempt(function(){
- return navigator.plugins['Shockwave Flash'].description;
-}, function(){
- return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
-}) || '0 r0').match(/\d+/g);
-
-Browser.Plugins.Flash = {
- version: Number(version[0] || '0.' + version[1]) || 0,
- build: Number(version[2]) || 0
-};
-
-// String scripts
-
-Browser.exec = function(text){
- if (!text) return text;
- if (window.execScript){
- window.execScript(text);
- } else {
- var script = document.createElement('script');
- script.setAttribute('type', 'text/javascript');
- script.text = text;
- document.head.appendChild(script);
- document.head.removeChild(script);
- }
- return text;
-};
-
-String.implement('stripScripts', function(exec){
- var scripts = '';
- var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
- scripts += code + '\n';
- return '';
- });
- if (exec === true) Browser.exec(scripts);
- else if (typeOf(exec) == 'function') exec(scripts, text);
- return text;
-});
-
-// Window, Document
-
-Browser.extend({
- Document: this.Document,
- Window: this.Window,
- Element: this.Element,
- Event: this.Event
-});
-
-this.Window = this.$constructor = new Type('Window', function(){});
-
-this.$family = Function.from('window').hide();
-
-Window.mirror(function(name, method){
- window[name] = method;
-});
-
-this.Document = document.$constructor = new Type('Document', function(){});
-
-document.$family = Function.from('document').hide();
-
-Document.mirror(function(name, method){
- document[name] = method;
-});
-
-document.html = document.documentElement;
-if (!document.head) document.head = document.getElementsByTagName('head')[0];
-
-if (document.execCommand) try {
- document.execCommand("BackgroundImageCache", false, true);
-} catch (e){}
-
-/*<ltIE9>*/
-if (this.attachEvent && !this.addEventListener){
- var unloadEvent = function(){
- this.detachEvent('onunload', unloadEvent);
- document.head = document.html = document.window = null;
- };
- this.attachEvent('onunload', unloadEvent);
-}
-
-// IE fails on collections and <select>.options (refers to <select>)
-var arrayFrom = Array.from;
-try {
- arrayFrom(document.html.childNodes);
-} catch(e){
- Array.from = function(item){
- if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
- var i = item.length, array = new Array(i);
- while (i--) array[i] = item[i];
- return array;
- }
- return arrayFrom(item);
- };
-
- var prototype = Array.prototype,
- slice = prototype.slice;
- ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
- var method = prototype[name];
- Array[name] = function(item){
- return method.apply(Array.from(item), slice.call(arguments, 1));
- };
- });
-}
-/*</ltIE9>*/
-
-//<1.2compat>
-
-if (Browser.Platform.ios) Browser.Platform.ipod = true;
-
-Browser.Engine = {};
-
-var setEngine = function(name, version){
- Browser.Engine.name = name;
- Browser.Engine[name + version] = true;
- Browser.Engine.version = version;
-};
-
-if (Browser.ie){
- Browser.Engine.trident = true;
-
- switch (Browser.version){
- case 6: setEngine('trident', 4); break;
- case 7: setEngine('trident', 5); break;
- case 8: setEngine('trident', 6);
- }
-}
-
-if (Browser.firefox){
- Browser.Engine.gecko = true;
-
- if (Browser.version >= 3) setEngine('gecko', 19);
- else setEngine('gecko', 18);
-}
-
-if (Browser.safari || Browser.chrome){
- Browser.Engine.webkit = true;
-
- switch (Browser.version){
- case 2: setEngine('webkit', 419); break;
- case 3: setEngine('webkit', 420); break;
- case 4: setEngine('webkit', 525);
- }
-}
-
-if (Browser.opera){
- Browser.Engine.presto = true;
-
- if (Browser.version >= 9.6) setEngine('presto', 960);
- else if (Browser.version >= 9.5) setEngine('presto', 950);
- else setEngine('presto', 925);
-}
-
-if (Browser.name == 'unknown'){
- switch ((ua.match(/(?:webkit|khtml|gecko)/) || [])[0]){
- case 'webkit':
- case 'khtml':
- Browser.Engine.webkit = true;
- break;
- case 'gecko':
- Browser.Engine.gecko = true;
- }
-}
-
-this.$exec = Browser.exec;
-
-//</1.2compat>
-
-})();
-
-
-/*
----
-
-name: Event
-
-description: Contains the Event Type, to make the event object cross-browser.
-
-license: MIT-style license.
-
-requires: [Window, Document, Array, Function, String, Object]
-
-provides: Event
-
-...
-*/
-
-(function() {
-
-var _keys = {};
-
-var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){
- if (!win) win = window;
- event = event || win.event;
- if (event.$extended) return event;
- this.event = event;
- this.$extended = true;
- this.shift = event.shiftKey;
- this.control = event.ctrlKey;
- this.alt = event.altKey;
- this.meta = event.metaKey;
- var type = this.type = event.type;
- var target = event.target || event.srcElement;
- while (target && target.nodeType == 3) target = target.parentNode;
- this.target = document.id(target);
-
- if (type.indexOf('key') == 0){
- var code = this.code = (event.which || event.keyCode);
- this.key = _keys[code]/*<1.3compat>*/ || Object.keyOf(Event.Keys, code)/*</1.3compat>*/;
- if (type == 'keydown'){
- if (code > 111 && code < 124) this.key = 'f' + (code - 111);
- else if (code > 95 && code < 106) this.key = code - 96;
- }
- if (this.key == null) this.key = String.fromCharCode(code).toLowerCase();
- } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || type == 'DOMMouseScroll' || type.indexOf('mouse') == 0){
- var doc = win.document;
- doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
- this.page = {
- x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft,
- y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop
- };
- this.client = {
- x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX,
- y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY
- };
- if (type == 'DOMMouseScroll' || type == 'mousewheel')
- this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
-
- this.rightClick = (event.which == 3 || event.button == 2);
- if (type == 'mouseover' || type == 'mouseout'){
- var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' : 'to') + 'Element'];
- while (related && related.nodeType == 3) related = related.parentNode;
- this.relatedTarget = document.id(related);
- }
- } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){
- this.rotation = event.rotation;
- this.scale = event.scale;
- this.targetTouches = event.targetTouches;
- this.changedTouches = event.changedTouches;
- var touches = this.touches = event.touches;
- if (touches && touches[0]){
- var touch = touches[0];
- this.page = {x: touch.pageX, y: touch.pageY};
- this.client = {x: touch.clientX, y: touch.clientY};
- }
- }
-
- if (!this.client) this.client = {};
- if (!this.page) this.page = {};
-});
-
-DOMEvent.implement({
-
- stop: function(){
- return this.preventDefault().stopPropagation();
- },
-
- stopPropagation: function(){
- if (this.event.stopPropagation) this.event.stopPropagation();
- else this.event.cancelBubble = true;
- return this;
- },
-
- preventDefault: function(){
- if (this.event.preventDefault) this.event.preventDefault();
- else this.event.returnValue = false;
- return this;
- }
-
-});
-
-DOMEvent.defineKey = function(code, key){
- _keys[code] = key;
- return this;
-};
-
-DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true);
-
-DOMEvent.defineKeys({
- '38': 'up', '40': 'down', '37': 'left', '39': 'right',
- '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab',
- '46': 'delete', '13': 'enter'
-});
-
-})();
-
-/*<1.3compat>*/
-var Event = DOMEvent;
-Event.Keys = {};
-/*</1.3compat>*/
-
-/*<1.2compat>*/
-
-Event.Keys = new Hash(Event.Keys);
-
-/*</1.2compat>*/
-
-
-/*
----
-
-name: Class
-
-description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
-
-license: MIT-style license.
-
-requires: [Array, String, Function, Number]
-
-provides: Class
-
-...
-*/
-
-(function(){
-
-var Class = this.Class = new Type('Class', function(params){
- if (instanceOf(params, Function)) params = {initialize: params};
-
- var newClass = function(){
- reset(this);
- if (newClass.$prototyping) return this;
- this.$caller = null;
- var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
- this.$caller = this.caller = null;
- return value;
- }.extend(this).implement(params);
-
- newClass.$constructor = Class;
- newClass.prototype.$constructor = newClass;
- newClass.prototype.parent = parent;
-
- return newClass;
-});
-
-var parent = function(){
- if (!this.$caller) throw new Error('The method "parent" cannot be called.');
- var name = this.$caller.$name,
- parent = this.$caller.$owner.parent,
- previous = (parent) ? parent.prototype[name] : null;
- if (!previous) throw new Error('The method "' + name + '" has no parent.');
- return previous.apply(this, arguments);
-};
-
-var reset = function(object){
- for (var key in object){
- var value = object[key];
- switch (typeOf(value)){
- case 'object':
- var F = function(){};
- F.prototype = value;
- object[key] = reset(new F);
- break;
- case 'array': object[key] = value.clone(); break;
- }
- }
- return object;
-};
-
-var wrap = function(self, key, method){
- if (method.$origin) method = method.$origin;
- var wrapper = function(){
- if (method.$protected && this.$caller == null) throw new Error('The method "' + key + '" cannot be called.');
- var caller = this.caller, current = this.$caller;
- this.caller = current; this.$caller = wrapper;
- var result = method.apply(this, arguments);
- this.$caller = current; this.caller = caller;
- return result;
- }.extend({$owner: self, $origin: method, $name: key});
- return wrapper;
-};
-
-var implement = function(key, value, retain){
- if (Class.Mutators.hasOwnProperty(key)){
- value = Class.Mutators[key].call(this, value);
- if (value == null) return this;
- }
-
- if (typeOf(value) == 'function'){
- if (value.$hidden) return this;
- this.prototype[key] = (retain) ? value : wrap(this, key, value);
- } else {
- Object.merge(this.prototype, key, value);
- }
-
- return this;
-};
-
-var getInstance = function(klass){
- klass.$prototyping = true;
- var proto = new klass;
- delete klass.$prototyping;
- return proto;
-};
-
-Class.implement('implement', implement.overloadSetter());
-
-Class.Mutators = {
-
- Extends: function(parent){
- this.parent = parent;
- this.prototype = getInstance(parent);
- },
-
- Implements: function(items){
- Array.from(items).each(function(item){
- var instance = new item;
- for (var key in instance) implement.call(this, key, instance[key], true);
- }, this);
- }
-};
-
-})();
-
-
-/*
----
-
-name: Class.Extras
-
-description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
-
-license: MIT-style license.
-
-requires: Class
-
-provides: [Class.Extras, Chain, Events, Options]
-
-...
-*/
-
-(function(){
-
-this.Chain = new Class({
-
- $chain: [],
-
- chain: function(){
- this.$chain.append(Array.flatten(arguments));
- return this;
- },
-
- callChain: function(){
- return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
- },
-
- clearChain: function(){
- this.$chain.empty();
- return this;
- }
-
-});
-
-var removeOn = function(string){
- return string.replace(/^on([A-Z])/, function(full, first){
- return first.toLowerCase();
- });
-};
-
-this.Events = new Class({
-
- $events: {},
-
- addEvent: function(type, fn, internal){
- type = removeOn(type);
-
- /*<1.2compat>*/
- if (fn == $empty) return this;
- /*</1.2compat>*/
-
- this.$events[type] = (this.$events[type] || []).include(fn);
- if (internal) fn.internal = true;
- return this;
- },
-
- addEvents: function(events){
- for (var type in events) this.addEvent(type, events[type]);
- return this;
- },
-
- fireEvent: function(type, args, delay){
- type = removeOn(type);
- var events = this.$events[type];
- if (!events) return this;
- args = Array.from(args);
- events.each(function(fn){
- if (delay) fn.delay(delay, this, args);
- else fn.apply(this, args);
- }, this);
- return this;
- },
-
- removeEvent: function(type, fn){
- type = removeOn(type);
- var events = this.$events[type];
- if (events && !fn.internal){
- var index = events.indexOf(fn);
- if (index != -1) delete events[index];
- }
- return this;
- },
-
- removeEvents: function(events){
- var type;
- if (typeOf(events) == 'object'){
- for (type in events) this.removeEvent(type, events[type]);
- return this;
- }
- if (events) events = removeOn(events);
- for (type in this.$events){
- if (events && events != type) continue;
- var fns = this.$events[type];
- for (var i = fns.length; i--;) if (i in fns){
- this.removeEvent(type, fns[i]);
- }
- }
- return this;
- }
-
-});
-
-this.Options = new Class({
-
- setOptions: function(){
- var options = this.options = Object.merge.apply(null, [{}, this.options].append(arguments));
- if (this.addEvent) for (var option in options){
- if (typeOf(options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
- this.addEvent(option, options[option]);
- delete options[option];
- }
- return this;
- }
-
-});
-
-})();
-
-
-/*
----
-name: Slick.Parser
-description: Standalone CSS3 Selector parser
-provides: Slick.Parser
-...
-*/
-
-;(function(){
-
-var parsed,
- separatorIndex,
- combinatorIndex,
- reversed,
- cache = {},
- reverseCache = {},
- reUnescape = /\\/g;
-
-var parse = function(expression, isReversed){
- if (expression == null) return null;
- if (expression.Slick === true) return expression;
- expression = ('' + expression).replace(/^\s+|\s+$/g, '');
- reversed = !!isReversed;
- var currentCache = (reversed) ? reverseCache : cache;
- if (currentCache[expression]) return currentCache[expression];
- parsed = {
- Slick: true,
- expressions: [],
- raw: expression,
- reverse: function(){
- return parse(this.raw, true);
- }
- };
- separatorIndex = -1;
- while (expression != (expression = expression.replace(regexp, parser)));
- parsed.length = parsed.expressions.length;
- return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
-};
-
-var reverseCombinator = function(combinator){
- if (combinator === '!') return ' ';
- else if (combinator === ' ') return '!';
- else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
- else return '!' + combinator;
-};
-
-var reverse = function(expression){
- var expressions = expression.expressions;
- for (var i = 0; i < expressions.length; i++){
- var exp = expressions[i];
- var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
-
- for (var j = 0; j < exp.length; j++){
- var cexp = exp[j];
- if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
- cexp.combinator = cexp.reverseCombinator;
- delete cexp.reverseCombinator;
- }
-
- exp.reverse().push(last);
- }
- return expression;
-};
-
-var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
- return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
- return '\\' + match;
- });
-};
-
-var regexp = new RegExp(
-/*
-#!/usr/bin/env ruby
-puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
-__END__
- "(?x)^(?:\
- \\s* ( , ) \\s* # Separator \n\
- | \\s* ( <combinator>+ ) \\s* # Combinator \n\
- | ( \\s+ ) # CombinatorChildren \n\
- | ( <unicode>+ | \\* ) # Tag \n\
- | \\# ( <unicode>+ ) # ID \n\
- | \\. ( <unicode>+ ) # ClassName \n\
- | # Attribute \n\
- \\[ \
- \\s* (<unicode1>+) (?: \
- \\s* ([*^$!~|]?=) (?: \
- \\s* (?:\
- ([\"']?)(.*?)\\9 \
- )\
- ) \
- )? \\s* \
- \\](?!\\]) \n\
- | :+ ( <unicode>+ )(?:\
- \\( (?:\
- (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
- ) \\)\
- )?\
- )"
-*/
- "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
- .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
- .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
- .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
-);
-
-function parser(
- rawMatch,
-
- separator,
- combinator,
- combinatorChildren,
-
- tagName,
- id,
- className,
-
- attributeKey,
- attributeOperator,
- attributeQuote,
- attributeValue,
-
- pseudoMarker,
- pseudoClass,
- pseudoQuote,
- pseudoClassQuotedValue,
- pseudoClassValue
-){
- if (separator || separatorIndex === -1){
- parsed.expressions[++separatorIndex] = [];
- combinatorIndex = -1;
- if (separator) return '';
- }
-
- if (combinator || combinatorChildren || combinatorIndex === -1){
- combinator = combinator || ' ';
- var currentSeparator = parsed.expressions[separatorIndex];
- if (reversed && currentSeparator[combinatorIndex])
- currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
- currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
- }
-
- var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
-
- if (tagName){
- currentParsed.tag = tagName.replace(reUnescape, '');
-
- } else if (id){
- currentParsed.id = id.replace(reUnescape, '');
-
- } else if (className){
- className = className.replace(reUnescape, '');
-
- if (!currentParsed.classList) currentParsed.classList = [];
- if (!currentParsed.classes) currentParsed.classes = [];
- currentParsed.classList.push(className);
- currentParsed.classes.push({
- value: className,
- regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
- });
-
- } else if (pseudoClass){
- pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
- pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
-
- if (!currentParsed.pseudos) currentParsed.pseudos = [];
- currentParsed.pseudos.push({
- key: pseudoClass.replace(reUnescape, ''),
- value: pseudoClassValue,
- type: pseudoMarker.length == 1 ? 'class' : 'element'
- });
-
- } else if (attributeKey){
- attributeKey = attributeKey.replace(reUnescape, '');
- attributeValue = (attributeValue || '').replace(reUnescape, '');
-
- var test, regexp;
-
- switch (attributeOperator){
- case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
- case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
- case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
- case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
- case '=' : test = function(value){
- return attributeValue == value;
- }; break;
- case '*=' : test = function(value){
- return value && value.indexOf(attributeValue) > -1;
- }; break;
- case '!=' : test = function(value){
- return attributeValue != value;
- }; break;
- default : test = function(value){
- return !!value;
- };
- }
-
- if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
- return false;
- };
-
- if (!test) test = function(value){
- return value && regexp.test(value);
- };
-
- if (!currentParsed.attributes) currentParsed.attributes = [];
- currentParsed.attributes.push({
- key: attributeKey,
- operator: attributeOperator,
- value: attributeValue,
- test: test
- });
-
- }
-
- return '';
-};
-
-// Slick NS
-
-var Slick = (this.Slick || {});
-
-Slick.parse = function(expression){
- return parse(expression);
-};
-
-Slick.escapeRegExp = escapeRegExp;
-
-if (!this.Slick) this.Slick = Slick;
-
-}).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
-
-
-/*
----
-name: Slick.Finder
-description: The new, superfast css selector engine.
-provides: Slick.Finder
-requires: Slick.Parser
-...
-*/
-
-;(function(){
-
-var local = {},
- featuresCache = {},
- toString = Object.prototype.toString;
-
-// Feature / Bug detection
-
-local.isNativeCode = function(fn){
- return (/\{\s*\[native code\]\s*\}/).test('' + fn);
-};
-
-local.isXML = function(document){
- return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]') ||
- (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
-};
-
-local.setDocument = function(document){
-
- // convert elements / window arguments to document. if document cannot be extrapolated, the function returns.
- var nodeType = document.nodeType;
- if (nodeType == 9); // document
- else if (nodeType) document = document.ownerDocument; // node
- else if (document.navigator) document = document.document; // window
- else return;
-
- // check if it's the old document
-
- if (this.document === document) return;
- this.document = document;
-
- // check if we have done feature detection on this document before
-
- var root = document.documentElement,
- rootUid = this.getUIDXML(root),
- features = featuresCache[rootUid],
- feature;
-
- if (features){
- for (feature in features){
- this[feature] = features[feature];
- }
- return;
- }
-
- features = featuresCache[rootUid] = {};
-
- features.root = root;
- features.isXMLDocument = this.isXML(document);
-
- features.brokenStarGEBTN
- = features.starSelectsClosedQSA
- = features.idGetsName
- = features.brokenMixedCaseQSA
- = features.brokenGEBCN
- = features.brokenCheckedQSA
- = features.brokenEmptyAttributeQSA
- = features.isHTMLDocument
- = features.nativeMatchesSelector
- = false;
-
- var starSelectsClosed, starSelectsComments,
- brokenSecondClassNameGEBCN, cachedGetElementsByClassName,
- brokenFormAttributeGetter;
-
- var selected, id = 'slick_uniqueid';
- var testNode = document.createElement('div');
-
- var testRoot = document.body || document.getElementsByTagName('body')[0] || root;
- testRoot.appendChild(testNode);
-
- // on non-HTML documents innerHTML and getElementsById doesnt work properly
- try {
- testNode.innerHTML = '<a id="'+id+'"></a>';
- features.isHTMLDocument = !!document.getElementById(id);
- } catch(e){};
-
- if (features.isHTMLDocument){
-
- testNode.style.display = 'none';
-
- // IE returns comment nodes for getElementsByTagName('*') for some documents
- testNode.appendChild(document.createComment(''));
- starSelectsComments = (testNode.getElementsByTagName('*').length > 1);
-
- // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for some documents
- try {
- testNode.innerHTML = 'foo</foo>';
- selected = testNode.getElementsByTagName('*');
- starSelectsClosed = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
- } catch(e){};
-
- features.brokenStarGEBTN = starSelectsComments || starSelectsClosed;
-
- // IE returns elements with the name instead of just id for getElementsById for some documents
- try {
- testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>';
- features.idGetsName = document.getElementById(id) === testNode.firstChild;
- } catch(e){};
-
- if (testNode.getElementsByClassName){
-
- // Safari 3.2 getElementsByClassName caches results
- try {
- testNode.innerHTML = '<a class="f"></a><a class="b"></a>';
- testNode.getElementsByClassName('b').length;
- testNode.firstChild.className = 'b';
- cachedGetElementsByClassName = (testNode.getElementsByClassName('b').length != 2);
- } catch(e){};
-
- // Opera 9.6 getElementsByClassName doesnt detects the class if its not the first one
- try {
- testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>';
- brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').length != 2);
- } catch(e){};
-
- features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNameGEBCN;
- }
-
- if (testNode.querySelectorAll){
- // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for some documents
- try {
- testNode.innerHTML = 'foo</foo>';
- selected = testNode.querySelectorAll('*');
- features.starSelectsClosedQSA = (selected && !!selected.length && selected[0].nodeName.charAt(0) == '/');
- } catch(e){};
-
- // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode
- try {
- testNode.innerHTML = '<a class="MiX"></a>';
- features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length;
- } catch(e){};
-
- // Webkit and Opera dont return selected options on querySelectorAll
- try {
- testNode.innerHTML = '<select><option selected="selected">a</option></select>';
- features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').length == 0);
- } catch(e){};
-
- // IE returns incorrect results for attr[*^$]="" selectors on querySelectorAll
- try {
- testNode.innerHTML = '<a class=""></a>';
- features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*=""]').length != 0);
- } catch(e){};
-
- }
-
- // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a reference to the input
- try {
- testNode.innerHTML = '<form action="s"><input id="action"/></form>';
- brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') != 's');
- } catch(e){};
-
- // native matchesSelector function
-
- features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSelector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector;
- if (features.nativeMatchesSelector) try {
- // if matchesSelector trows errors on incorrect sintaxes we can use it
- features.nativeMatchesSelector.call(root, ':slick');
- features.nativeMatchesSelector = null;
- } catch(e){};
-
- }
-
- try {
- root.slick_expando = 1;
- delete root.slick_expando;
- features.getUID = this.getUIDHTML;
- } catch(e) {
- features.getUID = this.getUIDXML;
- }
-
- testRoot.removeChild(testNode);
- testNode = selected = testRoot = null;
-
- // getAttribute
-
- features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter) ? function(node, name){
- var method = this.attributeGetters[name];
- if (method) return method.call(node);
- var attributeNode = node.getAttributeNode(name);
- return (attributeNode) ? attributeNode.nodeValue : null;
- } : function(node, name){
- var method = this.attributeGetters[name];
- return (method) ? method.call(node) : node.getAttribute(name);
- };
-
- // hasAttribute
-
- features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? function(node, attribute) {
- return node.hasAttribute(attribute);
- } : function(node, attribute) {
- node = node.getAttributeNode(attribute);
- return !!(node && (node.specified || node.nodeValue));
- };
-
- // contains
- // FIXME: Add specs: local.contains should be different for xml and html documents?
- var nativeRootContains = root && this.isNativeCode(root.contains),
- nativeDocumentContains = document && this.isNativeCode(document.contains);
-
- features.contains = (nativeRootContains && nativeDocumentContains) ? function(context, node){
- return context.contains(node);
- } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){
- // IE8 does not have .contains on document.
- return context === node || ((context === document) ? document.documentElement : context).contains(node);
- } : (root && root.compareDocumentPosition) ? function(context, node){
- return context === node || !!(context.compareDocumentPosition(node) & 16);
- } : function(context, node){
- if (node) do {
- if (node === context) return true;
- } while ((node = node.parentNode));
- return false;
- };
-
- // document order sorting
- // credits to Sizzle (http://sizzlejs.com/)
-
- features.documentSorter = (root.compareDocumentPosition) ? function(a, b){
- if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0;
- return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
- } : ('sourceIndex' in root) ? function(a, b){
- if (!a.sourceIndex || !b.sourceIndex) return 0;
- return a.sourceIndex - b.sourceIndex;
- } : (document.createRange) ? function(a, b){
- if (!a.ownerDocument || !b.ownerDocument) return 0;
- var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
- aRange.setStart(a, 0);
- aRange.setEnd(a, 0);
- bRange.setStart(b, 0);
- bRange.setEnd(b, 0);
- return aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
- } : null ;
-
- root = null;
-
- for (feature in features){
- this[feature] = features[feature];
- }
-};
-
-// Main Method
-
-var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/,
- reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/,
- qsaFailExpCache = {};
-
-local.search = function(context, expression, append, first){
-
- var found = this.found = (first) ? null : (append || []);
-
- if (!context) return found;
- else if (context.navigator) context = context.document; // Convert the node from a window to a document
- else if (!context.nodeType) return found;
-
- // setup
-
- var parsed, i,
- uniques = this.uniques = {},
- hasOthers = !!(append && append.length),
- contextIsDocument = (context.nodeType == 9);
-
- if (this.document !== (contextIsDocument ? context : context.ownerDocument)) this.setDocument(context);
-
- // avoid duplicating items already in the append array
- if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = true;
-
- // expression checks
-
- if (typeof expression == 'string'){ // expression is a string
-
- /*<simple-selectors-override>*/
- var simpleSelector = expression.match(reSimpleSelector);
- simpleSelectors: if (simpleSelector) {
-
- var symbol = simpleSelector[1],
- name = simpleSelector[2],
- node, nodes;
-
- if (!symbol){
-
- if (name == '*' && this.brokenStarGEBTN) break simpleSelectors;
- nodes = context.getElementsByTagName(name);
- if (first) return nodes[0] || null;
- for (i = 0; node = nodes[i++];){
- if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
- }
-
- } else if (symbol == '#'){
-
- if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors;
- node = context.getElementById(name);
- if (!node) return found;
- if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) break simpleSelectors;
- if (first) return node || null;
- if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
-
- } else if (symbol == '.'){
-
- if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.brokenGEBCN) && context.querySelectorAll)) break simpleSelectors;
- if (context.getElementsByClassName && !this.brokenGEBCN){
- nodes = context.getElementsByClassName(name);
- if (first) return nodes[0] || null;
- for (i = 0; node = nodes[i++];){
- if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
- }
- } else {
- var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s|$)');
- nodes = context.getElementsByTagName('*');
- for (i = 0; node = nodes[i++];){
- className = node.className;
- if (!(className && matchClass.test(className))) continue;
- if (first) return node;
- if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
- }
- }
-
- }
-
- if (hasOthers) this.sort(found);
- return (first) ? null : found;
-
- }
- /*</simple-selectors-override>*/
-
- /*<query-selector-override>*/
- querySelector: if (context.querySelectorAll) {
-
- if (!this.isHTMLDocument
- || qsaFailExpCache[expression]
- //TODO: only skip when expression is actually mixed case
- || this.brokenMixedCaseQSA
- || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1)
- || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression))
- || (!contextIsDocument //Abort when !contextIsDocument and...
- // there are multiple expressions in the selector
- // since we currently only fix non-document rooted QSA for single expression selectors
- && expression.indexOf(',') > -1
- )
- || Slick.disableQSA
- ) break querySelector;
-
- var _expression = expression, _context = context;
- if (!contextIsDocument){
- // non-document rooted QSA
- // credits to Andrew Dupont
- var currentId = _context.getAttribute('id'), slickid = 'slickid__';
- _context.setAttribute('id', slickid);
- _expression = '#' + slickid + ' ' + _expression;
- context = _context.parentNode;
- }
-
- try {
- if (first) return context.querySelector(_expression) || null;
- else nodes = context.querySelectorAll(_expression);
- } catch(e) {
- qsaFailExpCache[expression] = 1;
- break querySelector;
- } finally {
- if (!contextIsDocument){
- if (currentId) _context.setAttribute('id', currentId);
- else _context.removeAttribute('id');
- context = _context;
- }
- }
-
- if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){
- if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) found.push(node);
- } else for (i = 0; node = nodes[i++];){
- if (!(hasOthers && uniques[this.getUID(node)])) found.push(node);
- }
-
- if (hasOthers) this.sort(found);
- return found;
-
- }
- /*</query-selector-override>*/
-
- parsed = this.Slick.parse(expression);
- if (!parsed.length) return found;
- } else if (expression == null){ // there is no expression
- return found;
- } else if (expression.Slick){ // expression is a parsed Slick object
- parsed = expression;
- } else if (this.contains(context.documentElement || context, expression)){ // expression is a node
- (found) ? found.push(expression) : found = expression;
- return found;
- } else { // other junk
- return found;
- }
-
- /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
-
- // cache elements for the nth selectors
-
- this.posNTH = {};
- this.posNTHLast = {};
- this.posNTHType = {};
- this.posNTHTypeLast = {};
-
- /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
-
- // if append is null and there is only a single selector with one expression use pushArray, else use pushUID
- this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions[0].length == 1))) ? this.pushArray : this.pushUID;
-
- if (found == null) found = [];
-
- // default engine
-
- var j, m, n;
- var combinator, tag, id, classList, classes, attributes, pseudos;
- var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;
-
- search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){
-
- combinator = 'combinator:' + currentBit.combinator;
- if (!this[combinator]) continue search;
-
- tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
- id = currentBit.id;
- classList = currentBit.classList;
- classes = currentBit.classes;
- attributes = currentBit.attributes;
- pseudos = currentBit.pseudos;
- lastBit = (j === (currentExpression.length - 1));
-
- this.bitUniques = {};
-
- if (lastBit){
- this.uniques = uniques;
- this.found = found;
- } else {
- this.uniques = {};
- this.found = [];
- }
-
- if (j === 0){
- this[combinator](context, tag, id, classes, attributes, pseudos, classList);
- if (first && lastBit && found.length) break search;
- } else {
- if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
- this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
- if (found.length) break search;
- } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
- }
-
- currentItems = this.found;
- }
-
- // should sort if there are nodes in append and if you pass multiple expressions.
- if (hasOthers || (parsed.expressions.length > 1)) this.sort(found);
-
- return (first) ? (found[0] || null) : found;
-};
-
-// Utils
-
-local.uidx = 1;
-local.uidk = 'slick-uniqueid';
-
-local.getUIDXML = function(node){
- var uid = node.getAttribute(this.uidk);
- if (!uid){
- uid = this.uidx++;
- node.setAttribute(this.uidk, uid);
- }
- return uid;
-};
-
-local.getUIDHTML = function(node){
- return node.uniqueNumber || (node.uniqueNumber = this.uidx++);
-};
-
-// sort based on the setDocument documentSorter method.
-
-local.sort = function(results){
- if (!this.documentSorter) return results;
- results.sort(this.documentSorter);
- return results;
-};
-
-/*<pseudo-selectors>*//*<nth-pseudo-selectors>*/
-
-local.cacheNTH = {};
-
-local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/;
-
-local.parseNTHArgument = function(argument){
- var parsed = argument.match(this.matchNTH);
- if (!parsed) return false;
- var special = parsed[2] || false;
- var a = parsed[1] || 1;
- if (a == '-') a = -1;
- var b = +parsed[3] || 0;
- parsed =
- (special == 'n') ? {a: a, b: b} :
- (special == 'odd') ? {a: 2, b: 1} :
- (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a};
-
- return (this.cacheNTH[argument] = parsed);
-};
-
-local.createNTHPseudo = function(child, sibling, positions, ofType){
- return function(node, argument){
- var uid = this.getUID(node);
- if (!this[positions][uid]){
- var parent = node.parentNode;
- if (!parent) return false;
- var el = parent[child], count = 1;
- if (ofType){
- var nodeName = node.nodeName;
- do {
- if (el.nodeName != nodeName) continue;
- this[positions][this.getUID(el)] = count++;
- } while ((el = el[sibling]));
- } else {
- do {
- if (el.nodeType != 1) continue;
- this[positions][this.getUID(el)] = count++;
- } while ((el = el[sibling]));
- }
- }
- argument = argument || 'n';
- var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument);
- if (!parsed) return false;
- var a = parsed.a, b = parsed.b, pos = this[positions][uid];
- if (a == 0) return b == pos;
- if (a > 0){
- if (pos < b) return false;
- } else {
- if (b < pos) return false;
- }
- return ((pos - b) % a) == 0;
- };
-};
-
-/*</nth-pseudo-selectors>*//*</pseudo-selectors>*/
-
-local.pushArray = function(node, tag, id, classes, attributes, pseudos){
- if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
-};
-
-local.pushUID = function(node, tag, id, classes, attributes, pseudos){
- var uid = this.getUID(node);
- if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
- this.uniques[uid] = true;
- this.found.push(node);
- }
-};
-
-local.matchNode = function(node, selector){
- if (this.isHTMLDocument && this.nativeMatchesSelector){
- try {
- return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\s*([^'"\]]+?)\s*\]/g, '[$1="$2"]'));
- } catch(matchError) {}
- }
-
- var parsed = this.Slick.parse(selector);
- if (!parsed) return true;
-
- // simple (single) selectors
- var expressions = parsed.expressions, simpleExpCounter = 0, i;
- for (i = 0; (currentExpression = expressions[i]); i++){
- if (currentExpression.length == 1){
- var exp = currentExpression[0];
- if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true;
- simpleExpCounter++;
- }
- }
-
- if (simpleExpCounter == parsed.length) return false;
-
- var nodes = this.search(this.document, parsed), item;
- for (i = 0; item = nodes[i++];){
- if (item === node) return true;
- }
- return false;
-};
-
-local.matchPseudo = function(node, name, argument){
- var pseudoName = 'pseudo:' + name;
- if (this[pseudoName]) return this[pseudoName](node, argument);
- var attribute = this.getAttribute(node, name);
- return (argument) ? argument == attribute : !!attribute;
-};
-
-local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
- if (tag){
- var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperCase();
- if (tag == '*'){
- if (nodeName < '@') return false; // Fix for comment nodes and closed nodes
- } else {
- if (nodeName != tag) return false;
- }
- }
-
- if (id && node.getAttribute('id') != id) return false;
-
- var i, part, cls;
- if (classes) for (i = classes.length; i--;){
- cls = this.getAttribute(node, 'class');
- if (!(cls && classes[i].regexp.test(cls))) return false;
- }
- if (attributes) for (i = attributes.length; i--;){
- part = attributes[i];
- if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
- }
- if (pseudos) for (i = pseudos.length; i--;){
- part = pseudos[i];
- if (!this.matchPseudo(node, part.key, part.value)) return false;
- }
- return true;
-};
-
-var combinators = {
-
- ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level
-
- var i, item, children;
-
- if (this.isHTMLDocument){
- getById: if (id){
- item = this.document.getElementById(id);
- if ((!item && node.all) || (this.idGetsName && item && item.getAttributeNode('id').nodeValue != id)){
- // all[id] returns all the elements with that name or id inside node
- // if theres just one it will return the element, else it will be a collection
- children = node.all[id];
- if (!children) return;
- if (!children[0]) children = [children];
- for (i = 0; item = children[i++];){
- var idNode = item.getAttributeNode('id');
- if (idNode && idNode.nodeValue == id){
- this.push(item, tag, null, classes, attributes, pseudos);
- break;
- }
- }
- return;
- }
- if (!item){
- // if the context is in the dom we return, else we will try GEBTN, breaking the getById label
- if (this.contains(this.root, node)) return;
- else break getById;
- } else if (this.document !== node && !this.contains(node, item)) return;
- this.push(item, tag, null, classes, attributes, pseudos);
- return;
- }
- getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBCN){
- children = node.getElementsByClassName(classList.join(' '));
- if (!(children && children.length)) break getByClass;
- for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
- return;
- }
- }
- getByTag: {
- children = node.getElementsByTagName(tag);
- if (!(children && children.length)) break getByTag;
- if (!this.brokenStarGEBTN) tag = null;
- for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
- }
- },
-
- '>': function(node, tag, id, classes, attributes, pseudos){ // direct children
- if ((node = node.firstChild)) do {
- if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
- } while ((node = node.nextSibling));
- },
-
- '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
- while ((node = node.nextSibling)) if (node.nodeType == 1){
- this.push(node, tag, id, classes, attributes, pseudos);
- break;
- }
- },
-
- '^': function(node, tag, id, classes, attributes, pseudos){ // first child
- node = node.firstChild;
- if (node){
- if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
- else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
- }
- },
-
- '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
- while ((node = node.nextSibling)){
- if (node.nodeType != 1) continue;
- var uid = this.getUID(node);
- if (this.bitUniques[uid]) break;
- this.bitUniques[uid] = true;
- this.push(node, tag, id, classes, attributes, pseudos);
- }
- },
-
- '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
- this['combinator:+'](node, tag, id, classes, attributes, pseudos);
- this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
- },
-
- '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
- this['combinator:~'](node, tag, id, classes, attributes, pseudos);
- this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
- },
-
- '!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
- while ((node = node.parentNode)) if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
- },
-
- '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
- node = node.parentNode;
- if (node !== this.document) this.push(node, tag, id, classes, attributes, pseudos);
- },
-
- '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
- while ((node = node.previousSibling)) if (node.nodeType == 1){
- this.push(node, tag, id, classes, attributes, pseudos);
- break;
- }
- },
-
- '!^': function(node, tag, id, classes, attributes, pseudos){ // last child
- node = node.lastChild;
- if (node){
- if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseudos);
- else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
- }
- },
-
- '!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
- while ((node = node.previousSibling)){
- if (node.nodeType != 1) continue;
- var uid = this.getUID(node);
- if (this.bitUniques[uid]) break;
- this.bitUniques[uid] = true;
- this.push(node, tag, id, classes, attributes, pseudos);
- }
- }
-
-};
-
-for (var c in combinators) local['combinator:' + c] = combinators[c];
-
-var pseudos = {
-
- /*<pseudo-selectors>*/
-
- 'empty': function(node){
- var child = node.firstChild;
- return !(child && child.nodeType == 1) && !(node.innerText || node.textContent || '').length;
- },
-
- 'not': function(node, expression){
- return !this.matchNode(node, expression);
- },
-
- 'contains': function(node, text){
- return (node.innerText || node.textContent || '').indexOf(text) > -1;
- },
-
- 'first-child': function(node){
- while ((node = node.previousSibling)) if (node.nodeType == 1) return false;
- return true;
- },
-
- 'last-child': function(node){
- while ((node = node.nextSibling)) if (node.nodeType == 1) return false;
- return true;
- },
-
- 'only-child': function(node){
- var prev = node;
- while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false;
- var next = node;
- while ((next = next.nextSibling)) if (next.nodeType == 1) return false;
- return true;
- },
-
- /*<nth-pseudo-selectors>*/
-
- 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'),
-
- 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHLast'),
-
- 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType', true),
-
- 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'posNTHTypeLast', true),
-
- 'index': function(node, index){
- return this['pseudo:nth-child'](node, '' + (index + 1));
- },
-
- 'even': function(node){
- return this['pseudo:nth-child'](node, '2n');
- },
-
- 'odd': function(node){
- return this['pseudo:nth-child'](node, '2n+1');
- },
-
- /*</nth-pseudo-selectors>*/
-
- /*<of-type-pseudo-selectors>*/
-
- 'first-of-type': function(node){
- var nodeName = node.nodeName;
- while ((node = node.previousSibling)) if (node.nodeName == nodeName) return false;
- return true;
- },
-
- 'last-of-type': function(node){
- var nodeName = node.nodeName;
- while ((node = node.nextSibling)) if (node.nodeName == nodeName) return false;
- return true;
- },
-
- 'only-of-type': function(node){
- var prev = node, nodeName = node.nodeName;
- while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return false;
- var next = node;
- while ((next = next.nextSibling)) if (next.nodeName == nodeName) return false;
- return true;
- },
-
- /*</of-type-pseudo-selectors>*/
-
- // custom pseudos
-
- 'enabled': function(node){
- return !node.disabled;
- },
-
- 'disabled': function(node){
- return node.disabled;
- },
-
- 'checked': function(node){
- return node.checked || node.selected;
- },
-
- 'focus': function(node){
- return this.isHTMLDocument && this.document.activeElement === node && (node.href || node.type || this.hasAttribute(node, 'tabindex'));
- },
-
- 'root': function(node){
- return (node === this.root);
- },
-
- 'selected': function(node){
- return node.selected;
- }
-
- /*</pseudo-selectors>*/
-};
-
-for (var p in pseudos) local['pseudo:' + p] = pseudos[p];
-
-// attributes methods
-
-var attributeGetters = local.attributeGetters = {
-
- 'for': function(){
- return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for');
- },
-
- 'href': function(){
- return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('href');
- },
-
- 'style': function(){
- return (this.style) ? this.style.cssText : this.getAttribute('style');
- },
-
- 'tabindex': function(){
- var attributeNode = this.getAttributeNode('tabindex');
- return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
- },
-
- 'type': function(){
- return this.getAttribute('type');
- },
-
- 'maxlength': function(){
- var attributeNode = this.getAttributeNode('maxLength');
- return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue : null;
- }
-
-};
-
-attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxlength;
-
-// Slick
-
-var Slick = local.Slick = (this.Slick || {});
-
-Slick.version = '1.1.7';
-
-// Slick finder
-
-Slick.search = function(context, expression, append){
- return local.search(context, expression, append);
-};
-
-Slick.find = function(context, expression){
- return local.search(context, expression, null, true);
-};
-
-// Slick containment checker
-
-Slick.contains = function(container, node){
- local.setDocument(container);
- return local.contains(container, node);
-};
-
-// Slick attribute getter
-
-Slick.getAttribute = function(node, name){
- local.setDocument(node);
- return local.getAttribute(node, name);
-};
-
-Slick.hasAttribute = function(node, name){
- local.setDocument(node);
- return local.hasAttribute(node, name);
-};
-
-// Slick matcher
-
-Slick.match = function(node, selector){
- if (!(node && selector)) return false;
- if (!selector || selector === node) return true;
- local.setDocument(node);
- return local.matchNode(node, selector);
-};
-
-// Slick attribute accessor
-
-Slick.defineAttributeGetter = function(name, fn){
- local.attributeGetters[name] = fn;
- return this;
-};
-
-Slick.lookupAttributeGetter = function(name){
- return local.attributeGetters[name];
-};
-
-// Slick pseudo accessor
-
-Slick.definePseudo = function(name, fn){
- local['pseudo:' + name] = function(node, argument){
- return fn.call(node, argument);
- };
- return this;
-};
-
-Slick.lookupPseudo = function(name){
- var pseudo = local['pseudo:' + name];
- if (pseudo) return function(argument){
- return pseudo.call(this, argument);
- };
- return null;
-};
-
-// Slick overrides accessor
-
-Slick.override = function(regexp, fn){
- local.override(regexp, fn);
- return this;
-};
-
-Slick.isXML = local.isXML;
-
-Slick.uidOf = function(node){
- return local.getUIDHTML(node);
-};
-
-if (!this.Slick) this.Slick = Slick;
-
-}).apply(/*<CommonJS>*/(typeof exports != 'undefined') ? exports : /*</CommonJS>*/this);
-
-
-/*
----
-
-name: Element
-
-description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
-
-license: MIT-style license.
-
-requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
-
-provides: [Element, Elements, $, $$, Iframe, Selectors]
-
-...
-*/
-
-var Element = function(tag, props){
- var konstructor = Element.Constructors[tag];
- if (konstructor) return konstructor(props);
- if (typeof tag != 'string') return document.id(tag).set(props);
-
- if (!props) props = {};
-
- if (!(/^[\w-]+$/).test(tag)){
- var parsed = Slick.parse(tag).expressions[0][0];
- tag = (parsed.tag == '*') ? 'div' : parsed.tag;
- if (parsed.id && props.id == null) props.id = parsed.id;
-
- var attributes = parsed.attributes;
- if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){
- attr = attributes[i];
- if (props[attr.key] != null) continue;
-
- if (attr.value != null && attr.operator == '=') props[attr.key] = attr.value;
- else if (!attr.value && !attr.operator) props[attr.key] = true;
- }
-
- if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' ');
- }
-
- return document.newElement(tag, props);
-};
-
-
-if (Browser.Element){
- Element.prototype = Browser.Element.prototype;
- // IE8 and IE9 require the wrapping.
- Element.prototype._fireEvent = (function(fireEvent){
- return function(type, event){
- return fireEvent.call(this, type, event);
- };
- })(Element.prototype.fireEvent);
-}
-
-new Type('Element', Element).mirror(function(name){
- if (Array.prototype[name]) return;
-
- var obj = {};
- obj[name] = function(){
- var results = [], args = arguments, elements = true;
- for (var i = 0, l = this.length; i < l; i++){
- var element = this[i], result = results[i] = element[name].apply(element, args);
- elements = (elements && typeOf(result) == 'element');
- }
- return (elements) ? new Elements(results) : results;
- };
-
- Elements.implement(obj);
-});
-
-if (!Browser.Element){
- Element.parent = Object;
-
- Element.Prototype = {
- '$constructor': Element,
- '$family': Function.from('element').hide()
- };
-
- Element.mirror(function(name, method){
- Element.Prototype[name] = method;
- });
-}
-
-Element.Constructors = {};
-
-//<1.2compat>
-
-Element.Constructors = new Hash;
-
-//</1.2compat>
-
-var IFrame = new Type('IFrame', function(){
- var params = Array.link(arguments, {
- properties: Type.isObject,
- iframe: function(obj){
- return (obj != null);
- }
- });
-
- var props = params.properties || {}, iframe;
- if (params.iframe) iframe = document.id(params.iframe);
- var onload = props.onload || function(){};
- delete props.onload;
- props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick();
- iframe = new Element(iframe || 'iframe', props);
-
- var onLoad = function(){
- onload.call(iframe.contentWindow);
- };
-
- if (window.frames[props.id]) onLoad();
- else iframe.addListener('load', onLoad);
- return iframe;
-});
-
-var Elements = this.Elements = function(nodes){
- if (nodes && nodes.length){
- var uniques = {}, node;
- for (var i = 0; node = nodes[i++];){
- var uid = Slick.uidOf(node);
- if (!uniques[uid]){
- uniques[uid] = true;
- this.push(node);
- }
- }
- }
-};
-
-Elements.prototype = {length: 0};
-Elements.parent = Array;
-
-new Type('Elements', Elements).implement({
-
- filter: function(filter, bind){
- if (!filter) return this;
- return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){
- return item.match(filter);
- } : filter, bind));
- }.protect(),
-
- push: function(){
- var length = this.length;
- for (var i = 0, l = arguments.length; i < l; i++){
- var item = document.id(arguments[i]);
- if (item) this[length++] = item;
- }
- return (this.length = length);
- }.protect(),
-
- unshift: function(){
- var items = [];
- for (var i = 0, l = arguments.length; i < l; i++){
- var item = document.id(arguments[i]);
- if (item) items.push(item);
- }
- return Array.prototype.unshift.apply(this, items);
- }.protect(),
-
- concat: function(){
- var newElements = new Elements(this);
- for (var i = 0, l = arguments.length; i < l; i++){
- var item = arguments[i];
- if (Type.isEnumerable(item)) newElements.append(item);
- else newElements.push(item);
- }
- return newElements;
- }.protect(),
-
- append: function(collection){
- for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]);
- return this;
- }.protect(),
-
- empty: function(){
- while (this.length) delete this[--this.length];
- return this;
- }.protect()
-
-});
-
-//<1.2compat>
-
-Elements.alias('extend', 'append');
-
-//</1.2compat>
-
-(function(){
-
-// FF, IE
-var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2};
-
-splice.call(object, 1, 1);
-if (object[1] == 1) Elements.implement('splice', function(){
- var length = this.length;
- var result = splice.apply(this, arguments);
- while (length >= this.length) delete this[length--];
- return result;
-}.protect());
-
-Array.forEachMethod(function(method, name){
- Elements.implement(name, method);
-});
-
-Array.mirror(Elements);
-
-/*<ltIE8>*/
-var createElementAcceptsHTML;
-try {
- createElementAcceptsHTML = (document.createElement('<input name=x>').name == 'x');
-} catch (e){}
-
-var escapeQuotes = function(html){
- return ('' + html).replace(/&/g, '&').replace(/"/g, '"');
-};
-/*</ltIE8>*/
-
-Document.implement({
-
- newElement: function(tag, props){
- if (props && props.checked != null) props.defaultChecked = props.checked;
- /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
- if (createElementAcceptsHTML && props){
- tag = '<' + tag;
- if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
- if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
- tag += '>';
- delete props.name;
- delete props.type;
- }
- /*</ltIE8>*/
- return this.id(this.createElement(tag)).set(props);
- }
-
-});
-
-})();
-
-(function(){
-
-Slick.uidOf(window);
-Slick.uidOf(document);
-
-Document.implement({
-
- newTextNode: function(text){
- return this.createTextNode(text);
- },
-
- getDocument: function(){
- return this;
- },
-
- getWindow: function(){
- return this.window;
- },
-
- id: (function(){
-
- var types = {
-
- string: function(id, nocash, doc){
- id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1'));
- return (id) ? types.element(id, nocash) : null;
- },
-
- element: function(el, nocash){
- Slick.uidOf(el);
- if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){
- var fireEvent = el.fireEvent;
- // wrapping needed in IE7, or else crash
- el._fireEvent = function(type, event){
- return fireEvent(type, event);
- };
- Object.append(el, Element.Prototype);
- }
- return el;
- },
-
- object: function(obj, nocash, doc){
- if (obj.toElement) return types.element(obj.toElement(doc), nocash);
- return null;
- }
-
- };
-
- types.textnode = types.whitespace = types.window = types.document = function(zero){
- return zero;
- };
-
- return function(el, nocash, doc){
- if (el && el.$family && el.uniqueNumber) return el;
- var type = typeOf(el);
- return (types[type]) ? types[type](el, nocash, doc || document) : null;
- };
-
- })()
-
-});
-
-if (window.$ == null) Window.implement('$', function(el, nc){
- return document.id(el, nc, this.document);
-});
-
-Window.implement({
-
- getDocument: function(){
- return this.document;
- },
-
- getWindow: function(){
- return this;
- }
-
-});
-
-[Document, Element].invoke('implement', {
-
- getElements: function(expression){
- return Slick.search(this, expression, new Elements);
- },
-
- getElement: function(expression){
- return document.id(Slick.find(this, expression));
- }
-
-});
-
-var contains = {contains: function(element){
- return Slick.contains(this, element);
-}};
-
-if (!document.contains) Document.implement(contains);
-if (!document.createElement('div').contains) Element.implement(contains);
-
-//<1.2compat>
-
-Element.implement('hasChild', function(element){
- return this !== element && this.contains(element);
-});
-
-(function(search, find, match){
-
- this.Selectors = {};
- var pseudos = this.Selectors.Pseudo = new Hash();
-
- var addSlickPseudos = function(){
- for (var name in pseudos) if (pseudos.hasOwnProperty(name)){
- Slick.definePseudo(name, pseudos[name]);
- delete pseudos[name];
- }
- };
-
- Slick.search = function(context, expression, append){
- addSlickPseudos();
- return search.call(this, context, expression, append);
- };
-
- Slick.find = function(context, expression){
- addSlickPseudos();
- return find.call(this, context, expression);
- };
-
- Slick.match = function(node, selector){
- addSlickPseudos();
- return match.call(this, node, selector);
- };
-
-})(Slick.search, Slick.find, Slick.match);
-
-//</1.2compat>
-
-// tree walking
-
-var injectCombinator = function(expression, combinator){
- if (!expression) return combinator;
-
- expression = Object.clone(Slick.parse(expression));
-
- var expressions = expression.expressions;
- for (var i = expressions.length; i--;)
- expressions[i][0].combinator = combinator;
-
- return expression;
-};
-
-Object.forEach({
- getNext: '~',
- getPrevious: '!~',
- getParent: '!'
-}, function(combinator, method){
- Element.implement(method, function(expression){
- return this.getElement(injectCombinator(expression, combinator));
- });
-});
-
-Object.forEach({
- getAllNext: '~',
- getAllPrevious: '!~',
- getSiblings: '~~',
- getChildren: '>',
- getParents: '!'
-}, function(combinator, method){
- Element.implement(method, function(expression){
- return this.getElements(injectCombinator(expression, combinator));
- });
-});
-
-Element.implement({
-
- getFirst: function(expression){
- return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
- },
-
- getLast: function(expression){
- return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
- },
-
- getWindow: function(){
- return this.ownerDocument.window;
- },
-
- getDocument: function(){
- return this.ownerDocument;
- },
-
- getElementById: function(id){
- return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')));
- },
-
- match: function(expression){
- return !expression || Slick.match(this, expression);
- }
-
-});
-
-//<1.2compat>
-
-if (window.$$ == null) Window.implement('$$', function(selector){
- var elements = new Elements;
- if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements);
- var args = Array.flatten(arguments);
- for (var i = 0, l = args.length; i < l; i++){
- var item = args[i];
- switch (typeOf(item)){
- case 'element': elements.push(item); break;
- case 'string': Slick.search(this.document, item, elements);
- }
- }
- return elements;
-});
-
-//</1.2compat>
-
-if (window.$$ == null) Window.implement('$$', function(selector){
- if (arguments.length == 1){
- if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements);
- else if (Type.isEnumerable(selector)) return new Elements(selector);
- }
- return new Elements(arguments);
-});
-
-// Inserters
-
-var inserters = {
-
- before: function(context, element){
- var parent = element.parentNode;
- if (parent) parent.insertBefore(context, element);
- },
-
- after: function(context, element){
- var parent = element.parentNode;
- if (parent) parent.insertBefore(context, element.nextSibling);
- },
-
- bottom: function(context, element){
- element.appendChild(context);
- },
-
- top: function(context, element){
- element.insertBefore(context, element.firstChild);
- }
-
-};
-
-inserters.inside = inserters.bottom;
-
-//<1.2compat>
-
-Object.each(inserters, function(inserter, where){
-
- where = where.capitalize();
-
- var methods = {};
-
- methods['inject' + where] = function(el){
- inserter(this, document.id(el, true));
- return this;
- };
-
- methods['grab' + where] = function(el){
- inserter(document.id(el, true), this);
- return this;
- };
-
- Element.implement(methods);
-
-});
-
-//</1.2compat>
-
-// getProperty / setProperty
-
-var propertyGetters = {}, propertySetters = {};
-
-// properties
-
-var properties = {};
-Array.forEach([
- 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
- 'frameBorder', 'rowSpan', 'tabIndex', 'useMap'
-], function(property){
- properties[property.toLowerCase()] = property;
-});
-
-properties.html = 'innerHTML';
-properties.text = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
-
-Object.forEach(properties, function(real, key){
- propertySetters[key] = function(node, value){
- node[real] = value;
- };
- propertyGetters[key] = function(node){
- return node[real];
- };
-});
-
-// Booleans
-
-var bools = [
- 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked',
- 'disabled', 'readOnly', 'multiple', 'selected', 'noresize',
- 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay',
- 'loop'
-];
-
-var booleans = {};
-Array.forEach(bools, function(bool){
- var lower = bool.toLowerCase();
- booleans[lower] = bool;
- propertySetters[lower] = function(node, value){
- node[bool] = !!value;
- };
- propertyGetters[lower] = function(node){
- return !!node[bool];
- };
-});
-
-// Special cases
-
-Object.append(propertySetters, {
-
- 'class': function(node, value){
- ('className' in node) ? node.className = (value || '') : node.setAttribute('class', value);
- },
-
- 'for': function(node, value){
- ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
- },
-
- 'style': function(node, value){
- (node.style) ? node.style.cssText = value : node.setAttribute('style', value);
- },
-
- 'value': function(node, value){
- node.value = (value != null) ? value : '';
- }
-
-});
-
-propertyGetters['class'] = function(node){
- return ('className' in node) ? node.className || null : node.getAttribute('class');
-};
-
-/* <webkit> */
-var el = document.createElement('button');
-// IE sets type as readonly and throws
-try { el.type = 'button'; } catch(e){}
-if (el.type != 'button') propertySetters.type = function(node, value){
- node.setAttribute('type', value);
-};
-el = null;
-/* </webkit> */
-
-/*<IE>*/
-var input = document.createElement('input');
-input.value = 't';
-input.type = 'submit';
-if (input.value != 't') propertySetters.type = function(node, type){
- var value = node.value;
- node.type = type;
- node.value = value;
-};
-input = null;
-/*</IE>*/
-
-/* getProperty, setProperty */
-
-/* <ltIE9> */
-var pollutesGetAttribute = (function(div){
- div.random = 'attribute';
- return (div.getAttribute('random') == 'attribute');
-})(document.createElement('div'));
-
-/* <ltIE9> */
-
-Element.implement({
-
- setProperty: function(name, value){
- var setter = propertySetters[name.toLowerCase()];
- if (setter){
- setter(this, value);
- } else {
- /* <ltIE9> */
- if (pollutesGetAttribute) var attributeWhiteList = this.retrieve('$attributeWhiteList', {});
- /* </ltIE9> */
-
- if (value == null){
- this.removeAttribute(name);
- /* <ltIE9> */
- if (pollutesGetAttribute) delete attributeWhiteList[name];
- /* </ltIE9> */
- } else {
- this.setAttribute(name, '' + value);
- /* <ltIE9> */
- if (pollutesGetAttribute) attributeWhiteList[name] = true;
- /* </ltIE9> */
- }
- }
- return this;
- },
-
- setProperties: function(attributes){
- for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
- return this;
- },
-
- getProperty: function(name){
- var getter = propertyGetters[name.toLowerCase()];
- if (getter) return getter(this);
- /* <ltIE9> */
- if (pollutesGetAttribute){
- var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve('$attributeWhiteList', {});
- if (!attr) return null;
- if (attr.expando && !attributeWhiteList[name]){
- var outer = this.outerHTML;
- // segment by the opening tag and find mention of attribute name
- if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(name) < 0) return null;
- attributeWhiteList[name] = true;
- }
- }
- /* </ltIE9> */
- var result = Slick.getAttribute(this, name);
- return (!result && !Slick.hasAttribute(this, name)) ? null : result;
- },
-
- getProperties: function(){
- var args = Array.from(arguments);
- return args.map(this.getProperty, this).associate(args);
- },
-
- removeProperty: function(name){
- return this.setProperty(name, null);
- },
-
- removeProperties: function(){
- Array.each(arguments, this.removeProperty, this);
- return this;
- },
-
- set: function(prop, value){
- var property = Element.Properties[prop];
- (property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
- }.overloadSetter(),
-
- get: function(prop){
- var property = Element.Properties[prop];
- return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
- }.overloadGetter(),
-
- erase: function(prop){
- var property = Element.Properties[prop];
- (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
- return this;
- },
-
- hasClass: function(className){
- return this.className.clean().contains(className, ' ');
- },
-
- addClass: function(className){
- if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
- return this;
- },
-
- removeClass: function(className){
- this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
- return this;
- },
-
- toggleClass: function(className, force){
- if (force == null) force = !this.hasClass(className);
- return (force) ? this.addClass(className) : this.removeClass(className);
- },
-
- adopt: function(){
- var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length;
- if (length > 1) parent = fragment = document.createDocumentFragment();
-
- for (var i = 0; i < length; i++){
- var element = document.id(elements[i], true);
- if (element) parent.appendChild(element);
- }
-
- if (fragment) this.appendChild(fragment);
-
- return this;
- },
-
- appendText: function(text, where){
- return this.grab(this.getDocument().newTextNode(text), where);
- },
-
- grab: function(el, where){
- inserters[where || 'bottom'](document.id(el, true), this);
- return this;
- },
-
- inject: function(el, where){
- inserters[where || 'bottom'](this, document.id(el, true));
- return this;
- },
-
- replaces: function(el){
- el = document.id(el, true);
- el.parentNode.replaceChild(this, el);
- return this;
- },
-
- wraps: function(el, where){
- el = document.id(el, true);
- return this.replaces(el).grab(el, where);
- },
-
- getSelected: function(){
- this.selectedIndex; // Safari 3.2.1
- return new Elements(Array.from(this.options).filter(function(option){
- return option.selected;
- }));
- },
-
- toQueryString: function(){
- var queryString = [];
- this.getElements('input, select, textarea').each(function(el){
- var type = el.type;
- if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return;
-
- var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){
- // IE
- return document.id(opt).get('value');
- }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value');
-
- Array.from(value).each(function(val){
- if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val));
- });
- });
- return queryString.join('&');
- }
-
-});
-
-var collected = {}, storage = {};
-
-var get = function(uid){
- return (storage[uid] || (storage[uid] = {}));
-};
-
-var clean = function(item){
- var uid = item.uniqueNumber;
- if (item.removeEvents) item.removeEvents();
- if (item.clearAttributes) item.clearAttributes();
- if (uid != null){
- delete collected[uid];
- delete storage[uid];
- }
- return item;
-};
-
-var formProps = {input: 'checked', option: 'selected', textarea: 'value'};
-
-Element.implement({
-
- destroy: function(){
- var children = clean(this).getElementsByTagName('*');
- Array.each(children, clean);
- Element.dispose(this);
- return null;
- },
-
- empty: function(){
- Array.from(this.childNodes).each(Element.dispose);
- return this;
- },
-
- dispose: function(){
- return (this.parentNode) ? this.parentNode.removeChild(this) : this;
- },
-
- clone: function(contents, keepid){
- contents = contents !== false;
- var clone = this.cloneNode(contents), ce = [clone], te = [this], i;
-
- if (contents){
- ce.append(Array.from(clone.getElementsByTagName('*')));
- te.append(Array.from(this.getElementsByTagName('*')));
- }
-
- for (i = ce.length; i--;){
- var node = ce[i], element = te[i];
- if (!keepid) node.removeAttribute('id');
- /*<ltIE9>*/
- if (node.clearAttributes){
- node.clearAttributes();
- node.mergeAttributes(element);
- node.removeAttribute('uniqueNumber');
- if (node.options){
- var no = node.options, eo = element.options;
- for (var j = no.length; j--;) no[j].selected = eo[j].selected;
- }
- }
- /*</ltIE9>*/
- var prop = formProps[element.tagName.toLowerCase()];
- if (prop && element[prop]) node[prop] = element[prop];
- }
-
- /*<ltIE9>*/
- if (Browser.ie){
- var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object');
- for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML;
- }
- /*</ltIE9>*/
- return document.id(clone);
- }
-
-});
-
-[Element, Window, Document].invoke('implement', {
-
- addListener: function(type, fn){
- if (type == 'unload'){
- var old = fn, self = this;
- fn = function(){
- self.removeListener('unload', fn);
- old();
- };
- } else {
- collected[Slick.uidOf(this)] = this;
- }
- if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]);
- else this.attachEvent('on' + type, fn);
- return this;
- },
-
- removeListener: function(type, fn){
- if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]);
- else this.detachEvent('on' + type, fn);
- return this;
- },
-
- retrieve: function(property, dflt){
- var storage = get(Slick.uidOf(this)), prop = storage[property];
- if (dflt != null && prop == null) prop = storage[property] = dflt;
- return prop != null ? prop : null;
- },
-
- store: function(property, value){
- var storage = get(Slick.uidOf(this));
- storage[property] = value;
- return this;
- },
-
- eliminate: function(property){
- var storage = get(Slick.uidOf(this));
- delete storage[property];
- return this;
- }
-
-});
-
-/*<ltIE9>*/
-if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){
- Object.each(collected, clean);
- if (window.CollectGarbage) CollectGarbage();
-});
-/*</ltIE9>*/
-
-Element.Properties = {};
-
-//<1.2compat>
-
-Element.Properties = new Hash;
-
-//</1.2compat>
-
-Element.Properties.style = {
-
- set: function(style){
- this.style.cssText = style;
- },
-
- get: function(){
- return this.style.cssText;
- },
-
- erase: function(){
- this.style.cssText = '';
- }
-
-};
-
-Element.Properties.tag = {
-
- get: function(){
- return this.tagName.toLowerCase();
- }
-
-};
-
-Element.Properties.html = {
-
- set: function(html){
- if (html == null) html = '';
- else if (typeOf(html) == 'array') html = html.join('');
- this.innerHTML = html;
- },
-
- erase: function(){
- this.innerHTML = '';
- }
-
-};
-
-/*<ltIE9>*/
-// technique by jdbarlett - http://jdbartlett.com/innershiv/
-var div = document.createElement('div');
-div.innerHTML = '<nav></nav>';
-var supportsHTML5Elements = (div.childNodes.length == 1);
-if (!supportsHTML5Elements){
- var tags = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' '),
- fragment = document.createDocumentFragment(), l = tags.length;
- while (l--) fragment.createElement(tags[l]);
-}
-div = null;
-/*</ltIE9>*/
-
-/*<IE>*/
-var supportsTableInnerHTML = Function.attempt(function(){
- var table = document.createElement('table');
- table.innerHTML = '<tr><td></td></tr>';
- return true;
-});
-
-/*<ltFF4>*/
-var tr = document.createElement('tr'), html = '<td></td>';
-tr.innerHTML = html;
-var supportsTRInnerHTML = (tr.innerHTML == html);
-tr = null;
-/*</ltFF4>*/
-
-if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){
-
- Element.Properties.html.set = (function(set){
-
- var translations = {
- table: [1, '<table>', '</table>'],
- select: [1, '<select>', '</select>'],
- tbody: [2, '<table><tbody>', '</tbody></table>'],
- tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
- };
-
- translations.thead = translations.tfoot = translations.tbody;
-
- return function(html){
- var wrap = translations[this.get('tag')];
- if (!wrap && !supportsHTML5Elements) wrap = [0, '', ''];
- if (!wrap) return set.call(this, html);
-
- var level = wrap[0], wrapper = document.createElement('div'), target = wrapper;
- if (!supportsHTML5Elements) fragment.appendChild(wrapper);
- wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join('');
- while (level--) target = target.firstChild;
- this.empty().adopt(target.childNodes);
- if (!supportsHTML5Elements) fragment.removeChild(wrapper);
- wrapper = null;
- };
-
- })(Element.Properties.html.set);
-}
-/*</IE>*/
-
-/*<ltIE9>*/
-var testForm = document.createElement('form');
-testForm.innerHTML = '<select><option>s</option></select>';
-
-if (testForm.firstChild.value != 's') Element.Properties.value = {
-
- set: function(value){
- var tag = this.get('tag');
- if (tag != 'select') return this.setProperty('value', value);
- var options = this.getElements('option');
- for (var i = 0; i < options.length; i++){
- var option = options[i],
- attr = option.getAttributeNode('value'),
- optionValue = (attr && attr.specified) ? option.value : option.get('text');
- if (optionValue == value) return option.selected = true;
- }
- },
-
- get: function(){
- var option = this, tag = option.get('tag');
-
- if (tag != 'select' && tag != 'option') return this.getProperty('value');
-
- if (tag == 'select' && !(option = option.getSelected()[0])) return '';
-
- var attr = option.getAttributeNode('value');
- return (attr && attr.specified) ? option.value : option.get('text');
- }
-
-};
-testForm = null;
-/*</ltIE9>*/
-
-/*<IE>*/
-if (document.createElement('div').getAttributeNode('id')) Element.Properties.id = {
- set: function(id){
- this.id = this.getAttributeNode('id').value = id;
- },
- get: function(){
- return this.id || null;
- },
- erase: function(){
- this.id = this.getAttributeNode('id').value = '';
- }
-};
-/*</IE>*/
-
-})();
-
-
-/*
----
-
-name: Element.Style
-
-description: Contains methods for interacting with the styles of Elements in a fashionable way.
-
-license: MIT-style license.
-
-requires: Element
-
-provides: Element.Style
-
-...
-*/
-
-(function(){
-
-var html = document.html;
-
-//<ltIE9>
-// Check for oldIE, which does not remove styles when they're set to null
-var el = document.createElement('div');
-el.style.color = 'red';
-el.style.color = null;
-var doesNotRemoveStyles = el.style.color == 'red';
-el = null;
-//</ltIE9>
-
-Element.Properties.styles = {set: function(styles){
- this.setStyles(styles);
-}};
-
-var hasOpacity = (html.style.opacity != null),
- hasFilter = (html.style.filter != null),
- reAlpha = /alpha\(opacity=([\d.]+)\)/i;
-
-var setVisibility = function(element, opacity){
- element.store('$opacity', opacity);
- element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidden';
-};
-
-var setOpacity = (hasOpacity ? function(element, opacity){
- element.style.opacity = opacity;
-} : (hasFilter ? function(element, opacity){
- var style = element.style;
- if (!element.currentStyle || !element.currentStyle.hasLayout) style.zoom = 1;
- if (opacity == null || opacity == 1) opacity = '';
- else opacity = 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')';
- var filter = style.filter || element.getComputedStyle('filter') || '';
- style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filter + opacity;
- if (!style.filter) style.removeAttribute('filter');
-} : setVisibility));
-
-var getOpacity = (hasOpacity ? function(element){
- var opacity = element.style.opacity || element.getComputedStyle('opacity');
- return (opacity == '') ? 1 : opacity.toFloat();
-} : (hasFilter ? function(element){
- var filter = (element.style.filter || element.getComputedStyle('filter')),
- opacity;
- if (filter) opacity = filter.match(reAlpha);
- return (opacity == null || filter == null) ? 1 : (opacity[1] / 100);
-} : function(element){
- var opacity = element.retrieve('$opacity');
- if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1);
- return opacity;
-}));
-
-var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat';
-
-Element.implement({
-
- getComputedStyle: function(property){
- if (this.currentStyle) return this.currentStyle[property.camelCase()];
- var defaultView = Element.getDocument(this).defaultView,
- computed = defaultView ? defaultView.getComputedStyle(this, null) : null;
- return (computed) ? computed.getPropertyValue((property == floatName) ? 'float' : property.hyphenate()) : null;
- },
-
- setStyle: function(property, value){
- if (property == 'opacity'){
- if (value != null) value = parseFloat(value);
- setOpacity(this, value);
- return this;
- }
- property = (property == 'float' ? floatName : property).camelCase();
- if (typeOf(value) != 'string'){
- var map = (Element.Styles[property] || '@').split(' ');
- value = Array.from(value).map(function(val, i){
- if (!map[i]) return '';
- return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
- }).join(' ');
- } else if (value == String(Number(value))){
- value = Math.round(value);
- }
- this.style[property] = value;
- //<ltIE9>
- if ((value == '' || value == null) && doesNotRemoveStyles && this.style.removeAttribute){
- this.style.removeAttribute(property);
- }
- //</ltIE9>
- return this;
- },
-
- getStyle: function(property){
- if (property == 'opacity') return getOpacity(this);
- property = (property == 'float' ? floatName : property).camelCase();
- var result = this.style[property];
- if (!result || property == 'zIndex'){
- result = [];
- for (var style in Element.ShortStyles){
- if (property != style) continue;
- for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
- return result.join(' ');
- }
- result = this.getComputedStyle(property);
- }
- if (result){
- result = String(result);
- var color = result.match(/rgba?\([\d\s,]+\)/);
- if (color) result = result.replace(color[0], color[0].rgbToHex());
- }
- if (Browser.opera || Browser.ie){
- if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){
- var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
- values.each(function(value){
- size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
- }, this);
- return this['offset' + property.capitalize()] - size + 'px';
- }
- if (Browser.ie && (/^border(.+)Width|margin|padding/).test(property) && isNaN(parseFloat(result))){
- return '0px';
- }
- }
- return result;
- },
-
- setStyles: function(styles){
- for (var style in styles) this.setStyle(style, styles[style]);
- return this;
- },
-
- getStyles: function(){
- var result = {};
- Array.flatten(arguments).each(function(key){
- result[key] = this.getStyle(key);
- }, this);
- return result;
- }
-
-});
-
-Element.Styles = {
- left: '@px', top: '@px', bottom: '@px', right: '@px',
- width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
- backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
- fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
- margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
- borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
- zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
-};
-
-//<1.3compat>
-
-Element.implement({
-
- setOpacity: function(value){
- setOpacity(this, value);
- return this;
- },
-
- getOpacity: function(){
- return getOpacity(this);
- }
-
-});
-
-Element.Properties.opacity = {
-
- set: function(opacity){
- setOpacity(this, opacity);
- setVisibility(this, opacity);
- },
-
- get: function(){
- return getOpacity(this);
- }
-
-};
-
-//</1.3compat>
-
-//<1.2compat>
-
-Element.Styles = new Hash(Element.Styles);
-
-//</1.2compat>
-
-Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
-
-['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
- var Short = Element.ShortStyles;
- var All = Element.Styles;
- ['margin', 'padding'].each(function(style){
- var sd = style + direction;
- Short[style][sd] = All[sd] = '@px';
- });
- var bd = 'border' + direction;
- Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
- var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
- Short[bd] = {};
- Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
- Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
- Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
-});
-
-})();
-
-
-/*
----
-
-name: Element.Event
-
-description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events, if necessary.
-
-license: MIT-style license.
-
-requires: [Element, Event]
-
-provides: Element.Event
-
-...
-*/
-
-(function(){
-
-Element.Properties.events = {set: function(events){
- this.addEvents(events);
-}};
-
-[Element, Window, Document].invoke('implement', {
-
- addEvent: function(type, fn){
- var events = this.retrieve('events', {});
- if (!events[type]) events[type] = {keys: [], values: []};
- if (events[type].keys.contains(fn)) return this;
- events[type].keys.push(fn);
- var realType = type,
- custom = Element.Events[type],
- condition = fn,
- self = this;
- if (custom){
- if (custom.onAdd) custom.onAdd.call(this, fn, type);
- if (custom.condition){
- condition = function(event){
- if (custom.condition.call(this, event, type)) return fn.call(this, event);
- return true;
- };
- }
- if (custom.base) realType = Function.from(custom.base).call(this, type);
- }
- var defn = function(){
- return fn.call(self);
- };
- var nativeEvent = Element.NativeEvents[realType];
- if (nativeEvent){
- if (nativeEvent == 2){
- defn = function(event){
- event = new DOMEvent(event, self.getWindow());
- if (condition.call(self, event) === false) event.stop();
- };
- }
- this.addListener(realType, defn, arguments[2]);
- }
- events[type].values.push(defn);
- return this;
- },
-
- removeEvent: function(type, fn){
- var events = this.retrieve('events');
- if (!events || !events[type]) return this;
- var list = events[type];
- var index = list.keys.indexOf(fn);
- if (index == -1) return this;
- var value = list.values[index];
- delete list.keys[index];
- delete list.values[index];
- var custom = Element.Events[type];
- if (custom){
- if (custom.onRemove) custom.onRemove.call(this, fn, type);
- if (custom.base) type = Function.from(custom.base).call(this, type);
- }
- return (Element.NativeEvents[type]) ? this.removeListener(type, value, arguments[2]) : this;
- },
-
- addEvents: function(events){
- for (var event in events) this.addEvent(event, events[event]);
- return this;
- },
-
- removeEvents: function(events){
- var type;
- if (typeOf(events) == 'object'){
- for (type in events) this.removeEvent(type, events[type]);
- return this;
- }
- var attached = this.retrieve('events');
- if (!attached) return this;
- if (!events){
- for (type in attached) this.removeEvents(type);
- this.eliminate('events');
- } else if (attached[events]){
- attached[events].keys.each(function(fn){
- this.removeEvent(events, fn);
- }, this);
- delete attached[events];
- }
- return this;
- },
-
- fireEvent: function(type, args, delay){
- var events = this.retrieve('events');
- if (!events || !events[type]) return this;
- args = Array.from(args);
-
- events[type].keys.each(function(fn){
- if (delay) fn.delay(delay, this, args);
- else fn.apply(this, args);
- }, this);
- return this;
- },
-
- cloneEvents: function(from, type){
- from = document.id(from);
- var events = from.retrieve('events');
- if (!events) return this;
- if (!type){
- for (var eventType in events) this.cloneEvents(from, eventType);
- } else if (events[type]){
- events[type].keys.each(function(fn){
- this.addEvent(type, fn);
- }, this);
- }
- return this;
- }
-
-});
-
-Element.NativeEvents = {
- click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
- mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
- mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
- keydown: 2, keypress: 2, keyup: 2, //keyboard
- orientationchange: 2, // mobile
- touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch
- gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture
- focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input: 2, //form elements
- load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
- error: 1, abort: 1, scroll: 1 //misc
-};
-
-Element.Events = {mousewheel: {
- base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel'
-}};
-
-if ('onmouseenter' in document.documentElement){
- Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2;
-} else {
- var check = function(event){
- var related = event.relatedTarget;
- if (related == null) return true;
- if (!related) return false;
- return (related != this && related.prefix != 'xul' && typeOf(this) != 'document' && !this.contains(related));
- };
-
- Element.Events.mouseenter = {
- base: 'mouseover',
- condition: check
- };
-
- Element.Events.mouseleave = {
- base: 'mouseout',
- condition: check
- };
-}
-
-/*<ltIE9>*/
-if (!window.addEventListener){
- Element.NativeEvents.propertychange = 2;
- Element.Events.change = {
- base: function(){
- var type = this.type;
- return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbox')) ? 'propertychange' : 'change'
- },
- condition: function(event){
- return this.type != 'radio' || (event.event.propertyName == 'checked' && this.checked);
- }
- }
-}
-/*</ltIE9>*/
-
-//<1.2compat>
-
-Element.Events = new Hash(Element.Events);
-
-//</1.2compat>
-
-})();
-
-
-/*
----
-
-name: Element.Delegation
-
-description: Extends the Element native object to include the delegate method for more efficient event management.
-
-license: MIT-style license.
-
-requires: [Element.Event]
-
-provides: [Element.Delegation]
-
-...
-*/
-
-(function(){
-
-var eventListenerSupport = !!window.addEventListener;
-
-Element.NativeEvents.focusin = Element.NativeEvents.focusout = 2;
-
-var bubbleUp = function(self, match, fn, event, target){
- while (target && target != self){
- if (match(target, event)) return fn.call(target, event, target);
- target = document.id(target.parentNode);
- }
-};
-
-var map = {
- mouseenter: {
- base: 'mouseover'
- },
- mouseleave: {
- base: 'mouseout'
- },
- focus: {
- base: 'focus' + (eventListenerSupport ? '' : 'in'),
- capture: true
- },
- blur: {
- base: eventListenerSupport ? 'blur' : 'focusout',
- capture: true
- }
-};
-
-/*<ltIE9>*/
-var _key = '$delegation:';
-var formObserver = function(type){
-
- return {
-
- base: 'focusin',
-
- remove: function(self, uid){
- var list = self.retrieve(_key + type + 'listeners', {})[uid];
- if (list && list.forms) for (var i = list.forms.length; i--;){
- list.forms[i].removeEvent(type, list.fns[i]);
- }
- },
-
- listen: function(self, match, fn, event, target, uid){
- var form = (target.get('tag') == 'form') ? target : event.target.getParent('form');
- if (!form) return;
-
- var listeners = self.retrieve(_key + type + 'listeners', {}),
- listener = listeners[uid] || {forms: [], fns: []},
- forms = listener.forms, fns = listener.fns;
-
- if (forms.indexOf(form) != -1) return;
- forms.push(form);
-
- var _fn = function(event){
- bubbleUp(self, match, fn, event, target);
- };
- form.addEvent(type, _fn);
- fns.push(_fn);
-
- listeners[uid] = listener;
- self.store(_key + type + 'listeners', listeners);
- }
- };
-};
-
-var inputObserver = function(type){
- return {
- base: 'focusin',
- listen: function(self, match, fn, event, target){
- var events = {blur: function(){
- this.removeEvents(events);
- }};
- events[type] = function(event){
- bubbleUp(self, match, fn, event, target);
- };
- event.target.addEvents(events);
- }
- };
-};
-
-if (!eventListenerSupport) Object.append(map, {
- submit: formObserver('submit'),
- reset: formObserver('reset'),
- change: inputObserver('change'),
- select: inputObserver('select')
-});
-/*</ltIE9>*/
-
-var proto = Element.prototype,
- addEvent = proto.addEvent,
- removeEvent = proto.removeEvent;
-
-var relay = function(old, method){
- return function(type, fn, useCapture){
- if (type.indexOf(':relay') == -1) return old.call(this, type, fn, useCapture);
- var parsed = Slick.parse(type).expressions[0][0];
- if (parsed.pseudos[0].key != 'relay') return old.call(this, type, fn, useCapture);
- var newType = parsed.tag;
- parsed.pseudos.slice(1).each(function(pseudo){
- newType += ':' + pseudo.key + (pseudo.value ? '(' + pseudo.value + ')' : '');
- });
- old.call(this, type, fn);
- return method.call(this, newType, parsed.pseudos[0].value, fn);
- };
-};
-
-var delegation = {
-
- addEvent: function(type, match, fn){
- var storage = this.retrieve('$delegates', {}), stored = storage[type];
- if (stored) for (var _uid in stored){
- if (stored[_uid].fn == fn && stored[_uid].match == match) return this;
- }
-
- var _type = type, _match = match, _fn = fn, _map = map[type] || {};
- type = _map.base || _type;
-
- match = function(target){
- return Slick.match(target, _match);
- };
-
- var elementEvent = Element.Events[_type];
- if (elementEvent && elementEvent.condition){
- var __match = match, condition = elementEvent.condition;
- match = function(target, event){
- return __match(target, event) && condition.call(target, event, type);
- };
- }
-
- var self = this, uid = String.uniqueID();
- var delegator = _map.listen ? function(event, target){
- if (!target && event && event.target) target = event.target;
- if (target) _map.listen(self, match, fn, event, target, uid);
- } : function(event, target){
- if (!target && event && event.target) target = event.target;
- if (target) bubbleUp(self, match, fn, event, target);
- };
-
- if (!stored) stored = {};
- stored[uid] = {
- match: _match,
- fn: _fn,
- delegator: delegator
- };
- storage[_type] = stored;
- return addEvent.call(this, type, delegator, _map.capture);
- },
-
- removeEvent: function(type, match, fn, _uid){
- var storage = this.retrieve('$delegates', {}), stored = storage[type];
- if (!stored) return this;
-
- if (_uid){
- var _type = type, delegator = stored[_uid].delegator, _map = map[type] || {};
- type = _map.base || _type;
- if (_map.remove) _map.remove(this, _uid);
- delete stored[_uid];
- storage[_type] = stored;
- return removeEvent.call(this, type, delegator);
- }
-
- var __uid, s;
- if (fn) for (__uid in stored){
- s = stored[__uid];
- if (s.match == match && s.fn == fn) return delegation.removeEvent.call(this, type, match, fn, __uid);
- } else for (__uid in stored){
- s = stored[__uid];
- if (s.match == match) delegation.removeEvent.call(this, type, match, s.fn, __uid);
- }
- return this;
- }
-
-};
-
-[Element, Window, Document].invoke('implement', {
- addEvent: relay(addEvent, delegation.addEvent),
- removeEvent: relay(removeEvent, delegation.removeEvent)
-});
-
-})();
-
-
-/*
----
-
-name: Element.Dimensions
-
-description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
-
-license: MIT-style license.
-
-credits:
- - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
- - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
-
-requires: [Element, Element.Style]
-
-provides: [Element.Dimensions]
-
-...
-*/
-
-(function(){
-
-var element = document.createElement('div'),
- child = document.createElement('div');
-element.style.height = '0';
-element.appendChild(child);
-var brokenOffsetParent = (child.offsetParent === element);
-element = child = null;
-
-var isOffset = function(el){
- return styleString(el, 'position') != 'static' || isBody(el);
-};
-
-var isOffsetStatic = function(el){
- return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName);
-};
-
-Element.implement({
-
- scrollTo: function(x, y){
- if (isBody(this)){
- this.getWindow().scrollTo(x, y);
- } else {
- this.scrollLeft = x;
- this.scrollTop = y;
- }
- return this;
- },
-
- getSize: function(){
- if (isBody(this)) return this.getWindow().getSize();
- return {x: this.offsetWidth, y: this.offsetHeight};
- },
-
- getScrollSize: function(){
- if (isBody(this)) return this.getWindow().getScrollSize();
- return {x: this.scrollWidth, y: this.scrollHeight};
- },
-
- getScroll: function(){
- if (isBody(this)) return this.getWindow().getScroll();
- return {x: this.scrollLeft, y: this.scrollTop};
- },
-
- getScrolls: function(){
- var element = this.parentNode, position = {x: 0, y: 0};
- while (element && !isBody(element)){
- position.x += element.scrollLeft;
- position.y += element.scrollTop;
- element = element.parentNode;
- }
- return position;
- },
-
- getOffsetParent: brokenOffsetParent ? function(){
- var element = this;
- if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
-
- var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffsetStatic : isOffset;
- while ((element = element.parentNode)){
- if (isOffsetCheck(element)) return element;
- }
- return null;
- } : function(){
- var element = this;
- if (isBody(element) || styleString(element, 'position') == 'fixed') return null;
-
- try {
- return element.offsetParent;
- } catch(e) {}
- return null;
- },
-
- getOffsets: function(){
- if (this.getBoundingClientRect && !Browser.Platform.ios){
- var bound = this.getBoundingClientRect(),
- html = document.id(this.getDocument().documentElement),
- htmlScroll = html.getScroll(),
- elemScrolls = this.getScrolls(),
- isFixed = (styleString(this, 'position') == 'fixed');
-
- return {
- x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
- y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
- };
- }
-
- var element = this, position = {x: 0, y: 0};
- if (isBody(this)) return position;
-
- while (element && !isBody(element)){
- position.x += element.offsetLeft;
- position.y += element.offsetTop;
-
- if (Browser.firefox){
- if (!borderBox(element)){
- position.x += leftBorder(element);
- position.y += topBorder(element);
- }
- var parent = element.parentNode;
- if (parent && styleString(parent, 'overflow') != 'visible'){
- position.x += leftBorder(parent);
- position.y += topBorder(parent);
- }
- } else if (element != this && Browser.safari){
- position.x += leftBorder(element);
- position.y += topBorder(element);
- }
-
- element = element.offsetParent;
- }
- if (Browser.firefox && !borderBox(this)){
- position.x -= leftBorder(this);
- position.y -= topBorder(this);
- }
- return position;
- },
-
- getPosition: function(relative){
- var offset = this.getOffsets(),
- scroll = this.getScrolls();
- var position = {
- x: offset.x - scroll.x,
- y: offset.y - scroll.y
- };
-
- if (relative && (relative = document.id(relative))){
- var relativePosition = relative.getPosition();
- return {x: position.x - relativePosition.x - leftBorder(relative), y: position.y - relativePosition.y - topBorder(relative)};
- }
- return position;
- },
-
- getCoordinates: function(element){
- if (isBody(this)) return this.getWindow().getCoordinates();
- var position = this.getPosition(element),
- size = this.getSize();
- var obj = {
- left: position.x,
- top: position.y,
- width: size.x,
- height: size.y
- };
- obj.right = obj.left + obj.width;
- obj.bottom = obj.top + obj.height;
- return obj;
- },
-
- computePosition: function(obj){
- return {
- left: obj.x - styleNumber(this, 'margin-left'),
- top: obj.y - styleNumber(this, 'margin-top')
- };
- },
-
- setPosition: function(obj){
- return this.setStyles(this.computePosition(obj));
- }
-
-});
-
-
-[Document, Window].invoke('implement', {
-
- getSize: function(){
- var doc = getCompatElement(this);
- return {x: doc.clientWidth, y: doc.clientHeight};
- },
-
- getScroll: function(){
- var win = this.getWindow(), doc = getCompatElement(this);
- return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
- },
-
- getScrollSize: function(){
- var doc = getCompatElement(this),
- min = this.getSize(),
- body = this.getDocument().body;
-
- return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(doc.scrollHeight, body.scrollHeight, min.y)};
- },
-
- getPosition: function(){
- return {x: 0, y: 0};
- },
-
- getCoordinates: function(){
- var size = this.getSize();
- return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
- }
-
-});
-
-// private methods
-
-var styleString = Element.getComputedStyle;
-
-function styleNumber(element, style){
- return styleString(element, style).toInt() || 0;
-}
-
-function borderBox(element){
- return styleString(element, '-moz-box-sizing') == 'border-box';
-}
-
-function topBorder(element){
- return styleNumber(element, 'border-top-width');
-}
-
-function leftBorder(element){
- return styleNumber(element, 'border-left-width');
-}
-
-function isBody(element){
- return (/^(?:body|html)$/i).test(element.tagName);
-}
-
-function getCompatElement(element){
- var doc = element.getDocument();
- return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
-}
-
-})();
-
-//aliases
-Element.alias({position: 'setPosition'}); //compatability
-
-[Window, Document, Element].invoke('implement', {
-
- getHeight: function(){
- return this.getSize().y;
- },
-
- getWidth: function(){
- return this.getSize().x;
- },
-
- getScrollTop: function(){
- return this.getScroll().y;
- },
-
- getScrollLeft: function(){
- return this.getScroll().x;
- },
-
- getScrollHeight: function(){
- return this.getScrollSize().y;
- },
-
- getScrollWidth: function(){
- return this.getScrollSize().x;
- },
-
- getTop: function(){
- return this.getPosition().y;
- },
-
- getLeft: function(){
- return this.getPosition().x;
- }
-
-});
-
-
-/*
----
-
-name: Fx
-
-description: Contains the basic animation logic to be extended by all other Fx Classes.
-
-license: MIT-style license.
-
-requires: [Chain, Events, Options]
-
-provides: Fx
-
-...
-*/
-
-(function(){
-
-var Fx = this.Fx = new Class({
-
- Implements: [Chain, Events, Options],
-
- options: {
- /*
- onStart: nil,
- onCancel: nil,
- onComplete: nil,
- */
- fps: 60,
- unit: false,
- duration: 500,
- frames: null,
- frameSkip: true,
- link: 'ignore'
- },
-
- initialize: function(options){
- this.subject = this.subject || this;
- this.setOptions(options);
- },
-
- getTransition: function(){
- return function(p){
- return -(Math.cos(Math.PI * p) - 1) / 2;
- };
- },
-
- step: function(now){
- if (this.options.frameSkip){
- var diff = (this.time != null) ? (now - this.time) : 0, frames = diff / this.frameInterval;
- this.time = now;
- this.frame += frames;
- } else {
- this.frame++;
- }
-
- if (this.frame < this.frames){
- var delta = this.transition(this.frame / this.frames);
- this.set(this.compute(this.from, this.to, delta));
- } else {
- this.frame = this.frames;
- this.set(this.compute(this.from, this.to, 1));
- this.stop();
- }
- },
-
- set: function(now){
- return now;
- },
-
- compute: function(from, to, delta){
- return Fx.compute(from, to, delta);
- },
-
- check: function(){
- if (!this.isRunning()) return true;
- switch (this.options.link){
- case 'cancel': this.cancel(); return true;
- case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
- }
- return false;
- },
-
- start: function(from, to){
- if (!this.check(from, to)) return this;
- this.from = from;
- this.to = to;
- this.frame = (this.options.frameSkip) ? 0 : -1;
- this.time = null;
- this.transition = this.getTransition();
- var frames = this.options.frames, fps = this.options.fps, duration = this.options.duration;
- this.duration = Fx.Durations[duration] || duration.toInt();
- this.frameInterval = 1000 / fps;
- this.frames = frames || Math.round(this.duration / this.frameInterval);
- this.fireEvent('start', this.subject);
- pushInstance.call(this, fps);
- return this;
- },
-
- stop: function(){
- if (this.isRunning()){
- this.time = null;
- pullInstance.call(this, this.options.fps);
- if (this.frames == this.frame){
- this.fireEvent('complete', this.subject);
- if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
- } else {
- this.fireEvent('stop', this.subject);
- }
- }
- return this;
- },
-
- cancel: function(){
- if (this.isRunning()){
- this.time = null;
- pullInstance.call(this, this.options.fps);
- this.frame = this.frames;
- this.fireEvent('cancel', this.subject).clearChain();
- }
- return this;
- },
-
- pause: function(){
- if (this.isRunning()){
- this.time = null;
- pullInstance.call(this, this.options.fps);
- }
- return this;
- },
-
- resume: function(){
- if ((this.frame < this.frames) && !this.isRunning()) pushInstance.call(this, this.options.fps);
- return this;
- },
-
- isRunning: function(){
- var list = instances[this.options.fps];
- return list && list.contains(this);
- }
-
-});
-
-Fx.compute = function(from, to, delta){
- return (to - from) * delta + from;
-};
-
-Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
-
-// global timers
-
-var instances = {}, timers = {};
-
-var loop = function(){
- var now = Date.now();
- for (var i = this.length; i--;){
- var instance = this[i];
- if (instance) instance.step(now);
- }
-};
-
-var pushInstance = function(fps){
- var list = instances[fps] || (instances[fps] = []);
- list.push(this);
- if (!timers[fps]) timers[fps] = loop.periodical(Math.round(1000 / fps), list);
-};
-
-var pullInstance = function(fps){
- var list = instances[fps];
- if (list){
- list.erase(this);
- if (!list.length && timers[fps]){
- delete instances[fps];
- timers[fps] = clearInterval(timers[fps]);
- }
- }
-};
-
-})();
-
-
-/*
----
-
-name: Fx.CSS
-
-description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
-
-license: MIT-style license.
-
-requires: [Fx, Element.Style]
-
-provides: Fx.CSS
-
-...
-*/
-
-Fx.CSS = new Class({
-
- Extends: Fx,
-
- //prepares the base from/to object
-
- prepare: function(element, property, values){
- values = Array.from(values);
- var from = values[0], to = values[1];
- if (to == null){
- to = from;
- from = element.getStyle(property);
- var unit = this.options.unit;
- // adapted from: https://github.com/ryanmorr/fx/blob/master/fx.js#L299
- if (unit && from.slice(-unit.length) != unit && parseFloat(from) != 0){
- element.setStyle(property, to + unit);
- var value = element.getComputedStyle(property);
- // IE and Opera support pixelLeft or pixelWidth
- if (!(/px$/.test(value))){
- value = element.style[('pixel-' + property).camelCase()];
- if (value == null){
- // adapted from Dean Edwards' http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
- var left = element.style.left;
- element.style.left = to + unit;
- value = element.style.pixelLeft;
- element.style.left = left;
- }
- }
- from = (to || 1) / (parseFloat(value) || 1) * (parseFloat(from) || 0);
- element.setStyle(property, from + unit);
- }
- }
- return {from: this.parse(from), to: this.parse(to)};
- },
-
- //parses a value into an array
-
- parse: function(value){
- value = Function.from(value)();
- value = (typeof value == 'string') ? value.split(' ') : Array.from(value);
- return value.map(function(val){
- val = String(val);
- var found = false;
- Object.each(Fx.CSS.Parsers, function(parser, key){
- if (found) return;
- var parsed = parser.parse(val);
- if (parsed || parsed === 0) found = {value: parsed, parser: parser};
- });
- found = found || {value: val, parser: Fx.CSS.Parsers.String};
- return found;
- });
- },
-
- //computes by a from and to prepared objects, using their parsers.
-
- compute: function(from, to, delta){
- var computed = [];
- (Math.min(from.length, to.length)).times(function(i){
- computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
- });
- computed.$family = Function.from('fx:css:value');
- return computed;
- },
-
- //serves the value as settable
-
- serve: function(value, unit){
- if (typeOf(value) != 'fx:css:value') value = this.parse(value);
- var returned = [];
- value.each(function(bit){
- returned = returned.concat(bit.parser.serve(bit.value, unit));
- });
- return returned;
- },
-
- //renders the change to an element
-
- render: function(element, property, value, unit){
- element.setStyle(property, this.serve(value, unit));
- },
-
- //searches inside the page css to find the values for a selector
-
- search: function(selector){
- if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
- var to = {}, selectorTest = new RegExp('^' + selector.escapeRegExp() + '$');
- Array.each(document.styleSheets, function(sheet, j){
- var href = sheet.href;
- if (href && href.contains('://') && !href.contains(document.domain)) return;
- var rules = sheet.rules || sheet.cssRules;
- Array.each(rules, function(rule, i){
- if (!rule.style) return;
- var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
- return m.toLowerCase();
- }) : null;
- if (!selectorText || !selectorTest.test(selectorText)) return;
- Object.each(Element.Styles, function(value, style){
- if (!rule.style[style] || Element.ShortStyles[style]) return;
- value = String(rule.style[style]);
- to[style] = ((/^rgb/).test(value)) ? value.rgbToHex() : value;
- });
- });
- });
- return Fx.CSS.Cache[selector] = to;
- }
-
-});
-
-Fx.CSS.Cache = {};
-
-Fx.CSS.Parsers = {
-
- Color: {
- parse: function(value){
- if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
- return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
- },
- compute: function(from, to, delta){
- return from.map(function(value, i){
- return Math.round(Fx.compute(from[i], to[i], delta));
- });
- },
- serve: function(value){
- return value.map(Number);
- }
- },
-
- Number: {
- parse: parseFloat,
- compute: Fx.compute,
- serve: function(value, unit){
- return (unit) ? value + unit : value;
- }
- },
-
- String: {
- parse: Function.from(false),
- compute: function(zero, one){
- return one;
- },
- serve: function(zero){
- return zero;
- }
- }
-
-};
-
-//<1.2compat>
-
-Fx.CSS.Parsers = new Hash(Fx.CSS.Parsers);
-
-//</1.2compat>
-
-
-/*
----
-
-name: Fx.Tween
-
-description: Formerly Fx.Style, effect to transition any CSS property for an element.
-
-license: MIT-style license.
-
-requires: Fx.CSS
-
-provides: [Fx.Tween, Element.fade, Element.highlight]
-
-...
-*/
-
-Fx.Tween = new Class({
-
- Extends: Fx.CSS,
-
- initialize: function(element, options){
- this.element = this.subject = document.id(element);
- this.parent(options);
- },
-
- set: function(property, now){
- if (arguments.length == 1){
- now = property;
- property = this.property || this.options.property;
- }
- this.render(this.element, property, now, this.options.unit);
- return this;
- },
-
- start: function(property, from, to){
- if (!this.check(property, from, to)) return this;
- var args = Array.flatten(arguments);
- this.property = this.options.property || args.shift();
- var parsed = this.prepare(this.element, this.property, args);
- return this.parent(parsed.from, parsed.to);
- }
-
-});
-
-Element.Properties.tween = {
-
- set: function(options){
- this.get('tween').cancel().setOptions(options);
- return this;
- },
-
- get: function(){
- var tween = this.retrieve('tween');
- if (!tween){
- tween = new Fx.Tween(this, {link: 'cancel'});
- this.store('tween', tween);
- }
- return tween;
- }
-
-};
-
-Element.implement({
-
- tween: function(property, from, to){
- this.get('tween').start(property, from, to);
- return this;
- },
-
- fade: function(how){
- var fade = this.get('tween'), method, args = ['opacity'].append(arguments), toggle;
- if (args[1] == null) args[1] = 'toggle';
- switch (args[1]){
- case 'in': method = 'start'; args[1] = 1; break;
- case 'out': method = 'start'; args[1] = 0; break;
- case 'show': method = 'set'; args[1] = 1; break;
- case 'hide': method = 'set'; args[1] = 0; break;
- case 'toggle':
- var flag = this.retrieve('fade:flag', this.getStyle('opacity') == 1);
- method = 'start';
- args[1] = flag ? 0 : 1;
- this.store('fade:flag', !flag);
- toggle = true;
- break;
- default: method = 'start';
- }
- if (!toggle) this.eliminate('fade:flag');
- fade[method].apply(fade, args);
- var to = args[args.length - 1];
- if (method == 'set' || to != 0) this.setStyle('visibility', to == 0 ? 'hidden' : 'visible');
- else fade.chain(function(){
- this.element.setStyle('visibility', 'hidden');
- this.callChain();
- });
- return this;
- },
-
- highlight: function(start, end){
- if (!end){
- end = this.retrieve('highlight:original', this.getStyle('background-color'));
- end = (end == 'transparent') ? '#fff' : end;
- }
- var tween = this.get('tween');
- tween.start('background-color', start || '#ffff88', end).chain(function(){
- this.setStyle('background-color', this.retrieve('highlight:original'));
- tween.callChain();
- }.bind(this));
- return this;
- }
-
-});
-
-
-/*
----
-
-name: Fx.Morph
-
-description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
-
-license: MIT-style license.
-
-requires: Fx.CSS
-
-provides: Fx.Morph
-
-...
-*/
-
-Fx.Morph = new Class({
-
- Extends: Fx.CSS,
-
- initialize: function(element, options){
- this.element = this.subject = document.id(element);
- this.parent(options);
- },
-
- set: function(now){
- if (typeof now == 'string') now = this.search(now);
- for (var p in now) this.render(this.element, p, now[p], this.options.unit);
- return this;
- },
-
- compute: function(from, to, delta){
- var now = {};
- for (var p in from) now[p] = this.parent(from[p], to[p], delta);
- return now;
- },
-
- start: function(properties){
- if (!this.check(properties)) return this;
- if (typeof properties == 'string') properties = this.search(properties);
- var from = {}, to = {};
- for (var p in properties){
- var parsed = this.prepare(this.element, p, properties[p]);
- from[p] = parsed.from;
- to[p] = parsed.to;
- }
- return this.parent(from, to);
- }
-
-});
-
-Element.Properties.morph = {
-
- set: function(options){
- this.get('morph').cancel().setOptions(options);
- return this;
- },
-
- get: function(){
- var morph = this.retrieve('morph');
- if (!morph){
- morph = new Fx.Morph(this, {link: 'cancel'});
- this.store('morph', morph);
- }
- return morph;
- }
-
-};
-
-Element.implement({
-
- morph: function(props){
- this.get('morph').start(props);
- return this;
- }
-
-});
-
-
-/*
----
-
-name: Fx.Transitions
-
-description: Contains a set of advanced transitions to be used with any of the Fx Classes.
-
-license: MIT-style license.
-
-credits:
- - Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
-
-requires: Fx
-
-provides: Fx.Transitions
-
-...
-*/
-
-Fx.implement({
-
- getTransition: function(){
- var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
- if (typeof trans == 'string'){
- var data = trans.split(':');
- trans = Fx.Transitions;
- trans = trans[data[0]] || trans[data[0].capitalize()];
- if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
- }
- return trans;
- }
-
-});
-
-Fx.Transition = function(transition, params){
- params = Array.from(params);
- var easeIn = function(pos){
- return transition(pos, params);
- };
- return Object.append(easeIn, {
- easeIn: easeIn,
- easeOut: function(pos){
- return 1 - transition(1 - pos, params);
- },
- easeInOut: function(pos){
- return (pos <= 0.5 ? transition(2 * pos, params) : (2 - transition(2 * (1 - pos), params))) / 2;
- }
- });
-};
-
-Fx.Transitions = {
-
- linear: function(zero){
- return zero;
- }
-
-};
-
-//<1.2compat>
-
-Fx.Transitions = new Hash(Fx.Transitions);
-
-//</1.2compat>
-
-Fx.Transitions.extend = function(transitions){
- for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
-};
-
-Fx.Transitions.extend({
-
- Pow: function(p, x){
- return Math.pow(p, x && x[0] || 6);
- },
-
- Expo: function(p){
- return Math.pow(2, 8 * (p - 1));
- },
-
- Circ: function(p){
- return 1 - Math.sin(Math.acos(p));
- },
-
- Sine: function(p){
- return 1 - Math.cos(p * Math.PI / 2);
- },
-
- Back: function(p, x){
- x = x && x[0] || 1.618;
- return Math.pow(p, 2) * ((x + 1) * p - x);
- },
-
- Bounce: function(p){
- var value;
- for (var a = 0, b = 1; 1; a += b, b /= 2){
- if (p >= (7 - 4 * a) / 11){
- value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
- break;
- }
- }
- return value;
- },
-
- Elastic: function(p, x){
- return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x && x[0] || 1) / 3);
- }
-
-});
-
-['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
- Fx.Transitions[transition] = new Fx.Transition(function(p){
- return Math.pow(p, i + 2);
- });
-});
-
-
-/*
----
-
-name: Request
-
-description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
-
-license: MIT-style license.
-
-requires: [Object, Element, Chain, Events, Options, Browser]
-
-provides: Request
-
-...
-*/
-
-(function(){
-
-var empty = function(){},
- progressSupport = ('onprogress' in new Browser.Request);
-
-var Request = this.Request = new Class({
-
- Implements: [Chain, Events, Options],
-
- options: {/*
- onRequest: function(){},
- onLoadstart: function(event, xhr){},
- onProgress: function(event, xhr){},
- onComplete: function(){},
- onCancel: function(){},
- onSuccess: function(responseText, responseXML){},
- onFailure: function(xhr){},
- onException: function(headerName, value){},
- onTimeout: function(){},
- user: '',
- password: '',*/
- url: '',
- data: '',
- headers: {
- 'X-Requested-With': 'XMLHttpRequest',
- 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
- },
- async: true,
- format: false,
- method: 'post',
- link: 'ignore',
- isSuccess: null,
- emulation: true,
- urlEncoded: true,
- encoding: 'utf-8',
- evalScripts: false,
- evalResponse: false,
- timeout: 0,
- noCache: false
- },
-
- initialize: function(options){
- this.xhr = new Browser.Request();
- this.setOptions(options);
- this.headers = this.options.headers;
- },
-
- onStateChange: function(){
- var xhr = this.xhr;
- if (xhr.readyState != 4 || !this.running) return;
- this.running = false;
- this.status = 0;
- Function.attempt(function(){
- var status = xhr.status;
- this.status = (status == 1223) ? 204 : status;
- }.bind(this));
- xhr.onreadystatechange = empty;
- if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
- clearTimeout(this.timer);
-
- this.response = {text: this.xhr.responseText || '', xml: this.xhr.responseXML};
- if (this.options.isSuccess.call(this, this.status))
- this.success(this.response.text, this.response.xml);
- else
- this.failure();
- },
-
- isSuccess: function(){
- var status = this.status;
- return (status >= 200 && status < 300);
- },
-
- isRunning: function(){
- return !!this.running;
- },
-
- processScripts: function(text){
- if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return Browser.exec(text);
- return text.stripScripts(this.options.evalScripts);
- },
-
- success: function(text, xml){
- this.onSuccess(this.processScripts(text), xml);
- },
-
- onSuccess: function(){
- this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
- },
-
- failure: function(){
- this.onFailure();
- },
-
- onFailure: function(){
- this.fireEvent('complete').fireEvent('failure', this.xhr);
- },
-
- loadstart: function(event){
- this.fireEvent('loadstart', [event, this.xhr]);
- },
-
- progress: function(event){
- this.fireEvent('progress', [event, this.xhr]);
- },
-
- timeout: function(){
- this.fireEvent('timeout', this.xhr);
- },
-
- setHeader: function(name, value){
- this.headers[name] = value;
- return this;
- },
-
- getHeader: function(name){
- return Function.attempt(function(){
- return this.xhr.getResponseHeader(name);
- }.bind(this));
- },
-
- check: function(){
- if (!this.running) return true;
- switch (this.options.link){
- case 'cancel': this.cancel(); return true;
- case 'chain': this.chain(this.caller.pass(arguments, this)); return false;
- }
- return false;
- },
-
- send: function(options){
- if (!this.check(options)) return this;
-
- this.options.isSuccess = this.options.isSuccess || this.isSuccess;
- this.running = true;
-
- var type = typeOf(options);
- if (type == 'string' || type == 'element') options = {data: options};
-
- var old = this.options;
- options = Object.append({data: old.data, url: old.url, method: old.method}, options);
- var data = options.data, url = String(options.url), method = options.method.toLowerCase();
-
- switch (typeOf(data)){
- case 'element': data = document.id(data).toQueryString(); break;
- case 'object': case 'hash': data = Object.toQueryString(data);
- }
-
- if (this.options.format){
- var format = 'format=' + this.options.format;
- data = (data) ? format + '&' + data : format;
- }
-
- if (this.options.emulation && !['get', 'post'].contains(method)){
- var _method = '_method=' + method;
- data = (data) ? _method + '&' + data : _method;
- method = 'post';
- }
-
- if (this.options.urlEncoded && ['post', 'put'].contains(method)){
- var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
- this.headers['Content-type'] = 'application/x-www-form-urlencoded' + encoding;
- }
-
- if (!url) url = document.location.pathname;
-
- var trimPosition = url.lastIndexOf('/');
- if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
-
- if (this.options.noCache)
- url += (url.contains('?') ? '&' : '?') + String.uniqueID();
-
- if (data && method == 'get'){
- url += (url.contains('?') ? '&' : '?') + data;
- data = null;
- }
-
- var xhr = this.xhr;
- if (progressSupport){
- xhr.onloadstart = this.loadstart.bind(this);
- xhr.onprogress = this.progress.bind(this);
- }
-
- xhr.open(method.toUpperCase(), url, this.options.async, this.options.user, this.options.password);
- if (this.options.user && 'withCredentials' in xhr) xhr.withCredentials = true;
-
- xhr.onreadystatechange = this.onStateChange.bind(this);
-
- Object.each(this.headers, function(value, key){
- try {
- xhr.setRequestHeader(key, value);
- } catch (e){
- this.fireEvent('exception', [key, value]);
- }
- }, this);
-
- this.fireEvent('request');
- xhr.send(data);
- if (!this.options.async) this.onStateChange();
- else if (this.options.timeout) this.timer = this.timeout.delay(this.options.timeout, this);
- return this;
- },
-
- cancel: function(){
- if (!this.running) return this;
- this.running = false;
- var xhr = this.xhr;
- xhr.abort();
- clearTimeout(this.timer);
- xhr.onreadystatechange = empty;
- if (progressSupport) xhr.onprogress = xhr.onloadstart = empty;
- this.xhr = new Browser.Request();
- this.fireEvent('cancel');
- return this;
- }
-
-});
-
-var methods = {};
-['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
- methods[method] = function(data){
- var object = {
- method: method
- };
- if (data != null) object.data = data;
- return this.send(object);
- };
-});
-
-Request.implement(methods);
-
-Element.Properties.send = {
-
- set: function(options){
- var send = this.get('send').cancel();
- send.setOptions(options);
- return this;
- },
-
- get: function(){
- var send = this.retrieve('send');
- if (!send){
- send = new Request({
- data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
- });
- this.store('send', send);
- }
- return send;
- }
-
-};
-
-Element.implement({
-
- send: function(url){
- var sender = this.get('send');
- sender.send({data: this, url: url || sender.options.url});
- return this;
- }
-
-});
-
-})();
-
-
-/*
----
-
-name: Request.HTML
-
-description: Extends the basic Request Class with additional methods for interacting with HTML responses.
-
-license: MIT-style license.
-
-requires: [Element, Request]
-
-provides: Request.HTML
-
-...
-*/
-
-Request.HTML = new Class({
-
- Extends: Request,
-
- options: {
- update: false,
- append: false,
- evalScripts: true,
- filter: false,
- headers: {
- Accept: 'text/html, application/xml, text/xml, */*'
- }
- },
-
- success: function(text){
- var options = this.options, response = this.response;
-
- response.html = text.stripScripts(function(script){
- response.javascript = script;
- });
-
- var match = response.html.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
- if (match) response.html = match[1];
- var temp = new Element('div').set('html', response.html);
-
- response.tree = temp.childNodes;
- response.elements = temp.getElements(options.filter || '*');
-
- if (options.filter) response.tree = response.elements;
- if (options.update){
- var update = document.id(options.update).empty();
- if (options.filter) update.adopt(response.elements);
- else update.set('html', response.html);
- } else if (options.append){
- var append = document.id(options.append);
- if (options.filter) response.elements.reverse().inject(append);
- else append.adopt(temp.getChildren());
- }
- if (options.evalScripts) Browser.exec(response.javascript);
-
- this.onSuccess(response.tree, response.elements, response.html, response.javascript);
- }
-
-});
-
-Element.Properties.load = {
-
- set: function(options){
- var load = this.get('load').cancel();
- load.setOptions(options);
- return this;
- },
-
- get: function(){
- var load = this.retrieve('load');
- if (!load){
- load = new Request.HTML({data: this, link: 'cancel', update: this, method: 'get'});
- this.store('load', load);
- }
- return load;
- }
-
-};
-
-Element.implement({
-
- load: function(){
- this.get('load').send(Array.link(arguments, {data: Type.isObject, url: Type.isString}));
- return this;
- }
-
-});
-
-
-/*
----
-
-name: JSON
-
-description: JSON encoder and decoder.
-
-license: MIT-style license.
-
-SeeAlso: <http://www.json.org/>
-
-requires: [Array, String, Number, Function]
-
-provides: JSON
-
-...
-*/
-
-if (typeof JSON == 'undefined') this.JSON = {};
-
-//<1.2compat>
-
-JSON = new Hash({
- stringify: JSON.stringify,
- parse: JSON.parse
-});
-
-//</1.2compat>
-
-(function(){
-
-var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
-
-var escape = function(chr){
- return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
-};
-
-JSON.validate = function(string){
- string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
- replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
- replace(/(?:^|:|,)(?:\s*\[)+/g, '');
-
- return (/^[\],:{}\s]*$/).test(string);
-};
-
-JSON.encode = JSON.stringify ? function(obj){
- return JSON.stringify(obj);
-} : function(obj){
- if (obj && obj.toJSON) obj = obj.toJSON();
-
- switch (typeOf(obj)){
- case 'string':
- return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
- case 'array':
- return '[' + obj.map(JSON.encode).clean() + ']';
- case 'object': case 'hash':
- var string = [];
- Object.each(obj, function(value, key){
- var json = JSON.encode(value);
- if (json) string.push(JSON.encode(key) + ':' + json);
- });
- return '{' + string + '}';
- case 'number': case 'boolean': return '' + obj;
- case 'null': return 'null';
- }
-
- return null;
-};
-
-JSON.decode = function(string, secure){
- if (!string || typeOf(string) != 'string') return null;
-
- if (secure || JSON.secure){
- if (JSON.parse) return JSON.parse(string);
- if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
- }
-
- return eval('(' + string + ')');
-};
-
-})();
-
-
-/*
----
-
-name: Request.JSON
-
-description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
-
-license: MIT-style license.
-
-requires: [Request, JSON]
-
-provides: Request.JSON
-
-...
-*/
-
-Request.JSON = new Class({
-
- Extends: Request,
-
- options: {
- /*onError: function(text, error){},*/
- secure: true
- },
-
- initialize: function(options){
- this.parent(options);
- Object.append(this.headers, {
- 'Accept': 'application/json',
- 'X-Request': 'JSON'
- });
- },
-
- success: function(text){
- var json;
- try {
- json = this.response.json = JSON.decode(text, this.options.secure);
- } catch (error){
- this.fireEvent('error', [text, error]);
- return;
- }
- if (json == null) this.onFailure();
- else this.onSuccess(json, text);
- }
-
-});
-
-
-/*
----
-
-name: Cookie
-
-description: Class for creating, reading, and deleting browser Cookies.
-
-license: MIT-style license.
-
-credits:
- - Based on the functions by Peter-Paul Koch (http://quirksmode.org).
-
-requires: [Options, Browser]
-
-provides: Cookie
-
-...
-*/
-
-var Cookie = new Class({
-
- Implements: Options,
-
- options: {
- path: '/',
- domain: false,
- duration: false,
- secure: false,
- document: document,
- encode: true
- },
-
- initialize: function(key, options){
- this.key = key;
- this.setOptions(options);
- },
-
- write: function(value){
- if (this.options.encode) value = encodeURIComponent(value);
- if (this.options.domain) value += '; domain=' + this.options.domain;
- if (this.options.path) value += '; path=' + this.options.path;
- if (this.options.duration){
- var date = new Date();
- date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
- value += '; expires=' + date.toGMTString();
- }
- if (this.options.secure) value += '; secure';
- this.options.document.cookie = this.key + '=' + value;
- return this;
- },
-
- read: function(){
- var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
- return (value) ? decodeURIComponent(value[1]) : null;
- },
-
- dispose: function(){
- new Cookie(this.key, Object.merge({}, this.options, {duration: -1})).write('');
- return this;
- }
-
-});
-
-Cookie.write = function(key, value, options){
- return new Cookie(key, options).write(value);
-};
-
-Cookie.read = function(key){
- return new Cookie(key).read();
-};
-
-Cookie.dispose = function(key, options){
- return new Cookie(key, options).dispose();
-};
-
-
-/*
----
-
-name: DOMReady
-
-description: Contains the custom event domready.
-
-license: MIT-style license.
-
-requires: [Browser, Element, Element.Event]
-
-provides: [DOMReady, DomReady]
-
-...
-*/
-
-(function(window, document){
-
-var ready,
- loaded,
- checks = [],
- shouldPoll,
- timer,
- testElement = document.createElement('div');
-
-var domready = function(){
- clearTimeout(timer);
- if (ready) return;
- Browser.loaded = ready = true;
- document.removeListener('DOMContentLoaded', domready).removeListener('readystatechange', check);
-
- document.fireEvent('domready');
- window.fireEvent('domready');
-};
-
-var check = function(){
- for (var i = checks.length; i--;) if (checks[i]()){
- domready();
- return true;
- }
- return false;
-};
-
-var poll = function(){
- clearTimeout(timer);
- if (!check()) timer = setTimeout(poll, 10);
-};
-
-document.addListener('DOMContentLoaded', domready);
-
-/*<ltIE8>*/
-// doScroll technique by Diego Perini http://javascript.nwbox.com/IEContentLoaded/
-// testElement.doScroll() throws when the DOM is not ready, only in the top window
-var doScrollWorks = function(){
- try {
- testElement.doScroll();
- return true;
- } catch (e){}
- return false;
-};
-// If doScroll works already, it can't be used to determine domready
-// e.g. in an iframe
-if (testElement.doScroll && !doScrollWorks()){
- checks.push(doScrollWorks);
- shouldPoll = true;
-}
-/*</ltIE8>*/
-
-if (document.readyState) checks.push(function(){
- var state = document.readyState;
- return (state == 'loaded' || state == 'complete');
-});
-
-if ('onreadystatechange' in document) document.addListener('readystatechange', check);
-else shouldPoll = true;
-
-if (shouldPoll) poll();
-
-Element.Events.domready = {
- onAdd: function(fn){
- if (ready) fn.call(this);
- }
-};
-
-// Make sure that domready fires before load
-Element.Events.load = {
- base: 'load',
- onAdd: function(fn){
- if (loaded && this == window) fn.call(this);
- },
- condition: function(){
- if (this == window){
- domready();
- delete Element.Events.load;
- }
- return true;
- }
-};
-
-// This is based on the custom load event
-window.addEvent('load', function(){
- loaded = true;
-});
-
-})(window, document);
-
-
-/*
----
-
-name: Swiff
-
-description: Wrapper for embedding SWF movies. Supports External Interface Communication.
-
-license: MIT-style license.
-
-credits:
- - Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
-
-requires: [Options, Object, Element]
-
-provides: Swiff
-
-...
-*/
-
-(function(){
-
-var Swiff = this.Swiff = new Class({
-
- Implements: Options,
-
- options: {
- id: null,
- height: 1,
- width: 1,
- container: null,
- properties: {},
- params: {
- quality: 'high',
- allowScriptAccess: 'always',
- wMode: 'window',
- swLiveConnect: true
- },
- callBacks: {},
- vars: {}
- },
-
- toElement: function(){
- return this.object;
- },
-
- initialize: function(path, options){
- this.instance = 'Swiff_' + String.uniqueID();
-
- this.setOptions(options);
- options = this.options;
- var id = this.id = options.id || this.instance;
- var container = document.id(options.container);
-
- Swiff.CallBacks[this.instance] = {};
-
- var params = options.params, vars = options.vars, callBacks = options.callBacks;
- var properties = Object.append({height: options.height, width: options.width}, options.properties);
-
- var self = this;
-
- for (var callBack in callBacks){
- Swiff.CallBacks[this.instance][callBack] = (function(option){
- return function(){
- return option.apply(self.object, arguments);
- };
- })(callBacks[callBack]);
- vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
- }
-
- params.flashVars = Object.toQueryString(vars);
- if (Browser.ie){
- properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
- params.movie = path;
- } else {
- properties.type = 'application/x-shockwave-flash';
- }
- properties.data = path;
-
- var build = '<object id="' + id + '"';
- for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
- build += '>';
- for (var param in params){
- if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
- }
- build += '</object>';
- this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
- },
-
- replaces: function(element){
- element = document.id(element, true);
- element.parentNode.replaceChild(this.toElement(), element);
- return this;
- },
-
- inject: function(element){
- document.id(element, true).appendChild(this.toElement());
- return this;
- },
-
- remote: function(){
- return Swiff.remote.apply(Swiff, [this.toElement()].append(arguments));
- }
-
-});
-
-Swiff.CallBacks = {};
-
-Swiff.remote = function(obj, fn){
- var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
- return eval(rs);
-};
-
-})();
-
deleted file mode 100644
index 98ac4a54818a74ededaeed76adad802034071c41..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/underscore-1.5.js
+++ /dev/null
@@ -1,1276 +0,0 @@
-// Underscore.js 1.5.2
-// http://underscorejs.org
-// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
-// Underscore may be freely distributed under the MIT license.
-
-(function() {
-
- // Baseline setup
- // --------------
-
- // Establish the root object, `window` in the browser, or `exports` on the server.
- var root = this;
-
- // Save the previous value of the `_` variable.
- var previousUnderscore = root._;
-
- // Establish the object that gets returned to break out of a loop iteration.
- var breaker = {};
-
- // Save bytes in the minified (but not gzipped) version:
- var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
-
- // Create quick reference variables for speed access to core prototypes.
- var
- push = ArrayProto.push,
- slice = ArrayProto.slice,
- concat = ArrayProto.concat,
- toString = ObjProto.toString,
- hasOwnProperty = ObjProto.hasOwnProperty;
-
- // All **ECMAScript 5** native function implementations that we hope to use
- // are declared here.
- var
- nativeForEach = ArrayProto.forEach,
- nativeMap = ArrayProto.map,
- nativeReduce = ArrayProto.reduce,
- nativeReduceRight = ArrayProto.reduceRight,
- nativeFilter = ArrayProto.filter,
- nativeEvery = ArrayProto.every,
- nativeSome = ArrayProto.some,
- nativeIndexOf = ArrayProto.indexOf,
- nativeLastIndexOf = ArrayProto.lastIndexOf,
- nativeIsArray = Array.isArray,
- nativeKeys = Object.keys,
- nativeBind = FuncProto.bind;
-
- // Create a safe reference to the Underscore object for use below.
- var _ = function(obj) {
- if (obj instanceof _) return obj;
- if (!(this instanceof _)) return new _(obj);
- this._wrapped = obj;
- };
-
- // Export the Underscore object for **Node.js**, with
- // backwards-compatibility for the old `require()` API. If we're in
- // the browser, add `_` as a global object via a string identifier,
- // for Closure Compiler "advanced" mode.
- if (typeof exports !== 'undefined') {
- if (typeof module !== 'undefined' && module.exports) {
- exports = module.exports = _;
- }
- exports._ = _;
- } else {
- root._ = _;
- }
-
- // Current version.
- _.VERSION = '1.5.2';
-
- // Collection Functions
- // --------------------
-
- // The cornerstone, an `each` implementation, aka `forEach`.
- // Handles objects with the built-in `forEach`, arrays, and raw objects.
- // Delegates to **ECMAScript 5**'s native `forEach` if available.
- var each = _.each = _.forEach = function(obj, iterator, context) {
- if (obj == null) return;
- if (nativeForEach && obj.forEach === nativeForEach) {
- obj.forEach(iterator, context);
- } else if (obj.length === +obj.length) {
- for (var i = 0, length = obj.length; i < length; i++) {
- if (iterator.call(context, obj[i], i, obj) === breaker) return;
- }
- } else {
- var keys = _.keys(obj);
- for (var i = 0, length = keys.length; i < length; i++) {
- if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
- }
- }
- };
-
- // Return the results of applying the iterator to each element.
- // Delegates to **ECMAScript 5**'s native `map` if available.
- _.map = _.collect = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
- each(obj, function(value, index, list) {
- results.push(iterator.call(context, value, index, list));
- });
- return results;
- };
-
- var reduceError = 'Reduce of empty array with no initial value';
-
- // **Reduce** builds up a single result from a list of values, aka `inject`,
- // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
- _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
- if (obj == null) obj = [];
- if (nativeReduce && obj.reduce === nativeReduce) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
- }
- each(obj, function(value, index, list) {
- if (!initial) {
- memo = value;
- initial = true;
- } else {
- memo = iterator.call(context, memo, value, index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
- return memo;
- };
-
- // The right-associative version of reduce, also known as `foldr`.
- // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
- _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
- var initial = arguments.length > 2;
- if (obj == null) obj = [];
- if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
- if (context) iterator = _.bind(iterator, context);
- return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
- }
- var length = obj.length;
- if (length !== +length) {
- var keys = _.keys(obj);
- length = keys.length;
- }
- each(obj, function(value, index, list) {
- index = keys ? keys[--length] : --length;
- if (!initial) {
- memo = obj[index];
- initial = true;
- } else {
- memo = iterator.call(context, memo, obj[index], index, list);
- }
- });
- if (!initial) throw new TypeError(reduceError);
- return memo;
- };
-
- // Return the first value which passes a truth test. Aliased as `detect`.
- _.find = _.detect = function(obj, iterator, context) {
- var result;
- any(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) {
- result = value;
- return true;
- }
- });
- return result;
- };
-
- // Return all the elements that pass a truth test.
- // Delegates to **ECMAScript 5**'s native `filter` if available.
- // Aliased as `select`.
- _.filter = _.select = function(obj, iterator, context) {
- var results = [];
- if (obj == null) return results;
- if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
- each(obj, function(value, index, list) {
- if (iterator.call(context, value, index, list)) results.push(value);
- });
- return results;
- };
-
- // Return all the elements for which a truth test fails.
- _.reject = function(obj, iterator, context) {
- return _.filter(obj, function(value, index, list) {
- return !iterator.call(context, value, index, list);
- }, context);
- };
-
- // Determine whether all of the elements match a truth test.
- // Delegates to **ECMAScript 5**'s native `every` if available.
- // Aliased as `all`.
- _.every = _.all = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = true;
- if (obj == null) return result;
- if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
- each(obj, function(value, index, list) {
- if (!(result = result && iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
- };
-
- // Determine if at least one element in the object matches a truth test.
- // Delegates to **ECMAScript 5**'s native `some` if available.
- // Aliased as `any`.
- var any = _.some = _.any = function(obj, iterator, context) {
- iterator || (iterator = _.identity);
- var result = false;
- if (obj == null) return result;
- if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
- each(obj, function(value, index, list) {
- if (result || (result = iterator.call(context, value, index, list))) return breaker;
- });
- return !!result;
- };
-
- // Determine if the array or object contains a given value (using `===`).
- // Aliased as `include`.
- _.contains = _.include = function(obj, target) {
- if (obj == null) return false;
- if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
- return any(obj, function(value) {
- return value === target;
- });
- };
-
- // Invoke a method (with arguments) on every item in a collection.
- _.invoke = function(obj, method) {
- var args = slice.call(arguments, 2);
- var isFunc = _.isFunction(method);
- return _.map(obj, function(value) {
- return (isFunc ? method : value[method]).apply(value, args);
- });
- };
-
- // Convenience version of a common use case of `map`: fetching a property.
- _.pluck = function(obj, key) {
- return _.map(obj, function(value){ return value[key]; });
- };
-
- // Convenience version of a common use case of `filter`: selecting only objects
- // containing specific `key:value` pairs.
- _.where = function(obj, attrs, first) {
- if (_.isEmpty(attrs)) return first ? void 0 : [];
- return _[first ? 'find' : 'filter'](obj, function(value) {
- for (var key in attrs) {
- if (attrs[key] !== value[key]) return false;
- }
- return true;
- });
- };
-
- // Convenience version of a common use case of `find`: getting the first object
- // containing specific `key:value` pairs.
- _.findWhere = function(obj, attrs) {
- return _.where(obj, attrs, true);
- };
-
- // Return the maximum element or (element-based computation).
- // Can't optimize arrays of integers longer than 65,535 elements.
- // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
- _.max = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.max.apply(Math, obj);
- }
- if (!iterator && _.isEmpty(obj)) return -Infinity;
- var result = {computed : -Infinity, value: -Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed > result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
- };
-
- // Return the minimum element (or element-based computation).
- _.min = function(obj, iterator, context) {
- if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
- return Math.min.apply(Math, obj);
- }
- if (!iterator && _.isEmpty(obj)) return Infinity;
- var result = {computed : Infinity, value: Infinity};
- each(obj, function(value, index, list) {
- var computed = iterator ? iterator.call(context, value, index, list) : value;
- computed < result.computed && (result = {value : value, computed : computed});
- });
- return result.value;
- };
-
- // Shuffle an array, using the modern version of the
- // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
- _.shuffle = function(obj) {
- var rand;
- var index = 0;
- var shuffled = [];
- each(obj, function(value) {
- rand = _.random(index++);
- shuffled[index - 1] = shuffled[rand];
- shuffled[rand] = value;
- });
- return shuffled;
- };
-
- // Sample **n** random values from an array.
- // If **n** is not specified, returns a single random element from the array.
- // The internal `guard` argument allows it to work with `map`.
- _.sample = function(obj, n, guard) {
- if (arguments.length < 2 || guard) {
- return obj[_.random(obj.length - 1)];
- }
- return _.shuffle(obj).slice(0, Math.max(0, n));
- };
-
- // An internal function to generate lookup iterators.
- var lookupIterator = function(value) {
- return _.isFunction(value) ? value : function(obj){ return obj[value]; };
- };
-
- // Sort the object's values by a criterion produced by an iterator.
- _.sortBy = function(obj, value, context) {
- var iterator = lookupIterator(value);
- return _.pluck(_.map(obj, function(value, index, list) {
- return {
- value: value,
- index: index,
- criteria: iterator.call(context, value, index, list)
- };
- }).sort(function(left, right) {
- var a = left.criteria;
- var b = right.criteria;
- if (a !== b) {
- if (a > b || a === void 0) return 1;
- if (a < b || b === void 0) return -1;
- }
- return left.index - right.index;
- }), 'value');
- };
-
- // An internal function used for aggregate "group by" operations.
- var group = function(behavior) {
- return function(obj, value, context) {
- var result = {};
- var iterator = value == null ? _.identity : lookupIterator(value);
- each(obj, function(value, index) {
- var key = iterator.call(context, value, index, obj);
- behavior(result, key, value);
- });
- return result;
- };
- };
-
- // Groups the object's values by a criterion. Pass either a string attribute
- // to group by, or a function that returns the criterion.
- _.groupBy = group(function(result, key, value) {
- (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
- });
-
- // Indexes the object's values by a criterion, similar to `groupBy`, but for
- // when you know that your index values will be unique.
- _.indexBy = group(function(result, key, value) {
- result[key] = value;
- });
-
- // Counts instances of an object that group by a certain criterion. Pass
- // either a string attribute to count by, or a function that returns the
- // criterion.
- _.countBy = group(function(result, key) {
- _.has(result, key) ? result[key]++ : result[key] = 1;
- });
-
- // Use a comparator function to figure out the smallest index at which
- // an object should be inserted so as to maintain order. Uses binary search.
- _.sortedIndex = function(array, obj, iterator, context) {
- iterator = iterator == null ? _.identity : lookupIterator(iterator);
- var value = iterator.call(context, obj);
- var low = 0, high = array.length;
- while (low < high) {
- var mid = (low + high) >>> 1;
- iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
- }
- return low;
- };
-
- // Safely create a real, live array from anything iterable.
- _.toArray = function(obj) {
- if (!obj) return [];
- if (_.isArray(obj)) return slice.call(obj);
- if (obj.length === +obj.length) return _.map(obj, _.identity);
- return _.values(obj);
- };
-
- // Return the number of elements in an object.
- _.size = function(obj) {
- if (obj == null) return 0;
- return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
- };
-
- // Array Functions
- // ---------------
-
- // Get the first element of an array. Passing **n** will return the first N
- // values in the array. Aliased as `head` and `take`. The **guard** check
- // allows it to work with `_.map`.
- _.first = _.head = _.take = function(array, n, guard) {
- if (array == null) return void 0;
- return (n == null) || guard ? array[0] : slice.call(array, 0, n);
- };
-
- // Returns everything but the last entry of the array. Especially useful on
- // the arguments object. Passing **n** will return all the values in
- // the array, excluding the last N. The **guard** check allows it to work with
- // `_.map`.
- _.initial = function(array, n, guard) {
- return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
- };
-
- // Get the last element of an array. Passing **n** will return the last N
- // values in the array. The **guard** check allows it to work with `_.map`.
- _.last = function(array, n, guard) {
- if (array == null) return void 0;
- if ((n == null) || guard) {
- return array[array.length - 1];
- } else {
- return slice.call(array, Math.max(array.length - n, 0));
- }
- };
-
- // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
- // Especially useful on the arguments object. Passing an **n** will return
- // the rest N values in the array. The **guard**
- // check allows it to work with `_.map`.
- _.rest = _.tail = _.drop = function(array, n, guard) {
- return slice.call(array, (n == null) || guard ? 1 : n);
- };
-
- // Trim out all falsy values from an array.
- _.compact = function(array) {
- return _.filter(array, _.identity);
- };
-
- // Internal implementation of a recursive `flatten` function.
- var flatten = function(input, shallow, output) {
- if (shallow && _.every(input, _.isArray)) {
- return concat.apply(output, input);
- }
- each(input, function(value) {
- if (_.isArray(value) || _.isArguments(value)) {
- shallow ? push.apply(output, value) : flatten(value, shallow, output);
- } else {
- output.push(value);
- }
- });
- return output;
- };
-
- // Flatten out an array, either recursively (by default), or just one level.
- _.flatten = function(array, shallow) {
- return flatten(array, shallow, []);
- };
-
- // Return a version of the array that does not contain the specified value(s).
- _.without = function(array) {
- return _.difference(array, slice.call(arguments, 1));
- };
-
- // Produce a duplicate-free version of the array. If the array has already
- // been sorted, you have the option of using a faster algorithm.
- // Aliased as `unique`.
- _.uniq = _.unique = function(array, isSorted, iterator, context) {
- if (_.isFunction(isSorted)) {
- context = iterator;
- iterator = isSorted;
- isSorted = false;
- }
- var initial = iterator ? _.map(array, iterator, context) : array;
- var results = [];
- var seen = [];
- each(initial, function(value, index) {
- if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
- seen.push(value);
- results.push(array[index]);
- }
- });
- return results;
- };
-
- // Produce an array that contains the union: each distinct element from all of
- // the passed-in arrays.
- _.union = function() {
- return _.uniq(_.flatten(arguments, true));
- };
-
- // Produce an array that contains every item shared between all the
- // passed-in arrays.
- _.intersection = function(array) {
- var rest = slice.call(arguments, 1);
- return _.filter(_.uniq(array), function(item) {
- return _.every(rest, function(other) {
- return _.indexOf(other, item) >= 0;
- });
- });
- };
-
- // Take the difference between one array and a number of other arrays.
- // Only the elements present in just the first array will remain.
- _.difference = function(array) {
- var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
- return _.filter(array, function(value){ return !_.contains(rest, value); });
- };
-
- // Zip together multiple lists into a single array -- elements that share
- // an index go together.
- _.zip = function() {
- var length = _.max(_.pluck(arguments, "length").concat(0));
- var results = new Array(length);
- for (var i = 0; i < length; i++) {
- results[i] = _.pluck(arguments, '' + i);
- }
- return results;
- };
-
- // Converts lists into objects. Pass either a single array of `[key, value]`
- // pairs, or two parallel arrays of the same length -- one of keys, and one of
- // the corresponding values.
- _.object = function(list, values) {
- if (list == null) return {};
- var result = {};
- for (var i = 0, length = list.length; i < length; i++) {
- if (values) {
- result[list[i]] = values[i];
- } else {
- result[list[i][0]] = list[i][1];
- }
- }
- return result;
- };
-
- // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
- // we need this function. Return the position of the first occurrence of an
- // item in an array, or -1 if the item is not included in the array.
- // Delegates to **ECMAScript 5**'s native `indexOf` if available.
- // If the array is large and already in sort order, pass `true`
- // for **isSorted** to use binary search.
- _.indexOf = function(array, item, isSorted) {
- if (array == null) return -1;
- var i = 0, length = array.length;
- if (isSorted) {
- if (typeof isSorted == 'number') {
- i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
- } else {
- i = _.sortedIndex(array, item);
- return array[i] === item ? i : -1;
- }
- }
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
- for (; i < length; i++) if (array[i] === item) return i;
- return -1;
- };
-
- // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
- _.lastIndexOf = function(array, item, from) {
- if (array == null) return -1;
- var hasIndex = from != null;
- if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
- return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
- }
- var i = (hasIndex ? from : array.length);
- while (i--) if (array[i] === item) return i;
- return -1;
- };
-
- // Generate an integer Array containing an arithmetic progression. A port of
- // the native Python `range()` function. See
- // [the Python documentation](http://docs.python.org/library/functions.html#range).
- _.range = function(start, stop, step) {
- if (arguments.length <= 1) {
- stop = start || 0;
- start = 0;
- }
- step = arguments[2] || 1;
-
- var length = Math.max(Math.ceil((stop - start) / step), 0);
- var idx = 0;
- var range = new Array(length);
-
- while(idx < length) {
- range[idx++] = start;
- start += step;
- }
-
- return range;
- };
-
- // Function (ahem) Functions
- // ------------------
-
- // Reusable constructor function for prototype setting.
- var ctor = function(){};
-
- // Create a function bound to a given object (assigning `this`, and arguments,
- // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
- // available.
- _.bind = function(func, context) {
- var args, bound;
- if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
- if (!_.isFunction(func)) throw new TypeError;
- args = slice.call(arguments, 2);
- return bound = function() {
- if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
- ctor.prototype = func.prototype;
- var self = new ctor;
- ctor.prototype = null;
- var result = func.apply(self, args.concat(slice.call(arguments)));
- if (Object(result) === result) return result;
- return self;
- };
- };
-
- // Partially apply a function by creating a version that has had some of its
- // arguments pre-filled, without changing its dynamic `this` context.
- _.partial = function(func) {
- var args = slice.call(arguments, 1);
- return function() {
- return func.apply(this, args.concat(slice.call(arguments)));
- };
- };
-
- // Bind all of an object's methods to that object. Useful for ensuring that
- // all callbacks defined on an object belong to it.
- _.bindAll = function(obj) {
- var funcs = slice.call(arguments, 1);
- if (funcs.length === 0) throw new Error("bindAll must be passed function names");
- each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
- return obj;
- };
-
- // Memoize an expensive function by storing its results.
- _.memoize = function(func, hasher) {
- var memo = {};
- hasher || (hasher = _.identity);
- return function() {
- var key = hasher.apply(this, arguments);
- return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
- };
- };
-
- // Delays a function for the given number of milliseconds, and then calls
- // it with the arguments supplied.
- _.delay = function(func, wait) {
- var args = slice.call(arguments, 2);
- return setTimeout(function(){ return func.apply(null, args); }, wait);
- };
-
- // Defers a function, scheduling it to run after the current call stack has
- // cleared.
- _.defer = function(func) {
- return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
- };
-
- // Returns a function, that, when invoked, will only be triggered at most once
- // during a given window of time. Normally, the throttled function will run
- // as much as it can, without ever going more than once per `wait` duration;
- // but if you'd like to disable the execution on the leading edge, pass
- // `{leading: false}`. To disable execution on the trailing edge, ditto.
- _.throttle = function(func, wait, options) {
- var context, args, result;
- var timeout = null;
- var previous = 0;
- options || (options = {});
- var later = function() {
- previous = options.leading === false ? 0 : new Date;
- timeout = null;
- result = func.apply(context, args);
- };
- return function() {
- var now = new Date;
- if (!previous && options.leading === false) previous = now;
- var remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0) {
- clearTimeout(timeout);
- timeout = null;
- previous = now;
- result = func.apply(context, args);
- } else if (!timeout && options.trailing !== false) {
- timeout = setTimeout(later, remaining);
- }
- return result;
- };
- };
-
- // Returns a function, that, as long as it continues to be invoked, will not
- // be triggered. The function will be called after it stops being called for
- // N milliseconds. If `immediate` is passed, trigger the function on the
- // leading edge, instead of the trailing.
- _.debounce = function(func, wait, immediate) {
- var timeout, args, context, timestamp, result;
- return function() {
- context = this;
- args = arguments;
- timestamp = new Date();
- var later = function() {
- var last = (new Date()) - timestamp;
- if (last < wait) {
- timeout = setTimeout(later, wait - last);
- } else {
- timeout = null;
- if (!immediate) result = func.apply(context, args);
- }
- };
- var callNow = immediate && !timeout;
- if (!timeout) {
- timeout = setTimeout(later, wait);
- }
- if (callNow) result = func.apply(context, args);
- return result;
- };
- };
-
- // Returns a function that will be executed at most one time, no matter how
- // often you call it. Useful for lazy initialization.
- _.once = function(func) {
- var ran = false, memo;
- return function() {
- if (ran) return memo;
- ran = true;
- memo = func.apply(this, arguments);
- func = null;
- return memo;
- };
- };
-
- // Returns the first function passed as an argument to the second,
- // allowing you to adjust arguments, run code before and after, and
- // conditionally execute the original function.
- _.wrap = function(func, wrapper) {
- return function() {
- var args = [func];
- push.apply(args, arguments);
- return wrapper.apply(this, args);
- };
- };
-
- // Returns a function that is the composition of a list of functions, each
- // consuming the return value of the function that follows.
- _.compose = function() {
- var funcs = arguments;
- return function() {
- var args = arguments;
- for (var i = funcs.length - 1; i >= 0; i--) {
- args = [funcs[i].apply(this, args)];
- }
- return args[0];
- };
- };
-
- // Returns a function that will only be executed after being called N times.
- _.after = function(times, func) {
- return function() {
- if (--times < 1) {
- return func.apply(this, arguments);
- }
- };
- };
-
- // Object Functions
- // ----------------
-
- // Retrieve the names of an object's properties.
- // Delegates to **ECMAScript 5**'s native `Object.keys`
- _.keys = nativeKeys || function(obj) {
- if (obj !== Object(obj)) throw new TypeError('Invalid object');
- var keys = [];
- for (var key in obj) if (_.has(obj, key)) keys.push(key);
- return keys;
- };
-
- // Retrieve the values of an object's properties.
- _.values = function(obj) {
- var keys = _.keys(obj);
- var length = keys.length;
- var values = new Array(length);
- for (var i = 0; i < length; i++) {
- values[i] = obj[keys[i]];
- }
- return values;
- };
-
- // Convert an object into a list of `[key, value]` pairs.
- _.pairs = function(obj) {
- var keys = _.keys(obj);
- var length = keys.length;
- var pairs = new Array(length);
- for (var i = 0; i < length; i++) {
- pairs[i] = [keys[i], obj[keys[i]]];
- }
- return pairs;
- };
-
- // Invert the keys and values of an object. The values must be serializable.
- _.invert = function(obj) {
- var result = {};
- var keys = _.keys(obj);
- for (var i = 0, length = keys.length; i < length; i++) {
- result[obj[keys[i]]] = keys[i];
- }
- return result;
- };
-
- // Return a sorted list of the function names available on the object.
- // Aliased as `methods`
- _.functions = _.methods = function(obj) {
- var names = [];
- for (var key in obj) {
- if (_.isFunction(obj[key])) names.push(key);
- }
- return names.sort();
- };
-
- // Extend a given object with all the properties in passed-in object(s).
- _.extend = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- obj[prop] = source[prop];
- }
- }
- });
- return obj;
- };
-
- // Return a copy of the object only containing the whitelisted properties.
- _.pick = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- each(keys, function(key) {
- if (key in obj) copy[key] = obj[key];
- });
- return copy;
- };
-
- // Return a copy of the object without the blacklisted properties.
- _.omit = function(obj) {
- var copy = {};
- var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
- for (var key in obj) {
- if (!_.contains(keys, key)) copy[key] = obj[key];
- }
- return copy;
- };
-
- // Fill in a given object with default properties.
- _.defaults = function(obj) {
- each(slice.call(arguments, 1), function(source) {
- if (source) {
- for (var prop in source) {
- if (obj[prop] === void 0) obj[prop] = source[prop];
- }
- }
- });
- return obj;
- };
-
- // Create a (shallow-cloned) duplicate of an object.
- _.clone = function(obj) {
- if (!_.isObject(obj)) return obj;
- return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
- };
-
- // Invokes interceptor with the obj, and then returns obj.
- // The primary purpose of this method is to "tap into" a method chain, in
- // order to perform operations on intermediate results within the chain.
- _.tap = function(obj, interceptor) {
- interceptor(obj);
- return obj;
- };
-
- // Internal recursive comparison function for `isEqual`.
- var eq = function(a, b, aStack, bStack) {
- // Identical objects are equal. `0 === -0`, but they aren't identical.
- // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
- if (a === b) return a !== 0 || 1 / a == 1 / b;
- // A strict comparison is necessary because `null == undefined`.
- if (a == null || b == null) return a === b;
- // Unwrap any wrapped objects.
- if (a instanceof _) a = a._wrapped;
- if (b instanceof _) b = b._wrapped;
- // Compare `[[Class]]` names.
- var className = toString.call(a);
- if (className != toString.call(b)) return false;
- switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
- case '[object String]':
- // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
- // equivalent to `new String("5")`.
- return a == String(b);
- case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
- case '[object Date]':
- case '[object Boolean]':
- // Coerce dates and booleans to numeric primitive values. Dates are compared by their
- // millisecond representations. Note that invalid dates with millisecond representations
- // of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
- }
- if (typeof a != 'object' || typeof b != 'object') return false;
- // Assume equality for cyclic structures. The algorithm for detecting cyclic
- // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
- var length = aStack.length;
- while (length--) {
- // Linear search. Performance is inversely proportional to the number of
- // unique nested structures.
- if (aStack[length] == a) return bStack[length] == b;
- }
- // Objects with different constructors are not equivalent, but `Object`s
- // from different frames are.
- var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
- _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
- return false;
- }
- // Add the first object to the stack of traversed objects.
- aStack.push(a);
- bStack.push(b);
- var size = 0, result = true;
- // Recursively compare objects and arrays.
- if (className == '[object Array]') {
- // Compare array lengths to determine if a deep comparison is necessary.
- size = a.length;
- result = size == b.length;
- if (result) {
- // Deep compare the contents, ignoring non-numeric properties.
- while (size--) {
- if (!(result = eq(a[size], b[size], aStack, bStack))) break;
- }
- }
- } else {
- // Deep compare objects.
- for (var key in a) {
- if (_.has(a, key)) {
- // Count the expected number of properties.
- size++;
- // Deep compare each member.
- if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
- }
- }
- // Ensure that both objects contain the same number of properties.
- if (result) {
- for (key in b) {
- if (_.has(b, key) && !(size--)) break;
- }
- result = !size;
- }
- }
- // Remove the first object from the stack of traversed objects.
- aStack.pop();
- bStack.pop();
- return result;
- };
-
- // Perform a deep comparison to check if two objects are equal.
- _.isEqual = function(a, b) {
- return eq(a, b, [], []);
- };
-
- // Is a given array, string, or object empty?
- // An "empty" object has no enumerable own-properties.
- _.isEmpty = function(obj) {
- if (obj == null) return true;
- if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
- for (var key in obj) if (_.has(obj, key)) return false;
- return true;
- };
-
- // Is a given value a DOM element?
- _.isElement = function(obj) {
- return !!(obj && obj.nodeType === 1);
- };
-
- // Is a given value an array?
- // Delegates to ECMA5's native Array.isArray
- _.isArray = nativeIsArray || function(obj) {
- return toString.call(obj) == '[object Array]';
- };
-
- // Is a given variable an object?
- _.isObject = function(obj) {
- return obj === Object(obj);
- };
-
- // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
- each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
- _['is' + name] = function(obj) {
- return toString.call(obj) == '[object ' + name + ']';
- };
- });
-
- // Define a fallback version of the method in browsers (ahem, IE), where
- // there isn't any inspectable "Arguments" type.
- if (!_.isArguments(arguments)) {
- _.isArguments = function(obj) {
- return !!(obj && _.has(obj, 'callee'));
- };
- }
-
- // Optimize `isFunction` if appropriate.
- if (typeof (/./) !== 'function') {
- _.isFunction = function(obj) {
- return typeof obj === 'function';
- };
- }
-
- // Is a given object a finite number?
- _.isFinite = function(obj) {
- return isFinite(obj) && !isNaN(parseFloat(obj));
- };
-
- // Is the given value `NaN`? (NaN is the only number which does not equal itself).
- _.isNaN = function(obj) {
- return _.isNumber(obj) && obj != +obj;
- };
-
- // Is a given value a boolean?
- _.isBoolean = function(obj) {
- return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
- };
-
- // Is a given value equal to null?
- _.isNull = function(obj) {
- return obj === null;
- };
-
- // Is a given variable undefined?
- _.isUndefined = function(obj) {
- return obj === void 0;
- };
-
- // Shortcut function for checking if an object has a given property directly
- // on itself (in other words, not on a prototype).
- _.has = function(obj, key) {
- return hasOwnProperty.call(obj, key);
- };
-
- // Utility Functions
- // -----------------
-
- // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
- // previous owner. Returns a reference to the Underscore object.
- _.noConflict = function() {
- root._ = previousUnderscore;
- return this;
- };
-
- // Keep the identity function around for default iterators.
- _.identity = function(value) {
- return value;
- };
-
- // Run a function **n** times.
- _.times = function(n, iterator, context) {
- var accum = Array(Math.max(0, n));
- for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
- return accum;
- };
-
- // Return a random integer between min and max (inclusive).
- _.random = function(min, max) {
- if (max == null) {
- max = min;
- min = 0;
- }
- return min + Math.floor(Math.random() * (max - min + 1));
- };
-
- // List of HTML entities for escaping.
- var entityMap = {
- escape: {
- '&': '&',
- '<': '<',
- '>': '>',
- '"': '"',
- "'": '''
- }
- };
- entityMap.unescape = _.invert(entityMap.escape);
-
- // Regexes containing the keys and values listed immediately above.
- var entityRegexes = {
- escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
- unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
- };
-
- // Functions for escaping and unescaping strings to/from HTML interpolation.
- _.each(['escape', 'unescape'], function(method) {
- _[method] = function(string) {
- if (string == null) return '';
- return ('' + string).replace(entityRegexes[method], function(match) {
- return entityMap[method][match];
- });
- };
- });
-
- // If the value of the named `property` is a function then invoke it with the
- // `object` as context; otherwise, return it.
- _.result = function(object, property) {
- if (object == null) return void 0;
- var value = object[property];
- return _.isFunction(value) ? value.call(object) : value;
- };
-
- // Add your own custom functions to the Underscore object.
- _.mixin = function(obj) {
- each(_.functions(obj), function(name) {
- var func = _[name] = obj[name];
- _.prototype[name] = function() {
- var args = [this._wrapped];
- push.apply(args, arguments);
- return result.call(this, func.apply(_, args));
- };
- });
- };
-
- // Generate a unique integer id (unique within the entire client session).
- // Useful for temporary DOM ids.
- var idCounter = 0;
- _.uniqueId = function(prefix) {
- var id = ++idCounter + '';
- return prefix ? prefix + id : id;
- };
-
- // By default, Underscore uses ERB-style template delimiters, change the
- // following template settings to use alternative delimiters.
- _.templateSettings = {
- evaluate : /<%([\s\S]+?)%>/g,
- interpolate : /<%=([\s\S]+?)%>/g,
- escape : /<%-([\s\S]+?)%>/g
- };
-
- // When customizing `templateSettings`, if you don't want to define an
- // interpolation, evaluation or escaping regex, we need one that is
- // guaranteed not to match.
- var noMatch = /(.)^/;
-
- // Certain characters need to be escaped so that they can be put into a
- // string literal.
- var escapes = {
- "'": "'",
- '\\': '\\',
- '\r': 'r',
- '\n': 'n',
- '\t': 't',
- '\u2028': 'u2028',
- '\u2029': 'u2029'
- };
-
- var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
-
- // JavaScript micro-templating, similar to John Resig's implementation.
- // Underscore templating handles arbitrary delimiters, preserves whitespace,
- // and correctly escapes quotes within interpolated code.
- _.template = function(text, data, settings) {
- var render;
- settings = _.defaults({}, settings, _.templateSettings);
-
- // Combine delimiters into one regular expression via alternation.
- var matcher = new RegExp([
- (settings.escape || noMatch).source,
- (settings.interpolate || noMatch).source,
- (settings.evaluate || noMatch).source
- ].join('|') + '|$', 'g');
-
- // Compile the template source, escaping string literals appropriately.
- var index = 0;
- var source = "__p+='";
- text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
- source += text.slice(index, offset)
- .replace(escaper, function(match) { return '\\' + escapes[match]; });
-
- if (escape) {
- source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
- }
- if (interpolate) {
- source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
- }
- if (evaluate) {
- source += "';\n" + evaluate + "\n__p+='";
- }
- index = offset + match.length;
- return match;
- });
- source += "';\n";
-
- // If a variable is not specified, place data values in local scope.
- if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
-
- source = "var __t,__p='',__j=Array.prototype.join," +
- "print=function(){__p+=__j.call(arguments,'');};\n" +
- source + "return __p;\n";
-
- try {
- render = new Function(settings.variable || 'obj', '_', source);
- } catch (e) {
- e.source = source;
- throw e;
- }
-
- if (data) return render(data, _);
- var template = function(data) {
- return render.call(this, data, _);
- };
-
- // Provide the compiled function source as a convenience for precompilation.
- template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
-
- return template;
- };
-
- // Add a "chain" function, which will delegate to the wrapper.
- _.chain = function(obj) {
- return _(obj).chain();
- };
-
- // OOP
- // ---------------
- // If Underscore is called as a function, it returns a wrapped object that
- // can be used OO-style. This wrapper holds altered versions of all the
- // underscore functions. Wrapped objects may be chained.
-
- // Helper function to continue chaining intermediate results.
- var result = function(obj) {
- return this._chain ? _(obj).chain() : obj;
- };
-
- // Add all of the Underscore functions to the wrapper object.
- _.mixin(_);
-
- // Add all mutator Array functions to the wrapper.
- each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
- var method = ArrayProto[name];
- _.prototype[name] = function() {
- var obj = this._wrapped;
- method.apply(obj, arguments);
- if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
- return result.call(this, obj);
- };
- });
-
- // Add all accessor Array functions to the wrapper.
- each(['concat', 'join', 'slice'], function(name) {
- var method = ArrayProto[name];
- _.prototype[name] = function() {
- return result.call(this, method.apply(this._wrapped, arguments));
- };
- });
-
- _.extend(_.prototype, {
-
- // Start chaining a wrapped Underscore object.
- chain: function() {
- this._chain = true;
- return this;
- },
-
- // Extracts the result from a wrapped and chained object.
- value: function() {
- return this._wrapped;
- }
-
- });
-
-}).call(this);
deleted file mode 100644
index da1ed9f2c90797cd9cbd5739247d23d93f617816..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
--- a/js/src/jsapi-tests/binast/parser/tester/frameworks/yui-3.12.js
+++ /dev/null
@@ -1,11542 +0,0 @@
-/*
-YUI 3.12.0 (build 8655935)
-Copyright 2013 Yahoo! Inc. All rights reserved.
-Licensed under the BSD License.
-http://yuilibrary.com/license/
-*/
-
-/**
-The YUI module contains the components required for building the YUI seed file.
-This includes the script loading mechanism, a simple queue, and the core
-utilities for the library.
-
-@module yui
-@main yui
-@submodule yui-base
-**/
-
-/*jshint eqeqeq: false*/
-if (typeof YUI != 'undefined') {
- YUI._YUI = YUI;
-}
-
-/**
-The YUI global namespace object. This is the constructor for all YUI instances.
-
-This is a self-instantiable factory function, meaning you don't need to precede
-it with the `new` operator. You can invoke it directly like this:
-
- YUI().use('*', function (Y) {
- // Y is a new YUI instance.
- });
-
-But it also works like this:
-
- var Y = YUI();
-
-The `YUI` constructor accepts an optional config object, like this:
-
- YUI({
- debug: true,
- combine: false
- }).use('node', function (Y) {
- // Y.Node is ready to use.
- });
-
-See the API docs for the <a href="config.html">Config</a> class for the complete
-list of supported configuration properties accepted by the YUI constuctor.
-
-If a global `YUI` object is already defined, the existing YUI object will not be
-overwritten, to ensure that defined namespaces are preserved.
-
-Each YUI instance has full custom event support, but only if the event system is
-available.
-
-@class YUI
-@uses EventTarget
-@constructor
-@global
-@param {Object} [config]* Zero or more optional configuration objects. Config
- values are stored in the `Y.config` property. See the
- <a href="config.html">Config</a> docs for the list of supported properties.
-**/
-
- /*global YUI*/
- /*global YUI_config*/
- var YUI = function() {
- var i = 0,
- Y = this,
- args = arguments,
- l = args.length,
- instanceOf = function(o, type) {
- return (o && o.hasOwnProperty && (o instanceof type));
- },
- gconf = (typeof YUI_config !== 'undefined') && YUI_config;
-
- if (!(instanceOf(Y, YUI))) {
- Y = new YUI();
- } else {
- // set up the core environment
- Y._init();
-
- /**
- Master configuration that might span multiple contexts in a non-
- browser environment. It is applied first to all instances in all
- contexts.
-
- @example
-
- YUI.GlobalConfig = {
- filter: 'debug'
- };
-
- YUI().use('node', function (Y) {
- // debug files used here
- });
-
- YUI({
- filter: 'min'
- }).use('node', function (Y) {
- // min files used here
- });
-
- @property {Object} GlobalConfig
- @global
- @static
- **/
- if (YUI.GlobalConfig) {
- Y.applyConfig(YUI.GlobalConfig);
- }
-
- /**
- Page-level config applied to all YUI instances created on the
- current page. This is applied after `YUI.GlobalConfig` and before
- any instance-level configuration.
-
- @example
-
- // Single global var to include before YUI seed file
- YUI_config = {
- filter: 'debug'
- };
-
- YUI().use('node', function (Y) {
- // debug files used here
- });
-
- YUI({
- filter: 'min'
- }).use('node', function (Y) {
- // min files used here
- });
-
- @property {Object} YUI_config
- @global
- **/
- if (gconf) {
- Y.applyConfig(gconf);
- }
-
- // bind the specified additional modules for this instance
- if (!l) {
- Y._setup();
- }
- }
-
- if (l) {
- // Each instance can accept one or more configuration objects.
- // These are applied after YUI.GlobalConfig and YUI_Config,
- // overriding values set in those config files if there is a
- // matching property.
- for (; i < l; i++) {
- Y.applyConfig(args[i]);
- }
-
- Y._setup();
- }
-
- Y.instanceOf = instanceOf;
-
- return Y;
- };
-
-(function() {
-
- var proto, prop,
- VERSION = '3.12.0',
- PERIOD = '.',
- BASE = 'http://yui.yahooapis.com/',
- /*
- These CSS class names can't be generated by
- getClassName since it is not available at the
- time they are being used.
- */
- DOC_LABEL = 'yui3-js-enabled',
- CSS_STAMP_EL = 'yui3-css-stamp',
- NOOP = function() {},
- SLICE = Array.prototype.slice,
- APPLY_TO_AUTH = { 'io.xdrReady': 1, // the functions applyTo
- 'io.xdrResponse': 1, // can call. this should
- 'SWF.eventHandler': 1 }, // be done at build time
- hasWin = (typeof window != 'undefined'),
- win = (hasWin) ? window : null,
- doc = (hasWin) ? win.document : null,
- docEl = doc && doc.documentElement,
- docClass = docEl && docEl.className,
- instances = {},
- time = new Date().getTime(),
- add = function(el, type, fn, capture) {
- if (el && el.addEventListener) {
- el.addEventListener(type, fn, capture);
- } else if (el && el.attachEvent) {
- el.attachEvent('on' + type, fn);
- }
- },
- remove = function(el, type, fn, capture) {
- if (el && el.removeEventListener) {
- // this can throw an uncaught exception in FF
- try {
- el.removeEventListener(type, fn, capture);
- } catch (ex) {}
- } else if (el && el.detachEvent) {
- el.detachEvent('on' + type, fn);
- }
- },
- handleLoad = function() {
- YUI.Env.windowLoaded = true;
- YUI.Env.DOMReady = true;
- if (hasWin) {
- remove(window, 'load', handleLoad);
- }
- },
- getLoader = function(Y, o) {
- var loader = Y.Env._loader,
- lCore = [ 'loader-base' ],
- G_ENV = YUI.Env,
- mods = G_ENV.mods;
-
- if (loader) {
- //loader._config(Y.config);
- loader.ignoreRegistered = false;
- loader.onEnd = null;
- loader.data = null;
- loader.required = [];
- loader.loadType = null;
- } else {
- loader = new Y.Loader(Y.config);
- Y.Env._loader = loader;
- }
- if (mods && mods.loader) {
- lCore = [].concat(lCore, YUI.Env.loaderExtras);
- }
- YUI.Env.core = Y.Array.dedupe([].concat(YUI.Env.core, lCore));
-
- return loader;
- },
-
- clobber = function(r, s) {
- for (var i in s) {
- if (s.hasOwnProperty(i)) {
- r[i] = s[i];
- }
- }
- },
-
- ALREADY_DONE = { success: true };
-
-// Stamp the documentElement (HTML) with a class of "yui-loaded" to
-// enable styles that need to key off of JS being enabled.
-if (docEl && docClass.indexOf(DOC_LABEL) == -1) {
- if (docClass) {
- docClass += ' ';
- }
- docClass += DOC_LABEL;
- docEl.className = docClass;
-}
-
-if (VERSION.indexOf('@') > -1) {
- VERSION = '3.5.0'; // dev time hack for cdn test
-}
-
-proto = {
- /**
- Applies a new configuration object to the config of this YUI instance. This
- will merge new group/module definitions, and will also update the loader
- cache if necessary. Updating `Y.config` directly will not update the cache.
-
- @method applyConfig
- @param {Object} o the configuration object.
- @since 3.2.0
- **/
- applyConfig: function(o) {
-
- o = o || NOOP;
-
- var attr,
- name,
- // detail,
- config = this.config,
- mods = config.modules,
- groups = config.groups,
- aliases = config.aliases,
- loader = this.Env._loader;
-
- for (name in o) {
- if (o.hasOwnProperty(name)) {
- attr = o[name];
- if (mods && name == 'modules') {
- clobber(mods, attr);
- } else if (aliases && name == 'aliases') {
- clobber(aliases, attr);
- } else if (groups && name == 'groups') {
- clobber(groups, attr);
- } else if (name == 'win') {
- config[name] = (attr && attr.contentWindow) || attr;
- config.doc = config[name] ? config[name].document : null;
- } else if (name == '_yuid') {
- // preserve the guid
- } else {
- config[name] = attr;
- }
- }
- }
-
- if (loader) {
- loader._config(o);
- }
-
- },
-
- /**
- Old way to apply a config to this instance (calls `applyConfig` under the
- hood).
-
- @private
- @method _config
- @param {Object} o The config to apply
- **/
- _config: function(o) {
- this.applyConfig(o);
- },
-
- /**
- Initializes this YUI instance.
-
- @private
- @method _init
- **/
- _init: function() {
- var filter, el,
- Y = this,
- G_ENV = YUI.Env,
- Env = Y.Env,
- prop;
-
- /**
- The version number of this YUI instance.
-
- This value is typically updated by a script when a YUI release is built,
- so it may not reflect the correct version number when YUI is run from
- the development source tree.
-
- @property {String} version
- **/
- Y.version = VERSION;
-
- if (!Env) {
- Y.Env = {
- core: ['get', 'features', 'intl-base', 'yui-log', 'yui-later', 'loader-base', 'loader-rollup', 'loader-yui3'],
- loaderExtras: ['loader-rollup', 'loader-yui3'],
- mods: {}, // flat module map
- versions: {}, // version module map
- base: BASE,
- cdn: BASE + VERSION + '/build/',
- // bootstrapped: false,
- _idx: 0,
- _used: {},
- _attached: {},
- _missed: [],
- _yidx: 0,
- _uidx: 0,
- _guidp: 'y',
- _loaded: {},
- // serviced: {},
- // Regex in English:
- // I'll start at the \b(simpleyui).
- // 1. Look in the test string for "simpleyui" or "yui" or
- // "yui-base" or "yui-davglass" or "yui-foobar" that comes after a word break. That is, it
- // can't match "foyui" or "i_heart_simpleyui". This can be anywhere in the string.
- // 2. After #1 must come a forward slash followed by the string matched in #1, so
- // "yui-base/yui-base" or "simpleyui/simpleyui" or "yui-pants/yui-pants".
- // 3. The second occurence of the #1 token can optionally be followed by "-debug" or "-min",
- // so "yui/yui-min", "yui/yui-debug", "yui-base/yui-base-debug". NOT "yui/yui-tshirt".
- // 4. This is followed by ".js", so "yui/yui.js", "simpleyui/simpleyui-min.js"
- // 0. Going back to the beginning, now. If all that stuff in 1-4 comes after a "?" in the string,
- // then capture the junk between the LAST "&" and the string in 1-4. So
- // "blah?foo/yui/yui.js" will capture "foo/" and "blah?some/thing.js&3.3.0/build/yui-davglass/yui-davglass.js"
- // will capture "3.3.0/build/"
- //
- // Regex Exploded:
- // (?:\? Find a ?
- // (?:[^&]*&) followed by 0..n characters followed by an &
- // * in fact, find as many sets of characters followed by a & as you can
- // ([^&]*) capture the stuff after the last & in \1
- // )? but it's ok if all this ?junk&more_junk stuff isn't even there
- // \b(simpleyui| after a word break find either the string "simpleyui" or
- // yui(?:-\w+)? the string "yui" optionally followed by a -, then more characters
- // ) and store the simpleyui or yui-* string in \2
- // \/\2 then comes a / followed by the simpleyui or yui-* string in \2
- // (?:-(min|debug))? optionally followed by "-min" or "-debug"
- // .js and ending in ".js"
- _BASE_RE: /(?:\?(?:[^&]*&)*([^&]*))?\b(simpleyui|yui(?:-\w+)?)\/\2(?:-(min|debug))?\.js/,
- parseBasePath: function(src, pattern) {
- var match = src.match(pattern),
- path, filter;
-
- if (match) {
- path = RegExp.leftContext || src.slice(0, src.indexOf(match[0]));
-
- // this is to set up the path to the loader. The file
- // filter for loader should match the yui include.
- filter = match[3];
-
- // extract correct path for mixed combo urls
- // http://yuilibrary.com/projects/yui3/ticket/2528423
- if (match[1]) {
- path += '?' + match[1];
- }
- path = {
- filter: filter,
- path: path
- };
- }
- return path;
- },
- getBase: G_ENV && G_ENV.getBase ||
- function(pattern) {
- var nodes = (doc && doc.getElementsByTagName('script')) || [],
- path = Env.cdn, parsed,
- i, len, src;
-
- for (i = 0, len = nodes.length; i < len; ++i) {
- src = nodes[i].src;
- if (src) {
- parsed = Y.Env.parseBasePath(src, pattern);
- if (parsed) {
- filter = parsed.filter;
- path = parsed.path;
- break;
- }
- }
- }
-
- // use CDN default
- return path;
- }
-
- };
-
- Env = Y.Env;
-
- Env._loaded[VERSION] = {};
-
- if (G_ENV && Y !== YUI) {
- Env._yidx = ++G_ENV._yidx;
- Env._guidp = ('yui_' + VERSION + '_' +
- Env._yidx + '_' + time).replace(/[^a-z0-9_]+/g, '_');
- } else if (YUI._YUI) {
-
- G_ENV = YUI._YUI.Env;
- Env._yidx += G_ENV._yidx;
- Env._uidx += G_ENV._uidx;
-
- for (prop in G_ENV) {
- if (!(prop in Env)) {
- Env[prop] = G_ENV[prop];
- }
- }
-
- delete YUI._YUI;
- }
-
- Y.id = Y.stamp(Y);
- instances[Y.id] = Y;
-
- }
-
- Y.constructor = YUI;
-
- // configuration defaults
- Y.config = Y.config || {
- bootstrap: true,
- cacheUse: true,
- debug: true,
- doc: doc,
- fetchCSS: true,
- throwFail: true,
- useBrowserConsole: true,
- useNativeES5: true,
- win: win,
- global: Function('return this')()
- };
-
- //Register the CSS stamp element
- if (doc && !doc.getElementById(CSS_STAMP_EL)) {
- el = doc.createElement('div');
- el.innerHTML = '<div id="' + CSS_STAMP_EL + '" style="position: absolute !important; visibility: hidden !important"></div>';
- YUI.Env.cssStampEl = el.firstChild;
- if (doc.body) {
- doc.body.appendChild(YUI.Env.cssStampEl);
- } else {
- docEl.insertBefore(YUI.Env.cssStampEl, docEl.firstChild);
- }
- } else if (doc && doc.getElementById(CSS_STAMP_EL) && !YUI.Env.cssStampEl) {
- YUI.Env.cssStampEl = doc.getElementById(CSS_STAMP_EL);
- }
-
- Y.config.lang = Y.config.lang || 'en-US';
-
- Y.config.base = YUI.config.base || Y.Env.getBase(Y.Env._BASE_RE);
-
- if (!filter || (!('mindebug').indexOf(filter))) {
- filter = 'min';
- }
- filter = (filter) ? '-' + filter : filter;
- Y.config.loaderPath = YUI.config.loaderPath || 'loader/loader' + filter + '.js';
-
- },
-
- /**
- Finishes the instance setup. Attaches whatever YUI modules were defined
- at the time that this instance was created.
-
- @method _setup
- @private
- **/
- _setup: function() {
- var i, Y = this,
- core = [],
- mods = YUI.Env.mods,
- extras = Y.config.core || [].concat(YUI.Env.core); //Clone it..
-
- for (i = 0; i < extras.length; i++) {
- if (mods[extras[i]]) {
- core.push(extras[i]);
- }
- }
-
- Y._attach(['yui-base']);
- Y._attach(core);
-
- if (Y.Loader) {
- getLoader(Y);
- }
-
- },
-
- /**
- Executes the named method on the specified YUI instance if that method is
- whitelisted.
-
- @method applyTo
- @param {String} id YUI instance id.
- @param {String} method Name of the method to execute. For example:
- 'Object.keys'.
- @param {Array} args Arguments to apply to the method.
- @return {Mixed} Return value from the applied method, or `null` if the
- specified instance was not found or the method was not whitelisted.
- **/
- applyTo: function(id, method, args) {
- if (!(method in APPLY_TO_AUTH)) {
- this.log(method + ': applyTo not allowed', 'warn', 'yui');
- return null;
- }
-
- var instance = instances[id], nest, m, i;
- if (instance) {
- nest = method.split('.');
- m = instance;
- for (i = 0; i < nest.length; i = i + 1) {
- m = m[nest[i]];
- if (!m) {
- this.log('applyTo not found: ' + method, 'warn', 'yui');
- }
- }
- return m && m.apply(instance, args);
- }
-
- return null;
- },
-
-/**
-Registers a YUI module and makes it available for use in a `YUI().use()` call or
-as a dependency for other modules.
-
-The easiest way to create a first-class YUI module is to use
-<a href="http://yui.github.com/shifter/">Shifter</a>, the YUI component build
-tool.
-
-Shifter will automatically wrap your module code in a `YUI.add()` call along
-with any configuration info required for the module.
-
-@example
-
- YUI.add('davglass', function (Y) {
- Y.davglass = function () {
- };
- }, '3.4.0', {
- requires: ['harley-davidson', 'mt-dew']
- });
-
-@method add
-@param {String} name Module name.
-@param {Function} fn Function containing module code. This function will be
- executed whenever the module is attached to a specific YUI instance.
-
- @param {YUI} fn.Y The YUI instance to which this module is attached.
- @param {String} fn.name Name of the module
-
-@param {String} version Module version number. This is currently used only for
- informational purposes, and is not used internally by YUI.
-
-@param {Object} [config] Module config.
- @param {Array} [config.requires] Array of other module names that must be
- attached before this module can be attached.
- @param {Array} [config.optional] Array of optional module names that should
- be attached before this module is attached if they've already been
- loaded. If the `loadOptional` YUI option is `true`, optional modules
- that have not yet been loaded will be loaded just as if they were hard
- requirements.
- @param {Array} [config.use] Array of module names that are included within
- or otherwise provided by this module, and which should be attached
- automatically when this module is attached. This makes it possible to
- create "virtual rollup" modules that simply attach a collection of other
- modules or submodules.
-
-@return {YUI} This YUI instance.
-**/
- add: function(name, fn, version, details) {
- details = details || {};
- var env = YUI.Env,
- mod = {
- name: name,
- fn: fn,
- version: version,
- details: details
- },
- //Instance hash so we don't apply it to the same instance twice
- applied = {},
- loader, inst,
- i, versions = env.versions;
-
- env.mods[name] = mod;
- versions[version] = versions[version] || {};
- versions[version][name] = mod;
-
- for (i in instances) {
- if (instances.hasOwnProperty(i)) {
- inst = instances[i];
- if (!applied[inst.id]) {
- applied[inst.id] = true;
- loader = inst.Env._loader;
- if (loader) {
- if (!loader.moduleInfo[name] || loader.moduleInfo[name].temp) {
- loader.addModule(details, name);
- }
- }
- }
- }
- }
-
- return this;
- },
-
- /**
- Executes the callback function associated with each required module,
- attaching the module to this YUI instance.
-
- @method _attach
- @param {Array} r The array of modules to attach
- @param {Boolean} [moot=false] If `true`, don't throw a warning if the module
- is not attached.
- @private
- **/
- _attach: function(r, moot) {
- var i, name, mod, details, req, use, after,
- mods = YUI.Env.mods,
- aliases = YUI.Env.aliases,
- Y = this, j,
- cache = YUI.Env._renderedMods,
- loader = Y.Env._loader,
- done = Y.Env._attached,
- len = r.length, loader, def, go,
- c = [];
-
- //Check for conditional modules (in a second+ instance) and add their requirements
- //TODO I hate this entire method, it needs to be fixed ASAP (3.5.0) ^davglass
- for (i = 0; i < len; i++) {
- name = r[i];
- mod = mods[name];
- c.push(name);
- if (loader && loader.conditions[name]) {
- for (j in loader.conditions[name]) {
- if (loader.conditions[name].hasOwnProperty(j)) {
- def = loader.conditions[name][j];
- go = def && ((def.ua && Y.UA[def.ua]) || (def.test && def.test(Y)));
- if (go) {
- c.push(def.name);
- }
- }
- }
- }
- }
- r = c;
- len = r.length;
-
- for (i = 0; i < len; i++) {
- if (!done[r[i]]) {
- name = r[i];
- mod = mods[name];
-
- if (aliases && aliases[name] && !mod) {
- Y._attach(aliases[name]);
- continue;
- }
- if (!mod) {
- if (loader && loader.moduleInfo[name]) {
- mod = loader.moduleInfo[name];
- moot = true;
- }
-
-
- //if (!loader || !loader.moduleInfo[name]) {
- //if ((!loader || !loader.moduleInfo[name]) && !moot) {
- if (!moot && name) {
- if ((name.indexOf('skin-') === -1) && (name.indexOf('css') === -1)) {
- Y.Env._missed.push(name);
- Y.Env._missed = Y.Array.dedupe(Y.Env._missed);
- Y.message('NOT loaded: ' + name, 'warn', 'yui');
- }
- }
- } else {
- done[name] = true;
- //Don't like this, but in case a mod was asked for once, then we fetch it
- //We need to remove it from the missed list ^davglass
- for (j = 0; j < Y.Env._missed.length; j++) {
- if (Y.Env._missed[j] === name) {
- Y.message('Found: ' + name + ' (was reported as missing earlier)', 'warn', 'yui');
- Y.Env._missed.splice(j, 1);
- }
- }
- /*
- If it's a temp module, we need to redo it's requirements if it's already loaded
- since it may have been loaded by another instance and it's dependencies might
- have been redefined inside the fetched file.
- */
- if (loader && cache && cache[name] && cache[name].temp) {
- loader.getRequires(cache[name]);
- req = [];
- for (j in loader.moduleInfo[name].expanded_map) {
- if (loader.moduleInfo[name].expanded_map.hasOwnProperty(j)) {
- req.push(j);
- }
- }
- Y._attach(req);
- }
-
- details = mod.details;
- req = details.requires;
- use = details.use;
- after = details.after;
- //Force Intl load if there is a language (Loader logic) @todo fix this shit
- if (details.lang) {
- req = req || [];
- req.unshift('intl');
- }
-
- if (req) {
- for (j = 0; j < req.length; j++) {
- if (!done[req[j]]) {
- if (!Y._attach(req)) {
- return false;
- }
- break;
- }
- }
- }
-
- if (after) {
- for (j = 0; j < after.length; j++) {
- if (!done[after[j]]) {
- if (!Y._attach(after, true)) {
- return false;
- }
- break;
- }
- }
- }
-
- if (mod.fn) {
- if (Y.config.throwFail) {
- mod.fn(Y, name);
- } else {
- try {
- mod.fn(Y, name);
- } catch (e) {
- Y.error('Attach error: ' + name, e, name);
- return false;
- }
- }
- }
-
- if (use) {
- for (j = 0; j < use.length; j++) {
- if (!done[use[j]]) {
- if (!Y._attach(use)) {
- return false;
- }
- break;
- }
- }
- }
-
-
-
- }
- }
- }
-
- return true;
- },
-
- /**
- Delays the `use` callback until another event has taken place such as
- `window.onload`, `domready`, `contentready`, or `available`.
-
- @private
- @method _delayCallback
- @param {Function} cb The original `use` callback.
- @param {String|Object} until Either an event name ('load', 'domready', etc.)
- or an object containing event/args keys for contentready/available.
- @return {Function}
- **/
- _delayCallback: function(cb, until) {
-
- var Y = this,
- mod = ['event-base'];
-
- until = (Y.Lang.isObject(until) ? until : { event: until });
-
- if (until.event === 'load') {
- mod.push('event-synthetic');
- }
-
- return function() {
- var args = arguments;
- Y._use(mod, function() {
- Y.on(until.event, function() {
- args[1].delayUntil = until.event;
- cb.apply(Y, args);
- }, until.args);
- });
- };
- },
-
- /**
- Attaches one or more modules to this YUI instance. When this is executed,
- the requirements of the desired modules are analyzed, and one of several
- things can happen:
-
-
- * All required modules have already been loaded, and just need to be
- attached to this YUI instance. In this case, the `use()` callback will
- be executed synchronously after the modules are attached.
-
- * One or more modules have not yet been loaded, or the Get utility is not
- available, or the `bootstrap` config option is `false`. In this case,
- a warning is issued indicating that modules are missing, but all
- available modules will still be attached and the `use()` callback will
- be executed synchronously.
-
- * One or more modules are missing and the Loader is not available but the
- Get utility is, and `bootstrap` is not `false`. In this case, the Get
- utility will be used to load the Loader, and we will then proceed to
- the following state:
-
- * One or more modules are missing and the Loader is available. In this
- case, the Loader will be used to resolve the dependency tree for the
- missing modules and load them and their dependencies. When the Loader is
- finished loading modules, the `use()` callback will be executed
- asynchronously.
-
- @example
-
- // Loads and attaches dd and its dependencies.
- YUI().use('dd', function (Y) {
- // ...
- });
-
- // Loads and attaches dd and node as well as all of their dependencies.
- YUI().use(['dd', 'node'], function (Y) {
- // ...
- });
-
- // Attaches all modules that have already been loaded.
- YUI().use('*', function (Y) {
- // ...
- });
-
- // Attaches a gallery module.
- YUI().use('gallery-yql', function (Y) {
- // ...
- });
-
- // Attaches a YUI 2in3 module.
- YUI().use('yui2-datatable', function (Y) {
- // ...
- });
-
- @method use
- @param {String|Array} modules* One or more module names to attach.
- @param {Function} [callback] Callback function to be executed once all
- specified modules and their dependencies have been attached.
- @param {YUI} callback.Y The YUI instance created for this sandbox.
- @param {Object} callback.status Object containing `success`, `msg` and
- `data` properties.
- @chainable
- **/
- use: function() {
- var args = SLICE.call(arguments, 0),
- callback = args[args.length - 1],
- Y = this,
- i = 0,
- name,
- Env = Y.Env,
- provisioned = true;
-
- // The last argument supplied to use can be a load complete callback
- if (Y.Lang.isFunction(callback)) {
- args.pop();
- if (Y.config.delayUntil) {
- callback = Y._delayCallback(callback, Y.config.delayUntil);
- }
- } else {
- callback = null;
- }
- if (Y.Lang.isArray(args[0])) {
- args = args[0];
- }
-
- if (Y.config.cacheUse) {
- while ((name = args[i++])) {
- if (!Env._attached[name]) {
- provisioned = false;
- break;
- }
- }
-
- if (provisioned) {
- if (args.length) {
- }
- Y._notify(callback, ALREADY_DONE, args);
- return Y;
- }
- }
-
- if (Y._loading) {
- Y._useQueue = Y._useQueue || new Y.Queue();
- Y._useQueue.add([args, callback]);
- } else {
- Y._use(args, function(Y, response) {
- Y._notify(callback, response, args);
- });
- }
-
- return Y;
- },
-
- /**
- Handles Loader notifications about attachment/load errors.
-
- @method _notify
- @param {Function} callback Callback to pass to `Y.config.loadErrorFn`.
- @param {Object} response Response returned from Loader.
- @param {Array} args Arguments passed from Loader.
- @private
- **/
- _notify: function(callback, response, args) {
- if (!response.success && this.config.loadErrorFn) {
- this.config.loadErrorFn.call(this, this, callback, response, args);
- } else if (callback) {
- if (this.Env._missed && this.Env._missed.length) {
- response.msg = 'Missing modules: ' + this.Env._missed.join();
- response.success = false;
- }
- if (this.config.throwFail) {
- callback(this, response);
- } else {
- try {
- callback(this, response);
- } catch (e) {
- this.error('use callback error', e, args);
- }
- }
- }
- },
-
- /**
- Called from the `use` method queue to ensure that only one set of loading
- logic is performed at a time.
-
- @method _use
- @param {String} args* One or more modules to attach.
- @param {Function} [callback] Function to call once all required modules have
- been attached.
- @private
- **/
- _use: function(args, callback) {
-
- if (!this.Array) {
- this._attach(['yui-base']);
- }
-
- var len, loader, handleBoot,
- Y = this,
- G_ENV = YUI.Env,
- mods = G_ENV.mods,
- Env = Y.Env,
- used = Env._used,
- aliases = G_ENV.aliases,
- queue = G_ENV._loaderQueue,
- firstArg = args[0],
- YArray = Y.Array,
- config = Y.config,
- boot = config.bootstrap,
- missing = [],
- i,
- r = [],
- ret = true,
- fetchCSS = config.fetchCSS,
- process = function(names, skip) {
-
- var i = 0, a = [], name, len, m, req, use;
-
- if (!names.length) {
- return;
- }
-
- if (aliases) {
- len = names.length;
- for (i = 0; i < len; i++) {
- if (aliases[names[i]] && !mods[names[i]]) {
- a = [].concat(a, aliases[names[i]]);
- } else {
- a.push(names[i]);
- }
- }
- names = a;
- }
-
- len = names.length;
-
- for (i = 0; i < len; i++) {
- name = names[i];
- if (!skip) {
- r.push(name);
- }
-
- // only attach a module once
- if (used[name]) {
- continue;
- }
-
- m = mods[name];
- req = null;
- use = null;
-
- if (m) {
- used[name] = true;
- req = m.details.requires;
- use = m.details.use;
- } else {
- // CSS files don't register themselves, see if it has
- // been loaded
- if (!G_ENV._loaded[VERSION][name]) {
- missing.push(name);
- } else {
- used[name] = true; // probably css
- }
- }
-
- // make sure requirements are attached
- if (req && req.length) {
- process(req);
- }
-
- // make sure we grab the submodule dependencies too
- if (use && use.length) {
- process(use, 1);
- }
- }
-
- },
-
- handleLoader = function(fromLoader) {
- var response = fromLoader || {
- success: true,
- msg: 'not dynamic'
- },
- redo, origMissing,
- ret = true,
- data = response.data;
-
- Y._loading = false;
-
- if (data) {
- origMissing = missing;
- missing = [];
- r = [];
- process(data);
- redo = missing.length;
- if (redo) {
- if ([].concat(missing).sort().join() ==
- origMissing.sort().join()) {
- redo = false;
- }
- }
- }
-
- if (redo && data) {
- Y._loading = true;
- Y._use(missing, function() {
- if (Y._attach(data)) {
- Y._notify(callback, response, data);
- }
- });
- } else {
- if (data) {
- ret = Y._attach(data);
- }
- if (ret) {
- Y._notify(callback, response, args);
- }
- }
-
- if (Y._useQueue && Y._useQueue.size() && !Y._loading) {
- Y._use.apply(Y, Y._useQueue.next());
- }
-
- };
-
-
- // YUI().use('*'); // bind everything available
- if (firstArg === '*') {
- args = [];
- for (i in mods) {
- if (mods.hasOwnProperty(i)) {
- args.push(i);
- }
- }
- ret = Y._attach(args);
- if (ret) {
- handleLoader();
- }
- return Y;
- }
-
- if ((mods.loader || mods['loader-base']) && !Y.Loader) {
- Y._attach(['loader' + ((!mods.loader) ? '-base' : '')]);
- }
-
-
- // use loader to expand dependencies and sort the
- // requirements if it is available.
- if (boot && Y.Loader && args.length) {
- loader = getLoader(Y);
- loader.require(args);
- loader.ignoreRegistered = true;
- loader._boot = true;
- loader.calculate(null, (fetchCSS) ? null : 'js');
- args = loader.sorted;
- loader._boot = false;
- }
-
- process(args);
-
- len = missing.length;
-
-
- if (len) {
- missing = YArray.dedupe(missing);
- len = missing.length;
- }
-
-
- // dynamic load
- if (boot && len && Y.Loader) {
- Y._loading = true;
- loader = getLoader(Y);
- loader.onEnd = handleLoader;
- loader.context = Y;
- loader.data = args;
- loader.ignoreRegistered = false;
- loader.require(missing);
- loader.insert(null, (fetchCSS) ? null : 'js');
-
- } else if (boot && len && Y.Get && !Env.bootstrapped) {
-
- Y._loading = true;
-
- handleBoot = function() {
- Y._loading = false;
- queue.running = false;
- Env.bootstrapped = true;
- G_ENV._bootstrapping = false;
- if (Y._attach(['loader'])) {
- Y._use(args, callback);
- }
- };
-
- if (G_ENV._bootstrapping) {
- queue.add(handleBoot);
- } else {
- G_ENV._bootstrapping = true;
- Y.Get.script(config.base + config.loaderPath, {
- onEnd: handleBoot
- });
- }
-
- } else {
- ret = Y._attach(args);
- if (ret) {
- handleLoader();
- }
- }
-
- return Y;
- },
-
-
- /**
- Utility method for safely creating namespaces if they don't already exist.
- May be called statically on the YUI global object or as a method on a YUI
- instance.
-
- When called statically, a namespace will be created on the YUI global
- object:
-
- // Create `YUI.your.namespace.here` as nested objects, preserving any
- // objects that already exist instead of overwriting them.
- YUI.namespace('your.namespace.here');
-
- When called as a method on a YUI instance, a namespace will be created on
- that instance:
-
- // Creates `Y.property.package`.
- Y.namespace('property.package');
-
- Dots in the input string cause `namespace` to create nested objects for each
- token. If any part of the requested namespace already exists, the current
- object will be left in place and will not be overwritten. This allows
- multiple calls to `namespace` to preserve existing namespaced properties.
-
- If the first token in the namespace string is "YAHOO", that token is
- discarded. This is legacy behavior for backwards compatibility with YUI 2.
-
- Be careful with namespace tokens. Reserved words may work in some browsers
- and not others. For instance, the following will fail in some browsers
- because the supported version of JavaScript reserves the word "long":
-
- Y.namespace('really.long.nested.namespace');
-
- Note: If you pass multiple arguments to create multiple namespaces, only the
- last one created is returned from this function.
-
- @method namespace
- @param {String} namespace* One or more namespaces to create.
- @return {Object} Reference to the last namespace object created.
- **/
- namespace: function() {
- var a = arguments, o, i = 0, j, d, arg;
-
- for (; i < a.length; i++) {
- o = this; //Reset base object per argument or it will get reused from the last
- arg = a[i];
- if (arg.indexOf(PERIOD) > -1) { //Skip this if no "." is present
- d = arg.split(PERIOD);
- for (j = (d[0] == 'YAHOO') ? 1 : 0; j < d.length; j++) {
- o[d[j]] = o[d[j]] || {};
- o = o[d[j]];
- }
- } else {
- o[arg] = o[arg] || {};
- o = o[arg]; //Reset base object to the new object so it's returned
- }
- }
- return o;
- },
-
- // this is replaced if the log module is included
- log: NOOP,
- message: NOOP,
- // this is replaced if the dump module is included
- dump: function (o) { return ''+o; },
-
- /**
- Reports an error.
-
- The reporting mechanism is controlled by the `throwFail` configuration
- attribute. If `throwFail` is falsy, the message is logged. If `throwFail` is
- truthy, a JS exception is thrown.
-
- If an `errorFn` is specified in the config it must return `true` to indicate
- that the exception was handled and keep it from being thrown.
-
- @method error
- @param {String} msg Error message.
- @param {Error|String} [e] JavaScript error object or an error string.
- @param {String} [src] Source of the error (such as the name of the module in
- which the error occurred).
- @chainable
- **/
- error: function(msg, e, src) {
- //TODO Add check for window.onerror here
-
- var Y = this, ret;
-
- if (Y.config.errorFn) {
- ret = Y.config.errorFn.apply(Y, arguments);
- }
-
- if (!ret) {
- throw (e || new Error(msg));
- } else {
- Y.message(msg, 'error', ''+src); // don't scrub this one
- }
-
- return Y;
- },
-
- /**
- Generates an id string that is unique among all YUI instances in this
- execution context.
-
- @method guid
- @param {String} [pre] Prefix.
- @return {String} Unique id.
- **/
- guid: function(pre) {
- var id = this.Env._guidp + '_' + (++this.Env._uidx);
- return (pre) ? (pre + id) : id;
- },
-
- /**
- Returns a unique id associated with the given object and (if *readOnly* is
- falsy) stamps the object with that id so it can be identified in the future.
-
- Stamping an object involves adding a `_yuid` property to it that contains
- the object's id. One exception to this is that in Internet Explorer, DOM
- nodes have a `uniqueID` property that contains a browser-generated unique
- id, which will be used instead of a YUI-generated id when available.
-
- @method stamp
- @param {Object} o Object to stamp.
- @param {Boolean} readOnly If truthy and the given object has not already
- been stamped, the object will not be modified and `null` will be
- returned.
- @return {String} Object's unique id, or `null` if *readOnly* was truthy and
- the given object was not already stamped.
- **/
- stamp: function(o, readOnly) {
- var uid;
- if (!o) {
- return o;
- }
-
- // IE generates its own unique ID for dom nodes
- // The uniqueID property of a document node returns a new ID
- if (o.uniqueID && o.nodeType && o.nodeType !== 9) {
- uid = o.uniqueID;
- } else {
- uid = (typeof o === 'string') ? o : o._yuid;
- }
-
- if (!uid) {
- uid = this.guid();
- if (!readOnly) {
- try {
- o._yuid = uid;
- } catch (e) {
- uid = null;
- }
- }
- }
- return uid;
- },
-
- /**
- Destroys this YUI instance.
-
- @method destroy
- @since 3.3.0
- **/
- destroy: function() {
- var Y = this;
- if (Y.Event) {
- Y.Event._unload();
- }
- delete instances[Y.id];
- delete Y.Env;
- delete Y.config;
- }
-
- /**
- Safe `instanceof` wrapper that works around a memory leak in IE when the
- object being tested is `window` or `document`.
-
- Unless you are testing objects that may be `window` or `document`, you
- should use the native `instanceof` operator instead of this method.
-
- @method instanceOf
- @param {Object} o Object to check.
- @param {Object} type Class to check against.
- @since 3.3.0
- **/
-};
-
- YUI.prototype = proto;
-
- // inheritance utilities are not available yet
- for (prop in proto) {
- if (proto.hasOwnProperty(prop)) {
- YUI[prop] = proto[prop];
- }
- }
-
- /**
- Applies a configuration to all YUI instances in this execution context.
-
- The main use case for this method is in "mashups" where several third-party
- scripts need to write to a global YUI config, but cannot share a single
- centrally-managed config object. This way they can all call
- `YUI.applyConfig({})` instead of overwriting the single global config.
-
- @example
-
- YUI.applyConfig({
- modules: {
- davglass: {
- fullpath: './davglass.js'
- }
- }
- });
-
- YUI.applyConfig({
- modules: {
- foo: {
- fullpath: './foo.js'
- }
- }
- });
-
- YUI().use('davglass', function (Y) {
- // Module davglass will be available here.
- });
-
- @method applyConfig
- @param {Object} o Configuration object to apply.
- @static
- @since 3.5.0
- **/
- YUI.applyConfig = function(o) {
- if (!o) {
- return;
- }
- //If there is a GlobalConfig, apply it first to set the defaults
- if (YUI.GlobalConfig) {
- this.prototype.applyConfig.call(this, YUI.GlobalConfig);
- }
- //Apply this config to it
- this.prototype.applyConfig.call(this, o);
- //Reset GlobalConfig to the combined config
- YUI.GlobalConfig = this.config;
- };
-
- // set up the environment
- YUI._init();
-
- if (hasWin) {
- // add a window load event at load time so we can capture
- // the case where it fires before dynamic loading is
- // complete.
- add(window, 'load', handleLoad);
- } else {
- handleLoad();
- }
-
- YUI.Env.add = add;
- YUI.Env.remove = remove;
-
- /*global exports*/
- // Support the CommonJS method for exporting our single global
- if (typeof exports == 'object') {
- exports.YUI = YUI;
- /**
- * Set a method to be called when `Get.script` is called in Node.js
- * `Get` will open the file, then pass it's content and it's path
- * to this method before attaching it. Commonly used for code coverage
- * instrumentation. <strong>Calling this multiple times will only
- * attach the last hook method</strong>. This method is only
- * available in Node.js.
- * @method setLoadHook
- * @static
- * @param {Function} fn The function to set
- * @param {String} fn.data The content of the file
- * @param {String} fn.path The file path of the file
- */
- YUI.setLoadHook = function(fn) {
- YUI._getLoadHook = fn;
- };
- /**
- * Load hook for `Y.Get.script` in Node.js, see `YUI.setLoadHook`
- * @method _getLoadHook
- * @private
- * @param {String} data The content of the file
- * @param {String} path The file path of the file
- */
- YUI._getLoadHook = null;
- }
-
- YUI.Env[VERSION] = {};
-}());
-
-
-/**
-Config object that contains all of the configuration options for
-this `YUI` instance.
-
-This object is supplied by the implementer when instantiating YUI. Some
-properties have default values if they are not supplied by the implementer.
-
-This object should not be updated directly because some values are cached. Use
-`applyConfig()` to update the config object on a YUI instance that has already
-been configured.
-
-@class config
-@static
-**/
-
-/**
-If `true` (the default), YUI will "bootstrap" the YUI Loader and module metadata
-if they're needed to load additional dependencies and aren't already available.
-
-Setting this to `false` will prevent YUI from automatically loading the Loader
-and module metadata, so you will need to manually ensure that they're available
-or handle dependency resolution yourself.
-
-@property {Boolean} bootstrap
-@default true
-**/
-
-/**
-
-@property {Object} aliases
-**/
-
-/**
-A hash of module group definitions.
-
-For each group you can specify a list of modules and the base path and
-combo spec to use when dynamically loading the modules.
-
-@example
-
- groups: {
- yui2: {
- // specify whether or not this group has a combo service
- combine: true,
-
- // The comboSeperator to use with this group's combo handler
- comboSep: ';',
-
- // The maxURLLength for this server
- maxURLLength: 500,
-
- // the base path for non-combo paths
- base: 'http://yui.yahooapis.com/2.8.0r4/build/',
-
- // the path to the combo service
- comboBase: 'http://yui.yahooapis.com/combo?',
-
- // a fragment to prepend to the path attribute when
- // when building combo urls
- root: '2.8.0r4/build/',
-
- // the module definitions
- modules: {
- yui2_yde: {
- path: "yahoo-dom-event/yahoo-dom-event.js"
- },
- yui2_anim: {
- path: "animation/animation.js",
- requires: ['yui2_yde']
- }
- }
- }
- }
-
-@property {Object} groups
-**/
-
-/**
-Path to the Loader JS file, relative to the `base` path.
-
-This is used to dynamically bootstrap the Loader when it's needed and isn't yet
-available.
-
-@property {String} loaderPath
-@default "loader/loader-min.js"
-**/
-
-/**
-If `true`, YUI will attempt to load CSS dependencies and skins. Set this to
-`false` to prevent YUI from loading any CSS, or set it to the string `"force"`
-to force CSS dependencies to be loaded even if their associated JS modules are
-already loaded.
-
-@property {Boolean|String} fetchCSS
-@default true
-**/
-
-/**
-Default gallery version used to build gallery module urls.
-
-@property {String} gallery
-@since 3.1.0
-**/
-
-/**
-Default YUI 2 version used to build YUI 2 module urls.
-
-This is used for intrinsic YUI 2 support via the 2in3 project. Also see the
-`2in3` config for pulling different revisions of the wrapped YUI 2 modules.
-
-@property {String} yui2
-@default "2.9.0"
-@since 3.1.0
-**/
-
-/**
-Revision number of YUI 2in3 modules that should be used when loading YUI 2in3.
-
-@property {String} 2in3
-@default "4"
-@since 3.1.0
-**/
-
-/**
-Alternate console log function that should be used in environments without a
-supported native console. This function is executed with the YUI instance as its
-`this` object.
-
-@property {Function} logFn
-@since 3.1.0
-**/
-
-/**
-The minimum log level to log messages for. Log levels are defined
-incrementally. Messages greater than or equal to the level specified will
-be shown. All others will be discarded. The order of log levels in
-increasing priority is:
-
- debug
- info
- warn
- error
-
-@property {String} logLevel
-@default 'debug'
-@since 3.10.0
-**/
-
-/**
-Callback to execute when `Y.error()` is called. It receives the error message
-and a JavaScript error object if one was provided.
-
-This function is executed with the YUI instance as its `this` object.
-
-Returning `true` from this function will prevent an exception from being thrown.
-
-@property {Function} errorFn
-@param {String} errorFn.msg Error message
-@param {Object} [errorFn.err] Error object (if one was provided).
-@since 3.2.0
-**/
-
-/**
-A callback to execute when Loader fails to load one or more resources.
-
-This could be because of a script load failure. It could also be because a
-module fails to register itself when the `requireRegistration` config is `true`.
-
-If this function is defined, the `use()` callback will only be called when the
-loader succeeds. Otherwise, `use()` will always executes unless there was a
-JavaScript error when attaching a module.
-
-@property {Function} loadErrorFn
-@since 3.3.0
-**/
-
-/**
-If `true`, Loader will expect all loaded scripts to be first-class YUI modules
-that register themselves with the YUI global, and will trigger a failure if a
-loaded script does not register a YUI module.
-
-@property {Boolean} requireRegistration
-@default false
-@since 3.3.0
-**/
-
-/**
-Cache serviced use() requests.
-
-@property {Boolean} cacheUse
-@default true
-@since 3.3.0
-@deprecated No longer used.
-**/
-
-/**
-Whether or not YUI should use native ES5 functionality when available for
-features like `Y.Array.each()`, `Y.Object()`, etc.
-
-When `false`, YUI will always use its own fallback implementations instead of
-relying on ES5 functionality, even when ES5 functionality is available.
-
-@property {Boolean} useNativeES5
-@default true
-@since 3.5.0
-**/
-
-/**
- * Leverage native JSON stringify if the browser has a native
- * implementation. In general, this is a good idea. See the Known Issues
- * section in the JSON user guide for caveats. The default value is true
- * for browsers with native JSON support.
- *
- * @property useNativeJSONStringify
- * @type Boolean
- * @default true
- * @since 3.8.0
- */
-
- /**
- * Leverage native JSON parse if the browser has a native implementation.
- * In general, this is a good idea. See the Known Issues section in the
- * JSON user guide for caveats. The default value is true for browsers with
- * native JSON support.
- *
- * @property useNativeJSONParse
- * @type Boolean
- * @default true
- * @since 3.8.0
- */
-
-/**
-Delay the `use` callback until a specific event has passed (`load`, `domready`, `contentready` or `available`)
-
-@property {Object|String} delayUntil
-@since 3.6.0
-@example
-
-You can use `load` or `domready` strings by default:
-
- YUI({
- delayUntil: 'domready'
- }, function (Y) {
- // This will not execute until 'domeready' occurs.
- });
-
-Or you can delay until a node is available (with `available` or `contentready`):
-
- YUI({
- delayUntil: {
- event: 'available',
- args : '#foo'
- }
- }, function (Y) {
- // This will not execute until a node matching the selector "#foo" is
- // available in the DOM.
- });
-
-**/
-YUI.add('yui-base', function (Y, NAME) {
-
-/*
- * YUI stub
- * @module yui
- * @submodule yui-base
- */
-/**
- * The YUI module contains the components required for building the YUI
- * seed file. This includes the script loading mechanism, a simple queue,
- * and the core utilities for the library.
- * @module yui
- * @submodule yui-base
- */
-
-/**
- * Provides core language utilites and extensions used throughout YUI.
- *
- * @class Lang
- * @static
- */
-
-var L = Y.Lang || (Y.Lang = {}),
-
-STRING_PROTO = String.prototype,
-TOSTRING = Object.prototype.toString,
-
-TYPES = {
- 'undefined' : 'undefined',
- 'number' : 'number',
- 'boolean' : 'boolean',
- 'string' : 'string',
- '[object Function]': 'function',
- '[object RegExp]' : 'regexp',
- '[object Array]' : 'array',
- '[object Date]' : 'date',
- '[object Error]' : 'error'
-},
-
-SUBREGEX = /\{\s*([^|}]+?)\s*(?:\|([^}]*))?\s*\}/g,
-
-WHITESPACE = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF",
-WHITESPACE_CLASS = "[\x09-\x0D\x20\xA0\u1680\u180E\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]+",
-TRIM_LEFT_REGEX = new RegExp("^" + WHITESPACE_CLASS),
-TRIM_RIGHT_REGEX = new RegExp(WHITESPACE_CLASS + "$"),
-TRIMREGEX = new RegExp(TRIM_LEFT_REGEX.source + "|" + TRIM_RIGHT_REGEX.source, "g"),
-
-NATIVE_FN_REGEX = /\{\s*\[(?:native code|function)\]\s*\}/i;
-
-// -- Protected Methods --------------------------------------------------------
-
-/**
-Returns `true` if the given function appears to be implemented in native code,
-`false` otherwise. Will always return `false` -- even in ES5-capable browsers --
-if the `useNativeES5` YUI config option is set to `false`.
-
-This isn't guaranteed to be 100% accurate and won't work for anything other than
-functions, but it can be useful for determining whether a function like
-`Array.prototype.forEach` is native or a JS shim provided by another library.
-
-There's a great article by @kangax discussing certain flaws with this technique:
-<http://perfectionkills.com/detecting-built-in-host-methods/>
-
-While his points are valid, it's still possible to benefit from this function
-as long as it's used carefully and sparingly, and in such a way that false
-negatives have minimal consequences. It's used internally to avoid using
-potentially broken non-native ES5 shims that have been added to the page by
-other libraries.
-
-@method _isNative
-@param {Function} fn Function to test.
-@return {Boolean} `true` if _fn_ appears to be native, `false` otherwise.
-@static
-@protected
-@since 3.5.0
-**/
-L._isNative = function (fn) {
- return !!(Y.config.useNativeES5 && fn && NATIVE_FN_REGEX.test(fn));
-};
-
-// -- Public Methods -----------------------------------------------------------
-
-/**
- * Determines whether or not the provided item is an array.
- *
- * Returns `false` for array-like collections such as the function `arguments`
- * collection or `HTMLElement` collections. Use `Y.Array.test()` if you want to
- * test for an array-like collection.
- *
- * @method isArray
- * @param o The object to test.
- * @return {boolean} true if o is an array.
- * @static
- */
-L.isArray = L._isNative(Array.isArray) ? Array.isArray : function (o) {
- return L.type(o) === 'array';
-};
-
-/**
- * Determines whether or not the provided item is a boolean.
- * @method isBoolean
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is a boolean.
- */
-L.isBoolean = function(o) {
- return typeof o === 'boolean';
-};
-
-/**
- * Determines whether or not the supplied item is a date instance.
- * @method isDate
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is a date.
- */
-L.isDate = function(o) {
- return L.type(o) === 'date' && o.toString() !== 'Invalid Date' && !isNaN(o);
-};
-
-/**
- * <p>
- * Determines whether or not the provided item is a function.
- * Note: Internet Explorer thinks certain functions are objects:
- * </p>
- *
- * <pre>
- * var obj = document.createElement("object");
- * Y.Lang.isFunction(obj.getAttribute) // reports false in IE
- *
- * var input = document.createElement("input"); // append to body
- * Y.Lang.isFunction(input.focus) // reports false in IE
- * </pre>
- *
- * <p>
- * You will have to implement additional tests if these functions
- * matter to you.
- * </p>
- *
- * @method isFunction
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is a function.
- */
-L.isFunction = function(o) {
- return L.type(o) === 'function';
-};
-
-/**
- * Determines whether or not the provided item is null.
- * @method isNull
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is null.
- */
-L.isNull = function(o) {
- return o === null;
-};
-
-/**
- * Determines whether or not the provided item is a legal number.
- * @method isNumber
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is a number.
- */
-L.isNumber = function(o) {
- return typeof o === 'number' && isFinite(o);
-};
-
-/**
- * Determines whether or not the provided item is of type object
- * or function. Note that arrays are also objects, so
- * <code>Y.Lang.isObject([]) === true</code>.
- * @method isObject
- * @static
- * @param o The object to test.
- * @param failfn {boolean} fail if the input is a function.
- * @return {boolean} true if o is an object.
- * @see isPlainObject
- */
-L.isObject = function(o, failfn) {
- var t = typeof o;
- return (o && (t === 'object' ||
- (!failfn && (t === 'function' || L.isFunction(o))))) || false;
-};
-
-/**
- * Determines whether or not the provided item is a string.
- * @method isString
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is a string.
- */
-L.isString = function(o) {
- return typeof o === 'string';
-};
-
-/**
- * Determines whether or not the provided item is undefined.
- * @method isUndefined
- * @static
- * @param o The object to test.
- * @return {boolean} true if o is undefined.
- */
-L.isUndefined = function(o) {
- return typeof o === 'undefined';
-};
-
-/**
- * A convenience method for detecting a legitimate non-null value.
- * Returns false for null/undefined/NaN, true for other values,
- * including 0/false/''
- * @method isValue
- * @static
- * @param o The item to test.
- * @return {boolean} true if it is not null/undefined/NaN || false.
- */
-L.isValue = function(o) {
- var t = L.type(o);
-
- switch (t) {
- case 'number':
- return isFinite(o);
-
- case 'null': // fallthru
- case 'undefined':
- return false;
-
- default:
- return !!t;
- }
-};
-
-/**
- * Returns the current time in milliseconds.
- *
- * @method now
- * @return {Number} Current time in milliseconds.
- * @static
- * @since 3.3.0
- */
-L.now = Date.now || function () {
- return new Date().getTime();
-};
-
-/**
- * Lightweight version of <code>Y.substitute</code>. Uses the same template
- * structure as <code>Y.substitute</code>, but doesn't support recursion,
- * auto-object coersion, or formats.
- * @method sub
- * @param {string} s String to be modified.
- * @param {object} o Object containing replacement values.
- * @return {string} the substitute result.
- * @static
- * @since 3.2.0
- */
-L.sub = function(s, o) {
- return s.replace ? s.replace(SUBREGEX, function (match, key) {
- return L.isUndefined(o[key]) ? match : o[key];
- }) : s;
-};
-
-/**
- * Returns a string without any leading or trailing whitespace. If
- * the input is not a string, the input will be returned untouched.
- * @method trim
- * @static
- * @param s {string} the string to trim.
- * @return {string} the trimmed string.
- */
-L.trim = L._isNative(STRING_PROTO.trim) && !WHITESPACE.trim() ? function(s) {
- return s && s.trim ? s.trim() : s;
-} : function (s) {
- try {
- return s.replace(TRIMREGEX, '');
- } catch (e) {
- return s;
- }
-};
-
-/**
- * Returns a string without any leading whitespace.
- * @method trimLeft
- * @static
- * @param s {string} the string to trim.
- * @return {string} the trimmed string.
- */
-L.trimLeft = L._isNative(STRING_PROTO.trimLeft) && !WHITESPACE.trimLeft() ? function (s) {
- return s.trimLeft();
-} : function (s) {
- return s.replace(TRIM_LEFT_REGEX, '');
-};
-
-/**
- * Returns a string without any trailing whitespace.
- * @method trimRight
- * @static
- * @param s {string} the string to trim.
- * @return {string} the trimmed string.
- */
-L.trimRight = L._isNative(STRING_PROTO.trimRight) && !WHITESPACE.trimRight() ? function (s) {
- return s.trimRight();
-} : function (s) {
- return s.replace(TRIM_RIGHT_REGEX, '');
-};
-
-/**
-Returns one of the following strings, representing the type of the item passed
-in:
-
- * "array"
- * "boolean"
- * "date"
- * "error"
- * "function"
- * "null"
- * "number"
- * "object"
- * "regexp"
- * "string"
- * "undefined"
-
-Known issues:
-
- * `typeof HTMLElementCollection` returns function in Safari, but
- `Y.Lang.type()` reports "object", which could be a good thing --
- but it actually caused the logic in <code>Y.Lang.isObject</code> to fail.
-
-@method type
-@param o the item to test.
-@return {string} the detected type.
-@static
-**/
-L.type = function(o) {
- return TYPES[typeof o] || TYPES[TOSTRING.call(o)] || (o ? 'object' : 'null');
-};
-/**
-@module yui
-@submodule yui-base
-*/
-
-var Lang = Y.Lang,
- Native = Array.prototype,
-
- hasOwn = Object.prototype.hasOwnProperty;
-
-/**
-Provides utility methods for working with arrays. Additional array helpers can
-be found in the `collection` and `array-extras` modules.
-
-`Y.Array(thing)` returns a native array created from _thing_. Depending on
-_thing_'s type, one of the following will happen:
-
- * Arrays are returned unmodified unless a non-zero _startIndex_ is
- specified.
- * Array-like collections (see `Array.test()`) are converted to arrays.
- * For everything else, a new array is created with _thing_ as the sole
- item.
-
-Note: elements that are also collections, such as `<form>` and `<select>`
-elements, are not automatically converted to arrays. To force a conversion,
-pass `true` as the value of the _force_ parameter.
-
-@class Array
-@constructor
-@param {Any} thing The thing to arrayify.
-@param {Number} [startIndex=0] If non-zero and _thing_ is an array or array-like
- collection, a subset of items starting at the specified index will be
- returned.
-@param {Boolean} [force=false] If `true`, _thing_ will be treated as an
- array-like collection no matter what.
-@return {Array} A native array created from _thing_, according to the rules
- described above.
-**/
-function YArray(thing, startIndex, force) {
- var len, result;
-
- /*jshint expr: true*/
- startIndex || (startIndex = 0);
-
- if (force || YArray.test(thing)) {
- // IE throws when trying to slice HTMLElement collections.
- try {
- return Native.slice.call(thing, startIndex);
- } catch (ex) {
- result = [];
-
- for (len = thing.length; startIndex < len; ++startIndex) {
- result.push(thing[startIndex]);
- }
-
- return result;
- }
- }
-
- return [thing];
-}
-
-Y.Array = YArray;
-
-/**
-Dedupes an array of strings, returning an array that's guaranteed to contain
-only one copy of a given string.
-
-This method differs from `Array.unique()` in that it's optimized for use only
-with arrays consisting entirely of strings or entirely of numbers, whereas
-`unique` may be used with other value types (but is slower).
-
-Using `dedupe()` with values other than strings or numbers, or with arrays
-containing a mix of strings and numbers, may result in unexpected behavior.
-
-@method dedupe
-@param {String[]|Number[]} array Array of strings or numbers to dedupe.
-@return {Array} Copy of _array_ containing no duplicate values.
-@static
-@since 3.4.0
-**/
-YArray.dedupe = Lang._isNative(Object.create) ? function (array) {
- var hash = Object.create(null),
- results = [],
- i, item, len;
-
- for (i = 0, len = array.length; i < len; ++i) {
- item = array[i];
-
- if (!hash[item]) {
- hash[item] = 1;
- results.push(item);
- }
- }
-
- return results;
-} : function (array) {
- var hash = {},
- results = [],
- i, item, len;
-
- for (i = 0, len = array.length; i < len; ++i) {
- item = array[i];
-
- if (!hasOwn.call(hash, item)) {
- hash[item] = 1;
- results.push(item);
- }
- }
-
- return results;
-};
-
-/**
-Executes the supplied function on each item in the array. This method wraps
-the native ES5 `Array.forEach()` method if available.
-
-@method each
-@param {Array} array Array to iterate.
-@param {Function} fn Function to execute on each item in the array. The function
- will receive the following arguments:
- @param {Any} fn.item Current array item.
- @param {Number} fn.index Current array index.
- @param {Array} fn.array Array being iterated.
-@param {Object} [thisObj] `this` object to use when calling _fn_.
-@return {YUI} The YUI instance.
-@static
-**/
-YArray.each = YArray.forEach = Lang._isNative(Native.forEach) ? function (array, fn, thisObj) {
- Native.forEach.call(array || [], fn, thisObj || Y);
- return Y;
-} : function (array, fn, thisObj) {
- for (var i = 0, len = (array && array.length) || 0; i < len; ++i) {
- if (i in array) {
- fn.call(thisObj || Y, array[i], i, array);
- }
- }
-
- return Y;
-};
-
-/**
-Alias for `each()`.
-
-@method forEach
-@static
-**/
-
-/**
-Returns an object using the first array as keys and the second as values. If
-the second array is not provided, or if it doesn't contain the same number of
-values as the first array, then `true` will be used in place of the missing
-values.
-
-@example
-
- Y.Array.hash(['a', 'b', 'c'], ['foo', 'bar']);
- // => {a: 'foo', b: 'bar', c: true}
-
-@method hash
-@param {String[]} keys Array of strings to use as keys.
-@param {Array} [values] Array to use as values.
-@return {Object} Hash using the first array as keys and the second as values.
-@static
-**/
-YArray.hash = function (keys, values) {
- var hash = {},
- vlen = (values && values.length) || 0,
- i, len;
-
- for (i = 0, len = keys.length; i < len; ++i) {
- if (i in keys) {
- hash[keys[i]] = vlen > i && i in values ? values[i] : true;
- }
- }
-
- return hash;
-};
-
-/**
-Returns the index of the first item in the array that's equal (using a strict
-equality check) to the specified _value_, or `-1` if the value isn't found.
-
-This method wraps the native ES5 `Array.indexOf()` method if available.
-
-@method indexOf
-@param {Array} array Array to search.
-@param {Any} value Value to search for.
-@param {Number} [from=0] The index at which to begin the search.
-@return {Number} Index of the item strictly equal to _value_, or `-1` if not
- found.
-@static
-**/
-YArray.indexOf = Lang._isNative(Native.indexOf) ? function (array, value, from) {
- return Native.indexOf.call(array, value, from);
-} : function (array, value, from) {
- // http://es5.github.com/#x15.4.4.14
- var len = array.length;
-
- from = +from || 0;
- from = (from > 0 || -1) * Math.floor(Math.abs(from));
-
- if (from < 0) {
- from += len;
-
- if (from < 0) {
- from = 0;
- }
- }
-
- for (; from < len; ++from) {
- if (from in array && array[from] === value) {
- return from;
- }
- }
-
- return -1;
-};
-
-/**
-Numeric sort convenience function.
-
-The native `Array.prototype.sort()` function converts values to strings and
-sorts them in lexicographic order, which is unsuitable for sorting numeric
-values. Provide `Array.numericSort` as a custom sort function when you want
-to sort values in numeric order.
-
-@example
-
- [42, 23, 8, 16, 4, 15].sort(Y.Array.numericSort);
- // => [4, 8, 15, 16, 23, 42]
-
-@method numericSort
-@param {Number} a First value to compare.
-@param {Number} b Second value to compare.
-@return {Number} Difference between _a_ and _b_.
-@static
-**/
-YArray.numericSort = function (a, b) {
- return a - b;
-};
-
-/**
-Executes the supplied function on each item in the array. Returning a truthy
-value from the function will stop the processing of remaining items.
-
-@method some
-@param {Array} array Array to iterate over.
-@param {Function} fn Function to execute on each item. The function will receive
- the following arguments:
- @param {Any} fn.value Current array item.
- @param {Number} fn.index Current array index.
- @param {Array} fn.array Array being iterated over.
-@param {Object} [thisObj] `this` object to use when calling _fn_.
-@return {Boolean} `true` if the function returns a truthy value on any of the
- items in the array; `false` otherwise.
-@static
-**/
-YArray.some = Lang._isNative(Native.some) ? function (array, fn, thisObj) {
- return Native.some.call(array, fn, thisObj);
-} : function (array, fn, thisObj) {
- for (var i = 0, len = array.length; i < len; ++i) {
- if (i in array && fn.call(thisObj, array[i], i, array)) {
- return true;
- }
- }
-
- return false;
-};
-
-/**
-Evaluates _obj_ to determine if it's an array, an array-like collection, or
-something else. This is useful when working with the function `arguments`
-collection and `HTMLElement` collections.
-
-Note: This implementation doesn't consider elements that are also
-collections, such as `<form>` and `<select>`, to be array-like.
-
-@method test
-@param {Object} obj Object to test.
-@return {Number} A number indicating the results of the test:
-
- * 0: Neither an array nor an array-like collection.
- * 1: Real array.
- * 2: Array-like collection.
-
-@static
-**/
-YArray.test = function (obj) {
- var result = 0;
-
- if (Lang.isArray(obj)) {
- result = 1;
- } else if (Lang.isObject(obj)) {
- try {
- // indexed, but no tagName (element) or scrollTo/document (window. From DOM.isWindow test which we can't use here),
- // or functions without apply/call (Safari
- // HTMLElementCollection bug).
- if ('length' in obj && !obj.tagName && !(obj.scrollTo && obj.document) && !obj.apply) {
- result = 2;
- }
- } catch (ex) {}
- }
-
- return result;
-};
-/**
- * The YUI module contains the components required for building the YUI
- * seed file. This includes the script loading mechanism, a simple queue,
- * and the core utilities for the library.
- * @module yui
- * @submodule yui-base
- */
-
-/**
- * A simple FIFO queue. Items are added to the Queue with add(1..n items) and
- * removed using next().
- *
- * @class Queue
- * @constructor
- * @param {MIXED} item* 0..n items to seed the queue.
- */
-function Queue() {
- this._init();
- this.add.apply(this, arguments);
-}
-
-Queue.prototype = {
- /**
- * Initialize the queue
- *
- * @method _init
- * @protected
- */
- _init: function() {
- /**
- * The collection of enqueued items
- *
- * @property _q
- * @type Array
- * @protected
- */
- this._q = [];
- },
-
- /**
- * Get the next item in the queue. FIFO support
- *
- * @method next
- * @return {MIXED} the next item in the queue.
- */
- next: function() {
- return this._q.shift();
- },
-
- /**
- * Get the last in the queue. LIFO support.
- *
- * @method last
- * @return {MIXED} the last item in the queue.
- */
- last: function() {
- return this._q.pop();
- },
-
- /**
- * Add 0..n items to the end of the queue.
- *
- * @method add
- * @param {MIXED} item* 0..n items.
- * @return {object} this queue.
- */
- add: function() {
- this._q.push.apply(this._q, arguments);
-
- return this;
- },
-
- /**
- * Returns the current number of queued items.
- *
- * @method size
- * @return {Number} The size.
- */
- size: function() {
- return this._q.length;
- }
-};
-
-Y.Queue = Queue;
-
-YUI.Env._loaderQueue = YUI.Env._loaderQueue || new Queue();
-
-/**
-The YUI module contains the components required for building the YUI seed file.
-This includes the script loading mechanism, a simple queue, and the core
-utilities for the library.
-
-@module yui
-@submodule yui-base
-**/
-
-var CACHED_DELIMITER = '__',
-
- hasOwn = Object.prototype.hasOwnProperty,
- isObject = Y.Lang.isObject;
-
-/**
-Returns a wrapper for a function which caches the return value of that function,
-keyed off of the combined string representation of the argument values provided
-when the wrapper is called.
-
-Calling this function again with the same arguments will return the cached value
-rather than executing the wrapped function.
-
-Note that since the cache is keyed off of the string representation of arguments
-passed to the wrapper function, arguments that aren't strings and don't provide
-a meaningful `toString()` method may result in unexpected caching behavior. For
-example, the objects `{}` and `{foo: 'bar'}` would both be converted to the
-string `[object Object]` when used as a cache key.
-
-@method cached
-@param {Function} source The function to memoize.
-@param {Object} [cache={}] Object in which to store cached values. You may seed
- this object with pre-existing cached values if desired.
-@param {any} [refetch] If supplied, this value is compared with the cached value
- using a `==` comparison. If the values are equal, the wrapped function is
- executed again even though a cached value exists.
-@return {Function} Wrapped function.
-@for YUI
-**/
-Y.cached = function (source, cache, refetch) {
- /*jshint expr: true*/
- cache || (cache = {});
-
- return function (arg) {
- var key = arguments.length > 1 ?
- Array.prototype.join.call(arguments, CACHED_DELIMITER) :
- String(arg);
-
- /*jshint eqeqeq: false*/
- if (!(key in cache) || (refetch && cache[key] == refetch)) {
- cache[key] = source.apply(source, arguments);
- }
-
- return cache[key];
- };
-};
-
-/**
-Returns the `location` object from the window/frame in which this YUI instance
-operates, or `undefined` when executing in a non-browser environment
-(e.g. Node.js).
-
-It is _not_ recommended to hold references to the `window.location` object
-outside of the scope of a function in which its properties are being accessed or
-its methods are being called. This is because of a nasty bug/issue that exists
-in both Safari and MobileSafari browsers:
-[WebKit Bug 34679](https://bugs.webkit.org/show_bug.cgi?id=34679).
-
-@method getLocation
-@return {location} The `location` object from the window/frame in which this YUI
- instance operates.
-@since 3.5.0
-**/
-Y.getLocation = function () {
- // It is safer to look this up every time because yui-base is attached to a
- // YUI instance before a user's config is applied; i.e. `Y.config.win` does
- // not point the correct window object when this file is loaded.
- var win = Y.config.win;
-
- // It is not safe to hold a reference to the `location` object outside the
- // scope in which it is being used. The WebKit engine used in Safari and
- // MobileSafari will "disconnect" the `location` object from the `window`
- // when a page is restored from back/forward history cache.
- return win && win.location;
-};
-
-/**
-Returns a new object containing all of the properties of all the supplied
-objects. The properties from later objects will overwrite those in earlier
-objects.
-
-Passing in a single object will create a shallow copy of it. For a deep copy,
-use `clone()`.
-
-@method merge
-@param {Object} objects* One or more objects to merge.
-@return {Object} A new merged object.
-**/
-Y.merge = function () {
- var i = 0,
- len = arguments.length,
- result = {},
- key,
- obj;
-
- for (; i < len; ++i) {
- obj = arguments[i];
-
- for (key in obj) {
- if (hasOwn.call(obj, key)) {
- result[key] = obj[key];
- }
- }
- }
-
- return result;
-};
-
-/**
-Mixes _supplier_'s properties into _receiver_.
-
-Properties on _receiver_ or _receiver_'s prototype will not be overwritten or
-shadowed unless the _overwrite_ parameter is `true`, and will not be merged
-unless the _merge_ parameter is `true`.
-
-In the default mode (0), only properties the supplier owns are copied (prototype
-properties are not copied). The following copying modes are available:
-
- * `0`: _Default_. Object to object.
- * `1`: Prototype to prototype.
- * `2`: Prototype to prototype and object to object.
- * `3`: Prototype to object.
- * `4`: Object to prototype.
-
-@method mix
-@param {Function|Object} receiver The object or function to receive the mixed
- properties.
-@param {Function|Object} supplier The object or function supplying the
- properties to be mixed.
-@param {Boolean} [overwrite=false] If `true`, properties that already exist
- on the receiver will be overwritten with properties from the supplier.
-@param {String[]} [whitelist] An array of property names to copy. If
- specified, only the whitelisted properties will be copied, and all others
- will be ignored.
-@param {Number} [mode=0] Mix mode to use. See above for available modes.
-@param {Boolean} [merge=false] If `true`, objects and arrays that already
- exist on the receiver will have the corresponding object/array from the
- supplier merged into them, rather than being skipped or overwritten. When
- both _overwrite_ and _merge_ are `true`, _merge_ takes precedence.
-@return {Function|Object|YUI} The receiver, or the YUI instance if the
- specified receiver is falsy.
-**/
-Y.mix = function(receiver, supplier, overwrite, whitelist, mode, merge) {
- var alwaysOverwrite, exists, from, i, key, len, to;
-
- // If no supplier is given, we return the receiver. If no receiver is given,
- // we return Y. Returning Y doesn't make much sense to me, but it's
- // grandfathered in for backcompat reasons.
- if (!receiver || !supplier) {
- return receiver || Y;
- }
-
- if (mode) {
- // In mode 2 (prototype to prototype and object to object), we recurse
- // once to do the proto to proto mix. The object to object mix will be
- // handled later on.
- if (mode === 2) {
- Y.mix(receiver.prototype, supplier.prototype, overwrite,
- whitelist, 0, merge);
- }
-
- // Depending on which mode is specified, we may be copying from or to
- // the prototypes of the supplier and receiver.
- from = mode === 1 || mode === 3 ? supplier.prototype : supplier;
- to = mode === 1 || mode === 4 ? receiver.prototype : receiver;
-
- // If either the supplier or receiver doesn't actually have a
- // prototype property, then we could end up with an undefined `from`
- // or `to`. If that happens, we abort and return the receiver.
- if (!from || !to) {
- return receiver;
- }
- } else {
- from = supplier;
- to = receiver;
- }
-
- // If `overwrite` is truthy and `merge` is falsy, then we can skip a
- // property existence check on each iteration and save some time.
- alwaysOverwrite = overwrite && !merge;
-
- if (whitelist) {
- for (i = 0, len = whitelist.length; i < len; ++i) {
- key = whitelist[i];
-
- // We call `Object.prototype.hasOwnProperty` instead of calling
- // `hasOwnProperty` on the object itself, since the object's
- // `hasOwnProperty` method may have been overridden or removed.
- // Also, some native objects don't implement a `hasOwnProperty`
- // method.
- if (!hasOwn.call(from, key)) {
- continue;
- }
-
- // The `key in to` check here is (sadly) intentional for backwards
- // compatibility reasons. It prevents undesired shadowing of
- // prototype members on `to`.
- exists = alwaysOverwrite ? false : key in to;
-
- if (merge && exists && isObject(to[key], true)
- && isObject(from[key], true)) {
- // If we're in merge mode, and the key is present on both
- // objects, and the value on both objects is either an object or
- // an array (but not a function), then we recurse to merge the
- // `from` value into the `to` value instead of overwriting it.
- //
- // Note: It's intentional that the whitelist isn't passed to the
- // recursive call here. This is legacy behavior that lots of
- // code still depends on.
- Y.mix(to[key], from[key], overwrite, null, 0, merge);
- } else if (overwrite || !exists) {
- // We're not in merge mode, so we'll only copy the `from` value
- // to the `to` value if we're in overwrite mode or if the
- // current key doesn't exist on the `to` object.
- to[key] = from[key];
- }
- }
- } else {
- for (key in from) {
- // The code duplication here is for runtime performance reasons.
- // Combining whitelist and non-whitelist operations into a single
- // loop or breaking the shared logic out into a function both result
- // in worse performance, and Y.mix is critical enough that the byte
- // tradeoff is worth it.
- if (!hasOwn.call(from, key)) {
- continue;
- }
-
- // The `key in to` check here is (sadly) intentional for backwards
- // compatibility reasons. It prevents undesired shadowing of
- // prototype members on `to`.
- exists = alwaysOverwrite ? false : key in to;
-
- if (merge && exists && isObject(to[key], true)
- && isObject(from[key], true)) {
- Y.mix(to[key], from[key], overwrite, null, 0, merge);
- } else if (overwrite || !exists) {
- to[key] = from[key];
- }
- }
-
- // If this is an IE browser with the JScript enumeration bug, force
- // enumeration of the buggy properties by making a recursive call with
- // the buggy properties as the whitelist.
- if (Y.Object._hasEnumBug) {
- Y.mix(to, from, overwrite, Y.Object._forceEnum, mode, merge);
- }
- }
-
- return receiver;
-};
-/**
- * The YUI module contains the components required for building the YUI
- * seed file. This includes the script loading mechanism, a simple queue,
- * and the core utilities for the library.
- * @module yui
- * @submodule yui-base
- */
-
-/**
- * Adds utilities to the YUI instance for working with objects.
- *
- * @class Object
- */
-
-var Lang = Y.Lang,
- hasOwn = Object.prototype.hasOwnProperty,
-
- UNDEFINED, // <-- Note the comma. We're still declaring vars.
-
-/**
- * Returns a new object that uses _obj_ as its prototype. This method wraps the
- * native ES5 `Object.create()` method if available, but doesn't currently
- * pass through `Object.create()`'s second argument (properties) in order to
- * ensure compatibility with older browsers.
- *
- * @method ()
- * @param {Object} obj Prototype object.
- * @return {Object} New object using _obj_ as its prototype.
- * @static
- */
-O = Y.Object = Lang._isNative(Object.create) ? function (obj) {
- // We currently wrap the native Object.create instead of simply aliasing it
- // to ensure consistency with our fallback shim, which currently doesn't
- // support Object.create()'s second argument (properties). Once we have a
- // safe fallback for the properties arg, we can stop wrapping
- // Object.create().
- return Object.create(obj);
-} : (function () {
- // Reusable constructor function for the Object.create() shim.
- function F() {}
-
- // The actual shim.
- return function (obj) {
- F.prototype = obj;
- return new F();
- };
-}()),
-
-/**
- * Property names that IE doesn't enumerate in for..in loops, even when they
- * should be enumerable. When `_hasEnumBug` is `true`, it's necessary to
- * manually enumerate these properties.
- *
- * @property _forceEnum
- * @type String[]
- * @protected
- * @static
- */
-forceEnum = O._forceEnum = [
- 'hasOwnProperty',
- 'isPrototypeOf',
- 'propertyIsEnumerable',
- 'toString',
- 'toLocaleString',
- 'valueOf'
-],
-
-/**
- * `true` if this browser has the JScript enumeration bug that prevents
- * enumeration of the properties named in the `_forceEnum` array, `false`
- * otherwise.
- *
- * See:
- * - <https://developer.mozilla.org/en/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug>
- * - <http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation>
- *
- * @property _hasEnumBug
- * @type Boolean
- * @protected
- * @static
- */
-hasEnumBug = O._hasEnumBug = !{valueOf: 0}.propertyIsEnumerable('valueOf'),
-
-/**
- * `true` if this browser incorrectly considers the `prototype` property of
- * functions to be enumerable. Currently known to affect Opera 11.50 and Android 2.3.x.
- *
- * @property _hasProtoEnumBug
- * @type Boolean
- * @protected
- * @static
- */
-hasProtoEnumBug = O._hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
-
-/**
- * Returns `true` if _key_ exists on _obj_, `false` if _key_ doesn't exist or
- * exists only on _obj_'s prototype. This is essentially a safer version of
- * `obj.hasOwnProperty()`.
- *
- * @method owns
- * @param {Object} obj Object to test.
- * @param {String} key Property name to look for.
- * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
- * @static
- */
-owns = O.owns = function (obj, key) {
- return !!obj && hasOwn.call(obj, key);
-}; // <-- End of var declarations.
-
-/**
- * Alias for `owns()`.
- *
- * @method hasKey
- * @param {Object} obj Object to test.
- * @param {String} key Property name to look for.
- * @return {Boolean} `true` if _key_ exists on _obj_, `false` otherwise.
- * @static
- */
-O.hasKey = owns;
-
-/**
- * Returns an array containing the object's enumerable keys. Does not include
- * prototype keys or non-enumerable keys.
- *
- * Note that keys are returned in enumeration order (that is, in the same order
- * that they would be enumerated by a `for-in` loop), which may not be the same
- * as the order in which they were defined.
- *
- * This method is an alias for the native ES5 `Object.keys()` method if
- * available and non-buggy. The Opera 11.50 and Android 2.3.x versions of
- * `Object.keys()` have an inconsistency as they consider `prototype` to be
- * enumerable, so a non-native shim is used to rectify the difference.
- *
- * @example
- *
- * Y.Object.keys({a: 'foo', b: 'bar', c: 'baz'});
- * // => ['a', 'b', 'c']
- *
- * @method keys
- * @param {Object} obj An object.
- * @return {String[]} Array of keys.
- * @static
- */
-O.keys = Lang._isNative(Object.keys) && !hasProtoEnumBug ? Object.keys : function (obj) {
- if (!Lang.isObject(obj)) {
- throw new TypeError('Object.keys called on a non-object');
- }
-
- var keys = [],
- i, key, len;
-
- if (hasProtoEnumBug && typeof obj === 'function') {
- for (key in obj) {
- if (owns(obj, key) && key !== 'prototype') {
- keys.push(key);
- }
- }
- } else {
- for (key in obj) {
- if (owns(obj, key)) {
- keys.push(key);
- }
- }
- }
-
- if (hasEnumBug) {
- for (i = 0, len = forceEnum.length; i < len; ++i) {
- key = forceEnum[i];
-
- if (owns(obj, key)) {
- keys.push(key);
- }
- }
- }
-
- return keys;
-};
-
-/**
- * Returns an array containing the values of the object's enumerable keys.
- *
- * Note that values are returned in enumeration order (that is, in the same
- * order that they would be enumerated by a `for-in` loop), which may not be the
- * same as the order in which they were defined.
- *
- * @example
- *
- * Y.Object.values({a: 'foo', b: 'bar', c: 'baz'});
- * // => ['foo', 'bar', 'baz']
- *
- * @method values
- * @param {Object} obj An object.
- * @return {Array} Array of values.
- * @static
- */
-O.values = function (obj) {
- var keys = O.keys(obj),
- i = 0,
- len = keys.length,
- values = [];
-
- for (; i < len; ++i) {
- values.push(obj[keys[i]]);
- }
-
- return values;
-};
-
-/**
- * Returns the number of enumerable keys owned by an object.
- *
- * @method size
- * @param {Object} obj An object.
- * @return {Number} The object's size.
- * @static
- */
-O.size = function (obj) {
- try {
- return O.keys(obj).length;
- } catch (ex) {
- return 0; // Legacy behavior for non-objects.
- }
-};
-
-/**
- * Returns `true` if the object owns an enumerable property with the specified
- * value.
- *
- * @method hasValue
- * @param {Object} obj An object.
- * @param {any} value The value to search for.
- * @return {Boolean} `true` if _obj_ contains _value_, `false` otherwise.
- * @static
- */
-O.hasValue = function (obj, value) {
- return Y.Array.indexOf(O.values(obj), value) > -1;
-};
-
-/**
- * Executes a function on each enumerable property in _obj_. The function
- * receives the value, the key, and the object itself as parameters (in that
- * order).
- *
- * By default, only properties owned by _obj_ are enumerated. To include
- * prototype properties, set the _proto_ parameter to `true`.
- *
- * @method each
- * @param {Object} obj Object to enumerate.
- * @param {Function} fn Function to execute on each enumerable property.
- * @param {mixed} fn.value Value of the current property.
- * @param {String} fn.key Key of the current property.
- * @param {Object} fn.obj Object being enumerated.
- * @param {Object} [thisObj] `this` object to use when calling _fn_.
- * @param {Boolean} [proto=false] Include prototype properties.
- * @return {YUI} the YUI instance.
- * @chainable
- * @static
- */
-O.each = function (obj, fn, thisObj, proto) {
- var key;
-
- for (key in obj) {
- if (proto || owns(obj, key)) {
- fn.call(thisObj || Y, obj[key], key, obj);
- }
- }
-
- return Y;
-};
-
-/**
- * Executes a function on each enumerable property in _obj_, but halts if the
- * function returns a truthy value. The function receives the value, the key,
- * and the object itself as paramters (in that order).
- *
- * By default, only properties owned by _obj_ are enumerated. To include
- * prototype properties, set the _proto_ parameter to `true`.
- *
- * @method some
- * @param {Object} obj Object to enumerate.
- * @param {Function} fn Function to execute on each enumerable property.
- * @param {mixed} fn.value Value of the current property.
- * @param {String} fn.key Key of the current property.
- * @param {Object} fn.obj Object being enumerated.
- * @param {Object} [thisObj] `this` object to use when calling _fn_.
- * @param {Boolean} [proto=false] Include prototype properties.
- * @return {Boolean} `true` if any execution of _fn_ returns a truthy value,
- * `false` otherwise.
- * @static
- */
-O.some = function (obj, fn, thisObj, proto) {
- var key;
-
- for (key in obj) {
- if (proto || owns(obj, key)) {
- if (fn.call(thisObj || Y, obj[key], key, obj)) {
- return true;
- }
- }
- }
-
- return false;
-};
-
-/**
- * Retrieves the sub value at the provided path,
- * from the value object provided.
- *
- * @method getValue
- * @static
- * @param o The object from which to extract the property value.
- * @param path {Array} A path array, specifying the object traversal path
- * from which to obtain the sub value.
- * @return {Any} The value stored in the path, undefined if not found,
- * undefined if the source is not an object. Returns the source object
- * if an empty path is provided.
- */
-O.getValue = function(o, path) {
- if (!Lang.isObject(o)) {
- return UNDEFINED;
- }
-
- var i,
- p = Y.Array(path),
- l = p.length;
-
- for (i = 0; o !== UNDEFINED && i < l; i++) {
- o = o[p[i]];
- }
-
- return o;
-};
-
-/**
- * Sets the sub-attribute value at the provided path on the
- * value object. Returns the modified value object, or
- * undefined if the path is invalid.
- *
- * @method setValue
- * @static
- * @param o The object on which to set the sub value.
- * @param path {Array} A path array, specifying the object traversal path
- * at which to set the sub value.
- * @param val {Any} The new value for the sub-attribute.
- * @return {Object} The modified object, with the new sub value set, or
- * undefined, if the path was invalid.
- */
-O.setValue = function(o, path, val) {
- var i,
- p = Y.Array(path),
- leafIdx = p.length - 1,
- ref = o;
-
- if (leafIdx >= 0) {
- for (i = 0; ref !== UNDEFINED && i < leafIdx; i++) {
- ref = ref[p[i]];
- }
-
- if (ref !== UNDEFINED) {
- ref[p[i]] = val;
- } else {
- return UNDEFINED;
- }
- }
-
- return o;
-};
-
-/**
- * Returns `true` if the object has no enumerable properties of its own.
- *
- * @method isEmpty
- * @param {Object} obj An object.
- * @return {Boolean} `true` if the object is empty.
- * @static
- * @since 3.2.0
- */
-O.isEmpty = function (obj) {
- return !O.keys(Object(obj)).length;
-};
-/**
- * The YUI module contains the components required for building the YUI seed
- * file. This includes the script loading mechanism, a simple queue, and the
- * core utilities for the library.
- * @module yui
- * @submodule yui-base
- */
-
-/**
- * YUI user agent detection.
- * Do not fork for a browser if it can be avoided. Use feature detection when
- * you can. Use the user agent as a last resort. For all fields listed
- * as @type float, UA stores a version number for the browser engine,
- * 0 otherwise. This value may or may not map to the version number of
- * the browser using the engine. The value is presented as a float so
- * that it can easily be used for boolean evaluation as well as for
- * looking for a particular range of versions. Because of this,
- * some of the granularity of the version info may be lost. The fields that
- * are @type string default to null. The API docs list the values that
- * these fields can have.
- * @class UA
- * @static
- */
-
-/**
-* Static method on `YUI.Env` for parsing a UA string. Called at instantiation
-* to populate `Y.UA`.
-*
-* @static
-* @method parseUA
-* @param {String} [subUA=navigator.userAgent] UA string to parse
-* @return {Object} The Y.UA object
-*/
-YUI.Env.parseUA = function(subUA) {
-
- var numberify = function(s) {
- var c = 0;
- return parseFloat(s.replace(/\./g, function() {
- return (c++ === 1) ? '' : '.';
- }));
- },
-
- win = Y.config.win,
-
- nav = win && win.navigator,
-
- o = {
-
- /**
- * Internet Explorer version number or 0. Example: 6
- * @property ie
- * @type float
- * @static
- */
- ie: 0,
-
- /**
- * Opera version number or 0. Example: 9.2
- * @property opera
- * @type float
- * @static
- */
- opera: 0,
-
- /**
- * Gecko engine revision number. Will evaluate to 1 if Gecko
- * is detected but the revision could not be found. Other browsers
- * will be 0. Example: 1.8
- * <pre>
- * Firefox 1.0.0.4: 1.7.8 <-- Reports 1.7
- * Firefox 1.5.0.9: 1.8.0.9 <-- 1.8
- * Firefox 2.0.0.3: 1.8.1.3 <-- 1.81
- * Firefox 3.0 <-- 1.9
- * Firefox 3.5 <-- 1.91
- * </pre>
- * @property gecko
- * @type float
- * @static
- */
- gecko: 0,
-
- /**
- * AppleWebKit version. KHTML browsers that are not WebKit browsers
- * will evaluate to 1, other browsers 0. Example: 418.9
- * <pre>
- * Safari 1.3.2 (312.6): 312.8.1 <-- Reports 312.8 -- currently the
- * latest available for Mac OSX 10.3.
- * Safari 2.0.2: 416 <-- hasOwnProperty introduced
- * Safari 2.0.4: 418 <-- preventDefault fixed
- * Safari 2.0.4 (419.3): 418.9.1 <-- One version of Safari may run
- * different versions of webkit
- * Safari 2.0.4 (419.3): 419 <-- Tiger installations that have been
- * updated, but not updated
- * to the latest patch.
- * Webkit 212 nightly: 522+ <-- Safari 3.0 precursor (with native
- * SVG and many major issues fixed).
- * Safari 3.0.4 (523.12) 523.12 <-- First Tiger release - automatic
- * update from 2.x via the 10.4.11 OS patch.
- * Webkit nightly 1/2008:525+ <-- Supports DOMContentLoaded event.
- * yahoo.com user agent hack removed.
- * </pre>
- * http://en.wikipedia.org/wiki/Safari_version_history
- * @property webkit
- * @type float
- * @static
- */
- webkit: 0,
-
- /**
- * Safari will be detected as webkit, but this property will also
- * be populated with the Safari version number
- * @property safari
- * @type float
- * @static
- */
- safari: 0,
-
- /**
- * Chrome will be detected as webkit, but this property will also
- * be populated with the Chrome version number
- * @property chrome
- * @type float
- * @static
- */
- chrome: 0,
-
- /**
- * The mobile property will be set to a string containing any relevant
- * user agent information when a modern mobile browser is detected.
- * Currently limited to Safari on the iPhone/iPod Touch, Nokia N-series
- * devices with the WebKit-based browser, and Opera Mini.
- * @property mobile
- * @type string
- * @default null
- * @static
- */
- mobile: null,
-
- /**
- * Adobe AIR version number or 0. Only populated if webkit is detected.
- * Example: 1.0
- * @property air
- * @type float
- */
- air: 0,
- /**
- * PhantomJS version number or 0. Only populated if webkit is detected.
- * Example: 1.0
- * @property phantomjs
- * @type float
- */
- phantomjs: 0,
- /**
- * Detects Apple iPad's OS version
- * @property ipad
- * @type float
- * @static
- */
- ipad: 0,
- /**
- * Detects Apple iPhone's OS version
- * @property iphone
- * @type float
- * @static
- */
- iphone: 0,
- /**
- * Detects Apples iPod's OS version
- * @property ipod
- * @type float
- * @static
- */
- ipod: 0,
- /**
- * General truthy check for iPad, iPhone or iPod
- * @property ios
- * @type Boolean
- * @default null
- * @static
- */
- ios: null,
- /**
- * Detects Googles Android OS version
- * @property android
- * @type float
- * @static
- */
- android: 0,
- /**
- * Detects Kindle Silk
- * @property silk
- * @type float
- * @static
- */
- silk: 0,
- /**
- * Detects Kindle Silk Acceleration
- * @property accel
- * @type Boolean
- * @static
- */
- accel: false,
- /**
- * Detects Palms WebOS version
- * @property webos
- * @type float
- * @static
- */
- webos: 0,
-
- /**
- * Google Caja version number or 0.
- * @property caja
- * @type float
- */
- caja: nav && nav.cajaVersion,
-
- /**
- * Set to true if the page appears to be in SSL
- * @property secure
- * @type boolean
- * @static
- */
- secure: false,
-
- /**
- * The operating system. Currently only detecting windows or macintosh
- * @property os
- * @type string
- * @default null
- * @static
- */
- os: null,
-
- /**
- * The Nodejs Version
- * @property nodejs
- * @type float
- * @default 0
- * @static
- */
- nodejs: 0,
- /**
- * Window8/IE10 Application host environment
- * @property winjs
- * @type Boolean
- * @static
- */
- winjs: !!((typeof Windows !== "undefined") && Windows.System),
- /**
- * Are touch/msPointer events available on this device
- * @property touchEnabled
- * @type Boolean
- * @static
- */
- touchEnabled: false
- },
-
- ua = subUA || nav && nav.userAgent,
-
- loc = win && win.location,
-
- href = loc && loc.href,
-
- m;
-
- /**
- * The User Agent string that was parsed
- * @property userAgent
- * @type String
- * @static
- */
- o.userAgent = ua;
-
-
- o.secure = href && (href.toLowerCase().indexOf('https') === 0);
-
- if (ua) {
-
- if ((/windows|win32/i).test(ua)) {
- o.os = 'windows';
- } else if ((/macintosh|mac_powerpc/i).test(ua)) {
- o.os = 'macintosh';
- } else if ((/android/i).test(ua)) {
- o.os = 'android';
- } else if ((/symbos/i).test(ua)) {
- o.os = 'symbos';
- } else if ((/linux/i).test(ua)) {
- o.os = 'linux';
- } else if ((/rhino/i).test(ua)) {
- o.os = 'rhino';
- }
-
- // Modern KHTML browsers should qualify as Safari X-Grade
- if ((/KHTML/).test(ua)) {
- o.webkit = 1;
- }
- if ((/IEMobile|XBLWP7/).test(ua)) {
- o.mobile = 'windows';
- }
- if ((/Fennec/).test(ua)) {
- o.mobile = 'gecko';
- }
- // Modern WebKit browsers are at least X-Grade
- m = ua.match(/AppleWebKit\/([^\s]*)/);
- if (m && m[1]) {
- o.webkit = numberify(m[1]);
- o.safari = o.webkit;
-
- if (/PhantomJS/.test(ua)) {
- m = ua.match(/PhantomJS\/([^\s]*)/);
- if (m && m[1]) {
- o.phantomjs = numberify(m[1]);
- }
- }
-
- // Mobile browser check
- if (/ Mobile\//.test(ua) || (/iPad|iPod|iPhone/).test(ua)) {
- o.mobile = 'Apple'; // iPhone or iPod Touch
-
- m = ua.match(/OS ([^\s]*)/);
- if (m && m[1]) {
- m = numberify(m[1].replace('_', '.'));
- }
- o.ios = m;
- o.os = 'ios';
- o.ipad = o.ipod = o.iphone = 0;
-
- m = ua.match(/iPad|iPod|iPhone/);
- if (m && m[0]) {
- o[m[0].toLowerCase()] = o.ios;
- }
- } else {
- m = ua.match(/NokiaN[^\/]*|webOS\/\d\.\d/);
- if (m) {
- // Nokia N-series, webOS, ex: NokiaN95
- o.mobile = m[0];
- }
- if (/webOS/.test(ua)) {
- o.mobile = 'WebOS';
- m = ua.match(/webOS\/([^\s]*);/);
- if (m && m[1]) {
- o.webos = numberify(m[1]);
- }
- }
- if (/ Android/.test(ua)) {
- if (/Mobile/.test(ua)) {
- o.mobile = 'Android';
- }
- m = ua.match(/Android ([^\s]*);/);
- if (m && m[1]) {
- o.android = numberify(m[1]);
- }
-
- }
- if (/Silk/.test(ua)) {
- m = ua.match(/Silk\/([^\s]*)\)/);
- if (m && m[1]) {
- o.silk = numberify(m[1]);
- }
- if (!o.android) {
- o.android = 2.34; //Hack for desktop mode in Kindle
- o.os = 'Android';
- }
- if (/Accelerated=true/.test(ua)) {
- o.accel = true;
- }
- }
- }
-
- m = ua.match(/OPR\/(\d+\.\d+)/);
-
- if (m && m[1]) {
- // Opera 15+ with Blink (pretends to be both Chrome and Safari)
- o.opera = numberify(m[1]);
- } else {
- m = ua.match(/(Chrome|CrMo|CriOS)\/([^\s]*)/);
-
- if (m && m[1] && m[2]) {
- o.chrome = numberify(m[2]); // Chrome
- o.safari = 0; //Reset safari back to 0
- if (m[1] === 'CrMo') {
- o.mobile = 'chrome';
- }
- } else {
- m = ua.match(/AdobeAIR\/([^\s]*)/);
- if (m) {
- o.air = m[0]; // Adobe AIR 1.0 or better
- }
- }
- }
- }
-
- if (!o.webkit) { // not webkit
-// @todo check Opera/8.01 (J2ME/MIDP; Opera Mini/2.0.4509/1316; fi; U; ssr)
- if (/Opera/.test(ua)) {
- m = ua.match(/Opera[\s\/]([^\s]*)/);
- if (m && m[1]) {
- o.opera = numberify(m[1]);
- }
- m = ua.match(/Version\/([^\s]*)/);
- if (m && m[1]) {
- o.opera = numberify(m[1]); // opera 10+
- }
-
- if (/Opera Mobi/.test(ua)) {
- o.mobile = 'opera';
- m = ua.replace('Opera Mobi', '').match(/Opera ([^\s]*)/);
- if (m && m[1]) {
- o.opera = numberify(m[1]);
- }
- }
- m = ua.match(/Opera Mini[^;]*/);
-
- if (m) {
- o.mobile = m[0]; // ex: Opera Mini/2.0.4509/1316
- }
- } else { // not opera or webkit
- m = ua.match(/MSIE ([^;]*)|Trident.*; rv:([0-9.]+)/);
-
- if (m && (m[1] || m[2])) {
- o.ie = numberify(m[1] || m[2]);
- } else { // not opera, webkit, or ie
- m = ua.match(/Gecko\/([^\s]*)/);
-
- if (m) {
- o.gecko = 1; // Gecko detected, look for revision
- m = ua.match(/rv:([^\s\)]*)/);
- if (m && m[1]) {
- o.gecko = numberify(m[1]);
- if (/Mobile|Tablet/.test(ua)) {
- o.mobile = "ffos";
- }
- }
- }
- }
- }
- }
- }
-
- //Check for known properties to tell if touch events are enabled on this device or if
- //the number of MSPointer touchpoints on this device is greater than 0.
- if (win && nav && !(o.chrome && o.chrome < 6)) {
- o.touchEnabled = (("ontouchstart" in win) || (("msMaxTouchPoints" in nav) && (nav.msMaxTouchPoints > 0)));
- }
-
- //It was a parsed UA, do not assign the global value.
- if (!subUA) {
-
- if (typeof process === 'object') {
-
- if (process.versions && process.versions.node) {
- //NodeJS
- o.os = process.platform;
- o.nodejs = numberify(process.versions.node);
- }
- }
-
- YUI.Env.UA = o;
-
- }
-
- return o;
-};
-
-
-Y.UA = YUI.Env.UA || YUI.Env.parseUA();
-
-/**
-Performs a simple comparison between two version numbers, accounting for
-standard versioning logic such as the fact that "535.8" is a lower version than
-"535.24", even though a simple numerical comparison would indicate that it's
-greater. Also accounts for cases such as "1.1" vs. "1.1.0", which are
-considered equivalent.
-
-Returns -1 if version _a_ is lower than version _b_, 0 if they're equivalent,
-1 if _a_ is higher than _b_.
-
-Versions may be numbers or strings containing numbers and dots. For example,
-both `535` and `"535.8.10"` are acceptable. A version string containing
-non-numeric characters, like `"535.8.beta"`, may produce unexpected results.
-
-@method compareVersions
-@param {Number|String} a First version number to compare.
-@param {Number|String} b Second version number to compare.
-@return -1 if _a_ is lower than _b_, 0 if they're equivalent, 1 if _a_ is
- higher than _b_.
-**/
-Y.UA.compareVersions = function (a, b) {
- var aPart, aParts, bPart, bParts, i, len;
-
- if (a === b) {
- return 0;
- }
-
- aParts = (a + '').split('.');
- bParts = (b + '').split('.');
-
- for (i = 0, len = Math.max(aParts.length, bParts.length); i < len; ++i) {
- aPart = parseInt(aParts[i], 10);
- bPart = parseInt(bParts[i], 10);
-
- /*jshint expr: true*/
- isNaN(aPart) && (aPart = 0);
- isNaN(bPart) && (bPart = 0);
-
- if (aPart < bPart) {
- return -1;
- }
-
- if (aPart > bPart) {
- return 1;
- }
- }
-
- return 0;
-};
-YUI.Env.aliases = {
- "anim": ["anim-base","anim-color","anim-curve","anim-easing","anim-node-plugin","anim-scroll","anim-xy"],
- "anim-shape-transform": ["anim-shape"],
- "app": ["app-base","app-content","app-transitions","lazy-model-list","model","model-list","model-sync-rest","router","view","view-node-map"],
- "attribute": ["attribute-base","attribute-complex"],
- "attribute-events": ["attribute-observable"],
- "autocomplete": ["autocomplete-base","autocomplete-sources","autocomplete-list","autocomplete-plugin"],
- "axes": ["axis-numeric","axis-category","axis-time","axis-stacked"],
- "axes-base": ["axis-numeric-base","axis-category-base","axis-time-base","axis-stacked-base"],
- "base": ["base-base","base-pluginhost","base-build"],
- "cache": ["cache-base","cache-offline","cache-plugin"],
- "charts": ["charts-base"],
- "collection": ["array-extras","arraylist","arraylist-add","arraylist-filter","array-invoke"],
- "color": ["color-base","color-hsl","color-harmony"],
- "controller": ["router"],
- "dataschema": ["dataschema-base","dataschema-json","dataschema-xml","dataschema-array","dataschema-text"],
- "datasource": ["datasource-local","datasource-io","datasource-get","datasource-function","datasource-cache","datasource-jsonschema","datasource-xmlschema","datasource-arrayschema","datasource-textschema","datasource-polling"],
- "datatable": ["datatable-core","datatable-table","datatable-head","datatable-body","datatable-base","datatable-column-widths","datatable-message","datatable-mutable","datatable-sort","datatable-datasource"],
- "datatype": ["datatype-date","datatype-number","datatype-xml"],
- "datatype-date": ["datatype-date-parse","datatype-date-format","datatype-date-math"],
- "datatype-number": ["datatype-number-parse","datatype-number-format"],
- "datatype-xml": ["datatype-xml-parse","datatype-xml-format"],
- "dd": ["dd-ddm-base","dd-ddm","dd-ddm-drop","dd-drag","dd-proxy","dd-constrain","dd-drop","dd-scroll","dd-delegate"],
- "dom": ["dom-base","dom-screen","dom-style","selector-native","selector"],
- "editor": ["frame","editor-selection","exec-command","editor-base","editor-para","editor-br","editor-bidi","editor-tab","createlink-base"],
- "event": ["event-base","event-delegate","event-synthetic","event-mousewheel","event-mouseenter","event-key","event-focus","event-resize","event-hover","event-outside","event-touch","event-move","event-flick","event-valuechange","event-tap"],
- "event-custom": ["event-custom-base","event-custom-complex"],
- "event-gestures": ["event-flick","event-move"],
- "handlebars": ["handlebars-compiler"],
- "highlight": ["highlight-base","highlight-accentfold"],
- "history": ["history-base","history-hash","history-hash-ie","history-html5"],
- "io": ["io-base","io-xdr","io-form","io-upload-iframe","io-queue"],
- "json": ["json-parse","json-stringify"],
- "loader": ["loader-base","loader-rollup","loader-yui3"],
- "node": ["node-base","node-event-delegate","node-pluginhost","node-screen","node-style"],
- "pluginhost": ["pluginhost-base","pluginhost-config"],
- "querystring": ["querystring-parse","querystring-stringify"],
- "recordset": ["recordset-base","recordset-sort","recordset-filter","recordset-indexer"],
- "resize": ["resize-base","resize-proxy","resize-constrain"],
- "slider": ["slider-base","slider-value-range","clickable-rail","range-slider"],
- "template": ["template-base","template-micro"],
- "text": ["text-accentfold","text-wordbreak"],
- "widget": ["widget-base","widget-htmlparser","widget-skin","widget-uievents"]
-};
-
-
-}, '3.12.0', {
- "use": [
- "yui-base",
- "get",
- "features",
- "intl-base",
- "yui-log",
- "yui-later",
- "loader-base",
- "loader-rollup",
- "loader-yui3"
- ]
-});
-YUI.add('get', function (Y, NAME) {
-
-/*jslint boss:true, expr:true, laxbreak: true */
-
-/**
-Provides dynamic loading of remote JavaScript and CSS resources.
-
-@module get
-@class Get
-@static
-**/
-
-var Lang = Y.Lang,
-
- CUSTOM_ATTRS, // defined lazily in Y.Get.Transaction._createNode()
-
- Get, Transaction;
-
-Y.Get = Get = {
- // -- Public Properties ----------------------------------------------------
-
- /**
- Default options for CSS requests. Options specified here will override
- global defaults for CSS requests.
-
- See the `options` property for all available options.
-
- @property cssOptions
- @type Object
- @static
- @since 3.5.0
- **/
- cssOptions: {
- attributes: {
- rel: 'stylesheet'
- },
-
- doc : Y.config.linkDoc || Y.config.doc,
- pollInterval: 50
- },
-
- /**
- Default options for JS requests. Options specified here will override global
- defaults for JS requests.
-
- See the `options` property for all available options.
-
- @property jsOptions
- @type Object
- @static
- @since 3.5.0
- **/
- jsOptions: {
- autopurge: true,
- doc : Y.config.scriptDoc || Y.config.doc
- },
-
- /**
- Default options to use for all requests.
-
- Note that while all available options are documented here for ease of
- discovery, some options (like callback functions) only make sense at the
- transaction level.
-
- Callback functions specified via the options object or the `options`
- parameter of the `css()`, `js()`, or `load()` methods will receive the
- transaction object as a parameter. See `Y.Get.Transaction` for details on
- the properties and methods available on transactions.
-
- @static
- @since 3.5.0
- @property {Object} options
-
- @property {Boolean} [options.async=false] Whether or not to load scripts
- asynchronously, meaning they're requested in parallel and execution
- order is not guaranteed. Has no effect on CSS, since CSS is always
- loaded asynchronously.
-
- @property {Object} [options.attributes] HTML attribute name/value pairs that
- should be added to inserted nodes. By default, the `charset` attribute
- will be set to "utf-8" and nodes will be given an auto-generated `id`
- attribute, but you can override these with your own values if desired.
-
- @property {Boolean} [options.autopurge] Whether or not to automatically
- purge inserted nodes after the purge threshold is reached. This is
- `true` by default for JavaScript, but `false` for CSS since purging a
- CSS node will also remove any styling applied by the referenced file.
-
- @property {Object} [options.context] `this` object to use when calling
- callback functions. Defaults to the transaction object.
-
- @property {Mixed} [options.data] Arbitrary data object to pass to "on*"
- callbacks.
-
- @property {Document} [options.doc] Document into which nodes should be
- inserted. By default, the current document is used.
-
- @property {HTMLElement|String} [options.insertBefore] HTML element or id
- string of an element before which all generated nodes should be
- inserted. If not specified, Get will automatically determine the best
- place to insert nodes for maximum compatibility.
-
- @property {Function} [options.onEnd] Callback to execute after a transaction
- is complete, regardless of whether it succeeded or failed.
-
- @property {Function} [options.onFailure] Callback to execute after a
- transaction fails, times out, or is aborted.
-
- @property {Function} [options.onProgress] Callback to execute after each
- individual request in a transaction either succeeds or fails.
-
- @property {Function} [options.onSuccess] Callback to execute after a
- transaction completes successfully with no errors. Note that in browsers
- that don't support the `error` event on CSS `<link>` nodes, a failed CSS
- request may still be reported as a success because in these browsers
- it can be difficult or impossible to distinguish between success and
- failure for CSS resources.
-
- @property {Function} [options.onTimeout] Callback to execute after a
- transaction times out.
-
- @property {Number} [options.pollInterval=50] Polling interval (in
- milliseconds) for detecting CSS load completion in browsers that don't
- support the `load` event on `<link>` nodes. This isn't used for
- JavaScript.
-
- @property {Number} [options.purgethreshold=20] Number of nodes to insert
- before triggering an automatic purge when `autopurge` is `true`.
-
- @property {Number} [options.timeout] Number of milliseconds to wait before
- aborting a transaction. When a timeout occurs, the `onTimeout` callback
- is called, followed by `onFailure` and finally `onEnd`. By default,
- there is no timeout.
-
- @property {String} [options.type] Resource type ("css" or "js"). This option
- is set automatically by the `css()` and `js()` functions and will be
- ignored there, but may be useful when using the `load()` function. If
- not specified, the type will be inferred from the URL, defaulting to
- "js" if the URL doesn't contain a recognizable file extension.
- **/
- options: {
- attributes: {
- charset: 'utf-8'
- },
-
- purgethreshold: 20
- },
-
- // -- Protected Properties -------------------------------------------------
-
- /**
- Regex that matches a CSS URL. Used to guess the file type when it's not
- specified.
-
- @property REGEX_CSS
- @type RegExp
- @final
- @protected
- @static
- @since 3.5.0
- **/
- REGEX_CSS: /\.css(?:[?;].*)?$/i,
-
- /**
- Regex that matches a JS URL. Used to guess the file type when it's not
- specified.
-
- @property REGEX_JS
- @type RegExp
- @final
- @protected
- @static
- @since 3.5.0
- **/
- REGEX_JS : /\.js(?:[?;].*)?$/i,
-
- /**
- Contains information about the current environment, such as what script and
- link injection features it supports.
-
- This object is created and populated the first time the `_getEnv()` method
- is called.
-
- @property _env
- @type Object
- @protected
- @static
- @since 3.5.0
- **/
-
- /**
- Mapping of document _yuid strings to <head> or <base> node references so we
- don't have to look the node up each time we want to insert a request node.
-
- @property _insertCache
- @type Object
- @protected
- @static
- @since 3.5.0
- **/
- _insertCache: {},
-
- /**
- Information about the currently pending transaction, if any.
-
- This is actually an object with two properties: `callback`, containing the
- optional callback passed to `css()`, `load()`, or `js()`; and `transaction`,
- containing the actual transaction instance.
-
- @property _pending
- @type Object
- @protected
- @static
- @since 3.5.0
- **/
- _pending: null,
-
- /**
- HTML nodes eligible to be purged next time autopurge is triggered.
-
- @property _purgeNodes
- @type HTMLElement[]
- @protected
- @static
- @since 3.5.0
- **/
- _purgeNodes: [],
-
- /**
- Queued transactions and associated callbacks.
-
- @property _queue
- @type Object[]
- @protected
- @static
- @since 3.5.0
- **/
- _queue: [],
-
- // -- Public Methods -------------------------------------------------------
-
- /**
- Aborts the specified transaction.
-
- This will cause the transaction's `onFailure` callback to be called and
- will prevent any new script and link nodes from being added to the document,
- but any resources that have already been requested will continue loading
- (there's no safe way to prevent this, unfortunately).
-
- *Note:* This method is deprecated as of 3.5.0, and will be removed in a
- future version of YUI. Use the transaction-level `abort()` method instead.
-
- @method abort
- @param {Get.Transaction} transaction Transaction to abort.
- @deprecated Use the `abort()` method on the transaction instead.
- @static
- **/
- abort: function (transaction) {
- var i, id, item, len, pending;
-
-
- if (!transaction.abort) {
- id = transaction;
- pending = this._pending;
- transaction = null;
-
- if (pending && pending.transaction.id === id) {
- transaction = pending.transaction;
- this._pending = null;
- } else {
- for (i = 0, len = this._queue.length; i < len; ++i) {
- item = this._queue[i].transaction;
-
- if (item.id === id) {
- transaction = item;
- this._queue.splice(i, 1);
- break;
- }
- }
- }
- }
-
- transaction && transaction.abort();
- },
-
- /**
- Loads one or more CSS files.
-
- The _urls_ parameter may be provided as a URL string, a request object,
- or an array of URL strings and/or request objects.
-
- A request object is just an object that contains a `url` property and zero
- or more options that should apply specifically to that request.
- Request-specific options take priority over transaction-level options and
- default options.
-
- URLs may be relative or absolute, and do not have to have the same origin
- as the current page.
-
- The `options` parameter may be omitted completely and a callback passed in
- its place, if desired.
-
- @example
-
- // Load a single CSS file and log a message on completion.
- Y.Get.css('foo.css', function (err) {
- if (err) {
- } else {
- }
- });
-
- // Load multiple CSS files and log a message when all have finished
- // loading.
- var urls = ['foo.css', 'http://example.com/bar.css', 'baz/quux.css'];
-
- Y.Get.css(urls, function (err) {
- if (err) {
- } else {
- }
- });
-
- // Specify transaction-level options, which will apply to all requests
- // within the transaction.
- Y.Get.css(urls, {
- attributes: {'class': 'my-css'},
- timeout : 5000
- });
-
- // Specify per-request options, which override transaction-level and
- // default options.
- Y.Get.css([
- {url: 'foo.css', attributes: {id: 'foo'}},
- {url: 'bar.css', attributes: {id: 'bar', charset: 'iso-8859-1'}}
- ]);
-
- @method css
- @param {String|Object|Array} urls URL string, request object, or array
- of URLs and/or request objects to load.
- @param {Object} [options] Options for this transaction. See the
- `Y.Get.options` property for a complete list of available options.
- @param {Function} [callback] Callback function to be called on completion.
- This is a general callback and will be called before any more granular
- callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
- object.
-
- @param {Array|null} callback.err Array of errors that occurred during
- the transaction, or `null` on success.
- @param {Get.Transaction} callback.transaction Transaction object.
-
- @return {Get.Transaction} Transaction object.
- @static
- **/
- css: function (urls, options, callback) {
- return this._load('css', urls, options, callback);
- },
-
- /**
- Loads one or more JavaScript resources.
-
- The _urls_ parameter may be provided as a URL string, a request object,
- or an array of URL strings and/or request objects.
-
- A request object is just an object that contains a `url` property and zero
- or more options that should apply specifically to that request.
- Request-specific options take priority over transaction-level options and
- default options.
-
- URLs may be relative or absolute, and do not have to have the same origin
- as the current page.
-
- The `options` parameter may be omitted completely and a callback passed in
- its place, if desired.
-
- Scripts will be executed in the order they're specified unless the `async`
- option is `true`, in which case they'll be loaded in parallel and executed
- in whatever order they finish loading.
-
- @example
-
- // Load a single JS file and log a message on completion.
- Y.Get.js('foo.js', function (err) {
- if (err) {
- } else {
- }
- });
-
- // Load multiple JS files, execute them in order, and log a message when
- // all have finished loading.
- var urls = ['foo.js', 'http://example.com/bar.js', 'baz/quux.js'];
-
- Y.Get.js(urls, function (err) {
- if (err) {
- } else {
- }
- });
-
- // Specify transaction-level options, which will apply to all requests
- // within the transaction.
- Y.Get.js(urls, {
- attributes: {'class': 'my-js'},
- timeout : 5000
- });
-
- // Specify per-request options, which override transaction-level and
- // default options.
- Y.Get.js([
- {url: 'foo.js', attributes: {id: 'foo'}},
- {url: 'bar.js', attributes: {id: 'bar', charset: 'iso-8859-1'}}
- ]);
-
- @method js
- @param {String|Object|Array} urls URL string, request object, or array
- of URLs and/or request objects to load.
- @param {Object} [options] Options for this transaction. See the
- `Y.Get.options` property for a complete list of available options.
- @param {Function} [callback] Callback function to be called on completion.
- This is a general callback and will be called before any more granular
- callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
- object.
-
- @param {Array|null} callback.err Array of errors that occurred during
- the transaction, or `null` on success.
- @param {Get.Transaction} callback.transaction Transaction object.
-
- @return {Get.Transaction} Transaction object.
- @since 3.5.0
- @static
- **/
- js: function (urls, options, callback) {
- return this._load('js', urls, options, callback);
- },
-
- /**
- Loads one or more CSS and/or JavaScript resources in the same transaction.
-
- Use this method when you want to load both CSS and JavaScript in a single
- transaction and be notified when all requested URLs have finished loading,
- regardless of type.
-
- Behavior and options are the same as for the `css()` and `js()` methods. If
- a resource type isn't specified in per-request options or transaction-level
- options, Get will guess the file type based on the URL's extension (`.css`
- or `.js`, with or without a following query string). If the file type can't
- be guessed from the URL, a warning will be logged and Get will assume the
- URL is a JavaScript resource.
-
- @example
-
- // Load both CSS and JS files in a single transaction, and log a message
- // when all files have finished loading.
- Y.Get.load(['foo.css', 'bar.js', 'baz.css'], function (err) {
- if (err) {
- } else {
- }
- });
-
- @method load
- @param {String|Object|Array} urls URL string, request object, or array
- of URLs and/or request objects to load.
- @param {Object} [options] Options for this transaction. See the
- `Y.Get.options` property for a complete list of available options.
- @param {Function} [callback] Callback function to be called on completion.
- This is a general callback and will be called before any more granular
- callbacks (`onSuccess`, `onFailure`, etc.) specified in the `options`
- object.
-
- @param {Array|null} err Array of errors that occurred during the
- transaction, or `null` on success.
- @param {Get.Transaction} Transaction object.
-
- @return {Get.Transaction} Transaction object.
- @since 3.5.0
- @static
- **/
- load: function (urls, options, callback) {
- return this._load(null, urls, options, callback);
- },
-
- // -- Protected Methods ----------------------------------------------------
-
- /**
- Triggers an automatic purge if the purge threshold has been reached.
-
- @method _autoPurge
- @param {Number} threshold Purge threshold to use, in milliseconds.
- @protected
- @since 3.5.0
- @static
- **/
- _autoPurge: function (threshold) {
- if (threshold && this._purgeNodes.length >= threshold) {
- this._purge(this._purgeNodes);
- }
- },
-
- /**
- Populates the `_env` property with information about the current
- environment.
-
- @method _getEnv
- @return {Object} Environment information.
- @protected
- @since 3.5.0
- @static
- **/
- _getEnv: function () {
- var doc = Y.config.doc,
- ua = Y.UA;
-
- // Note: some of these checks require browser sniffs since it's not
- // feasible to load test files on every pageview just to perform a
- // feature test. I'm sorry if this makes you sad.
- return (this._env = {
-
- // True if this is a browser that supports disabling async mode on
- // dynamically created script nodes. See
- // https://developer.mozilla.org/En/HTML/Element/Script#Attributes
-
- // IE10 doesn't return true for the MDN feature test, so setting it explicitly,
- // because it is async by default, and allows you to disable async by setting it to false
- async: (doc && doc.createElement('script').async === true) || (ua.ie >= 10),
-
- // True if this browser fires an event when a dynamically injected
- // link node fails to load. This is currently true for Firefox 9+
- // and WebKit 535.24+
- cssFail: ua.gecko >= 9 || ua.compareVersions(ua.webkit, 535.24) >= 0,
-
- // True if this browser fires an event when a dynamically injected
- // link node finishes loading. This is currently true for IE, Opera,
- // Firefox 9+, and WebKit 535.24+. Note that IE versions <9 fire the
- // DOM 0 "onload" event, but not "load". All versions of IE fire
- // "onload".
- // davglass: Seems that Chrome on Android needs this to be false.
- cssLoad: (
- (!ua.gecko && !ua.webkit) || ua.gecko >= 9 ||
- ua.compareVersions(ua.webkit, 535.24) >= 0
- ) && !(ua.chrome && ua.chrome <= 18),
-
- // True if this browser preserves script execution order while
- // loading scripts in parallel as long as the script node's `async`
- // attribute is set to false to explicitly disable async execution.
- preservesScriptOrder: !!(ua.gecko || ua.opera || (ua.ie && ua.ie >= 10))
- });
- },
-
- _getTransaction: function (urls, options) {
- var requests = [],
- i, len, req, url;
-
- if (!Lang.isArray(urls)) {
- urls = [urls];
- }
-
- options = Y.merge(this.options, options);
-
- // Clone the attributes object so we don't end up modifying it by ref.
- options.attributes = Y.merge(this.options.attributes,
- options.attributes);
-
- for (i = 0, len = urls.length; i < len; ++i) {
- url = urls[i];
- req = {attributes: {}};
-
- // If `url` is a string, we create a URL object for it, then mix in
- // global options and request-specific options. If it's an object
- // with a "url" property, we assume it's a request object containing
- // URL-specific options.
- if (typeof url === 'string') {
- req.url = url;
- } else if (url.url) {
- // URL-specific options override both global defaults and
- // request-specific options.
- Y.mix(req, url, false, null, 0, true);
- url = url.url; // Make url a string so we can use it later.
- } else {
- continue;
- }
-
- Y.mix(req, options, false, null, 0, true);
-
- // If we didn't get an explicit type for this URL either in the
- // request options or the URL-specific options, try to determine
- // one from the file extension.
- if (!req.type) {
- if (this.REGEX_CSS.test(url)) {
- req.type = 'css';
- } else {
- if (!this.REGEX_JS.test(url)) {
- }
-
- req.type = 'js';
- }
- }
-
- // Mix in type-specific default options, but don't overwrite any
- // options that have already been set.
- Y.mix(req, req.type === 'js' ? this.jsOptions : this.cssOptions,
- false, null, 0, true);
-
- // Give the node an id attribute if it doesn't already have one.
- req.attributes.id || (req.attributes.id = Y.guid());
-
- // Backcompat for <3.5.0 behavior.
- if (req.win) {
- req.doc = req.win.document;
- } else {
- req.win = req.doc.defaultView || req.doc.parentWindow;
- }
-
- if (req.charset) {
- req.attributes.charset = req.charset;
- }
-
- requests.push(req);
- }
-
- return new Transaction(requests, options);
- },
-
- _load: function (type, urls, options, callback) {
- var transaction;
-
- // Allow callback as third param.
- if (typeof options === 'function') {
- callback = options;
- options = {};
- }
-
- options || (options = {});
- options.type = type;
-
- options._onFinish = Get._onTransactionFinish;
-
- if (!this._env) {
- this._getEnv();
- }
-
- transaction = this._getTransaction(urls, options);
-
- this._queue.push({
- callback : callback,
- transaction: transaction
- });
-
- this._next();
-
- return transaction;
- },
-
- _onTransactionFinish : function() {
- Get._pending = null;
- Get._next();
- },
-
- _next: function () {
- var item;
-
- if (this._pending) {
- return;
- }
-
- item = this._queue.shift();
-
- if (item) {
- this._pending = item;
- item.transaction.execute(item.callback);
- }
- },
-
- _purge: function (nodes) {
- var purgeNodes = this._purgeNodes,
- isTransaction = nodes !== purgeNodes,
- index, node;
-
- while (node = nodes.pop()) { // assignment
- // Don't purge nodes that haven't finished loading (or errored out),
- // since this can hang the transaction.
- if (!node._yuiget_finished) {
- continue;
- }
-
- node.parentNode && node.parentNode.removeChild(node);
-
- // If this is a transaction-level purge and this node also exists in
- // the Get-level _purgeNodes array, we need to remove it from
- // _purgeNodes to avoid creating a memory leak. The indexOf lookup
- // sucks, but until we get WeakMaps, this is the least troublesome
- // way to do this (we can't just hold onto node ids because they may
- // not be in the same document).
- if (isTransaction) {
- index = Y.Array.indexOf(purgeNodes, node);
-
- if (index > -1) {
- purgeNodes.splice(index, 1);
- }
- }
- }
- }
-};
-
-/**
-Alias for `js()`.
-
-@method script
-@static
-**/
-Get.script = Get.js;
-
-/**
-Represents a Get transaction, which may contain requests for one or more JS or
-CSS files.
-
-This class should not be instantiated manually. Instances will be created and
-returned as needed by Y.Get's `css()`, `js()`, and `load()` methods.
-
-@class Get.Transaction
-@constructor
-@since 3.5.0
-**/
-Get.Transaction = Transaction = function (requests, options) {
- var self = this;
-
- self.id = Transaction._lastId += 1;
- self.data = options.data;
- self.errors = [];
- self.nodes = [];
- self.options = options;
- self.requests = requests;
-
- self._callbacks = []; // callbacks to call after execution finishes
- self._queue = [];
- self._reqsWaiting = 0;
-
- // Deprecated pre-3.5.0 properties.
- self.tId = self.id; // Use `id` instead.
- self.win = options.win || Y.config.win;
-};
-
-/**
-Arbitrary data object associated with this transaction.
-
-This object comes from the options passed to `Get.css()`, `Get.js()`, or
-`Get.load()`, and will be `undefined` if no data object was specified.
-
-@property {Object} data
-**/
-
-/**
-Array of errors that have occurred during this transaction, if any.
-
-@since 3.5.0
-@property {Object[]} errors
-@property {String} errors.error Error message.
-@property {Object} errors.request Request object related to the error.
-**/
-
-/**
-Numeric id for this transaction, unique among all transactions within the same
-YUI sandbox in the current pageview.
-
-@property {Number} id
-@since 3.5.0
-**/
-
-/**
-HTMLElement nodes (native ones, not YUI Node instances) that have been inserted
-during the current transaction.
-
-@property {HTMLElement[]} nodes
-**/
-
-/**
-Options associated with this transaction.
-
-See `Get.options` for the full list of available options.
-
-@property {Object} options
-@since 3.5.0
-**/
-
-/**
-Request objects contained in this transaction. Each request object represents
-one CSS or JS URL that will be (or has been) requested and loaded into the page.
-
-@property {Object} requests
-@since 3.5.0
-**/
-
-/**
-Id of the most recent transaction.
-
-@property _lastId
-@type Number
-@protected
-@static
-**/
-Transaction._lastId = 0;
-
-Transaction.prototype = {
- // -- Public Properties ----------------------------------------------------
-
- /**
- Current state of this transaction. One of "new", "executing", or "done".
-
- @property _state
- @type String
- @protected
- **/
- _state: 'new', // "new", "executing", or "done"
-
- // -- Public Methods -------------------------------------------------------
-
- /**
- Aborts this transaction.
-
- This will cause the transaction's `onFailure` callback to be called and
- will prevent any new script and link nodes from being added to the document,
- but any resources that have already been requested will continue loading
- (there's no safe way to prevent this, unfortunately).
-
- @method abort
- @param {String} [msg="Aborted."] Optional message to use in the `errors`
- array describing why the transaction was aborted.
- **/
- abort: function (msg) {
- this._pending = null;
- this._pendingCSS = null;
- this._pollTimer = clearTimeout(this._pollTimer);
- this._queue = [];
- this._reqsWaiting = 0;
-
- this.errors.push({error: msg || 'Aborted'});
- this._finish();
- },
-
- /**
- Begins execting the transaction.
-
- There's usually no reason to call this manually, since Get will call it
- automatically when other pending transactions have finished. If you really
- want to execute your transaction before Get does, you can, but be aware that
- this transaction's scripts may end up executing before the scripts in other
- pending transactions.
-
- If the transaction is already executing, the specified callback (if any)
- will be queued and called after execution finishes. If the transaction has
- already finished, the callback will be called immediately (the transaction
- will not be executed again).
-
- @method execute
- @param {Function} callback Callback function to execute after all requests
- in the transaction are complete, or after the transaction is aborted.
- **/
- execute: function (callback) {
- var self = this,
- requests = self.requests,
- state = self._state,
- i, len, queue, req;
-
- if (state === 'done') {
- callback && callback(self.errors.length ? self.errors : null, self);
- return;
- } else {
- callback && self._callbacks.push(callback);
-
- if (state === 'executing') {
- return;
- }
- }
-
- self._state = 'executing';
- self._queue = queue = [];
-
- if (self.options.timeout) {
- self._timeout = setTimeout(function () {
- self.abort('Timeout');
- }, self.options.timeout);
- }
-
- self._reqsWaiting = requests.length;
-
- for (i = 0, len = requests.length; i < len; ++i) {
- req = requests[i];
-
- if (req.async || req.type === 'css') {
- // No need to queue CSS or fully async JS.
- self._insert(req);
- } else {
- queue.push(req);
- }
- }
-
- self._next();
- },
-
- /**
- Manually purges any `<script>` or `<link>` nodes this transaction has
- created.
-
- Be careful when purging a transaction that contains CSS requests, since
- removing `<link>` nodes will also remove any styles they applied.
-
- @method purge
- **/
- purge: function () {
- Get._purge(this.nodes);
- },
-
- // -- Protected Methods ----------------------------------------------------
- _createNode: function (name, attrs, doc) {
- var node = doc.createElement(name),
- attr, testEl;
-
- if (!CUSTOM_ATTRS) {
- // IE6 and IE7 expect property names rather than attribute names for
- // certain attributes. Rather than sniffing, we do a quick feature
- // test the first time _createNode() runs to determine whether we
- // need to provide a workaround.
- testEl = doc.createElement('div');
- testEl.setAttribute('class', 'a');
-
- CUSTOM_ATTRS = testEl.className === 'a' ? {} : {
- 'for' : 'htmlFor',
- 'class': 'className'
- };
- }
-
- for (attr in attrs) {
- if (attrs.hasOwnProperty(attr)) {
- node.setAttribute(CUSTOM_ATTRS[attr] || attr, attrs[attr]);
- }
- }
-
- return node;
- },
-
- _finish: function () {
- var errors = this.errors.length ? this.errors : null,
- options = this.options,
- thisObj = options.context || this,
- data, i, len;
-
- if (this._state === 'done') {
- return;
- }
-
- this._state = 'done';
-
- for (i = 0, len = this._callbacks.length; i < len; ++i) {
- this._callbacks[i].call(thisObj, errors, this);
- }
-
- data = this._getEventData();
-
- if (errors) {
- if (options.onTimeout && errors[errors.length - 1].error === 'Timeout') {
- options.onTimeout.call(thisObj, data);
- }
-
- if (options.onFailure) {
- options.onFailure.call(thisObj, data);
- }
- } else if (options.onSuccess) {
- options.onSuccess.call(thisObj, data);
- }
-
- if (options.onEnd) {
- options.onEnd.call(thisObj, data);
- }
-
- if (options._onFinish) {
- options._onFinish();
- }
- },
-
- _getEventData: function (req) {
- if (req) {
- // This merge is necessary for backcompat. I hate it.
- return Y.merge(this, {
- abort : this.abort, // have to copy these because the prototype isn't preserved
- purge : this.purge,
- request: req,
- url : req.url,
- win : req.win
- });
- } else {
- return this;
- }
- },
-
- _getInsertBefore: function (req) {
- var doc = req.doc,
- el = req.insertBefore,
- cache, docStamp;
-
- if (el) {
- return typeof el === 'string' ? doc.getElementById(el) : el;
- }
-
- cache = Get._insertCache;
- docStamp = Y.stamp(doc);
-
- if ((el = cache[docStamp])) { // assignment
- return el;
- }
-
- // Inserting before a <base> tag apparently works around an IE bug
- // (according to a comment from pre-3.5.0 Y.Get), but I'm not sure what
- // bug that is, exactly. Better safe than sorry?
- if ((el = doc.getElementsByTagName('base')[0])) { // assignment
- return (cache[docStamp] = el);
- }
-
- // Look for a <head> element.
- el = doc.head || doc.getElementsByTagName('head')[0];
-
- if (el) {
- // Create a marker node at the end of <head> to use as an insertion
- // point. Inserting before this node will ensure that all our CSS
- // gets inserted in the correct order, to maintain style precedence.
- el.appendChild(doc.createTextNode(''));
- return (cache[docStamp] = el.lastChild);
- }
-
- // If all else fails, just insert before the first script node on the
- // page, which is virtually guaranteed to exist.
- return (cache[docStamp] = doc.getElementsByTagName('script')[0]);
- },
-
- _insert: function (req) {
- var env = Get._env,
- insertBefore = this._getInsertBefore(req),
- isScript = req.type === 'js',
- node = req.node,
- self = this,
- ua = Y.UA,
- cssTimeout, nodeType;
-
- if (!node) {
- if (isScript) {
- nodeType = 'script';
- } else if (!env.cssLoad && ua.gecko) {
- nodeType = 'style';
- } else {
- nodeType = 'link';
- }
-
- node = req.node = this._createNode(nodeType, req.attributes,
- req.doc);
- }
-
- function onError() {
- self._progress('Failed to load ' + req.url, req);
- }
-
- function onLoad() {
- if (cssTimeout) {
- clearTimeout(cssTimeout);
- }
-
- self._progress(null, req);
- }
-
- // Deal with script asynchronicity.
- if (isScript) {
- node.setAttribute('src', req.url);
-
- if (req.async) {
- // Explicitly indicate that we want the browser to execute this
- // script asynchronously. This is necessary for older browsers
- // like Firefox <4.
- node.async = true;
- } else {
- if (env.async) {
- // This browser treats injected scripts as async by default
- // (standard HTML5 behavior) but asynchronous loading isn't
- // desired, so tell the browser not to mark this script as
- // async.
- node.async = false;
- }
-
- // If this browser doesn't preserve script execution order based
- // on insertion order, we'll need to avoid inserting other
- // scripts until this one finishes loading.
- if (!env.preservesScriptOrder) {
- this._pending = req;
- }
- }
- } else {
- if (!env.cssLoad && ua.gecko) {
- // In Firefox <9, we can import the requested URL into a <style>
- // node and poll for the existence of node.sheet.cssRules. This
- // gives us a reliable way to determine CSS load completion that
- // also works for cross-domain stylesheets.
- //
- // Props to Zach Leatherman for calling my attention to this
- // technique.
- node.innerHTML = (req.attributes.charset ?
- '@charset "' + req.attributes.charset + '";' : '') +
- '@import "' + req.url + '";';
- } else {
- node.setAttribute('href', req.url);
- }
- }
-
- // Inject the node.
- if (isScript && ua.ie && (ua.ie < 9 || (document.documentMode && document.documentMode < 9))) {
- // Script on IE < 9, and IE 9+ when in IE 8 or older modes, including quirks mode.
- node.onreadystatechange = function () {
- if (/loaded|complete/.test(node.readyState)) {
- node.onreadystatechange = null;
- onLoad();
- }
- };
- } else if (!isScript && !env.cssLoad) {
- // CSS on Firefox <9 or WebKit.
- this._poll(req);
- } else {
- // Script or CSS on everything else. Using DOM 0 events because that
- // evens the playing field with older IEs.
-
- if (ua.ie >= 10) {
-
- // We currently need to introduce a timeout for IE10, since it
- // calls onerror/onload synchronously for 304s - messing up existing
- // program flow.
-
- // Remove this block if the following bug gets fixed by GA
- /*jshint maxlen: 1500 */
- // https://connect.microsoft.com/IE/feedback/details/763871/dynamically-loaded-scripts-with-304s-responses-interrupt-the-currently-executing-js-thread-onload
- node.onerror = function() { setTimeout(onError, 0); };
- node.onload = function() { setTimeout(onLoad, 0); };
- } else {
- node.onerror = onError;
- node.onload = onLoad;
- }
-
- // If this browser doesn't fire an event when CSS fails to load,
- // fail after a timeout to avoid blocking the transaction queue.
- if (!env.cssFail && !isScript) {
- cssTimeout = setTimeout(onError, req.timeout || 3000);
- }
- }
-
- this.nodes.push(node);
- insertBefore.parentNode.insertBefore(node, insertBefore);
- },
-
- _next: function () {
- if (this._pending) {
- return;
- }
-
- // If there are requests in the queue, insert the next queued request.
- // Otherwise, if we're waiting on already-inserted requests to finish,
- // wait longer. If there are no queued requests and we're not waiting
- // for anything to load, then we're done!
- if (this._queue.length) {
- this._insert(this._queue.shift());
- } else if (!this._reqsWaiting) {
- this._finish();
- }
- },
-
- _poll: function (newReq) {
- var self = this,
- pendingCSS = self._pendingCSS,
- isWebKit = Y.UA.webkit,
- i, hasRules, j, nodeHref, req, sheets;
-
- if (newReq) {
- pendingCSS || (pendingCSS = self._pendingCSS = []);
- pendingCSS.push(newReq);
-
- if (self._pollTimer) {
- // A poll timeout is already pending, so no need to create a
- // new one.
- return;
- }
- }
-
- self._pollTimer = null;
-
- // Note: in both the WebKit and Gecko hacks below, a CSS URL that 404s
- // will still be treated as a success. There's no good workaround for
- // this.
-
- for (i = 0; i < pendingCSS.length; ++i) {
- req = pendingCSS[i];
-
- if (isWebKit) {
- // Look for a stylesheet matching the pending URL.
- sheets = req.doc.styleSheets;
- j = sheets.length;
- nodeHref = req.node.href;
-
- while (--j >= 0) {
- if (sheets[j].href === nodeHref) {
- pendingCSS.splice(i, 1);
- i -= 1;
- self._progress(null, req);
- break;
- }
- }
- } else {
- // Many thanks to Zach Leatherman for calling my attention to
- // the @import-based cross-domain technique used here, and to
- // Oleg Slobodskoi for an earlier same-domain implementation.
- //
- // See Zach's blog for more details:
- // http://www.zachleat.com/web/2010/07/29/load-css-dynamically/
- try {
- // We don't really need to store this value since we never
- // use it again, but if we don't store it, Closure Compiler
- // assumes the code is useless and removes it.
- hasRules = !!req.node.sheet.cssRules;
-
- // If we get here, the stylesheet has loaded.
- pendingCSS.splice(i, 1);
- i -= 1;
- self._progress(null, req);
- } catch (ex) {
- // An exception means the stylesheet is still loading.
- }
- }
- }
-
- if (pendingCSS.length) {
- self._pollTimer = setTimeout(function () {
- self._poll.call(self);
- }, self.options.pollInterval);
- }
- },
-
- _progress: function (err, req) {
- var options = this.options;
-
- if (err) {
- req.error = err;
-
- this.errors.push({
- error : err,
- request: req
- });
-
- }
-
- req.node._yuiget_finished = req.finished = true;
-
- if (options.onProgress) {
- options.onProgress.call(options.context || this,
- this._getEventData(req));
- }
-
- if (req.autopurge) {
- // Pre-3.5.0 Get always excludes the most recent node from an
- // autopurge. I find this odd, but I'm keeping that behavior for
- // the sake of backcompat.
- Get._autoPurge(this.options.purgethreshold);
- Get._purgeNodes.push(req.node);
- }
-
- if (this._pending === req) {
- this._pending = null;
- }
-
- this._reqsWaiting -= 1;
-
- this._next();
- }
-};
-
-
-}, '3.12.0', {"requires": ["yui-base"]});
-YUI.add('features', function (Y, NAME) {
-
-var feature_tests = {};
-
-/**
-Contains the core of YUI's feature test architecture.
-@module features
-*/
-
-/**
-* Feature detection
-* @class Features
-* @static
-*/
-
-Y.mix(Y.namespace('Features'), {
-
- /**
- * Object hash of all registered feature tests
- * @property tests
- * @type Object
- */
- tests: feature_tests,
-
- /**
- * Add a test to the system
- *
- * ```
- * Y.Features.add("load", "1", {});
- * ```
- *
- * @method add
- * @param {String} cat The category, right now only 'load' is supported
- * @param {String} name The number sequence of the test, how it's reported in the URL or config: 1, 2, 3
- * @param {Object} o Object containing test properties
- * @param {String} o.name The name of the test
- * @param {Function} o.test The test function to execute, the only argument to the function is the `Y` instance
- * @param {String} o.trigger The module that triggers this test.
- */
- add: function(cat, name, o) {
- feature_tests[cat] = feature_tests[cat] || {};
- feature_tests[cat][name] = o;
- },
- /**
- * Execute all tests of a given category and return the serialized results
- *
- * ```
- * caps=1:1;2:1;3:0
- * ```
- * @method all
- * @param {String} cat The category to execute
- * @param {Array} args The arguments to pass to the test function
- * @return {String} A semi-colon separated string of tests and their success/failure: 1:1;2:1;3:0
- */
- all: function(cat, args) {
- var cat_o = feature_tests[cat],
- // results = {};
- result = [];
- if (cat_o) {
- Y.Object.each(cat_o, function(v, k) {
- result.push(k + ':' + (Y.Features.test(cat, k, args) ? 1 : 0));
- });
- }
-
- return (result.length) ? result.join(';') : '';
- },
- /**
- * Run a sepecific test and return a Boolean response.
- *
- * ```
- * Y.Features.test("load", "1");
- * ```
- *
- * @method test
- * @param {String} cat The category of the test to run
- * @param {String} name The name of the test to run
- * @param {Array} args The arguments to pass to the test function
- * @return {Boolean} True or false if the test passed/failed.
- */
- test: function(cat, name, args) {
- args = args || [];
- var result, ua, test,
- cat_o = feature_tests[cat],
- feature = cat_o && cat_o[name];
-
- if (!feature) {
- } else {
-
- result = feature.result;
-
- if (Y.Lang.isUndefined(result)) {
-
- ua = feature.ua;
- if (ua) {
- result = (Y.UA[ua]);
- }
-
- test = feature.test;
- if (test && ((!ua) || result)) {
- result = test.apply(Y, args);
- }
-
- feature.result = result;
- }
- }
-
- return result;
- }
-});
-
-// Y.Features.add("load", "1", {});
-// Y.Features.test("load", "1");
-// caps=1:1;2:0;3:1;
-
-/* This file is auto-generated by (yogi.js loader --mix --yes) */
-/*jshint maxlen:900, eqeqeq: false */
-var add = Y.Features.add;
-// app-transitions-native
-add('load', '0', {
- "name": "app-transitions-native",
- "test": function (Y) {
- var doc = Y.config.doc,
- node = doc ? doc.documentElement : null;
-
- if (node && node.style) {
- return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
- }
-
- return false;
-},
- "trigger": "app-transitions"
-});
-// autocomplete-list-keys
-add('load', '1', {
- "name": "autocomplete-list-keys",
- "test": function (Y) {
- // Only add keyboard support to autocomplete-list if this doesn't appear to
- // be an iOS or Android-based mobile device.
- //
- // There's currently no feasible way to actually detect whether a device has
- // a hardware keyboard, so this sniff will have to do. It can easily be
- // overridden by manually loading the autocomplete-list-keys module.
- //
- // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
- // doesn't fire the keyboard events used by AutoCompleteList, so there's
- // no point loading the -keys module even when a bluetooth keyboard may be
- // available.
- return !(Y.UA.ios || Y.UA.android);
-},
- "trigger": "autocomplete-list"
-});
-// dd-gestures
-add('load', '2', {
- "name": "dd-gestures",
- "trigger": "dd-drag",
- "ua": "touchEnabled"
-});
-// dom-style-ie
-add('load', '3', {
- "name": "dom-style-ie",
- "test": function (Y) {
-
- var testFeature = Y.Features.test,
- addFeature = Y.Features.add,
- WINDOW = Y.config.win,
- DOCUMENT = Y.config.doc,
- DOCUMENT_ELEMENT = 'documentElement',
- ret = false;
-
- addFeature('style', 'computedStyle', {
- test: function() {
- return WINDOW && 'getComputedStyle' in WINDOW;
- }
- });
-
- addFeature('style', 'opacity', {
- test: function() {
- return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
- }
- });
-
- ret = (!testFeature('style', 'opacity') &&
- !testFeature('style', 'computedStyle'));
-
- return ret;
-},
- "trigger": "dom-style"
-});
-// editor-para-ie
-add('load', '4', {
- "name": "editor-para-ie",
- "trigger": "editor-para",
- "ua": "ie",
- "when": "instead"
-});
-// event-base-ie
-add('load', '5', {
- "name": "event-base-ie",
- "test": function(Y) {
- var imp = Y.config.doc && Y.config.doc.implementation;
- return (imp && (!imp.hasFeature('Events', '2.0')));
-},
- "trigger": "node-base"
-});
-// graphics-canvas
-add('load', '6', {
- "name": "graphics-canvas",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
- return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
-},
- "trigger": "graphics"
-});
-// graphics-canvas-default
-add('load', '7', {
- "name": "graphics-canvas-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
- return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
-},
- "trigger": "graphics"
-});
-// graphics-svg
-add('load', '8', {
- "name": "graphics-svg",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
-
- return svg && (useSVG || !canvas);
-},
- "trigger": "graphics"
-});
-// graphics-svg-default
-add('load', '9', {
- "name": "graphics-svg-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
-
- return svg && (useSVG || !canvas);
-},
- "trigger": "graphics"
-});
-// graphics-vml
-add('load', '10', {
- "name": "graphics-vml",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- canvas = DOCUMENT && DOCUMENT.createElement("canvas");
- return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
-},
- "trigger": "graphics"
-});
-// graphics-vml-default
-add('load', '11', {
- "name": "graphics-vml-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- canvas = DOCUMENT && DOCUMENT.createElement("canvas");
- return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
-},
- "trigger": "graphics"
-});
-// history-hash-ie
-add('load', '12', {
- "name": "history-hash-ie",
- "test": function (Y) {
- var docMode = Y.config.doc && Y.config.doc.documentMode;
-
- return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
- !docMode || docMode < 8);
-},
- "trigger": "history-hash"
-});
-// io-nodejs
-add('load', '13', {
- "name": "io-nodejs",
- "trigger": "io-base",
- "ua": "nodejs"
-});
-// json-parse-shim
-add('load', '14', {
- "name": "json-parse-shim",
- "test": function (Y) {
- var _JSON = Y.config.global.JSON,
- Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
- nativeSupport = Y.config.useNativeJSONParse !== false && !!Native;
-
- function workingNative( k, v ) {
- return k === "ok" ? true : v;
- }
-
- // Double check basic functionality. This is mainly to catch early broken
- // implementations of the JSON API in Firefox 3.1 beta1 and beta2
- if ( nativeSupport ) {
- try {
- nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
- }
- catch ( e ) {
- nativeSupport = false;
- }
- }
-
- return !nativeSupport;
-},
- "trigger": "json-parse"
-});
-// json-stringify-shim
-add('load', '15', {
- "name": "json-stringify-shim",
- "test": function (Y) {
- var _JSON = Y.config.global.JSON,
- Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
- nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native;
-
- // Double check basic native functionality. This is primarily to catch broken
- // early JSON API implementations in Firefox 3.1 beta1 and beta2.
- if ( nativeSupport ) {
- try {
- nativeSupport = ( '0' === Native.stringify(0) );
- } catch ( e ) {
- nativeSupport = false;
- }
- }
-
-
- return !nativeSupport;
-},
- "trigger": "json-stringify"
-});
-// scrollview-base-ie
-add('load', '16', {
- "name": "scrollview-base-ie",
- "trigger": "scrollview-base",
- "ua": "ie"
-});
-// selector-css2
-add('load', '17', {
- "name": "selector-css2",
- "test": function (Y) {
- var DOCUMENT = Y.config.doc,
- ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
-
- return ret;
-},
- "trigger": "selector"
-});
-// transition-timer
-add('load', '18', {
- "name": "transition-timer",
- "test": function (Y) {
- var DOCUMENT = Y.config.doc,
- node = (DOCUMENT) ? DOCUMENT.documentElement: null,
- ret = true;
-
- if (node && node.style) {
- ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
- }
-
- return ret;
-},
- "trigger": "transition"
-});
-// widget-base-ie
-add('load', '19', {
- "name": "widget-base-ie",
- "trigger": "widget-base",
- "ua": "ie"
-});
-// yql-jsonp
-add('load', '20', {
- "name": "yql-jsonp",
- "test": function (Y) {
- /* Only load the JSONP module when not in nodejs or winjs
- TODO Make the winjs module a CORS module
- */
- return (!Y.UA.nodejs && !Y.UA.winjs);
-},
- "trigger": "yql",
- "when": "after"
-});
-// yql-nodejs
-add('load', '21', {
- "name": "yql-nodejs",
- "trigger": "yql",
- "ua": "nodejs",
- "when": "after"
-});
-// yql-winjs
-add('load', '22', {
- "name": "yql-winjs",
- "trigger": "yql",
- "ua": "winjs",
- "when": "after"
-});
-
-}, '3.12.0', {"requires": ["yui-base"]});
-YUI.add('intl-base', function (Y, NAME) {
-
-/**
- * The Intl utility provides a central location for managing sets of
- * localized resources (strings and formatting patterns).
- *
- * @class Intl
- * @uses EventTarget
- * @static
- */
-
-var SPLIT_REGEX = /[, ]/;
-
-Y.mix(Y.namespace('Intl'), {
-
- /**
- * Returns the language among those available that
- * best matches the preferred language list, using the Lookup
- * algorithm of BCP 47.
- * If none of the available languages meets the user's preferences,
- * then "" is returned.
- * Extended language ranges are not supported.
- *
- * @method lookupBestLang
- * @param {String[] | String} preferredLanguages The list of preferred
- * languages in descending preference order, represented as BCP 47
- * language tags. A string array or a comma-separated list.
- * @param {String[]} availableLanguages The list of languages
- * that the application supports, represented as BCP 47 language
- * tags.
- *
- * @return {String} The available language that best matches the
- * preferred language list, or "".
- * @since 3.1.0
- */
- lookupBestLang: function(preferredLanguages, availableLanguages) {
-
- var i, language, result, index;
-
- // check whether the list of available languages contains language;
- // if so return it
- function scan(language) {
- var i;
- for (i = 0; i < availableLanguages.length; i += 1) {
- if (language.toLowerCase() ===
- availableLanguages[i].toLowerCase()) {
- return availableLanguages[i];
- }
- }
- }
-
- if (Y.Lang.isString(preferredLanguages)) {
- preferredLanguages = preferredLanguages.split(SPLIT_REGEX);
- }
-
- for (i = 0; i < preferredLanguages.length; i += 1) {
- language = preferredLanguages[i];
- if (!language || language === '*') {
- continue;
- }
- // check the fallback sequence for one language
- while (language.length > 0) {
- result = scan(language);
- if (result) {
- return result;
- } else {
- index = language.lastIndexOf('-');
- if (index >= 0) {
- language = language.substring(0, index);
- // one-character subtags get cut along with the
- // following subtag
- if (index >= 2 && language.charAt(index - 2) === '-') {
- language = language.substring(0, index - 2);
- }
- } else {
- // nothing available for this language
- break;
- }
- }
- }
- }
-
- return '';
- }
-});
-
-
-}, '3.12.0', {"requires": ["yui-base"]});
-YUI.add('yui-log', function (Y, NAME) {
-
-/**
- * Provides console log capability and exposes a custom event for
- * console implementations. This module is a `core` YUI module,
- * <a href="../classes/YUI.html#method_log">it's documentation is located under the YUI class</a>.
- *
- * @module yui
- * @submodule yui-log
- */
-
-var INSTANCE = Y,
- LOGEVENT = 'yui:log',
- UNDEFINED = 'undefined',
- LEVELS = { debug: 1,
- info: 2,
- warn: 4,
- error: 8 };
-
-/**
- * If the 'debug' config is true, a 'yui:log' event will be
- * dispatched, which the Console widget and anything else
- * can consume. If the 'useBrowserConsole' config is true, it will
- * write to the browser console if available. YUI-specific log
- * messages will only be present in the -debug versions of the
- * JS files. The build system is supposed to remove log statements
- * from the raw and minified versions of the files.
- *
- * @method log
- * @for YUI
- * @param {String} msg The message to log.
- * @param {String} cat The log category for the message. Default
- * categories are "info", "warn", "error", time".
- * Custom categories can be used as well. (opt).
- * @param {String} src The source of the the message (opt).
- * @param {boolean} silent If true, the log event won't fire.
- * @return {YUI} YUI instance.
- */
-INSTANCE.log = function(msg, cat, src, silent) {
- var bail, excl, incl, m, f, minlevel,
- Y = INSTANCE,
- c = Y.config,
- publisher = (Y.fire) ? Y : YUI.Env.globalEvents;
- // suppress log message if the config is off or the event stack
- // or the event call stack contains a consumer of the yui:log event
- if (c.debug) {
- // apply source filters
- src = src || "";
- if (typeof src !== "undefined") {
- excl = c.logExclude;
- incl = c.logInclude;
- if (incl && !(src in incl)) {
- bail = 1;
- } else if (incl && (src in incl)) {
- bail = !incl[src];
- } else if (excl && (src in excl)) {
- bail = excl[src];
- }
-
- // Determine the current minlevel as defined in configuration
- Y.config.logLevel = Y.config.logLevel || 'debug';
- minlevel = LEVELS[Y.config.logLevel.toLowerCase()];
-
- if (cat in LEVELS && LEVELS[cat] < minlevel) {
- // Skip this message if the we don't meet the defined minlevel
- bail = 1;
- }
- }
- if (!bail) {
- if (c.useBrowserConsole) {
- m = (src) ? src + ': ' + msg : msg;
- if (Y.Lang.isFunction(c.logFn)) {
- c.logFn.call(Y, msg, cat, src);
- } else if (typeof console !== UNDEFINED && console.log) {
- f = (cat && console[cat] && (cat in LEVELS)) ? cat : 'log';
- console[f](m);
- } else if (typeof opera !== UNDEFINED) {
- opera.postError(m);
- }
- }
-
- if (publisher && !silent) {
-
- if (publisher === Y && (!publisher.getEvent(LOGEVENT))) {
- publisher.publish(LOGEVENT, {
- broadcast: 2
- });
- }
-
- publisher.fire(LOGEVENT, {
- msg: msg,
- cat: cat,
- src: src
- });
- }
- }
- }
-
- return Y;
-};
-
-/**
- * Write a system message. This message will be preserved in the
- * minified and raw versions of the YUI files, unlike log statements.
- * @method message
- * @for YUI
- * @param {String} msg The message to log.
- * @param {String} cat The log category for the message. Default
- * categories are "info", "warn", "error", time".
- * Custom categories can be used as well. (opt).
- * @param {String} src The source of the the message (opt).
- * @param {boolean} silent If true, the log event won't fire.
- * @return {YUI} YUI instance.
- */
-INSTANCE.message = function() {
- return INSTANCE.log.apply(INSTANCE, arguments);
-};
-
-
-}, '3.12.0', {"requires": ["yui-base"]});
-YUI.add('yui-later', function (Y, NAME) {
-
-/**
- * Provides a setTimeout/setInterval wrapper. This module is a `core` YUI module,
- * <a href="../classes/YUI.html#method_later">it's documentation is located under the YUI class</a>.
- *
- * @module yui
- * @submodule yui-later
- */
-
-var NO_ARGS = [];
-
-/**
- * Executes the supplied function in the context of the supplied
- * object 'when' milliseconds later. Executes the function a
- * single time unless periodic is set to true.
- * @for YUI
- * @method later
- * @param when {int} the number of milliseconds to wait until the fn
- * is executed.
- * @param o the context object.
- * @param fn {Function|String} the function to execute or the name of
- * the method in the 'o' object to execute.
- * @param data [Array] data that is provided to the function. This
- * accepts either a single item or an array. If an array is provided,
- * the function is executed with one parameter for each array item.
- * If you need to pass a single array parameter, it needs to be wrapped
- * in an array [myarray].
- *
- * Note: native methods in IE may not have the call and apply methods.
- * In this case, it will work, but you are limited to four arguments.
- *
- * @param periodic {boolean} if true, executes continuously at supplied
- * interval until canceled.
- * @return {object} a timer object. Call the cancel() method on this
- * object to stop the timer.
- */
-Y.later = function(when, o, fn, data, periodic) {
- when = when || 0;
- data = (!Y.Lang.isUndefined(data)) ? Y.Array(data) : NO_ARGS;
- o = o || Y.config.win || Y;
-
- var cancelled = false,
- method = (o && Y.Lang.isString(fn)) ? o[fn] : fn,
- wrapper = function() {
- // IE 8- may execute a setInterval callback one last time
- // after clearInterval was called, so in order to preserve
- // the cancel() === no more runny-run, we have to jump through
- // an extra hoop.
- if (!cancelled) {
- if (!method.apply) {
- method(data[0], data[1], data[2], data[3]);
- } else {
- method.apply(o, data || NO_ARGS);
- }
- }
- },
- id = (periodic) ? setInterval(wrapper, when) : setTimeout(wrapper, when);
-
- return {
- id: id,
- interval: periodic,
- cancel: function() {
- cancelled = true;
- if (this.interval) {
- clearInterval(id);
- } else {
- clearTimeout(id);
- }
- }
- };
-};
-
-Y.Lang.later = Y.later;
-
-
-
-}, '3.12.0', {"requires": ["yui-base"]});
-YUI.add('loader-base', function (Y, NAME) {
-
-/**
- * The YUI loader core
- * @module loader
- * @submodule loader-base
- */
-
-(function() {
- var VERSION = Y.version,
- BUILD = '/build/',
- ROOT = VERSION + '/',
- CDN_BASE = Y.Env.base,
- GALLERY_VERSION = 'gallery-2013.08.22-21-03',
- TNT = '2in3',
- TNT_VERSION = '4',
- YUI2_VERSION = '2.9.0',
- COMBO_BASE = CDN_BASE + 'combo?',
- META = {
- version: VERSION,
- root: ROOT,
- base: Y.Env.base,
- comboBase: COMBO_BASE,
- skin: {
- defaultSkin: 'sam',
- base: 'assets/skins/',
- path: 'skin.css',
- after: [
- 'cssreset',
- 'cssfonts',
- 'cssgrids',
- 'cssbase',
- 'cssreset-context',
- 'cssfonts-context'
- ]
- },
- groups: {},
- patterns: {}
- },
- groups = META.groups,
- yui2Update = function(tnt, yui2, config) {
- var root = TNT + '.' +
- (tnt || TNT_VERSION) + '/' +
- (yui2 || YUI2_VERSION) + BUILD,
- base = (config && config.base) ? config.base : CDN_BASE,
- combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
-
- groups.yui2.base = base + root;
- groups.yui2.root = root;
- groups.yui2.comboBase = combo;
- },
- galleryUpdate = function(tag, config) {
- var root = (tag || GALLERY_VERSION) + BUILD,
- base = (config && config.base) ? config.base : CDN_BASE,
- combo = (config && config.comboBase) ? config.comboBase : COMBO_BASE;
-
- groups.gallery.base = base + root;
- groups.gallery.root = root;
- groups.gallery.comboBase = combo;
- };
-
-
- groups[VERSION] = {};
-
- groups.gallery = {
- ext: false,
- combine: true,
- comboBase: COMBO_BASE,
- update: galleryUpdate,
- patterns: {
- 'gallery-': {},
- 'lang/gallery-': {},
- 'gallerycss-': {
- type: 'css'
- }
- }
- };
-
- groups.yui2 = {
- combine: true,
- ext: false,
- comboBase: COMBO_BASE,
- update: yui2Update,
- patterns: {
- 'yui2-': {
- configFn: function(me) {
- if (/-skin|reset|fonts|grids|base/.test(me.name)) {
- me.type = 'css';
- me.path = me.path.replace(/\.js/, '.css');
- // this makes skins in builds earlier than
- // 2.6.0 work as long as combine is false
- me.path = me.path.replace(/\/yui2-skin/,
- '/assets/skins/sam/yui2-skin');
- }
- }
- }
- }
- };
-
- galleryUpdate();
- yui2Update();
-
- if (YUI.Env[VERSION]) {
- Y.mix(META, YUI.Env[VERSION], false, [
- 'modules',
- 'groups',
- 'skin'
- ], 0, true);
- }
-
- YUI.Env[VERSION] = META;
-}());
-/*jslint forin: true, maxlen: 350 */
-
-/**
- * Loader dynamically loads script and css files. It includes the dependency
- * information for the version of the library in use, and will automatically pull in
- * dependencies for the modules requested. It can also load the
- * files from the Yahoo! CDN, and it can utilize the combo service provided on
- * this network to reduce the number of http connections required to download
- * YUI files.
- *
- * @module loader
- * @main loader
- * @submodule loader-base
- */
-
-var NOT_FOUND = {},
- NO_REQUIREMENTS = [],
- MAX_URL_LENGTH = 1024,
- GLOBAL_ENV = YUI.Env,
- GLOBAL_LOADED = GLOBAL_ENV._loaded,
- CSS = 'css',
- JS = 'js',
- INTL = 'intl',
- DEFAULT_SKIN = 'sam',
- VERSION = Y.version,
- ROOT_LANG = '',
- YObject = Y.Object,
- oeach = YObject.each,
- yArray = Y.Array,
- _queue = GLOBAL_ENV._loaderQueue,
- META = GLOBAL_ENV[VERSION],
- SKIN_PREFIX = 'skin-',
- L = Y.Lang,
- ON_PAGE = GLOBAL_ENV.mods,
- modulekey,
- _path = function(dir, file, type, nomin) {
- var path = dir + '/' + file;
- if (!nomin) {
- path += '-min';
- }
- path += '.' + (type || CSS);
-
- return path;
- };
-
-
- if (!YUI.Env._cssLoaded) {
- YUI.Env._cssLoaded = {};
- }
-
-
-/**
- * The component metadata is stored in Y.Env.meta.
- * Part of the loader module.
- * @property meta
- * @for YUI
- */
-Y.Env.meta = META;
-
-/**
- * Loader dynamically loads script and css files. It includes the dependency
- * info for the version of the library in use, and will automatically pull in
- * dependencies for the modules requested. It can load the
- * files from the Yahoo! CDN, and it can utilize the combo service provided on
- * this network to reduce the number of http connections required to download
- * YUI files. You can also specify an external, custom combo service to host
- * your modules as well.
-
- var Y = YUI();
- var loader = new Y.Loader({
- filter: 'debug',
- base: '../../',
- root: 'build/',
- combine: true,
- require: ['node', 'dd', 'console']
- });
- var out = loader.resolve(true);
-
- * @constructor
- * @class Loader
- * @param {Object} config an optional set of configuration options.
- * @param {String} config.base The base dir which to fetch this module from
- * @param {String} config.comboBase The Combo service base path. Ex: `http://yui.yahooapis.com/combo?`
- * @param {String} config.root The root path to prepend to module names for the combo service. Ex: `2.5.2/build/`
- * @param {String|Object} config.filter A filter to apply to result urls. <a href="#property_filter">See filter property</a>
- * @param {Object} config.filters Per-component filter specification. If specified for a given component, this overrides the filter config.
- * @param {Boolean} config.combine Use a combo service to reduce the number of http connections required to load your dependencies
- * @param {Boolean} [config.async=true] Fetch files in async
- * @param {Array} config.ignore: A list of modules that should never be dynamically loaded
- * @param {Array} config.force A list of modules that should always be loaded when required, even if already present on the page
- * @param {HTMLElement|String} config.insertBefore Node or id for a node that should be used as the insertion point for new nodes
- * @param {Object} config.jsAttributes Object literal containing attributes to add to script nodes
- * @param {Object} config.cssAttributes Object literal containing attributes to add to link nodes
- * @param {Number} config.timeout The number of milliseconds before a timeout occurs when dynamically loading nodes. If not set, there is no timeout
- * @param {Object} config.context Execution context for all callbacks
- * @param {Function} config.onSuccess Callback for the 'success' event
- * @param {Function} config.onFailure Callback for the 'failure' event
- * @param {Function} config.onCSS Callback for the 'CSSComplete' event. When loading YUI components with CSS the CSS is loaded first, then the script. This provides a moment you can tie into to improve the presentation of the page while the script is loading.
- * @param {Function} config.onTimeout Callback for the 'timeout' event
- * @param {Function} config.onProgress Callback executed each time a script or css file is loaded
- * @param {Object} config.modules A list of module definitions. See <a href="#method_addModule">Loader.addModule</a> for the supported module metadata
- * @param {Object} config.groups A list of group definitions. Each group can contain specific definitions for `base`, `comboBase`, `combine`, and accepts a list of `modules`.
- * @param {String} config.2in3 The version of the YUI 2 in 3 wrapper to use. The intrinsic support for YUI 2 modules in YUI 3 relies on versions of the YUI 2 components inside YUI 3 module wrappers. These wrappers change over time to accomodate the issues that arise from running YUI 2 in a YUI 3 sandbox.
- * @param {String} config.yui2 When using the 2in3 project, you can select the version of YUI 2 to use. Valid values are `2.2.2`, `2.3.1`, `2.4.1`, `2.5.2`, `2.6.0`, `2.7.0`, `2.8.0`, `2.8.1` and `2.9.0` [default] -- plus all versions of YUI 2 going forward.
- */
-Y.Loader = function(o) {
-
- var self = this;
-
- //Catch no config passed.
- o = o || {};
-
- modulekey = META.md5;
-
- /**
- * Internal callback to handle multiple internal insert() calls
- * so that css is inserted prior to js
- * @property _internalCallback
- * @private
- */
- // self._internalCallback = null;
-
- /**
- * Callback that will be executed when the loader is finished
- * with an insert
- * @method onSuccess
- * @type function
- */
- // self.onSuccess = null;
-
- /**
- * Callback that will be executed if there is a failure
- * @method onFailure
- * @type function
- */
- // self.onFailure = null;
-
- /**
- * Callback for the 'CSSComplete' event. When loading YUI components
- * with CSS the CSS is loaded first, then the script. This provides
- * a moment you can tie into to improve the presentation of the page
- * while the script is loading.
- * @method onCSS
- * @type function
- */
- // self.onCSS = null;
-
- /**
- * Callback executed each time a script or css file is loaded
- * @method onProgress
- * @type function
- */
- // self.onProgress = null;
-
- /**
- * Callback that will be executed if a timeout occurs
- * @method onTimeout
- * @type function
- */
- // self.onTimeout = null;
-
- /**
- * The execution context for all callbacks
- * @property context
- * @default {YUI} the YUI instance
- */
- self.context = Y;
-
- /**
- * Data that is passed to all callbacks
- * @property data
- */
- // self.data = null;
-
- /**
- * Node reference or id where new nodes should be inserted before
- * @property insertBefore
- * @type string|HTMLElement
- */
- // self.insertBefore = null;
-
- /**
- * The charset attribute for inserted nodes
- * @property charset
- * @type string
- * @deprecated , use cssAttributes or jsAttributes.
- */
- // self.charset = null;
-
- /**
- * An object literal containing attributes to add to link nodes
- * @property cssAttributes
- * @type object
- */
- // self.cssAttributes = null;
-
- /**
- * An object literal containing attributes to add to script nodes
- * @property jsAttributes
- * @type object
- */
- // self.jsAttributes = null;
-
- /**
- * The base directory.
- * @property base
- * @type string
- * @default http://yui.yahooapis.com/[YUI VERSION]/build/
- */
- self.base = Y.Env.meta.base + Y.Env.meta.root;
-
- /**
- * Base path for the combo service
- * @property comboBase
- * @type string
- * @default http://yui.yahooapis.com/combo?
- */
- self.comboBase = Y.Env.meta.comboBase;
-
- /*
- * Base path for language packs.
- */
- // self.langBase = Y.Env.meta.langBase;
- // self.lang = "";
-
- /**
- * If configured, the loader will attempt to use the combo
- * service for YUI resources and configured external resources.
- * @property combine
- * @type boolean
- * @default true if a base dir isn't in the config
- */
- self.combine = o.base &&
- (o.base.indexOf(self.comboBase.substr(0, 20)) > -1);
-
- /**
- * The default seperator to use between files in a combo URL
- * @property comboSep
- * @type {String}
- * @default Ampersand
- */
- self.comboSep = '&';
- /**
- * Max url length for combo urls. The default is 1024. This is the URL
- * limit for the Yahoo! hosted combo servers. If consuming
- * a different combo service that has a different URL limit
- * it is possible to override this default by supplying
- * the maxURLLength config option. The config option will
- * only take effect if lower than the default.
- *
- * @property maxURLLength
- * @type int
- */
- self.maxURLLength = MAX_URL_LENGTH;
-
- /**
- * Ignore modules registered on the YUI global
- * @property ignoreRegistered
- * @default false
- */
- self.ignoreRegistered = o.ignoreRegistered;
-
- /**
- * Root path to prepend to module path for the combo
- * service
- * @property root
- * @type string
- * @default [YUI VERSION]/build/
- */
- self.root = Y.Env.meta.root;
-
- /**
- * Timeout value in milliseconds. If set, self value will be used by
- * the get utility. the timeout event will fire if
- * a timeout occurs.
- * @property timeout
- * @type int
- */
- self.timeout = 0;
-
- /**
- * A list of modules that should not be loaded, even if
- * they turn up in the dependency tree
- * @property ignore
- * @type string[]
- */
- // self.ignore = null;
-
- /**
- * A list of modules that should always be loaded, even
- * if they have already been inserted into the page.
- * @property force
- * @type string[]
- */
- // self.force = null;
-
- self.forceMap = {};
-
- /**
- * Should we allow rollups
- * @property allowRollup
- * @type boolean
- * @default false
- */
- self.allowRollup = false;
-
- /**
- * A filter to apply to result urls. This filter will modify the default
- * path for all modules. The default path for the YUI library is the
- * minified version of the files (e.g., event-min.js). The filter property
- * can be a predefined filter or a custom filter. The valid predefined
- * filters are:
- * <dl>
- * <dt>DEBUG</dt>
- * <dd>Selects the debug versions of the library (e.g., event-debug.js).
- * This option will automatically include the Logger widget</dd>
- * <dt>RAW</dt>
- * <dd>Selects the non-minified version of the library (e.g., event.js).
- * </dd>
- * </dl>
- * You can also define a custom filter, which must be an object literal
- * containing a search expression and a replace string:
- *
- * myFilter: {
- * 'searchExp': "-min\\.js",
- * 'replaceStr': "-debug.js"
- * }
- *
- * @property filter
- * @type string| {searchExp: string, replaceStr: string}
- */
- // self.filter = null;
-
- /**
- * per-component filter specification. If specified for a given
- * component, this overrides the filter config.
- * @property filters
- * @type object
- */
- self.filters = {};
-
- /**
- * The list of requested modules
- * @property required
- * @type {string: boolean}
- */
- self.required = {};
-
- /**
- * If a module name is predefined when requested, it is checked againsts
- * the patterns provided in this property. If there is a match, the
- * module is added with the default configuration.
- *
- * At the moment only supporting module prefixes, but anticipate
- * supporting at least regular expressions.
- * @property patterns
- * @type Object
- */
- // self.patterns = Y.merge(Y.Env.meta.patterns);
- self.patterns = {};
-
- /**
- * The library metadata
- * @property moduleInfo
- */
- // self.moduleInfo = Y.merge(Y.Env.meta.moduleInfo);
- self.moduleInfo = {};
-
- self.groups = Y.merge(Y.Env.meta.groups);
-
- /**
- * Provides the information used to skin the skinnable components.
- * The following skin definition would result in 'skin1' and 'skin2'
- * being loaded for calendar (if calendar was requested), and
- * 'sam' for all other skinnable components:
- *
- * skin: {
- * // The default skin, which is automatically applied if not
- * // overriden by a component-specific skin definition.
- * // Change this in to apply a different skin globally
- * defaultSkin: 'sam',
- *
- * // This is combined with the loader base property to get
- * // the default root directory for a skin. ex:
- * // http://yui.yahooapis.com/2.3.0/build/assets/skins/sam/
- * base: 'assets/skins/',
- *
- * // Any component-specific overrides can be specified here,
- * // making it possible to load different skins for different
- * // components. It is possible to load more than one skin
- * // for a given component as well.
- * overrides: {
- * calendar: ['skin1', 'skin2']
- * }
- * }
- * @property skin
- * @type {Object}
- */
- self.skin = Y.merge(Y.Env.meta.skin);
-
- /*
- * Map of conditional modules
- * @since 3.2.0
- */
- self.conditions = {};
-
- // map of modules with a hash of modules that meet the requirement
- // self.provides = {};
-
- self.config = o;
- self._internal = true;
-
- self._populateCache();
-
- /**
- * Set when beginning to compute the dependency tree.
- * Composed of what YUI reports to be loaded combined
- * with what has been loaded by any instance on the page
- * with the version number specified in the metadata.
- * @property loaded
- * @type {string: boolean}
- */
- self.loaded = GLOBAL_LOADED[VERSION];
-
-
- /**
- * Should Loader fetch scripts in `async`, defaults to `true`
- * @property async
- */
-
- self.async = true;
-
- self._inspectPage();
-
- self._internal = false;
-
- self._config(o);
-
- self.forceMap = (self.force) ? Y.Array.hash(self.force) : {};
-
- self.testresults = null;
-
- if (Y.config.tests) {
- self.testresults = Y.config.tests;
- }
-
- /**
- * List of rollup files found in the library metadata
- * @property rollups
- */
- // self.rollups = null;
-
- /**
- * Whether or not to load optional dependencies for
- * the requested modules
- * @property loadOptional
- * @type boolean
- * @default false
- */
- // self.loadOptional = false;
-
- /**
- * All of the derived dependencies in sorted order, which
- * will be populated when either calculate() or insert()
- * is called
- * @property sorted
- * @type string[]
- */
- self.sorted = [];
-
- /*
- * A list of modules to attach to the YUI instance when complete.
- * If not supplied, the sorted list of dependencies are applied.
- * @property attaching
- */
- // self.attaching = null;
-
- /**
- * Flag to indicate the dependency tree needs to be recomputed
- * if insert is called again.
- * @property dirty
- * @type boolean
- * @default true
- */
- self.dirty = true;
-
- /**
- * List of modules inserted by the utility
- * @property inserted
- * @type {string: boolean}
- */
- self.inserted = {};
-
- /**
- * List of skipped modules during insert() because the module
- * was not defined
- * @property skipped
- */
- self.skipped = {};
-
- // Y.on('yui:load', self.loadNext, self);
-
- self.tested = {};
-
- /*
- * Cached sorted calculate results
- * @property results
- * @since 3.2.0
- */
- //self.results = {};
-
- if (self.ignoreRegistered) {
- //Clear inpage already processed modules.
- self._resetModules();
- }
-
-};
-
-Y.Loader.prototype = {
- /**
- * Checks the cache for modules and conditions, if they do not exist
- * process the default metadata and populate the local moduleInfo hash.
- * @method _populateCache
- * @private
- */
- _populateCache: function() {
- var self = this,
- defaults = META.modules,
- cache = GLOBAL_ENV._renderedMods,
- i;
-
- if (cache && !self.ignoreRegistered) {
- for (i in cache) {
- if (cache.hasOwnProperty(i)) {
- self.moduleInfo[i] = Y.merge(cache[i]);
- }
- }
-
- cache = GLOBAL_ENV._conditions;
- for (i in cache) {
- if (cache.hasOwnProperty(i)) {
- self.conditions[i] = Y.merge(cache[i]);
- }
- }
-
- } else {
- for (i in defaults) {
- if (defaults.hasOwnProperty(i)) {
- self.addModule(defaults[i], i);
- }
- }
- }
-
- },
- /**
- * Reset modules in the module cache to a pre-processed state so additional
- * computations with a different skin or language will work as expected.
- * @method _resetModules
- * @private
- */
- _resetModules: function() {
- var self = this, i, o,
- mod, name, details;
- for (i in self.moduleInfo) {
- if (self.moduleInfo.hasOwnProperty(i)) {
- mod = self.moduleInfo[i];
- name = mod.name;
- details = (YUI.Env.mods[name] ? YUI.Env.mods[name].details : null);
-
- if (details) {
- self.moduleInfo[name]._reset = true;
- self.moduleInfo[name].requires = details.requires || [];
- self.moduleInfo[name].optional = details.optional || [];
- self.moduleInfo[name].supersedes = details.supercedes || [];
- }
-
- if (mod.defaults) {
- for (o in mod.defaults) {
- if (mod.defaults.hasOwnProperty(o)) {
- if (mod[o]) {
- mod[o] = mod.defaults[o];
- }
- }
- }
- }
- delete mod.langCache;
- delete mod.skinCache;
- if (mod.skinnable) {
- self._addSkin(self.skin.defaultSkin, mod.name);
- }
- }
- }
- },
- /**
- Regex that matches a CSS URL. Used to guess the file type when it's not
- specified.
-
- @property REGEX_CSS
- @type RegExp
- @final
- @protected
- @since 3.5.0
- **/
- REGEX_CSS: /\.css(?:[?;].*)?$/i,
-
- /**
- * Default filters for raw and debug
- * @property FILTER_DEFS
- * @type Object
- * @final
- * @protected
- */
- FILTER_DEFS: {
- RAW: {
- 'searchExp': '-min\\.js',
- 'replaceStr': '.js'
- },
- DEBUG: {
- 'searchExp': '-min\\.js',
- 'replaceStr': '-debug.js'
- },
- COVERAGE: {
- 'searchExp': '-min\\.js',
- 'replaceStr': '-coverage.js'
- }
- },
- /*
- * Check the pages meta-data and cache the result.
- * @method _inspectPage
- * @private
- */
- _inspectPage: function() {
- var self = this, v, m, req, mr, i;
-
- //Inspect the page for CSS only modules and mark them as loaded.
- for (i in self.moduleInfo) {
- if (self.moduleInfo.hasOwnProperty(i)) {
- v = self.moduleInfo[i];
- if (v.type && v.type === CSS) {
- if (self.isCSSLoaded(v.name)) {
- self.loaded[i] = true;
- }
- }
- }
- }
- for (i in ON_PAGE) {
- if (ON_PAGE.hasOwnProperty(i)) {
- v = ON_PAGE[i];
- if (v.details) {
- m = self.moduleInfo[v.name];
- req = v.details.requires;
- mr = m && m.requires;
-
- if (m) {
- if (!m._inspected && req && mr.length !== req.length) {
- // console.log('deleting ' + m.name);
- delete m.expanded;
- }
- } else {
- m = self.addModule(v.details, i);
- }
- m._inspected = true;
- }
- }
- }
- },
- /*
- * returns true if b is not loaded, and is required directly or by means of modules it supersedes.
- * @private
- * @method _requires
- * @param {String} mod1 The first module to compare
- * @param {String} mod2 The second module to compare
- */
- _requires: function(mod1, mod2) {
-
- var i, rm, after_map, s,
- info = this.moduleInfo,
- m = info[mod1],
- other = info[mod2];
-
- if (!m || !other) {
- return false;
- }
-
- rm = m.expanded_map;
- after_map = m.after_map;
-
- // check if this module should be sorted after the other
- // do this first to short circut circular deps
- if (after_map && (mod2 in after_map)) {
- return true;
- }
-
- after_map = other.after_map;
-
- // and vis-versa
- if (after_map && (mod1 in after_map)) {
- return false;
- }
-
- // check if this module requires one the other supersedes
- s = info[mod2] && info[mod2].supersedes;
- if (s) {
- for (i = 0; i < s.length; i++) {
- if (this._requires(mod1, s[i])) {
- return true;
- }
- }
- }
-
- s = info[mod1] && info[mod1].supersedes;
- if (s) {
- for (i = 0; i < s.length; i++) {
- if (this._requires(mod2, s[i])) {
- return false;
- }
- }
- }
-
- // check if this module requires the other directly
- // if (r && yArray.indexOf(r, mod2) > -1) {
- if (rm && (mod2 in rm)) {
- return true;
- }
-
- // external css files should be sorted below yui css
- if (m.ext && m.type === CSS && !other.ext && other.type === CSS) {
- return true;
- }
-
- return false;
- },
- /**
- * Apply a new config to the Loader instance
- * @method _config
- * @private
- * @param {Object} o The new configuration
- */
- _config: function(o) {
- var i, j, val, a, f, group, groupName, self = this,
- mods = [], mod;
- // apply config values
- if (o) {
- for (i in o) {
- if (o.hasOwnProperty(i)) {
- val = o[i];
- //TODO This should be a case
- if (i === 'require') {
- self.require(val);
- } else if (i === 'skin') {
- //If the config.skin is a string, format to the expected object
- if (typeof val === 'string') {
- self.skin.defaultSkin = o.skin;
- val = {
- defaultSkin: val
- };
- }
-
- Y.mix(self.skin, val, true);
- } else if (i === 'groups') {
- for (j in val) {
- if (val.hasOwnProperty(j)) {
- groupName = j;
- group = val[j];
- self.addGroup(group, groupName);
- if (group.aliases) {
- for (a in group.aliases) {
- if (group.aliases.hasOwnProperty(a)) {
- self.addAlias(group.aliases[a], a);
- }
- }
- }
- }
- }
-
- } else if (i === 'modules') {
- // add a hash of module definitions
- for (j in val) {
- if (val.hasOwnProperty(j)) {
- self.addModule(val[j], j);
- }
- }
- } else if (i === 'aliases') {
- for (j in val) {
- if (val.hasOwnProperty(j)) {
- self.addAlias(val[j], j);
- }
- }
- } else if (i === 'gallery') {
- if (this.groups.gallery.update) {
- this.groups.gallery.update(val, o);
- }
- } else if (i === 'yui2' || i === '2in3') {
- if (this.groups.yui2.update) {
- this.groups.yui2.update(o['2in3'], o.yui2, o);
- }
- } else {
- self[i] = val;
- }
- }
- }
- }
-
- // fix filter
- f = self.filter;
-
- if (L.isString(f)) {
- f = f.toUpperCase();
- self.filterName = f;
- self.filter = self.FILTER_DEFS[f];
- if (f === 'DEBUG') {
- self.require('yui-log', 'dump');
- }
- }
-
- if (self.filterName && self.coverage) {
- if (self.filterName === 'COVERAGE' && L.isArray(self.coverage) && self.coverage.length) {
- for (i = 0; i < self.coverage.length; i++) {
- mod = self.coverage[i];
- if (self.moduleInfo[mod] && self.moduleInfo[mod].use) {
- mods = [].concat(mods, self.moduleInfo[mod].use);
- } else {
- mods.push(mod);
- }
- }
- self.filters = self.filters || {};
- Y.Array.each(mods, function(mod) {
- self.filters[mod] = self.FILTER_DEFS.COVERAGE;
- });
- self.filterName = 'RAW';
- self.filter = self.FILTER_DEFS[self.filterName];
- }
- }
-
- },
-
- /**
- * Returns the skin module name for the specified skin name. If a
- * module name is supplied, the returned skin module name is
- * specific to the module passed in.
- * @method formatSkin
- * @param {string} skin the name of the skin.
- * @param {string} mod optional: the name of a module to skin.
- * @return {string} the full skin module name.
- */
- formatSkin: function(skin, mod) {
- var s = SKIN_PREFIX + skin;
- if (mod) {
- s = s + '-' + mod;
- }
-
- return s;
- },
-
- /**
- * Adds the skin def to the module info
- * @method _addSkin
- * @param {string} skin the name of the skin.
- * @param {string} mod the name of the module.
- * @param {string} parent parent module if this is a skin of a
- * submodule or plugin.
- * @return {string} the module name for the skin.
- * @private
- */
- _addSkin: function(skin, mod, parent) {
- var mdef, pkg, name, nmod,
- info = this.moduleInfo,
- sinf = this.skin,
- ext = info[mod] && info[mod].ext;
-
- // Add a module definition for the module-specific skin css
- if (mod) {
- name = this.formatSkin(skin, mod);
- if (!info[name]) {
- mdef = info[mod];
- pkg = mdef.pkg || mod;
- nmod = {
- skin: true,
- name: name,
- group: mdef.group,
- type: 'css',
- after: sinf.after,
- path: (parent || pkg) + '/' + sinf.base + skin +
- '/' + mod + '.css',
- ext: ext
- };
- if (mdef.base) {
- nmod.base = mdef.base;
- }
- if (mdef.configFn) {
- nmod.configFn = mdef.configFn;
- }
- this.addModule(nmod, name);
-
- }
- }
-
- return name;
- },
- /**
- * Adds an alias module to the system
- * @method addAlias
- * @param {Array} use An array of modules that makes up this alias
- * @param {String} name The name of the alias
- * @example
- * var loader = new Y.Loader({});
- * loader.addAlias([ 'node', 'yql' ], 'davglass');
- * loader.require(['davglass']);
- * var out = loader.resolve(true);
- *
- * //out.js will contain Node and YQL modules
- */
- addAlias: function(use, name) {
- YUI.Env.aliases[name] = use;
- this.addModule({
- name: name,
- use: use
- });
- },
- /**
- * Add a new module group
- * @method addGroup
- * @param {Object} config An object containing the group configuration data
- * @param {String} config.name required, the group name
- * @param {String} config.base The base directory for this module group
- * @param {String} config.root The root path to add to each combo resource path
- * @param {Boolean} config.combine Should the request be combined
- * @param {String} config.comboBase Combo service base path
- * @param {Object} config.modules The group of modules
- * @param {String} name the group name.
- * @example
- * var loader = new Y.Loader({});
- * loader.addGroup({
- * name: 'davglass',
- * combine: true,
- * comboBase: '/combo?',
- * root: '',
- * modules: {
- * //Module List here
- * }
- * }, 'davglass');
- */
- addGroup: function(o, name) {
- var mods = o.modules,
- self = this, i, v;
-
- name = name || o.name;
- o.name = name;
- self.groups[name] = o;
-
- if (o.patterns) {
- for (i in o.patterns) {
- if (o.patterns.hasOwnProperty(i)) {
- o.patterns[i].group = name;
- self.patterns[i] = o.patterns[i];
- }
- }
- }
-
- if (mods) {
- for (i in mods) {
- if (mods.hasOwnProperty(i)) {
- v = mods[i];
- if (typeof v === 'string') {
- v = { name: i, fullpath: v };
- }
- v.group = name;
- self.addModule(v, i);
- }
- }
- }
- },
-
- /**
- * Add a new module to the component metadata.
- * @method addModule
- * @param {Object} config An object containing the module data.
- * @param {String} config.name Required, the component name
- * @param {String} config.type Required, the component type (js or css)
- * @param {String} config.path Required, the path to the script from `base`
- * @param {Array} config.requires Array of modules required by this component
- * @param {Array} [config.optional] Array of optional modules for this component
- * @param {Array} [config.supersedes] Array of the modules this component replaces
- * @param {Array} [config.after] Array of modules the components which, if present, should be sorted above this one
- * @param {Object} [config.after_map] Faster alternative to 'after' -- supply a hash instead of an array
- * @param {Number} [config.rollup] The number of superseded modules required for automatic rollup
- * @param {String} [config.fullpath] If `fullpath` is specified, this is used instead of the configured `base + path`
- * @param {Boolean} [config.skinnable] Flag to determine if skin assets should automatically be pulled in
- * @param {Object} [config.submodules] Hash of submodules
- * @param {String} [config.group] The group the module belongs to -- this is set automatically when it is added as part of a group configuration.
- * @param {Array} [config.lang] Array of BCP 47 language tags of languages for which this module has localized resource bundles, e.g., `["en-GB", "zh-Hans-CN"]`
- * @param {Object} [config.condition] Specifies that the module should be loaded automatically if a condition is met. This is an object with up to four fields:
- * @param {String} [config.condition.trigger] The name of a module that can trigger the auto-load
- * @param {Function} [config.condition.test] A function that returns true when the module is to be loaded.
- * @param {String} [config.condition.ua] The UA name of <a href="UA.html">Y.UA</a> object that returns true when the module is to be loaded. e.g., `"ie"`, `"nodejs"`.
- * @param {String} [config.condition.when] Specifies the load order of the conditional module
- * with regard to the position of the trigger module.
- * This should be one of three values: `before`, `after`, or `instead`. The default is `after`.
- * @param {Object} [config.testresults] A hash of test results from `Y.Features.all()`
- * @param {Function} [config.configFn] A function to exectute when configuring this module
- * @param {Object} config.configFn.mod The module config, modifying this object will modify it's config. Returning false will delete the module's config.
- * @param {String} [name] The module name, required if not in the module data.
- * @return {Object} the module definition or null if the object passed in did not provide all required attributes.
- */
- addModule: function(o, name) {
- name = name || o.name;
-
- if (typeof o === 'string') {
- o = { name: name, fullpath: o };
- }
-
-
- var subs, i, l, t, sup, s, smod, plugins, plug,
- j, langs, packName, supName, flatSup, flatLang, lang, ret,
- overrides, skinname, when, g, p,
- conditions = this.conditions, trigger;
-
- //Only merge this data if the temp flag is set
- //from an earlier pass from a pattern or else
- //an override module (YUI_config) can not be used to
- //replace a default module.
- if (this.moduleInfo[name] && this.moduleInfo[name].temp) {
- //This catches temp modules loaded via a pattern
- // The module will be added twice, once from the pattern and
- // Once from the actual add call, this ensures that properties
- // that were added to the module the first time around (group: gallery)
- // are also added the second time around too.
- o = Y.merge(this.moduleInfo[name], o);
- }
-
- o.name = name;
-
- if (!o || !o.name) {
- return null;
- }
-
- if (!o.type) {
- //Always assume it's javascript unless the CSS pattern is matched.
- o.type = JS;
- p = o.path || o.fullpath;
- if (p && this.REGEX_CSS.test(p)) {
- o.type = CSS;
- }
- }
-
- if (!o.path && !o.fullpath) {
- o.path = _path(name, name, o.type);
- }
- o.supersedes = o.supersedes || o.use;
-
- o.ext = ('ext' in o) ? o.ext : (this._internal) ? false : true;
-
- // Handle submodule logic
- subs = o.submodules;
-
- this.moduleInfo[name] = o;
-
- o.requires = o.requires || [];
-
- /*
- Only allowing the cascade of requires information, since
- optional and supersedes are far more fine grained than
- a blanket requires is.
- */
- if (this.requires) {
- for (i = 0; i < this.requires.length; i++) {
- o.requires.push(this.requires[i]);
- }
- }
- if (o.group && this.groups && this.groups[o.group]) {
- g = this.groups[o.group];
- if (g.requires) {
- for (i = 0; i < g.requires.length; i++) {
- o.requires.push(g.requires[i]);
- }
- }
- }
-
-
- if (!o.defaults) {
- o.defaults = {
- requires: o.requires ? [].concat(o.requires) : null,
- supersedes: o.supersedes ? [].concat(o.supersedes) : null,
- optional: o.optional ? [].concat(o.optional) : null
- };
- }
-
- if (o.skinnable && o.ext && o.temp) {
- skinname = this._addSkin(this.skin.defaultSkin, name);
- o.requires.unshift(skinname);
- }
-
- if (o.requires.length) {
- o.requires = this.filterRequires(o.requires) || [];
- }
-
- if (!o.langPack && o.lang) {
- langs = yArray(o.lang);
- for (j = 0; j < langs.length; j++) {
- lang = langs[j];
- packName = this.getLangPackName(lang, name);
- smod = this.moduleInfo[packName];
- if (!smod) {
- smod = this._addLangPack(lang, o, packName);
- }
- }
- }
-
-
- if (subs) {
- sup = o.supersedes || [];
- l = 0;
-
- for (i in subs) {
- if (subs.hasOwnProperty(i)) {
- s = subs[i];
-
- s.path = s.path || _path(name, i, o.type);
- s.pkg = name;
- s.group = o.group;
-
- if (s.supersedes) {
- sup = sup.concat(s.supersedes);
- }
-
- smod = this.addModule(s, i);
- sup.push(i);
-
- if (smod.skinnable) {
- o.skinnable = true;
- overrides = this.skin.overrides;
- if (overrides && overrides[i]) {
- for (j = 0; j < overrides[i].length; j++) {
- skinname = this._addSkin(overrides[i][j],
- i, name);
- sup.push(skinname);
- }
- }
- skinname = this._addSkin(this.skin.defaultSkin,
- i, name);
- sup.push(skinname);
- }
-
- // looks like we are expected to work out the metadata
- // for the parent module language packs from what is
- // specified in the child modules.
- if (s.lang && s.lang.length) {
-
- langs = yArray(s.lang);
- for (j = 0; j < langs.length; j++) {
- lang = langs[j];
- packName = this.getLangPackName(lang, name);
- supName = this.getLangPackName(lang, i);
- smod = this.moduleInfo[packName];
-
- if (!smod) {
- smod = this._addLangPack(lang, o, packName);
- }
-
- flatSup = flatSup || yArray.hash(smod.supersedes);
-
- if (!(supName in flatSup)) {
- smod.supersedes.push(supName);
- }
-
- o.lang = o.lang || [];
-
- flatLang = flatLang || yArray.hash(o.lang);
-
- if (!(lang in flatLang)) {
- o.lang.push(lang);
- }
-
-// Add rollup file, need to add to supersedes list too
-
- // default packages
- packName = this.getLangPackName(ROOT_LANG, name);
- supName = this.getLangPackName(ROOT_LANG, i);
-
- smod = this.moduleInfo[packName];
-
- if (!smod) {
- smod = this._addLangPack(lang, o, packName);
- }
-
- if (!(supName in flatSup)) {
- smod.supersedes.push(supName);
- }
-
-// Add rollup file, need to add to supersedes list too
-
- }
- }
-
- l++;
- }
- }
- //o.supersedes = YObject.keys(yArray.hash(sup));
- o.supersedes = yArray.dedupe(sup);
- if (this.allowRollup) {
- o.rollup = (l < 4) ? l : Math.min(l - 1, 4);
- }
- }
-
- plugins = o.plugins;
- if (plugins) {
- for (i in plugins) {
- if (plugins.hasOwnProperty(i)) {
- plug = plugins[i];
- plug.pkg = name;
- plug.path = plug.path || _path(name, i, o.type);
- plug.requires = plug.requires || [];
- plug.group = o.group;
- this.addModule(plug, i);
- if (o.skinnable) {
- this._addSkin(this.skin.defaultSkin, i, name);
- }
-
- }
- }
- }
-
- if (o.condition) {
- t = o.condition.trigger;
- if (YUI.Env.aliases[t]) {
- t = YUI.Env.aliases[t];
- }
- if (!Y.Lang.isArray(t)) {
- t = [t];
- }
-
- for (i = 0; i < t.length; i++) {
- trigger = t[i];
- when = o.condition.when;
- conditions[trigger] = conditions[trigger] || {};
- conditions[trigger][name] = o.condition;
- // the 'when' attribute can be 'before', 'after', or 'instead'
- // the default is after.
- if (when && when !== 'after') {
- if (when === 'instead') { // replace the trigger
- o.supersedes = o.supersedes || [];
- o.supersedes.push(trigger);
- }
- // before the trigger
- // the trigger requires the conditional mod,
- // so it should appear before the conditional
- // mod if we do not intersede.
- } else { // after the trigger
- o.after = o.after || [];
- o.after.push(trigger);
- }
- }
- }
-
- if (o.supersedes) {
- o.supersedes = this.filterRequires(o.supersedes);
- }
-
- if (o.after) {
- o.after = this.filterRequires(o.after);
- o.after_map = yArray.hash(o.after);
- }
-
- // this.dirty = true;
-
- if (o.configFn) {
- ret = o.configFn(o);
- if (ret === false) {
- delete this.moduleInfo[name];
- delete GLOBAL_ENV._renderedMods[name];
- o = null;
- }
- }
- //Add to global cache
- if (o) {
- if (!GLOBAL_ENV._renderedMods) {
- GLOBAL_ENV._renderedMods = {};
- }
- GLOBAL_ENV._renderedMods[name] = Y.mix(GLOBAL_ENV._renderedMods[name] || {}, o);
- GLOBAL_ENV._conditions = conditions;
- }
-
- return o;
- },
-
- /**
- * Add a requirement for one or more module
- * @method require
- * @param {string[] | string*} what the modules to load.
- */
- require: function(what) {
- var a = (typeof what === 'string') ? yArray(arguments) : what;
- this.dirty = true;
- this.required = Y.merge(this.required, yArray.hash(this.filterRequires(a)));
-
- this._explodeRollups();
- },
- /**
- * Grab all the items that were asked for, check to see if the Loader
- * meta-data contains a "use" array. If it doesm remove the asked item and replace it with
- * the content of the "use".
- * This will make asking for: "dd"
- * Actually ask for: "dd-ddm-base,dd-ddm,dd-ddm-drop,dd-drag,dd-proxy,dd-constrain,dd-drop,dd-scroll,dd-drop-plugin"
- * @private
- * @method _explodeRollups
- */
- _explodeRollups: function() {
- var self = this, m, m2, i, a, v, len, len2,
- r = self.required;
-
- if (!self.allowRollup) {
- for (i in r) {
- if (r.hasOwnProperty(i)) {
- m = self.getModule(i);
- if (m && m.use) {
- len = m.use.length;
- for (a = 0; a < len; a++) {
- m2 = self.getModule(m.use[a]);
- if (m2 && m2.use) {
- len2 = m2.use.length;
- for (v = 0; v < len2; v++) {
- r[m2.use[v]] = true;
- }
- } else {
- r[m.use[a]] = true;
- }
- }
- }
- }
- }
- self.required = r;
- }
-
- },
- /**
- * Explodes the required array to remove aliases and replace them with real modules
- * @method filterRequires
- * @param {Array} r The original requires array
- * @return {Array} The new array of exploded requirements
- */
- filterRequires: function(r) {
- if (r) {
- if (!Y.Lang.isArray(r)) {
- r = [r];
- }
- r = Y.Array(r);
- var c = [], i, mod, o, m;
-
- for (i = 0; i < r.length; i++) {
- mod = this.getModule(r[i]);
- if (mod && mod.use) {
- for (o = 0; o < mod.use.length; o++) {
- //Must walk the other modules in case a module is a rollup of rollups (datatype)
- m = this.getModule(mod.use[o]);
- if (m && m.use && (m.name !== mod.name)) {
- c = Y.Array.dedupe([].concat(c, this.filterRequires(m.use)));
- } else {
- c.push(mod.use[o]);
- }
- }
- } else {
- c.push(r[i]);
- }
- }
- r = c;
- }
- return r;
- },
- /**
- * Returns an object containing properties for all modules required
- * in order to load the requested module
- * @method getRequires
- * @param {object} mod The module definition from moduleInfo.
- * @return {array} the expanded requirement list.
- */
- getRequires: function(mod) {
-
- if (!mod) {
- //console.log('returning no reqs for ' + mod.name);
- return NO_REQUIREMENTS;
- }
-
- if (mod._parsed) {
- //console.log('returning requires for ' + mod.name, mod.requires);
- return mod.expanded || NO_REQUIREMENTS;
- }
-
- //TODO add modue cache here out of scope..
-
- var i, m, j, add, packName, lang, testresults = this.testresults,
- name = mod.name, cond,
- adddef = ON_PAGE[name] && ON_PAGE[name].details,
- d, go, def,
- r, old_mod,
- o, skinmod, skindef, skinpar, skinname,
- intl = mod.lang || mod.intl,
- info = this.moduleInfo,
- ftests = Y.Features && Y.Features.tests.load,
- hash, reparse;
-
- // console.log(name);
-
- // pattern match leaves module stub that needs to be filled out
- if (mod.temp && adddef) {
- old_mod = mod;
- mod = this.addModule(adddef, name);
- mod.group = old_mod.group;
- mod.pkg = old_mod.pkg;
- delete mod.expanded;
- }
-
- // console.log('cache: ' + mod.langCache + ' == ' + this.lang);
-
- //If a skin or a lang is different, reparse..
- reparse = !((!this.lang || mod.langCache === this.lang) && (mod.skinCache === this.skin.defaultSkin));
-
- if (mod.expanded && !reparse) {
- return mod.expanded;
- }
-
-
- d = [];
- hash = {};
- r = this.filterRequires(mod.requires);
- if (mod.lang) {
- //If a module has a lang attribute, auto add the intl requirement.
- d.unshift('intl');
- r.unshift('intl');
- intl = true;
- }
- o = this.filterRequires(mod.optional);
-
-
- mod._parsed = true;
- mod.langCache = this.lang;
- mod.skinCache = this.skin.defaultSkin;
-
- for (i = 0; i < r.length; i++) {
- if (!hash[r[i]]) {
- d.push(r[i]);
- hash[r[i]] = true;
- m = this.getModule(r[i]);
- if (m) {
- add = this.getRequires(m);
- intl = intl || (m.expanded_map &&
- (INTL in m.expanded_map));
- for (j = 0; j < add.length; j++) {
- d.push(add[j]);
- }
- }
- }
- }
-
- // get the requirements from superseded modules, if any
- r = this.filterRequires(mod.supersedes);
- if (r) {
- for (i = 0; i < r.length; i++) {
- if (!hash[r[i]]) {
- // if this module has submodules, the requirements list is
- // expanded to include the submodules. This is so we can
- // prevent dups when a submodule is already loaded and the
- // parent is requested.
- if (mod.submodules) {
- d.push(r[i]);
- }
-
- hash[r[i]] = true;
- m = this.getModule(r[i]);
-
- if (m) {
- add = this.getRequires(m);
- intl = intl || (m.expanded_map &&
- (INTL in m.expanded_map));
- for (j = 0; j < add.length; j++) {
- d.push(add[j]);
- }
- }
- }
- }
- }
-
- if (o && this.loadOptional) {
- for (i = 0; i < o.length; i++) {
- if (!hash[o[i]]) {
- d.push(o[i]);
- hash[o[i]] = true;
- m = info[o[i]];
- if (m) {
- add = this.getRequires(m);
- intl = intl || (m.expanded_map &&
- (INTL in m.expanded_map));
- for (j = 0; j < add.length; j++) {
- d.push(add[j]);
- }
- }
- }
- }
- }
-
- cond = this.conditions[name];
-
- if (cond) {
- //Set the module to not parsed since we have conditionals and this could change the dependency tree.
- mod._parsed = false;
- if (testresults && ftests) {
- oeach(testresults, function(result, id) {
- var condmod = ftests[id].name;
- if (!hash[condmod] && ftests[id].trigger === name) {
- if (result && ftests[id]) {
- hash[condmod] = true;
- d.push(condmod);
- }
- }
- });
- } else {
- for (i in cond) {
- if (cond.hasOwnProperty(i)) {
- if (!hash[i]) {
- def = cond[i];
- //first see if they've specfied a ua check
- //then see if they've got a test fn & if it returns true
- //otherwise just having a condition block is enough
- go = def && ((!def.ua && !def.test) || (def.ua && Y.UA[def.ua]) ||
- (def.test && def.test(Y, r)));
-
- if (go) {
- hash[i] = true;
- d.push(i);
- m = this.getModule(i);
- if (m) {
- add = this.getRequires(m);
- for (j = 0; j < add.length; j++) {
- d.push(add[j]);
- }
-
- }
- }
- }
- }
- }
- }
- }
-
- // Create skin modules
- if (mod.skinnable) {
- skindef = this.skin.overrides;
- for (i in YUI.Env.aliases) {
- if (YUI.Env.aliases.hasOwnProperty(i)) {
- if (Y.Array.indexOf(YUI.Env.aliases[i], name) > -1) {
- skinpar = i;
- }
- }
- }
- if (skindef && (skindef[name] || (skinpar && skindef[skinpar]))) {
- skinname = name;
- if (skindef[skinpar]) {
- skinname = skinpar;
- }
- for (i = 0; i < skindef[skinname].length; i++) {
- skinmod = this._addSkin(skindef[skinname][i], name);
- if (!this.isCSSLoaded(skinmod, this._boot)) {
- d.push(skinmod);
- }
- }
- } else {
- skinmod = this._addSkin(this.skin.defaultSkin, name);
- if (!this.isCSSLoaded(skinmod, this._boot)) {
- d.push(skinmod);
- }
- }
- }
-
- mod._parsed = false;
-
- if (intl) {
-
- if (mod.lang && !mod.langPack && Y.Intl) {
- lang = Y.Intl.lookupBestLang(this.lang || ROOT_LANG, mod.lang);
- packName = this.getLangPackName(lang, name);
- if (packName) {
- d.unshift(packName);
- }
- }
- d.unshift(INTL);
- }
-
- mod.expanded_map = yArray.hash(d);
-
- mod.expanded = YObject.keys(mod.expanded_map);
-
- return mod.expanded;
- },
- /**
- * Check to see if named css module is already loaded on the page
- * @method isCSSLoaded
- * @param {String} name The name of the css file
- * @return Boolean
- */
- isCSSLoaded: function(name, skip) {
- //TODO - Make this call a batching call with name being an array
- if (!name || !YUI.Env.cssStampEl || (!skip && this.ignoreRegistered)) {
- return false;
- }
- var el = YUI.Env.cssStampEl,
- ret = false,
- mod = YUI.Env._cssLoaded[name],
- style = el.currentStyle; //IE
-
-
- if (mod !== undefined) {
- return mod;
- }
-
- //Add the classname to the element
- el.className = name;
-
- if (!style) {
- style = Y.config.doc.defaultView.getComputedStyle(el, null);
- }
-
- if (style && style.display === 'none') {
- ret = true;
- }
-
-
- el.className = ''; //Reset the classname to ''
-
- YUI.Env._cssLoaded[name] = ret;
-
- return ret;
- },
-
- /**
- * Returns a hash of module names the supplied module satisfies.
- * @method getProvides
- * @param {string} name The name of the module.
- * @return {object} what this module provides.
- */
- getProvides: function(name) {
- var m = this.getModule(name), o, s;
- // supmap = this.provides;
-
- if (!m) {
- return NOT_FOUND;
- }
-
- if (m && !m.provides) {
- o = {};
- s = m.supersedes;
-
- if (s) {
- yArray.each(s, function(v) {
- Y.mix(o, this.getProvides(v));
- }, this);
- }
-
- o[name] = true;
- m.provides = o;
-
- }
-
- return m.provides;
- },
-
- /**
- * Calculates the dependency tree, the result is stored in the sorted
- * property.
- * @method calculate
- * @param {object} o optional options object.
- * @param {string} type optional argument to prune modules.
- */
- calculate: function(o, type) {
- if (o || type || this.dirty) {
-
- if (o) {
- this._config(o);
- }
-
- if (!this._init) {
- this._setup();
- }
-
- this._explode();
-
- if (this.allowRollup) {
- this._rollup();
- } else {
- this._explodeRollups();
- }
- this._reduce();
- this._sort();
- }
- },
- /**
- * Creates a "psuedo" package for languages provided in the lang array
- * @method _addLangPack
- * @private
- * @param {String} lang The language to create
- * @param {Object} m The module definition to create the language pack around
- * @param {String} packName The name of the package (e.g: lang/datatype-date-en-US)
- * @return {Object} The module definition
- */
- _addLangPack: function(lang, m, packName) {
- var name = m.name,
- packPath, conf,
- existing = this.moduleInfo[packName];
-
- if (!existing) {
-
- packPath = _path((m.pkg || name), packName, JS, true);
-
- conf = {
- path: packPath,
- intl: true,
- langPack: true,
- ext: m.ext,
- group: m.group,
- supersedes: []
- };
- if (m.root) {
- conf.root = m.root;
- }
- if (m.base) {
- conf.base = m.base;
- }
-
- if (m.configFn) {
- conf.configFn = m.configFn;
- }
-
- this.addModule(conf, packName);
-
- if (lang) {
- Y.Env.lang = Y.Env.lang || {};
- Y.Env.lang[lang] = Y.Env.lang[lang] || {};
- Y.Env.lang[lang][name] = true;
- }
- }
-
- return this.moduleInfo[packName];
- },
-
- /**
- * Investigates the current YUI configuration on the page. By default,
- * modules already detected will not be loaded again unless a force
- * option is encountered. Called by calculate()
- * @method _setup
- * @private
- */
- _setup: function() {
- var info = this.moduleInfo, name, i, j, m, l,
- packName;
-
- for (name in info) {
- if (info.hasOwnProperty(name)) {
- m = info[name];
- if (m) {
-
- // remove dups
- //m.requires = YObject.keys(yArray.hash(m.requires));
- m.requires = yArray.dedupe(m.requires);
-
- // Create lang pack modules
- //if (m.lang && m.lang.length) {
- if (m.lang) {
- // Setup root package if the module has lang defined,
- // it needs to provide a root language pack
- packName = this.getLangPackName(ROOT_LANG, name);
- this._addLangPack(null, m, packName);
- }
-
- }
- }
- }
-
-
- //l = Y.merge(this.inserted);
- l = {};
-
- // available modules
- if (!this.ignoreRegistered) {
- Y.mix(l, GLOBAL_ENV.mods);
- }
-
- // add the ignore list to the list of loaded packages
- if (this.ignore) {
- Y.mix(l, yArray.hash(this.ignore));
- }
-
- // expand the list to include superseded modules
- for (j in l) {
- if (l.hasOwnProperty(j)) {
- Y.mix(l, this.getProvides(j));
- }
- }
-
- // remove modules on the force list from the loaded list
- if (this.force) {
- for (i = 0; i < this.force.length; i++) {
- if (this.force[i] in l) {
- delete l[this.force[i]];
- }
- }
- }
-
- Y.mix(this.loaded, l);
-
- this._init = true;
- },
-
- /**
- * Builds a module name for a language pack
- * @method getLangPackName
- * @param {string} lang the language code.
- * @param {string} mname the module to build it for.
- * @return {string} the language pack module name.
- */
- getLangPackName: function(lang, mname) {
- return ('lang/' + mname + ((lang) ? '_' + lang : ''));
- },
- /**
- * Inspects the required modules list looking for additional
- * dependencies. Expands the required list to include all
- * required modules. Called by calculate()
- * @method _explode
- * @private
- */
- _explode: function() {
- //TODO Move done out of scope
- var r = this.required, m, reqs, done = {},
- self = this, name, expound;
-
- // the setup phase is over, all modules have been created
- self.dirty = false;
-
- self._explodeRollups();
- r = self.required;
-
- for (name in r) {
- if (r.hasOwnProperty(name)) {
- if (!done[name]) {
- done[name] = true;
- m = self.getModule(name);
- if (m) {
- expound = m.expound;
-
- if (expound) {
- r[expound] = self.getModule(expound);
- reqs = self.getRequires(r[expound]);
- Y.mix(r, yArray.hash(reqs));
- }
-
- reqs = self.getRequires(m);
- Y.mix(r, yArray.hash(reqs));
- }
- }
- }
- }
-
- },
- /**
- * The default method used to test a module against a pattern
- * @method _patternTest
- * @private
- * @param {String} mname The module being tested
- * @param {String} pname The pattern to match
- */
- _patternTest: function(mname, pname) {
- return (mname.indexOf(pname) > -1);
- },
- /**
- * Get's the loader meta data for the requested module
- * @method getModule
- * @param {String} mname The module name to get
- * @return {Object} The module metadata
- */
- getModule: function(mname) {
- //TODO: Remove name check - it's a quick hack to fix pattern WIP
- if (!mname) {
- return null;
- }
-
- var p, found, pname,
- m = this.moduleInfo[mname],
- patterns = this.patterns;
-
- // check the patterns library to see if we should automatically add
- // the module with defaults
- if (!m || (m && m.ext)) {
- for (pname in patterns) {
- if (patterns.hasOwnProperty(pname)) {
- p = patterns[pname];
-
- //There is no test method, create a default one that tests
- // the pattern against the mod name
- if (!p.test) {
- p.test = this._patternTest;
- }
-
- if (p.test(mname, pname)) {
- // use the metadata supplied for the pattern
- // as the module definition.
- found = p;
- break;
- }
- }
- }
- }
-
- if (!m) {
- if (found) {
- if (p.action) {
- p.action.call(this, mname, pname);
- } else {
- // ext true or false?
- m = this.addModule(Y.merge(found), mname);
- if (found.configFn) {
- m.configFn = found.configFn;
- }
- m.temp = true;
- }
- }
- } else {
- if (found && m && found.configFn && !m.configFn) {
- m.configFn = found.configFn;
- m.configFn(m);
- }
- }
-
- return m;
- },
-
- // impl in rollup submodule
- _rollup: function() { },
-
- /**
- * Remove superceded modules and loaded modules. Called by
- * calculate() after we have the mega list of all dependencies
- * @method _reduce
- * @return {object} the reduced dependency hash.
- * @private
- */
- _reduce: function(r) {
-
- r = r || this.required;
-
- var i, j, s, m, type = this.loadType,
- ignore = this.ignore ? yArray.hash(this.ignore) : false;
-
- for (i in r) {
- if (r.hasOwnProperty(i)) {
- m = this.getModule(i);
- // remove if already loaded
- if (((this.loaded[i] || ON_PAGE[i]) &&
- !this.forceMap[i] && !this.ignoreRegistered) ||
- (type && m && m.type !== type)) {
- delete r[i];
- }
- if (ignore && ignore[i]) {
- delete r[i];
- }
- // remove anything this module supersedes
- s = m && m.supersedes;
- if (s) {
- for (j = 0; j < s.length; j++) {
- if (s[j] in r) {
- delete r[s[j]];
- }
- }
- }
- }
- }
-
- return r;
- },
- /**
- * Handles the queue when a module has been loaded for all cases
- * @method _finish
- * @private
- * @param {String} msg The message from Loader
- * @param {Boolean} success A boolean denoting success or failure
- */
- _finish: function(msg, success) {
-
- _queue.running = false;
-
- var onEnd = this.onEnd;
- if (onEnd) {
- onEnd.call(this.context, {
- msg: msg,
- data: this.data,
- success: success
- });
- }
- this._continue();
- },
- /**
- * The default Loader onSuccess handler, calls this.onSuccess with a payload
- * @method _onSuccess
- * @private
- */
- _onSuccess: function() {
- var self = this, skipped = Y.merge(self.skipped), fn,
- failed = [], rreg = self.requireRegistration,
- success, msg, i, mod;
-
- for (i in skipped) {
- if (skipped.hasOwnProperty(i)) {
- delete self.inserted[i];
- }
- }
-
- self.skipped = {};
-
- for (i in self.inserted) {
- if (self.inserted.hasOwnProperty(i)) {
- mod = self.getModule(i);
- if (mod && rreg && mod.type === JS && !(i in YUI.Env.mods)) {
- failed.push(i);
- } else {
- Y.mix(self.loaded, self.getProvides(i));
- }
- }
- }
-
- fn = self.onSuccess;
- msg = (failed.length) ? 'notregistered' : 'success';
- success = !(failed.length);
- if (fn) {
- fn.call(self.context, {
- msg: msg,
- data: self.data,
- success: success,
- failed: failed,
- skipped: skipped
- });
- }
- self._finish(msg, success);
- },
- /**
- * The default Loader onProgress handler, calls this.onProgress with a payload
- * @method _onProgress
- * @private
- */
- _onProgress: function(e) {
- var self = this, i;
- //set the internal cache to what just came in.
- if (e.data && e.data.length) {
- for (i = 0; i < e.data.length; i++) {
- e.data[i] = self.getModule(e.data[i].name);
- }
- }
- if (self.onProgress) {
- self.onProgress.call(self.context, {
- name: e.url,
- data: e.data
- });
- }
- },
- /**
- * The default Loader onFailure handler, calls this.onFailure with a payload
- * @method _onFailure
- * @private
- */
- _onFailure: function(o) {
- var f = this.onFailure, msg = [], i = 0, len = o.errors.length;
-
- for (i; i < len; i++) {
- msg.push(o.errors[i].error);
- }
-
- msg = msg.join(',');
-
-
- if (f) {
- f.call(this.context, {
- msg: msg,
- data: this.data,
- success: false
- });
- }
-
- this._finish(msg, false);
-
- },
-
- /**
- * The default Loader onTimeout handler, calls this.onTimeout with a payload
- * @method _onTimeout
- * @param {Get.Transaction} transaction The Transaction object from `Y.Get`
- * @private
- */
- _onTimeout: function(transaction) {
- var f = this.onTimeout;
- if (f) {
- f.call(this.context, {
- msg: 'timeout',
- data: this.data,
- success: false,
- transaction: transaction
- });
- }
- },
-
- /**
- * Sorts the dependency tree. The last step of calculate()
- * @method _sort
- * @private
- */
- _sort: function() {
-
- // create an indexed list
- var s = YObject.keys(this.required),
- // loaded = this.loaded,
- //TODO Move this out of scope
- done = {},
- p = 0, l, a, b, j, k, moved, doneKey;
-
- // keep going until we make a pass without moving anything
- for (;;) {
-
- l = s.length;
- moved = false;
-
- // start the loop after items that are already sorted
- for (j = p; j < l; j++) {
-
- // check the next module on the list to see if its
- // dependencies have been met
- a = s[j];
-
- // check everything below current item and move if we
- // find a requirement for the current item
- for (k = j + 1; k < l; k++) {
- doneKey = a + s[k];
-
- if (!done[doneKey] && this._requires(a, s[k])) {
-
- // extract the dependency so we can move it up
- b = s.splice(k, 1);
-
- // insert the dependency above the item that
- // requires it
- s.splice(j, 0, b[0]);
-
- // only swap two dependencies once to short circut
- // circular dependencies
- done[doneKey] = true;
-
- // keep working
- moved = true;
-
- break;
- }
- }
-
- // jump out of loop if we moved something
- if (moved) {
- break;
- // this item is sorted, move our pointer and keep going
- } else {
- p++;
- }
- }
-
- // when we make it here and moved is false, we are
- // finished sorting
- if (!moved) {
- break;
- }
-
- }
-
- this.sorted = s;
- },
-
- /**
- * Handles the actual insertion of script/link tags
- * @method _insert
- * @private
- * @param {Object} source The YUI instance the request came from
- * @param {Object} o The metadata to include
- * @param {String} type JS or CSS
- * @param {Boolean} [skipcalc=false] Do a Loader.calculate on the meta
- */
- _insert: function(source, o, type, skipcalc) {
-
-
- // restore the state at the time of the request
- if (source) {
- this._config(source);
- }
-
- // build the dependency list
- // don't include type so we can process CSS and script in
- // one pass when the type is not specified.
-
- var modules = this.resolve(!skipcalc),
- self = this, comp = 0, actions = 0,
- mods = {}, deps, complete;
-
- self._refetch = [];
-
- if (type) {
- //Filter out the opposite type and reset the array so the checks later work
- modules[((type === JS) ? CSS : JS)] = [];
- }
- if (!self.fetchCSS) {
- modules.css = [];
- }
- if (modules.js.length) {
- comp++;
- }
- if (modules.css.length) {
- comp++;
- }
-
- //console.log('Resolved Modules: ', modules);
-
- complete = function(d) {
- actions++;
- var errs = {}, i = 0, o = 0, u = '', fn,
- modName, resMods;
-
- if (d && d.errors) {
- for (i = 0; i < d.errors.length; i++) {
- if (d.errors[i].request) {
- u = d.errors[i].request.url;
- } else {
- u = d.errors[i];
- }
- errs[u] = u;
- }
- }
-
- if (d && d.data && d.data.length && (d.type === 'success')) {
- for (i = 0; i < d.data.length; i++) {
- self.inserted[d.data[i].name] = true;
- //If the external module has a skin or a lang, reprocess it
- if (d.data[i].lang || d.data[i].skinnable) {
- delete self.inserted[d.data[i].name];
- self._refetch.push(d.data[i].name);
- }
- }
- }
-
- if (actions === comp) {
- self._loading = null;
- if (self._refetch.length) {
- //Get the deps for the new meta-data and reprocess
- for (i = 0; i < self._refetch.length; i++) {
- deps = self.getRequires(self.getModule(self._refetch[i]));
- for (o = 0; o < deps.length; o++) {
- if (!self.inserted[deps[o]]) {
- //We wouldn't be to this point without the module being here
- mods[deps[o]] = deps[o];
- }
- }
- }
- mods = Y.Object.keys(mods);
- if (mods.length) {
- self.require(mods);
- resMods = self.resolve(true);
- if (resMods.cssMods.length) {
- for (i=0; i < resMods.cssMods.length; i++) {
- modName = resMods.cssMods[i].name;
- delete YUI.Env._cssLoaded[modName];
- if (self.isCSSLoaded(modName)) {
- self.inserted[modName] = true;
- delete self.required[modName];
- }
- }
- self.sorted = [];
- self._sort();
- }
- d = null; //bail
- self._insert(); //insert the new deps
- }
- }
- if (d && d.fn) {
- fn = d.fn;
- delete d.fn;
- fn.call(self, d);
- }
- }
- };
-
- this._loading = true;
-
- if (!modules.js.length && !modules.css.length) {
- actions = -1;
- complete({
- fn: self._onSuccess
- });
- return;
- }
-
-
- if (modules.css.length) { //Load CSS first
- Y.Get.css(modules.css, {
- data: modules.cssMods,
- attributes: self.cssAttributes,
- insertBefore: self.insertBefore,
- charset: self.charset,
- timeout: self.timeout,
- context: self,
- onProgress: function(e) {
- self._onProgress.call(self, e);
- },
- onTimeout: function(d) {
- self._onTimeout.call(self, d);
- },
- onSuccess: function(d) {
- d.type = 'success';
- d.fn = self._onSuccess;
- complete.call(self, d);
- },
- onFailure: function(d) {
- d.type = 'failure';
- d.fn = self._onFailure;
- complete.call(self, d);
- }
- });
- }
-
- if (modules.js.length) {
- Y.Get.js(modules.js, {
- data: modules.jsMods,
- insertBefore: self.insertBefore,
- attributes: self.jsAttributes,
- charset: self.charset,
- timeout: self.timeout,
- autopurge: false,
- context: self,
- async: self.async,
- onProgress: function(e) {
- self._onProgress.call(self, e);
- },
- onTimeout: function(d) {
- self._onTimeout.call(self, d);
- },
- onSuccess: function(d) {
- d.type = 'success';
- d.fn = self._onSuccess;
- complete.call(self, d);
- },
- onFailure: function(d) {
- d.type = 'failure';
- d.fn = self._onFailure;
- complete.call(self, d);
- }
- });
- }
- },
- /**
- * Once a loader operation is completely finished, process any additional queued items.
- * @method _continue
- * @private
- */
- _continue: function() {
- if (!(_queue.running) && _queue.size() > 0) {
- _queue.running = true;
- _queue.next()();
- }
- },
-
- /**
- * inserts the requested modules and their dependencies.
- * <code>type</code> can be "js" or "css". Both script and
- * css are inserted if type is not provided.
- * @method insert
- * @param {object} o optional options object.
- * @param {string} type the type of dependency to insert.
- */
- insert: function(o, type, skipsort) {
- var self = this, copy = Y.merge(this);
- delete copy.require;
- delete copy.dirty;
- _queue.add(function() {
- self._insert(copy, o, type, skipsort);
- });
- this._continue();
- },
-
- /**
- * Executed every time a module is loaded, and if we are in a load
- * cycle, we attempt to load the next script. Public so that it
- * is possible to call this if using a method other than
- * Y.register to determine when scripts are fully loaded
- * @method loadNext
- * @deprecated
- * @param {string} mname optional the name of the module that has
- * been loaded (which is usually why it is time to load the next
- * one).
- */
- loadNext: function() {
- return;
- },
-
- /**
- * Apply filter defined for this instance to a url/path
- * @method _filter
- * @param {string} u the string to filter.
- * @param {string} name the name of the module, if we are processing
- * a single module as opposed to a combined url.
- * @return {string} the filtered string.
- * @private
- */
- _filter: function(u, name, group) {
- var f = this.filter,
- hasFilter = name && (name in this.filters),
- modFilter = hasFilter && this.filters[name],
- groupName = group || (this.moduleInfo[name] ? this.moduleInfo[name].group : null);
-
- if (groupName && this.groups[groupName] && this.groups[groupName].filter) {
- modFilter = this.groups[groupName].filter;
- hasFilter = true;
- }
-
- if (u) {
- if (hasFilter) {
- f = (L.isString(modFilter)) ? this.FILTER_DEFS[modFilter.toUpperCase()] || null : modFilter;
- }
- if (f) {
- u = u.replace(new RegExp(f.searchExp, 'g'), f.replaceStr);
- }
- }
- return u;
- },
-
- /**
- * Generates the full url for a module
- * @method _url
- * @param {string} path the path fragment.
- * @param {String} name The name of the module
- * @param {String} [base=self.base] The base url to use
- * @return {string} the full url.
- * @private
- */
- _url: function(path, name, base) {
- return this._filter((base || this.base || '') + path, name);
- },
- /**
- * Returns an Object hash of file arrays built from `loader.sorted` or from an arbitrary list of sorted modules.
- * @method resolve
- * @param {Boolean} [calc=false] Perform a loader.calculate() before anything else
- * @param {Array} [s=loader.sorted] An override for the loader.sorted array
- * @return {Object} Object hash (js and css) of two arrays of file lists
- * @example This method can be used as an off-line dep calculator
- *
- * var Y = YUI();
- * var loader = new Y.Loader({
- * filter: 'debug',
- * base: '../../',
- * root: 'build/',
- * combine: true,
- * require: ['node', 'dd', 'console']
- * });
- * var out = loader.resolve(true);
- *
- */
- resolve: function(calc, s) {
-
- var len, i, m, url, group, groupName, j, frag,
- comboSource, comboSources, mods, comboBase,
- base, urls, u = [], tmpBase, baseLen, resCombos = {},
- self = this, comboSep, maxURLLength,
- inserted = (self.ignoreRegistered) ? {} : self.inserted,
- resolved = { js: [], jsMods: [], css: [], cssMods: [] },
- type = self.loadType || 'js', addSingle;
-
- if (self.skin.overrides || self.skin.defaultSkin !== DEFAULT_SKIN || self.ignoreRegistered) {
- self._resetModules();
- }
-
- if (calc) {
- self.calculate();
- }
- s = s || self.sorted;
-
- addSingle = function(m) {
-
- if (m) {
- group = (m.group && self.groups[m.group]) || NOT_FOUND;
-
- //Always assume it's async
- if (group.async === false) {
- m.async = group.async;
- }
-
- url = (m.fullpath) ? self._filter(m.fullpath, s[i]) :
- self._url(m.path, s[i], group.base || m.base);
-
- if (m.attributes || m.async === false) {
- url = {
- url: url,
- async: m.async
- };
- if (m.attributes) {
- url.attributes = m.attributes;
- }
- }
- resolved[m.type].push(url);
- resolved[m.type + 'Mods'].push(m);
- } else {
- }
-
- };
-
- len = s.length;
-
- // the default combo base
- comboBase = self.comboBase;
-
- url = comboBase;
-
- comboSources = {};
-
- for (i = 0; i < len; i++) {
- comboSource = comboBase;
- m = self.getModule(s[i]);
- groupName = m && m.group;
- group = self.groups[groupName];
- if (groupName && group) {
-
- if (!group.combine || m.fullpath) {
- //This is not a combo module, skip it and load it singly later.
- addSingle(m);
- continue;
- }
- m.combine = true;
- if (group.comboBase) {
- comboSource = group.comboBase;
- }
-
- if ("root" in group && L.isValue(group.root)) {
- m.root = group.root;
- }
- m.comboSep = group.comboSep || self.comboSep;
- m.maxURLLength = group.maxURLLength || self.maxURLLength;
- } else {
- if (!self.combine) {
- //This is not a combo module, skip it and load it singly later.
- addSingle(m);
- continue;
- }
- }
-
- comboSources[comboSource] = comboSources[comboSource] || [];
- comboSources[comboSource].push(m);
- }
-
- for (j in comboSources) {
- if (comboSources.hasOwnProperty(j)) {
- resCombos[j] = resCombos[j] || { js: [], jsMods: [], css: [], cssMods: [] };
- url = j;
- mods = comboSources[j];
- len = mods.length;
-
- if (len) {
- for (i = 0; i < len; i++) {
- if (inserted[mods[i]]) {
- continue;
- }
- m = mods[i];
- // Do not try to combine non-yui JS unless combo def
- // is found
- if (m && (m.combine || !m.ext)) {
- resCombos[j].comboSep = m.comboSep;
- resCombos[j].group = m.group;
- resCombos[j].maxURLLength = m.maxURLLength;
- frag = ((L.isValue(m.root)) ? m.root : self.root) + (m.path || m.fullpath);
- frag = self._filter(frag, m.name);
- resCombos[j][m.type].push(frag);
- resCombos[j][m.type + 'Mods'].push(m);
- } else {
- //Add them to the next process..
- if (mods[i]) {
- addSingle(mods[i]);
- }
- }
-
- }
- }
- }
- }
-
-
- for (j in resCombos) {
- if (resCombos.hasOwnProperty(j)) {
- base = j;
- comboSep = resCombos[base].comboSep || self.comboSep;
- maxURLLength = resCombos[base].maxURLLength || self.maxURLLength;
- for (type in resCombos[base]) {
- if (type === JS || type === CSS) {
- urls = resCombos[base][type];
- mods = resCombos[base][type + 'Mods'];
- len = urls.length;
- tmpBase = base + urls.join(comboSep);
- baseLen = tmpBase.length;
- if (maxURLLength <= base.length) {
- maxURLLength = MAX_URL_LENGTH;
- }
-
- if (len) {
- if (baseLen > maxURLLength) {
- u = [];
- for (s = 0; s < len; s++) {
- u.push(urls[s]);
- tmpBase = base + u.join(comboSep);
-
- if (tmpBase.length > maxURLLength) {
- m = u.pop();
- tmpBase = base + u.join(comboSep);
- resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
- u = [];
- if (m) {
- u.push(m);
- }
- }
- }
- if (u.length) {
- tmpBase = base + u.join(comboSep);
- resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
- }
- } else {
- resolved[type].push(self._filter(tmpBase, null, resCombos[base].group));
- }
- }
- resolved[type + 'Mods'] = resolved[type + 'Mods'].concat(mods);
- }
- }
- }
- }
-
- resCombos = null;
-
- return resolved;
- },
- /**
- Shortcut to calculate, resolve and load all modules.
-
- var loader = new Y.Loader({
- ignoreRegistered: true,
- modules: {
- mod: {
- path: 'mod.js'
- }
- },
- requires: [ 'mod' ]
- });
- loader.load(function() {
- console.log('All modules have loaded..');
- });
-
-
- @method load
- @param {Callback} cb Executed after all load operations are complete
- */
- load: function(cb) {
- if (!cb) {
- return;
- }
- var self = this,
- out = self.resolve(true);
-
- self.data = out;
-
- self.onEnd = function() {
- cb.apply(self.context || self, arguments);
- };
-
- self.insert();
- }
-};
-
-
-
-}, '3.12.0', {"requires": ["get", "features"]});
-YUI.add('loader-rollup', function (Y, NAME) {
-
-/**
- * Optional automatic rollup logic for reducing http connections
- * when not using a combo service.
- * @module loader
- * @submodule rollup
- */
-
-/**
- * Look for rollup packages to determine if all of the modules a
- * rollup supersedes are required. If so, include the rollup to
- * help reduce the total number of connections required. Called
- * by calculate(). This is an optional feature, and requires the
- * appropriate submodule to function.
- * @method _rollup
- * @for Loader
- * @private
- */
-Y.Loader.prototype._rollup = function() {
- var i, j, m, s, r = this.required, roll,
- info = this.moduleInfo, rolled, c, smod;
-
- // find and cache rollup modules
- if (this.dirty || !this.rollups) {
- this.rollups = {};
- for (i in info) {
- if (info.hasOwnProperty(i)) {
- m = this.getModule(i);
- // if (m && m.rollup && m.supersedes) {
- if (m && m.rollup) {
- this.rollups[i] = m;
- }
- }
- }
- }
-
- // make as many passes as needed to pick up rollup rollups
- for (;;) {
- rolled = false;
-
- // go through the rollup candidates
- for (i in this.rollups) {
- if (this.rollups.hasOwnProperty(i)) {
- // there can be only one, unless forced
- if (!r[i] && ((!this.loaded[i]) || this.forceMap[i])) {
- m = this.getModule(i);
- s = m.supersedes || [];
- roll = false;
-
- // @TODO remove continue
- if (!m.rollup) {
- continue;
- }
-
- c = 0;
-
- // check the threshold
- for (j = 0; j < s.length; j++) {
- smod = info[s[j]];
-
- // if the superseded module is loaded, we can't
- // load the rollup unless it has been forced.
- if (this.loaded[s[j]] && !this.forceMap[s[j]]) {
- roll = false;
- break;
- // increment the counter if this module is required.
- // if we are beyond the rollup threshold, we will
- // use the rollup module
- } else if (r[s[j]] && m.type === smod.type) {
- c++;
- roll = (c >= m.rollup);
- if (roll) {
- break;
- }
- }
- }
-
- if (roll) {
- // add the rollup
- r[i] = true;
- rolled = true;
-
- // expand the rollup's dependencies
- this.getRequires(m);
- }
- }
- }
- }
-
- // if we made it here w/o rolling up something, we are done
- if (!rolled) {
- break;
- }
- }
-};
-
-
-}, '3.12.0', {"requires": ["loader-base"]});
-YUI.add('loader-yui3', function (Y, NAME) {
-
-/* This file is auto-generated by (yogi.js loader --mix --yes) */
-
-/*jshint maxlen:900, eqeqeq: false */
-
-/**
- * YUI 3 module metadata
- * @module loader
- * @submodule loader-yui3
- */
-YUI.Env[Y.version].modules = YUI.Env[Y.version].modules || {};
-Y.mix(YUI.Env[Y.version].modules, {
- "align-plugin": {
- "requires": [
- "node-screen",
- "node-pluginhost"
- ]
- },
- "anim": {
- "use": [
- "anim-base",
- "anim-color",
- "anim-curve",
- "anim-easing",
- "anim-node-plugin",
- "anim-scroll",
- "anim-xy"
- ]
- },
- "anim-base": {
- "requires": [
- "base-base",
- "node-style"
- ]
- },
- "anim-color": {
- "requires": [
- "anim-base"
- ]
- },
- "anim-curve": {
- "requires": [
- "anim-xy"
- ]
- },
- "anim-easing": {
- "requires": [
- "anim-base"
- ]
- },
- "anim-node-plugin": {
- "requires": [
- "node-pluginhost",
- "anim-base"
- ]
- },
- "anim-scroll": {
- "requires": [
- "anim-base"
- ]
- },
- "anim-shape": {
- "requires": [
- "anim-base",
- "anim-easing",
- "anim-color",
- "matrix"
- ]
- },
- "anim-shape-transform": {
- "use": [
- "anim-shape"
- ]
- },
- "anim-xy": {
- "requires": [
- "anim-base",
- "node-screen"
- ]
- },
- "app": {
- "use": [
- "app-base",
- "app-content",
- "app-transitions",
- "lazy-model-list",
- "model",
- "model-list",
- "model-sync-rest",
- "router",
- "view",
- "view-node-map"
- ]
- },
- "app-base": {
- "requires": [
- "classnamemanager",
- "pjax-base",
- "router",
- "view"
- ]
- },
- "app-content": {
- "requires": [
- "app-base",
- "pjax-content"
- ]
- },
- "app-transitions": {
- "requires": [
- "app-base"
- ]
- },
- "app-transitions-css": {
- "type": "css"
- },
- "app-transitions-native": {
- "condition": {
- "name": "app-transitions-native",
- "test": function (Y) {
- var doc = Y.config.doc,
- node = doc ? doc.documentElement : null;
-
- if (node && node.style) {
- return ('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
- }
-
- return false;
-},
- "trigger": "app-transitions"
- },
- "requires": [
- "app-transitions",
- "app-transitions-css",
- "parallel",
- "transition"
- ]
- },
- "array-extras": {
- "requires": [
- "yui-base"
- ]
- },
- "array-invoke": {
- "requires": [
- "yui-base"
- ]
- },
- "arraylist": {
- "requires": [
- "yui-base"
- ]
- },
- "arraylist-add": {
- "requires": [
- "arraylist"
- ]
- },
- "arraylist-filter": {
- "requires": [
- "arraylist"
- ]
- },
- "arraysort": {
- "requires": [
- "yui-base"
- ]
- },
- "async-queue": {
- "requires": [
- "event-custom"
- ]
- },
- "attribute": {
- "use": [
- "attribute-base",
- "attribute-complex"
- ]
- },
- "attribute-base": {
- "requires": [
- "attribute-core",
- "attribute-observable",
- "attribute-extras"
- ]
- },
- "attribute-complex": {
- "requires": [
- "attribute-base"
- ]
- },
- "attribute-core": {
- "requires": [
- "oop"
- ]
- },
- "attribute-events": {
- "use": [
- "attribute-observable"
- ]
- },
- "attribute-extras": {
- "requires": [
- "oop"
- ]
- },
- "attribute-observable": {
- "requires": [
- "event-custom"
- ]
- },
- "autocomplete": {
- "use": [
- "autocomplete-base",
- "autocomplete-sources",
- "autocomplete-list",
- "autocomplete-plugin"
- ]
- },
- "autocomplete-base": {
- "optional": [
- "autocomplete-sources"
- ],
- "requires": [
- "array-extras",
- "base-build",
- "escape",
- "event-valuechange",
- "node-base"
- ]
- },
- "autocomplete-filters": {
- "requires": [
- "array-extras",
- "text-wordbreak"
- ]
- },
- "autocomplete-filters-accentfold": {
- "requires": [
- "array-extras",
- "text-accentfold",
- "text-wordbreak"
- ]
- },
- "autocomplete-highlighters": {
- "requires": [
- "array-extras",
- "highlight-base"
- ]
- },
- "autocomplete-highlighters-accentfold": {
- "requires": [
- "array-extras",
- "highlight-accentfold"
- ]
- },
- "autocomplete-list": {
- "after": [
- "autocomplete-sources"
- ],
- "lang": [
- "en",
- "es",
- "hu",
- "it"
- ],
- "requires": [
- "autocomplete-base",
- "event-resize",
- "node-screen",
- "selector-css3",
- "shim-plugin",
- "widget",
- "widget-position",
- "widget-position-align"
- ],
- "skinnable": true
- },
- "autocomplete-list-keys": {
- "condition": {
- "name": "autocomplete-list-keys",
- "test": function (Y) {
- // Only add keyboard support to autocomplete-list if this doesn't appear to
- // be an iOS or Android-based mobile device.
- //
- // There's currently no feasible way to actually detect whether a device has
- // a hardware keyboard, so this sniff will have to do. It can easily be
- // overridden by manually loading the autocomplete-list-keys module.
- //
- // Worth noting: even though iOS supports bluetooth keyboards, Mobile Safari
- // doesn't fire the keyboard events used by AutoCompleteList, so there's
- // no point loading the -keys module even when a bluetooth keyboard may be
- // available.
- return !(Y.UA.ios || Y.UA.android);
-},
- "trigger": "autocomplete-list"
- },
- "requires": [
- "autocomplete-list",
- "base-build"
- ]
- },
- "autocomplete-plugin": {
- "requires": [
- "autocomplete-list",
- "node-pluginhost"
- ]
- },
- "autocomplete-sources": {
- "optional": [
- "io-base",
- "json-parse",
- "jsonp",
- "yql"
- ],
- "requires": [
- "autocomplete-base"
- ]
- },
- "axes": {
- "use": [
- "axis-numeric",
- "axis-category",
- "axis-time",
- "axis-stacked"
- ]
- },
- "axes-base": {
- "use": [
- "axis-numeric-base",
- "axis-category-base",
- "axis-time-base",
- "axis-stacked-base"
- ]
- },
- "axis": {
- "requires": [
- "dom",
- "widget",
- "widget-position",
- "widget-stack",
- "graphics",
- "axis-base"
- ]
- },
- "axis-base": {
- "requires": [
- "classnamemanager",
- "datatype-number",
- "datatype-date",
- "base",
- "event-custom"
- ]
- },
- "axis-category": {
- "requires": [
- "axis",
- "axis-category-base"
- ]
- },
- "axis-category-base": {
- "requires": [
- "axis-base"
- ]
- },
- "axis-numeric": {
- "requires": [
- "axis",
- "axis-numeric-base"
- ]
- },
- "axis-numeric-base": {
- "requires": [
- "axis-base"
- ]
- },
- "axis-stacked": {
- "requires": [
- "axis-numeric",
- "axis-stacked-base"
- ]
- },
- "axis-stacked-base": {
- "requires": [
- "axis-numeric-base"
- ]
- },
- "axis-time": {
- "requires": [
- "axis",
- "axis-time-base"
- ]
- },
- "axis-time-base": {
- "requires": [
- "axis-base"
- ]
- },
- "base": {
- "use": [
- "base-base",
- "base-pluginhost",
- "base-build"
- ]
- },
- "base-base": {
- "requires": [
- "attribute-base",
- "base-core",
- "base-observable"
- ]
- },
- "base-build": {
- "requires": [
- "base-base"
- ]
- },
- "base-core": {
- "requires": [
- "attribute-core"
- ]
- },
- "base-observable": {
- "requires": [
- "attribute-observable"
- ]
- },
- "base-pluginhost": {
- "requires": [
- "base-base",
- "pluginhost"
- ]
- },
- "button": {
- "requires": [
- "button-core",
- "cssbutton",
- "widget"
- ]
- },
- "button-core": {
- "requires": [
- "attribute-core",
- "classnamemanager",
- "node-base"
- ]
- },
- "button-group": {
- "requires": [
- "button-plugin",
- "cssbutton",
- "widget"
- ]
- },
- "button-plugin": {
- "requires": [
- "button-core",
- "cssbutton",
- "node-pluginhost"
- ]
- },
- "cache": {
- "use": [
- "cache-base",
- "cache-offline",
- "cache-plugin"
- ]
- },
- "cache-base": {
- "requires": [
- "base"
- ]
- },
- "cache-offline": {
- "requires": [
- "cache-base",
- "json"
- ]
- },
- "cache-plugin": {
- "requires": [
- "plugin",
- "cache-base"
- ]
- },
- "calendar": {
- "requires": [
- "calendar-base",
- "calendarnavigator"
- ],
- "skinnable": true
- },
- "calendar-base": {
- "lang": [
- "de",
- "en",
- "es",
- "es-AR",
- "fr",
- "hu",
- "it",
- "ja",
- "nb-NO",
- "nl",
- "pt-BR",
- "ru",
- "zh-Hans",
- "zh-Hans-CN",
- "zh-Hant",
- "zh-Hant-HK",
- "zh-HANT-TW"
- ],
- "requires": [
- "widget",
- "datatype-date",
- "datatype-date-math",
- "cssgrids"
- ],
- "skinnable": true
- },
- "calendarnavigator": {
- "requires": [
- "plugin",
- "classnamemanager",
- "datatype-date",
- "node"
- ],
- "skinnable": true
- },
- "charts": {
- "use": [
- "charts-base"
- ]
- },
- "charts-base": {
- "requires": [
- "dom",
- "event-mouseenter",
- "event-touch",
- "graphics-group",
- "axes",
- "series-pie",
- "series-line",
- "series-marker",
- "series-area",
- "series-spline",
- "series-column",
- "series-bar",
- "series-areaspline",
- "series-combo",
- "series-combospline",
- "series-line-stacked",
- "series-marker-stacked",
- "series-area-stacked",
- "series-spline-stacked",
- "series-column-stacked",
- "series-bar-stacked",
- "series-areaspline-stacked",
- "series-combo-stacked",
- "series-combospline-stacked"
- ]
- },
- "charts-legend": {
- "requires": [
- "charts-base"
- ]
- },
- "classnamemanager": {
- "requires": [
- "yui-base"
- ]
- },
- "clickable-rail": {
- "requires": [
- "slider-base"
- ]
- },
- "collection": {
- "use": [
- "array-extras",
- "arraylist",
- "arraylist-add",
- "arraylist-filter",
- "array-invoke"
- ]
- },
- "color": {
- "use": [
- "color-base",
- "color-hsl",
- "color-harmony"
- ]
- },
- "color-base": {
- "requires": [
- "yui-base"
- ]
- },
- "color-harmony": {
- "requires": [
- "color-hsl"
- ]
- },
- "color-hsl": {
- "requires": [
- "color-base"
- ]
- },
- "color-hsv": {
- "requires": [
- "color-base"
- ]
- },
- "console": {
- "lang": [
- "en",
- "es",
- "hu",
- "it",
- "ja"
- ],
- "requires": [
- "yui-log",
- "widget"
- ],
- "skinnable": true
- },
- "console-filters": {
- "requires": [
- "plugin",
- "console"
- ],
- "skinnable": true
- },
- "controller": {
- "use": [
- "router"
- ]
- },
- "cookie": {
- "requires": [
- "yui-base"
- ]
- },
- "createlink-base": {
- "requires": [
- "editor-base"
- ]
- },
- "cssbase": {
- "after": [
- "cssreset",
- "cssfonts",
- "cssgrids",
- "cssreset-context",
- "cssfonts-context",
- "cssgrids-context"
- ],
- "type": "css"
- },
- "cssbase-context": {
- "after": [
- "cssreset",
- "cssfonts",
- "cssgrids",
- "cssreset-context",
- "cssfonts-context",
- "cssgrids-context"
- ],
- "type": "css"
- },
- "cssbutton": {
- "type": "css"
- },
- "cssfonts": {
- "type": "css"
- },
- "cssfonts-context": {
- "type": "css"
- },
- "cssgrids": {
- "optional": [
- "cssnormalize"
- ],
- "type": "css"
- },
- "cssgrids-base": {
- "optional": [
- "cssnormalize"
- ],
- "type": "css"
- },
- "cssgrids-responsive": {
- "optional": [
- "cssnormalize"
- ],
- "requires": [
- "cssgrids",
- "cssgrids-responsive-base"
- ],
- "type": "css"
- },
- "cssgrids-units": {
- "optional": [
- "cssnormalize"
- ],
- "requires": [
- "cssgrids-base"
- ],
- "type": "css"
- },
- "cssnormalize": {
- "type": "css"
- },
- "cssnormalize-context": {
- "type": "css"
- },
- "cssreset": {
- "type": "css"
- },
- "cssreset-context": {
- "type": "css"
- },
- "dataschema": {
- "use": [
- "dataschema-base",
- "dataschema-json",
- "dataschema-xml",
- "dataschema-array",
- "dataschema-text"
- ]
- },
- "dataschema-array": {
- "requires": [
- "dataschema-base"
- ]
- },
- "dataschema-base": {
- "requires": [
- "base"
- ]
- },
- "dataschema-json": {
- "requires": [
- "dataschema-base",
- "json"
- ]
- },
- "dataschema-text": {
- "requires": [
- "dataschema-base"
- ]
- },
- "dataschema-xml": {
- "requires": [
- "dataschema-base"
- ]
- },
- "datasource": {
- "use": [
- "datasource-local",
- "datasource-io",
- "datasource-get",
- "datasource-function",
- "datasource-cache",
- "datasource-jsonschema",
- "datasource-xmlschema",
- "datasource-arrayschema",
- "datasource-textschema",
- "datasource-polling"
- ]
- },
- "datasource-arrayschema": {
- "requires": [
- "datasource-local",
- "plugin",
- "dataschema-array"
- ]
- },
- "datasource-cache": {
- "requires": [
- "datasource-local",
- "plugin",
- "cache-base"
- ]
- },
- "datasource-function": {
- "requires": [
- "datasource-local"
- ]
- },
- "datasource-get": {
- "requires": [
- "datasource-local",
- "get"
- ]
- },
- "datasource-io": {
- "requires": [
- "datasource-local",
- "io-base"
- ]
- },
- "datasource-jsonschema": {
- "requires": [
- "datasource-local",
- "plugin",
- "dataschema-json"
- ]
- },
- "datasource-local": {
- "requires": [
- "base"
- ]
- },
- "datasource-polling": {
- "requires": [
- "datasource-local"
- ]
- },
- "datasource-textschema": {
- "requires": [
- "datasource-local",
- "plugin",
- "dataschema-text"
- ]
- },
- "datasource-xmlschema": {
- "requires": [
- "datasource-local",
- "plugin",
- "datatype-xml",
- "dataschema-xml"
- ]
- },
- "datatable": {
- "use": [
- "datatable-core",
- "datatable-table",
- "datatable-head",
- "datatable-body",
- "datatable-base",
- "datatable-column-widths",
- "datatable-message",
- "datatable-mutable",
- "datatable-sort",
- "datatable-datasource"
- ]
- },
- "datatable-base": {
- "requires": [
- "datatable-core",
- "datatable-table",
- "datatable-head",
- "datatable-body",
- "base-build",
- "widget"
- ],
- "skinnable": true
- },
- "datatable-body": {
- "requires": [
- "datatable-core",
- "view",
- "classnamemanager"
- ]
- },
- "datatable-column-widths": {
- "requires": [
- "datatable-base"
- ]
- },
- "datatable-core": {
- "requires": [
- "escape",
- "model-list",
- "node-event-delegate"
- ]
- },
- "datatable-datasource": {
- "requires": [
- "datatable-base",
- "plugin",
- "datasource-local"
- ]
- },
- "datatable-foot": {
- "requires": [
- "datatable-core",
- "view"
- ]
- },
- "datatable-formatters": {
- "requires": [
- "datatable-body",
- "datatype-number-format",
- "datatype-date-format",
- "escape"
- ]
- },
- "datatable-head": {
- "requires": [
- "datatable-core",
- "view",
- "classnamemanager"
- ]
- },
- "datatable-message": {
- "lang": [
- "en",
- "fr",
- "es",
- "hu",
- "it"
- ],
- "requires": [
- "datatable-base"
- ],
- "skinnable": true
- },
- "datatable-mutable": {
- "requires": [
- "datatable-base"
- ]
- },
- "datatable-paginator": {
- "lang": [
- "en"
- ],
- "requires": [
- "model",
- "view",
- "paginator-core",
- "datatable-foot",
- "datatable-paginator-templates"
- ],
- "skinnable": true
- },
- "datatable-paginator-templates": {
- "requires": [
- "template"
- ]
- },
- "datatable-scroll": {
- "requires": [
- "datatable-base",
- "datatable-column-widths",
- "dom-screen"
- ],
- "skinnable": true
- },
- "datatable-sort": {
- "lang": [
- "en",
- "fr",
- "es",
- "hu"
- ],
- "requires": [
- "datatable-base"
- ],
- "skinnable": true
- },
- "datatable-table": {
- "requires": [
- "datatable-core",
- "datatable-head",
- "datatable-body",
- "view",
- "classnamemanager"
- ]
- },
- "datatype": {
- "use": [
- "datatype-date",
- "datatype-number",
- "datatype-xml"
- ]
- },
- "datatype-date": {
- "use": [
- "datatype-date-parse",
- "datatype-date-format",
- "datatype-date-math"
- ]
- },
- "datatype-date-format": {
- "lang": [
- "ar",
- "ar-JO",
- "ca",
- "ca-ES",
- "da",
- "da-DK",
- "de",
- "de-AT",
- "de-DE",
- "el",
- "el-GR",
- "en",
- "en-AU",
- "en-CA",
- "en-GB",
- "en-IE",
- "en-IN",
- "en-JO",
- "en-MY",
- "en-NZ",
- "en-PH",
- "en-SG",
- "en-US",
- "es",
- "es-AR",
- "es-BO",
- "es-CL",
- "es-CO",
- "es-EC",
- "es-ES",
- "es-MX",
- "es-PE",
- "es-PY",
- "es-US",
- "es-UY",
- "es-VE",
- "fi",
- "fi-FI",
- "fr",
- "fr-BE",
- "fr-CA",
- "fr-FR",
- "hi",
- "hi-IN",
- "hu",
- "id",
- "id-ID",
- "it",
- "it-IT",
- "ja",
- "ja-JP",
- "ko",
- "ko-KR",
- "ms",
- "ms-MY",
- "nb",
- "nb-NO",
- "nl",
- "nl-BE",
- "nl-NL",
- "pl",
- "pl-PL",
- "pt",
- "pt-BR",
- "ro",
- "ro-RO",
- "ru",
- "ru-RU",
- "sv",
- "sv-SE",
- "th",
- "th-TH",
- "tr",
- "tr-TR",
- "vi",
- "vi-VN",
- "zh-Hans",
- "zh-Hans-CN",
- "zh-Hant",
- "zh-Hant-HK",
- "zh-Hant-TW"
- ]
- },
- "datatype-date-math": {
- "requires": [
- "yui-base"
- ]
- },
- "datatype-date-parse": {},
- "datatype-number": {
- "use": [
- "datatype-number-parse",
- "datatype-number-format"
- ]
- },
- "datatype-number-format": {},
- "datatype-number-parse": {},
- "datatype-xml": {
- "use": [
- "datatype-xml-parse",
- "datatype-xml-format"
- ]
- },
- "datatype-xml-format": {},
- "datatype-xml-parse": {},
- "dd": {
- "use": [
- "dd-ddm-base",
- "dd-ddm",
- "dd-ddm-drop",
- "dd-drag",
- "dd-proxy",
- "dd-constrain",
- "dd-drop",
- "dd-scroll",
- "dd-delegate"
- ]
- },
- "dd-constrain": {
- "requires": [
- "dd-drag"
- ]
- },
- "dd-ddm": {
- "requires": [
- "dd-ddm-base",
- "event-resize"
- ]
- },
- "dd-ddm-base": {
- "requires": [
- "node",
- "base",
- "yui-throttle",
- "classnamemanager"
- ]
- },
- "dd-ddm-drop": {
- "requires": [
- "dd-ddm"
- ]
- },
- "dd-delegate": {
- "requires": [
- "dd-drag",
- "dd-drop-plugin",
- "event-mouseenter"
- ]
- },
- "dd-drag": {
- "requires": [
- "dd-ddm-base"
- ]
- },
- "dd-drop": {
- "requires": [
- "dd-drag",
- "dd-ddm-drop"
- ]
- },
- "dd-drop-plugin": {
- "requires": [
- "dd-drop"
- ]
- },
- "dd-gestures": {
- "condition": {
- "name": "dd-gestures",
- "trigger": "dd-drag",
- "ua": "touchEnabled"
- },
- "requires": [
- "dd-drag",
- "event-synthetic",
- "event-gestures"
- ]
- },
- "dd-plugin": {
- "optional": [
- "dd-constrain",
- "dd-proxy"
- ],
- "requires": [
- "dd-drag"
- ]
- },
- "dd-proxy": {
- "requires": [
- "dd-drag"
- ]
- },
- "dd-scroll": {
- "requires": [
- "dd-drag"
- ]
- },
- "dial": {
- "lang": [
- "en",
- "es",
- "hu"
- ],
- "requires": [
- "widget",
- "dd-drag",
- "event-mouseenter",
- "event-move",
- "event-key",
- "transition",
- "intl"
- ],
- "skinnable": true
- },
- "dom": {
- "use": [
- "dom-base",
- "dom-screen",
- "dom-style",
- "selector-native",
- "selector"
- ]
- },
- "dom-base": {
- "requires": [
- "dom-core"
- ]
- },
- "dom-core": {
- "requires": [
- "oop",
- "features"
- ]
- },
- "dom-deprecated": {
- "requires": [
- "dom-base"
- ]
- },
- "dom-screen": {
- "requires": [
- "dom-base",
- "dom-style"
- ]
- },
- "dom-style": {
- "requires": [
- "dom-base",
- "color-base"
- ]
- },
- "dom-style-ie": {
- "condition": {
- "name": "dom-style-ie",
- "test": function (Y) {
-
- var testFeature = Y.Features.test,
- addFeature = Y.Features.add,
- WINDOW = Y.config.win,
- DOCUMENT = Y.config.doc,
- DOCUMENT_ELEMENT = 'documentElement',
- ret = false;
-
- addFeature('style', 'computedStyle', {
- test: function() {
- return WINDOW && 'getComputedStyle' in WINDOW;
- }
- });
-
- addFeature('style', 'opacity', {
- test: function() {
- return DOCUMENT && 'opacity' in DOCUMENT[DOCUMENT_ELEMENT].style;
- }
- });
-
- ret = (!testFeature('style', 'opacity') &&
- !testFeature('style', 'computedStyle'));
-
- return ret;
-},
- "trigger": "dom-style"
- },
- "requires": [
- "dom-style"
- ]
- },
- "dump": {
- "requires": [
- "yui-base"
- ]
- },
- "editor": {
- "use": [
- "frame",
- "editor-selection",
- "exec-command",
- "editor-base",
- "editor-para",
- "editor-br",
- "editor-bidi",
- "editor-tab",
- "createlink-base"
- ]
- },
- "editor-base": {
- "requires": [
- "base",
- "frame",
- "node",
- "exec-command",
- "editor-selection"
- ]
- },
- "editor-bidi": {
- "requires": [
- "editor-base"
- ]
- },
- "editor-br": {
- "requires": [
- "editor-base"
- ]
- },
- "editor-lists": {
- "requires": [
- "editor-base"
- ]
- },
- "editor-para": {
- "requires": [
- "editor-para-base"
- ]
- },
- "editor-para-base": {
- "requires": [
- "editor-base"
- ]
- },
- "editor-para-ie": {
- "condition": {
- "name": "editor-para-ie",
- "trigger": "editor-para",
- "ua": "ie",
- "when": "instead"
- },
- "requires": [
- "editor-para-base"
- ]
- },
- "editor-selection": {
- "requires": [
- "node"
- ]
- },
- "editor-tab": {
- "requires": [
- "editor-base"
- ]
- },
- "escape": {
- "requires": [
- "yui-base"
- ]
- },
- "event": {
- "after": [
- "node-base"
- ],
- "use": [
- "event-base",
- "event-delegate",
- "event-synthetic",
- "event-mousewheel",
- "event-mouseenter",
- "event-key",
- "event-focus",
- "event-resize",
- "event-hover",
- "event-outside",
- "event-touch",
- "event-move",
- "event-flick",
- "event-valuechange",
- "event-tap"
- ]
- },
- "event-base": {
- "after": [
- "node-base"
- ],
- "requires": [
- "event-custom-base"
- ]
- },
- "event-base-ie": {
- "after": [
- "event-base"
- ],
- "condition": {
- "name": "event-base-ie",
- "test": function(Y) {
- var imp = Y.config.doc && Y.config.doc.implementation;
- return (imp && (!imp.hasFeature('Events', '2.0')));
-},
- "trigger": "node-base"
- },
- "requires": [
- "node-base"
- ]
- },
- "event-contextmenu": {
- "requires": [
- "event-synthetic",
- "dom-screen"
- ]
- },
- "event-custom": {
- "use": [
- "event-custom-base",
- "event-custom-complex"
- ]
- },
- "event-custom-base": {
- "requires": [
- "oop"
- ]
- },
- "event-custom-complex": {
- "requires": [
- "event-custom-base"
- ]
- },
- "event-delegate": {
- "requires": [
- "node-base"
- ]
- },
- "event-flick": {
- "requires": [
- "node-base",
- "event-touch",
- "event-synthetic"
- ]
- },
- "event-focus": {
- "requires": [
- "event-synthetic"
- ]
- },
- "event-gestures": {
- "use": [
- "event-flick",
- "event-move"
- ]
- },
- "event-hover": {
- "requires": [
- "event-mouseenter"
- ]
- },
- "event-key": {
- "requires": [
- "event-synthetic"
- ]
- },
- "event-mouseenter": {
- "requires": [
- "event-synthetic"
- ]
- },
- "event-mousewheel": {
- "requires": [
- "node-base"
- ]
- },
- "event-move": {
- "requires": [
- "node-base",
- "event-touch",
- "event-synthetic"
- ]
- },
- "event-outside": {
- "requires": [
- "event-synthetic"
- ]
- },
- "event-resize": {
- "requires": [
- "node-base",
- "event-synthetic"
- ]
- },
- "event-simulate": {
- "requires": [
- "event-base"
- ]
- },
- "event-synthetic": {
- "requires": [
- "node-base",
- "event-custom-complex"
- ]
- },
- "event-tap": {
- "requires": [
- "node-base",
- "event-base",
- "event-touch",
- "event-synthetic"
- ]
- },
- "event-touch": {
- "requires": [
- "node-base"
- ]
- },
- "event-valuechange": {
- "requires": [
- "event-focus",
- "event-synthetic"
- ]
- },
- "exec-command": {
- "requires": [
- "frame"
- ]
- },
- "features": {
- "requires": [
- "yui-base"
- ]
- },
- "file": {
- "requires": [
- "file-flash",
- "file-html5"
- ]
- },
- "file-flash": {
- "requires": [
- "base"
- ]
- },
- "file-html5": {
- "requires": [
- "base"
- ]
- },
- "frame": {
- "requires": [
- "base",
- "node",
- "selector-css3",
- "yui-throttle"
- ]
- },
- "gesture-simulate": {
- "requires": [
- "async-queue",
- "event-simulate",
- "node-screen"
- ]
- },
- "get": {
- "requires": [
- "yui-base"
- ]
- },
- "graphics": {
- "requires": [
- "node",
- "event-custom",
- "pluginhost",
- "matrix",
- "classnamemanager"
- ]
- },
- "graphics-canvas": {
- "condition": {
- "name": "graphics-canvas",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
- return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
-},
- "trigger": "graphics"
- },
- "requires": [
- "graphics"
- ]
- },
- "graphics-canvas-default": {
- "condition": {
- "name": "graphics-canvas-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useCanvas = Y.config.defaultGraphicEngine && Y.config.defaultGraphicEngine == "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
- return (!svg || useCanvas) && (canvas && canvas.getContext && canvas.getContext("2d"));
-},
- "trigger": "graphics"
- }
- },
- "graphics-group": {
- "requires": [
- "graphics"
- ]
- },
- "graphics-svg": {
- "condition": {
- "name": "graphics-svg",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
-
- return svg && (useSVG || !canvas);
-},
- "trigger": "graphics"
- },
- "requires": [
- "graphics"
- ]
- },
- "graphics-svg-default": {
- "condition": {
- "name": "graphics-svg-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- useSVG = !Y.config.defaultGraphicEngine || Y.config.defaultGraphicEngine != "canvas",
- canvas = DOCUMENT && DOCUMENT.createElement("canvas"),
- svg = (DOCUMENT && DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"));
-
- return svg && (useSVG || !canvas);
-},
- "trigger": "graphics"
- }
- },
- "graphics-vml": {
- "condition": {
- "name": "graphics-vml",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- canvas = DOCUMENT && DOCUMENT.createElement("canvas");
- return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
-},
- "trigger": "graphics"
- },
- "requires": [
- "graphics"
- ]
- },
- "graphics-vml-default": {
- "condition": {
- "name": "graphics-vml-default",
- "test": function(Y) {
- var DOCUMENT = Y.config.doc,
- canvas = DOCUMENT && DOCUMENT.createElement("canvas");
- return (DOCUMENT && !DOCUMENT.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") && (!canvas || !canvas.getContext || !canvas.getContext("2d")));
-},
- "trigger": "graphics"
- }
- },
- "handlebars": {
- "use": [
- "handlebars-compiler"
- ]
- },
- "handlebars-base": {
- "requires": []
- },
- "handlebars-compiler": {
- "requires": [
- "handlebars-base"
- ]
- },
- "highlight": {
- "use": [
- "highlight-base",
- "highlight-accentfold"
- ]
- },
- "highlight-accentfold": {
- "requires": [
- "highlight-base",
- "text-accentfold"
- ]
- },
- "highlight-base": {
- "requires": [
- "array-extras",
- "classnamemanager",
- "escape",
- "text-wordbreak"
- ]
- },
- "history": {
- "use": [
- "history-base",
- "history-hash",
- "history-hash-ie",
- "history-html5"
- ]
- },
- "history-base": {
- "requires": [
- "event-custom-complex"
- ]
- },
- "history-hash": {
- "after": [
- "history-html5"
- ],
- "requires": [
- "event-synthetic",
- "history-base",
- "yui-later"
- ]
- },
- "history-hash-ie": {
- "condition": {
- "name": "history-hash-ie",
- "test": function (Y) {
- var docMode = Y.config.doc && Y.config.doc.documentMode;
-
- return Y.UA.ie && (!('onhashchange' in Y.config.win) ||
- !docMode || docMode < 8);
-},
- "trigger": "history-hash"
- },
- "requires": [
- "history-hash",
- "node-base"
- ]
- },
- "history-html5": {
- "optional": [
- "json"
- ],
- "requires": [
- "event-base",
- "history-base",
- "node-base"
- ]
- },
- "imageloader": {
- "requires": [
- "base-base",
- "node-style",
- "node-screen"
- ]
- },
- "intl": {
- "requires": [
- "intl-base",
- "event-custom"
- ]
- },
- "intl-base": {
- "requires": [
- "yui-base"
- ]
- },
- "io": {
- "use": [
- "io-base",
- "io-xdr",
- "io-form",
- "io-upload-iframe",
- "io-queue"
- ]
- },
- "io-base": {
- "requires": [
- "event-custom-base",
- "querystring-stringify-simple"
- ]
- },
- "io-form": {
- "requires": [
- "io-base",
- "node-base"
- ]
- },
- "io-nodejs": {
- "condition": {
- "name": "io-nodejs",
- "trigger": "io-base",
- "ua": "nodejs"
- },
- "requires": [
- "io-base"
- ]
- },
- "io-queue": {
- "requires": [
- "io-base",
- "queue-promote"
- ]
- },
- "io-upload-iframe": {
- "requires": [
- "io-base",
- "node-base"
- ]
- },
- "io-xdr": {
- "requires": [
- "io-base",
- "datatype-xml-parse"
- ]
- },
- "json": {
- "use": [
- "json-parse",
- "json-stringify"
- ]
- },
- "json-parse": {
- "requires": [
- "yui-base"
- ]
- },
- "json-parse-shim": {
- "condition": {
- "name": "json-parse-shim",
- "test": function (Y) {
- var _JSON = Y.config.global.JSON,
- Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
- nativeSupport = Y.config.useNativeJSONParse !== false && !!Native;
-
- function workingNative( k, v ) {
- return k === "ok" ? true : v;
- }
-
- // Double check basic functionality. This is mainly to catch early broken
- // implementations of the JSON API in Firefox 3.1 beta1 and beta2
- if ( nativeSupport ) {
- try {
- nativeSupport = ( Native.parse( '{"ok":false}', workingNative ) ).ok;
- }
- catch ( e ) {
- nativeSupport = false;
- }
- }
-
- return !nativeSupport;
-},
- "trigger": "json-parse"
- },
- "requires": [
- "json-parse"
- ]
- },
- "json-stringify": {
- "requires": [
- "yui-base"
- ]
- },
- "json-stringify-shim": {
- "condition": {
- "name": "json-stringify-shim",
- "test": function (Y) {
- var _JSON = Y.config.global.JSON,
- Native = Object.prototype.toString.call(_JSON) === '[object JSON]' && _JSON,
- nativeSupport = Y.config.useNativeJSONStringify !== false && !!Native;
-
- // Double check basic native functionality. This is primarily to catch broken
- // early JSON API implementations in Firefox 3.1 beta1 and beta2.
- if ( nativeSupport ) {
- try {
- nativeSupport = ( '0' === Native.stringify(0) );
- } catch ( e ) {
- nativeSupport = false;
- }
- }
-
-
- return !nativeSupport;
-},
- "trigger": "json-stringify"
- },
- "requires": [
- "json-stringify"
- ]
- },
- "jsonp": {
- "requires": [
- "get",
- "oop"
- ]
- },
- "jsonp-url": {
- "requires": [
- "jsonp"
- ]
- },
- "lazy-model-list": {
- "requires": [
- "model-list"
- ]
- },
- "loader": {
- "use": [
- "loader-base",
- "loader-rollup",
- "loader-yui3"
- ]
- },
- "loader-base": {
- "requires": [
- "get",
- "features"
- ]
- },
- "loader-rollup": {
- "requires": [
- "loader-base"
- ]
- },
- "loader-yui3": {
- "requires": [
- "loader-base"
- ]
- },
- "matrix": {
- "requires": [
- "yui-base"
- ]
- },
- "model": {
- "requires": [
- "base-build",
- "escape",
- "json-parse"
- ]
- },
- "model-list": {
- "requires": [
- "array-extras",
- "array-invoke",
- "arraylist",
- "base-build",
- "escape",
- "json-parse",
- "model"
- ]
- },
- "model-sync-rest": {
- "requires": [
- "model",
- "io-base",
- "json-stringify"
- ]
- },
- "node": {
- "use": [
- "node-base",
- "node-event-delegate",
- "node-pluginhost",
- "node-screen",
- "node-style"
- ]
- },
- "node-base": {
- "requires": [
- "event-base",
- "node-core",
- "dom-base",
- "dom-style"
- ]
- },
- "node-core": {
- "requires": [
- "dom-core",
- "selector"
- ]
- },
- "node-deprecated": {
- "requires": [
- "node-base"
- ]
- },
- "node-event-delegate": {
- "requires": [
- "node-base",
- "event-delegate"
- ]
- },
- "node-event-html5": {
- "requires": [
- "node-base"
- ]
- },
- "node-event-simulate": {
- "requires": [
- "node-base",
- "event-simulate",
- "gesture-simulate"
- ]
- },
- "node-flick": {
- "requires": [
- "classnamemanager",
- "transition",
- "event-flick",
- "plugin"
- ],
- "skinnable": true
- },
- "node-focusmanager": {
- "requires": [
- "attribute",
- "node",
- "plugin",
- "node-event-simulate",
- "event-key",
- "event-focus"
- ]
- },
- "node-load": {
- "requires": [
- "node-base",
- "io-base"
- ]
- },
- "node-menunav": {
- "requires": [
- "node",
- "classnamemanager",
- "plugin",
- "node-focusmanager"
- ],
- "skinnable": true
- },
- "node-pluginhost": {
- "requires": [
- "node-base",
- "pluginhost"
- ]
- },
- "node-screen": {
- "requires": [
- "dom-screen",
- "node-base"
- ]
- },
- "node-scroll-info": {
- "requires": [
- "array-extras",
- "base-build",
- "event-resize",
- "node-pluginhost",
- "plugin",
- "selector"
- ]
- },
- "node-style": {
- "requires": [
- "dom-style",
- "node-base"
- ]
- },
- "oop": {
- "requires": [
- "yui-base"
- ]
- },
- "overlay": {
- "requires": [
- "widget",
- "widget-stdmod",
- "widget-position",
- "widget-position-align",
- "widget-stack",
- "widget-position-constrain"
- ],
- "skinnable": true
- },
- "paginator": {
- "requires": [
- "paginator-core"
- ]
- },
- "paginator-core": {
- "requires": [
- "base"
- ]
- },
- "paginator-url": {
- "requires": [
- "paginator"
- ]
- },
- "panel": {
- "requires": [
- "widget",
- "widget-autohide",
- "widget-buttons",
- "widget-modality",
- "widget-position",
- "widget-position-align",
- "widget-position-constrain",
- "widget-stack",
- "widget-stdmod"
- ],
- "skinnable": true
- },
- "parallel": {
- "requires": [
- "yui-base"
- ]
- },
- "pjax": {
- "requires": [
- "pjax-base",
- "pjax-content"
- ]
- },
- "pjax-base": {
- "requires": [
- "classnamemanager",
- "node-event-delegate",
- "router"
- ]
- },
- "pjax-content": {
- "requires": [
- "io-base",
- "node-base",
- "router"
- ]
- },
- "pjax-plugin": {
- "requires": [
- "node-pluginhost",
- "pjax",
- "plugin"
- ]
- },
- "plugin": {
- "requires": [
- "base-base"
- ]
- },
- "pluginhost": {
- "use": [
- "pluginhost-base",
- "pluginhost-config"
- ]
- },
- "pluginhost-base": {
- "requires": [
- "yui-base"
- ]
- },
- "pluginhost-config": {
- "requires": [
- "pluginhost-base"
- ]
- },
- "promise": {
- "requires": [
- "timers"
- ]
- },
- "querystring": {
- "use": [
- "querystring-parse",
- "querystring-stringify"
- ]
- },
- "querystring-parse": {
- "requires": [
- "yui-base",
- "array-extras"
- ]
- },
- "querystring-parse-simple": {
- "requires": [
- "yui-base"
- ]
- },
- "querystring-stringify": {
- "requires": [
- "yui-base"
- ]
- },
- "querystring-stringify-simple": {
- "requires": [
- "yui-base"
- ]
- },
- "queue-promote": {
- "requires": [
- "yui-base"
- ]
- },
- "range-slider": {
- "requires": [
- "slider-base",
- "slider-value-range",
- "clickable-rail"
- ]
- },
- "recordset": {
- "use": [
- "recordset-base",
- "recordset-sort",
- "recordset-filter",
- "recordset-indexer"
- ]
- },
- "recordset-base": {
- "requires": [
- "base",
- "arraylist"
- ]
- },
- "recordset-filter": {
- "requires": [
- "recordset-base",
- "array-extras",
- "plugin"
- ]
- },
- "recordset-indexer": {
- "requires": [
- "recordset-base",
- "plugin"
- ]
- },
- "recordset-sort": {
- "requires": [
- "arraysort",
- "recordset-base",
- "plugin"
- ]
- },
- "resize": {
- "use": [
- "resize-base",
- "resize-proxy",
- "resize-constrain"
- ]
- },
- "resize-base": {
- "requires": [
- "base",
- "widget",
- "event",
- "oop",
- "dd-drag",
- "dd-delegate",
- "dd-drop"
- ],
- "skinnable": true
- },
- "resize-constrain": {
- "requires": [
- "plugin",
- "resize-base"
- ]
- },
- "resize-plugin": {
- "optional": [
- "resize-constrain"
- ],
- "requires": [
- "resize-base",
- "plugin"
- ]
- },
- "resize-proxy": {
- "requires": [
- "plugin",
- "resize-base"
- ]
- },
- "router": {
- "optional": [
- "querystring-parse"
- ],
- "requires": [
- "array-extras",
- "base-build",
- "history"
- ]
- },
- "scrollview": {
- "requires": [
- "scrollview-base",
- "scrollview-scrollbars"
- ]
- },
- "scrollview-base": {
- "requires": [
- "widget",
- "event-gestures",
- "event-mousewheel",
- "transition"
- ],
- "skinnable": true
- },
- "scrollview-base-ie": {
- "condition": {
- "name": "scrollview-base-ie",
- "trigger": "scrollview-base",
- "ua": "ie"
- },
- "requires": [
- "scrollview-base"
- ]
- },
- "scrollview-list": {
- "requires": [
- "plugin",
- "classnamemanager"
- ],
- "skinnable": true
- },
- "scrollview-paginator": {
- "requires": [
- "plugin",
- "classnamemanager"
- ]
- },
- "scrollview-scrollbars": {
- "requires": [
- "classnamemanager",
- "transition",
- "plugin"
- ],
- "skinnable": true
- },
- "selector": {
- "requires": [
- "selector-native"
- ]
- },
- "selector-css2": {
- "condition": {
- "name": "selector-css2",
- "test": function (Y) {
- var DOCUMENT = Y.config.doc,
- ret = DOCUMENT && !('querySelectorAll' in DOCUMENT);
-
- return ret;
-},
- "trigger": "selector"
- },
- "requires": [
- "selector-native"
- ]
- },
- "selector-css3": {
- "requires": [
- "selector-native",
- "selector-css2"
- ]
- },
- "selector-native": {
- "requires": [
- "dom-base"
- ]
- },
- "series-area": {
- "requires": [
- "series-cartesian",
- "series-fill-util"
- ]
- },
- "series-area-stacked": {
- "requires": [
- "series-stacked",
- "series-area"
- ]
- },
- "series-areaspline": {
- "requires": [
- "series-area",
- "series-curve-util"
- ]
- },
- "series-areaspline-stacked": {
- "requires": [
- "series-stacked",
- "series-areaspline"
- ]
- },
- "series-bar": {
- "requires": [
- "series-marker",
- "series-histogram-base"
- ]
- },
- "series-bar-stacked": {
- "requires": [
- "series-stacked",
- "series-bar"
- ]
- },
- "series-base": {
- "requires": [
- "graphics",
- "axis-base"
- ]
- },
- "series-candlestick": {
- "requires": [
- "series-range"
- ]
- },
- "series-cartesian": {
- "requires": [
- "series-base"
- ]
- },
- "series-column": {
- "requires": [
- "series-marker",
- "series-histogram-base"
- ]
- },
- "series-column-stacked": {
- "requires": [
- "series-stacked",
- "series-column"
- ]
- },
- "series-combo": {
- "requires": [
- "series-cartesian",
- "series-line-util",
- "series-plot-util",
- "series-fill-util"
- ]
- },
- "series-combo-stacked": {
- "requires": [
- "series-stacked",
- "series-combo"
- ]
- },
- "series-combospline": {
- "requires": [
- "series-combo",
- "series-curve-util"
- ]
- },
- "series-combospline-stacked": {
- "requires": [
- "series-combo-stacked",
- "series-curve-util"
- ]
- },
- "series-curve-util": {},
- "series-fill-util": {},
- "series-histogram-base": {
- "requires": [
- "series-cartesian",
- "series-plot-util"
- ]
- },
- "series-line": {
- "requires": [
- "series-cartesian",
- "series-line-util"
- ]
- },
- "series-line-stacked": {
- "requires": [
- "series-stacked",
- "series-line"
- ]
- },
- "series-line-util": {},
- "series-marker": {
- "requires": [
- "series-cartesian",
- "series-plot-util"
- ]
- },
- "series-marker-stacked": {
- "requires": [
- "series-stacked",
- "series-marker"
- ]
- },
- "series-ohlc": {
- "requires": [
- "series-range"
- ]
- },
- "series-pie": {
- "requires": [
- "series-base",
- "series-plot-util"
- ]
- },
- "series-plot-util": {},
- "series-range": {
- "requires": [
- "series-cartesian"
- ]
- },
- "series-spline": {
- "requires": [
- "series-line",
- "series-curve-util"
- ]
- },
- "series-spline-stacked": {
- "requires": [
- "series-stacked",
- "series-spline"
- ]
- },
- "series-stacked": {
- "requires": [
- "axis-stacked"
- ]
- },
- "shim-plugin": {
- "requires": [
- "node-style",
- "node-pluginhost"
- ]
- },
- "slider": {
- "use": [
- "slider-base",
- "slider-value-range",
- "clickable-rail",
- "range-slider"
- ]
- },
- "slider-base": {
- "requires": [
- "widget",
- "dd-constrain",
- "event-key"
- ],
- "skinnable": true
- },
- "slider-value-range": {
- "requires": [
- "slider-base"
- ]
- },
- "sortable": {
- "requires": [
- "dd-delegate",
- "dd-drop-plugin",
- "dd-proxy"
- ]
- },
- "sortable-scroll": {
- "requires": [
- "dd-scroll",
- "sortable"
- ]
- },
- "stylesheet": {
- "requires": [
- "yui-base"
- ]
- },
- "substitute": {
- "optional": [
- "dump"
- ],
- "requires": [
- "yui-base"
- ]
- },
- "swf": {
- "requires": [
- "event-custom",
- "node",
- "swfdetect",
- "escape"
- ]
- },
- "swfdetect": {
- "requires": [
- "yui-base"
- ]
- },
- "tabview": {
- "requires": [
- "widget",
- "widget-parent",
- "widget-child",
- "tabview-base",
- "node-pluginhost",
- "node-focusmanager"
- ],
- "skinnable": true
- },
- "tabview-base": {
- "requires": [
- "node-event-delegate",
- "classnamemanager"
- ]
- },
- "tabview-plugin": {
- "requires": [
- "tabview-base"
- ]
- },
- "template": {
- "use": [
- "template-base",
- "template-micro"
- ]
- },
- "template-base": {
- "requires": [
- "yui-base"
- ]
- },
- "template-micro": {
- "requires": [
- "escape"
- ]
- },
- "test": {
- "requires": [
- "event-simulate",
- "event-custom",
- "json-stringify"
- ]
- },
- "test-console": {
- "requires": [
- "console-filters",
- "test",
- "array-extras"
- ],
- "skinnable": true
- },
- "text": {
- "use": [
- "text-accentfold",
- "text-wordbreak"
- ]
- },
- "text-accentfold": {
- "requires": [
- "array-extras",
- "text-data-accentfold"
- ]
- },
- "text-data-accentfold": {
- "requires": [
- "yui-base"
- ]
- },
- "text-data-wordbreak": {
- "requires": [
- "yui-base"
- ]
- },
- "text-wordbreak": {
- "requires": [
- "array-extras",
- "text-data-wordbreak"
- ]
- },
- "timers": {
- "requires": [
- "yui-base"
- ]
- },
- "transition": {
- "requires": [
- "node-style"
- ]
- },
- "transition-timer": {
- "condition": {
- "name": "transition-timer",
- "test": function (Y) {
- var DOCUMENT = Y.config.doc,
- node = (DOCUMENT) ? DOCUMENT.documentElement: null,
- ret = true;
-
- if (node && node.style) {
- ret = !('MozTransition' in node.style || 'WebkitTransition' in node.style || 'transition' in node.style);
- }
-
- return ret;
-},
- "trigger": "transition"
- },
- "requires": [
- "transition"
- ]
- },
- "tree": {
- "requires": [
- "base-build",
- "tree-node"
- ]
- },
- "tree-labelable": {
- "requires": [
- "tree"
- ]
- },
- "tree-lazy": {
- "requires": [
- "base-pluginhost",
- "plugin",
- "tree"
- ]
- },
- "tree-node": {},
- "tree-openable": {
- "requires": [
- "tree"
- ]
- },
- "tree-selectable": {
- "requires": [
- "tree"
- ]
- },
- "tree-sortable": {
- "requires": [
- "tree"
- ]
- },
- "uploader": {
- "requires": [
- "uploader-html5",
- "uploader-flash"
- ]
- },
- "uploader-flash": {
- "requires": [
- "swf",
- "widget",
- "base",
- "cssbutton",
- "node",
- "event-custom",
- "file-flash",
- "uploader-queue"
- ]
- },
- "uploader-html5": {
- "requires": [
- "widget",
- "node-event-simulate",
- "file-html5",
- "uploader-queue"
- ]
- },
- "uploader-queue": {
- "requires": [
- "base"
- ]
- },
- "view": {
- "requires": [
- "base-build",
- "node-event-delegate"
- ]
- },
- "view-node-map": {
- "requires": [
- "view"
- ]
- },
- "widget": {
- "use": [
- "widget-base",
- "widget-htmlparser",
- "widget-skin",
- "widget-uievents"
- ]
- },
- "widget-anim": {
- "requires": [
- "anim-base",
- "plugin",
- "widget"
- ]
- },
- "widget-autohide": {
- "requires": [
- "base-build",
- "event-key",
- "event-outside",
- "widget"
- ]
- },
- "widget-base": {
- "requires": [
- "attribute",
- "base-base",
- "base-pluginhost",
- "classnamemanager",
- "event-focus",
- "node-base",
- "node-style"
- ],
- "skinnable": true
- },
- "widget-base-ie": {
- "condition": {
- "name": "widget-base-ie",
- "trigger": "widget-base",
- "ua": "ie"
- },
- "requires": [
- "widget-base"
- ]
- },
- "widget-buttons": {
- "requires": [
- "button-plugin",
- "cssbutton",
- "widget-stdmod"
- ]
- },
- "widget-child": {
- "requires": [
- "base-build",
- "widget"
- ]
- },
- "widget-htmlparser": {
- "requires": [
- "widget-base"
- ]
- },
- "widget-locale": {
- "requires": [
- "widget-base"
- ]
- },
- "widget-modality": {
- "requires": [
- "base-build",
- "event-outside",
- "widget"
- ],
- "skinnable": true
- },
- "widget-parent": {
- "requires": [
- "arraylist",
- "base-build",
- "widget"
- ]
- },
- "widget-position": {
- "requires": [
- "base-build",
- "node-screen",
- "widget"
- ]
- },
- "widget-position-align": {
- "requires": [
- "widget-position"
- ]
- },
- "widget-position-constrain": {
- "requires": [
- "widget-position"
- ]
- },
- "widget-skin": {
- "requires": [
- "widget-base"
- ]
- },
- "widget-stack": {
- "requires": [
- "base-build",
- "widget"
- ],
- "skinnable": true
- },
- "widget-stdmod": {
- "requires": [
- "base-build",
- "widget"
- ]
- },
- "widget-uievents": {
- "requires": [
- "node-event-delegate",
- "widget-base"
- ]
- },
- "yql": {
- "requires": [
- "oop"
- ]
- },
- "yql-jsonp": {
- "condition": {
- "name": "yql-jsonp",
- "test": function (Y) {
- /* Only load the JSONP module when not in nodejs or winjs
- TODO Make the winjs module a CORS module
- */
- return (!Y.UA.nodejs && !Y.UA.winjs);
-},
- "trigger": "yql",
- "when": "after"
- },
- "requires": [
- "jsonp",
- "jsonp-url"
- ]
- },
- "yql-nodejs": {
- "condition": {
- "name": "yql-nodejs",
- "trigger": "yql",
- "ua": "nodejs",
- "when": "after"
- }
- },
- "yql-winjs": {
- "condition": {
- "name": "yql-winjs",
- "trigger": "yql",
- "ua": "winjs",
- "when": "after"
- }
- },
- "yui": {},
- "yui-base": {},
- "yui-later": {
- "requires": [
- "yui-base"
- ]
- },
- "yui-log": {
- "requires": [
- "yui-base"
- ]
- },
- "yui-throttle": {
- "requires": [
- "yui-base"
- ]
- }
-});
-YUI.Env[Y.version].md5 = 'fd7c67956df50e445f40d1668dd1dc80';
-
-
-}, '3.12.0', {"requires": ["loader-base"]});
-YUI.add('yui', function (Y, NAME) {}, '3.12.0', {
- "use": [
- "yui-base",
- "get",
- "features",
- "intl-base",
- "yui-log",
- "yui-later",
- "loader-base",
- "loader-rollup",
- "loader-yui3"
- ]
-});
--- a/js/src/jsapi-tests/testBinASTReader.cpp
+++ b/js/src/jsapi-tests/testBinASTReader.cpp
@@ -49,17 +49,17 @@ readFull(JSContext* cx, const char* path
js::Vector<uint8_t> intermediate(cx);
readFull(path, intermediate);
if (!buf.appendAll(intermediate))
MOZ_CRASH("Couldn't read data");
}
// Invariant: `path` must end with directory separator.
-void
+template<typename Tok> void
runTestFromPath(JSContext* cx, const char* path)
{
const char BIN_SUFFIX[] = ".binjs";
const char TXT_SUFFIX[] = ".js";
fprintf(stderr, "runTestFromPath: entering directory '%s'\n", path);
const size_t pathlen = strlen(path);
#if defined(XP_UNIX)
@@ -117,17 +117,17 @@ runTestFromPath(JSContext* cx, const cha
MOZ_CRASH();
if (!subPath.append(d_name, namlen))
MOZ_CRASH();
// Append same directory separator.
if (!subPath.append(path[pathlen - 1]))
MOZ_CRASH();
if (!subPath.append(0))
MOZ_CRASH();
- runTestFromPath(cx, subPath.begin());
+ runTestFromPath<Tok>(cx, subPath.begin());
continue;
}
{
// Make sure that we run GC between two tests. Otherwise, since we're running
// everything from the same cx and without returning to JS, there is nothing
// to deallocate the ASTs.
JS::PrepareForFullGC(cx);
@@ -197,17 +197,17 @@ runTestFromPath(JSContext* cx, const cha
// Parse binary file.
CompileOptions binOptions(cx);
binOptions.setFileAndLine(binPath.begin(), 0);
js::frontend::UsedNameTracker binUsedNames(cx);
if (!binUsedNames.init())
MOZ_CRASH("Couldn't initialized binUsedNames");
- js::frontend::BinASTParser binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
+ js::frontend::BinASTParser<Tok> binParser(cx, allocScope.alloc(), binUsedNames, binOptions);
auto binParsed = binParser.parse(binSource); // Will be deallocated once `reader` goes out of scope.
RootedValue binExn(cx);
if (binParsed.isErr()) {
// Save exception for more detailed error message, if necessary.
if (!js::GetAndClearException(cx, &binExn))
MOZ_CRASH("Couldn't clear binExn");
}
@@ -294,16 +294,18 @@ runTestFromPath(JSContext* cx, const cha
if (closedir(dir) != 0)
MOZ_CRASH("Could not close dir");
#endif // defined(XP_WIN)
}
BEGIN_TEST(testBinASTReaderECMAScript2)
{
#if defined(XP_WIN)
- runTestFromPath(cx, "jsapi-tests\\binast\\parser\\tester\\");
+ runTestFromPath<js::frontend::BinTokenReaderTester>(cx, "jsapi-tests\\binast\\parser\\tester\\");
+ runTestFromPath<js::frontend::BinTokenReaderMultipart(cx, "jsapi-tests\\binast\\parser\\multipart\\");
#else
- runTestFromPath(cx, "jsapi-tests/binast/parser/tester/");
+ runTestFromPath<js::frontend::BinTokenReaderTester>(cx, "jsapi-tests/binast/parser/tester/");
+ runTestFromPath<js::frontend::BinTokenReaderMultipart>(cx, "jsapi-tests/binast/parser/multipart/");
#endif // defined(XP_XIN)
return true;
}
END_TEST(testBinASTReaderECMAScript2)
--- a/js/src/jsapi-tests/testBinTokenReaderTester.cpp
+++ b/js/src/jsapi-tests/testBinTokenReaderTester.cpp
@@ -125,78 +125,78 @@ void readFull(const char* path, js::Vect
// Reading a simple string.
BEGIN_TEST(testBinTokenReaderTesterSimpleString)
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-simple-string.binjs", contents);
Tokenizer tokenizer(cx, contents);
- Maybe<Chars> found;
- CHECK(tokenizer.readMaybeChars(found));
+ Chars found(cx);
+ CHECK(tokenizer.readChars(found).isOk());
- CHECK(Tokenizer::equals(*found, "simple string")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
+ CHECK(Tokenizer::equals(found, "simple string")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
return true;
}
END_TEST(testBinTokenReaderTesterSimpleString)
// Reading a string with embedded 0.
BEGIN_TEST(testBinTokenReaderTesterStringWithEscapes)
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-string-with-escapes.binjs", contents);
Tokenizer tokenizer(cx, contents);
- Maybe<Chars> found;
- CHECK(tokenizer.readMaybeChars(found));
+ Chars found(cx);
+ CHECK(tokenizer.readChars(found).isOk());
- CHECK(Tokenizer::equals(*found, "string with escapes \0\1\0")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
+ CHECK(Tokenizer::equals(found, "string with escapes \0\1\0")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
return true;
}
END_TEST(testBinTokenReaderTesterStringWithEscapes)
// Reading an empty untagged tuple
BEGIN_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-empty-untagged-tuple.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
Tokenizer::AutoTuple guard(tokenizer);
- CHECK(tokenizer.enterUntaggedTuple(guard));
- CHECK(guard.done());
+ CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
+ CHECK(guard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterEmptyUntaggedTuple)
// Reading a untagged tuple with two strings
BEGIN_TEST(testBinTokenReaderTesterTwoStringsInTuple)
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-untagged-tuple.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
Tokenizer::AutoTuple guard(tokenizer);
- CHECK(tokenizer.enterUntaggedTuple(guard));
+ CHECK(tokenizer.enterUntaggedTuple(guard).isOk());
- Maybe<Chars> found_0;
- CHECK(tokenizer.readMaybeChars(found_0));
- CHECK(Tokenizer::equals(*found_0, "foo")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
+ Chars found_0(cx);
+ CHECK(tokenizer.readChars(found_0).isOk());
+ CHECK(Tokenizer::equals(found_0, "foo")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
- Maybe<Chars> found_1;
- CHECK(tokenizer.readMaybeChars(found_1));
- CHECK(Tokenizer::equals(*found_1, "bar")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
+ Chars found_1(cx);
+ CHECK(tokenizer.readChars(found_1).isOk());
+ CHECK(Tokenizer::equals(found_1, "bar")); // FIXME: Find a way to make CHECK_EQUAL use `Tokenizer::equals`.
- CHECK(guard.done());
+ CHECK(guard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterTwoStringsInTuple)
// Reading a tagged tuple `Pattern { id: "foo", value: 3.1415}`
BEGIN_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
@@ -204,33 +204,33 @@ BEGIN_TEST(testBinTokenReaderTesterSimpl
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-simple-tagged-tuple.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
js::frontend::BinKind tag;
Tokenizer::BinFields fields(cx);
Tokenizer::AutoTaggedTuple guard(tokenizer);
- CHECK(tokenizer.enterTaggedTuple(tag, fields, guard));
+ CHECK(tokenizer.enterTaggedTuple(tag, fields, guard).isOk());
CHECK(tag == js::frontend::BinKind::BindingIdentifier);
- Maybe<Chars> found_id;
+ Chars found_id(cx);
const double EXPECTED_value = 3.1415;
- Maybe<double> found_value;
// Order of fields is deterministic.
CHECK(fields[0] == js::frontend::BinField::Label);
CHECK(fields[1] == js::frontend::BinField::Value);
- CHECK(tokenizer.readMaybeChars(found_id));
- CHECK(tokenizer.readMaybeDouble(found_value));
+ CHECK(tokenizer.readChars(found_id).isOk());
+ Maybe<double> found_value = tokenizer.readMaybeDouble().unwrap();
+ CHECK(found_value.isSome());
CHECK(EXPECTED_value == *found_value); // Apparently, CHECK_EQUAL doesn't work on `double`.
- CHECK(Tokenizer::equals(*found_id, "foo"));
- CHECK(guard.done());
+ CHECK(Tokenizer::equals(found_id, "foo"));
+ CHECK(guard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterSimpleTaggedTuple)
// Reading an empty list
@@ -238,49 +238,49 @@ BEGIN_TEST(testBinTokenReaderTesterEmpty
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-empty-list.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
uint32_t length;
Tokenizer::AutoList guard(tokenizer);
- CHECK(tokenizer.enterList(length, guard));
+ CHECK(tokenizer.enterList(length, guard).isOk());
CHECK(length == 0);
- CHECK(guard.done());
+ CHECK(guard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterEmptyList)
// Reading `["foo", "bar"]`
BEGIN_TEST(testBinTokenReaderTesterSimpleList)
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-trivial-list.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
uint32_t length;
Tokenizer::AutoList guard(tokenizer);
- CHECK(tokenizer.enterList(length, guard));
+ CHECK(tokenizer.enterList(length, guard).isOk());
CHECK(length == 2);
- Maybe<Chars> found_0;
- CHECK(tokenizer.readMaybeChars(found_0));
- CHECK(Tokenizer::equals(*found_0, "foo"));
+ Chars found_0(cx);
+ CHECK(tokenizer.readChars(found_0).isOk());
+ CHECK(Tokenizer::equals(found_0, "foo"));
- Maybe<Chars> found_1;
- CHECK(tokenizer.readMaybeChars(found_1));
- CHECK(Tokenizer::equals(*found_1, "bar"));
+ Chars found_1(cx);
+ CHECK(tokenizer.readChars(found_1).isOk());
+ CHECK(Tokenizer::equals(found_1, "bar"));
- CHECK(guard.done());
+ CHECK(guard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterSimpleList)
// Reading `[["foo", "bar"]]`
@@ -288,34 +288,34 @@ BEGIN_TEST(testBinTokenReaderTesterNeste
{
js::Vector<uint8_t> contents(cx);
readFull("jsapi-tests/binast/tokenizer/tester/test-nested-lists.binjs", contents);
Tokenizer tokenizer(cx, contents);
{
uint32_t outerLength;
Tokenizer::AutoList outerGuard(tokenizer);
- CHECK(tokenizer.enterList(outerLength, outerGuard));
+ CHECK(tokenizer.enterList(outerLength, outerGuard).isOk());
CHECK(outerLength == 1);
{
uint32_t innerLength;
Tokenizer::AutoList innerGuard(tokenizer);
- CHECK(tokenizer.enterList(innerLength, innerGuard));
+ CHECK(tokenizer.enterList(innerLength, innerGuard).isOk());
CHECK(innerLength == 2);
- Maybe<Chars> found_0;
- CHECK(tokenizer.readMaybeChars(found_0));
- CHECK(Tokenizer::equals(*found_0, "foo"));
+ Chars found_0(cx);
+ CHECK(tokenizer.readChars(found_0).isOk());
+ CHECK(Tokenizer::equals(found_0, "foo"));
- Maybe<Chars> found_1;
- CHECK(tokenizer.readMaybeChars(found_1));
- CHECK(Tokenizer::equals(*found_1, "bar"));
+ Chars found_1(cx);
+ CHECK(tokenizer.readChars(found_1).isOk());
+ CHECK(Tokenizer::equals(found_1, "bar"));
- CHECK(innerGuard.done());
+ CHECK(innerGuard.done().isOk());
}
- CHECK(outerGuard.done());
+ CHECK(outerGuard.done().isOk());
}
return true;
}
END_TEST(testBinTokenReaderTesterNestedList)