Bug Tracker

Changeset 812

Show
Ignore:
Timestamp:
12/31/06 05:22:06 (2 years ago)
Author:
john
Message:

Moved the bulk of the selector code out into a separate file, changed the build files to represent this.

Location:
trunk/jquery
Files:
2 added
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/jquery/build.xml

    r629 r812  
    4747            <fileset dir="${SRC_DIR}" includes="intro.js" /> 
    4848            <fileset dir="${SRC_DIR}" includes="jquery/jquery.js" /> 
     49            <fileset dir="${SRC_DIR}" includes="selector/selector.js" /> 
    4950            <fileset dir="${SRC_DIR}" includes="event/event.js" /> 
    5051            <fileset dir="${SRC_DIR}" includes="fx/fx.js" /> 
  • trunk/jquery/Makefile

    r629 r812  
    99 
    1010BASE_FILES = ${SRC_DIR}/jquery/jquery.js\ 
     11    ${SRC_DIR}/selector/selector.js\ 
    1112    ${SRC_DIR}/event/event.js\ 
    1213    ${SRC_DIR}/fx/fx.js\ 
  • trunk/jquery/src/jquery/jquery.js

    r811 r812  
    13991399        return r; 
    14001400    }, 
    1401  
    1402     /** 
    1403      * A handy, and fast, way to traverse in a particular direction and find 
    1404      * a specific element. 
    1405      * 
    1406      * @private 
    1407      * @name $.nth 
    1408      * @type DOMElement 
    1409      * @param DOMElement cur The element to search from. 
    1410      * @param Number|String num The Nth result to match. Can be a number or a string (like 'even' or 'odd'). 
    1411      * @param String dir The direction to move in (pass in something like 'previousSibling' or 'nextSibling'). 
    1412      * @cat DOM/Traversing 
    1413      */ 
    1414     nth: function(cur,result,dir){ 
    1415         result = result || 1; 
    1416         var num = 0; 
    1417         for ( ; cur; cur = cur[dir] ) { 
    1418             if ( cur.nodeType == 1 ) num++; 
    1419             if ( num == result || result == "even" && num % 2 == 0 && num > 1 || 
    1420                 result == "odd" && num % 2 == 1 ) return cur; 
    1421         } 
    1422     }, 
    1423  
    1424     expr: { 
    1425         "": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()", 
    1426         "#": "a.getAttribute('id')==m[2]", 
    1427         ":": { 
    1428             // Position Checks 
    1429             lt: "i<m[3]-0", 
    1430             gt: "i>m[3]-0", 
    1431             nth: "m[3]-0==i", 
    1432             eq: "m[3]-0==i", 
    1433             first: "i==0", 
    1434             last: "i==r.length-1", 
    1435             even: "i%2==0", 
    1436             odd: "i%2", 
    1437  
    1438             // Child Checks 
    1439             "nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling')==a", 
    1440             "first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a", 
    1441             "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a", 
    1442             "only-child": "jQuery.sibling(a.parentNode.firstChild).length==1", 
    1443  
    1444             // Parent Checks 
    1445             parent: "a.childNodes.length", 
    1446             empty: "!a.childNodes.length", 
    1447  
    1448             // Text Check 
    1449             contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0", 
    1450  
    1451             // Visibility 
    1452             visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'", 
    1453             hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'", 
    1454  
    1455             // Form attributes 
    1456             enabled: "!a.disabled", 
    1457             disabled: "a.disabled", 
    1458             checked: "a.checked", 
    1459             selected: "a.selected || jQuery.attr(a, 'selected')", 
    1460  
    1461             // Form elements 
    1462             text: "a.type=='text'", 
    1463             radio: "a.type=='radio'", 
    1464             checkbox: "a.type=='checkbox'", 
    1465             file: "a.type=='file'", 
    1466             password: "a.type=='password'", 
    1467             submit: "a.type=='submit'", 
    1468             image: "a.type=='image'", 
    1469             reset: "a.type=='reset'", 
    1470             button: "a.type=='button'||a.nodeName=='BUTTON'", 
    1471             input: "/input|select|textarea|button/i.test(a.nodeName)" 
    1472         }, 
    1473         ".": "jQuery.className.has(a,m[2])", 
    1474         "@": { 
    1475             "=": "z==m[4]", 
    1476             "!=": "z!=m[4]", 
    1477             "^=": "z && !z.indexOf(m[4])", 
    1478             "$=": "z && z.substr(z.length - m[4].length,m[4].length)==m[4]", 
    1479             "*=": "z && z.indexOf(m[4])>=0", 
    1480             "": "z", 
    1481             _resort: function(m){ 
    1482                 return ["", m[1], m[3], m[2], m[5]]; 
    1483             }, 
    1484             _prefix: "z=jQuery.attr(a,m[3]);" 
    1485         }, 
    1486         "[": "jQuery.find(m[2],a).length" 
    1487     }, 
    1488  
    1489     /** 
    1490      * All elements on a specified axis. 
    1491      * 
    1492      * @private 
    1493      * @name $.sibling 
    1494      * @type Array 
    1495      * @param Element elem The element to find all the siblings of (including itself). 
    1496      * @cat DOM/Traversing 
    1497      */ 
    1498     sibling: function( n, elem ) { 
    1499         var r = []; 
    1500  
    1501         for ( ; n; n = n.nextSibling ) { 
    1502             if ( n.nodeType == 1 && (!elem || n != elem) ) 
    1503                 r.push( n ); 
    1504         } 
    1505  
    1506         return r; 
    1507     }, 
    1508  
    1509     token: [ 
    1510         "\\.\\.|/\\.\\.", "a.parentNode", 
    1511         ">|/", "jQuery.sibling(a.firstChild)", 
    1512         "\\+", "jQuery.nth(a,2,'nextSibling')", 
    1513         "~", function(a){ 
    1514             var s = jQuery.sibling(a.parentNode.firstChild); 
    1515             return s.slice(0, jQuery.inArray(a,s)); 
    1516         } 
    1517     ], 
    1518  
    1519     /** 
    1520      * @name $.find 
    1521      * @type Array<Element> 
    1522      * @private 
    1523      * @cat Core 
    1524      */ 
    1525     find: function( t, context ) { 
    1526         // Quickly handle non-string expressions 
    1527         if ( typeof t != "string" ) 
    1528             return [ t ]; 
    1529  
    1530         // Make sure that the context is a DOM Element 
    1531         if ( context && context.nodeType == undefined ) 
    1532             context = null; 
    1533  
    1534         // Set the correct context (if none is provided) 
    1535         context = context || document; 
    1536  
    1537         // Handle the common XPath // expression 
    1538         if ( !t.indexOf("//") ) { 
    1539             context = context.documentElement; 
    1540             t = t.substr(2,t.length); 
    1541  
    1542         // And the / root expression 
    1543         } else if ( !t.indexOf("/") ) { 
    1544             context = context.documentElement; 
    1545             t = t.substr(1,t.length); 
    1546             if ( t.indexOf("/") >= 1 ) 
    1547                 t = t.substr(t.indexOf("/"),t.length); 
    1548         } 
    1549  
    1550         // Initialize the search 
    1551         var ret = [context], done = [], last = null; 
    1552  
    1553         // Continue while a selector expression exists, and while 
    1554         // we're no longer looping upon ourselves 
    1555         while ( t && last != t ) { 
    1556             var r = []; 
    1557             last = t; 
    1558  
    1559             t = jQuery.trim(t).replace( /^\/\//i, "" ); 
    1560  
    1561             var foundToken = false; 
    1562  
    1563             // An attempt at speeding up child selectors that 
    1564             // point to a specific element tag 
    1565             var re = /^[\/>]\s*([a-z0-9*-]+)/i; 
    1566             var m = re.exec(t); 
    1567  
    1568             if ( m ) { 
    1569                 // Perform our own iteration and filter 
    1570                 for ( var i = 0, rl = ret.length; i < rl; i++ ) 
    1571                     for ( var c = ret[i].firstChild; c; c = c.nextSibling ) 
    1572                         if ( c.nodeType == 1 && ( c.nodeName == m[1].toUpperCase() || m[1] == "*" ) ) 
    1573                             r.push( c ); 
    1574  
    1575                 ret = r; 
    1576                 t = jQuery.trim( t.replace( re, "" ) ); 
    1577                 foundToken = true; 
    1578             } else { 
    1579                 // Look for pre-defined expression tokens 
    1580                 for ( var i = 0; i < jQuery.token.length; i += 2 ) { 
    1581                     // Attempt to match each, individual, token in 
    1582                     // the specified order 
    1583                     var re = new RegExp("^(" + jQuery.token[i] + ")"); 
    1584                     var m = re.exec(t); 
    1585  
    1586                     // If the token match was found 
    1587                     if ( m ) { 
    1588                         // Map it against the token's handler 
    1589                         r = ret = jQuery.map( ret, jQuery.token[i+1].constructor == Function ? 
    1590                             jQuery.token[i+1] : 
    1591                             function(a){ return eval(jQuery.token[i+1]); }); 
    1592  
    1593                         // And remove the token 
    1594                         t = jQuery.trim( t.replace( re, "" ) ); 
    1595                         foundToken = true; 
    1596                         break; 
    1597                     } 
    1598                 } 
    1599             } 
    1600  
    1601             // See if there's still an expression, and that we haven't already 
    1602             // matched a token 
    1603             if ( t && !foundToken ) { 
    1604                 // Handle multiple expressions 
    1605                 if ( !t.indexOf(",") || !t.indexOf("|") ) { 
    1606                     // Clean teh result set 
    1607                     if ( ret[0] == context ) ret.shift(); 
    1608  
    1609                     // Merge the result sets 
    1610                     jQuery.merge( done, ret ); 
    1611  
    1612                     // Reset the context 
    1613                     r = ret = [context]; 
    1614  
    1615                     // Touch up the selector string 
    1616                     t = " " + t.substr(1,t.length); 
    1617  
    1618                 } else { 
    1619                     // Optomize for the case nodeName#idName 
    1620                     var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i; 
    1621                     var m = re2.exec(t); 
    1622                      
    1623                     // Re-organize the results, so that they're consistent 
    1624                     if ( m ) { 
    1625                        m = [ 0, m[2], m[3], m[1] ]; 
    1626  
    1627                     } else { 
    1628                         // Otherwise, do a traditional filter check for 
    1629                         // ID, class, and element selectors 
    1630                         re2 = /^([#.]?)([a-z0-9\\*_-]*)/i; 
    1631                         m = re2.exec(t); 
    1632                     } 
    1633  
    1634                     // Try to do a global search by ID, where we can 
    1635                     if ( m[1] == "#" && ret[ret.length-1].getElementById ) { 
    1636                         // Optimization for HTML document case 
    1637                         var oid = ret[ret.length-1].getElementById(m[2]); 
    1638  
    1639                         // Do a quick check for node name (where applicable) so 
    1640                         // that div#foo searches will be really fast 
    1641                         ret = r = oid &&  
    1642                           (!m[3] || oid.nodeName == m[3].toUpperCase()) ? [oid] : []; 
    1643  
    1644                     // Use the DOM 0 shortcut for the body element 
    1645                     } else if ( m[1] == "" && m[2] == "body" ) { 
    1646                         ret = r = [ document.body ]; 
    1647  
    1648                     } else { 
    1649                         // Pre-compile a regular expression to handle class searches 
    1650                         if ( m[1] == "." ) 
    1651                             var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)"); 
    1652  
    1653                         // We need to find all descendant elements, it is more 
    1654                         // efficient to use getAll() when we are already further down 
    1655                         // the tree - we try to recognize that here 
    1656                         for ( var i = 0, rl = ret.length; i < rl; i++ ) 
    1657                             jQuery.merge( r, 
    1658                                 m[1] != "" && ret.length != 1 ? 
    1659                                     jQuery.getAll( ret[i], [], m[1], m[2], rec ) : 
    1660                                     ret[i].getElementsByTagName( m[1] != "" || m[0] == "" ? "*" : m[2] ) 
    1661                             ); 
    1662  
    1663                         // It's faster to filter by class and be done with it 
    1664                         if ( m[1] == "." && ret.length == 1 ) 
    1665                             r = jQuery.grep( r, function(e) { 
    1666                                 return rec.test(e.className); 
    1667                             }); 
    1668  
    1669                         // Same with ID filtering 
    1670                         if ( m[1] == "#" && ret.length == 1 ) { 
    1671                             // Remember, then wipe out, the result set 
    1672                             var tmp = r; 
    1673                             r = []; 
    1674  
    1675                             // Then try to find the element with the ID 
    1676                             for ( var i = 0, tl = tmp.length; i < tl; i++ ) 
    1677                                 if ( tmp[i].getAttribute("id") == m[2] ) { 
    1678                                     r = [ tmp[i] ]; 
    1679                                     break; 
    1680                                 } 
    1681                         } 
    1682  
    1683                         ret = r; 
    1684                     } 
    1685  
    1686                     t = t.replace( re2, "" ); 
    1687                 } 
    1688  
    1689             } 
    1690  
    1691             // If a selector string still exists 
    1692             if ( t ) { 
    1693                 // Attempt to filter it 
    1694                 var val = jQuery.filter(t,r); 
    1695                 ret = r = val.r; 
    1696                 t = jQuery.trim(val.t); 
    1697             } 
    1698         } 
    1699  
    1700         // Remove the root context 
    1701         if ( ret && ret[0] == context ) ret.shift(); 
    1702  
    1703         // And combine the results 
    1704         jQuery.merge( done, ret ); 
    1705  
    1706         return done; 
    1707     }, 
    1708  
    1709     getAll: function( o, r, token, name, re ) { 
    1710         for ( var s = o.firstChild; s; s = s.nextSibling ) 
    1711             if ( s.nodeType == 1 ) { 
    1712                 var add = true; 
    1713  
    1714                 if ( token == "." ) 
    1715                     add = s.className && re.test(s.className); 
    1716                 else if ( token == "#" ) 
    1717                     add = s.getAttribute('id') == name; 
    17181401     
    1719                 if ( add ) 
    1720                     r.push( s ); 
    1721  
    1722                 if ( token == "#" && r.length ) break; 
    1723  
    1724                 if ( s.firstChild ) 
    1725                     jQuery.getAll( s, r, token, name, re ); 
    1726             } 
    1727  
    1728         return r; 
    1729     }, 
    1730  
    17311402    attr: function(elem, name, value){ 
    17321403        var fix = { 
     
    17821453        } 
    17831454    }, 
    1784  
    1785     // The regular expressions that power the parsing engine 
    1786     parse: [ 
    1787         // Match: [@value='test'], [@foo] 
    1788         "\\[ *(@)S *([!*$^=]*) *('?\"?)(.*?)\\4 *\\]", 
    1789  
    1790         // Match: [div], [div p] 
    1791         "(\\[)\\s*(.*?)\\s*\\]", 
    1792  
    1793         // Match: :contains('foo') 
    1794         "(:)S\\(\"?'?([^\\)]*?)\"?'?\\)", 
    1795  
    1796         // Match: :even, :last-chlid 
    1797         "([:.#]*)S" 
    1798     ], 
    1799  
    1800     filter: function(t,r,not) { 
    1801         // Look for common filter expressions 
    1802         while ( t && /^[a-z[({<*:.#]/i.test(t) ) { 
    1803  
    1804             var p = jQuery.parse; 
    1805  
    1806             for ( var i = 0, pl = p.length; i < pl; i++ ) { 
    1807          
    1808                 // Look for, and replace, string-like sequences 
    1809                 // and finally build a regexp out of it 
    1810                 var re = new RegExp( 
    1811                     "^" + p[i].replace("S", "([a-z*_-][a-z0-9_-]*)"), "i" ); 
    1812  
    1813                 var m = re.exec( t ); 
    1814  
    1815                 if ( m ) { 
    1816                     // Re-organize the first match 
    1817                     if ( jQuery.expr[ m[1] ]._resort ) 
    1818                         m = jQuery.expr[ m[1] ]._resort( m ); 
    1819  
    1820                     // Remove what we just matched 
    1821                     t = t.replace( re, "" ); 
    1822  
    1823                     break; 
    1824                 } 
    1825             } 
    1826  
    1827             // :not() is a special case that can be optimized by 
    1828             // keeping it out of the expression list 
    1829             if ( m[1] == ":" && m[2] == "not" ) 
    1830                 r = jQuery.filter(m[3], r, true).r; 
    1831  
    1832             // Handle classes as a special case (this will help to 
    1833             // improve the speed, as the regexp will only be compiled once) 
    1834             else if ( m[1] == "." ) { 
    1835  
    1836                 var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)"); 
    1837                 r = jQuery.grep( r, function(e){ 
    1838                     return re.test(e.className || ''); 
    1839                 }, not); 
    1840  
    1841             // Otherwise, find the expression to execute 
    1842             } else { 
    1843                 var f = jQuery.expr[m[1]]; 
    1844                 if ( typeof f != "string" ) 
    1845                     f = jQuery.expr[m[1]][m[2]]; 
    1846  
    1847                 // Build a custom macro to enclose it 
    1848                 eval("f = function(a,i){" + 
    1849                     ( jQuery.expr[ m[1] ]._prefix || "" ) + 
    1850                     "return " + f + "}"); 
    1851  
    1852                 // Execute it against the current filter 
    1853                 r = jQuery.grep( r, f, not ); 
    1854             } 
    1855         } 
    1856  
    1857         // Return an array of filtered elements (r) 
    1858         // and the modified expression string (t) 
    1859         return { r: r, t: t }; 
    1860     }, 
    1861  
     1455     
    18621456    /** 
    18631457     * Remove the whitespace from the beginning and end of a string. 
     
    18731467    trim: function(t){ 
    18741468        return t.replace(/^\s+|\s+$/g, ""); 
    1875     }, 
    1876  
    1877     /** 
    1878      * All ancestors of a given element. 
    1879      * 
    1880      * @private 
    1881      * @name $.parents 
    1882      * @type Array<Element> 
    1883      * @param Element elem The element to find the ancestors of. 
    1884      * @cat DOM/Traversing 
    1885      */ 
    1886     parents: function( elem ){ 
    1887         var matched = []; 
    1888         var cur = elem.parentNode; 
    1889         while ( cur && cur != document ) { 
    1890             matched.push( cur ); 
    1891             cur = cur.parentNode; 
    1892         } 
    1893         return matched; 
    18941469    }, 
    18951470