X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fcore.js;h=a6d4c5f74b2a8ee97bbd51fb3ccf11d6278a1737;hb=58235cc38ea835cde0ae90dd2919b86e47f3dd05;hp=969f3d40b967f325c0f63d0cf4ea4e87b1cc0148;hpb=f38251b2ce84a0ab6302475786c3e721dba2177c;p=jquery.git diff --git a/src/core.js b/src/core.js index 969f3d4..56fd098 100644 --- a/src/core.js +++ b/src/core.js @@ -1,247 +1,349 @@ -/* - * jQuery @VERSION - New Wave Javascript - * - * Copyright (c) 2007 John Resig (jquery.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date$ - * $Rev$ - */ - -// Map over jQuery in case of overwrite -if ( typeof jQuery != "undefined" ) - var _jQuery = jQuery; - -var jQuery = window.jQuery = function(a,c) { - // If the context is global, return a new object - if ( window == this || !this.init ) - return new jQuery(a,c); - - return this.init(a,c); -}; - -// Map over the $ in case of overwrite -if ( typeof $ != "undefined" ) - var _$ = $; - -// Map the jQuery namespace to the '$' one -window.$ = jQuery; +var + // Will speed up references to window, and allows munging its name. + 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.$, + + jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return selector === undefined ? + rootjQuery : + new jQuery.fn.init( selector, context ); + }, -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + // 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 = /^.[^:#\[\.,]*$/; jQuery.fn = jQuery.prototype = { - init: function(a,c) { - // Make sure that a selection was provided - a = a || document; + init: function( selector, context ) { + // Handle $("") or $(null) + 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 a == "string" ) { - var m = quickExpr.exec(a); - if ( m && (m[1] || !c) ) { + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + var match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + // HANDLE: $(html) -> $(array) - if ( m[1] ) - a = jQuery.clean( [ m[1] ], c ); + if ( match[1] ) { + selector = jQuery.clean( [ match[1] ], context ); // HANDLE: $("#id") - else { - var tmp = document.getElementById( m[3] ); - if ( tmp ) - // Handle the case where IE and Opera return items - // by name instead of ID - if ( tmp.id != m[3] ) - return jQuery().find( a ); - else { - this[0] = tmp; - this.length = 1; - return this; - } - else - a = []; + } else { + var 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 + var ret = jQuery( elem || null ); + ret.context = document; + ret.selector = selector; + return ret; } - // HANDLE: $(expr) - } else - return new jQuery( c ).find( a ); + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(content).find(expr) + } else { + return jQuery( context ).find( selector ); + } // HANDLE: $(function) // Shortcut for document ready - } else if ( jQuery.isFunction(a) ) - return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a ); - - return this.setArray( - // HANDLE: $(array) - a.constructor == Array && a || + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } - // HANDLE: $(arraylike) - // Watch for when an array-like object is passed as the selector - (a.jquery || a.length && a != window && !a.nodeType && a[0] != undefined && a[0].nodeType) && jQuery.makeArray( a ) || + // Make sure that old selector state is passed along + if ( selector.selector && selector.context ) { + this.selector = selector.selector; + this.context = selector.context; + } - // HANDLE: $(*) - [ a ] ); + 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; }, - - length: 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 == undefined ? + return num === undefined ? // Return a 'clean' array - jQuery.makeArray( this ) : + Array.prototype.slice.call( this ) : // Return just the object - this[num]; + this[ num ]; }, - - pushStack: function( a ) { - var ret = jQuery(a); + + // 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; }, - - setArray: function( a ) { + + // 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, a ); + Array.prototype.push.apply( this, elems ); + return this; }, - each: function( fn, args ) { - return jQuery.each( this, fn, args ); + // 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 ); }, - index: function( obj ) { - var pos = -1; - this.each(function(i){ - if ( this == obj ) pos = i; - }); - return pos; + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); }, - attr: function( key, value, type ) { - var obj = key; - + attr: function( name, value, type ) { + var options = name; + // Look for the case where we're accessing a style value - if ( key.constructor == String ) - if ( value == undefined ) - return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined; + if ( typeof name === "string" ) + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); + else { - obj = {}; - obj[ key ] = value; + options = {}; + options[ name ] = value; } - + // Check to see if we're setting style values - return this.each(function(index){ + return this.each(function(i){ // Set all the styles - for ( var prop in obj ) + for ( name in options ) jQuery.attr( - type ? this.style : this, - prop, jQuery.prop(this, obj[prop], type, index, prop) + type ? + this.style : + this, + name, jQuery.prop( this, options[ name ], type, i, name ) ); }); }, css: function( key, value ) { + // ignore negative width and height values + if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) + value = undefined; return this.attr( key, value, "curCSS" ); }, - text: function(e) { - if ( typeof e != "object" && e != null ) - return this.empty().append( document.createTextNode( e ) ); + text: function( text ) { + if ( typeof text !== "object" && text != null ) + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); + + var ret = ""; - var t = ""; - jQuery.each( e || this, function(){ + jQuery.each( text || this, function(){ jQuery.each( this.childNodes, function(){ if ( this.nodeType != 8 ) - t += this.nodeType != 1 ? - this.nodeValue : jQuery.fn.text([ this ]); + ret += this.nodeType != 1 ? + this.nodeValue : + jQuery.fn.text( [ this ] ); }); }); - return t; + + return ret; }, - wrapAll: function(html) { - if ( this[0] ) + wrapAll: function( html ) { + if ( this[0] ) { // The elements to wrap the target around - jQuery(html, this[0].ownerDocument) - .clone() - .insertBefore(this[0]) - .map(function(){ - var elem = this; - while ( elem.firstChild ) - elem = elem.firstChild; - return elem; - }) - .append(this); + var wrap = jQuery( html, this[0].ownerDocument ).clone(); + + if ( this[0].parentNode ) + wrap.insertBefore( this[0] ); + + wrap.map(function(){ + var elem = this; + + while ( elem.firstChild ) + elem = elem.firstChild; + + return elem; + }).append(this); + } return this; }, - wrapInner: function(html) { + wrapInner: function( html ) { return this.each(function(){ - jQuery(this).contents().wrapAll(html); + jQuery( this ).contents().wrapAll( html ); }); }, - wrap: function(html) { + wrap: function( html ) { return this.each(function(){ - jQuery(this).wrapAll(html); + jQuery( this ).wrapAll( html ); }); }, append: function() { - return this.domManip(arguments, true, 1, function(a){ - this.appendChild( a ); + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.appendChild( elem ); }); }, prepend: function() { - return this.domManip(arguments, true, -1, function(a){ - this.insertBefore( a, this.firstChild ); + return this.domManip(arguments, true, function(elem){ + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); }); }, - + before: function() { - return this.domManip(arguments, false, 1, function(a){ - this.parentNode.insertBefore( a, this ); + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this ); }); }, after: function() { - return this.domManip(arguments, false, -1, function(a){ - this.parentNode.insertBefore( a, this.nextSibling ); + return this.domManip(arguments, false, function(elem){ + this.parentNode.insertBefore( elem, this.nextSibling ); }); }, end: function() { - return this.prevObject || jQuery([]); + return this.prevObject || jQuery(null); }, - find: function(t) { - var data = jQuery.map(this, function(a){ return jQuery.find(t,a); }); - return this.pushStack( /[^+>] [^+>]/.test( t ) || t.indexOf("..") > -1 ? - jQuery.unique( data ) : data ); + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), length = 0, + splice = Array.prototype.splice; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + splice.call(ret, n--, 1); + break; + } + } + } + } + } + + return ret; }, - clone: function(events) { + clone: function( events ) { // Do the clone var ret = this.map(function(){ - return this.outerHTML ? jQuery(this.outerHTML)[0] : this.cloneNode(true); + if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) { + // IE copies events bound via attachEvent when + // using cloneNode. Calling detachEvent on the + // clone will also remove the events from the orignal + // In order to get around this, we use innerHTML. + // Unfortunately, this means some modifications to + // attributes in IE that are actually only stored + // as properties will not be copied (such as the + // the name attribute on an input). + var html = this.outerHTML; + if ( !html ) { + var div = this.ownerDocument.createElement("div"); + div.appendChild( this.cloneNode(true) ); + html = div.innerHTML; + } + + return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0]; + } else + return this.cloneNode(true); }); - - if (events === true) { - var clone = ret.find("*").andSelf(); - - this.find("*").andSelf().each(function(i) { - var events = jQuery.data(this, "events"); - for ( var type in events ) - for ( var handler in events[type] ) - jQuery.event.add(clone[i], type, events[type][handler], events[type][handler].data); + + // Copy the events from the original to the clone + if ( events === true ) { + var orig = this.find("*").andSelf(), i = 0; + + ret.find("*").andSelf().each(function(){ + if ( this.nodeName !== orig[i].nodeName ) + return; + + var events = jQuery.data( orig[i], "events" ); + + for ( var type in events ) { + for ( var handler in events[ type ] ) { + jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data ); + } + } + + i++; }); } @@ -249,787 +351,855 @@ jQuery.fn = jQuery.prototype = { return ret; }, - filter: function(t) { + filter: function( selector ) { return this.pushStack( - jQuery.isFunction( t ) && - jQuery.grep(this, function(el, index){ - return t.apply(el, [index]); + jQuery.isFunction( selector ) && + jQuery.grep(this, function(elem, i){ + return selector.call( elem, i ); }) || - jQuery.multiFilter(t,this) ); + jQuery.multiFilter( selector, jQuery.grep(this, function(elem){ + return elem.nodeType === 1; + }) ), "filter", selector ); }, - not: function(t) { - return this.pushStack( - t.constructor == String && - jQuery.multiFilter(t, this, true) || - - jQuery.grep(this, function(a) { - return ( t.constructor == Array || t.jquery ) - ? jQuery.inArray( a, t ) < 0 - : a != t; - }) - ); + closest: function( selector ) { + var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null, + closer = 0; + + return this.map(function(){ + var cur = this; + while ( cur && cur.ownerDocument ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) { + jQuery.data(cur, "closest", closer); + return cur; + } + cur = cur.parentNode; + closer++; + } + }); }, - add: function(t) { - return this.pushStack( jQuery.merge( + not: function( selector ) { + if ( typeof selector === "string" ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector ); + else + selector = jQuery.multiFilter( selector, this ); + + var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; + return this.filter(function() { + return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; + }); + }, + + add: function( selector ) { + return this.pushStack( jQuery.unique( jQuery.merge( this.get(), - t.constructor == String ? - jQuery(t).get() : - t.length != undefined && (!t.nodeName || t.nodeName == "FORM") ? - t : [t] ) - ); + typeof selector === "string" ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ))); }, - is: function(expr) { - return expr ? jQuery.multiFilter(expr,this).length > 0 : false; + is: function( selector ) { + return !!selector && jQuery.multiFilter( selector, this ).length > 0; }, - hasClass: function(expr) { - return this.is("." + expr); + hasClass: function( selector ) { + return !!selector && this.is( "." + selector ); }, - - val: function( val ) { - if ( val == undefined ) { - if ( this.length ) { - var elem = this[0]; - + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if( jQuery.nodeName( elem, 'option' ) ) + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + // We need to handle select boxes special - if ( jQuery.nodeName(elem, "select") ) { + if ( jQuery.nodeName( elem, "select" ) ) { var index = elem.selectedIndex, - a = [], + values = [], options = elem.options, one = elem.type == "select-one"; - + // Nothing was selected if ( index < 0 ) return null; // Loop through all the selected options for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[i]; + var option = options[ i ]; + if ( option.selected ) { // Get the specifc value for the option - var val = jQuery.browser.msie && !option.attributes["value"].specified ? option.text : option.value; - + value = jQuery(option).val(); + // We don't need an array for one selects if ( one ) - return val; - + return value; + // Multi-Selects return an array - a.push(val); + values.push( value ); } } - - return a; - + + return values; + } + // Everything else, we just grab the value - } else - return this[0].value.replace(/\r/g, ""); + return (elem.value || "").replace(/\r/g, ""); + } - } else - return this.each(function(){ - if ( val.constructor == Array && /radio|checkbox/.test(this.type) ) - this.checked = (jQuery.inArray(this.value, val) >= 0 || - jQuery.inArray(this.name, val) >= 0); - else if ( jQuery.nodeName(this, "select") ) { - var tmp = val.constructor == Array ? val : [val]; - - jQuery("option", this).each(function(){ - this.selected = (jQuery.inArray(this.value, tmp) >= 0 || - jQuery.inArray(this.text, tmp) >= 0); - }); - - if ( !tmp.length ) - this.selectedIndex = -1; - } else - this.value = val; - }); + + return undefined; + } + + if ( typeof value === "number" ) + value += ''; + + return this.each(function(){ + if ( this.nodeType != 1 ) + return; + + if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); + + else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(value); + + jQuery( "option", this ).each(function(){ + this.selected = (jQuery.inArray( this.value, values ) >= 0 || + jQuery.inArray( this.text, values ) >= 0); + }); + + if ( !values.length ) + this.selectedIndex = -1; + + } else + this.value = value; + }); + }, + + html: function( value ) { + return value === undefined ? + (this[0] ? + this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") : + null) : + this.empty().append( value ); }, - - html: function( val ) { - return val == undefined ? - ( this.length ? this[0].innerHTML : null ) : - this.empty().append( val ); + + replaceWith: function( value ) { + return this.after( value ).remove(); }, - replaceWith: function( val ) { - return this.after( val ).remove(); + eq: function( i ) { + return this.slice( i, +i + 1 ); }, slice: function() { - return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + return this.pushStack( Array.prototype.slice.apply( this, arguments ), + "slice", Array.prototype.slice.call(arguments).join(",") ); }, - map: function(fn) { - return this.pushStack(jQuery.map( this, function(elem,i){ - return fn.call( elem, i, elem ); + map: function( callback ) { + return this.pushStack( jQuery.map(this, function(elem, i){ + return callback.call( elem, i, elem ); })); }, andSelf: function() { return this.add( this.prevObject ); }, - - domManip: function(args, table, dir, fn) { - var clone = this.length > 1, a; - - return this.each(function(){ - if ( !a ) { - a = jQuery.clean(args, this.ownerDocument); - if ( dir < 0 ) - a.reverse(); - } - var obj = this; + domManip: function( args, table, callback ) { + if ( this[0] ) { + var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(), + scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ), + first = fragment.firstChild; - if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") ) - obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); + if ( first ) + for ( var i = 0, l = this.length; i < l; i++ ) + callback.call( root(this[i], first), this.length > 1 || i > 0 ? + fragment.cloneNode(true) : fragment ); + + if ( scripts ) + jQuery.each( scripts, evalScript ); + } - jQuery.each( a, function(){ - if ( jQuery.nodeName(this, "script") ) { - if ( this.src ) - jQuery.ajax({ url: this.src, async: false, dataType: "script" }); - else - jQuery.globalEval( this.text || this.textContent || this.innerHTML || "" ); - } else - fn.apply( obj, [ clone ? this.cloneNode(true) : this ] ); - }); - }); + return this; + + function root( elem, cur ) { + return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ? + (elem.getElementsByTagName("tbody")[0] || + elem.appendChild(elem.ownerDocument.createElement("tbody"))) : + elem; + } } }; +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +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; +} + jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object - var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; // Handle a deep copy situation - if ( target.constructor == Boolean ) { + 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 ( al == 1 ) { + if ( length == i ) { target = this; - a = 0; + --i; } - var prop; - - for ( ; a < al; a++ ) + for ( ; i < length; i++ ) // Only deal with non-null/undefined values - if ( (prop = arguments[a]) != null ) + if ( (options = arguments[ i ]) != null ) // Extend the base object - for ( var i in prop ) { + for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + // Prevent never-ending loop - if ( target == prop[i] ) + if ( target === copy ) continue; // Recurse if we're merging object values - if ( deep && typeof prop[i] == 'object' && target[i] ) - jQuery.extend( target[i], prop[i] ); + if ( deep && copy && typeof copy === "object" && !copy.nodeType ) + target[ name ] = jQuery.extend( deep, + // Never move original objects, clone them + src || ( copy.length != null ? [ ] : { } ) + , copy ); // Don't bring in undefined values - else if ( prop[i] != undefined ) - target[i] = prop[i]; + else if ( copy !== undefined ) + target[ name ] = copy; + } // Return the modified object return target; }; -var expando = "jQuery" + (new Date()).getTime(), uuid = 0; +// exclude the following css properties to add px +var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, + // cache defaultView + defaultView = document.defaultView || {}, + toString = Object.prototype.toString; jQuery.extend({ - noConflict: function(deep) { + noConflict: function( deep ) { window.$ = _$; + if ( deep ) window.jQuery = _jQuery; + return jQuery; }, - // This may seem like some crazy code, but trust me when I say that this - // is the only cross-browser way to do this. --John - isFunction: function( fn ) { - return !!fn && typeof fn != "string" && !fn.nodeName && - fn.constructor != Array && /function/i.test( fn + "" ); + // 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]"; }, - - // check if an element is in a XML document - isXMLDoc: function(elem) { - return elem.documentElement && !elem.body || - elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + + 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 && jQuery.isXMLDoc( elem.ownerDocument ); }, // Evalulates a script in a global context - // Evaluates Async. in Safari 2 :-( globalEval: function( data ) { - data = jQuery.trim( data ); - if ( data ) { - if ( window.execScript ) - window.execScript( data ); - else if ( jQuery.browser.safari ) - // safari doesn't provide a synchronous global eval - window.setTimeout( data, 0 ); + 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 - eval.call( window, data ); + 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(); }, - - cache: {}, - - data: function( elem, name, data ) { - var id = elem[ expando ]; - - // Compute a unique ID for the element - if ( !id ) - id = elem[ expando ] = ++uuid; - - // Only generate the data cache if we're - // trying to access or manipulate it - if ( name && !jQuery.cache[ id ] ) - jQuery.cache[ id ] = {}; - - // Prevent overriding the named cache with undefined values - if ( data != undefined ) - jQuery.cache[ id ][ name ] = data; - - // Return the named cache data, or the ID for the element - return name ? jQuery.cache[ id ][ name ] : id; - }, - - removeData: function( elem, name ) { - var id = elem[ expando ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( jQuery.cache[ id ] ) { - // Remove the section of cache data - delete jQuery.cache[ id ][ name ]; - - // If we've removed all the data, remove the element's cache - name = ""; - for ( name in jQuery.cache[ id ] ) break; - if ( !name ) - jQuery.removeData( elem ); - } - - // Otherwise, we want to remove all of the element's data - } else { - // Clean up the element expando - try { - delete elem[ expando ]; - } catch(e){ - // IE has trouble directly removing the expando - // but it's ok with using removeAttribute - elem.removeAttribute( expando ); - } - - // Completely remove the data cache - delete jQuery.cache[ id ]; - } - }, // args is for internal usage only - each: function( obj, fn, args ) { + each: function( object, callback, args ) { + var name, i = 0, length = object.length; + if ( args ) { - if ( obj.length == undefined ) - for ( var i in obj ) - fn.apply( obj[i], args ); - else - for ( var i = 0, ol = obj.length; i < ol; i++ ) - if ( fn.apply( obj[i], args ) === false ) break; + 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 ( obj.length == undefined ) - for ( var i in obj ) - fn.call( obj[i], i, obj[i] ); - else - for ( var i = 0, ol = obj.length, val = obj[0]; - i < ol && fn.call(val,i,val) !== false; val = obj[++i] ){} + 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 obj; + return object; }, - - prop: function(elem, value, type, index, prop){ - // Handle executable functions - if ( jQuery.isFunction( value ) ) - value = value.call( elem, [index] ); - - // exclude the following css properties to add px - var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; - // Handle passing in a number to a CSS property - return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ? - value + "px" : - value; + prop: function( elem, value, type, i, name ) { + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, i ); + + // Handle passing in a number to a CSS property + return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ? + value + "px" : + value; }, className: { // internal only, use addClass("class") - add: function( elem, c ){ - jQuery.each( (c || "").split(/\s+/), function(i, cur){ - if ( !jQuery.className.has( elem.className, cur ) ) - elem.className += ( elem.className ? " " : "" ) + cur; + add: function( elem, classNames ) { + jQuery.each((classNames || "").split(/\s+/), function(i, className){ + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) + elem.className += (elem.className ? " " : "") + className; }); }, // internal only, use removeClass("class") - remove: function( elem, c ){ - elem.className = c != undefined ? - jQuery.grep( elem.className.split(/\s+/), function(cur){ - return !jQuery.className.has( c, cur ); - }).join(" ") : ""; + remove: function( elem, classNames ) { + if (elem.nodeType == 1) + elem.className = classNames !== undefined ? + jQuery.grep(elem.className.split(/\s+/), function(className){ + return !jQuery.className.has( classNames, className ); + }).join(" ") : + ""; }, - // internal only, use is(".class") - has: function( t, c ) { - return jQuery.inArray( c, (t.className || t).toString().split(/\s+/) ) > -1; + // internal only, use hasClass("class") + has: function( elem, className ) { + return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; } }, - swap: function(e,o,f) { - for ( var i in o ) { - e.style["old"+i] = e.style[i]; - e.style[i] = o[i]; + // A method for quickly swapping in/out CSS properties to get correct calculations + swap: function( elem, options, callback ) { + var old = {}; + // Remember the old values, and insert the new ones + for ( var name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; } - f.apply( e, [] ); - for ( var i in o ) - e.style[i] = e.style["old"+i]; - }, - css: function(e,p) { - if ( p == "height" || p == "width" ) { - var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; + callback.call( elem ); - jQuery.each( d, function(){ - old["padding" + this] = 0; - old["border" + this + "Width"] = 0; - }); + // Revert the old values + for ( var name in options ) + elem.style[ name ] = old[ name ]; + }, - jQuery.swap( e, old, function() { - if ( jQuery(e).is(':visible') ) { - oHeight = e.offsetHeight; - oWidth = e.offsetWidth; - } else { - e = jQuery(e.cloneNode(true)) - .find(":radio").removeAttr("checked").end() - .css({ - visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0" - }).appendTo(e.parentNode)[0]; + css: function( elem, name, force, extra ) { + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; - var parPos = jQuery.css(e.parentNode,"position") || "static"; - if ( parPos == "static" ) - e.parentNode.style.position = "relative"; + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; - oHeight = e.clientHeight; - oWidth = e.clientWidth; + if ( extra === "border" ) + return; - if ( parPos == "static" ) - e.parentNode.style.position = "static"; + jQuery.each( which, function() { + if ( !extra ) + val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + if ( extra === "margin" ) + val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0; + else + val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + } - e.parentNode.removeChild(e); - } - }); + if ( elem.offsetWidth !== 0 ) + getWH(); + else + jQuery.swap( elem, props, getWH ); - return p == "height" ? oHeight : oWidth; + return Math.max(0, Math.round(val)); } - return jQuery.curCSS( e, p ); + return jQuery.curCSS( elem, name, force ); }, - curCSS: function(elem, prop, force) { - var ret, stack = [], swap = []; + curCSS: function( elem, name, force ) { + var ret, style = elem.style; - // A helper method for determining if an element's values are broken - function color(a){ - if ( !jQuery.browser.safari ) - return false; + // We need to handle opacity special in IE + if ( name == "opacity" && !jQuery.support.opacity ) { + ret = jQuery.attr( style, "opacity" ); - var ret = document.defaultView.getComputedStyle(a,null); - return !ret || ret.getPropertyValue("color") == ""; + return ret == "" ? + "1" : + ret; } - if (prop == "opacity" && jQuery.browser.msie) { - ret = jQuery.attr(elem.style, "opacity"); - return ret == "" ? "1" : ret; - } - - if (prop.match(/float/i)) - prop = styleFloat; + // Make sure we're using the right name for getting the float value + if ( name.match( /float/i ) ) + name = styleFloat; - if (!force && elem.style[prop]) - ret = elem.style[prop]; + if ( !force && style && style[ name ] ) + ret = style[ name ]; - else if (document.defaultView && document.defaultView.getComputedStyle) { + else if ( defaultView.getComputedStyle ) { - if (prop.match(/float/i)) - prop = "float"; + // Only "float" is needed here + if ( name.match( /float/i ) ) + name = "float"; - prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); - var cur = document.defaultView.getComputedStyle(elem, null); + name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - if ( cur && !color(elem) ) - ret = cur.getPropertyValue(prop); + var computedStyle = defaultView.getComputedStyle( elem, null ); - // If the element isn't reporting its values properly in Safari - // then some display: none elements are involved - else { - // Locate all of the parent display: none elements - for ( var a = elem; a && color(a); a = a.parentNode ) - stack.unshift(a); - - // Go through and make them visible, but in reverse - // (It would be better if we knew the exact display type that they had) - for ( a = 0; a < stack.length; a++ ) - if ( color(stack[a]) ) { - swap[a] = stack[a].style.display; - stack[a].style.display = "block"; - } - - // Since we flip the display style, we have to handle that - // one special, otherwise get the value - ret = prop == "display" && swap[stack.length-1] != null ? - "none" : - document.defaultView.getComputedStyle(elem,null).getPropertyValue(prop) || ""; - - // Finally, revert the display styles back - for ( a = 0; a < swap.length; a++ ) - if ( swap[a] != null ) - stack[a].style.display = swap[a]; - } + if ( computedStyle ) + ret = computedStyle.getPropertyValue( name ); - if ( prop == "opacity" && ret == "" ) + // We should always get a number back from opacity + if ( name == "opacity" && ret == "" ) ret = "1"; - } else if (elem.currentStyle) { - var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); - ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; + } else if ( elem.currentStyle ) { + var camelCase = name.replace(/\-(\w)/g, function(all, letter){ + return letter.toUpperCase(); + }); + + ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels - if ( !/^\d+(px)?$/i.test(ret) && /^\d/.test(ret) ) { - var style = elem.style.left; - var runtimeStyle = elem.runtimeStyle.left; + if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { + // Remember the original values + var left = style.left, rsLeft = elem.runtimeStyle.left; + + // Put in the new values to get a computed value out elem.runtimeStyle.left = elem.currentStyle.left; - elem.style.left = ret || 0; - ret = elem.style.pixelLeft + "px"; - elem.style.left = style; - elem.runtimeStyle.left = runtimeStyle; + style.left = ret || 0; + ret = style.pixelLeft + "px"; + + // Revert the changed values + style.left = left; + elem.runtimeStyle.left = rsLeft; } } return ret; }, - - clean: function(a, doc) { - var r = []; - doc = doc || document; - jQuery.each( a, function(i,arg){ - if ( !arg ) return; + clean: function( elems, context, fragment ) { + context = context || document; + + // !context.createElement fails in IE with an error but returns typeof 'object' + if ( typeof context.createElement === "undefined" ) + context = context.ownerDocument || context[0] && context[0].ownerDocument || document; + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) { + var match = /^<(\w+)\s*\/?>$/.exec(elems[0]); + if ( match ) + return [ context.createElement( match[1] ) ]; + } + + var ret = [], scripts = [], div = context.createElement("div"); + + jQuery.each(elems, function(i, elem){ + if ( typeof elem === "number" ) + elem += ''; + + if ( !elem ) + return; - if ( arg.constructor == Number ) - arg = arg.toString(); - // Convert html string into DOM nodes - if ( typeof arg == "string" ) { + if ( typeof elem === "string" ) { // Fix "XHTML"-style tags in all browsers - arg = arg.replace(/(<(\w+)[^>]*?)\/>/g, function(m, all, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i)? m : all+">"; + elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? + all : + front + ">"; }); // Trim whitespace, otherwise indexOf won't work as expected - var s = jQuery.trim(arg).toLowerCase(), div = doc.createElement("div"), tb = []; + var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase(); var wrap = // option or optgroup - !s.indexOf("", ""] || - - !s.indexOf("", ""] || - - s.match(/^<(thead|tbody|tfoot|colg|cap)/) && - [1, "", "
"] || - - !s.indexOf("", ""] || - + !tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || + + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [ 1, "", "
" ] || + + !tags.indexOf("", "" ] || + // matched above - (!s.indexOf("", ""] || - - !s.indexOf("", ""] || + (!tags.indexOf("", "" ] || + + !tags.indexOf("", "" ] || // IE can't serialize and