X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fcore.js;h=27cdbfe1fff23610a704304a660a01a39513cf02;hb=da76a723e14c037d59e830bb0d01b0b627286020;hp=62e41c966ea62cdd83fc61c3778304f542144567;hpb=b6d70a7ce3795e8c1306a513b89a31de0c5f0a13;p=jquery.git diff --git a/src/core.js b/src/core.js index 62e41c9..27cdbfe 100644 --- a/src/core.js +++ b/src/core.js @@ -1,7 +1,7 @@ /* * jQuery @VERSION - New Wave Javascript * - * Copyright (c) 2007 John Resig (jquery.com) + * Copyright (c) 2008 John Resig (jquery.com) * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * @@ -10,26 +10,24 @@ */ // Map over jQuery in case of overwrite -if ( window.jQuery ) - var _jQuery = window.jQuery; - -var jQuery = window.jQuery = function( selector, context ) { - // If the context is a namespace object, return a new object - return this instanceof jQuery ? - this.init( selector, context ) : - new jQuery( selector, context ); -}; - +var _jQuery = window.jQuery, // Map over the $ in case of overwrite -if ( window.$ ) - var _$ = window.$; - -// Map the jQuery namespace to the '$' one -window.$ = jQuery; + _$ = window.$; + +var jQuery = window.jQuery = window.$ = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); +}; // A simple way to check for HTML strings or ID strings // (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/, + +// Is it a simple selector + isSimple = /^.[^:#\[\.]*$/, + +// Will speed up references to undefined, and allows munging its name. + undefined; jQuery.fn = jQuery.prototype = { init: function( selector, context ) { @@ -41,9 +39,9 @@ jQuery.fn = jQuery.prototype = { this[0] = selector; this.length = 1; return this; - + } // Handle HTML strings - } else if ( typeof selector == "string" ) { + if ( typeof selector == "string" ) { // Are we dealing with HTML string or an ID? var match = quickExpr.exec( selector ); @@ -59,45 +57,31 @@ jQuery.fn = jQuery.prototype = { var elem = document.getElementById( match[3] ); // Make sure an element was located - if ( elem ) + if ( elem ){ // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id != match[3] ) return jQuery().find( selector ); // Otherwise, we inject the element directly into the jQuery object - else { - this[0] = elem; - this.length = 1; - return this; - } - - else - selector = []; + return jQuery( elem ); + } + selector = []; } // HANDLE: $(expr, [context]) // (which is just equivalent to: $(content).find(expr) } else - return new jQuery( context ).find( selector ); + return jQuery( context ).find( selector ); // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) - return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); - - return this.setArray( - // HANDLE: $(array) - selector.constructor == Array && selector || - - // HANDLE: $(arraylike) - // Watch for when an array-like object, contains DOM nodes, is passed in as the selector - (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); - // HANDLE: $(*) - [ selector ] ); + return this.setArray(jQuery.makeArray(selector)); }, - + // The current version of jQuery being used jquery: "@VERSION", @@ -105,7 +89,7 @@ jQuery.fn = jQuery.prototype = { size: function() { return this.length; }, - + // The number of elements contained in the matched element set length: 0, @@ -120,7 +104,7 @@ jQuery.fn = jQuery.prototype = { // 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 ) { @@ -133,7 +117,7 @@ jQuery.fn = jQuery.prototype = { // 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 @@ -142,7 +126,7 @@ jQuery.fn = jQuery.prototype = { // is a super-fast way to populate an object with array-like properties this.length = 0; Array.prototype.push.apply( this, elems ); - + return this; }, @@ -153,33 +137,31 @@ jQuery.fn = jQuery.prototype = { return jQuery.each( this, callback, args ); }, - // Determine the position of an element within + // Determine the position of an element within // the matched set of elements index: function( elem ) { var ret = -1; // Locate the position of the desired element - this.each(function(i){ - if ( this == elem ) - ret = i; - }); - - return ret; + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem && elem.jquery ? elem[0] : elem + , this ); }, attr: function( name, value, type ) { var options = name; - + // Look for the case where we're accessing a style value if ( name.constructor == String ) - if ( value == undefined ) - return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; + if ( value === undefined ) + return this[0] && jQuery[ type || "attr" ]( this[0], name ); else { options = {}; options[ name ] = value; } - + // Check to see if we're setting style values return this.each(function(i){ // Set all the styles @@ -202,7 +184,7 @@ jQuery.fn = jQuery.prototype = { text: function( text ) { if ( typeof text != "object" && text != null ) - return this.empty().append( document.createTextNode( text ) ); + return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); var ret = ""; @@ -251,16 +233,18 @@ jQuery.fn = jQuery.prototype = { append: function() { return this.domManip(arguments, true, false, function(elem){ - this.appendChild( elem ); + if (this.nodeType == 1) + this.appendChild( elem ); }); }, prepend: function() { return this.domManip(arguments, true, true, function(elem){ - this.insertBefore( elem, this.firstChild ); + if (this.nodeType == 1) + this.insertBefore( elem, this.firstChild ); }); }, - + before: function() { return this.domManip(arguments, false, false, function(elem){ this.parentNode.insertBefore( elem, this ); @@ -290,9 +274,21 @@ jQuery.fn = jQuery.prototype = { clone: function( events ) { // Do the clone var ret = this.map(function(){ - return this.outerHTML ? - jQuery( this.outerHTML )[0] : - this.cloneNode( true ); + if ( jQuery.browser.msie && !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 clone = this.cloneNode(true), + container = document.createElement("div"); + container.appendChild(clone); + return jQuery.clean([container.innerHTML])[0]; + } else + return this.cloneNode(true); }); // Need to set the expando to null on the cloned set if it exists @@ -302,10 +298,12 @@ jQuery.fn = jQuery.prototype = { if ( this[ expando ] != undefined ) this[ expando ] = null; }); - + // Copy the events from the original to the clone if ( events === true ) this.find("*").andSelf().each(function(i){ + if (this.nodeType == 3) + return; var events = jQuery.data( this, "events" ); for ( var type in events ) @@ -328,36 +326,36 @@ jQuery.fn = jQuery.prototype = { }, not: function( selector ) { - return this.pushStack( - selector.constructor == String && - jQuery.multiFilter( selector, this, true ) || - - jQuery.grep(this, function(elem) { - return selector.constructor == Array || selector.jquery ? - jQuery.inArray( elem, selector ) < 0 : - elem != selector; - }) ); + if ( selector.constructor == String ) + // test special case where just one selector is passed in + if ( isSimple.test( selector ) ) + return this.pushStack( jQuery.multiFilter( selector, this, true ) ); + 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.merge( + return this.pushStack( jQuery.unique( jQuery.merge( this.get(), - selector.constructor == String ? - jQuery( selector ).get() : - selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? - selector : [selector] ) ); + typeof selector == 'string' ? + jQuery( selector ) : + jQuery.makeArray( selector ) + ))); }, is: function( selector ) { - return selector ? - jQuery.multiFilter( selector, this ).length > 0 : - false; + return !!selector && jQuery.multiFilter( selector, this ).length > 0; }, hasClass: function( selector ) { return this.is( "." + selector ); }, - + val: function( value ) { if ( value == undefined ) { @@ -370,7 +368,7 @@ jQuery.fn = jQuery.prototype = { values = [], options = elem.options, one = elem.type == "select-one"; - + // Nothing was selected if ( index < 0 ) return null; @@ -382,48 +380,53 @@ jQuery.fn = jQuery.prototype = { if ( option.selected ) { // Get the specifc value for the option value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; - + // We don't need an array for one selects if ( one ) return value; - + // Multi-Selects return an array values.push( value ); } } - + return values; - + // Everything else, we just grab the value } else return (this[0].value || "").replace(/\r/g, ""); } - } else - return this.each(function(){ - if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) - this.checked = (jQuery.inArray(this.value, value) >= 0 || - jQuery.inArray(this.name, value) >= 0); + return undefined; + } - else if ( jQuery.nodeName( this, "select" ) ) { - var values = value.constructor == Array ? - value : - [ value ]; + return this.each(function(){ + if ( this.nodeType != 1 ) + return; - jQuery( "option", this ).each(function(){ - this.selected = (jQuery.inArray( this.value, values ) >= 0 || - jQuery.inArray( this.text, values ) >= 0); - }); + if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) + this.checked = (jQuery.inArray(this.value, value) >= 0 || + jQuery.inArray(this.name, value) >= 0); - if ( !values.length ) - this.selectedIndex = -1; + else if ( jQuery.nodeName( this, "select" ) ) { + var values = value.constructor == Array ? + value : + [ value ]; - } else - this.value = 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.length ? @@ -453,9 +456,34 @@ jQuery.fn = jQuery.prototype = { andSelf: function() { return this.add( this.prevObject ); }, - + + data: function( key, value ){ + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data === undefined && this.length ) + data = jQuery.data( this[0], key ); + + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } else + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ + jQuery.data( this, key, value ); + }); + }, + + removeData: function( key ){ + return this.each(function(){ + jQuery.removeData( this, key ); + }); + }, + domManip: function( args, table, reverse, callback ) { - var clone = this.length > 1, elems; + var clone = this.length > 1, elems; return this.each(function(){ if ( !elems ) { @@ -468,25 +496,18 @@ jQuery.fn = jQuery.prototype = { var obj = this; if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) - obj = this.getElementsByTagName("tbody")[0] || this.appendChild( document.createElement("tbody") ); + obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); var scripts = jQuery( [] ); jQuery.each(elems, function(){ var elem = clone ? - this.cloneNode( true ) : + jQuery( this ).clone( true )[0] : this; + // execute all scripts after the elements have been injected if ( jQuery.nodeName( elem, "script" ) ) { - - // If scripts are waiting to be executed, wait on this script as well - if ( scripts.length ) - scripts = scripts.add( elem ); - - // If nothing is waiting to be executed, run immediately - else - evalScript( 0, elem ); - + scripts = scripts.add( elem ); } else { // Remove any inner scripts for later evaluation if ( elem.nodeType == 1 ) @@ -502,6 +523,9 @@ jQuery.fn = jQuery.prototype = { } }; +// 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({ @@ -517,6 +541,10 @@ function evalScript( i, elem ) { elem.parentNode.removeChild( elem ); } +function now(){ + return +new Date; +} + jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; @@ -530,13 +558,13 @@ jQuery.extend = jQuery.fn.extend = function() { } // Handle case when target is a string or something (possible in deep copy) - if ( typeof target != "object" ) + if ( typeof target != "object" && typeof target != "function" ) target = {}; // extend jQuery itself if only one argument is passed - if ( length == 1 ) { + if ( length == i ) { target = this; - i = 0; + --i; } for ( ; i < length; i++ ) @@ -544,17 +572,22 @@ jQuery.extend = jQuery.fn.extend = function() { if ( (options = arguments[ i ]) != null ) // Extend the base object for ( var name in options ) { + var src = target[ name ], copy = options[ name ]; + // Prevent never-ending loop - if ( target === options[ name ] ) + if ( target === copy ) continue; // Recurse if we're merging object values - if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) - target[ name ] = jQuery.extend( target[ name ], options[ name ] ); + 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 ( options[ name ] != undefined ) - target[ name ] = options[ name ]; + else if ( copy !== undefined ) + target[ name ] = copy; } @@ -562,10 +595,11 @@ jQuery.extend = jQuery.fn.extend = function() { return target; }; -var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; - -// exclude the following css properties to add px -var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; +var expando = "jQuery" + now(), uuid = 0, windowData = {}, + // exclude the following css properties to add px + exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, + // cache defaultView + defaultView = document.defaultView || {}; jQuery.extend({ noConflict: function( deep ) { @@ -577,13 +611,12 @@ jQuery.extend({ 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 + // See test/unit/core.js for details concerning this function. isFunction: function( fn ) { - return !!fn && typeof fn != "string" && !fn.nodeName && - fn.constructor != Array && /function/i.test( fn + "" ); + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /^[\s[]?function/.test( fn + "" ); }, - + // check if an element is in a (or is an) XML document isXMLDoc: function( elem ) { return elem.documentElement && !elem.body || @@ -591,7 +624,6 @@ jQuery.extend({ }, // Evalulates a script in a global context - // Evaluates Async. in Safari 2 :-( globalEval: function( data ) { data = jQuery.trim( data ); @@ -615,9 +647,9 @@ jQuery.extend({ nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); }, - + cache: {}, - + data: function( elem, name, data ) { elem = elem == window ? windowData : @@ -626,24 +658,24 @@ jQuery.extend({ var id = elem[ expando ]; // Compute a unique ID for the element - if ( !id ) + 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 ) + if ( data !== undefined ) jQuery.cache[ id ][ name ] = data; - - // Return the named cache data, or the ID for the element + + // Return the named cache data, or the ID for the element return name ? jQuery.cache[ id ][ name ] : id; }, - + removeData: function( elem, name ) { elem = elem == window ? windowData : @@ -686,33 +718,37 @@ jQuery.extend({ // args is for internal usage only each: function( object, callback, args ) { + var name, i = 0, length = object.length; + if ( args ) { - if ( object.length == undefined ) - for ( var name in object ) - callback.apply( object[ name ], args ); - else - for ( var i = 0, length = object.length; i < length; i++ ) - if ( callback.apply( object[ i ], args ) === false ) + 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 ( object.length == undefined ) - for ( var name in object ) - callback.call( object[ name ], name, object[ name ] ); - else - for ( var i = 0, length = object.length, value = object[0]; + 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; }, - + 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 value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? value + "px" : @@ -723,21 +759,22 @@ jQuery.extend({ // internal only, use addClass("class") add: function( elem, classNames ) { jQuery.each((classNames || "").split(/\s+/), function(i, className){ - if ( !jQuery.className.has( elem.className, className ) ) + if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) elem.className += (elem.className ? " " : "") + className; }); }, // internal only, use removeClass("class") remove: function( elem, classNames ) { - elem.className = classNames != undefined ? - jQuery.grep(elem.className.split(/\s+/), function(className){ - return !jQuery.className.has( classNames, className ); - }).join(" ") : - ""; + 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") + // internal only, use hasClass("class") has: function( elem, className ) { return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; } @@ -745,9 +782,10 @@ jQuery.extend({ // 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 ) { - elem.style[ "old" + name ] = elem.style[ name ]; + old[ name ] = elem.style[ name ]; elem.style[ name ] = options[ name ]; } @@ -755,91 +793,70 @@ jQuery.extend({ // Revert the old values for ( var name in options ) - elem.style[ name ] = elem.style[ "old" + name ]; + elem.style[ name ] = old[ name ]; }, css: function( elem, name, force ) { - if ( name == "height" || name == "width" ) { - var old = {}, height, width; - - // Revert the padding and border widths to get the - // correct height/width values - jQuery.each([ "Top", "Bottom", "Right", "Left" ], function(){ - old[ "padding" + this ] = 0; - old[ "border" + this + "Width" ] = 0; - }); - - // Swap out the padding/border values temporarily - jQuery.swap( elem, old, function() { - - // If the element is visible, then the calculation is easy - if ( jQuery( elem ).is(":visible") ) { - height = elem.offsetHeight; - width = elem.offsetWidth; + if ( name == "width" || name == "height" ) { + var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; + + function getWH() { + val = name == "width" ? elem.offsetWidth : elem.offsetHeight; + var padding = 0, border = 0; + jQuery.each( which, function() { + padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; + border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; + }); + val -= Math.round(padding + border); + } - // Otherwise, we need to flip out more values - } else { - elem = jQuery( elem.cloneNode(true) ) - .find(":radio").removeAttr("checked").removeAttr("defaultChecked").end() - .css({ - visibility: "hidden", - position: "absolute", - display: "block", - right: "0", - left: "0" - }).appendTo( elem.parentNode )[0]; - - var position = jQuery.css( elem.parentNode, "position" ) || "static"; - if ( position == "static" ) - elem.parentNode.style.position = "relative"; - - height = elem.clientHeight; - width = elem.clientWidth; - - if ( position == "static" ) - elem.parentNode.style.position = "static"; - - elem.parentNode.removeChild( elem ); - } - }); + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); - return name == "height" ? - height : - width; + return Math.max(0, val); } return jQuery.curCSS( elem, name, force ); }, curCSS: function( elem, name, force ) { - var ret; + var ret, style = elem.style; // A helper method for determining if an element's values are broken function color( elem ) { if ( !jQuery.browser.safari ) return false; - var ret = document.defaultView.getComputedStyle( elem, null ); + // defaultView is cached + var ret = defaultView.getComputedStyle( elem, null ); return !ret || ret.getPropertyValue("color") == ""; } // We need to handle opacity special in IE if ( name == "opacity" && jQuery.browser.msie ) { - ret = jQuery.attr( elem.style, "opacity" ); + ret = jQuery.attr( style, "opacity" ); return ret == "" ? "1" : ret; } - + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = style.outline; + style.outline = "0 solid black"; + style.outline = save; + } + // Make sure we're using the right name for getting the float value if ( name.match( /float/i ) ) name = styleFloat; - if ( !force && elem.style[ name ] ) - ret = elem.style[ name ]; + if ( !force && style && style[ name ] ) + ret = style[ name ]; - else if ( document.defaultView && document.defaultView.getComputedStyle ) { + else if ( defaultView.getComputedStyle ) { // Only "float" is needed here if ( name.match( /float/i ) ) @@ -847,23 +864,23 @@ jQuery.extend({ name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); + var computedStyle = defaultView.getComputedStyle( elem, null ); - if ( getComputedStyle && !color( elem ) ) - ret = getComputedStyle.getPropertyValue( name ); + if ( computedStyle && !color( elem ) ) + ret = computedStyle.getPropertyValue( name ); // If the element isn't reporting its values properly in Safari // then some display: none elements are involved else { - var swap = [], stack = []; + var swap = [], stack = [], a = elem, i = 0; // Locate all of the parent display: none elements - for ( var a = elem; a && color(a); a = a.parentNode ) + for ( ; 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 ( var i = 0; i < stack.length; i++ ) + for ( ; i < stack.length; i++ ) if ( color( stack[ i ] ) ) { swap[ i ] = stack[ i ].style.display; stack[ i ].style.display = "block"; @@ -873,10 +890,10 @@ jQuery.extend({ // one special, otherwise get the value ret = name == "display" && swap[ stack.length - 1 ] != null ? "none" : - ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; + ( computedStyle && computedStyle.getPropertyValue( name ) ) || ""; // Finally, revert the display styles back - for ( var i = 0; i < swap.length; i++ ) + for ( i = 0; i < swap.length; i++ ) if ( swap[ i ] != null ) stack[ i ].style.display = swap[ i ]; } @@ -899,38 +916,41 @@ jQuery.extend({ // but a number that has a weird ending, we need to convert it to pixels if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { // Remember the original values - var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; + 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"; + style.left = ret || 0; + ret = style.pixelLeft + "px"; // Revert the changed values - elem.style.left = style; - elem.runtimeStyle.left = runtimeStyle; + style.left = left; + elem.runtimeStyle.left = rsLeft; } } return ret; }, - + clean: function( elems, context ) { var ret = []; 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; jQuery.each(elems, function(i, elem){ if ( !elem ) return; if ( elem.constructor == Number ) - elem = elem.toString(); - + elem += ''; + // Convert html string into DOM nodes if ( typeof elem == "string" ) { // Fix "XHTML"-style tags in all browsers elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i) ? + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? all : front + ">"; }); @@ -942,58 +962,58 @@ jQuery.extend({ // option or optgroup !tags.indexOf("", "" ] || - + !tags.indexOf("", "" ] || - + tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && [ 1, "", "
" ] || - + !tags.indexOf("", "" ] || - + // matched above (!tags.indexOf("", "" ] || - + !tags.indexOf("", "" ] || // IE can't serialize and