X-Git-Url: http://git.asbjorn.it/?a=blobdiff_plain;f=src%2Fcore.js;h=ad938f2b53ace3d0c6a5ac0cbdb6506dbdaec398;hb=7ef40fd19926c779086ae7d79796032708d568e0;hp=23c1b79f31151d2fba8a7db52b088eb7fe27dec2;hpb=1be558203961c43043d6e9de3341e8bb9c3dcbf3;p=jquery.git diff --git a/src/core.js b/src/core.js index 23c1b79..ad938f2 100644 --- a/src/core.js +++ b/src/core.js @@ -14,10 +14,8 @@ 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 ); + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.prototype.init( selector, context ); }; // Map over the $ in case of overwrite @@ -31,6 +29,9 @@ window.$ = jQuery; // (both of which we optimize for) var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; +// Is it a simple selector +var isSimple = /^.[^:#\[\.]*$/; + jQuery.fn = jQuery.prototype = { init: function( selector, context ) { // Make sure that a selection was provided @@ -251,13 +252,15 @@ 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 ); }); }, @@ -290,9 +293,23 @@ 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"), + container2 = document.createElement("div"); + container.appendChild(clone); + container2.innerHTML = container.innerHTML; + return container2.firstChild; + } else + return this.cloneNode(true); }); // Need to set the expando to null on the cloned set if it exists @@ -328,19 +345,21 @@ 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 !selector ? this : this.pushStack( jQuery.merge( this.get(), selector.constructor == String ? jQuery( selector ).get() : @@ -400,28 +419,33 @@ jQuery.fn = jQuery.prototype = { } - } 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 ) { @@ -477,16 +501,9 @@ jQuery.fn = jQuery.prototype = { this.cloneNode( true ) : 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 +519,9 @@ jQuery.fn = jQuery.prototype = { } }; +// Give the init function the jQuery prototype for later instantiation +jQuery.prototype.init.prototype = jQuery.prototype; + function evalScript( i, elem ) { if ( elem.src ) jQuery.ajax({ @@ -722,18 +742,19 @@ 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") @@ -744,9 +765,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 ]; } @@ -754,59 +776,31 @@ 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; - - // 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 ); - } - }); - - return name == "height" ? - height : - width; + 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); + } + + if ( jQuery(elem).is(":visible") ) + getWH(); + else + jQuery.swap( elem, props, getWH ); + + return val; } - + return jQuery.curCSS( elem, name, force ); }, @@ -830,6 +824,12 @@ jQuery.extend({ "1" : ret; } + // Opera sometimes will give the wrong display answer, this fixes it, see #2037 + if ( jQuery.browser.opera && name == "display" ) { + var save = elem.style.display; + elem.style.display = "block"; + elem.style.display = save; + } // Make sure we're using the right name for getting the float value if ( name.match( /float/i ) ) @@ -986,9 +986,9 @@ jQuery.extend({ div.childNodes : []; - for ( var i = tbody.length - 1; i >= 0 ; --i ) - if ( jQuery.nodeName( tbody[ i ], "tbody" ) && !tbody[ i ].childNodes.length ) - tbody[ i ].parentNode.removeChild( tbody[ i ] ); + for ( var j = tbody.length - 1; j >= 0 ; --j ) + if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) + tbody[ j ].parentNode.removeChild( tbody[ j ] ); // IE completely kills leading whitespace when innerHTML is used if ( /^\s/.test( elem ) ) @@ -1014,6 +1014,10 @@ jQuery.extend({ }, attr: function( elem, name, value ) { + // don't set attributes on text and comment nodes + if (!elem || elem.nodeType == 3 || elem.nodeType == 8) + return undefined; + var fix = jQuery.isXMLDoc( elem ) ? {} : jQuery.props; @@ -1267,7 +1271,8 @@ jQuery.each({ jQuery.each({ removeAttr: function( name ) { jQuery.attr( this, name, "" ); - this.removeAttribute( name ); + if (this.nodeType == 1) + this.removeAttribute( name ); }, addClass: function( classNames ) { @@ -1325,8 +1330,11 @@ jQuery.each([ "Height", "Width" ], function(i, name){ // Get document width or height this[0] == document ? - // Either scroll[Width/Height] or offset[Width/Height], whichever is greater (Mozilla reports scrollWidth the same as offsetWidth) - Math.max( document.body[ "scroll" + name ], document.body[ "offset" + name ] ) : + // Either scroll[Width/Height] or offset[Width/Height], whichever is greater + Math.max( + Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]), + Math.max(document.body["offset" + name], document.documentElement["offset" + name]) + ) : // Get or set width or height on the element size == undefined ?