01-core.js | |
---|---|
jQuery Annotated Source. You can view the source and contribute on Github. | |
| |
Chapter 1: Core | (function( window, undefined ) { |
Use the correct document accordingly with window argument (sandbox) | var document = window.document,
navigator = window.navigator,
location = window.location; |
Hello, jQuery | var jQuery = (function() { |
Define a local copy of jQuery. The jQuery object is actually just the init constructor 'enhanced' | var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
}, |
Map over jQuery in case of overwrite | _jQuery = window.jQuery, |
Map over the $ in case of overwrite | _$ = window.$, |
A central reference to the root jQuery(document) | rootjQuery, |
A simple way to check for HTML strings or ID strings (both of which we optimize for) | quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, |
Check if a string has a non-whitespace character in it | rnotwhite = /\S/, |
Used for trimming whitespace | trimLeft = /^\s+/,
trimRight = /\s+$/, |
Check for digits | rdigit = /\d/, |
Match a standalone tag | rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, |
JSON RegExp | rvalidchars = /^[\],:{}\s]*$/,
rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, |
Useragent RegExp | rwebkit = /(webkit)[ \/]([\w.]+)/,
ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
rmsie = /(msie) ([\w.]+)/,
rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, |
Matches dashed string for camelizing | rdashAlpha = /-([a-z])/ig, |
Used by jQuery.camelCase as callback to replace() | fcamelCase = function( all, letter ) {
return letter.toUpperCase();
}, |
Keep a UserAgent string for use with jQuery.browser | userAgent = navigator.userAgent, |
For matching the engine and version of the browser | browserMatch, |
The deferred used on DOM ready | readyList, |
The ready event handler | DOMContentLoaded, |
Save a reference to some core methods | toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
push = Array.prototype.push,
slice = Array.prototype.slice,
trim = String.prototype.trim,
indexOf = Array.prototype.indexOf, |
[[Class]] -> type pairs | class2type = {}; |
jQuery prototype | jQuery.fn = jQuery.prototype = {
constructor: jQuery,
|
Main jQuery function | init: function( selector, context, rootjQuery ) {
var match, elem, ret, doc; |
Handle $(""), $(null), or $(undefined) | if ( !selector ) {
return this;
} |
Handle $(DOMElement) | if ( selector.nodeType ) {
this.context = this[0] = selector;
this.length = 1;
return this;
} |
The body element only exists once, optimize finding it | if ( selector === "body" && !context && document.body ) {
this.context = document;
this[0] = document.body;
this.selector = selector;
this.length = 1;
return this;
} |
Handle HTML strings | if ( typeof selector === "string" ) { |
Are we dealing with HTML string or an ID? | if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { |
Assume that strings that start and end with <> are HTML and skip the regex check | match = [ null, selector, null ];
} else {
match = quickExpr.exec( selector );
} |
Verify a match, and that no context was specified for #id | if ( match && (match[1] || !context) ) { |
HANDLE: $(html) -> $(array) | if ( match[1] ) {
context = context instanceof jQuery ? context[0] : context;
doc = (context ? context.ownerDocument || context : document); |
If a single string is passed in and it's a single tag just do a createElement and skip the rest | ret = rsingleTag.exec( selector );
if ( ret ) {
if ( jQuery.isPlainObject( context ) ) {
selector = [ document.createElement( ret[1] ) ];
jQuery.fn.attr.call( selector, context, true );
} else {
selector = [ doc.createElement( ret[1] ) ];
}
} else {
ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
}
return jQuery.merge( this, selector ); |
HANDLE: $("#id") | } else {
elem = document.getElementById( match[2] ); |
Check parentNode to catch when Blackberry 4.6 returns nodes that are no longer in the document #6963 | if ( elem && elem.parentNode ) { |
Handle the case where IE and Opera return items by name instead of ID | if ( elem.id !== match[2] ) {
return rootjQuery.find( selector );
} |
Otherwise, we inject the element directly into the jQuery object | this.length = 1;
this[0] = elem;
}
this.context = document;
this.selector = selector;
return this;
} |
HANDLE: $(expr, $(...)) | } else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector ); |
HANDLE: $(expr, context) (which is just equivalent to: $(context).find(expr) | } else {
return this.constructor( context ).find( selector );
} |
HANDLE: $(function) Shortcut for document ready | } else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
if (selector.selector !== undefined) {
this.selector = selector.selector;
this.context = selector.context;
}
return jQuery.makeArray( selector, this );
}, |
Start with an empty selector | selector: "", |
The current version of jQuery being used | jquery: "1.6.2", |
The default length of a jQuery object is 0 | length: 0, |
The number of elements contained in the matched element set | size: function() {
return this.length;
},
|
Retrieve all the DOM elements contained in the jQuery set, as an array | toArray: function() {
return slice.call( this, 0 );
}, |
Get the Nth element in the matched element set OR Get the whole matched element set as a clean array | get: function( num ) {
return num == null ? |
Return a 'clean' array | this.toArray() : |
Return just the object | ( num < 0 ? this[ this.length + num ] : this[ num ] );
}, |
Take an array of elements and push it onto the stack (returning the new matched element set) | pushStack: function( elems, name, selector ) { |
Build a new jQuery matched element set | var ret = this.constructor();
if ( jQuery.isArray( elems ) ) {
push.apply( ret, elems );
} else {
jQuery.merge( ret, elems );
} |
Add the old object onto the stack (as a reference) | ret.prevObject = this;
ret.context = this.context;
if ( name === "find" ) {
ret.selector = this.selector + (this.selector ? " " : "") + selector;
} else if ( name ) {
ret.selector = this.selector + "." + name + "(" + selector + ")";
} |
Return the newly-formed element set | return ret;
}, |
Execute a callback for every element in the matched set. (You can seed the arguments with an array of args, but this is only used internally.) | each: function( callback, args ) {
return jQuery.each( this, callback, args );
},
|
Specify a function to execute when the DOM is fully loaded. | ready: function( fn ) { |
Attach the listeners | jQuery.bindReady(); |
Add the callback | readyList.done( fn );
return this;
},
|
Reduce the set of matched elements to the one at the specified index | eq: function( i ) {
return i === -1 ?
this.slice( i ) :
this.slice( i, +i + 1 );
},
|
Reduce the set of matched elements to the first in the set | first: function() {
return this.eq( 0 );
},
|
Reduce the set of matched elements to the final one in the set | last: function() {
return this.eq( -1 );
},
|
Reduce the set of matched elements to a subset specified by a range of indices | slice: function() {
return this.pushStack( slice.apply( this, arguments ),
"slice", slice.call(arguments).join(",") );
},
|
Pass each element in the current matched set through a function, producing a new jQuery object containing the return values | map: function( callback ) {
return this.pushStack( jQuery.map(this, function( elem, i ) {
return callback.call( elem, i, elem );
}));
},
|
End the most recent filtering operation in the current chain and return the set of matched elements to its previous state | end: function() {
return this.prevObject || this.constructor(null);
}, |
For internal use only. Behaves like an Array's method, not like a jQuery method. | push: push,
sort: [].sort,
splice: [].splice
}; |
Give the init function the jQuery prototype for later instantiation | jQuery.fn.init.prototype = jQuery.fn; |
Utilities | |
Merge the contents of two or more objects together into the first object | jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false; |
Handle a deep copy situation | if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {}; |
skip the boolean and the target | i = 2;
} |
Handle case when target is a string or something (possible in deep copy) | if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
} |
extend jQuery itself if only one argument is passed | if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) { |
Only deal with non-null/undefined values | if ( (options = arguments[ i ]) != null ) { |
Extend the base object | for ( name in options ) {
src = target[ name ];
copy = options[ name ]; |
Prevent never-ending loop | if ( target === copy ) {
continue;
} |
Recurse if we're merging plain objects or arrays | if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
} |
Never move original objects, clone them | target[ name ] = jQuery.extend( deep, clone, copy ); |
Don't bring in undefined values | } else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
} |
Return the modified object | return target;
};
jQuery.extend({ |
Relinquish jQuery's control of the $ variable | noConflict: function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
},
|
Is the DOM ready to be used? Set to true once it occurs. | isReady: false, |
A counter to track how many items to wait for before the ready event fires. See #6781 | readyWait: 1, |
Hold (or release) the ready event | holdReady: function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
}, |
Handle when the DOM is ready | ready: function( wait ) { |
Either a released hold or an DOMready/load event and not yet ready | if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { |
Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). | if ( !document.body ) {
return setTimeout( jQuery.ready, 1 );
} |
Remember that the DOM is ready | jQuery.isReady = true; |
If a normal DOM Ready event fired, decrement, and wait if need be | if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
} |
If there are functions bound, to execute | readyList.resolveWith( document, [ jQuery ] ); |
Trigger any bound ready events | if ( jQuery.fn.trigger ) {
jQuery( document ).trigger( "ready" ).unbind( "ready" );
}
}
},
bindReady: function() {
if ( readyList ) {
return;
}
readyList = jQuery._Deferred(); |
Catch cases where $(document).ready() is called after the browser event has already occurred. | if ( document.readyState === "complete" ) { |
Handle it asynchronously to allow scripts the opportunity to delay ready | return setTimeout( jQuery.ready, 1 );
} |
Mozilla, Opera and webkit nightlies currently support this event | if ( document.addEventListener ) { |
Use the handy event callback | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); |
A fallback to window.onload, that will always work | window.addEventListener( "load", jQuery.ready, false ); |
If IE event model is used | } else if ( document.attachEvent ) { |
ensure firing before onload, maybe late but safe also for iframes | document.attachEvent( "onreadystatechange", DOMContentLoaded ); |
A fallback to window.onload, that will always work | window.attachEvent( "onload", jQuery.ready ); |
If IE and not a frame continually check to see if the document is ready | var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
}, |
See test/unit/core.js for details concerning isFunction. Since version 1.3, DOM methods and functions like alert aren't supported. They return false on IE (#2968). | isFunction: function( obj ) {
return jQuery.type(obj) === "function";
},
|
Determine whether the argument is an array | isArray: Array.isArray || function( obj ) {
return jQuery.type(obj) === "array";
}, |
A crude way of determining if an object is a window | isWindow: function( obj ) {
return obj && typeof obj === "object" && "setInterval" in obj;
},
isNaN: function( obj ) {
return obj == null || !rdigit.test( obj ) || isNaN( obj );
},
|
Determine the internal JavaScript [[Class]] of an object | type: function( obj ) {
return obj == null ?
String( obj ) :
class2type[ toString.call(obj) ] || "object";
}, |
Check to see if an object is a plain object (created using "{}" or "new Object") | isPlainObject: function( obj ) { |
Must be an Object. Because of IE, we also have to check the presence of the constructor property. Make sure that DOM nodes and window objects don't pass through, as well | if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
return false;
} |
Not own constructor property must be Object | if ( obj.constructor &&
!hasOwn.call(obj, "constructor") &&
!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
return false;
} |
Own properties are enumerated firstly, so to speed up, if last one is own, then all properties are own. | var key;
for ( key in obj ) {}
return key === undefined || hasOwn.call( obj, key );
}, |
Check to see if an object is empty (contains no properties). | isEmptyObject: function( obj ) {
for ( var name in obj ) {
return false;
}
return true;
},
error: function( msg ) {
throw msg;
},
|
Takes a well-formed JSON string and returns the resulting JavaScript object. | parseJSON: function( data ) {
if ( typeof data !== "string" || !data ) {
return null;
} |
Make sure leading/trailing whitespace is removed (IE can't handle it) | data = jQuery.trim( data ); |
Attempt to parse using the native JSON parser first | if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
} |
Make sure the incoming data is actual JSON Logic borrowed from http://json.org/json2.js | if ( rvalidchars.test( data.replace( rvalidescape, "@" )
.replace( rvalidtokens, "]" )
.replace( rvalidbraces, "")) ) {
return (new Function( "return " + data ))();
}
jQuery.error( "Invalid JSON: " + data );
}, |
Cross-browser xml parsing (xml & tmp used internally) | parseXML: function( data , xml , tmp ) {
if ( window.DOMParser ) { // Standard
tmp = new DOMParser();
xml = tmp.parseFromString( data , "text/xml" );
} else { // IE
xml = new ActiveXObject( "Microsoft.XMLDOM" );
xml.async = "false";
xml.loadXML( data );
}
tmp = xml.documentElement;
if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
}, |
An empty function | noop: function() {}, |
Evaluates a script in a global context Workarounds based on findings by Jim Driscoll http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context | globalEval: function( data ) {
if ( data && rnotwhite.test( data ) ) { |
We use execScript on Internet Explorer We use an anonymous function so that context is window rather than jQuery in Firefox | ( window.execScript || function( data ) {
window[ "eval" ].call( window, data );
} )( data );
}
}, |
Converts a dashed string to camelCased string; Used by both the css and data modules | camelCase: function( string ) {
return string.replace( rdashAlpha, fcamelCase );
}, |
Returns the uppercase node name | nodeName: function( elem, name ) {
return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}, |
args is for internal usage only | each: function( object, callback, args ) {
var name, i = 0,
length = object.length,
isObj = length === undefined || jQuery.isFunction( object );
if ( args ) {
if ( isObj ) {
for ( name in object ) {
if ( callback.apply( object[ name ], args ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.apply( object[ i++ ], args ) === false ) {
break;
}
}
} |
A special, fast, case for the most common use of each | } else {
if ( isObj ) {
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
} else {
for ( ; i < length; ) {
if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
break;
}
}
}
}
return object;
}, |
Use native String.trim function wherever possible | trim: trim ?
function( text ) {
return text == null ?
"" :
trim.call( text );
} : |
Otherwise use our own trimming functionality | function( text ) {
return text == null ?
"" :
text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
}, |
results is for internal usage only | makeArray: function( array, results ) {
var ret = results || [];
if ( array != null ) { |
The window, strings (and functions) also have 'length' The extra typeof function check is to prevent crashes in Safari 2 (See: #3039) Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 | var type = jQuery.type( array );
if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
push.call( ret, array );
} else {
jQuery.merge( ret, array );
}
}
return ret;
}, |
Search for a specified value within an array and return its index (or -1 if not found). | inArray: function( elem, array ) {
if ( indexOf ) {
return indexOf.call( array, elem );
}
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
},
|
Merge the contents of two arrays together into the first array. | merge: function( first, second ) {
var i = first.length,
j = 0;
if ( typeof second.length === "number" ) {
for ( var l = second.length; j < l; j++ ) {
first[ i++ ] = second[ j ];
}
} else {
while ( second[j] !== undefined ) {
first[ i++ ] = second[ j++ ];
}
}
first.length = i;
return first;
}, |
Finds the elements of an array which satisfy a filter function. The original array is not affected | grep: function( elems, callback, inv ) {
var ret = [], retVal;
inv = !!inv; |
Go through the array, only saving the items that pass the validator function | for ( var i = 0, length = elems.length; i < length; i++ ) {
retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
}, |
Translate all items in an array or object to new array of items. | map: function( elems, callback, arg ) {
var value, key, ret = [],
i = 0,
length = elems.length, |
jquery objects are treated as arrays | isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; |
Go through the array, translating each of the items to their | if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
} |
Go through every key on the object, | } else {
for ( key in elems ) {
value = callback( elems[ key ], key, arg );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
} |
Flatten any nested arrays | return ret.concat.apply( [], ret );
}, |
A global GUID counter for objects | guid: 1, |
Bind a function to a context, optionally partially applying any arguments. | proxy: function( fn, context ) {
if ( typeof context === "string" ) {
var tmp = fn[ context ];
context = fn;
fn = tmp;
} |
Quick check to determine if target is callable, in the spec this throws a TypeError, but we will just return undefined. | if ( !jQuery.isFunction( fn ) ) {
return undefined;
} |
Simulated bind | var args = slice.call( arguments, 2 ),
proxy = function() {
return fn.apply( context, args.concat( slice.call( arguments ) ) );
}; |
Set the guid of unique handler to the same of original handler, so it can be removed | proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
return proxy;
}, |
Mutifunctional method to get and set values to a collection The value/s can optionally be executed if it's a function | access: function( elems, key, value, exec, fn, pass ) {
var length = elems.length; |
Setting many attributes | if ( typeof key === "object" ) {
for ( var k in key ) {
jQuery.access( elems, k, key[k], exec, fn, value );
}
return elems;
} |
Setting one attribute | if ( value !== undefined ) { |
Optionally, function values get executed if exec is true | exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
}
return elems;
} |
Getting an attribute | return length ? fn( elems[0], key ) : undefined;
},
|
Return a number representing the current time | now: function() {
return (new Date()).getTime();
}, |
Use of jQuery.browser is frowned upon. More details: http://docs.jquery.com/Utilities/jQuery.browser | uaMatch: function( ua ) {
ua = ua.toLowerCase();
var match = rwebkit.exec( ua ) ||
ropera.exec( ua ) ||
rmsie.exec( ua ) ||
ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
[];
return { browser: match[1] || "", version: match[2] || "0" };
}, |
Creates a new copy of jQuery whose properties and methods can be modified without affecting the original jQuery object. | sub: function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, this );
jQuerySub.superclass = this;
jQuerySub.fn = jQuerySub.prototype = this();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
return jQuerySub;
},
browser: {}
}); |
Populate the class2type map | jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
}); |
Pass user agent to internal | browserMatch = jQuery.uaMatch( userAgent ); |
Set properties for jQuery.browser | if ( browserMatch.browser ) {
jQuery.browser[ browserMatch.browser ] = true;
jQuery.browser.version = browserMatch.version;
} |
Deprecated, use jQuery.browser.webkit instead | if ( jQuery.browser.webkit ) {
jQuery.browser.safari = true;
} |
IE doesn't match non-breaking spaces with \s | if ( rnotwhite.test( "\xA0" ) ) {
trimLeft = /^[\s\xA0]+/;
trimRight = /[\s\xA0]+$/;
} |
All jQuery objects should point back to these | rootjQuery = jQuery(document); |
Cleanup functions for the document ready method | if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() { |
Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). | if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
};
} |
The DOM ready check for Internet Explorer | function doScrollCheck() {
if ( jQuery.isReady ) {
return;
} |
If IE is used, use the trick by Diego Perini http://javascript.nwbox.com/IEContentLoaded/ | try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
} |
and execute any waiting functions | jQuery.ready();
}
return jQuery;
})();
|