jQuery.merge speedup, bug#444
authorDave Methvin <dave.methvin@gmail.com>
Tue, 19 Dec 2006 04:31:33 +0000 (04:31 +0000)
committerDave Methvin <dave.methvin@gmail.com>
Tue, 19 Dec 2006 04:31:33 +0000 (04:31 +0000)
<tbody> duplicated, bug#418 (jQuery.clean & domManip)
query for id in context ignores context, bug#267

src/jquery/coreTest.js
src/jquery/jquery.js

index be39a87..25fd4dd 100644 (file)
@@ -331,11 +331,15 @@ test("expressions - element", function() {
 });\r
 \r
 test("expressions - id", function() {\r
-       expect(5);\r
+       expect(8);\r
        t( "ID Selector", "#body", ["body"] );\r
        t( "ID Selector w/ Element", "body#body", ["body"] );\r
        t( "ID Selector w/ Element", "ul#first", [] );\r
        \r
+       t( "ID Selector, child ID present", "#form > #radio1", ["radio1"] );  // bug #267\r
+       t( "ID Selector, not an ancestor ID", "#form  #first", [] );\r
+       t( "ID Selector, not a child ID", "#form > #option1a", [] );\r
+       \r
        t( "All Children of ID", "#foo/*", ["sndp", "en", "sap"]  );\r
        t( "All Children of ID with no children", "#firstUL/*", []  );\r
 });\r
