jquery/src/core.js

488 lines
12 KiB
JavaScript
Raw Normal View History

// Will speed up references to window, and allows munging its name.
var window = this,
// Will speed up references to undefined, and allows munging its name.
undefined,
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$,
// Define a local copy of jQuery
jQuery,
// A central reference to the root jQuery(document)
rootjQuery,
jQuery = window.jQuery = window.$ = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return arguments.length === 0 ?
rootjQuery :
new jQuery.fn.init( selector, context );
},
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
// Is it a simple selector
isSimple = /^.[^:#\[\.,]*$/,
// Keep a UserAgent string for use with jQuery.browser
userAgent = navigator.userAgent.toLowerCase(),
// Save a reference to the core toString method
toString = Object.prototype.toString;
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
var match, elem, ret;
// Handle $(""), $(null), or $(undefined)
if ( !selector ) {
this.length = 0;
return this;
}
// Handle $(DOMElement)
if ( selector.nodeType ) {
this[0] = selector;
this.length = 1;
this.context = selector;
return this;
}
// Handle HTML strings
if ( typeof selector === "string" ) {
// Are we dealing with HTML string or an ID?
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] ) {
selector = jQuery.clean( [ match[1] ], context );
// HANDLE: $("#id")
} else {
elem = document.getElementById( match[3] );
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem && elem.id !== match[3] ) {
return rootjQuery.find( selector );
}
// Otherwise, we inject the element directly into the jQuery object
ret = jQuery( elem || null );
ret.context = document;
ret.selector = selector;
return ret;
}
// 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 jQuery( context ).find( selector );
}
// HANDLE: $(function)
// Shortcut for document ready
} else if ( jQuery.isFunction( selector ) ) {
return rootjQuery.ready( selector );
}
// Make sure that old selector state is passed along
if ( selector.selector && selector.context ) {
this.selector = selector.selector;
this.context = selector.context;
}
return this.setArray(jQuery.isArray( selector ) ?
selector :
jQuery.makeArray(selector));
},
// Start with an empty selector
selector: "",
// The current version of jQuery being used
jquery: "@VERSION",
// The number of elements contained in the matched element set
size: function() {
return this.length;
},
// 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
Array.prototype.slice.call( this ) :
// Return just the object
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 = jQuery( elems || null );
// 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;
},
// Force the current matched set of elements to become
// the specified array of elements (destroying the stack in the process)
// You should use pushStack() in order to do this, but maintain the stack
setArray: function( elems ) {
// Resetting the length to 0, then using the native Array push
// is a super-fast way to populate an object with array-like properties
this.length = 0;
Array.prototype.push.apply( this, elems );
return this;
},
// 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 );
},
// Determine the position of an element within
// the matched set of elements
index: function( elem ) {
if ( !elem || typeof elem === "string" ) {
return jQuery.inArray( this[0],
// If it receives a string, the selector is used
// If it receives nothing, the siblings are used
elem ? jQuery( elem ) : this.parent().children() );
}
// Locate the position of the desired element
return jQuery.inArray(
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[0] : elem, this );
},
is: function( selector ) {
return !!selector && jQuery.multiFilter( selector, this ).length > 0;
},
// 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;
jQuery.extend = jQuery.fn.extend = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
// 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 object values
if ( deep && copy && typeof copy === "object" && !copy.nodeType ) {
2009-03-23 02:55:17 +01:00
target[ name ] = jQuery.extend( deep,
// Never move original objects, clone them
src || ( copy.length != null ? [ ] : { } ), copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend({
noConflict: function( deep ) {
window.$ = _$;
if ( deep ) {
window.jQuery = _jQuery;
}
return jQuery;
},
// 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 toString.call(obj) === "[object Function]";
},
isArray: function( obj ) {
return toString.call(obj) === "[object Array]";
},
// check if an element is in a (or is an) XML document
isXMLDoc: function( elem ) {
return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
},
// Evalulates a script in a global context
globalEval: function( data ) {
if ( data && /\S/.test(data) ) {
// Inspired by code by Andrea Giammarchi
// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
var head = document.getElementsByTagName("head")[0] || document.documentElement,
script = document.createElement("script");
script.type = "text/javascript";
if ( jQuery.support.scriptEval ) {
script.appendChild( document.createTextNode( data ) );
} else {
script.text = data;
}
// Use insertBefore instead of appendChild to circumvent an IE6 bug.
// This arises when a base node is used (#2709).
head.insertBefore( script, head.firstChild );
head.removeChild( script );
}
},
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;
if ( args ) {
if ( length === undefined ) {
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 ( length === undefined ) {
for ( name in object ) {
if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
break;
}
}
} else {
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
}
}
return object;
},
trim: function( text ) {
return (text || "").replace( /^\s+|\s+$/g, "" );
},
makeArray: function( array ) {
var ret = [], i;
if ( array != null ) {
i = array.length;
// The window, strings (and functions) also have 'length'
if ( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval ) {
ret[0] = array;
} else {
while ( i ) {
ret[--i] = array[i];
}
}
}
return ret;
},
inArray: function( elem, array ) {
for ( var i = 0, length = array.length; i < length; i++ ) {
if ( array[ i ] === elem ) {
return i;
}
}
return -1;
},
merge: function( first, second ) {
// We have to loop this way because IE & Opera overwrite the length
// expando of getElementsByTagName
2008-05-13 04:20:08 +02:00
var i = 0, elem, pos = first.length;
// Also, we need to make sure that the correct elements are being returned
// (IE returns comment nodes in a '*' query)
if ( !jQuery.support.getAll ) {
while ( (elem = second[ i++ ]) != null ) {
if ( elem.nodeType !== 8 ) {
2008-05-13 04:20:08 +02:00
first[ pos++ ] = elem;
}
}
} else {
while ( (elem = second[ i++ ]) != null ) {
2008-05-13 04:20:08 +02:00
first[ pos++ ] = elem;
}
}
return first;
},
unique: function( array ) {
var ret = [], done = {}, id;
try {
for ( var i = 0, length = array.length; i < length; i++ ) {
id = jQuery.data( array[ i ] );
if ( !done[ id ] ) {
done[ id ] = true;
ret.push( array[ i ] );
}
}
} catch( e ) {
ret = array;
}
return ret;
},
grep: function( elems, callback, inv ) {
var ret = [];
// Go through the array, only saving the items
// that pass the validator function
for ( var i = 0, length = elems.length; i < length; i++ ) {
if ( !inv !== !callback( elems[ i ], i ) ) {
ret.push( elems[ i ] );
}
}
return ret;
},
map: function( elems, callback ) {
var ret = [], value;
// Go through the array, translating each of the items to their
// new value (or values).
for ( var i = 0, length = elems.length; i < length; i++ ) {
value = callback( elems[ i ], i );
if ( value != null ) {
ret[ ret.length ] = value;
}
}
return ret.concat.apply( [], ret );
},
// Use of jQuery.browser is deprecated.
// It's included for backwards compatibility and plugins,
// although they should work to migrate away.
browser: {
version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
safari: /webkit/.test( userAgent ),
opera: /opera/.test( userAgent ),
msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
}
});
// All jQuery objects should point back to these
rootjQuery = jQuery(document);
function evalScript( i, elem ) {
if ( elem.src ) {
jQuery.ajax({
url: elem.src,
async: false,
dataType: "script"
});
} else {
jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
function now() {
return (new Date).getTime();
}