X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=src%2Fjquery%2Fjquery.js;h=5e2864b3159d0110c99fbd8515bc5d42a12b1ab0;hb=54035207fe91cb57f49bb8c0c9f7b4ada8d05346;hp=a2a9b9f7956054b07a1812b32aa872c59ac35b82;hpb=958bed09da67c052dfa85c0bb8c0dc88873e5923;p=jquery.git diff --git a/src/jquery/jquery.js b/src/jquery/jquery.js index a2a9b9f..5e2864b 100644 --- a/src/jquery/jquery.js +++ b/src/jquery/jquery.js @@ -24,39 +24,10 @@ window.undefined = window.undefined; */ var jQuery = function(a,c) { // If the context is global, return a new object - if ( window == this ) + if ( window == this || !this.init ) return new jQuery(a,c); - - // Make sure that a selection was provided - a = a || document; - - // HANDLE: $(function) - // Shortcut for document ready - if ( jQuery.isFunction(a) ) - return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a ); - // Handle HTML strings - if ( typeof a == "string" ) { - // HANDLE: $(html) -> $(array) - var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a); - if ( m ) - a = jQuery.clean( [ m[1] ] ); - - // HANDLE: $(expr) - else - return new jQuery( c ).find( a ); - } - - return this.setArray( - // HANDLE: $(array) - a.constructor == Array && a || - - // 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 ) || - - // HANDLE: $(*) - [ a ] ); + return this.init(a,c); }; // Map over the $ in case of overwrite @@ -170,6 +141,48 @@ var $ = jQuery; jQuery.fn = jQuery.prototype = { /** + * Initialize a new jQuery object + * + * @private + * @name init + * @param String|Function|Element|Array|jQuery a selector + * @param jQuery|Element|Array c context + * @cat Core + */ + init: function(a,c) { + // Make sure that a selection was provided + a = a || document; + + // HANDLE: $(function) + // Shortcut for document ready + if ( jQuery.isFunction(a) ) + return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( a ); + + // Handle HTML strings + if ( typeof a == "string" ) { + // HANDLE: $(html) -> $(array) + var m = /^[^<]*(<(.|\s)+>)[^>]*$/.exec(a); + if ( m ) + a = jQuery.clean( [ m[1] ] ); + + // HANDLE: $(expr) + else + return new jQuery( c ).find( a ); + } + + return this.setArray( + // HANDLE: $(array) + a.constructor == Array && a || + + // 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 ) || + + // HANDLE: $(*) + [ a ] ); + }, + + /** * The current version of jQuery. * * @private @@ -798,7 +811,7 @@ jQuery.fn = jQuery.prototype = { /** * Searches for all elements that match the specified expression. - + * * This method is a good way to find additional descendant * elements with which to process. * @@ -817,9 +830,9 @@ jQuery.fn = jQuery.prototype = { * @cat DOM/Traversing */ find: function(t) { - return this.pushStack( jQuery.unique( jQuery.map( this, function(a){ - return jQuery.find(t,a); - }) ), 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 ); }, /** @@ -839,11 +852,30 @@ jQuery.fn = jQuery.prototype = { * @cat DOM/Manipulation */ clone: function(deep) { - return this.pushStack( jQuery.map( this, function(a){ - var a = a.cloneNode( deep != undefined ? deep : true ); - a.$events = null; // drop $events expando to avoid firing incorrect events - return a; + // Need to remove events on the element and its descendants + var $this = this.add(this.find("*")); + $this.each(function() { + this._$events = {}; + for (var type in this.$events) + this._$events[type] = jQuery.extend({},this.$events[type]); + }).unbind(); + + // Do the clone + var r = this.pushStack( jQuery.map( this, function(a){ + return a.cloneNode( deep != undefined ? deep : true ); }) ); + + // Add the events back to the original and its descendants + $this.each(function() { + var events = this._$events; + for (var type in events) + for (var handler in events[type]) + jQuery.event.add(this, type, events[type][handler], events[type][handler].data); + this._$events = null; + }); + + // Return the cloned set + return r; }, /** @@ -1177,10 +1209,6 @@ jQuery.fn = jQuery.prototype = { /** * Extend one object with one or more others, returning the original, * modified, object. This is a great utility for simple inheritance. - * - * There is also an optional collision resolution function. Any time the target and - * merged object both contain a key this function is called. This may be used to create - * a recursive merge. (See example) Unless you know what this is, you probably don't care. * * @example var settings = { validate: false, limit: 5, name: "foo" }; * var options = { validate: true, name: "bar" }; @@ -1194,19 +1222,8 @@ jQuery.fn = jQuery.prototype = { * @result settings == { validate: true, limit: 5, name: "bar" } * @desc Merge defaults and options, without modifying the defaults * - * @example var defaults = { validate: false, limit: 5, name: "foo", nested: {depth: false} }; - * var options = { validate: true, name: "bar", nested: {depth: true} }; - * var collision_resolver_fn = function(target, mergee) { - * // combine nested Objects, in this case the object being merged takes priority - * return jQuery.extend({}, target, mergee); - * } - * var settings = jQuery.extend({}, collision_resolver_fn, defaults, options); - * @result settings == { validate: true, limit: 5, name: "bar" } - * @desc Recursively merge defaults and options, without modifying the defaults - * * @name $.extend * @param Object target The object to extend - * @param Function (optional) collision resolution function. Hook to extend the merging behavior of $.extend(). See example. * @param Object prop1 The object that will be merged into the first. * @param Object propN (optional) More objects to merge into the first * @type Object @@ -1214,26 +1231,17 @@ jQuery.fn = jQuery.prototype = { */ jQuery.extend = jQuery.fn.extend = function() { // copy reference to target object - var resolver, prop, target = arguments[0], - a = 1; - + var target = arguments[0], a = 1; + // extend jQuery itself if only one argument is passed if ( arguments.length == 1 ) { target = this; a = 0; - } else if (jQuery.isFunction(arguments[a])) { - resolver = arguments[a++]; } - - while (prop = arguments[a++]) + var prop; + while ( (prop = arguments[a++]) != null ) // Extend the base object - for ( var i in prop ) { - if (resolver && target[i] && prop[i]) { - target[i] = resolver(target[i], prop[i]); - } else { - target[i] = prop[i]; - } - } + for ( var i in prop ) target[i] = prop[i]; // Return the modified object return target; @@ -1360,7 +1368,7 @@ jQuery.extend({ // internal only, use removeClass("class") remove: function( elem, c ){ - elem.className = c ? + elem.className = c != undefined ? jQuery.grep( elem.className.split(/\s+/), function(cur){ return !jQuery.className.has( c, cur ); }).join(" ") : ""; @@ -1434,15 +1442,15 @@ jQuery.extend({ return ret == "" ? "1" : ret; } - if (prop == "float" || prop == "cssFloat") - prop = jQuery.browser.msie ? "styleFloat" : "cssFloat"; + if (prop.match(/float/i)) + prop = jQuery.styleFloat; if (!force && elem.style[prop]) ret = elem.style[prop]; else if (document.defaultView && document.defaultView.getComputedStyle) { - if (prop == "cssFloat" || prop == "styleFloat") + if (prop.match(/float/i)) prop = "float"; prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); @@ -1476,20 +1484,20 @@ jQuery.extend({ if ( arg.constructor == Number ) arg = arg.toString(); - // Convert html string into DOM nodes + // Convert html string into DOM nodes if ( typeof arg == "string" ) { // Trim whitespace, otherwise indexOf won't work as expected - var s = jQuery.trim(arg), div = doc.createElement("div"), tb = []; + var s = jQuery.trim(arg).toLowerCase(), div = doc.createElement("div"), tb = []; var wrap = - // option or optgroup + // option or optgroup !s.indexOf("", ""] || !s.indexOf("", ""] || - (!s.indexOf("", ""] || !s.indexOf("", ""] || + !s.indexOf("", ""] || + [0,"",""]; // Go to html and back, then peel off extra wrappers @@ -1528,10 +1539,10 @@ jQuery.extend({ arg = jQuery.makeArray( div.childNodes ); } - if ( arg.length === 0 && !jQuery(arg).is("form, select") ) + if ( 0 === arg.length && (!jQuery.nodeName(arg, "form") && !jQuery.nodeName(arg, "select")) ) return; - if ( arg[0] == undefined || jQuery(arg).is("form, select") ) + if ( arg[0] == undefined || jQuery.nodeName(arg, "form") || arg.options ) r.push( arg ); else r = jQuery.merge( r, arg ); @@ -1542,35 +1553,7 @@ jQuery.extend({ }, attr: function(elem, name, value){ - var fix = jQuery.isXMLDoc(elem) ? {} : { - "for": "htmlFor", - "class": "className", - "float": jQuery.browser.msie ? "styleFloat" : "cssFloat", - cssFloat: jQuery.browser.msie ? "styleFloat" : "cssFloat", - innerHTML: "innerHTML", - className: "className", - value: "value", - disabled: "disabled", - checked: "checked", - readonly: "readOnly", - selected: "selected" - }; - - // IE actually uses filters for opacity ... elem is actually elem.style - if ( name == "opacity" && jQuery.browser.msie ) { - if ( value != undefined ) { - // IE has trouble with opacity if it does not have layout - // Force it by setting the zoom level - elem.zoom = 1; - - // Set the alpha filter to set the opacity - elem.filter = (elem.filter || "").replace(/alpha\([^)]*\)/,"") + - (parseFloat(value).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")"); - } - - return elem.filter ? - (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() : ""; - } + var fix = jQuery.isXMLDoc(elem) ? {} : jQuery.props; // Certain attributes only work when accessed via the old DOM 0 way if ( fix[name] ) { @@ -1582,6 +1565,8 @@ jQuery.extend({ // IE elem.getAttribute passes even for style else if ( elem.tagName ) { + + if ( value != undefined ) elem.setAttribute( name, value ); if ( jQuery.browser.msie && /href|src/.test(name) && !jQuery.isXMLDoc(elem) ) return elem.getAttribute( name, 2 ); @@ -1589,6 +1574,21 @@ jQuery.extend({ // elem is actually elem.style ... set the style } else { + // IE actually uses filters for opacity + if ( name == "opacity" && jQuery.browser.msie ) { + if ( value != undefined ) { + // IE has trouble with opacity if it does not have layout + // Force it by setting the zoom level + elem.zoom = 1; + + // Set the alpha filter to set the opacity + elem.filter = (elem.filter || "").replace(/alpha\([^)]*\)/,"") + + (parseFloat(value).toString() == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")"); + } + + return elem.filter ? + (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100).toString() : ""; + } name = name.replace(/-([a-z])/ig,function(z,b){return b.toUpperCase();}); if ( value != undefined ) elem[name] = value; return elem[name]; @@ -1631,24 +1631,16 @@ jQuery.extend({ }, /** - * Merge two arrays together, removing all duplicates. - * - * The result is the altered first argument with - * the unique elements from the second array added. + * Merge two arrays together by concatenating them. * * @example $.merge( [0,1,2], [2,3,4] ) - * @result [0,1,2,3,4] - * @desc Merges two arrays, removing the duplicate 2 - * - * @example var array = [3,2,1]; - * $.merge( array, [4,3,2] ) - * @result array == [3,2,1,4] - * @desc Merges two arrays, removing the duplicates 3 and 2 + * @result [0,1,2,2,3,4] + * @desc Merges two arrays. * * @name $.merge * @type Array - * @param Array first The first array to merge, the unique elements of second added. - * @param Array second The second array to merge into the first, unaltered. + * @param Array first The first array to merge, the elements of second are added. + * @param Array second The second array to append to the first, unaltered. * @cat JavaScript */ merge: function(first, second) { @@ -1659,11 +1651,23 @@ jQuery.extend({ return first; }, + /** + * Reduce an array (of jQuery objects only) to its unique elements. + * + * @example $.unique( [x1, x2, x3, x2, x3] ) + * @result [x1, x2, x3] + * @desc Reduces the arrays of jQuery objects to unique elements by removing the duplicates of x2 and x3 + * + * @name $.unique + * @type Array + * @param Array array The array to reduce to its unique jQuery objects. + * @cat JavaScript + */ unique: function(first) { var r = [], num = jQuery.mergeNum++; for ( var i = 0, fl = first.length; i < fl; i++ ) - if ( first[i].mergeNum != num ) { + if ( num != first[i].mergeNum ) { first[i].mergeNum = num; r.push(first[i]); } @@ -1753,7 +1757,7 @@ jQuery.extend({ if ( typeof fn == "string" ) fn = new Function("a","return " + fn); - var result = [], r = []; + var result = []; // Go through the array, translating each of the items to their // new value (or values). @@ -1807,6 +1811,7 @@ new function() { // Figure out what browser is being used jQuery.browser = { + version: (b.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], safari: /webkit/.test(b), opera: /opera/.test(b), msie: /msie/.test(b) && !/opera/.test(b), @@ -1815,6 +1820,24 @@ new function() { // Check to see if the W3C box model is being used jQuery.boxModel = !jQuery.browser.msie || document.compatMode == "CSS1Compat"; + + jQuery.styleFloat = jQuery.browser.msie ? "styleFloat" : "cssFloat", + + jQuery.props = { + "for": "htmlFor", + "class": "className", + "float": jQuery.styleFloat, + cssFloat: jQuery.styleFloat, + styleFloat: jQuery.styleFloat, + innerHTML: "innerHTML", + className: "className", + value: "value", + disabled: "disabled", + checked: "checked", + readonly: "readOnly", + selected: "selected", + maxlength: "maxLength" + }; }; /**