index e48f721..d3ed8c6 100644 (file)
@@ -988,33 +988,27 @@ jQuery.fn = jQuery.prototype = {
         * @private\r
         * @name domManip\r
         * @param Array args\r
-        * @param Boolean table\r
-        * @param Number dir\r
+        * @param Boolean table Insert TBODY in TABLEs if one is not found.\r
+        * @param Number dir If dir<0, process args in reverse order.\r
         * @param Function fn The function doing the DOM manipulation.\r
         * @type jQuery\r
         * @cat Core\r
         */\r
        domManip: function(args, table, dir, fn){\r
-               var clone = this.size() > 1;\r
+               var clone = this.length > 1; \r
                var a = jQuery.clean(args);\r
+               if ( dir < 0 )\r
+                       a.reverse();\r
 \r
                return this.each(function(){\r
                        var obj = this;\r
 \r
-                       if ( table && this.nodeName.toUpperCase() == "TABLE" && a[0].nodeName.toUpperCase() != "THEAD" ) {\r
-                               var tbody = this.getElementsByTagName("tbody");\r
+                       if ( table && this.nodeName.toUpperCase() == "TABLE" && a[0].nodeName.toUpperCase() == "TR" )\r
+                               obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody"));\r
 \r
-                               if ( !tbody.length ) {\r
-                                       obj = document.createElement("tbody");\r
-                                       this.appendChild( obj );\r
-                               } else\r
-                                       obj = tbody[0];\r
-                       }\r
+                       for ( var i=0; i < a.length; i++ )\r
+                               fn.apply( obj, [ clone ? a[i].cloneNode(true) : a[i] ] );\r
 \r
-                       for ( var i = ( dir < 0 ? a.length - 1 : 0 );\r
-                               i != ( dir < 0 ? dir : a.length ); i += dir ) {\r
-                                       fn.apply( obj, [ clone ? a[i].cloneNode(true) : a[i] ] );\r
-                       }\r
                });\r
        },\r
 \r
@@ -1337,26 +1331,44 @@ jQuery.extend({
                return ret;\r
        },\r
        \r
-       clean: function(a) {\r
+               clean: function(a) {\r
                var r = [];\r
                for ( var i = 0; i < a.length; i++ ) {\r
                        var arg = a[i];\r
                        if ( typeof arg == "string" ) { // Convert html string into DOM nodes\r
                                // Trim whitespace, otherwise indexOf won't work as expected\r
-                               var s = jQuery.trim(arg), div = document.createElement("div"), wrap = [0,"",""];\r
+                               var s = jQuery.trim(arg), s3 = s.substring(0,3), s6 = s.substring(0,6),\r
+                                       div = document.createElement("div"), wrap = [0,"",""];\r
 \r
-                               if ( !s.indexOf("<opt") ) // option or optgroup\r
+                               if ( s.substring(0,4) == "<opt" ) // option or optgroup\r
                                        wrap = [1, "<select>", "</select>"];\r
-                               else if ( !s.indexOf("<thead") || !s.indexOf("<tbody") )\r
+                               else if ( s6 == "<thead" || s6 == "<tbody" || s6 == "<tfoot" )\r
                                        wrap = [1, "<table>", "</table>"];\r
-                               else if ( !s.indexOf("<tr") )\r
-                                       wrap = [2, "<table>", "</table>"];      // tbody auto-inserted\r
-                               else if ( !s.indexOf("<td") || !s.indexOf("<th") )\r
+                               else if ( s3 == "<tr" )\r
+                                       wrap = [2, "<table><tbody>", "</tbody></table>"];\r
+                               else if ( s3 == "<td" || s3 == "<th" ) // <thead> matched above\r
                                        wrap = [3, "<table><tbody><tr>", "</tr></tbody></table>"];\r
 \r
                                // Go to html and back, then peel off extra wrappers\r
                                div.innerHTML = wrap[1] + s + wrap[2];\r
                                while ( wrap[0]-- ) div = div.firstChild;\r
+                               \r
+                               // Remove IE's autoinserted <tbody> from table fragments\r
+                               if ( jQuery.browser.msie ) {\r
+                                       var tb = null;\r
+                                       // String was a <table>, *may* have spurious <tbody>\r
+                                       if ( s6 == "<table" && s.indexOf("<tbody") < 0 ) \r
+                                               tb = div.firstChild && div.firstChild.childNodes;\r
+                                       // String was a bare <thead> or <tfoot>\r
+                                       else if ( wrap[1] == "<table>" && s.indexOf("<tbody") < 0 )\r
+                                               tb = div.childNodes;\r
+                                       if ( tb ) {\r
+                                               for ( var n = tb.length-1; n >= 0 ; --n )\r
+                                                       if ( tb[n].nodeName.toUpperCase() == "TBODY" && !tb[n].childNodes.length )\r
+                                                               tb[n].parentNode.removeChild(tb[n]);\r
+                                       }\r
+                               }\r
+                               \r
                                arg = div.childNodes;\r
                        } \r
                        \r
@@ -1373,7 +1385,7 @@ jQuery.extend({
 \r
        expr: {\r
                "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",\r
-               "#": "a.getAttribute('id')&&a.getAttribute('id')==m[2]",\r
+               "#": "a.getAttribute('id')==m[2]",\r
                ":": {\r
                        // Position Checks\r
                        lt: "i<m[3]-0",\r
@@ -1504,13 +1516,13 @@ jQuery.extend({
                                        var re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;\r
                                        var m = re2.exec(t);\r
 \r
-                                       if ( m[1] == "#" ) {\r
-                                               // Ummm, should make this work in all XML docs\r
-                                               var oid = document.getElementById(m[2]);\r
+                                       if ( m[1] == "#" && ret[ret.length-1].getElementById ) {\r
+                                               // Optimization for HTML document case\r
+                                               var oid = ret[ret.length-1].getElementById(m[2]);\r
                                                r = ret = oid ? [oid] : [];\r
                                                t = t.replace( re2, "" );\r
                                        } else {\r
-                                               if ( !m[2] || m[1] == "." ) m[2] = "*";\r
+                                               if ( !m[2] || m[1] == "." || m[1] == "#" ) m[2] = "*";\r
 \r
                                                for ( var i = 0; i < ret.length; i++ )\r
                                                        r = jQuery.merge( r,\r
@@ -1754,19 +1766,15 @@ jQuery.extend({
                for ( var k = 0; k < first.length; k++ )\r
                        result[k] = first[k];\r
 \r
-               // Now check for duplicates between a and b and only\r
-               // add the unique items\r
+               // Now check for duplicates between a and b\r
+               // and only add the unique items\r
+          DupCheck:\r
                for ( var i = 0; i < second.length; i++ ) {\r
-                       var noCollision = true;\r
-\r
-                       // The collision-checking process\r
                        for ( var j = 0; j < first.length; j++ )\r
                                if ( second[i] == first[j] )\r
-                                       noCollision = false;\r
-\r
-                       // If the item is unique, add it\r
-                       if ( noCollision )\r
-                               result.push( second[i] );\r
+                                       continue DupCheck;\r
+                       // The item is unique, add it\r
+                       result.push( second[i] );\r
                }\r
 \r
                return result;\r