Chris@0: /*!
Chris@0: * jQuery JavaScript Library v3.2.1
Chris@0: * https://jquery.com/
Chris@0: *
Chris@0: * Includes Sizzle.js
Chris@0: * https://sizzlejs.com/
Chris@0: *
Chris@0: * Copyright JS Foundation and other contributors
Chris@0: * Released under the MIT license
Chris@0: * https://jquery.org/license
Chris@0: *
Chris@0: * Date: 2017-03-20T18:59Z
Chris@0: */
Chris@0: ( function( global, factory ) {
Chris@0:
Chris@0: "use strict";
Chris@0:
Chris@0: if ( typeof module === "object" && typeof module.exports === "object" ) {
Chris@0:
Chris@0: // For CommonJS and CommonJS-like environments where a proper `window`
Chris@0: // is present, execute the factory and get jQuery.
Chris@0: // For environments that do not have a `window` with a `document`
Chris@0: // (such as Node.js), expose a factory as module.exports.
Chris@0: // This accentuates the need for the creation of a real `window`.
Chris@0: // e.g. var jQuery = require("jquery")(window);
Chris@0: // See ticket #14549 for more info.
Chris@0: module.exports = global.document ?
Chris@0: factory( global, true ) :
Chris@0: function( w ) {
Chris@0: if ( !w.document ) {
Chris@0: throw new Error( "jQuery requires a window with a document" );
Chris@0: }
Chris@0: return factory( w );
Chris@0: };
Chris@0: } else {
Chris@0: factory( global );
Chris@0: }
Chris@0:
Chris@0: // Pass this if window is not defined yet
Chris@0: } )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
Chris@0:
Chris@0: // Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
Chris@0: // throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
Chris@0: // arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
Chris@0: // enough that all such attempts are guarded in a try block.
Chris@0: "use strict";
Chris@0:
Chris@0: var arr = [];
Chris@0:
Chris@0: var document = window.document;
Chris@0:
Chris@0: var getProto = Object.getPrototypeOf;
Chris@0:
Chris@0: var slice = arr.slice;
Chris@0:
Chris@0: var concat = arr.concat;
Chris@0:
Chris@0: var push = arr.push;
Chris@0:
Chris@0: var indexOf = arr.indexOf;
Chris@0:
Chris@0: var class2type = {};
Chris@0:
Chris@0: var toString = class2type.toString;
Chris@0:
Chris@0: var hasOwn = class2type.hasOwnProperty;
Chris@0:
Chris@0: var fnToString = hasOwn.toString;
Chris@0:
Chris@0: var ObjectFunctionString = fnToString.call( Object );
Chris@0:
Chris@0: var support = {};
Chris@0:
Chris@0:
Chris@0:
Chris@0: function DOMEval( code, doc ) {
Chris@0: doc = doc || document;
Chris@0:
Chris@0: var script = doc.createElement( "script" );
Chris@0:
Chris@0: script.text = code;
Chris@0: doc.head.appendChild( script ).parentNode.removeChild( script );
Chris@0: }
Chris@0: /* global Symbol */
Chris@0: // Defining this global in .eslintrc.json would create a danger of using the global
Chris@0: // unguarded in another place, it seems safer to define global only for this module
Chris@0:
Chris@0:
Chris@0:
Chris@0: var
Chris@0: version = "3.2.1",
Chris@0:
Chris@0: // Define a local copy of jQuery
Chris@0: jQuery = function( selector, context ) {
Chris@0:
Chris@0: // The jQuery object is actually just the init constructor 'enhanced'
Chris@0: // Need init if jQuery is called (just allow error to be thrown if not included)
Chris@0: return new jQuery.fn.init( selector, context );
Chris@0: },
Chris@0:
Chris@0: // Support: Android <=4.0 only
Chris@0: // Make sure we trim BOM and NBSP
Chris@0: rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
Chris@0:
Chris@0: // Matches dashed string for camelizing
Chris@0: rmsPrefix = /^-ms-/,
Chris@0: rdashAlpha = /-([a-z])/g,
Chris@0:
Chris@0: // Used by jQuery.camelCase as callback to replace()
Chris@0: fcamelCase = function( all, letter ) {
Chris@0: return letter.toUpperCase();
Chris@0: };
Chris@0:
Chris@0: jQuery.fn = jQuery.prototype = {
Chris@0:
Chris@0: // The current version of jQuery being used
Chris@0: jquery: version,
Chris@0:
Chris@0: constructor: jQuery,
Chris@0:
Chris@0: // The default length of a jQuery object is 0
Chris@0: length: 0,
Chris@0:
Chris@0: toArray: function() {
Chris@0: return slice.call( this );
Chris@0: },
Chris@0:
Chris@0: // Get the Nth element in the matched element set OR
Chris@0: // Get the whole matched element set as a clean array
Chris@0: get: function( num ) {
Chris@0:
Chris@0: // Return all the elements in a clean array
Chris@0: if ( num == null ) {
Chris@0: return slice.call( this );
Chris@0: }
Chris@0:
Chris@0: // Return just the one element from the set
Chris@0: return num < 0 ? this[ num + this.length ] : this[ num ];
Chris@0: },
Chris@0:
Chris@0: // Take an array of elements and push it onto the stack
Chris@0: // (returning the new matched element set)
Chris@0: pushStack: function( elems ) {
Chris@0:
Chris@0: // Build a new jQuery matched element set
Chris@0: var ret = jQuery.merge( this.constructor(), elems );
Chris@0:
Chris@0: // Add the old object onto the stack (as a reference)
Chris@0: ret.prevObject = this;
Chris@0:
Chris@0: // Return the newly-formed element set
Chris@0: return ret;
Chris@0: },
Chris@0:
Chris@0: // Execute a callback for every element in the matched set.
Chris@0: each: function( callback ) {
Chris@0: return jQuery.each( this, callback );
Chris@0: },
Chris@0:
Chris@0: map: function( callback ) {
Chris@0: return this.pushStack( jQuery.map( this, function( elem, i ) {
Chris@0: return callback.call( elem, i, elem );
Chris@0: } ) );
Chris@0: },
Chris@0:
Chris@0: slice: function() {
Chris@0: return this.pushStack( slice.apply( this, arguments ) );
Chris@0: },
Chris@0:
Chris@0: first: function() {
Chris@0: return this.eq( 0 );
Chris@0: },
Chris@0:
Chris@0: last: function() {
Chris@0: return this.eq( -1 );
Chris@0: },
Chris@0:
Chris@0: eq: function( i ) {
Chris@0: var len = this.length,
Chris@0: j = +i + ( i < 0 ? len : 0 );
Chris@0: return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
Chris@0: },
Chris@0:
Chris@0: end: function() {
Chris@0: return this.prevObject || this.constructor();
Chris@0: },
Chris@0:
Chris@0: // For internal use only.
Chris@0: // Behaves like an Array's method, not like a jQuery method.
Chris@0: push: push,
Chris@0: sort: arr.sort,
Chris@0: splice: arr.splice
Chris@0: };
Chris@0:
Chris@0: jQuery.extend = jQuery.fn.extend = function() {
Chris@0: var options, name, src, copy, copyIsArray, clone,
Chris@0: target = arguments[ 0 ] || {},
Chris@0: i = 1,
Chris@0: length = arguments.length,
Chris@0: deep = false;
Chris@0:
Chris@0: // Handle a deep copy situation
Chris@0: if ( typeof target === "boolean" ) {
Chris@0: deep = target;
Chris@0:
Chris@0: // Skip the boolean and the target
Chris@0: target = arguments[ i ] || {};
Chris@0: i++;
Chris@0: }
Chris@0:
Chris@0: // Handle case when target is a string or something (possible in deep copy)
Chris@0: if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
Chris@0: target = {};
Chris@0: }
Chris@0:
Chris@0: // Extend jQuery itself if only one argument is passed
Chris@0: if ( i === length ) {
Chris@0: target = this;
Chris@0: i--;
Chris@0: }
Chris@0:
Chris@0: for ( ; i < length; i++ ) {
Chris@0:
Chris@0: // Only deal with non-null/undefined values
Chris@0: if ( ( options = arguments[ i ] ) != null ) {
Chris@0:
Chris@0: // Extend the base object
Chris@0: for ( name in options ) {
Chris@0: src = target[ name ];
Chris@0: copy = options[ name ];
Chris@0:
Chris@0: // Prevent never-ending loop
Chris@0: if ( target === copy ) {
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: // Recurse if we're merging plain objects or arrays
Chris@0: if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
Chris@0: ( copyIsArray = Array.isArray( copy ) ) ) ) {
Chris@0:
Chris@0: if ( copyIsArray ) {
Chris@0: copyIsArray = false;
Chris@0: clone = src && Array.isArray( src ) ? src : [];
Chris@0:
Chris@0: } else {
Chris@0: clone = src && jQuery.isPlainObject( src ) ? src : {};
Chris@0: }
Chris@0:
Chris@0: // Never move original objects, clone them
Chris@0: target[ name ] = jQuery.extend( deep, clone, copy );
Chris@0:
Chris@0: // Don't bring in undefined values
Chris@0: } else if ( copy !== undefined ) {
Chris@0: target[ name ] = copy;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Return the modified object
Chris@0: return target;
Chris@0: };
Chris@0:
Chris@0: jQuery.extend( {
Chris@0:
Chris@0: // Unique for each copy of jQuery on the page
Chris@0: expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
Chris@0:
Chris@0: // Assume jQuery is ready without the ready module
Chris@0: isReady: true,
Chris@0:
Chris@0: error: function( msg ) {
Chris@0: throw new Error( msg );
Chris@0: },
Chris@0:
Chris@0: noop: function() {},
Chris@0:
Chris@0: isFunction: function( obj ) {
Chris@0: return jQuery.type( obj ) === "function";
Chris@0: },
Chris@0:
Chris@0: isWindow: function( obj ) {
Chris@0: return obj != null && obj === obj.window;
Chris@0: },
Chris@0:
Chris@0: isNumeric: function( obj ) {
Chris@0:
Chris@0: // As of jQuery 3.0, isNumeric is limited to
Chris@0: // strings and numbers (primitives or objects)
Chris@0: // that can be coerced to finite numbers (gh-2662)
Chris@0: var type = jQuery.type( obj );
Chris@0: return ( type === "number" || type === "string" ) &&
Chris@0:
Chris@0: // parseFloat NaNs numeric-cast false positives ("")
Chris@0: // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
Chris@0: // subtraction forces infinities to NaN
Chris@0: !isNaN( obj - parseFloat( obj ) );
Chris@0: },
Chris@0:
Chris@0: isPlainObject: function( obj ) {
Chris@0: var proto, Ctor;
Chris@0:
Chris@0: // Detect obvious negatives
Chris@0: // Use toString instead of jQuery.type to catch host objects
Chris@0: if ( !obj || toString.call( obj ) !== "[object Object]" ) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@0: proto = getProto( obj );
Chris@0:
Chris@0: // Objects with no prototype (e.g., `Object.create( null )`) are plain
Chris@0: if ( !proto ) {
Chris@0: return true;
Chris@0: }
Chris@0:
Chris@0: // Objects with prototype are plain iff they were constructed by a global Object function
Chris@0: Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
Chris@0: return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
Chris@0: },
Chris@0:
Chris@0: isEmptyObject: function( obj ) {
Chris@0:
Chris@0: /* eslint-disable no-unused-vars */
Chris@0: // See https://github.com/eslint/eslint/issues/6125
Chris@0: var name;
Chris@0:
Chris@0: for ( name in obj ) {
Chris@0: return false;
Chris@0: }
Chris@0: return true;
Chris@0: },
Chris@0:
Chris@0: type: function( obj ) {
Chris@0: if ( obj == null ) {
Chris@0: return obj + "";
Chris@0: }
Chris@0:
Chris@0: // Support: Android <=2.3 only (functionish RegExp)
Chris@0: return typeof obj === "object" || typeof obj === "function" ?
Chris@0: class2type[ toString.call( obj ) ] || "object" :
Chris@0: typeof obj;
Chris@0: },
Chris@0:
Chris@0: // Evaluates a script in a global context
Chris@0: globalEval: function( code ) {
Chris@0: DOMEval( code );
Chris@0: },
Chris@0:
Chris@0: // Convert dashed to camelCase; used by the css and data modules
Chris@0: // Support: IE <=9 - 11, Edge 12 - 13
Chris@0: // Microsoft forgot to hump their vendor prefix (#9572)
Chris@0: camelCase: function( string ) {
Chris@0: return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
Chris@0: },
Chris@0:
Chris@0: each: function( obj, callback ) {
Chris@0: var length, i = 0;
Chris@0:
Chris@0: if ( isArrayLike( obj ) ) {
Chris@0: length = obj.length;
Chris@0: for ( ; i < length; i++ ) {
Chris@0: if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: } else {
Chris@0: for ( i in obj ) {
Chris@0: if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return obj;
Chris@0: },
Chris@0:
Chris@0: // Support: Android <=4.0 only
Chris@0: trim: function( text ) {
Chris@0: return text == null ?
Chris@0: "" :
Chris@0: ( text + "" ).replace( rtrim, "" );
Chris@0: },
Chris@0:
Chris@0: // results is for internal usage only
Chris@0: makeArray: function( arr, results ) {
Chris@0: var ret = results || [];
Chris@0:
Chris@0: if ( arr != null ) {
Chris@0: if ( isArrayLike( Object( arr ) ) ) {
Chris@0: jQuery.merge( ret,
Chris@0: typeof arr === "string" ?
Chris@0: [ arr ] : arr
Chris@0: );
Chris@0: } else {
Chris@0: push.call( ret, arr );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return ret;
Chris@0: },
Chris@0:
Chris@0: inArray: function( elem, arr, i ) {
Chris@0: return arr == null ? -1 : indexOf.call( arr, elem, i );
Chris@0: },
Chris@0:
Chris@0: // Support: Android <=4.0 only, PhantomJS 1 only
Chris@0: // push.apply(_, arraylike) throws on ancient WebKit
Chris@0: merge: function( first, second ) {
Chris@0: var len = +second.length,
Chris@0: j = 0,
Chris@0: i = first.length;
Chris@0:
Chris@0: for ( ; j < len; j++ ) {
Chris@0: first[ i++ ] = second[ j ];
Chris@0: }
Chris@0:
Chris@0: first.length = i;
Chris@0:
Chris@0: return first;
Chris@0: },
Chris@0:
Chris@0: grep: function( elems, callback, invert ) {
Chris@0: var callbackInverse,
Chris@0: matches = [],
Chris@0: i = 0,
Chris@0: length = elems.length,
Chris@0: callbackExpect = !invert;
Chris@0:
Chris@0: // Go through the array, only saving the items
Chris@0: // that pass the validator function
Chris@0: for ( ; i < length; i++ ) {
Chris@0: callbackInverse = !callback( elems[ i ], i );
Chris@0: if ( callbackInverse !== callbackExpect ) {
Chris@0: matches.push( elems[ i ] );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return matches;
Chris@0: },
Chris@0:
Chris@0: // arg is for internal usage only
Chris@0: map: function( elems, callback, arg ) {
Chris@0: var length, value,
Chris@0: i = 0,
Chris@0: ret = [];
Chris@0:
Chris@0: // Go through the array, translating each of the items to their new values
Chris@0: if ( isArrayLike( elems ) ) {
Chris@0: length = elems.length;
Chris@0: for ( ; i < length; i++ ) {
Chris@0: value = callback( elems[ i ], i, arg );
Chris@0:
Chris@0: if ( value != null ) {
Chris@0: ret.push( value );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Go through every key on the object,
Chris@0: } else {
Chris@0: for ( i in elems ) {
Chris@0: value = callback( elems[ i ], i, arg );
Chris@0:
Chris@0: if ( value != null ) {
Chris@0: ret.push( value );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Flatten any nested arrays
Chris@0: return concat.apply( [], ret );
Chris@0: },
Chris@0:
Chris@0: // A global GUID counter for objects
Chris@0: guid: 1,
Chris@0:
Chris@0: // Bind a function to a context, optionally partially applying any
Chris@0: // arguments.
Chris@0: proxy: function( fn, context ) {
Chris@0: var tmp, args, proxy;
Chris@0:
Chris@0: if ( typeof context === "string" ) {
Chris@0: tmp = fn[ context ];
Chris@0: context = fn;
Chris@0: fn = tmp;
Chris@0: }
Chris@0:
Chris@0: // Quick check to determine if target is callable, in the spec
Chris@0: // this throws a TypeError, but we will just return undefined.
Chris@0: if ( !jQuery.isFunction( fn ) ) {
Chris@0: return undefined;
Chris@0: }
Chris@0:
Chris@0: // Simulated bind
Chris@0: args = slice.call( arguments, 2 );
Chris@0: proxy = function() {
Chris@0: return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
Chris@0: };
Chris@0:
Chris@0: // Set the guid of unique handler to the same of original handler, so it can be removed
Chris@0: proxy.guid = fn.guid = fn.guid || jQuery.guid++;
Chris@0:
Chris@0: return proxy;
Chris@0: },
Chris@0:
Chris@0: now: Date.now,
Chris@0:
Chris@0: // jQuery.support is not used in Core but other projects attach their
Chris@0: // properties to it so it needs to exist.
Chris@0: support: support
Chris@0: } );
Chris@0:
Chris@0: if ( typeof Symbol === "function" ) {
Chris@0: jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
Chris@0: }
Chris@0:
Chris@0: // Populate the class2type map
Chris@0: jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
Chris@0: function( i, name ) {
Chris@0: class2type[ "[object " + name + "]" ] = name.toLowerCase();
Chris@0: } );
Chris@0:
Chris@0: function isArrayLike( obj ) {
Chris@0:
Chris@0: // Support: real iOS 8.2 only (not reproducible in simulator)
Chris@0: // `in` check used to prevent JIT error (gh-2145)
Chris@0: // hasOwn isn't used here due to false negatives
Chris@0: // regarding Nodelist length in IE
Chris@0: var length = !!obj && "length" in obj && obj.length,
Chris@0: type = jQuery.type( obj );
Chris@0:
Chris@0: if ( type === "function" || jQuery.isWindow( obj ) ) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@0: return type === "array" || length === 0 ||
Chris@0: typeof length === "number" && length > 0 && ( length - 1 ) in obj;
Chris@0: }
Chris@0: var Sizzle =
Chris@0: /*!
Chris@0: * Sizzle CSS Selector Engine v2.3.3
Chris@0: * https://sizzlejs.com/
Chris@0: *
Chris@0: * Copyright jQuery Foundation and other contributors
Chris@0: * Released under the MIT license
Chris@0: * http://jquery.org/license
Chris@0: *
Chris@0: * Date: 2016-08-08
Chris@0: */
Chris@0: (function( window ) {
Chris@0:
Chris@0: var i,
Chris@0: support,
Chris@0: Expr,
Chris@0: getText,
Chris@0: isXML,
Chris@0: tokenize,
Chris@0: compile,
Chris@0: select,
Chris@0: outermostContext,
Chris@0: sortInput,
Chris@0: hasDuplicate,
Chris@0:
Chris@0: // Local document vars
Chris@0: setDocument,
Chris@0: document,
Chris@0: docElem,
Chris@0: documentIsHTML,
Chris@0: rbuggyQSA,
Chris@0: rbuggyMatches,
Chris@0: matches,
Chris@0: contains,
Chris@0:
Chris@0: // Instance-specific data
Chris@0: expando = "sizzle" + 1 * new Date(),
Chris@0: preferredDoc = window.document,
Chris@0: dirruns = 0,
Chris@0: done = 0,
Chris@0: classCache = createCache(),
Chris@0: tokenCache = createCache(),
Chris@0: compilerCache = createCache(),
Chris@0: sortOrder = function( a, b ) {
Chris@0: if ( a === b ) {
Chris@0: hasDuplicate = true;
Chris@0: }
Chris@0: return 0;
Chris@0: },
Chris@0:
Chris@0: // Instance methods
Chris@0: hasOwn = ({}).hasOwnProperty,
Chris@0: arr = [],
Chris@0: pop = arr.pop,
Chris@0: push_native = arr.push,
Chris@0: push = arr.push,
Chris@0: slice = arr.slice,
Chris@0: // Use a stripped-down indexOf as it's faster than native
Chris@0: // https://jsperf.com/thor-indexof-vs-for/5
Chris@0: indexOf = function( list, elem ) {
Chris@0: var i = 0,
Chris@0: len = list.length;
Chris@0: for ( ; i < len; i++ ) {
Chris@0: if ( list[i] === elem ) {
Chris@0: return i;
Chris@0: }
Chris@0: }
Chris@0: return -1;
Chris@0: },
Chris@0:
Chris@0: booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
Chris@0:
Chris@0: // Regular expressions
Chris@0:
Chris@0: // http://www.w3.org/TR/css3-selectors/#whitespace
Chris@0: whitespace = "[\\x20\\t\\r\\n\\f]",
Chris@0:
Chris@0: // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
Chris@0: identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
Chris@0:
Chris@0: // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
Chris@0: attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
Chris@0: // Operator (capture 2)
Chris@0: "*([*^$|!~]?=)" + whitespace +
Chris@0: // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
Chris@0: "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
Chris@0: "*\\]",
Chris@0:
Chris@0: pseudos = ":(" + identifier + ")(?:\\((" +
Chris@0: // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
Chris@0: // 1. quoted (capture 3; capture 4 or capture 5)
Chris@0: "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
Chris@0: // 2. simple (capture 6)
Chris@0: "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
Chris@0: // 3. anything else (capture 2)
Chris@0: ".*" +
Chris@0: ")\\)|)",
Chris@0:
Chris@0: // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
Chris@0: rwhitespace = new RegExp( whitespace + "+", "g" ),
Chris@0: rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
Chris@0:
Chris@0: rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
Chris@0: rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
Chris@0:
Chris@0: rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
Chris@0:
Chris@0: rpseudo = new RegExp( pseudos ),
Chris@0: ridentifier = new RegExp( "^" + identifier + "$" ),
Chris@0:
Chris@0: matchExpr = {
Chris@0: "ID": new RegExp( "^#(" + identifier + ")" ),
Chris@0: "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
Chris@0: "TAG": new RegExp( "^(" + identifier + "|[*])" ),
Chris@0: "ATTR": new RegExp( "^" + attributes ),
Chris@0: "PSEUDO": new RegExp( "^" + pseudos ),
Chris@0: "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
Chris@0: "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
Chris@0: "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
Chris@0: "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
Chris@0: // For use in libraries implementing .is()
Chris@0: // We use this for POS matching in `select`
Chris@0: "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
Chris@0: whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
Chris@0: },
Chris@0:
Chris@0: rinputs = /^(?:input|select|textarea|button)$/i,
Chris@0: rheader = /^h\d$/i,
Chris@0:
Chris@0: rnative = /^[^{]+\{\s*\[native \w/,
Chris@0:
Chris@0: // Easily-parseable/retrievable ID or TAG or CLASS selectors
Chris@0: rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
Chris@0:
Chris@0: rsibling = /[+~]/,
Chris@0:
Chris@0: // CSS escapes
Chris@0: // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
Chris@0: runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
Chris@0: funescape = function( _, escaped, escapedWhitespace ) {
Chris@0: var high = "0x" + escaped - 0x10000;
Chris@0: // NaN means non-codepoint
Chris@0: // Support: Firefox<24
Chris@0: // Workaround erroneous numeric interpretation of +"0x"
Chris@0: return high !== high || escapedWhitespace ?
Chris@0: escaped :
Chris@0: high < 0 ?
Chris@0: // BMP codepoint
Chris@0: String.fromCharCode( high + 0x10000 ) :
Chris@0: // Supplemental Plane codepoint (surrogate pair)
Chris@0: String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
Chris@0: },
Chris@0:
Chris@0: // CSS string/identifier serialization
Chris@0: // https://drafts.csswg.org/cssom/#common-serializing-idioms
Chris@0: rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
Chris@0: fcssescape = function( ch, asCodePoint ) {
Chris@0: if ( asCodePoint ) {
Chris@0:
Chris@0: // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
Chris@0: if ( ch === "\0" ) {
Chris@0: return "\uFFFD";
Chris@0: }
Chris@0:
Chris@0: // Control characters and (dependent upon position) numbers get escaped as code points
Chris@0: return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
Chris@0: }
Chris@0:
Chris@0: // Other potentially-special ASCII characters get backslash-escaped
Chris@0: return "\\" + ch;
Chris@0: },
Chris@0:
Chris@0: // Used for iframes
Chris@0: // See setDocument()
Chris@0: // Removing the function wrapper causes a "Permission Denied"
Chris@0: // error in IE
Chris@0: unloadHandler = function() {
Chris@0: setDocument();
Chris@0: },
Chris@0:
Chris@0: disabledAncestor = addCombinator(
Chris@0: function( elem ) {
Chris@0: return elem.disabled === true && ("form" in elem || "label" in elem);
Chris@0: },
Chris@0: { dir: "parentNode", next: "legend" }
Chris@0: );
Chris@0:
Chris@0: // Optimize for push.apply( _, NodeList )
Chris@0: try {
Chris@0: push.apply(
Chris@0: (arr = slice.call( preferredDoc.childNodes )),
Chris@0: preferredDoc.childNodes
Chris@0: );
Chris@0: // Support: Android<4.0
Chris@0: // Detect silently failing push.apply
Chris@0: arr[ preferredDoc.childNodes.length ].nodeType;
Chris@0: } catch ( e ) {
Chris@0: push = { apply: arr.length ?
Chris@0:
Chris@0: // Leverage slice if possible
Chris@0: function( target, els ) {
Chris@0: push_native.apply( target, slice.call(els) );
Chris@0: } :
Chris@0:
Chris@0: // Support: IE<9
Chris@0: // Otherwise append directly
Chris@0: function( target, els ) {
Chris@0: var j = target.length,
Chris@0: i = 0;
Chris@0: // Can't trust NodeList.length
Chris@0: while ( (target[j++] = els[i++]) ) {}
Chris@0: target.length = j - 1;
Chris@0: }
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: function Sizzle( selector, context, results, seed ) {
Chris@0: var m, i, elem, nid, match, groups, newSelector,
Chris@0: newContext = context && context.ownerDocument,
Chris@0:
Chris@0: // nodeType defaults to 9, since context defaults to document
Chris@0: nodeType = context ? context.nodeType : 9;
Chris@0:
Chris@0: results = results || [];
Chris@0:
Chris@0: // Return early from calls with invalid selector or context
Chris@0: if ( typeof selector !== "string" || !selector ||
Chris@0: nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
Chris@0:
Chris@0: return results;
Chris@0: }
Chris@0:
Chris@0: // Try to shortcut find operations (as opposed to filters) in HTML documents
Chris@0: if ( !seed ) {
Chris@0:
Chris@0: if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
Chris@0: setDocument( context );
Chris@0: }
Chris@0: context = context || document;
Chris@0:
Chris@0: if ( documentIsHTML ) {
Chris@0:
Chris@0: // If the selector is sufficiently simple, try using a "get*By*" DOM method
Chris@0: // (excepting DocumentFragment context, where the methods don't exist)
Chris@0: if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
Chris@0:
Chris@0: // ID selector
Chris@0: if ( (m = match[1]) ) {
Chris@0:
Chris@0: // Document context
Chris@0: if ( nodeType === 9 ) {
Chris@0: if ( (elem = context.getElementById( m )) ) {
Chris@0:
Chris@0: // Support: IE, Opera, Webkit
Chris@0: // TODO: identify versions
Chris@0: // getElementById can match elements by name instead of ID
Chris@0: if ( elem.id === m ) {
Chris@0: results.push( elem );
Chris@0: return results;
Chris@0: }
Chris@0: } else {
Chris@0: return results;
Chris@0: }
Chris@0:
Chris@0: // Element context
Chris@0: } else {
Chris@0:
Chris@0: // Support: IE, Opera, Webkit
Chris@0: // TODO: identify versions
Chris@0: // getElementById can match elements by name instead of ID
Chris@0: if ( newContext && (elem = newContext.getElementById( m )) &&
Chris@0: contains( context, elem ) &&
Chris@0: elem.id === m ) {
Chris@0:
Chris@0: results.push( elem );
Chris@0: return results;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Type selector
Chris@0: } else if ( match[2] ) {
Chris@0: push.apply( results, context.getElementsByTagName( selector ) );
Chris@0: return results;
Chris@0:
Chris@0: // Class selector
Chris@0: } else if ( (m = match[3]) && support.getElementsByClassName &&
Chris@0: context.getElementsByClassName ) {
Chris@0:
Chris@0: push.apply( results, context.getElementsByClassName( m ) );
Chris@0: return results;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Take advantage of querySelectorAll
Chris@0: if ( support.qsa &&
Chris@0: !compilerCache[ selector + " " ] &&
Chris@0: (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
Chris@0:
Chris@0: if ( nodeType !== 1 ) {
Chris@0: newContext = context;
Chris@0: newSelector = selector;
Chris@0:
Chris@0: // qSA looks outside Element context, which is not what we want
Chris@0: // Thanks to Andrew Dupont for this workaround technique
Chris@0: // Support: IE <=8
Chris@0: // Exclude object elements
Chris@0: } else if ( context.nodeName.toLowerCase() !== "object" ) {
Chris@0:
Chris@0: // Capture the context ID, setting it first if necessary
Chris@0: if ( (nid = context.getAttribute( "id" )) ) {
Chris@0: nid = nid.replace( rcssescape, fcssescape );
Chris@0: } else {
Chris@0: context.setAttribute( "id", (nid = expando) );
Chris@0: }
Chris@0:
Chris@0: // Prefix every selector in the list
Chris@0: groups = tokenize( selector );
Chris@0: i = groups.length;
Chris@0: while ( i-- ) {
Chris@0: groups[i] = "#" + nid + " " + toSelector( groups[i] );
Chris@0: }
Chris@0: newSelector = groups.join( "," );
Chris@0:
Chris@0: // Expand context for sibling selectors
Chris@0: newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
Chris@0: context;
Chris@0: }
Chris@0:
Chris@0: if ( newSelector ) {
Chris@0: try {
Chris@0: push.apply( results,
Chris@0: newContext.querySelectorAll( newSelector )
Chris@0: );
Chris@0: return results;
Chris@0: } catch ( qsaError ) {
Chris@0: } finally {
Chris@0: if ( nid === expando ) {
Chris@0: context.removeAttribute( "id" );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // All others
Chris@0: return select( selector.replace( rtrim, "$1" ), context, results, seed );
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Create key-value caches of limited size
Chris@0: * @returns {function(string, object)} Returns the Object data after storing it on itself with
Chris@0: * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
Chris@0: * deleting the oldest entry
Chris@0: */
Chris@0: function createCache() {
Chris@0: var keys = [];
Chris@0:
Chris@0: function cache( key, value ) {
Chris@0: // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
Chris@0: if ( keys.push( key + " " ) > Expr.cacheLength ) {
Chris@0: // Only keep the most recent entries
Chris@0: delete cache[ keys.shift() ];
Chris@0: }
Chris@0: return (cache[ key + " " ] = value);
Chris@0: }
Chris@0: return cache;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Mark a function for special use by Sizzle
Chris@0: * @param {Function} fn The function to mark
Chris@0: */
Chris@0: function markFunction( fn ) {
Chris@0: fn[ expando ] = true;
Chris@0: return fn;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Support testing using an element
Chris@0: * @param {Function} fn Passed the created element and returns a boolean result
Chris@0: */
Chris@0: function assert( fn ) {
Chris@0: var el = document.createElement("fieldset");
Chris@0:
Chris@0: try {
Chris@0: return !!fn( el );
Chris@0: } catch (e) {
Chris@0: return false;
Chris@0: } finally {
Chris@0: // Remove from its parent by default
Chris@0: if ( el.parentNode ) {
Chris@0: el.parentNode.removeChild( el );
Chris@0: }
Chris@0: // release memory in IE
Chris@0: el = null;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Adds the same handler for all of the specified attrs
Chris@0: * @param {String} attrs Pipe-separated list of attributes
Chris@0: * @param {Function} handler The method that will be applied
Chris@0: */
Chris@0: function addHandle( attrs, handler ) {
Chris@0: var arr = attrs.split("|"),
Chris@0: i = arr.length;
Chris@0:
Chris@0: while ( i-- ) {
Chris@0: Expr.attrHandle[ arr[i] ] = handler;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Checks document order of two siblings
Chris@0: * @param {Element} a
Chris@0: * @param {Element} b
Chris@0: * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
Chris@0: */
Chris@0: function siblingCheck( a, b ) {
Chris@0: var cur = b && a,
Chris@0: diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
Chris@0: a.sourceIndex - b.sourceIndex;
Chris@0:
Chris@0: // Use IE sourceIndex if available on both nodes
Chris@0: if ( diff ) {
Chris@0: return diff;
Chris@0: }
Chris@0:
Chris@0: // Check if b follows a
Chris@0: if ( cur ) {
Chris@0: while ( (cur = cur.nextSibling) ) {
Chris@0: if ( cur === b ) {
Chris@0: return -1;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return a ? 1 : -1;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Returns a function to use in pseudos for input types
Chris@0: * @param {String} type
Chris@0: */
Chris@0: function createInputPseudo( type ) {
Chris@0: return function( elem ) {
Chris@0: var name = elem.nodeName.toLowerCase();
Chris@0: return name === "input" && elem.type === type;
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Returns a function to use in pseudos for buttons
Chris@0: * @param {String} type
Chris@0: */
Chris@0: function createButtonPseudo( type ) {
Chris@0: return function( elem ) {
Chris@0: var name = elem.nodeName.toLowerCase();
Chris@0: return (name === "input" || name === "button") && elem.type === type;
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Returns a function to use in pseudos for :enabled/:disabled
Chris@0: * @param {Boolean} disabled true for :disabled; false for :enabled
Chris@0: */
Chris@0: function createDisabledPseudo( disabled ) {
Chris@0:
Chris@0: // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
Chris@0: return function( elem ) {
Chris@0:
Chris@0: // Only certain elements can match :enabled or :disabled
Chris@0: // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
Chris@0: // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
Chris@0: if ( "form" in elem ) {
Chris@0:
Chris@0: // Check for inherited disabledness on relevant non-disabled elements:
Chris@0: // * listed form-associated elements in a disabled fieldset
Chris@0: // https://html.spec.whatwg.org/multipage/forms.html#category-listed
Chris@0: // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
Chris@0: // * option elements in a disabled optgroup
Chris@0: // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
Chris@0: // All such elements have a "form" property.
Chris@0: if ( elem.parentNode && elem.disabled === false ) {
Chris@0:
Chris@0: // Option elements defer to a parent optgroup if present
Chris@0: if ( "label" in elem ) {
Chris@0: if ( "label" in elem.parentNode ) {
Chris@0: return elem.parentNode.disabled === disabled;
Chris@0: } else {
Chris@0: return elem.disabled === disabled;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Support: IE 6 - 11
Chris@0: // Use the isDisabled shortcut property to check for disabled fieldset ancestors
Chris@0: return elem.isDisabled === disabled ||
Chris@0:
Chris@0: // Where there is no isDisabled, check manually
Chris@0: /* jshint -W018 */
Chris@0: elem.isDisabled !== !disabled &&
Chris@0: disabledAncestor( elem ) === disabled;
Chris@0: }
Chris@0:
Chris@0: return elem.disabled === disabled;
Chris@0:
Chris@0: // Try to winnow out elements that can't be disabled before trusting the disabled property.
Chris@0: // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
Chris@0: // even exist on them, let alone have a boolean value.
Chris@0: } else if ( "label" in elem ) {
Chris@0: return elem.disabled === disabled;
Chris@0: }
Chris@0:
Chris@0: // Remaining elements are neither :enabled nor :disabled
Chris@0: return false;
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Returns a function to use in pseudos for positionals
Chris@0: * @param {Function} fn
Chris@0: */
Chris@0: function createPositionalPseudo( fn ) {
Chris@0: return markFunction(function( argument ) {
Chris@0: argument = +argument;
Chris@0: return markFunction(function( seed, matches ) {
Chris@0: var j,
Chris@0: matchIndexes = fn( [], seed.length, argument ),
Chris@0: i = matchIndexes.length;
Chris@0:
Chris@0: // Match elements found at the specified indexes
Chris@0: while ( i-- ) {
Chris@0: if ( seed[ (j = matchIndexes[i]) ] ) {
Chris@0: seed[j] = !(matches[j] = seed[j]);
Chris@0: }
Chris@0: }
Chris@0: });
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Checks a node for validity as a Sizzle context
Chris@0: * @param {Element|Object=} context
Chris@0: * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
Chris@0: */
Chris@0: function testContext( context ) {
Chris@0: return context && typeof context.getElementsByTagName !== "undefined" && context;
Chris@0: }
Chris@0:
Chris@0: // Expose support vars for convenience
Chris@0: support = Sizzle.support = {};
Chris@0:
Chris@0: /**
Chris@0: * Detects XML nodes
Chris@0: * @param {Element|Object} elem An element or a document
Chris@0: * @returns {Boolean} True iff elem is a non-HTML XML node
Chris@0: */
Chris@0: isXML = Sizzle.isXML = function( elem ) {
Chris@0: // documentElement is verified for cases where it doesn't yet exist
Chris@0: // (such as loading iframes in IE - #4833)
Chris@0: var documentElement = elem && (elem.ownerDocument || elem).documentElement;
Chris@0: return documentElement ? documentElement.nodeName !== "HTML" : false;
Chris@0: };
Chris@0:
Chris@0: /**
Chris@0: * Sets document-related variables once based on the current document
Chris@0: * @param {Element|Object} [doc] An element or document object to use to set the document
Chris@0: * @returns {Object} Returns the current document
Chris@0: */
Chris@0: setDocument = Sizzle.setDocument = function( node ) {
Chris@0: var hasCompare, subWindow,
Chris@0: doc = node ? node.ownerDocument || node : preferredDoc;
Chris@0:
Chris@0: // Return early if doc is invalid or already selected
Chris@0: if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
Chris@0: return document;
Chris@0: }
Chris@0:
Chris@0: // Update global variables
Chris@0: document = doc;
Chris@0: docElem = document.documentElement;
Chris@0: documentIsHTML = !isXML( document );
Chris@0:
Chris@0: // Support: IE 9-11, Edge
Chris@0: // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
Chris@0: if ( preferredDoc !== document &&
Chris@0: (subWindow = document.defaultView) && subWindow.top !== subWindow ) {
Chris@0:
Chris@0: // Support: IE 11, Edge
Chris@0: if ( subWindow.addEventListener ) {
Chris@0: subWindow.addEventListener( "unload", unloadHandler, false );
Chris@0:
Chris@0: // Support: IE 9 - 10 only
Chris@0: } else if ( subWindow.attachEvent ) {
Chris@0: subWindow.attachEvent( "onunload", unloadHandler );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: /* Attributes
Chris@0: ---------------------------------------------------------------------- */
Chris@0:
Chris@0: // Support: IE<8
Chris@0: // Verify that getAttribute really returns attributes and not properties
Chris@0: // (excepting IE8 booleans)
Chris@0: support.attributes = assert(function( el ) {
Chris@0: el.className = "i";
Chris@0: return !el.getAttribute("className");
Chris@0: });
Chris@0:
Chris@0: /* getElement(s)By*
Chris@0: ---------------------------------------------------------------------- */
Chris@0:
Chris@0: // Check if getElementsByTagName("*") returns only elements
Chris@0: support.getElementsByTagName = assert(function( el ) {
Chris@0: el.appendChild( document.createComment("") );
Chris@0: return !el.getElementsByTagName("*").length;
Chris@0: });
Chris@0:
Chris@0: // Support: IE<9
Chris@0: support.getElementsByClassName = rnative.test( document.getElementsByClassName );
Chris@0:
Chris@0: // Support: IE<10
Chris@0: // Check if getElementById returns elements by name
Chris@0: // The broken getElementById methods don't pick up programmatically-set names,
Chris@0: // so use a roundabout getElementsByName test
Chris@0: support.getById = assert(function( el ) {
Chris@0: docElem.appendChild( el ).id = expando;
Chris@0: return !document.getElementsByName || !document.getElementsByName( expando ).length;
Chris@0: });
Chris@0:
Chris@0: // ID filter and find
Chris@0: if ( support.getById ) {
Chris@0: Expr.filter["ID"] = function( id ) {
Chris@0: var attrId = id.replace( runescape, funescape );
Chris@0: return function( elem ) {
Chris@0: return elem.getAttribute("id") === attrId;
Chris@0: };
Chris@0: };
Chris@0: Expr.find["ID"] = function( id, context ) {
Chris@0: if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
Chris@0: var elem = context.getElementById( id );
Chris@0: return elem ? [ elem ] : [];
Chris@0: }
Chris@0: };
Chris@0: } else {
Chris@0: Expr.filter["ID"] = function( id ) {
Chris@0: var attrId = id.replace( runescape, funescape );
Chris@0: return function( elem ) {
Chris@0: var node = typeof elem.getAttributeNode !== "undefined" &&
Chris@0: elem.getAttributeNode("id");
Chris@0: return node && node.value === attrId;
Chris@0: };
Chris@0: };
Chris@0:
Chris@0: // Support: IE 6 - 7 only
Chris@0: // getElementById is not reliable as a find shortcut
Chris@0: Expr.find["ID"] = function( id, context ) {
Chris@0: if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
Chris@0: var node, i, elems,
Chris@0: elem = context.getElementById( id );
Chris@0:
Chris@0: if ( elem ) {
Chris@0:
Chris@0: // Verify the id attribute
Chris@0: node = elem.getAttributeNode("id");
Chris@0: if ( node && node.value === id ) {
Chris@0: return [ elem ];
Chris@0: }
Chris@0:
Chris@0: // Fall back on getElementsByName
Chris@0: elems = context.getElementsByName( id );
Chris@0: i = 0;
Chris@0: while ( (elem = elems[i++]) ) {
Chris@0: node = elem.getAttributeNode("id");
Chris@0: if ( node && node.value === id ) {
Chris@0: return [ elem ];
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return [];
Chris@0: }
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: // Tag
Chris@0: Expr.find["TAG"] = support.getElementsByTagName ?
Chris@0: function( tag, context ) {
Chris@0: if ( typeof context.getElementsByTagName !== "undefined" ) {
Chris@0: return context.getElementsByTagName( tag );
Chris@0:
Chris@0: // DocumentFragment nodes don't have gEBTN
Chris@0: } else if ( support.qsa ) {
Chris@0: return context.querySelectorAll( tag );
Chris@0: }
Chris@0: } :
Chris@0:
Chris@0: function( tag, context ) {
Chris@0: var elem,
Chris@0: tmp = [],
Chris@0: i = 0,
Chris@0: // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
Chris@0: results = context.getElementsByTagName( tag );
Chris@0:
Chris@0: // Filter out possible comments
Chris@0: if ( tag === "*" ) {
Chris@0: while ( (elem = results[i++]) ) {
Chris@0: if ( elem.nodeType === 1 ) {
Chris@0: tmp.push( elem );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return tmp;
Chris@0: }
Chris@0: return results;
Chris@0: };
Chris@0:
Chris@0: // Class
Chris@0: Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
Chris@0: if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
Chris@0: return context.getElementsByClassName( className );
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: /* QSA/matchesSelector
Chris@0: ---------------------------------------------------------------------- */
Chris@0:
Chris@0: // QSA and matchesSelector support
Chris@0:
Chris@0: // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
Chris@0: rbuggyMatches = [];
Chris@0:
Chris@0: // qSa(:focus) reports false when true (Chrome 21)
Chris@0: // We allow this because of a bug in IE8/9 that throws an error
Chris@0: // whenever `document.activeElement` is accessed on an iframe
Chris@0: // So, we allow :focus to pass through QSA all the time to avoid the IE error
Chris@0: // See https://bugs.jquery.com/ticket/13378
Chris@0: rbuggyQSA = [];
Chris@0:
Chris@0: if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
Chris@0: // Build QSA regex
Chris@0: // Regex strategy adopted from Diego Perini
Chris@0: assert(function( el ) {
Chris@0: // Select is set to empty string on purpose
Chris@0: // This is to test IE's treatment of not explicitly
Chris@0: // setting a boolean content attribute,
Chris@0: // since its presence should be enough
Chris@0: // https://bugs.jquery.com/ticket/12359
Chris@0: docElem.appendChild( el ).innerHTML = "" +
Chris@0: "";
Chris@0:
Chris@0: // Support: IE8, Opera 11-12.16
Chris@0: // Nothing should be selected when empty strings follow ^= or $= or *=
Chris@0: // The test attribute must be unknown in Opera but "safe" for WinRT
Chris@0: // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
Chris@0: if ( el.querySelectorAll("[msallowcapture^='']").length ) {
Chris@0: rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
Chris@0: }
Chris@0:
Chris@0: // Support: IE8
Chris@0: // Boolean attributes and "value" are not treated correctly
Chris@0: if ( !el.querySelectorAll("[selected]").length ) {
Chris@0: rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
Chris@0: }
Chris@0:
Chris@0: // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
Chris@0: if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
Chris@0: rbuggyQSA.push("~=");
Chris@0: }
Chris@0:
Chris@0: // Webkit/Opera - :checked should return selected option elements
Chris@0: // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
Chris@0: // IE8 throws error here and will not see later tests
Chris@0: if ( !el.querySelectorAll(":checked").length ) {
Chris@0: rbuggyQSA.push(":checked");
Chris@0: }
Chris@0:
Chris@0: // Support: Safari 8+, iOS 8+
Chris@0: // https://bugs.webkit.org/show_bug.cgi?id=136851
Chris@0: // In-page `selector#id sibling-combinator selector` fails
Chris@0: if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
Chris@0: rbuggyQSA.push(".#.+[+~]");
Chris@0: }
Chris@0: });
Chris@0:
Chris@0: assert(function( el ) {
Chris@0: el.innerHTML = "" +
Chris@0: "";
Chris@0:
Chris@0: // Support: Windows 8 Native Apps
Chris@0: // The type and name attributes are restricted during .innerHTML assignment
Chris@0: var input = document.createElement("input");
Chris@0: input.setAttribute( "type", "hidden" );
Chris@0: el.appendChild( input ).setAttribute( "name", "D" );
Chris@0:
Chris@0: // Support: IE8
Chris@0: // Enforce case-sensitivity of name attribute
Chris@0: if ( el.querySelectorAll("[name=d]").length ) {
Chris@0: rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
Chris@0: }
Chris@0:
Chris@0: // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
Chris@0: // IE8 throws error here and will not see later tests
Chris@0: if ( el.querySelectorAll(":enabled").length !== 2 ) {
Chris@0: rbuggyQSA.push( ":enabled", ":disabled" );
Chris@0: }
Chris@0:
Chris@0: // Support: IE9-11+
Chris@0: // IE's :disabled selector does not pick up the children of disabled fieldsets
Chris@0: docElem.appendChild( el ).disabled = true;
Chris@0: if ( el.querySelectorAll(":disabled").length !== 2 ) {
Chris@0: rbuggyQSA.push( ":enabled", ":disabled" );
Chris@0: }
Chris@0:
Chris@0: // Opera 10-11 does not throw on post-comma invalid pseudos
Chris@0: el.querySelectorAll("*,:x");
Chris@0: rbuggyQSA.push(",.*:");
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
Chris@0: docElem.webkitMatchesSelector ||
Chris@0: docElem.mozMatchesSelector ||
Chris@0: docElem.oMatchesSelector ||
Chris@0: docElem.msMatchesSelector) )) ) {
Chris@0:
Chris@0: assert(function( el ) {
Chris@0: // Check to see if it's possible to do matchesSelector
Chris@0: // on a disconnected node (IE 9)
Chris@0: support.disconnectedMatch = matches.call( el, "*" );
Chris@0:
Chris@0: // This should fail with an exception
Chris@0: // Gecko does not error, returns false instead
Chris@0: matches.call( el, "[s!='']:x" );
Chris@0: rbuggyMatches.push( "!=", pseudos );
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
Chris@0: rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
Chris@0:
Chris@0: /* Contains
Chris@0: ---------------------------------------------------------------------- */
Chris@0: hasCompare = rnative.test( docElem.compareDocumentPosition );
Chris@0:
Chris@0: // Element contains another
Chris@0: // Purposefully self-exclusive
Chris@0: // As in, an element does not contain itself
Chris@0: contains = hasCompare || rnative.test( docElem.contains ) ?
Chris@0: function( a, b ) {
Chris@0: var adown = a.nodeType === 9 ? a.documentElement : a,
Chris@0: bup = b && b.parentNode;
Chris@0: return a === bup || !!( bup && bup.nodeType === 1 && (
Chris@0: adown.contains ?
Chris@0: adown.contains( bup ) :
Chris@0: a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
Chris@0: ));
Chris@0: } :
Chris@0: function( a, b ) {
Chris@0: if ( b ) {
Chris@0: while ( (b = b.parentNode) ) {
Chris@0: if ( b === a ) {
Chris@0: return true;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: return false;
Chris@0: };
Chris@0:
Chris@0: /* Sorting
Chris@0: ---------------------------------------------------------------------- */
Chris@0:
Chris@0: // Document order sorting
Chris@0: sortOrder = hasCompare ?
Chris@0: function( a, b ) {
Chris@0:
Chris@0: // Flag for duplicate removal
Chris@0: if ( a === b ) {
Chris@0: hasDuplicate = true;
Chris@0: return 0;
Chris@0: }
Chris@0:
Chris@0: // Sort on method existence if only one input has compareDocumentPosition
Chris@0: var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
Chris@0: if ( compare ) {
Chris@0: return compare;
Chris@0: }
Chris@0:
Chris@0: // Calculate position if both inputs belong to the same document
Chris@0: compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
Chris@0: a.compareDocumentPosition( b ) :
Chris@0:
Chris@0: // Otherwise we know they are disconnected
Chris@0: 1;
Chris@0:
Chris@0: // Disconnected nodes
Chris@0: if ( compare & 1 ||
Chris@0: (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
Chris@0:
Chris@0: // Choose the first element that is related to our preferred document
Chris@0: if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
Chris@0: return -1;
Chris@0: }
Chris@0: if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
Chris@0: return 1;
Chris@0: }
Chris@0:
Chris@0: // Maintain original order
Chris@0: return sortInput ?
Chris@0: ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
Chris@0: 0;
Chris@0: }
Chris@0:
Chris@0: return compare & 4 ? -1 : 1;
Chris@0: } :
Chris@0: function( a, b ) {
Chris@0: // Exit early if the nodes are identical
Chris@0: if ( a === b ) {
Chris@0: hasDuplicate = true;
Chris@0: return 0;
Chris@0: }
Chris@0:
Chris@0: var cur,
Chris@0: i = 0,
Chris@0: aup = a.parentNode,
Chris@0: bup = b.parentNode,
Chris@0: ap = [ a ],
Chris@0: bp = [ b ];
Chris@0:
Chris@0: // Parentless nodes are either documents or disconnected
Chris@0: if ( !aup || !bup ) {
Chris@0: return a === document ? -1 :
Chris@0: b === document ? 1 :
Chris@0: aup ? -1 :
Chris@0: bup ? 1 :
Chris@0: sortInput ?
Chris@0: ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
Chris@0: 0;
Chris@0:
Chris@0: // If the nodes are siblings, we can do a quick check
Chris@0: } else if ( aup === bup ) {
Chris@0: return siblingCheck( a, b );
Chris@0: }
Chris@0:
Chris@0: // Otherwise we need full lists of their ancestors for comparison
Chris@0: cur = a;
Chris@0: while ( (cur = cur.parentNode) ) {
Chris@0: ap.unshift( cur );
Chris@0: }
Chris@0: cur = b;
Chris@0: while ( (cur = cur.parentNode) ) {
Chris@0: bp.unshift( cur );
Chris@0: }
Chris@0:
Chris@0: // Walk down the tree looking for a discrepancy
Chris@0: while ( ap[i] === bp[i] ) {
Chris@0: i++;
Chris@0: }
Chris@0:
Chris@0: return i ?
Chris@0: // Do a sibling check if the nodes have a common ancestor
Chris@0: siblingCheck( ap[i], bp[i] ) :
Chris@0:
Chris@0: // Otherwise nodes in our document sort first
Chris@0: ap[i] === preferredDoc ? -1 :
Chris@0: bp[i] === preferredDoc ? 1 :
Chris@0: 0;
Chris@0: };
Chris@0:
Chris@0: return document;
Chris@0: };
Chris@0:
Chris@0: Sizzle.matches = function( expr, elements ) {
Chris@0: return Sizzle( expr, null, null, elements );
Chris@0: };
Chris@0:
Chris@0: Sizzle.matchesSelector = function( elem, expr ) {
Chris@0: // Set document vars if needed
Chris@0: if ( ( elem.ownerDocument || elem ) !== document ) {
Chris@0: setDocument( elem );
Chris@0: }
Chris@0:
Chris@0: // Make sure that attribute selectors are quoted
Chris@0: expr = expr.replace( rattributeQuotes, "='$1']" );
Chris@0:
Chris@0: if ( support.matchesSelector && documentIsHTML &&
Chris@0: !compilerCache[ expr + " " ] &&
Chris@0: ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
Chris@0: ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
Chris@0:
Chris@0: try {
Chris@0: var ret = matches.call( elem, expr );
Chris@0:
Chris@0: // IE 9's matchesSelector returns false on disconnected nodes
Chris@0: if ( ret || support.disconnectedMatch ||
Chris@0: // As well, disconnected nodes are said to be in a document
Chris@0: // fragment in IE 9
Chris@0: elem.document && elem.document.nodeType !== 11 ) {
Chris@0: return ret;
Chris@0: }
Chris@0: } catch (e) {}
Chris@0: }
Chris@0:
Chris@0: return Sizzle( expr, document, null, [ elem ] ).length > 0;
Chris@0: };
Chris@0:
Chris@0: Sizzle.contains = function( context, elem ) {
Chris@0: // Set document vars if needed
Chris@0: if ( ( context.ownerDocument || context ) !== document ) {
Chris@0: setDocument( context );
Chris@0: }
Chris@0: return contains( context, elem );
Chris@0: };
Chris@0:
Chris@0: Sizzle.attr = function( elem, name ) {
Chris@0: // Set document vars if needed
Chris@0: if ( ( elem.ownerDocument || elem ) !== document ) {
Chris@0: setDocument( elem );
Chris@0: }
Chris@0:
Chris@0: var fn = Expr.attrHandle[ name.toLowerCase() ],
Chris@0: // Don't get fooled by Object.prototype properties (jQuery #13807)
Chris@0: val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
Chris@0: fn( elem, name, !documentIsHTML ) :
Chris@0: undefined;
Chris@0:
Chris@0: return val !== undefined ?
Chris@0: val :
Chris@0: support.attributes || !documentIsHTML ?
Chris@0: elem.getAttribute( name ) :
Chris@0: (val = elem.getAttributeNode(name)) && val.specified ?
Chris@0: val.value :
Chris@0: null;
Chris@0: };
Chris@0:
Chris@0: Sizzle.escape = function( sel ) {
Chris@0: return (sel + "").replace( rcssescape, fcssescape );
Chris@0: };
Chris@0:
Chris@0: Sizzle.error = function( msg ) {
Chris@0: throw new Error( "Syntax error, unrecognized expression: " + msg );
Chris@0: };
Chris@0:
Chris@0: /**
Chris@0: * Document sorting and removing duplicates
Chris@0: * @param {ArrayLike} results
Chris@0: */
Chris@0: Sizzle.uniqueSort = function( results ) {
Chris@0: var elem,
Chris@0: duplicates = [],
Chris@0: j = 0,
Chris@0: i = 0;
Chris@0:
Chris@0: // Unless we *know* we can detect duplicates, assume their presence
Chris@0: hasDuplicate = !support.detectDuplicates;
Chris@0: sortInput = !support.sortStable && results.slice( 0 );
Chris@0: results.sort( sortOrder );
Chris@0:
Chris@0: if ( hasDuplicate ) {
Chris@0: while ( (elem = results[i++]) ) {
Chris@0: if ( elem === results[ i ] ) {
Chris@0: j = duplicates.push( i );
Chris@0: }
Chris@0: }
Chris@0: while ( j-- ) {
Chris@0: results.splice( duplicates[ j ], 1 );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Clear input after sorting to release objects
Chris@0: // See https://github.com/jquery/sizzle/pull/225
Chris@0: sortInput = null;
Chris@0:
Chris@0: return results;
Chris@0: };
Chris@0:
Chris@0: /**
Chris@0: * Utility function for retrieving the text value of an array of DOM nodes
Chris@0: * @param {Array|Element} elem
Chris@0: */
Chris@0: getText = Sizzle.getText = function( elem ) {
Chris@0: var node,
Chris@0: ret = "",
Chris@0: i = 0,
Chris@0: nodeType = elem.nodeType;
Chris@0:
Chris@0: if ( !nodeType ) {
Chris@0: // If no nodeType, this is expected to be an array
Chris@0: while ( (node = elem[i++]) ) {
Chris@0: // Do not traverse comment nodes
Chris@0: ret += getText( node );
Chris@0: }
Chris@0: } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
Chris@0: // Use textContent for elements
Chris@0: // innerText usage removed for consistency of new lines (jQuery #11153)
Chris@0: if ( typeof elem.textContent === "string" ) {
Chris@0: return elem.textContent;
Chris@0: } else {
Chris@0: // Traverse its children
Chris@0: for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
Chris@0: ret += getText( elem );
Chris@0: }
Chris@0: }
Chris@0: } else if ( nodeType === 3 || nodeType === 4 ) {
Chris@0: return elem.nodeValue;
Chris@0: }
Chris@0: // Do not include comment or processing instruction nodes
Chris@0:
Chris@0: return ret;
Chris@0: };
Chris@0:
Chris@0: Expr = Sizzle.selectors = {
Chris@0:
Chris@0: // Can be adjusted by the user
Chris@0: cacheLength: 50,
Chris@0:
Chris@0: createPseudo: markFunction,
Chris@0:
Chris@0: match: matchExpr,
Chris@0:
Chris@0: attrHandle: {},
Chris@0:
Chris@0: find: {},
Chris@0:
Chris@0: relative: {
Chris@0: ">": { dir: "parentNode", first: true },
Chris@0: " ": { dir: "parentNode" },
Chris@0: "+": { dir: "previousSibling", first: true },
Chris@0: "~": { dir: "previousSibling" }
Chris@0: },
Chris@0:
Chris@0: preFilter: {
Chris@0: "ATTR": function( match ) {
Chris@0: match[1] = match[1].replace( runescape, funescape );
Chris@0:
Chris@0: // Move the given value to match[3] whether quoted or unquoted
Chris@0: match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
Chris@0:
Chris@0: if ( match[2] === "~=" ) {
Chris@0: match[3] = " " + match[3] + " ";
Chris@0: }
Chris@0:
Chris@0: return match.slice( 0, 4 );
Chris@0: },
Chris@0:
Chris@0: "CHILD": function( match ) {
Chris@0: /* matches from matchExpr["CHILD"]
Chris@0: 1 type (only|nth|...)
Chris@0: 2 what (child|of-type)
Chris@0: 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
Chris@0: 4 xn-component of xn+y argument ([+-]?\d*n|)
Chris@0: 5 sign of xn-component
Chris@0: 6 x of xn-component
Chris@0: 7 sign of y-component
Chris@0: 8 y of y-component
Chris@0: */
Chris@0: match[1] = match[1].toLowerCase();
Chris@0:
Chris@0: if ( match[1].slice( 0, 3 ) === "nth" ) {
Chris@0: // nth-* requires argument
Chris@0: if ( !match[3] ) {
Chris@0: Sizzle.error( match[0] );
Chris@0: }
Chris@0:
Chris@0: // numeric x and y parameters for Expr.filter.CHILD
Chris@0: // remember that false/true cast respectively to 0/1
Chris@0: match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
Chris@0: match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
Chris@0:
Chris@0: // other types prohibit arguments
Chris@0: } else if ( match[3] ) {
Chris@0: Sizzle.error( match[0] );
Chris@0: }
Chris@0:
Chris@0: return match;
Chris@0: },
Chris@0:
Chris@0: "PSEUDO": function( match ) {
Chris@0: var excess,
Chris@0: unquoted = !match[6] && match[2];
Chris@0:
Chris@0: if ( matchExpr["CHILD"].test( match[0] ) ) {
Chris@0: return null;
Chris@0: }
Chris@0:
Chris@0: // Accept quoted arguments as-is
Chris@0: if ( match[3] ) {
Chris@0: match[2] = match[4] || match[5] || "";
Chris@0:
Chris@0: // Strip excess characters from unquoted arguments
Chris@0: } else if ( unquoted && rpseudo.test( unquoted ) &&
Chris@0: // Get excess from tokenize (recursively)
Chris@0: (excess = tokenize( unquoted, true )) &&
Chris@0: // advance to the next closing parenthesis
Chris@0: (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
Chris@0:
Chris@0: // excess is a negative index
Chris@0: match[0] = match[0].slice( 0, excess );
Chris@0: match[2] = unquoted.slice( 0, excess );
Chris@0: }
Chris@0:
Chris@0: // Return only captures needed by the pseudo filter method (type and argument)
Chris@0: return match.slice( 0, 3 );
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: filter: {
Chris@0:
Chris@0: "TAG": function( nodeNameSelector ) {
Chris@0: var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
Chris@0: return nodeNameSelector === "*" ?
Chris@0: function() { return true; } :
Chris@0: function( elem ) {
Chris@0: return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
Chris@0: };
Chris@0: },
Chris@0:
Chris@0: "CLASS": function( className ) {
Chris@0: var pattern = classCache[ className + " " ];
Chris@0:
Chris@0: return pattern ||
Chris@0: (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
Chris@0: classCache( className, function( elem ) {
Chris@0: return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
Chris@0: });
Chris@0: },
Chris@0:
Chris@0: "ATTR": function( name, operator, check ) {
Chris@0: return function( elem ) {
Chris@0: var result = Sizzle.attr( elem, name );
Chris@0:
Chris@0: if ( result == null ) {
Chris@0: return operator === "!=";
Chris@0: }
Chris@0: if ( !operator ) {
Chris@0: return true;
Chris@0: }
Chris@0:
Chris@0: result += "";
Chris@0:
Chris@0: return operator === "=" ? result === check :
Chris@0: operator === "!=" ? result !== check :
Chris@0: operator === "^=" ? check && result.indexOf( check ) === 0 :
Chris@0: operator === "*=" ? check && result.indexOf( check ) > -1 :
Chris@0: operator === "$=" ? check && result.slice( -check.length ) === check :
Chris@0: operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
Chris@0: operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
Chris@0: false;
Chris@0: };
Chris@0: },
Chris@0:
Chris@0: "CHILD": function( type, what, argument, first, last ) {
Chris@0: var simple = type.slice( 0, 3 ) !== "nth",
Chris@0: forward = type.slice( -4 ) !== "last",
Chris@0: ofType = what === "of-type";
Chris@0:
Chris@0: return first === 1 && last === 0 ?
Chris@0:
Chris@0: // Shortcut for :nth-*(n)
Chris@0: function( elem ) {
Chris@0: return !!elem.parentNode;
Chris@0: } :
Chris@0:
Chris@0: function( elem, context, xml ) {
Chris@0: var cache, uniqueCache, outerCache, node, nodeIndex, start,
Chris@0: dir = simple !== forward ? "nextSibling" : "previousSibling",
Chris@0: parent = elem.parentNode,
Chris@0: name = ofType && elem.nodeName.toLowerCase(),
Chris@0: useCache = !xml && !ofType,
Chris@0: diff = false;
Chris@0:
Chris@0: if ( parent ) {
Chris@0:
Chris@0: // :(first|last|only)-(child|of-type)
Chris@0: if ( simple ) {
Chris@0: while ( dir ) {
Chris@0: node = elem;
Chris@0: while ( (node = node[ dir ]) ) {
Chris@0: if ( ofType ?
Chris@0: node.nodeName.toLowerCase() === name :
Chris@0: node.nodeType === 1 ) {
Chris@0:
Chris@0: return false;
Chris@0: }
Chris@0: }
Chris@0: // Reverse direction for :only-* (if we haven't yet done so)
Chris@0: start = dir = type === "only" && !start && "nextSibling";
Chris@0: }
Chris@0: return true;
Chris@0: }
Chris@0:
Chris@0: start = [ forward ? parent.firstChild : parent.lastChild ];
Chris@0:
Chris@0: // non-xml :nth-child(...) stores cache data on `parent`
Chris@0: if ( forward && useCache ) {
Chris@0:
Chris@0: // Seek `elem` from a previously-cached index
Chris@0:
Chris@0: // ...in a gzip-friendly way
Chris@0: node = parent;
Chris@0: outerCache = node[ expando ] || (node[ expando ] = {});
Chris@0:
Chris@0: // Support: IE <9 only
Chris@0: // Defend against cloned attroperties (jQuery gh-1709)
Chris@0: uniqueCache = outerCache[ node.uniqueID ] ||
Chris@0: (outerCache[ node.uniqueID ] = {});
Chris@0:
Chris@0: cache = uniqueCache[ type ] || [];
Chris@0: nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
Chris@0: diff = nodeIndex && cache[ 2 ];
Chris@0: node = nodeIndex && parent.childNodes[ nodeIndex ];
Chris@0:
Chris@0: while ( (node = ++nodeIndex && node && node[ dir ] ||
Chris@0:
Chris@0: // Fallback to seeking `elem` from the start
Chris@0: (diff = nodeIndex = 0) || start.pop()) ) {
Chris@0:
Chris@0: // When found, cache indexes on `parent` and break
Chris@0: if ( node.nodeType === 1 && ++diff && node === elem ) {
Chris@0: uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: } else {
Chris@0: // Use previously-cached element index if available
Chris@0: if ( useCache ) {
Chris@0: // ...in a gzip-friendly way
Chris@0: node = elem;
Chris@0: outerCache = node[ expando ] || (node[ expando ] = {});
Chris@0:
Chris@0: // Support: IE <9 only
Chris@0: // Defend against cloned attroperties (jQuery gh-1709)
Chris@0: uniqueCache = outerCache[ node.uniqueID ] ||
Chris@0: (outerCache[ node.uniqueID ] = {});
Chris@0:
Chris@0: cache = uniqueCache[ type ] || [];
Chris@0: nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
Chris@0: diff = nodeIndex;
Chris@0: }
Chris@0:
Chris@0: // xml :nth-child(...)
Chris@0: // or :nth-last-child(...) or :nth(-last)?-of-type(...)
Chris@0: if ( diff === false ) {
Chris@0: // Use the same loop as above to seek `elem` from the start
Chris@0: while ( (node = ++nodeIndex && node && node[ dir ] ||
Chris@0: (diff = nodeIndex = 0) || start.pop()) ) {
Chris@0:
Chris@0: if ( ( ofType ?
Chris@0: node.nodeName.toLowerCase() === name :
Chris@0: node.nodeType === 1 ) &&
Chris@0: ++diff ) {
Chris@0:
Chris@0: // Cache the index of each encountered element
Chris@0: if ( useCache ) {
Chris@0: outerCache = node[ expando ] || (node[ expando ] = {});
Chris@0:
Chris@0: // Support: IE <9 only
Chris@0: // Defend against cloned attroperties (jQuery gh-1709)
Chris@0: uniqueCache = outerCache[ node.uniqueID ] ||
Chris@0: (outerCache[ node.uniqueID ] = {});
Chris@0:
Chris@0: uniqueCache[ type ] = [ dirruns, diff ];
Chris@0: }
Chris@0:
Chris@0: if ( node === elem ) {
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Incorporate the offset, then check against cycle size
Chris@0: diff -= last;
Chris@0: return diff === first || ( diff % first === 0 && diff / first >= 0 );
Chris@0: }
Chris@0: };
Chris@0: },
Chris@0:
Chris@0: "PSEUDO": function( pseudo, argument ) {
Chris@0: // pseudo-class names are case-insensitive
Chris@0: // http://www.w3.org/TR/selectors/#pseudo-classes
Chris@0: // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
Chris@0: // Remember that setFilters inherits from pseudos
Chris@0: var args,
Chris@0: fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
Chris@0: Sizzle.error( "unsupported pseudo: " + pseudo );
Chris@0:
Chris@0: // The user may use createPseudo to indicate that
Chris@0: // arguments are needed to create the filter function
Chris@0: // just as Sizzle does
Chris@0: if ( fn[ expando ] ) {
Chris@0: return fn( argument );
Chris@0: }
Chris@0:
Chris@0: // But maintain support for old signatures
Chris@0: if ( fn.length > 1 ) {
Chris@0: args = [ pseudo, pseudo, "", argument ];
Chris@0: return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
Chris@0: markFunction(function( seed, matches ) {
Chris@0: var idx,
Chris@0: matched = fn( seed, argument ),
Chris@0: i = matched.length;
Chris@0: while ( i-- ) {
Chris@0: idx = indexOf( seed, matched[i] );
Chris@0: seed[ idx ] = !( matches[ idx ] = matched[i] );
Chris@0: }
Chris@0: }) :
Chris@0: function( elem ) {
Chris@0: return fn( elem, 0, args );
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: return fn;
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: pseudos: {
Chris@0: // Potentially complex pseudos
Chris@0: "not": markFunction(function( selector ) {
Chris@0: // Trim the selector passed to compile
Chris@0: // to avoid treating leading and trailing
Chris@0: // spaces as combinators
Chris@0: var input = [],
Chris@0: results = [],
Chris@0: matcher = compile( selector.replace( rtrim, "$1" ) );
Chris@0:
Chris@0: return matcher[ expando ] ?
Chris@0: markFunction(function( seed, matches, context, xml ) {
Chris@0: var elem,
Chris@0: unmatched = matcher( seed, null, xml, [] ),
Chris@0: i = seed.length;
Chris@0:
Chris@0: // Match elements unmatched by `matcher`
Chris@0: while ( i-- ) {
Chris@0: if ( (elem = unmatched[i]) ) {
Chris@0: seed[i] = !(matches[i] = elem);
Chris@0: }
Chris@0: }
Chris@0: }) :
Chris@0: function( elem, context, xml ) {
Chris@0: input[0] = elem;
Chris@0: matcher( input, null, xml, results );
Chris@0: // Don't keep the element (issue #299)
Chris@0: input[0] = null;
Chris@0: return !results.pop();
Chris@0: };
Chris@0: }),
Chris@0:
Chris@0: "has": markFunction(function( selector ) {
Chris@0: return function( elem ) {
Chris@0: return Sizzle( selector, elem ).length > 0;
Chris@0: };
Chris@0: }),
Chris@0:
Chris@0: "contains": markFunction(function( text ) {
Chris@0: text = text.replace( runescape, funescape );
Chris@0: return function( elem ) {
Chris@0: return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
Chris@0: };
Chris@0: }),
Chris@0:
Chris@0: // "Whether an element is represented by a :lang() selector
Chris@0: // is based solely on the element's language value
Chris@0: // being equal to the identifier C,
Chris@0: // or beginning with the identifier C immediately followed by "-".
Chris@0: // The matching of C against the element's language value is performed case-insensitively.
Chris@0: // The identifier C does not have to be a valid language name."
Chris@0: // http://www.w3.org/TR/selectors/#lang-pseudo
Chris@0: "lang": markFunction( function( lang ) {
Chris@0: // lang value must be a valid identifier
Chris@0: if ( !ridentifier.test(lang || "") ) {
Chris@0: Sizzle.error( "unsupported lang: " + lang );
Chris@0: }
Chris@0: lang = lang.replace( runescape, funescape ).toLowerCase();
Chris@0: return function( elem ) {
Chris@0: var elemLang;
Chris@0: do {
Chris@0: if ( (elemLang = documentIsHTML ?
Chris@0: elem.lang :
Chris@0: elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
Chris@0:
Chris@0: elemLang = elemLang.toLowerCase();
Chris@0: return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
Chris@0: }
Chris@0: } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
Chris@0: return false;
Chris@0: };
Chris@0: }),
Chris@0:
Chris@0: // Miscellaneous
Chris@0: "target": function( elem ) {
Chris@0: var hash = window.location && window.location.hash;
Chris@0: return hash && hash.slice( 1 ) === elem.id;
Chris@0: },
Chris@0:
Chris@0: "root": function( elem ) {
Chris@0: return elem === docElem;
Chris@0: },
Chris@0:
Chris@0: "focus": function( elem ) {
Chris@0: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
Chris@0: },
Chris@0:
Chris@0: // Boolean properties
Chris@0: "enabled": createDisabledPseudo( false ),
Chris@0: "disabled": createDisabledPseudo( true ),
Chris@0:
Chris@0: "checked": function( elem ) {
Chris@0: // In CSS3, :checked should return both checked and selected elements
Chris@0: // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
Chris@0: var nodeName = elem.nodeName.toLowerCase();
Chris@0: return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
Chris@0: },
Chris@0:
Chris@0: "selected": function( elem ) {
Chris@0: // Accessing this property makes selected-by-default
Chris@0: // options in Safari work properly
Chris@0: if ( elem.parentNode ) {
Chris@0: elem.parentNode.selectedIndex;
Chris@0: }
Chris@0:
Chris@0: return elem.selected === true;
Chris@0: },
Chris@0:
Chris@0: // Contents
Chris@0: "empty": function( elem ) {
Chris@0: // http://www.w3.org/TR/selectors/#empty-pseudo
Chris@0: // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
Chris@0: // but not by others (comment: 8; processing instruction: 7; etc.)
Chris@0: // nodeType < 6 works because attributes (2) do not appear as children
Chris@0: for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
Chris@0: if ( elem.nodeType < 6 ) {
Chris@0: return false;
Chris@0: }
Chris@0: }
Chris@0: return true;
Chris@0: },
Chris@0:
Chris@0: "parent": function( elem ) {
Chris@0: return !Expr.pseudos["empty"]( elem );
Chris@0: },
Chris@0:
Chris@0: // Element/input types
Chris@0: "header": function( elem ) {
Chris@0: return rheader.test( elem.nodeName );
Chris@0: },
Chris@0:
Chris@0: "input": function( elem ) {
Chris@0: return rinputs.test( elem.nodeName );
Chris@0: },
Chris@0:
Chris@0: "button": function( elem ) {
Chris@0: var name = elem.nodeName.toLowerCase();
Chris@0: return name === "input" && elem.type === "button" || name === "button";
Chris@0: },
Chris@0:
Chris@0: "text": function( elem ) {
Chris@0: var attr;
Chris@0: return elem.nodeName.toLowerCase() === "input" &&
Chris@0: elem.type === "text" &&
Chris@0:
Chris@0: // Support: IE<8
Chris@0: // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
Chris@0: ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
Chris@0: },
Chris@0:
Chris@0: // Position-in-collection
Chris@0: "first": createPositionalPseudo(function() {
Chris@0: return [ 0 ];
Chris@0: }),
Chris@0:
Chris@0: "last": createPositionalPseudo(function( matchIndexes, length ) {
Chris@0: return [ length - 1 ];
Chris@0: }),
Chris@0:
Chris@0: "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
Chris@0: return [ argument < 0 ? argument + length : argument ];
Chris@0: }),
Chris@0:
Chris@0: "even": createPositionalPseudo(function( matchIndexes, length ) {
Chris@0: var i = 0;
Chris@0: for ( ; i < length; i += 2 ) {
Chris@0: matchIndexes.push( i );
Chris@0: }
Chris@0: return matchIndexes;
Chris@0: }),
Chris@0:
Chris@0: "odd": createPositionalPseudo(function( matchIndexes, length ) {
Chris@0: var i = 1;
Chris@0: for ( ; i < length; i += 2 ) {
Chris@0: matchIndexes.push( i );
Chris@0: }
Chris@0: return matchIndexes;
Chris@0: }),
Chris@0:
Chris@0: "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
Chris@0: var i = argument < 0 ? argument + length : argument;
Chris@0: for ( ; --i >= 0; ) {
Chris@0: matchIndexes.push( i );
Chris@0: }
Chris@0: return matchIndexes;
Chris@0: }),
Chris@0:
Chris@0: "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
Chris@0: var i = argument < 0 ? argument + length : argument;
Chris@0: for ( ; ++i < length; ) {
Chris@0: matchIndexes.push( i );
Chris@0: }
Chris@0: return matchIndexes;
Chris@0: })
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: Expr.pseudos["nth"] = Expr.pseudos["eq"];
Chris@0:
Chris@0: // Add button/input type pseudos
Chris@0: for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
Chris@0: Expr.pseudos[ i ] = createInputPseudo( i );
Chris@0: }
Chris@0: for ( i in { submit: true, reset: true } ) {
Chris@0: Expr.pseudos[ i ] = createButtonPseudo( i );
Chris@0: }
Chris@0:
Chris@0: // Easy API for creating new setFilters
Chris@0: function setFilters() {}
Chris@0: setFilters.prototype = Expr.filters = Expr.pseudos;
Chris@0: Expr.setFilters = new setFilters();
Chris@0:
Chris@0: tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
Chris@0: var matched, match, tokens, type,
Chris@0: soFar, groups, preFilters,
Chris@0: cached = tokenCache[ selector + " " ];
Chris@0:
Chris@0: if ( cached ) {
Chris@0: return parseOnly ? 0 : cached.slice( 0 );
Chris@0: }
Chris@0:
Chris@0: soFar = selector;
Chris@0: groups = [];
Chris@0: preFilters = Expr.preFilter;
Chris@0:
Chris@0: while ( soFar ) {
Chris@0:
Chris@0: // Comma and first run
Chris@0: if ( !matched || (match = rcomma.exec( soFar )) ) {
Chris@0: if ( match ) {
Chris@0: // Don't consume trailing commas as valid
Chris@0: soFar = soFar.slice( match[0].length ) || soFar;
Chris@0: }
Chris@0: groups.push( (tokens = []) );
Chris@0: }
Chris@0:
Chris@0: matched = false;
Chris@0:
Chris@0: // Combinators
Chris@0: if ( (match = rcombinators.exec( soFar )) ) {
Chris@0: matched = match.shift();
Chris@0: tokens.push({
Chris@0: value: matched,
Chris@0: // Cast descendant combinators to space
Chris@0: type: match[0].replace( rtrim, " " )
Chris@0: });
Chris@0: soFar = soFar.slice( matched.length );
Chris@0: }
Chris@0:
Chris@0: // Filters
Chris@0: for ( type in Expr.filter ) {
Chris@0: if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
Chris@0: (match = preFilters[ type ]( match ))) ) {
Chris@0: matched = match.shift();
Chris@0: tokens.push({
Chris@0: value: matched,
Chris@0: type: type,
Chris@0: matches: match
Chris@0: });
Chris@0: soFar = soFar.slice( matched.length );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: if ( !matched ) {
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Return the length of the invalid excess
Chris@0: // if we're just parsing
Chris@0: // Otherwise, throw an error or return tokens
Chris@0: return parseOnly ?
Chris@0: soFar.length :
Chris@0: soFar ?
Chris@0: Sizzle.error( selector ) :
Chris@0: // Cache the tokens
Chris@0: tokenCache( selector, groups ).slice( 0 );
Chris@0: };
Chris@0:
Chris@0: function toSelector( tokens ) {
Chris@0: var i = 0,
Chris@0: len = tokens.length,
Chris@0: selector = "";
Chris@0: for ( ; i < len; i++ ) {
Chris@0: selector += tokens[i].value;
Chris@0: }
Chris@0: return selector;
Chris@0: }
Chris@0:
Chris@0: function addCombinator( matcher, combinator, base ) {
Chris@0: var dir = combinator.dir,
Chris@0: skip = combinator.next,
Chris@0: key = skip || dir,
Chris@0: checkNonElements = base && key === "parentNode",
Chris@0: doneName = done++;
Chris@0:
Chris@0: return combinator.first ?
Chris@0: // Check against closest ancestor/preceding element
Chris@0: function( elem, context, xml ) {
Chris@0: while ( (elem = elem[ dir ]) ) {
Chris@0: if ( elem.nodeType === 1 || checkNonElements ) {
Chris@0: return matcher( elem, context, xml );
Chris@0: }
Chris@0: }
Chris@0: return false;
Chris@0: } :
Chris@0:
Chris@0: // Check against all ancestor/preceding elements
Chris@0: function( elem, context, xml ) {
Chris@0: var oldCache, uniqueCache, outerCache,
Chris@0: newCache = [ dirruns, doneName ];
Chris@0:
Chris@0: // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
Chris@0: if ( xml ) {
Chris@0: while ( (elem = elem[ dir ]) ) {
Chris@0: if ( elem.nodeType === 1 || checkNonElements ) {
Chris@0: if ( matcher( elem, context, xml ) ) {
Chris@0: return true;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: } else {
Chris@0: while ( (elem = elem[ dir ]) ) {
Chris@0: if ( elem.nodeType === 1 || checkNonElements ) {
Chris@0: outerCache = elem[ expando ] || (elem[ expando ] = {});
Chris@0:
Chris@0: // Support: IE <9 only
Chris@0: // Defend against cloned attroperties (jQuery gh-1709)
Chris@0: uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
Chris@0:
Chris@0: if ( skip && skip === elem.nodeName.toLowerCase() ) {
Chris@0: elem = elem[ dir ] || elem;
Chris@0: } else if ( (oldCache = uniqueCache[ key ]) &&
Chris@0: oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
Chris@0:
Chris@0: // Assign to newCache so results back-propagate to previous elements
Chris@0: return (newCache[ 2 ] = oldCache[ 2 ]);
Chris@0: } else {
Chris@0: // Reuse newcache so results back-propagate to previous elements
Chris@0: uniqueCache[ key ] = newCache;
Chris@0:
Chris@0: // A match means we're done; a fail means we have to keep checking
Chris@0: if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
Chris@0: return true;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: return false;
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: function elementMatcher( matchers ) {
Chris@0: return matchers.length > 1 ?
Chris@0: function( elem, context, xml ) {
Chris@0: var i = matchers.length;
Chris@0: while ( i-- ) {
Chris@0: if ( !matchers[i]( elem, context, xml ) ) {
Chris@0: return false;
Chris@0: }
Chris@0: }
Chris@0: return true;
Chris@0: } :
Chris@0: matchers[0];
Chris@0: }
Chris@0:
Chris@0: function multipleContexts( selector, contexts, results ) {
Chris@0: var i = 0,
Chris@0: len = contexts.length;
Chris@0: for ( ; i < len; i++ ) {
Chris@0: Sizzle( selector, contexts[i], results );
Chris@0: }
Chris@0: return results;
Chris@0: }
Chris@0:
Chris@0: function condense( unmatched, map, filter, context, xml ) {
Chris@0: var elem,
Chris@0: newUnmatched = [],
Chris@0: i = 0,
Chris@0: len = unmatched.length,
Chris@0: mapped = map != null;
Chris@0:
Chris@0: for ( ; i < len; i++ ) {
Chris@0: if ( (elem = unmatched[i]) ) {
Chris@0: if ( !filter || filter( elem, context, xml ) ) {
Chris@0: newUnmatched.push( elem );
Chris@0: if ( mapped ) {
Chris@0: map.push( i );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return newUnmatched;
Chris@0: }
Chris@0:
Chris@0: function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
Chris@0: if ( postFilter && !postFilter[ expando ] ) {
Chris@0: postFilter = setMatcher( postFilter );
Chris@0: }
Chris@0: if ( postFinder && !postFinder[ expando ] ) {
Chris@0: postFinder = setMatcher( postFinder, postSelector );
Chris@0: }
Chris@0: return markFunction(function( seed, results, context, xml ) {
Chris@0: var temp, i, elem,
Chris@0: preMap = [],
Chris@0: postMap = [],
Chris@0: preexisting = results.length,
Chris@0:
Chris@0: // Get initial elements from seed or context
Chris@0: elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
Chris@0:
Chris@0: // Prefilter to get matcher input, preserving a map for seed-results synchronization
Chris@0: matcherIn = preFilter && ( seed || !selector ) ?
Chris@0: condense( elems, preMap, preFilter, context, xml ) :
Chris@0: elems,
Chris@0:
Chris@0: matcherOut = matcher ?
Chris@0: // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
Chris@0: postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
Chris@0:
Chris@0: // ...intermediate processing is necessary
Chris@0: [] :
Chris@0:
Chris@0: // ...otherwise use results directly
Chris@0: results :
Chris@0: matcherIn;
Chris@0:
Chris@0: // Find primary matches
Chris@0: if ( matcher ) {
Chris@0: matcher( matcherIn, matcherOut, context, xml );
Chris@0: }
Chris@0:
Chris@0: // Apply postFilter
Chris@0: if ( postFilter ) {
Chris@0: temp = condense( matcherOut, postMap );
Chris@0: postFilter( temp, [], context, xml );
Chris@0:
Chris@0: // Un-match failing elements by moving them back to matcherIn
Chris@0: i = temp.length;
Chris@0: while ( i-- ) {
Chris@0: if ( (elem = temp[i]) ) {
Chris@0: matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: if ( seed ) {
Chris@0: if ( postFinder || preFilter ) {
Chris@0: if ( postFinder ) {
Chris@0: // Get the final matcherOut by condensing this intermediate into postFinder contexts
Chris@0: temp = [];
Chris@0: i = matcherOut.length;
Chris@0: while ( i-- ) {
Chris@0: if ( (elem = matcherOut[i]) ) {
Chris@0: // Restore matcherIn since elem is not yet a final match
Chris@0: temp.push( (matcherIn[i] = elem) );
Chris@0: }
Chris@0: }
Chris@0: postFinder( null, (matcherOut = []), temp, xml );
Chris@0: }
Chris@0:
Chris@0: // Move matched elements from seed to results to keep them synchronized
Chris@0: i = matcherOut.length;
Chris@0: while ( i-- ) {
Chris@0: if ( (elem = matcherOut[i]) &&
Chris@0: (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
Chris@0:
Chris@0: seed[temp] = !(results[temp] = elem);
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Add elements to results, through postFinder if defined
Chris@0: } else {
Chris@0: matcherOut = condense(
Chris@0: matcherOut === results ?
Chris@0: matcherOut.splice( preexisting, matcherOut.length ) :
Chris@0: matcherOut
Chris@0: );
Chris@0: if ( postFinder ) {
Chris@0: postFinder( null, results, matcherOut, xml );
Chris@0: } else {
Chris@0: push.apply( results, matcherOut );
Chris@0: }
Chris@0: }
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: function matcherFromTokens( tokens ) {
Chris@0: var checkContext, matcher, j,
Chris@0: len = tokens.length,
Chris@0: leadingRelative = Expr.relative[ tokens[0].type ],
Chris@0: implicitRelative = leadingRelative || Expr.relative[" "],
Chris@0: i = leadingRelative ? 1 : 0,
Chris@0:
Chris@0: // The foundational matcher ensures that elements are reachable from top-level context(s)
Chris@0: matchContext = addCombinator( function( elem ) {
Chris@0: return elem === checkContext;
Chris@0: }, implicitRelative, true ),
Chris@0: matchAnyContext = addCombinator( function( elem ) {
Chris@0: return indexOf( checkContext, elem ) > -1;
Chris@0: }, implicitRelative, true ),
Chris@0: matchers = [ function( elem, context, xml ) {
Chris@0: var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
Chris@0: (checkContext = context).nodeType ?
Chris@0: matchContext( elem, context, xml ) :
Chris@0: matchAnyContext( elem, context, xml ) );
Chris@0: // Avoid hanging onto element (issue #299)
Chris@0: checkContext = null;
Chris@0: return ret;
Chris@0: } ];
Chris@0:
Chris@0: for ( ; i < len; i++ ) {
Chris@0: if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
Chris@0: matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
Chris@0: } else {
Chris@0: matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
Chris@0:
Chris@0: // Return special upon seeing a positional matcher
Chris@0: if ( matcher[ expando ] ) {
Chris@0: // Find the next relative operator (if any) for proper handling
Chris@0: j = ++i;
Chris@0: for ( ; j < len; j++ ) {
Chris@0: if ( Expr.relative[ tokens[j].type ] ) {
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: return setMatcher(
Chris@0: i > 1 && elementMatcher( matchers ),
Chris@0: i > 1 && toSelector(
Chris@0: // If the preceding token was a descendant combinator, insert an implicit any-element `*`
Chris@0: tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
Chris@0: ).replace( rtrim, "$1" ),
Chris@0: matcher,
Chris@0: i < j && matcherFromTokens( tokens.slice( i, j ) ),
Chris@0: j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
Chris@0: j < len && toSelector( tokens )
Chris@0: );
Chris@0: }
Chris@0: matchers.push( matcher );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return elementMatcher( matchers );
Chris@0: }
Chris@0:
Chris@0: function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
Chris@0: var bySet = setMatchers.length > 0,
Chris@0: byElement = elementMatchers.length > 0,
Chris@0: superMatcher = function( seed, context, xml, results, outermost ) {
Chris@0: var elem, j, matcher,
Chris@0: matchedCount = 0,
Chris@0: i = "0",
Chris@0: unmatched = seed && [],
Chris@0: setMatched = [],
Chris@0: contextBackup = outermostContext,
Chris@0: // We must always have either seed elements or outermost context
Chris@0: elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
Chris@0: // Use integer dirruns iff this is the outermost matcher
Chris@0: dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
Chris@0: len = elems.length;
Chris@0:
Chris@0: if ( outermost ) {
Chris@0: outermostContext = context === document || context || outermost;
Chris@0: }
Chris@0:
Chris@0: // Add elements passing elementMatchers directly to results
Chris@0: // Support: IE<9, Safari
Chris@0: // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id
Chris@0: for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
Chris@0: if ( byElement && elem ) {
Chris@0: j = 0;
Chris@0: if ( !context && elem.ownerDocument !== document ) {
Chris@0: setDocument( elem );
Chris@0: xml = !documentIsHTML;
Chris@0: }
Chris@0: while ( (matcher = elementMatchers[j++]) ) {
Chris@0: if ( matcher( elem, context || document, xml) ) {
Chris@0: results.push( elem );
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: if ( outermost ) {
Chris@0: dirruns = dirrunsUnique;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Track unmatched elements for set filters
Chris@0: if ( bySet ) {
Chris@0: // They will have gone through all possible matchers
Chris@0: if ( (elem = !matcher && elem) ) {
Chris@0: matchedCount--;
Chris@0: }
Chris@0:
Chris@0: // Lengthen the array for every element, matched or not
Chris@0: if ( seed ) {
Chris@0: unmatched.push( elem );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // `i` is now the count of elements visited above, and adding it to `matchedCount`
Chris@0: // makes the latter nonnegative.
Chris@0: matchedCount += i;
Chris@0:
Chris@0: // Apply set filters to unmatched elements
Chris@0: // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
Chris@0: // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
Chris@0: // no element matchers and no seed.
Chris@0: // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
Chris@0: // case, which will result in a "00" `matchedCount` that differs from `i` but is also
Chris@0: // numerically zero.
Chris@0: if ( bySet && i !== matchedCount ) {
Chris@0: j = 0;
Chris@0: while ( (matcher = setMatchers[j++]) ) {
Chris@0: matcher( unmatched, setMatched, context, xml );
Chris@0: }
Chris@0:
Chris@0: if ( seed ) {
Chris@0: // Reintegrate element matches to eliminate the need for sorting
Chris@0: if ( matchedCount > 0 ) {
Chris@0: while ( i-- ) {
Chris@0: if ( !(unmatched[i] || setMatched[i]) ) {
Chris@0: setMatched[i] = pop.call( results );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Discard index placeholder values to get only actual matches
Chris@0: setMatched = condense( setMatched );
Chris@0: }
Chris@0:
Chris@0: // Add matches to results
Chris@0: push.apply( results, setMatched );
Chris@0:
Chris@0: // Seedless set matches succeeding multiple successful matchers stipulate sorting
Chris@0: if ( outermost && !seed && setMatched.length > 0 &&
Chris@0: ( matchedCount + setMatchers.length ) > 1 ) {
Chris@0:
Chris@0: Sizzle.uniqueSort( results );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Override manipulation of globals by nested matchers
Chris@0: if ( outermost ) {
Chris@0: dirruns = dirrunsUnique;
Chris@0: outermostContext = contextBackup;
Chris@0: }
Chris@0:
Chris@0: return unmatched;
Chris@0: };
Chris@0:
Chris@0: return bySet ?
Chris@0: markFunction( superMatcher ) :
Chris@0: superMatcher;
Chris@0: }
Chris@0:
Chris@0: compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
Chris@0: var i,
Chris@0: setMatchers = [],
Chris@0: elementMatchers = [],
Chris@0: cached = compilerCache[ selector + " " ];
Chris@0:
Chris@0: if ( !cached ) {
Chris@0: // Generate a function of recursive functions that can be used to check each element
Chris@0: if ( !match ) {
Chris@0: match = tokenize( selector );
Chris@0: }
Chris@0: i = match.length;
Chris@0: while ( i-- ) {
Chris@0: cached = matcherFromTokens( match[i] );
Chris@0: if ( cached[ expando ] ) {
Chris@0: setMatchers.push( cached );
Chris@0: } else {
Chris@0: elementMatchers.push( cached );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Cache the compiled function
Chris@0: cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
Chris@0:
Chris@0: // Save selector and tokenization
Chris@0: cached.selector = selector;
Chris@0: }
Chris@0: return cached;
Chris@0: };
Chris@0:
Chris@0: /**
Chris@0: * A low-level selection function that works with Sizzle's compiled
Chris@0: * selector functions
Chris@0: * @param {String|Function} selector A selector or a pre-compiled
Chris@0: * selector function built with Sizzle.compile
Chris@0: * @param {Element} context
Chris@0: * @param {Array} [results]
Chris@0: * @param {Array} [seed] A set of elements to match against
Chris@0: */
Chris@0: select = Sizzle.select = function( selector, context, results, seed ) {
Chris@0: var i, tokens, token, type, find,
Chris@0: compiled = typeof selector === "function" && selector,
Chris@0: match = !seed && tokenize( (selector = compiled.selector || selector) );
Chris@0:
Chris@0: results = results || [];
Chris@0:
Chris@0: // Try to minimize operations if there is only one selector in the list and no seed
Chris@0: // (the latter of which guarantees us context)
Chris@0: if ( match.length === 1 ) {
Chris@0:
Chris@0: // Reduce context if the leading compound selector is an ID
Chris@0: tokens = match[0] = match[0].slice( 0 );
Chris@0: if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
Chris@0: context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
Chris@0:
Chris@0: context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
Chris@0: if ( !context ) {
Chris@0: return results;
Chris@0:
Chris@0: // Precompiled matchers will still verify ancestry, so step up a level
Chris@0: } else if ( compiled ) {
Chris@0: context = context.parentNode;
Chris@0: }
Chris@0:
Chris@0: selector = selector.slice( tokens.shift().value.length );
Chris@0: }
Chris@0:
Chris@0: // Fetch a seed set for right-to-left matching
Chris@0: i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
Chris@0: while ( i-- ) {
Chris@0: token = tokens[i];
Chris@0:
Chris@0: // Abort if we hit a combinator
Chris@0: if ( Expr.relative[ (type = token.type) ] ) {
Chris@0: break;
Chris@0: }
Chris@0: if ( (find = Expr.find[ type ]) ) {
Chris@0: // Search, expanding context for leading sibling combinators
Chris@0: if ( (seed = find(
Chris@0: token.matches[0].replace( runescape, funescape ),
Chris@0: rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
Chris@0: )) ) {
Chris@0:
Chris@0: // If seed is empty or no tokens remain, we can return early
Chris@0: tokens.splice( i, 1 );
Chris@0: selector = seed.length && toSelector( tokens );
Chris@0: if ( !selector ) {
Chris@0: push.apply( results, seed );
Chris@0: return results;
Chris@0: }
Chris@0:
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Compile and execute a filtering function if one is not provided
Chris@0: // Provide `match` to avoid retokenization if we modified the selector above
Chris@0: ( compiled || compile( selector, match ) )(
Chris@0: seed,
Chris@0: context,
Chris@0: !documentIsHTML,
Chris@0: results,
Chris@0: !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
Chris@0: );
Chris@0: return results;
Chris@0: };
Chris@0:
Chris@0: // One-time assignments
Chris@0:
Chris@0: // Sort stability
Chris@0: support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
Chris@0:
Chris@0: // Support: Chrome 14-35+
Chris@0: // Always assume duplicates if they aren't passed to the comparison function
Chris@0: support.detectDuplicates = !!hasDuplicate;
Chris@0:
Chris@0: // Initialize against the default document
Chris@0: setDocument();
Chris@0:
Chris@0: // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
Chris@0: // Detached nodes confoundingly follow *each other*
Chris@0: support.sortDetached = assert(function( el ) {
Chris@0: // Should return 1, but returns 4 (following)
Chris@0: return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
Chris@0: });
Chris@0:
Chris@0: // Support: IE<8
Chris@0: // Prevent attribute/property "interpolation"
Chris@0: // https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
Chris@0: if ( !assert(function( el ) {
Chris@0: el.innerHTML = "";
Chris@0: return el.firstChild.getAttribute("href") === "#" ;
Chris@0: }) ) {
Chris@0: addHandle( "type|href|height|width", function( elem, name, isXML ) {
Chris@0: if ( !isXML ) {
Chris@0: return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
Chris@0: }
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: // Support: IE<9
Chris@0: // Use defaultValue in place of getAttribute("value")
Chris@0: if ( !support.attributes || !assert(function( el ) {
Chris@0: el.innerHTML = "";
Chris@0: el.firstChild.setAttribute( "value", "" );
Chris@0: return el.firstChild.getAttribute( "value" ) === "";
Chris@0: }) ) {
Chris@0: addHandle( "value", function( elem, name, isXML ) {
Chris@0: if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
Chris@0: return elem.defaultValue;
Chris@0: }
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: // Support: IE<9
Chris@0: // Use getAttributeNode to fetch booleans when getAttribute lies
Chris@0: if ( !assert(function( el ) {
Chris@0: return el.getAttribute("disabled") == null;
Chris@0: }) ) {
Chris@0: addHandle( booleans, function( elem, name, isXML ) {
Chris@0: var val;
Chris@0: if ( !isXML ) {
Chris@0: return elem[ name ] === true ? name.toLowerCase() :
Chris@0: (val = elem.getAttributeNode( name )) && val.specified ?
Chris@0: val.value :
Chris@0: null;
Chris@0: }
Chris@0: });
Chris@0: }
Chris@0:
Chris@0: return Sizzle;
Chris@0:
Chris@0: })( window );
Chris@0:
Chris@0:
Chris@0:
Chris@0: jQuery.find = Sizzle;
Chris@0: jQuery.expr = Sizzle.selectors;
Chris@0:
Chris@0: // Deprecated
Chris@0: jQuery.expr[ ":" ] = jQuery.expr.pseudos;
Chris@0: jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
Chris@0: jQuery.text = Sizzle.getText;
Chris@0: jQuery.isXMLDoc = Sizzle.isXML;
Chris@0: jQuery.contains = Sizzle.contains;
Chris@0: jQuery.escapeSelector = Sizzle.escape;
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: var dir = function( elem, dir, until ) {
Chris@0: var matched = [],
Chris@0: truncate = until !== undefined;
Chris@0:
Chris@0: while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
Chris@0: if ( elem.nodeType === 1 ) {
Chris@0: if ( truncate && jQuery( elem ).is( until ) ) {
Chris@0: break;
Chris@0: }
Chris@0: matched.push( elem );
Chris@0: }
Chris@0: }
Chris@0: return matched;
Chris@0: };
Chris@0:
Chris@0:
Chris@0: var siblings = function( n, elem ) {
Chris@0: var matched = [];
Chris@0:
Chris@0: for ( ; n; n = n.nextSibling ) {
Chris@0: if ( n.nodeType === 1 && n !== elem ) {
Chris@0: matched.push( n );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return matched;
Chris@0: };
Chris@0:
Chris@0:
Chris@0: var rneedsContext = jQuery.expr.match.needsContext;
Chris@0:
Chris@0:
Chris@0:
Chris@0: function nodeName( elem, name ) {
Chris@0:
Chris@0: return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
Chris@0:
Chris@0: };
Chris@0: var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
Chris@0:
Chris@0:
Chris@0:
Chris@0: var risSimple = /^.[^:#\[\.,]*$/;
Chris@0:
Chris@0: // Implement the identical functionality for filter and not
Chris@0: function winnow( elements, qualifier, not ) {
Chris@0: if ( jQuery.isFunction( qualifier ) ) {
Chris@0: return jQuery.grep( elements, function( elem, i ) {
Chris@0: return !!qualifier.call( elem, i, elem ) !== not;
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: // Single element
Chris@0: if ( qualifier.nodeType ) {
Chris@0: return jQuery.grep( elements, function( elem ) {
Chris@0: return ( elem === qualifier ) !== not;
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: // Arraylike of elements (jQuery, arguments, Array)
Chris@0: if ( typeof qualifier !== "string" ) {
Chris@0: return jQuery.grep( elements, function( elem ) {
Chris@0: return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: // Simple selector that can be filtered directly, removing non-Elements
Chris@0: if ( risSimple.test( qualifier ) ) {
Chris@0: return jQuery.filter( qualifier, elements, not );
Chris@0: }
Chris@0:
Chris@0: // Complex selector, compare the two sets, removing non-Elements
Chris@0: qualifier = jQuery.filter( qualifier, elements );
Chris@0: return jQuery.grep( elements, function( elem ) {
Chris@0: return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: jQuery.filter = function( expr, elems, not ) {
Chris@0: var elem = elems[ 0 ];
Chris@0:
Chris@0: if ( not ) {
Chris@0: expr = ":not(" + expr + ")";
Chris@0: }
Chris@0:
Chris@0: if ( elems.length === 1 && elem.nodeType === 1 ) {
Chris@0: return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
Chris@0: }
Chris@0:
Chris@0: return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
Chris@0: return elem.nodeType === 1;
Chris@0: } ) );
Chris@0: };
Chris@0:
Chris@0: jQuery.fn.extend( {
Chris@0: find: function( selector ) {
Chris@0: var i, ret,
Chris@0: len = this.length,
Chris@0: self = this;
Chris@0:
Chris@0: if ( typeof selector !== "string" ) {
Chris@0: return this.pushStack( jQuery( selector ).filter( function() {
Chris@0: for ( i = 0; i < len; i++ ) {
Chris@0: if ( jQuery.contains( self[ i ], this ) ) {
Chris@0: return true;
Chris@0: }
Chris@0: }
Chris@0: } ) );
Chris@0: }
Chris@0:
Chris@0: ret = this.pushStack( [] );
Chris@0:
Chris@0: for ( i = 0; i < len; i++ ) {
Chris@0: jQuery.find( selector, self[ i ], ret );
Chris@0: }
Chris@0:
Chris@0: return len > 1 ? jQuery.uniqueSort( ret ) : ret;
Chris@0: },
Chris@0: filter: function( selector ) {
Chris@0: return this.pushStack( winnow( this, selector || [], false ) );
Chris@0: },
Chris@0: not: function( selector ) {
Chris@0: return this.pushStack( winnow( this, selector || [], true ) );
Chris@0: },
Chris@0: is: function( selector ) {
Chris@0: return !!winnow(
Chris@0: this,
Chris@0:
Chris@0: // If this is a positional/relative selector, check membership in the returned set
Chris@0: // so $("p:first").is("p:last") won't return true for a doc with two "p".
Chris@0: typeof selector === "string" && rneedsContext.test( selector ) ?
Chris@0: jQuery( selector ) :
Chris@0: selector || [],
Chris@0: false
Chris@0: ).length;
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0:
Chris@0: // Initialize a jQuery object
Chris@0:
Chris@0:
Chris@0: // A central reference to the root jQuery(document)
Chris@0: var rootjQuery,
Chris@0:
Chris@0: // A simple way to check for HTML strings
Chris@0: // Prioritize #id over to avoid XSS via location.hash (#9521)
Chris@0: // Strict HTML recognition (#11290: must start with <)
Chris@0: // Shortcut simple #id case for speed
Chris@0: rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
Chris@0:
Chris@0: init = jQuery.fn.init = function( selector, context, root ) {
Chris@0: var match, elem;
Chris@0:
Chris@0: // HANDLE: $(""), $(null), $(undefined), $(false)
Chris@0: if ( !selector ) {
Chris@0: return this;
Chris@0: }
Chris@0:
Chris@0: // Method init() accepts an alternate rootjQuery
Chris@0: // so migrate can support jQuery.sub (gh-2101)
Chris@0: root = root || rootjQuery;
Chris@0:
Chris@0: // Handle HTML strings
Chris@0: if ( typeof selector === "string" ) {
Chris@0: if ( selector[ 0 ] === "<" &&
Chris@0: selector[ selector.length - 1 ] === ">" &&
Chris@0: selector.length >= 3 ) {
Chris@0:
Chris@0: // Assume that strings that start and end with <> are HTML and skip the regex check
Chris@0: match = [ null, selector, null ];
Chris@0:
Chris@0: } else {
Chris@0: match = rquickExpr.exec( selector );
Chris@0: }
Chris@0:
Chris@0: // Match html or make sure no context is specified for #id
Chris@0: if ( match && ( match[ 1 ] || !context ) ) {
Chris@0:
Chris@0: // HANDLE: $(html) -> $(array)
Chris@0: if ( match[ 1 ] ) {
Chris@0: context = context instanceof jQuery ? context[ 0 ] : context;
Chris@0:
Chris@0: // Option to run scripts is true for back-compat
Chris@0: // Intentionally let the error be thrown if parseHTML is not present
Chris@0: jQuery.merge( this, jQuery.parseHTML(
Chris@0: match[ 1 ],
Chris@0: context && context.nodeType ? context.ownerDocument || context : document,
Chris@0: true
Chris@0: ) );
Chris@0:
Chris@0: // HANDLE: $(html, props)
Chris@0: if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
Chris@0: for ( match in context ) {
Chris@0:
Chris@0: // Properties of context are called as methods if possible
Chris@0: if ( jQuery.isFunction( this[ match ] ) ) {
Chris@0: this[ match ]( context[ match ] );
Chris@0:
Chris@0: // ...and otherwise set as attributes
Chris@0: } else {
Chris@0: this.attr( match, context[ match ] );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return this;
Chris@0:
Chris@0: // HANDLE: $(#id)
Chris@0: } else {
Chris@0: elem = document.getElementById( match[ 2 ] );
Chris@0:
Chris@0: if ( elem ) {
Chris@0:
Chris@0: // Inject the element directly into the jQuery object
Chris@0: this[ 0 ] = elem;
Chris@0: this.length = 1;
Chris@0: }
Chris@0: return this;
Chris@0: }
Chris@0:
Chris@0: // HANDLE: $(expr, $(...))
Chris@0: } else if ( !context || context.jquery ) {
Chris@0: return ( context || root ).find( selector );
Chris@0:
Chris@0: // HANDLE: $(expr, context)
Chris@0: // (which is just equivalent to: $(context).find(expr)
Chris@0: } else {
Chris@0: return this.constructor( context ).find( selector );
Chris@0: }
Chris@0:
Chris@0: // HANDLE: $(DOMElement)
Chris@0: } else if ( selector.nodeType ) {
Chris@0: this[ 0 ] = selector;
Chris@0: this.length = 1;
Chris@0: return this;
Chris@0:
Chris@0: // HANDLE: $(function)
Chris@0: // Shortcut for document ready
Chris@0: } else if ( jQuery.isFunction( selector ) ) {
Chris@0: return root.ready !== undefined ?
Chris@0: root.ready( selector ) :
Chris@0:
Chris@0: // Execute immediately if ready is not present
Chris@0: selector( jQuery );
Chris@0: }
Chris@0:
Chris@0: return jQuery.makeArray( selector, this );
Chris@0: };
Chris@0:
Chris@0: // Give the init function the jQuery prototype for later instantiation
Chris@0: init.prototype = jQuery.fn;
Chris@0:
Chris@0: // Initialize central reference
Chris@0: rootjQuery = jQuery( document );
Chris@0:
Chris@0:
Chris@0: var rparentsprev = /^(?:parents|prev(?:Until|All))/,
Chris@0:
Chris@0: // Methods guaranteed to produce a unique set when starting from a unique set
Chris@0: guaranteedUnique = {
Chris@0: children: true,
Chris@0: contents: true,
Chris@0: next: true,
Chris@0: prev: true
Chris@0: };
Chris@0:
Chris@0: jQuery.fn.extend( {
Chris@0: has: function( target ) {
Chris@0: var targets = jQuery( target, this ),
Chris@0: l = targets.length;
Chris@0:
Chris@0: return this.filter( function() {
Chris@0: var i = 0;
Chris@0: for ( ; i < l; i++ ) {
Chris@0: if ( jQuery.contains( this, targets[ i ] ) ) {
Chris@0: return true;
Chris@0: }
Chris@0: }
Chris@0: } );
Chris@0: },
Chris@0:
Chris@0: closest: function( selectors, context ) {
Chris@0: var cur,
Chris@0: i = 0,
Chris@0: l = this.length,
Chris@0: matched = [],
Chris@0: targets = typeof selectors !== "string" && jQuery( selectors );
Chris@0:
Chris@0: // Positional selectors never match, since there's no _selection_ context
Chris@0: if ( !rneedsContext.test( selectors ) ) {
Chris@0: for ( ; i < l; i++ ) {
Chris@0: for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
Chris@0:
Chris@0: // Always skip document fragments
Chris@0: if ( cur.nodeType < 11 && ( targets ?
Chris@0: targets.index( cur ) > -1 :
Chris@0:
Chris@0: // Don't pass non-elements to Sizzle
Chris@0: cur.nodeType === 1 &&
Chris@0: jQuery.find.matchesSelector( cur, selectors ) ) ) {
Chris@0:
Chris@0: matched.push( cur );
Chris@0: break;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
Chris@0: },
Chris@0:
Chris@0: // Determine the position of an element within the set
Chris@0: index: function( elem ) {
Chris@0:
Chris@0: // No argument, return index in parent
Chris@0: if ( !elem ) {
Chris@0: return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
Chris@0: }
Chris@0:
Chris@0: // Index in selector
Chris@0: if ( typeof elem === "string" ) {
Chris@0: return indexOf.call( jQuery( elem ), this[ 0 ] );
Chris@0: }
Chris@0:
Chris@0: // Locate the position of the desired element
Chris@0: return indexOf.call( this,
Chris@0:
Chris@0: // If it receives a jQuery object, the first element is used
Chris@0: elem.jquery ? elem[ 0 ] : elem
Chris@0: );
Chris@0: },
Chris@0:
Chris@0: add: function( selector, context ) {
Chris@0: return this.pushStack(
Chris@0: jQuery.uniqueSort(
Chris@0: jQuery.merge( this.get(), jQuery( selector, context ) )
Chris@0: )
Chris@0: );
Chris@0: },
Chris@0:
Chris@0: addBack: function( selector ) {
Chris@0: return this.add( selector == null ?
Chris@0: this.prevObject : this.prevObject.filter( selector )
Chris@0: );
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0: function sibling( cur, dir ) {
Chris@0: while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
Chris@0: return cur;
Chris@0: }
Chris@0:
Chris@0: jQuery.each( {
Chris@0: parent: function( elem ) {
Chris@0: var parent = elem.parentNode;
Chris@0: return parent && parent.nodeType !== 11 ? parent : null;
Chris@0: },
Chris@0: parents: function( elem ) {
Chris@0: return dir( elem, "parentNode" );
Chris@0: },
Chris@0: parentsUntil: function( elem, i, until ) {
Chris@0: return dir( elem, "parentNode", until );
Chris@0: },
Chris@0: next: function( elem ) {
Chris@0: return sibling( elem, "nextSibling" );
Chris@0: },
Chris@0: prev: function( elem ) {
Chris@0: return sibling( elem, "previousSibling" );
Chris@0: },
Chris@0: nextAll: function( elem ) {
Chris@0: return dir( elem, "nextSibling" );
Chris@0: },
Chris@0: prevAll: function( elem ) {
Chris@0: return dir( elem, "previousSibling" );
Chris@0: },
Chris@0: nextUntil: function( elem, i, until ) {
Chris@0: return dir( elem, "nextSibling", until );
Chris@0: },
Chris@0: prevUntil: function( elem, i, until ) {
Chris@0: return dir( elem, "previousSibling", until );
Chris@0: },
Chris@0: siblings: function( elem ) {
Chris@0: return siblings( ( elem.parentNode || {} ).firstChild, elem );
Chris@0: },
Chris@0: children: function( elem ) {
Chris@0: return siblings( elem.firstChild );
Chris@0: },
Chris@0: contents: function( elem ) {
Chris@0: if ( nodeName( elem, "iframe" ) ) {
Chris@0: return elem.contentDocument;
Chris@0: }
Chris@0:
Chris@0: // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
Chris@0: // Treat the template element as a regular one in browsers that
Chris@0: // don't support it.
Chris@0: if ( nodeName( elem, "template" ) ) {
Chris@0: elem = elem.content || elem;
Chris@0: }
Chris@0:
Chris@0: return jQuery.merge( [], elem.childNodes );
Chris@0: }
Chris@0: }, function( name, fn ) {
Chris@0: jQuery.fn[ name ] = function( until, selector ) {
Chris@0: var matched = jQuery.map( this, fn, until );
Chris@0:
Chris@0: if ( name.slice( -5 ) !== "Until" ) {
Chris@0: selector = until;
Chris@0: }
Chris@0:
Chris@0: if ( selector && typeof selector === "string" ) {
Chris@0: matched = jQuery.filter( selector, matched );
Chris@0: }
Chris@0:
Chris@0: if ( this.length > 1 ) {
Chris@0:
Chris@0: // Remove duplicates
Chris@0: if ( !guaranteedUnique[ name ] ) {
Chris@0: jQuery.uniqueSort( matched );
Chris@0: }
Chris@0:
Chris@0: // Reverse order for parents* and prev-derivatives
Chris@0: if ( rparentsprev.test( name ) ) {
Chris@0: matched.reverse();
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return this.pushStack( matched );
Chris@0: };
Chris@0: } );
Chris@0: var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
Chris@0:
Chris@0:
Chris@0:
Chris@0: // Convert String-formatted options into Object-formatted ones
Chris@0: function createOptions( options ) {
Chris@0: var object = {};
Chris@0: jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
Chris@0: object[ flag ] = true;
Chris@0: } );
Chris@0: return object;
Chris@0: }
Chris@0:
Chris@0: /*
Chris@0: * Create a callback list using the following parameters:
Chris@0: *
Chris@0: * options: an optional list of space-separated options that will change how
Chris@0: * the callback list behaves or a more traditional option object
Chris@0: *
Chris@0: * By default a callback list will act like an event callback list and can be
Chris@0: * "fired" multiple times.
Chris@0: *
Chris@0: * Possible options:
Chris@0: *
Chris@0: * once: will ensure the callback list can only be fired once (like a Deferred)
Chris@0: *
Chris@0: * memory: will keep track of previous values and will call any callback added
Chris@0: * after the list has been fired right away with the latest "memorized"
Chris@0: * values (like a Deferred)
Chris@0: *
Chris@0: * unique: will ensure a callback can only be added once (no duplicate in the list)
Chris@0: *
Chris@0: * stopOnFalse: interrupt callings when a callback returns false
Chris@0: *
Chris@0: */
Chris@0: jQuery.Callbacks = function( options ) {
Chris@0:
Chris@0: // Convert options from String-formatted to Object-formatted if needed
Chris@0: // (we check in cache first)
Chris@0: options = typeof options === "string" ?
Chris@0: createOptions( options ) :
Chris@0: jQuery.extend( {}, options );
Chris@0:
Chris@0: var // Flag to know if list is currently firing
Chris@0: firing,
Chris@0:
Chris@0: // Last fire value for non-forgettable lists
Chris@0: memory,
Chris@0:
Chris@0: // Flag to know if list was already fired
Chris@0: fired,
Chris@0:
Chris@0: // Flag to prevent firing
Chris@0: locked,
Chris@0:
Chris@0: // Actual callback list
Chris@0: list = [],
Chris@0:
Chris@0: // Queue of execution data for repeatable lists
Chris@0: queue = [],
Chris@0:
Chris@0: // Index of currently firing callback (modified by add/remove as needed)
Chris@0: firingIndex = -1,
Chris@0:
Chris@0: // Fire callbacks
Chris@0: fire = function() {
Chris@0:
Chris@0: // Enforce single-firing
Chris@0: locked = locked || options.once;
Chris@0:
Chris@0: // Execute callbacks for all pending executions,
Chris@0: // respecting firingIndex overrides and runtime changes
Chris@0: fired = firing = true;
Chris@0: for ( ; queue.length; firingIndex = -1 ) {
Chris@0: memory = queue.shift();
Chris@0: while ( ++firingIndex < list.length ) {
Chris@0:
Chris@0: // Run callback and check for early termination
Chris@0: if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
Chris@0: options.stopOnFalse ) {
Chris@0:
Chris@0: // Jump to end and forget the data so .add doesn't re-fire
Chris@0: firingIndex = list.length;
Chris@0: memory = false;
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Forget the data if we're done with it
Chris@0: if ( !options.memory ) {
Chris@0: memory = false;
Chris@0: }
Chris@0:
Chris@0: firing = false;
Chris@0:
Chris@0: // Clean up if we're done firing for good
Chris@0: if ( locked ) {
Chris@0:
Chris@0: // Keep an empty list if we have data for future add calls
Chris@0: if ( memory ) {
Chris@0: list = [];
Chris@0:
Chris@0: // Otherwise, this object is spent
Chris@0: } else {
Chris@0: list = "";
Chris@0: }
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: // Actual Callbacks object
Chris@0: self = {
Chris@0:
Chris@0: // Add a callback or a collection of callbacks to the list
Chris@0: add: function() {
Chris@0: if ( list ) {
Chris@0:
Chris@0: // If we have memory from a past run, we should fire after adding
Chris@0: if ( memory && !firing ) {
Chris@0: firingIndex = list.length - 1;
Chris@0: queue.push( memory );
Chris@0: }
Chris@0:
Chris@0: ( function add( args ) {
Chris@0: jQuery.each( args, function( _, arg ) {
Chris@0: if ( jQuery.isFunction( arg ) ) {
Chris@0: if ( !options.unique || !self.has( arg ) ) {
Chris@0: list.push( arg );
Chris@0: }
Chris@0: } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
Chris@0:
Chris@0: // Inspect recursively
Chris@0: add( arg );
Chris@0: }
Chris@0: } );
Chris@0: } )( arguments );
Chris@0:
Chris@0: if ( memory && !firing ) {
Chris@0: fire();
Chris@0: }
Chris@0: }
Chris@0: return this;
Chris@0: },
Chris@0:
Chris@0: // Remove a callback from the list
Chris@0: remove: function() {
Chris@0: jQuery.each( arguments, function( _, arg ) {
Chris@0: var index;
Chris@0: while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
Chris@0: list.splice( index, 1 );
Chris@0:
Chris@0: // Handle firing indexes
Chris@0: if ( index <= firingIndex ) {
Chris@0: firingIndex--;
Chris@0: }
Chris@0: }
Chris@0: } );
Chris@0: return this;
Chris@0: },
Chris@0:
Chris@0: // Check if a given callback is in the list.
Chris@0: // If no argument is given, return whether or not list has callbacks attached.
Chris@0: has: function( fn ) {
Chris@0: return fn ?
Chris@0: jQuery.inArray( fn, list ) > -1 :
Chris@0: list.length > 0;
Chris@0: },
Chris@0:
Chris@0: // Remove all callbacks from the list
Chris@0: empty: function() {
Chris@0: if ( list ) {
Chris@0: list = [];
Chris@0: }
Chris@0: return this;
Chris@0: },
Chris@0:
Chris@0: // Disable .fire and .add
Chris@0: // Abort any current/pending executions
Chris@0: // Clear all callbacks and values
Chris@0: disable: function() {
Chris@0: locked = queue = [];
Chris@0: list = memory = "";
Chris@0: return this;
Chris@0: },
Chris@0: disabled: function() {
Chris@0: return !list;
Chris@0: },
Chris@0:
Chris@0: // Disable .fire
Chris@0: // Also disable .add unless we have memory (since it would have no effect)
Chris@0: // Abort any pending executions
Chris@0: lock: function() {
Chris@0: locked = queue = [];
Chris@0: if ( !memory && !firing ) {
Chris@0: list = memory = "";
Chris@0: }
Chris@0: return this;
Chris@0: },
Chris@0: locked: function() {
Chris@0: return !!locked;
Chris@0: },
Chris@0:
Chris@0: // Call all callbacks with the given context and arguments
Chris@0: fireWith: function( context, args ) {
Chris@0: if ( !locked ) {
Chris@0: args = args || [];
Chris@0: args = [ context, args.slice ? args.slice() : args ];
Chris@0: queue.push( args );
Chris@0: if ( !firing ) {
Chris@0: fire();
Chris@0: }
Chris@0: }
Chris@0: return this;
Chris@0: },
Chris@0:
Chris@0: // Call all the callbacks with the given arguments
Chris@0: fire: function() {
Chris@0: self.fireWith( this, arguments );
Chris@0: return this;
Chris@0: },
Chris@0:
Chris@0: // To know if the callbacks have already been called at least once
Chris@0: fired: function() {
Chris@0: return !!fired;
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: return self;
Chris@0: };
Chris@0:
Chris@0:
Chris@0: function Identity( v ) {
Chris@0: return v;
Chris@0: }
Chris@0: function Thrower( ex ) {
Chris@0: throw ex;
Chris@0: }
Chris@0:
Chris@0: function adoptValue( value, resolve, reject, noValue ) {
Chris@0: var method;
Chris@0:
Chris@0: try {
Chris@0:
Chris@0: // Check for promise aspect first to privilege synchronous behavior
Chris@0: if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
Chris@0: method.call( value ).done( resolve ).fail( reject );
Chris@0:
Chris@0: // Other thenables
Chris@0: } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
Chris@0: method.call( value, resolve, reject );
Chris@0:
Chris@0: // Other non-thenables
Chris@0: } else {
Chris@0:
Chris@0: // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
Chris@0: // * false: [ value ].slice( 0 ) => resolve( value )
Chris@0: // * true: [ value ].slice( 1 ) => resolve()
Chris@0: resolve.apply( undefined, [ value ].slice( noValue ) );
Chris@0: }
Chris@0:
Chris@0: // For Promises/A+, convert exceptions into rejections
Chris@0: // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
Chris@0: // Deferred#then to conditionally suppress rejection.
Chris@0: } catch ( value ) {
Chris@0:
Chris@0: // Support: Android 4.0 only
Chris@0: // Strict mode functions invoked without .call/.apply get global-object context
Chris@0: reject.apply( undefined, [ value ] );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: jQuery.extend( {
Chris@0:
Chris@0: Deferred: function( func ) {
Chris@0: var tuples = [
Chris@0:
Chris@0: // action, add listener, callbacks,
Chris@0: // ... .then handlers, argument index, [final state]
Chris@0: [ "notify", "progress", jQuery.Callbacks( "memory" ),
Chris@0: jQuery.Callbacks( "memory" ), 2 ],
Chris@0: [ "resolve", "done", jQuery.Callbacks( "once memory" ),
Chris@0: jQuery.Callbacks( "once memory" ), 0, "resolved" ],
Chris@0: [ "reject", "fail", jQuery.Callbacks( "once memory" ),
Chris@0: jQuery.Callbacks( "once memory" ), 1, "rejected" ]
Chris@0: ],
Chris@0: state = "pending",
Chris@0: promise = {
Chris@0: state: function() {
Chris@0: return state;
Chris@0: },
Chris@0: always: function() {
Chris@0: deferred.done( arguments ).fail( arguments );
Chris@0: return this;
Chris@0: },
Chris@0: "catch": function( fn ) {
Chris@0: return promise.then( null, fn );
Chris@0: },
Chris@0:
Chris@0: // Keep pipe for back-compat
Chris@0: pipe: function( /* fnDone, fnFail, fnProgress */ ) {
Chris@0: var fns = arguments;
Chris@0:
Chris@0: return jQuery.Deferred( function( newDefer ) {
Chris@0: jQuery.each( tuples, function( i, tuple ) {
Chris@0:
Chris@0: // Map tuples (progress, done, fail) to arguments (done, fail, progress)
Chris@0: var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
Chris@0:
Chris@0: // deferred.progress(function() { bind to newDefer or newDefer.notify })
Chris@0: // deferred.done(function() { bind to newDefer or newDefer.resolve })
Chris@0: // deferred.fail(function() { bind to newDefer or newDefer.reject })
Chris@0: deferred[ tuple[ 1 ] ]( function() {
Chris@0: var returned = fn && fn.apply( this, arguments );
Chris@0: if ( returned && jQuery.isFunction( returned.promise ) ) {
Chris@0: returned.promise()
Chris@0: .progress( newDefer.notify )
Chris@0: .done( newDefer.resolve )
Chris@0: .fail( newDefer.reject );
Chris@0: } else {
Chris@0: newDefer[ tuple[ 0 ] + "With" ](
Chris@0: this,
Chris@0: fn ? [ returned ] : arguments
Chris@0: );
Chris@0: }
Chris@0: } );
Chris@0: } );
Chris@0: fns = null;
Chris@0: } ).promise();
Chris@0: },
Chris@0: then: function( onFulfilled, onRejected, onProgress ) {
Chris@0: var maxDepth = 0;
Chris@0: function resolve( depth, deferred, handler, special ) {
Chris@0: return function() {
Chris@0: var that = this,
Chris@0: args = arguments,
Chris@0: mightThrow = function() {
Chris@0: var returned, then;
Chris@0:
Chris@0: // Support: Promises/A+ section 2.3.3.3.3
Chris@0: // https://promisesaplus.com/#point-59
Chris@0: // Ignore double-resolution attempts
Chris@0: if ( depth < maxDepth ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: returned = handler.apply( that, args );
Chris@0:
Chris@0: // Support: Promises/A+ section 2.3.1
Chris@0: // https://promisesaplus.com/#point-48
Chris@0: if ( returned === deferred.promise() ) {
Chris@0: throw new TypeError( "Thenable self-resolution" );
Chris@0: }
Chris@0:
Chris@0: // Support: Promises/A+ sections 2.3.3.1, 3.5
Chris@0: // https://promisesaplus.com/#point-54
Chris@0: // https://promisesaplus.com/#point-75
Chris@0: // Retrieve `then` only once
Chris@0: then = returned &&
Chris@0:
Chris@0: // Support: Promises/A+ section 2.3.4
Chris@0: // https://promisesaplus.com/#point-64
Chris@0: // Only check objects and functions for thenability
Chris@0: ( typeof returned === "object" ||
Chris@0: typeof returned === "function" ) &&
Chris@0: returned.then;
Chris@0:
Chris@0: // Handle a returned thenable
Chris@0: if ( jQuery.isFunction( then ) ) {
Chris@0:
Chris@0: // Special processors (notify) just wait for resolution
Chris@0: if ( special ) {
Chris@0: then.call(
Chris@0: returned,
Chris@0: resolve( maxDepth, deferred, Identity, special ),
Chris@0: resolve( maxDepth, deferred, Thrower, special )
Chris@0: );
Chris@0:
Chris@0: // Normal processors (resolve) also hook into progress
Chris@0: } else {
Chris@0:
Chris@0: // ...and disregard older resolution values
Chris@0: maxDepth++;
Chris@0:
Chris@0: then.call(
Chris@0: returned,
Chris@0: resolve( maxDepth, deferred, Identity, special ),
Chris@0: resolve( maxDepth, deferred, Thrower, special ),
Chris@0: resolve( maxDepth, deferred, Identity,
Chris@0: deferred.notifyWith )
Chris@0: );
Chris@0: }
Chris@0:
Chris@0: // Handle all other returned values
Chris@0: } else {
Chris@0:
Chris@0: // Only substitute handlers pass on context
Chris@0: // and multiple values (non-spec behavior)
Chris@0: if ( handler !== Identity ) {
Chris@0: that = undefined;
Chris@0: args = [ returned ];
Chris@0: }
Chris@0:
Chris@0: // Process the value(s)
Chris@0: // Default process is resolve
Chris@0: ( special || deferred.resolveWith )( that, args );
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: // Only normal processors (resolve) catch and reject exceptions
Chris@0: process = special ?
Chris@0: mightThrow :
Chris@0: function() {
Chris@0: try {
Chris@0: mightThrow();
Chris@0: } catch ( e ) {
Chris@0:
Chris@0: if ( jQuery.Deferred.exceptionHook ) {
Chris@0: jQuery.Deferred.exceptionHook( e,
Chris@0: process.stackTrace );
Chris@0: }
Chris@0:
Chris@0: // Support: Promises/A+ section 2.3.3.3.4.1
Chris@0: // https://promisesaplus.com/#point-61
Chris@0: // Ignore post-resolution exceptions
Chris@0: if ( depth + 1 >= maxDepth ) {
Chris@0:
Chris@0: // Only substitute handlers pass on context
Chris@0: // and multiple values (non-spec behavior)
Chris@0: if ( handler !== Thrower ) {
Chris@0: that = undefined;
Chris@0: args = [ e ];
Chris@0: }
Chris@0:
Chris@0: deferred.rejectWith( that, args );
Chris@0: }
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: // Support: Promises/A+ section 2.3.3.3.1
Chris@0: // https://promisesaplus.com/#point-57
Chris@0: // Re-resolve promises immediately to dodge false rejection from
Chris@0: // subsequent errors
Chris@0: if ( depth ) {
Chris@0: process();
Chris@0: } else {
Chris@0:
Chris@0: // Call an optional hook to record the stack, in case of exception
Chris@0: // since it's otherwise lost when execution goes async
Chris@0: if ( jQuery.Deferred.getStackHook ) {
Chris@0: process.stackTrace = jQuery.Deferred.getStackHook();
Chris@0: }
Chris@0: window.setTimeout( process );
Chris@0: }
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: return jQuery.Deferred( function( newDefer ) {
Chris@0:
Chris@0: // progress_handlers.add( ... )
Chris@0: tuples[ 0 ][ 3 ].add(
Chris@0: resolve(
Chris@0: 0,
Chris@0: newDefer,
Chris@0: jQuery.isFunction( onProgress ) ?
Chris@0: onProgress :
Chris@0: Identity,
Chris@0: newDefer.notifyWith
Chris@0: )
Chris@0: );
Chris@0:
Chris@0: // fulfilled_handlers.add( ... )
Chris@0: tuples[ 1 ][ 3 ].add(
Chris@0: resolve(
Chris@0: 0,
Chris@0: newDefer,
Chris@0: jQuery.isFunction( onFulfilled ) ?
Chris@0: onFulfilled :
Chris@0: Identity
Chris@0: )
Chris@0: );
Chris@0:
Chris@0: // rejected_handlers.add( ... )
Chris@0: tuples[ 2 ][ 3 ].add(
Chris@0: resolve(
Chris@0: 0,
Chris@0: newDefer,
Chris@0: jQuery.isFunction( onRejected ) ?
Chris@0: onRejected :
Chris@0: Thrower
Chris@0: )
Chris@0: );
Chris@0: } ).promise();
Chris@0: },
Chris@0:
Chris@0: // Get a promise for this deferred
Chris@0: // If obj is provided, the promise aspect is added to the object
Chris@0: promise: function( obj ) {
Chris@0: return obj != null ? jQuery.extend( obj, promise ) : promise;
Chris@0: }
Chris@0: },
Chris@0: deferred = {};
Chris@0:
Chris@0: // Add list-specific methods
Chris@0: jQuery.each( tuples, function( i, tuple ) {
Chris@0: var list = tuple[ 2 ],
Chris@0: stateString = tuple[ 5 ];
Chris@0:
Chris@0: // promise.progress = list.add
Chris@0: // promise.done = list.add
Chris@0: // promise.fail = list.add
Chris@0: promise[ tuple[ 1 ] ] = list.add;
Chris@0:
Chris@0: // Handle state
Chris@0: if ( stateString ) {
Chris@0: list.add(
Chris@0: function() {
Chris@0:
Chris@0: // state = "resolved" (i.e., fulfilled)
Chris@0: // state = "rejected"
Chris@0: state = stateString;
Chris@0: },
Chris@0:
Chris@0: // rejected_callbacks.disable
Chris@0: // fulfilled_callbacks.disable
Chris@0: tuples[ 3 - i ][ 2 ].disable,
Chris@0:
Chris@0: // progress_callbacks.lock
Chris@0: tuples[ 0 ][ 2 ].lock
Chris@0: );
Chris@0: }
Chris@0:
Chris@0: // progress_handlers.fire
Chris@0: // fulfilled_handlers.fire
Chris@0: // rejected_handlers.fire
Chris@0: list.add( tuple[ 3 ].fire );
Chris@0:
Chris@0: // deferred.notify = function() { deferred.notifyWith(...) }
Chris@0: // deferred.resolve = function() { deferred.resolveWith(...) }
Chris@0: // deferred.reject = function() { deferred.rejectWith(...) }
Chris@0: deferred[ tuple[ 0 ] ] = function() {
Chris@0: deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
Chris@0: return this;
Chris@0: };
Chris@0:
Chris@0: // deferred.notifyWith = list.fireWith
Chris@0: // deferred.resolveWith = list.fireWith
Chris@0: // deferred.rejectWith = list.fireWith
Chris@0: deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
Chris@0: } );
Chris@0:
Chris@0: // Make the deferred a promise
Chris@0: promise.promise( deferred );
Chris@0:
Chris@0: // Call given func if any
Chris@0: if ( func ) {
Chris@0: func.call( deferred, deferred );
Chris@0: }
Chris@0:
Chris@0: // All done!
Chris@0: return deferred;
Chris@0: },
Chris@0:
Chris@0: // Deferred helper
Chris@0: when: function( singleValue ) {
Chris@0: var
Chris@0:
Chris@0: // count of uncompleted subordinates
Chris@0: remaining = arguments.length,
Chris@0:
Chris@0: // count of unprocessed arguments
Chris@0: i = remaining,
Chris@0:
Chris@0: // subordinate fulfillment data
Chris@0: resolveContexts = Array( i ),
Chris@0: resolveValues = slice.call( arguments ),
Chris@0:
Chris@0: // the master Deferred
Chris@0: master = jQuery.Deferred(),
Chris@0:
Chris@0: // subordinate callback factory
Chris@0: updateFunc = function( i ) {
Chris@0: return function( value ) {
Chris@0: resolveContexts[ i ] = this;
Chris@0: resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
Chris@0: if ( !( --remaining ) ) {
Chris@0: master.resolveWith( resolveContexts, resolveValues );
Chris@0: }
Chris@0: };
Chris@0: };
Chris@0:
Chris@0: // Single- and empty arguments are adopted like Promise.resolve
Chris@0: if ( remaining <= 1 ) {
Chris@0: adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
Chris@0: !remaining );
Chris@0:
Chris@0: // Use .then() to unwrap secondary thenables (cf. gh-3000)
Chris@0: if ( master.state() === "pending" ||
Chris@0: jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
Chris@0:
Chris@0: return master.then();
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Multiple arguments are aggregated like Promise.all array elements
Chris@0: while ( i-- ) {
Chris@0: adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
Chris@0: }
Chris@0:
Chris@0: return master.promise();
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0:
Chris@0: // These usually indicate a programmer mistake during development,
Chris@0: // warn about them ASAP rather than swallowing them by default.
Chris@0: var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
Chris@0:
Chris@0: jQuery.Deferred.exceptionHook = function( error, stack ) {
Chris@0:
Chris@0: // Support: IE 8 - 9 only
Chris@0: // Console exists when dev tools are open, which can happen at any time
Chris@0: if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
Chris@0: window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
Chris@0: }
Chris@0: };
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: jQuery.readyException = function( error ) {
Chris@0: window.setTimeout( function() {
Chris@0: throw error;
Chris@0: } );
Chris@0: };
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: // The deferred used on DOM ready
Chris@0: var readyList = jQuery.Deferred();
Chris@0:
Chris@0: jQuery.fn.ready = function( fn ) {
Chris@0:
Chris@0: readyList
Chris@0: .then( fn )
Chris@0:
Chris@0: // Wrap jQuery.readyException in a function so that the lookup
Chris@0: // happens at the time of error handling instead of callback
Chris@0: // registration.
Chris@0: .catch( function( error ) {
Chris@0: jQuery.readyException( error );
Chris@0: } );
Chris@0:
Chris@0: return this;
Chris@0: };
Chris@0:
Chris@0: jQuery.extend( {
Chris@0:
Chris@0: // Is the DOM ready to be used? Set to true once it occurs.
Chris@0: isReady: false,
Chris@0:
Chris@0: // A counter to track how many items to wait for before
Chris@0: // the ready event fires. See #6781
Chris@0: readyWait: 1,
Chris@0:
Chris@0: // Handle when the DOM is ready
Chris@0: ready: function( wait ) {
Chris@0:
Chris@0: // Abort if there are pending holds or we're already ready
Chris@0: if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // Remember that the DOM is ready
Chris@0: jQuery.isReady = true;
Chris@0:
Chris@0: // If a normal DOM Ready event fired, decrement, and wait if need be
Chris@0: if ( wait !== true && --jQuery.readyWait > 0 ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // If there are functions bound, to execute
Chris@0: readyList.resolveWith( document, [ jQuery ] );
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0: jQuery.ready.then = readyList.then;
Chris@0:
Chris@0: // The ready event handler and self cleanup method
Chris@0: function completed() {
Chris@0: document.removeEventListener( "DOMContentLoaded", completed );
Chris@0: window.removeEventListener( "load", completed );
Chris@0: jQuery.ready();
Chris@0: }
Chris@0:
Chris@0: // Catch cases where $(document).ready() is called
Chris@0: // after the browser event has already occurred.
Chris@0: // Support: IE <=9 - 10 only
Chris@0: // Older IE sometimes signals "interactive" too soon
Chris@0: if ( document.readyState === "complete" ||
Chris@0: ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
Chris@0:
Chris@0: // Handle it asynchronously to allow scripts the opportunity to delay ready
Chris@0: window.setTimeout( jQuery.ready );
Chris@0:
Chris@0: } else {
Chris@0:
Chris@0: // Use the handy event callback
Chris@0: document.addEventListener( "DOMContentLoaded", completed );
Chris@0:
Chris@0: // A fallback to window.onload, that will always work
Chris@0: window.addEventListener( "load", completed );
Chris@0: }
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: // Multifunctional method to get and set values of a collection
Chris@0: // The value/s can optionally be executed if it's a function
Chris@0: var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
Chris@0: var i = 0,
Chris@0: len = elems.length,
Chris@0: bulk = key == null;
Chris@0:
Chris@0: // Sets many values
Chris@0: if ( jQuery.type( key ) === "object" ) {
Chris@0: chainable = true;
Chris@0: for ( i in key ) {
Chris@0: access( elems, fn, i, key[ i ], true, emptyGet, raw );
Chris@0: }
Chris@0:
Chris@0: // Sets one value
Chris@0: } else if ( value !== undefined ) {
Chris@0: chainable = true;
Chris@0:
Chris@0: if ( !jQuery.isFunction( value ) ) {
Chris@0: raw = true;
Chris@0: }
Chris@0:
Chris@0: if ( bulk ) {
Chris@0:
Chris@0: // Bulk operations run against the entire set
Chris@0: if ( raw ) {
Chris@0: fn.call( elems, value );
Chris@0: fn = null;
Chris@0:
Chris@0: // ...except when executing function values
Chris@0: } else {
Chris@0: bulk = fn;
Chris@0: fn = function( elem, key, value ) {
Chris@0: return bulk.call( jQuery( elem ), value );
Chris@0: };
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: if ( fn ) {
Chris@0: for ( ; i < len; i++ ) {
Chris@0: fn(
Chris@0: elems[ i ], key, raw ?
Chris@0: value :
Chris@0: value.call( elems[ i ], i, fn( elems[ i ], key ) )
Chris@0: );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: if ( chainable ) {
Chris@0: return elems;
Chris@0: }
Chris@0:
Chris@0: // Gets
Chris@0: if ( bulk ) {
Chris@0: return fn.call( elems );
Chris@0: }
Chris@0:
Chris@0: return len ? fn( elems[ 0 ], key ) : emptyGet;
Chris@0: };
Chris@0: var acceptData = function( owner ) {
Chris@0:
Chris@0: // Accepts only:
Chris@0: // - Node
Chris@0: // - Node.ELEMENT_NODE
Chris@0: // - Node.DOCUMENT_NODE
Chris@0: // - Object
Chris@0: // - Any
Chris@0: return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
Chris@0: };
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: function Data() {
Chris@0: this.expando = jQuery.expando + Data.uid++;
Chris@0: }
Chris@0:
Chris@0: Data.uid = 1;
Chris@0:
Chris@0: Data.prototype = {
Chris@0:
Chris@0: cache: function( owner ) {
Chris@0:
Chris@0: // Check if the owner object already has a cache
Chris@0: var value = owner[ this.expando ];
Chris@0:
Chris@0: // If not, create one
Chris@0: if ( !value ) {
Chris@0: value = {};
Chris@0:
Chris@0: // We can accept data for non-element nodes in modern browsers,
Chris@0: // but we should not, see #8335.
Chris@0: // Always return an empty object.
Chris@0: if ( acceptData( owner ) ) {
Chris@0:
Chris@0: // If it is a node unlikely to be stringify-ed or looped over
Chris@0: // use plain assignment
Chris@0: if ( owner.nodeType ) {
Chris@0: owner[ this.expando ] = value;
Chris@0:
Chris@0: // Otherwise secure it in a non-enumerable property
Chris@0: // configurable must be true to allow the property to be
Chris@0: // deleted when data is removed
Chris@0: } else {
Chris@0: Object.defineProperty( owner, this.expando, {
Chris@0: value: value,
Chris@0: configurable: true
Chris@0: } );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return value;
Chris@0: },
Chris@0: set: function( owner, data, value ) {
Chris@0: var prop,
Chris@0: cache = this.cache( owner );
Chris@0:
Chris@0: // Handle: [ owner, key, value ] args
Chris@0: // Always use camelCase key (gh-2257)
Chris@0: if ( typeof data === "string" ) {
Chris@0: cache[ jQuery.camelCase( data ) ] = value;
Chris@0:
Chris@0: // Handle: [ owner, { properties } ] args
Chris@0: } else {
Chris@0:
Chris@0: // Copy the properties one-by-one to the cache object
Chris@0: for ( prop in data ) {
Chris@0: cache[ jQuery.camelCase( prop ) ] = data[ prop ];
Chris@0: }
Chris@0: }
Chris@0: return cache;
Chris@0: },
Chris@0: get: function( owner, key ) {
Chris@0: return key === undefined ?
Chris@0: this.cache( owner ) :
Chris@0:
Chris@0: // Always use camelCase key (gh-2257)
Chris@0: owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
Chris@0: },
Chris@0: access: function( owner, key, value ) {
Chris@0:
Chris@0: // In cases where either:
Chris@0: //
Chris@0: // 1. No key was specified
Chris@0: // 2. A string key was specified, but no value provided
Chris@0: //
Chris@0: // Take the "read" path and allow the get method to determine
Chris@0: // which value to return, respectively either:
Chris@0: //
Chris@0: // 1. The entire cache object
Chris@0: // 2. The data stored at the key
Chris@0: //
Chris@0: if ( key === undefined ||
Chris@0: ( ( key && typeof key === "string" ) && value === undefined ) ) {
Chris@0:
Chris@0: return this.get( owner, key );
Chris@0: }
Chris@0:
Chris@0: // When the key is not a string, or both a key and value
Chris@0: // are specified, set or extend (existing objects) with either:
Chris@0: //
Chris@0: // 1. An object of properties
Chris@0: // 2. A key and value
Chris@0: //
Chris@0: this.set( owner, key, value );
Chris@0:
Chris@0: // Since the "set" path can have two possible entry points
Chris@0: // return the expected data based on which path was taken[*]
Chris@0: return value !== undefined ? value : key;
Chris@0: },
Chris@0: remove: function( owner, key ) {
Chris@0: var i,
Chris@0: cache = owner[ this.expando ];
Chris@0:
Chris@0: if ( cache === undefined ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: if ( key !== undefined ) {
Chris@0:
Chris@0: // Support array or space separated string of keys
Chris@0: if ( Array.isArray( key ) ) {
Chris@0:
Chris@0: // If key is an array of keys...
Chris@0: // We always set camelCase keys, so remove that.
Chris@0: key = key.map( jQuery.camelCase );
Chris@0: } else {
Chris@0: key = jQuery.camelCase( key );
Chris@0:
Chris@0: // If a key with the spaces exists, use it.
Chris@0: // Otherwise, create an array by matching non-whitespace
Chris@0: key = key in cache ?
Chris@0: [ key ] :
Chris@0: ( key.match( rnothtmlwhite ) || [] );
Chris@0: }
Chris@0:
Chris@0: i = key.length;
Chris@0:
Chris@0: while ( i-- ) {
Chris@0: delete cache[ key[ i ] ];
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Remove the expando if there's no more data
Chris@0: if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
Chris@0:
Chris@0: // Support: Chrome <=35 - 45
Chris@0: // Webkit & Blink performance suffers when deleting properties
Chris@0: // from DOM nodes, so set to undefined instead
Chris@0: // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
Chris@0: if ( owner.nodeType ) {
Chris@0: owner[ this.expando ] = undefined;
Chris@0: } else {
Chris@0: delete owner[ this.expando ];
Chris@0: }
Chris@0: }
Chris@0: },
Chris@0: hasData: function( owner ) {
Chris@0: var cache = owner[ this.expando ];
Chris@0: return cache !== undefined && !jQuery.isEmptyObject( cache );
Chris@0: }
Chris@0: };
Chris@0: var dataPriv = new Data();
Chris@0:
Chris@0: var dataUser = new Data();
Chris@0:
Chris@0:
Chris@0:
Chris@0: // Implementation Summary
Chris@0: //
Chris@0: // 1. Enforce API surface and semantic compatibility with 1.9.x branch
Chris@0: // 2. Improve the module's maintainability by reducing the storage
Chris@0: // paths to a single mechanism.
Chris@0: // 3. Use the same single mechanism to support "private" and "user" data.
Chris@0: // 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
Chris@0: // 5. Avoid exposing implementation details on user objects (eg. expando properties)
Chris@0: // 6. Provide a clear path for implementation upgrade to WeakMap in 2014
Chris@0:
Chris@0: var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
Chris@0: rmultiDash = /[A-Z]/g;
Chris@0:
Chris@0: function getData( data ) {
Chris@0: if ( data === "true" ) {
Chris@0: return true;
Chris@0: }
Chris@0:
Chris@0: if ( data === "false" ) {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@0: if ( data === "null" ) {
Chris@0: return null;
Chris@0: }
Chris@0:
Chris@0: // Only convert to a number if it doesn't change the string
Chris@0: if ( data === +data + "" ) {
Chris@0: return +data;
Chris@0: }
Chris@0:
Chris@0: if ( rbrace.test( data ) ) {
Chris@0: return JSON.parse( data );
Chris@0: }
Chris@0:
Chris@0: return data;
Chris@0: }
Chris@0:
Chris@0: function dataAttr( elem, key, data ) {
Chris@0: var name;
Chris@0:
Chris@0: // If nothing was found internally, try to fetch any
Chris@0: // data from the HTML5 data-* attribute
Chris@0: if ( data === undefined && elem.nodeType === 1 ) {
Chris@0: name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
Chris@0: data = elem.getAttribute( name );
Chris@0:
Chris@0: if ( typeof data === "string" ) {
Chris@0: try {
Chris@0: data = getData( data );
Chris@0: } catch ( e ) {}
Chris@0:
Chris@0: // Make sure we set the data so it isn't changed later
Chris@0: dataUser.set( elem, key, data );
Chris@0: } else {
Chris@0: data = undefined;
Chris@0: }
Chris@0: }
Chris@0: return data;
Chris@0: }
Chris@0:
Chris@0: jQuery.extend( {
Chris@0: hasData: function( elem ) {
Chris@0: return dataUser.hasData( elem ) || dataPriv.hasData( elem );
Chris@0: },
Chris@0:
Chris@0: data: function( elem, name, data ) {
Chris@0: return dataUser.access( elem, name, data );
Chris@0: },
Chris@0:
Chris@0: removeData: function( elem, name ) {
Chris@0: dataUser.remove( elem, name );
Chris@0: },
Chris@0:
Chris@0: // TODO: Now that all calls to _data and _removeData have been replaced
Chris@0: // with direct calls to dataPriv methods, these can be deprecated.
Chris@0: _data: function( elem, name, data ) {
Chris@0: return dataPriv.access( elem, name, data );
Chris@0: },
Chris@0:
Chris@0: _removeData: function( elem, name ) {
Chris@0: dataPriv.remove( elem, name );
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0: jQuery.fn.extend( {
Chris@0: data: function( key, value ) {
Chris@0: var i, name, data,
Chris@0: elem = this[ 0 ],
Chris@0: attrs = elem && elem.attributes;
Chris@0:
Chris@0: // Gets all values
Chris@0: if ( key === undefined ) {
Chris@0: if ( this.length ) {
Chris@0: data = dataUser.get( elem );
Chris@0:
Chris@0: if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
Chris@0: i = attrs.length;
Chris@0: while ( i-- ) {
Chris@0:
Chris@0: // Support: IE 11 only
Chris@0: // The attrs elements can be null (#14894)
Chris@0: if ( attrs[ i ] ) {
Chris@0: name = attrs[ i ].name;
Chris@0: if ( name.indexOf( "data-" ) === 0 ) {
Chris@0: name = jQuery.camelCase( name.slice( 5 ) );
Chris@0: dataAttr( elem, name, data[ name ] );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: dataPriv.set( elem, "hasDataAttrs", true );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return data;
Chris@0: }
Chris@0:
Chris@0: // Sets multiple values
Chris@0: if ( typeof key === "object" ) {
Chris@0: return this.each( function() {
Chris@0: dataUser.set( this, key );
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: return access( this, function( value ) {
Chris@0: var data;
Chris@0:
Chris@0: // The calling jQuery object (element matches) is not empty
Chris@0: // (and therefore has an element appears at this[ 0 ]) and the
Chris@0: // `value` parameter was not undefined. An empty jQuery object
Chris@0: // will result in `undefined` for elem = this[ 0 ] which will
Chris@0: // throw an exception if an attempt to read a data cache is made.
Chris@0: if ( elem && value === undefined ) {
Chris@0:
Chris@0: // Attempt to get data from the cache
Chris@0: // The key will always be camelCased in Data
Chris@0: data = dataUser.get( elem, key );
Chris@0: if ( data !== undefined ) {
Chris@0: return data;
Chris@0: }
Chris@0:
Chris@0: // Attempt to "discover" the data in
Chris@0: // HTML5 custom data-* attrs
Chris@0: data = dataAttr( elem, key );
Chris@0: if ( data !== undefined ) {
Chris@0: return data;
Chris@0: }
Chris@0:
Chris@0: // We tried really hard, but the data doesn't exist.
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // Set the data...
Chris@0: this.each( function() {
Chris@0:
Chris@0: // We always store the camelCased key
Chris@0: dataUser.set( this, key, value );
Chris@0: } );
Chris@0: }, null, value, arguments.length > 1, null, true );
Chris@0: },
Chris@0:
Chris@0: removeData: function( key ) {
Chris@0: return this.each( function() {
Chris@0: dataUser.remove( this, key );
Chris@0: } );
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0:
Chris@0: jQuery.extend( {
Chris@0: queue: function( elem, type, data ) {
Chris@0: var queue;
Chris@0:
Chris@0: if ( elem ) {
Chris@0: type = ( type || "fx" ) + "queue";
Chris@0: queue = dataPriv.get( elem, type );
Chris@0:
Chris@0: // Speed up dequeue by getting out quickly if this is just a lookup
Chris@0: if ( data ) {
Chris@0: if ( !queue || Array.isArray( data ) ) {
Chris@0: queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
Chris@0: } else {
Chris@0: queue.push( data );
Chris@0: }
Chris@0: }
Chris@0: return queue || [];
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: dequeue: function( elem, type ) {
Chris@0: type = type || "fx";
Chris@0:
Chris@0: var queue = jQuery.queue( elem, type ),
Chris@0: startLength = queue.length,
Chris@0: fn = queue.shift(),
Chris@0: hooks = jQuery._queueHooks( elem, type ),
Chris@0: next = function() {
Chris@0: jQuery.dequeue( elem, type );
Chris@0: };
Chris@0:
Chris@0: // If the fx queue is dequeued, always remove the progress sentinel
Chris@0: if ( fn === "inprogress" ) {
Chris@0: fn = queue.shift();
Chris@0: startLength--;
Chris@0: }
Chris@0:
Chris@0: if ( fn ) {
Chris@0:
Chris@0: // Add a progress sentinel to prevent the fx queue from being
Chris@0: // automatically dequeued
Chris@0: if ( type === "fx" ) {
Chris@0: queue.unshift( "inprogress" );
Chris@0: }
Chris@0:
Chris@0: // Clear up the last queue stop function
Chris@0: delete hooks.stop;
Chris@0: fn.call( elem, next, hooks );
Chris@0: }
Chris@0:
Chris@0: if ( !startLength && hooks ) {
Chris@0: hooks.empty.fire();
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: // Not public - generate a queueHooks object, or return the current one
Chris@0: _queueHooks: function( elem, type ) {
Chris@0: var key = type + "queueHooks";
Chris@0: return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
Chris@0: empty: jQuery.Callbacks( "once memory" ).add( function() {
Chris@0: dataPriv.remove( elem, [ type + "queue", key ] );
Chris@0: } )
Chris@0: } );
Chris@0: }
Chris@0: } );
Chris@0:
Chris@0: jQuery.fn.extend( {
Chris@0: queue: function( type, data ) {
Chris@0: var setter = 2;
Chris@0:
Chris@0: if ( typeof type !== "string" ) {
Chris@0: data = type;
Chris@0: type = "fx";
Chris@0: setter--;
Chris@0: }
Chris@0:
Chris@0: if ( arguments.length < setter ) {
Chris@0: return jQuery.queue( this[ 0 ], type );
Chris@0: }
Chris@0:
Chris@0: return data === undefined ?
Chris@0: this :
Chris@0: this.each( function() {
Chris@0: var queue = jQuery.queue( this, type, data );
Chris@0:
Chris@0: // Ensure a hooks for this queue
Chris@0: jQuery._queueHooks( this, type );
Chris@0:
Chris@0: if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
Chris@0: jQuery.dequeue( this, type );
Chris@0: }
Chris@0: } );
Chris@0: },
Chris@0: dequeue: function( type ) {
Chris@0: return this.each( function() {
Chris@0: jQuery.dequeue( this, type );
Chris@0: } );
Chris@0: },
Chris@0: clearQueue: function( type ) {
Chris@0: return this.queue( type || "fx", [] );
Chris@0: },
Chris@0:
Chris@0: // Get a promise resolved when queues of a certain type
Chris@0: // are emptied (fx is the type by default)
Chris@0: promise: function( type, obj ) {
Chris@0: var tmp,
Chris@0: count = 1,
Chris@0: defer = jQuery.Deferred(),
Chris@0: elements = this,
Chris@0: i = this.length,
Chris@0: resolve = function() {
Chris@0: if ( !( --count ) ) {
Chris@0: defer.resolveWith( elements, [ elements ] );
Chris@0: }
Chris@0: };
Chris@0:
Chris@0: if ( typeof type !== "string" ) {
Chris@0: obj = type;
Chris@0: type = undefined;
Chris@0: }
Chris@0: type = type || "fx";
Chris@0:
Chris@0: while ( i-- ) {
Chris@0: tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
Chris@0: if ( tmp && tmp.empty ) {
Chris@0: count++;
Chris@0: tmp.empty.add( resolve );
Chris@0: }
Chris@0: }
Chris@0: resolve();
Chris@0: return defer.promise( obj );
Chris@0: }
Chris@0: } );
Chris@0: var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
Chris@0:
Chris@0: var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
Chris@0:
Chris@0:
Chris@0: var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
Chris@0:
Chris@0: var isHiddenWithinTree = function( elem, el ) {
Chris@0:
Chris@0: // isHiddenWithinTree might be called from jQuery#filter function;
Chris@0: // in that case, element will be second argument
Chris@0: elem = el || elem;
Chris@0:
Chris@0: // Inline style trumps all
Chris@0: return elem.style.display === "none" ||
Chris@0: elem.style.display === "" &&
Chris@0:
Chris@0: // Otherwise, check computed style
Chris@0: // Support: Firefox <=43 - 45
Chris@0: // Disconnected elements can have computed display: none, so first confirm that elem is
Chris@0: // in the document.
Chris@0: jQuery.contains( elem.ownerDocument, elem ) &&
Chris@0:
Chris@0: jQuery.css( elem, "display" ) === "none";
Chris@0: };
Chris@0:
Chris@0: var swap = function( elem, options, callback, args ) {
Chris@0: var ret, name,
Chris@0: old = {};
Chris@0:
Chris@0: // Remember the old values, and insert the new ones
Chris@0: for ( name in options ) {
Chris@0: old[ name ] = elem.style[ name ];
Chris@0: elem.style[ name ] = options[ name ];
Chris@0: }
Chris@0:
Chris@0: ret = callback.apply( elem, args || [] );
Chris@0:
Chris@0: // Revert the old values
Chris@0: for ( name in options ) {
Chris@0: elem.style[ name ] = old[ name ];
Chris@0: }
Chris@0:
Chris@0: return ret;
Chris@0: };
Chris@0:
Chris@0:
Chris@0:
Chris@0:
Chris@0: function adjustCSS( elem, prop, valueParts, tween ) {
Chris@0: var adjusted,
Chris@0: scale = 1,
Chris@0: maxIterations = 20,
Chris@0: currentValue = tween ?
Chris@0: function() {
Chris@0: return tween.cur();
Chris@0: } :
Chris@0: function() {
Chris@0: return jQuery.css( elem, prop, "" );
Chris@0: },
Chris@0: initial = currentValue(),
Chris@0: unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
Chris@0:
Chris@0: // Starting value computation is required for potential unit mismatches
Chris@0: initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
Chris@0: rcssNum.exec( jQuery.css( elem, prop ) );
Chris@0:
Chris@0: if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
Chris@0:
Chris@0: // Trust units reported by jQuery.css
Chris@0: unit = unit || initialInUnit[ 3 ];
Chris@0:
Chris@0: // Make sure we update the tween properties later on
Chris@0: valueParts = valueParts || [];
Chris@0:
Chris@0: // Iteratively approximate from a nonzero starting point
Chris@0: initialInUnit = +initial || 1;
Chris@0:
Chris@0: do {
Chris@0:
Chris@0: // If previous iteration zeroed out, double until we get *something*.
Chris@0: // Use string for doubling so we don't accidentally see scale as unchanged below
Chris@0: scale = scale || ".5";
Chris@0:
Chris@0: // Adjust and apply
Chris@0: initialInUnit = initialInUnit / scale;
Chris@0: jQuery.style( elem, prop, initialInUnit + unit );
Chris@0:
Chris@0: // Update scale, tolerating zero or NaN from tween.cur()
Chris@0: // Break the loop if scale is unchanged or perfect, or if we've just had enough.
Chris@0: } while (
Chris@0: scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
Chris@0: );
Chris@0: }
Chris@0:
Chris@0: if ( valueParts ) {
Chris@0: initialInUnit = +initialInUnit || +initial || 0;
Chris@0:
Chris@0: // Apply relative offset (+=/-=) if specified
Chris@0: adjusted = valueParts[ 1 ] ?
Chris@0: initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
Chris@0: +valueParts[ 2 ];
Chris@0: if ( tween ) {
Chris@0: tween.unit = unit;
Chris@0: tween.start = initialInUnit;
Chris@0: tween.end = adjusted;
Chris@0: }
Chris@0: }
Chris@0: return adjusted;
Chris@0: }
Chris@0:
Chris@0:
Chris@0: var defaultDisplayMap = {};
Chris@0:
Chris@0: function getDefaultDisplay( elem ) {
Chris@0: var temp,
Chris@0: doc = elem.ownerDocument,
Chris@0: nodeName = elem.nodeName,
Chris@0: display = defaultDisplayMap[ nodeName ];
Chris@0:
Chris@0: if ( display ) {
Chris@0: return display;
Chris@0: }
Chris@0:
Chris@0: temp = doc.body.appendChild( doc.createElement( nodeName ) );
Chris@0: display = jQuery.css( temp, "display" );
Chris@0:
Chris@0: temp.parentNode.removeChild( temp );
Chris@0:
Chris@0: if ( display === "none" ) {
Chris@0: display = "block";
Chris@0: }
Chris@0: defaultDisplayMap[ nodeName ] = display;
Chris@0:
Chris@0: return display;
Chris@0: }
Chris@0:
Chris@0: function showHide( elements, show ) {
Chris@0: var display, elem,
Chris@0: values = [],
Chris@0: index = 0,
Chris@0: length = elements.length;
Chris@0:
Chris@0: // Determine new display value for elements that need to change
Chris@0: for ( ; index < length; index++ ) {
Chris@0: elem = elements[ index ];
Chris@0: if ( !elem.style ) {
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: display = elem.style.display;
Chris@0: if ( show ) {
Chris@0:
Chris@0: // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
Chris@0: // check is required in this first loop unless we have a nonempty display value (either
Chris@0: // inline or about-to-be-restored)
Chris@0: if ( display === "none" ) {
Chris@0: values[ index ] = dataPriv.get( elem, "display" ) || null;
Chris@0: if ( !values[ index ] ) {
Chris@0: elem.style.display = "";
Chris@0: }
Chris@0: }
Chris@0: if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
Chris@0: values[ index ] = getDefaultDisplay( elem );
Chris@0: }
Chris@0: } else {
Chris@0: if ( display !== "none" ) {
Chris@0: values[ index ] = "none";
Chris@0:
Chris@0: // Remember what we're overwriting
Chris@0: dataPriv.set( elem, "display", display );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Set the display of the elements in a second loop to avoid constant reflow
Chris@0: for ( index = 0; index < length; index++ ) {
Chris@0: if ( values[ index ] != null ) {
Chris@0: elements[ index ].style.display = values[ index ];
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return elements;
Chris@0: }
Chris@0:
Chris@0: jQuery.fn.extend( {
Chris@0: show: function() {
Chris@0: return showHide( this, true );
Chris@0: },
Chris@0: hide: function() {
Chris@0: return showHide( this );
Chris@0: },
Chris@0: toggle: function( state ) {
Chris@0: if ( typeof state === "boolean" ) {
Chris@0: return state ? this.show() : this.hide();
Chris@0: }
Chris@0:
Chris@0: return this.each( function() {
Chris@0: if ( isHiddenWithinTree( this ) ) {
Chris@0: jQuery( this ).show();
Chris@0: } else {
Chris@0: jQuery( this ).hide();
Chris@0: }
Chris@0: } );
Chris@0: }
Chris@0: } );
Chris@0: var rcheckableType = ( /^(?:checkbox|radio)$/i );
Chris@0:
Chris@0: var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
Chris@0:
Chris@0: var rscriptType = ( /^$|\/(?:java|ecma)script/i );
Chris@0:
Chris@0:
Chris@0:
Chris@0: // We have to close these tags to support XHTML (#13200)
Chris@0: var wrapMap = {
Chris@0:
Chris@0: // Support: IE <=9 only
Chris@0: option: [ 1, "" ],
Chris@0:
Chris@0: // XHTML parsers do not magically insert elements in the
Chris@0: // same way that tag soup parsers do. So we cannot shorten
Chris@0: // this by omitting or other required elements.
Chris@0: thead: [ 1, "" ],
Chris@0: col: [ 2, "" ],
Chris@0: tr: [ 2, "" ],
Chris@0: td: [ 3, "" ],
Chris@0:
Chris@0: _default: [ 0, "", "" ]
Chris@0: };
Chris@0:
Chris@0: // Support: IE <=9 only
Chris@0: wrapMap.optgroup = wrapMap.option;
Chris@0:
Chris@0: wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
Chris@0: wrapMap.th = wrapMap.td;
Chris@0:
Chris@0:
Chris@0: function getAll( context, tag ) {
Chris@0:
Chris@0: // Support: IE <=9 - 11 only
Chris@0: // Use typeof to avoid zero-argument method invocation on host objects (#15151)
Chris@0: var ret;
Chris@0:
Chris@0: if ( typeof context.getElementsByTagName !== "undefined" ) {
Chris@0: ret = context.getElementsByTagName( tag || "*" );
Chris@0:
Chris@0: } else if ( typeof context.querySelectorAll !== "undefined" ) {
Chris@0: ret = context.querySelectorAll( tag || "*" );
Chris@0:
Chris@0: } else {
Chris@0: ret = [];
Chris@0: }
Chris@0:
Chris@0: if ( tag === undefined || tag && nodeName( context, tag ) ) {
Chris@0: return jQuery.merge( [ context ], ret );
Chris@0: }
Chris@0:
Chris@0: return ret;
Chris@0: }
Chris@0:
Chris@0:
Chris@0: // Mark scripts as having already been evaluated
Chris@0: function setGlobalEval( elems, refElements ) {
Chris@0: var i = 0,
Chris@0: l = elems.length;
Chris@0:
Chris@0: for ( ; i < l; i++ ) {
Chris@0: dataPriv.set(
Chris@0: elems[ i ],
Chris@0: "globalEval",
Chris@0: !refElements || dataPriv.get( refElements[ i ], "globalEval" )
Chris@0: );
Chris@0: }
Chris@0: }
Chris@0:
Chris@0:
Chris@0: var rhtml = /<|?\w+;/;
Chris@0:
Chris@0: function buildFragment( elems, context, scripts, selection, ignored ) {
Chris@0: var elem, tmp, tag, wrap, contains, j,
Chris@0: fragment = context.createDocumentFragment(),
Chris@0: nodes = [],
Chris@0: i = 0,
Chris@0: l = elems.length;
Chris@0:
Chris@0: for ( ; i < l; i++ ) {
Chris@0: elem = elems[ i ];
Chris@0:
Chris@0: if ( elem || elem === 0 ) {
Chris@0:
Chris@0: // Add nodes directly
Chris@0: if ( jQuery.type( elem ) === "object" ) {
Chris@0:
Chris@0: // Support: Android <=4.0 only, PhantomJS 1 only
Chris@0: // push.apply(_, arraylike) throws on ancient WebKit
Chris@0: jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
Chris@0:
Chris@0: // Convert non-html into a text node
Chris@0: } else if ( !rhtml.test( elem ) ) {
Chris@0: nodes.push( context.createTextNode( elem ) );
Chris@0:
Chris@0: // Convert html into DOM nodes
Chris@0: } else {
Chris@0: tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
Chris@0:
Chris@0: // Deserialize a standard representation
Chris@0: tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
Chris@0: wrap = wrapMap[ tag ] || wrapMap._default;
Chris@0: tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
Chris@0:
Chris@0: // Descend through wrappers to the right content
Chris@0: j = wrap[ 0 ];
Chris@0: while ( j-- ) {
Chris@0: tmp = tmp.lastChild;
Chris@0: }
Chris@0:
Chris@0: // Support: Android <=4.0 only, PhantomJS 1 only
Chris@0: // push.apply(_, arraylike) throws on ancient WebKit
Chris@0: jQuery.merge( nodes, tmp.childNodes );
Chris@0:
Chris@0: // Remember the top-level container
Chris@0: tmp = fragment.firstChild;
Chris@0:
Chris@0: // Ensure the created nodes are orphaned (#12392)
Chris@0: tmp.textContent = "";
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Remove wrapper from fragment
Chris@0: fragment.textContent = "";
Chris@0:
Chris@0: i = 0;
Chris@0: while ( ( elem = nodes[ i++ ] ) ) {
Chris@0:
Chris@0: // Skip elements already in the context collection (trac-4087)
Chris@0: if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
Chris@0: if ( ignored ) {
Chris@0: ignored.push( elem );
Chris@0: }
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: contains = jQuery.contains( elem.ownerDocument, elem );
Chris@0:
Chris@0: // Append to fragment
Chris@0: tmp = getAll( fragment.appendChild( elem ), "script" );
Chris@0:
Chris@0: // Preserve script evaluation history
Chris@0: if ( contains ) {
Chris@0: setGlobalEval( tmp );
Chris@0: }
Chris@0:
Chris@0: // Capture executables
Chris@0: if ( scripts ) {
Chris@0: j = 0;
Chris@0: while ( ( elem = tmp[ j++ ] ) ) {
Chris@0: if ( rscriptType.test( elem.type || "" ) ) {
Chris@0: scripts.push( elem );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: return fragment;
Chris@0: }
Chris@0:
Chris@0:
Chris@0: ( function() {
Chris@0: var fragment = document.createDocumentFragment(),
Chris@0: div = fragment.appendChild( document.createElement( "div" ) ),
Chris@0: input = document.createElement( "input" );
Chris@0:
Chris@0: // Support: Android 4.0 - 4.3 only
Chris@0: // Check state lost if the name is set (#11217)
Chris@0: // Support: Windows Web Apps (WWA)
Chris@0: // `name` and `type` must use .setAttribute for WWA (#14901)
Chris@0: input.setAttribute( "type", "radio" );
Chris@0: input.setAttribute( "checked", "checked" );
Chris@0: input.setAttribute( "name", "t" );
Chris@0:
Chris@0: div.appendChild( input );
Chris@0:
Chris@0: // Support: Android <=4.1 only
Chris@0: // Older WebKit doesn't clone checked state correctly in fragments
Chris@0: support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
Chris@0:
Chris@0: // Support: IE <=11 only
Chris@0: // Make sure textarea (and checkbox) defaultValue is properly cloned
Chris@0: div.innerHTML = "";
Chris@0: support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
Chris@0: } )();
Chris@0: var documentElement = document.documentElement;
Chris@0:
Chris@0:
Chris@0:
Chris@0: var
Chris@0: rkeyEvent = /^key/,
Chris@0: rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
Chris@0: rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
Chris@0:
Chris@0: function returnTrue() {
Chris@0: return true;
Chris@0: }
Chris@0:
Chris@0: function returnFalse() {
Chris@0: return false;
Chris@0: }
Chris@0:
Chris@0: // Support: IE <=9 only
Chris@0: // See #13393 for more info
Chris@0: function safeActiveElement() {
Chris@0: try {
Chris@0: return document.activeElement;
Chris@0: } catch ( err ) { }
Chris@0: }
Chris@0:
Chris@0: function on( elem, types, selector, data, fn, one ) {
Chris@0: var origFn, type;
Chris@0:
Chris@0: // Types can be a map of types/handlers
Chris@0: if ( typeof types === "object" ) {
Chris@0:
Chris@0: // ( types-Object, selector, data )
Chris@0: if ( typeof selector !== "string" ) {
Chris@0:
Chris@0: // ( types-Object, data )
Chris@0: data = data || selector;
Chris@0: selector = undefined;
Chris@0: }
Chris@0: for ( type in types ) {
Chris@0: on( elem, type, selector, data, types[ type ], one );
Chris@0: }
Chris@0: return elem;
Chris@0: }
Chris@0:
Chris@0: if ( data == null && fn == null ) {
Chris@0:
Chris@0: // ( types, fn )
Chris@0: fn = selector;
Chris@0: data = selector = undefined;
Chris@0: } else if ( fn == null ) {
Chris@0: if ( typeof selector === "string" ) {
Chris@0:
Chris@0: // ( types, selector, fn )
Chris@0: fn = data;
Chris@0: data = undefined;
Chris@0: } else {
Chris@0:
Chris@0: // ( types, data, fn )
Chris@0: fn = data;
Chris@0: data = selector;
Chris@0: selector = undefined;
Chris@0: }
Chris@0: }
Chris@0: if ( fn === false ) {
Chris@0: fn = returnFalse;
Chris@0: } else if ( !fn ) {
Chris@0: return elem;
Chris@0: }
Chris@0:
Chris@0: if ( one === 1 ) {
Chris@0: origFn = fn;
Chris@0: fn = function( event ) {
Chris@0:
Chris@0: // Can use an empty set, since event contains the info
Chris@0: jQuery().off( event );
Chris@0: return origFn.apply( this, arguments );
Chris@0: };
Chris@0:
Chris@0: // Use same guid so caller can remove using origFn
Chris@0: fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
Chris@0: }
Chris@0: return elem.each( function() {
Chris@0: jQuery.event.add( this, types, fn, data, selector );
Chris@0: } );
Chris@0: }
Chris@0:
Chris@0: /*
Chris@0: * Helper functions for managing events -- not part of the public interface.
Chris@0: * Props to Dean Edwards' addEvent library for many of the ideas.
Chris@0: */
Chris@0: jQuery.event = {
Chris@0:
Chris@0: global: {},
Chris@0:
Chris@0: add: function( elem, types, handler, data, selector ) {
Chris@0:
Chris@0: var handleObjIn, eventHandle, tmp,
Chris@0: events, t, handleObj,
Chris@0: special, handlers, type, namespaces, origType,
Chris@0: elemData = dataPriv.get( elem );
Chris@0:
Chris@0: // Don't attach events to noData or text/comment nodes (but allow plain objects)
Chris@0: if ( !elemData ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // Caller can pass in an object of custom data in lieu of the handler
Chris@0: if ( handler.handler ) {
Chris@0: handleObjIn = handler;
Chris@0: handler = handleObjIn.handler;
Chris@0: selector = handleObjIn.selector;
Chris@0: }
Chris@0:
Chris@0: // Ensure that invalid selectors throw exceptions at attach time
Chris@0: // Evaluate against documentElement in case elem is a non-element node (e.g., document)
Chris@0: if ( selector ) {
Chris@0: jQuery.find.matchesSelector( documentElement, selector );
Chris@0: }
Chris@0:
Chris@0: // Make sure that the handler has a unique ID, used to find/remove it later
Chris@0: if ( !handler.guid ) {
Chris@0: handler.guid = jQuery.guid++;
Chris@0: }
Chris@0:
Chris@0: // Init the element's event structure and main handler, if this is the first
Chris@0: if ( !( events = elemData.events ) ) {
Chris@0: events = elemData.events = {};
Chris@0: }
Chris@0: if ( !( eventHandle = elemData.handle ) ) {
Chris@0: eventHandle = elemData.handle = function( e ) {
Chris@0:
Chris@0: // Discard the second event of a jQuery.event.trigger() and
Chris@0: // when an event is called after a page has unloaded
Chris@0: return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
Chris@0: jQuery.event.dispatch.apply( elem, arguments ) : undefined;
Chris@0: };
Chris@0: }
Chris@0:
Chris@0: // Handle multiple events separated by a space
Chris@0: types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
Chris@0: t = types.length;
Chris@0: while ( t-- ) {
Chris@0: tmp = rtypenamespace.exec( types[ t ] ) || [];
Chris@0: type = origType = tmp[ 1 ];
Chris@0: namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
Chris@0:
Chris@0: // There *must* be a type, no attaching namespace-only handlers
Chris@0: if ( !type ) {
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: // If event changes its type, use the special event handlers for the changed type
Chris@0: special = jQuery.event.special[ type ] || {};
Chris@0:
Chris@0: // If selector defined, determine special event api type, otherwise given type
Chris@0: type = ( selector ? special.delegateType : special.bindType ) || type;
Chris@0:
Chris@0: // Update special based on newly reset type
Chris@0: special = jQuery.event.special[ type ] || {};
Chris@0:
Chris@0: // handleObj is passed to all event handlers
Chris@0: handleObj = jQuery.extend( {
Chris@0: type: type,
Chris@0: origType: origType,
Chris@0: data: data,
Chris@0: handler: handler,
Chris@0: guid: handler.guid,
Chris@0: selector: selector,
Chris@0: needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
Chris@0: namespace: namespaces.join( "." )
Chris@0: }, handleObjIn );
Chris@0:
Chris@0: // Init the event handler queue if we're the first
Chris@0: if ( !( handlers = events[ type ] ) ) {
Chris@0: handlers = events[ type ] = [];
Chris@0: handlers.delegateCount = 0;
Chris@0:
Chris@0: // Only use addEventListener if the special events handler returns false
Chris@0: if ( !special.setup ||
Chris@0: special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
Chris@0:
Chris@0: if ( elem.addEventListener ) {
Chris@0: elem.addEventListener( type, eventHandle );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: if ( special.add ) {
Chris@0: special.add.call( elem, handleObj );
Chris@0:
Chris@0: if ( !handleObj.handler.guid ) {
Chris@0: handleObj.handler.guid = handler.guid;
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Add to the element's handler list, delegates in front
Chris@0: if ( selector ) {
Chris@0: handlers.splice( handlers.delegateCount++, 0, handleObj );
Chris@0: } else {
Chris@0: handlers.push( handleObj );
Chris@0: }
Chris@0:
Chris@0: // Keep track of which events have ever been used, for event optimization
Chris@0: jQuery.event.global[ type ] = true;
Chris@0: }
Chris@0:
Chris@0: },
Chris@0:
Chris@0: // Detach an event or set of events from an element
Chris@0: remove: function( elem, types, handler, selector, mappedTypes ) {
Chris@0:
Chris@0: var j, origCount, tmp,
Chris@0: events, t, handleObj,
Chris@0: special, handlers, type, namespaces, origType,
Chris@0: elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
Chris@0:
Chris@0: if ( !elemData || !( events = elemData.events ) ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // Once for each type.namespace in types; type may be omitted
Chris@0: types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
Chris@0: t = types.length;
Chris@0: while ( t-- ) {
Chris@0: tmp = rtypenamespace.exec( types[ t ] ) || [];
Chris@0: type = origType = tmp[ 1 ];
Chris@0: namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
Chris@0:
Chris@0: // Unbind all events (on this namespace, if provided) for the element
Chris@0: if ( !type ) {
Chris@0: for ( type in events ) {
Chris@0: jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
Chris@0: }
Chris@0: continue;
Chris@0: }
Chris@0:
Chris@0: special = jQuery.event.special[ type ] || {};
Chris@0: type = ( selector ? special.delegateType : special.bindType ) || type;
Chris@0: handlers = events[ type ] || [];
Chris@0: tmp = tmp[ 2 ] &&
Chris@0: new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
Chris@0:
Chris@0: // Remove matching events
Chris@0: origCount = j = handlers.length;
Chris@0: while ( j-- ) {
Chris@0: handleObj = handlers[ j ];
Chris@0:
Chris@0: if ( ( mappedTypes || origType === handleObj.origType ) &&
Chris@0: ( !handler || handler.guid === handleObj.guid ) &&
Chris@0: ( !tmp || tmp.test( handleObj.namespace ) ) &&
Chris@0: ( !selector || selector === handleObj.selector ||
Chris@0: selector === "**" && handleObj.selector ) ) {
Chris@0: handlers.splice( j, 1 );
Chris@0:
Chris@0: if ( handleObj.selector ) {
Chris@0: handlers.delegateCount--;
Chris@0: }
Chris@0: if ( special.remove ) {
Chris@0: special.remove.call( elem, handleObj );
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Remove generic event handler if we removed something and no more handlers exist
Chris@0: // (avoids potential for endless recursion during removal of special event handlers)
Chris@0: if ( origCount && !handlers.length ) {
Chris@0: if ( !special.teardown ||
Chris@0: special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
Chris@0:
Chris@0: jQuery.removeEvent( elem, type, elemData.handle );
Chris@0: }
Chris@0:
Chris@0: delete events[ type ];
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Remove data and the expando if it's no longer used
Chris@0: if ( jQuery.isEmptyObject( events ) ) {
Chris@0: dataPriv.remove( elem, "handle events" );
Chris@0: }
Chris@0: },
Chris@0:
Chris@0: dispatch: function( nativeEvent ) {
Chris@0:
Chris@0: // Make a writable jQuery.Event from the native event object
Chris@0: var event = jQuery.event.fix( nativeEvent );
Chris@0:
Chris@0: var i, j, ret, matched, handleObj, handlerQueue,
Chris@0: args = new Array( arguments.length ),
Chris@0: handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
Chris@0: special = jQuery.event.special[ event.type ] || {};
Chris@0:
Chris@0: // Use the fix-ed jQuery.Event rather than the (read-only) native event
Chris@0: args[ 0 ] = event;
Chris@0:
Chris@0: for ( i = 1; i < arguments.length; i++ ) {
Chris@0: args[ i ] = arguments[ i ];
Chris@0: }
Chris@0:
Chris@0: event.delegateTarget = this;
Chris@0:
Chris@0: // Call the preDispatch hook for the mapped type, and let it bail if desired
Chris@0: if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
Chris@0: return;
Chris@0: }
Chris@0:
Chris@0: // Determine handlers
Chris@0: handlerQueue = jQuery.event.handlers.call( this, event, handlers );
Chris@0:
Chris@0: // Run delegates first; they may want to stop propagation beneath us
Chris@0: i = 0;
Chris@0: while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
Chris@0: event.currentTarget = matched.elem;
Chris@0:
Chris@0: j = 0;
Chris@0: while ( ( handleObj = matched.handlers[ j++ ] ) &&
Chris@0: !event.isImmediatePropagationStopped() ) {
Chris@0:
Chris@0: // Triggered event must either 1) have no namespace, or 2) have namespace(s)
Chris@0: // a subset or equal to those in the bound event (both can have no namespace).
Chris@0: if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
Chris@0:
Chris@0: event.handleObj = handleObj;
Chris@0: event.data = handleObj.data;
Chris@0:
Chris@0: ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
Chris@0: handleObj.handler ).apply( matched.elem, args );
Chris@0:
Chris@0: if ( ret !== undefined ) {
Chris@0: if ( ( event.result = ret ) === false ) {
Chris@0: event.preventDefault();
Chris@0: event.stopPropagation();
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Call the postDispatch hook for the mapped type
Chris@0: if ( special.postDispatch ) {
Chris@0: special.postDispatch.call( this, event );
Chris@0: }
Chris@0:
Chris@0: return event.result;
Chris@0: },
Chris@0:
Chris@0: handlers: function( event, handlers ) {
Chris@0: var i, handleObj, sel, matchedHandlers, matchedSelectors,
Chris@0: handlerQueue = [],
Chris@0: delegateCount = handlers.delegateCount,
Chris@0: cur = event.target;
Chris@0:
Chris@0: // Find delegate handlers
Chris@0: if ( delegateCount &&
Chris@0:
Chris@0: // Support: IE <=9
Chris@0: // Black-hole SVG