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

This commit is contained in:
John Resig 2006-12-31 05:22:06 +00:00
parent 370c6d564a
commit c3d8cb0c09
4 changed files with 490 additions and 487 deletions

View file

@ -8,6 +8,7 @@ DIST_DIR = ${PREFIX}/dist
PLUG_DIR = ../plugins PLUG_DIR = ../plugins
BASE_FILES = ${SRC_DIR}/jquery/jquery.js\ BASE_FILES = ${SRC_DIR}/jquery/jquery.js\
${SRC_DIR}/selector/selector.js\
${SRC_DIR}/event/event.js\ ${SRC_DIR}/event/event.js\
${SRC_DIR}/fx/fx.js\ ${SRC_DIR}/fx/fx.js\
${SRC_DIR}/ajax/ajax.js ${SRC_DIR}/ajax/ajax.js

123
build.xml
View file

@ -14,18 +14,18 @@
3. Execute the standard jquery and packed targets to build your distribution 3. Execute the standard jquery and packed targets to build your distribution
TODO Using this build file to create docs for a single plugin TODO Using this build file to create docs for a single plugin
--> -->
<!-- SETUP --> <!-- SETUP -->
<property description="Source Folder" name="SRC_DIR" value="src" /> <property description="Source Folder" name="SRC_DIR" value="src" />
<property description="Files for parsing etc." name="BUILD_DIR" value="build" /> <property description="Files for parsing etc." name="BUILD_DIR" value="build" />
<property description="Rhino JS Engine" name="JAR" value="${BUILD_DIR}/js.jar" /> <property description="Rhino JS Engine" name="JAR" value="${BUILD_DIR}/js.jar" />
<property description="Dir to look for plugins" name="PLUGIN_DIR" location="../plugins" /> <property description="Dir to look for plugins" name="PLUGIN_DIR" location="../plugins" />
<property description="Add single plugins here" name="PLUGINS" value="none" /> <property description="Add single plugins here" name="PLUGINS" value="none" />
<property description="Add all plugins here" name="PLUGINS_ALL" <property description="Add all plugins here" name="PLUGINS_ALL"
value="button/*.js,center/*.js,cookie/*.js,form/*.js,greybox/*.js,interface/*.js,pager/*.js,tablesorter/*.js,tabs/*.js,tooltip/*.js,accordion/*.js" /> value="button/*.js,center/*.js,cookie/*.js,form/*.js,greybox/*.js,interface/*.js,pager/*.js,tablesorter/*.js,tabs/*.js,tooltip/*.js,accordion/*.js" />
<property description="Target parent folder for built files" name="PREFIX" value="." /> <property description="Target parent folder for built files" name="PREFIX" value="." />
<property description="Folder for docs target" name="DOCS_DIR" value="${PREFIX}/docs" /> <property description="Folder for docs target" name="DOCS_DIR" value="${PREFIX}/docs" />
@ -36,20 +36,21 @@
<property name="JQ" value="${DIST_DIR}/jquery.js" /> <property name="JQ" value="${DIST_DIR}/jquery.js" />
<property name="JQ_LITE" value="${DIST_DIR}/jquery.lite.js" /> <property name="JQ_LITE" value="${DIST_DIR}/jquery.lite.js" />
<property name="JQ_MIN" value="${DIST_DIR}/jquery.min.js" /> <property name="JQ_MIN" value="${DIST_DIR}/jquery.min.js" />
<property name="JQ_PACK" value="${DIST_DIR}/jquery.pack.js" /> <property name="JQ_PACK" value="${DIST_DIR}/jquery.pack.js" />
<!-- MAIN --> <!-- MAIN -->
<target name="jquery" description="Main jquery build, set PLUGINS property to include plugins"> <target name="jquery" description="Main jquery build, set PLUGINS property to include plugins">
<echo message="Building ${JQ}" /> <echo message="Building ${JQ}" />
<mkdir dir="${DIST_DIR}" /> <mkdir dir="${DIST_DIR}" />
<concat destfile="${JQ}"> <concat destfile="${JQ}">
<fileset dir="${SRC_DIR}" includes="intro.js" /> <fileset dir="${SRC_DIR}" includes="intro.js" />
<fileset dir="${SRC_DIR}" includes="jquery/jquery.js" /> <fileset dir="${SRC_DIR}" includes="jquery/jquery.js" />
<fileset dir="${SRC_DIR}" includes="selector/selector.js" />
<fileset dir="${SRC_DIR}" includes="event/event.js" /> <fileset dir="${SRC_DIR}" includes="event/event.js" />
<fileset dir="${SRC_DIR}" includes="fx/fx.js" /> <fileset dir="${SRC_DIR}" includes="fx/fx.js" />
<fileset dir="${SRC_DIR}" includes="ajax/ajax.js" /> <fileset dir="${SRC_DIR}" includes="ajax/ajax.js" />
<fileset dir="${PLUGIN_DIR}" includes="${PLUGINS}" /> <fileset dir="${PLUGIN_DIR}" includes="${PLUGINS}" />
<fileset dir="${SRC_DIR}" includes="outro.js" /> <fileset dir="${SRC_DIR}" includes="outro.js" />
</concat> </concat>
<echo message="${JQ} built." /> <echo message="${JQ} built." />
@ -58,7 +59,7 @@
<target name="jquery_with_plugins" description="Build jquery with all plugins, useful to full documentation"> <target name="jquery_with_plugins" description="Build jquery with all plugins, useful to full documentation">
<antcall target="jquery"> <antcall target="jquery">
<param name="PLUGINS" value="${PLUGINS_ALL}" /> <param name="PLUGINS" value="${PLUGINS_ALL}" />
</antcall> </antcall>
</target> </target>
<target name="lite" depends="jquery" description="Remove all /** */ comments"> <target name="lite" depends="jquery" description="Remove all /** */ comments">
@ -89,24 +90,24 @@
<arg value="${JQ_PACK}" /> <arg value="${JQ_PACK}" />
</java> </java>
<echo message="${JQ_PACK} built." /> <echo message="${JQ_PACK} built." />
</target> </target>
<target name="pack_with_plugins" depends="jquery_with_plugins" description="Pack jquery with all plugins, not very useful"> <target name="pack_with_plugins" depends="jquery_with_plugins" description="Pack jquery with all plugins, not very useful">
<echo message="Building ${JQ_PACK}" /> <echo message="Building ${JQ_PACK}" />
<java jar="${JAR}" fork="true"> <java jar="${JAR}" fork="true">
<arg value="${BUILD_DIR}/build/pack.js" /> <arg value="${BUILD_DIR}/build/pack.js" />
<arg value="${JQ}" /> <arg value="${JQ}" />
<arg value="${JQ_PACK}" /> <arg value="${JQ_PACK}" />
</java> </java>
<echo message="${JQ_PACK} built." /> <echo message="${JQ_PACK} built." />
</target> </target>
<target name="test" depends="jquery" description="Copy files for the test suite into their own directory."> <target name="test" depends="jquery" description="Copy files for the test suite into their own directory.">
<echo message="Building Test Suite" /> <echo message="Building Test Suite" />
<delete dir="${TEST_DIR}" /> <delete dir="${TEST_DIR}" />
<mkdir dir="${TEST_DIR}/data" /> <mkdir dir="${TEST_DIR}/data" />
<copy todir="${TEST_DIR}/data"> <copy todir="${TEST_DIR}/data">
<fileset dir="${BUILD_DIR}/test/data/" /> <fileset dir="${BUILD_DIR}/test/data/" />
</copy> </copy>
<copy todir="${TEST_DIR}" file="${BUILD_DIR}/test/index.html" /> <copy todir="${TEST_DIR}" file="${BUILD_DIR}/test/index.html" />
<echo message="Test Suite built." /> <echo message="Test Suite built." />
@ -134,31 +135,31 @@
<arg value="${DOCS_DIR}" /> <arg value="${DOCS_DIR}" />
</java> </java>
<echo message="Documentation built." /> <echo message="Documentation built." />
</target> </target>
<!-- TODO refactor to remove duplication with above --> <!-- TODO refactor to remove duplication with above -->
<target name="docs_with_plugins" depends="jquery_with_plugins"> <target name="docs_with_plugins" depends="jquery_with_plugins">
<echo message="Building Documentation" /> <echo message="Building Documentation" />
<delete dir="${DOCS_DIR}" /> <delete dir="${DOCS_DIR}" />
<mkdir dir="${DOCS_DIR}/data" /> <mkdir dir="${DOCS_DIR}/data" />
<copy todir="${DOCS_DIR}" file="${BUILD_DIR}/docs/.htaccess" /> <copy todir="${DOCS_DIR}" file="${BUILD_DIR}/docs/.htaccess" />
<mkdir dir="${DOCS_DIR}/js" /> <mkdir dir="${DOCS_DIR}/js" />
<copy todir="${DOCS_DIR}/js"> <copy todir="${DOCS_DIR}/js">
<fileset dir="${BUILD_DIR}/docs/js"> <fileset dir="${BUILD_DIR}/docs/js">
<include name="**/*.js" /> <include name="**/*.js" />
</fileset> </fileset>
</copy> </copy>
<copy todir="${DOCS_DIR}/style"> <copy todir="${DOCS_DIR}/style">
<fileset dir="${BUILD_DIR}/docs/style"> <fileset dir="${BUILD_DIR}/docs/style">
<include name="**" /> <include name="**" />
</fileset> </fileset>
</copy> </copy>
<java jar="${JAR}" fork="true"> <java jar="${JAR}" fork="true">
<arg value="${BUILD_DIR}/docs/docs.js" /> <arg value="${BUILD_DIR}/docs/docs.js" />
<arg value="${JQ}" /> <arg value="${JQ}" />
<arg value="${DOCS_DIR}" /> <arg value="${DOCS_DIR}" />
</java> </java>
<echo message="Documentation built." /> <echo message="Documentation built." />
</target> </target>
<target name="clean"> <target name="clean">
@ -176,15 +177,15 @@
<property name="TABS" value="${PLUGIN_DIR}/tabs/tabs.js" /> <property name="TABS" value="${PLUGIN_DIR}/tabs/tabs.js" />
<property name="TABS_PACK" value="${DIST_DIR}/jquery.tabs.pack.js" /> <property name="TABS_PACK" value="${DIST_DIR}/jquery.tabs.pack.js" />
<target name="pack_tabs"> <target name="pack_tabs">
<echo message="Building ${TABS_PACK}" /> <echo message="Building ${TABS_PACK}" />
<mkdir dir="${DIST_DIR}" /> <mkdir dir="${DIST_DIR}" />
<java jar="${JAR}" fork="true"> <java jar="${JAR}" fork="true">
<arg value="${BUILD_DIR}/build/pack.js" /> <arg value="${BUILD_DIR}/build/pack.js" />
<arg value="${TABS}" /> <arg value="${TABS}" />
<arg value="${TABS_PACK}" /> <arg value="${TABS_PACK}" />
</java> </java>
<echo message="${TABS_PACK} built." /> <echo message="${TABS_PACK} built." />
</target> </target>
</project> </project>

427
src/jquery/jquery.js vendored
View file

@ -1398,336 +1398,7 @@ jQuery.extend({
return r; return r;
}, },
/**
* A handy, and fast, way to traverse in a particular direction and find
* a specific element.
*
* @private
* @name $.nth
* @type DOMElement
* @param DOMElement cur The element to search from.
* @param Number|String num The Nth result to match. Can be a number or a string (like 'even' or 'odd').
* @param String dir The direction to move in (pass in something like 'previousSibling' or 'nextSibling').
* @cat DOM/Traversing
*/
nth: function(cur,result,dir){
result = result || 1;
var num = 0;
for ( ; cur; cur = cur[dir] ) {
if ( cur.nodeType == 1 ) num++;
if ( num == result || result == "even" && num % 2 == 0 && num > 1 ||
result == "odd" && num % 2 == 1 ) return cur;
}
},
expr: {
"": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",
"#": "a.getAttribute('id')==m[2]",
":": {
// Position Checks
lt: "i<m[3]-0",
gt: "i>m[3]-0",
nth: "m[3]-0==i",
eq: "m[3]-0==i",
first: "i==0",
last: "i==r.length-1",
even: "i%2==0",
odd: "i%2",
// Child Checks
"nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling')==a",
"first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a",
"last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a",
"only-child": "jQuery.sibling(a.parentNode.firstChild).length==1",
// Parent Checks
parent: "a.childNodes.length",
empty: "!a.childNodes.length",
// Text Check
contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0",
// Visibility
visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'",
hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'",
// Form attributes
enabled: "!a.disabled",
disabled: "a.disabled",
checked: "a.checked",
selected: "a.selected || jQuery.attr(a, 'selected')",
// Form elements
text: "a.type=='text'",
radio: "a.type=='radio'",
checkbox: "a.type=='checkbox'",
file: "a.type=='file'",
password: "a.type=='password'",
submit: "a.type=='submit'",
image: "a.type=='image'",
reset: "a.type=='reset'",
button: "a.type=='button'||a.nodeName=='BUTTON'",
input: "/input|select|textarea|button/i.test(a.nodeName)"
},
".": "jQuery.className.has(a,m[2])",
"@": {
"=": "z==m[4]",
"!=": "z!=m[4]",
"^=": "z && !z.indexOf(m[4])",
"$=": "z && z.substr(z.length - m[4].length,m[4].length)==m[4]",
"*=": "z && z.indexOf(m[4])>=0",
"": "z",
_resort: function(m){
return ["", m[1], m[3], m[2], m[5]];
},
_prefix: "z=jQuery.attr(a,m[3]);"
},
"[": "jQuery.find(m[2],a).length"
},
/**
* All elements on a specified axis.
*
* @private
* @name $.sibling
* @type Array
* @param Element elem The element to find all the siblings of (including itself).
* @cat DOM/Traversing
*/
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType == 1 && (!elem || n != elem) )
r.push( n );
}
return r;
},
token: [
"\\.\\.|/\\.\\.", "a.parentNode",
">|/", "jQuery.sibling(a.firstChild)",
"\\+", "jQuery.nth(a,2,'nextSibling')",
"~", function(a){
var s = jQuery.sibling(a.parentNode.firstChild);
return s.slice(0, jQuery.inArray(a,s));
}
],
/**
* @name $.find
* @type Array<Element>
* @private
* @cat Core
*/
find: function( t, context ) {
// Quickly handle non-string expressions
if ( typeof t != "string" )
return [ t ];
// Make sure that the context is a DOM Element
if ( context && context.nodeType == undefined )
context = null;
// Set the correct context (if none is provided)
context = context || document;
// Handle the common XPath // expression
if ( !t.indexOf("//") ) {
context = context.documentElement;
t = t.substr(2,t.length);
// And the / root expression
} else if ( !t.indexOf("/") ) {
context = context.documentElement;
t = t.substr(1,t.length);
if ( t.indexOf("/") >= 1 )
t = t.substr(t.indexOf("/"),t.length);
}
// Initialize the search
var ret = [context], done = [], last = null;
// Continue while a selector expression exists, and while
// we're no longer looping upon ourselves
while ( t && last != t ) {
var r = [];
last = t;
t = jQuery.trim(t).replace( /^\/\//i, "" );
var foundToken = false;
// An attempt at speeding up child selectors that
// point to a specific element tag
var re = /^[\/>]\s*([a-z0-9*-]+)/i;
var m = re.exec(t);
if ( m ) {
// Perform our own iteration and filter
for ( var i = 0, rl = ret.length; i < rl; i++ )
for ( var c = ret[i].firstChild; c; c = c.nextSibling )
if ( c.nodeType == 1 && ( c.nodeName == m[1].toUpperCase() || m[1] == "*" ) )
r.push( c );
ret = r;
t = jQuery.trim( t.replace( re, "" ) );
foundToken = true;
} else {
// Look for pre-defined expression tokens
for ( var i = 0; i < jQuery.token.length; i += 2 ) {
// Attempt to match each, individual, token in
// the specified order
var re = new RegExp("^(" + jQuery.token[i] + ")");
var m = re.exec(t);
// If the token match was found
if ( m ) {
// Map it against the token's handler
r = ret = jQuery.map( ret, jQuery.token[i+1].constructor == Function ?
jQuery.token[i+1] :
function(a){ return eval(jQuery.token[i+1]); });
// And remove the token
t = jQuery.trim( t.replace( re, "" ) );
foundToken = true;
break;
}
}
}
// See if there's still an expression, and that we haven't already
// matched a token
if ( t && !foundToken ) {
// Handle multiple expressions
if ( !t.indexOf(",") || !t.indexOf("|") ) {
// Clean teh result set
if ( ret[0] == context ) ret.shift();
// Merge the result sets
jQuery.merge( done, ret );
// Reset the context
r = ret = [context];
// Touch up the selector string
t = " " + t.substr(1,t.length);
} else {
// Optomize for the case nodeName#idName
var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i;
var m = re2.exec(t);
// Re-organize the results, so that they're consistent
if ( m ) {
m = [ 0, m[2], m[3], m[1] ];
} else {
// Otherwise, do a traditional filter check for
// ID, class, and element selectors
re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
m = re2.exec(t);
}
// Try to do a global search by ID, where we can
if ( m[1] == "#" && ret[ret.length-1].getElementById ) {
// Optimization for HTML document case
var oid = ret[ret.length-1].getElementById(m[2]);
// Do a quick check for node name (where applicable) so
// that div#foo searches will be really fast
ret = r = oid &&
(!m[3] || oid.nodeName == m[3].toUpperCase()) ? [oid] : [];
// Use the DOM 0 shortcut for the body element
} else if ( m[1] == "" && m[2] == "body" ) {
ret = r = [ document.body ];
} else {
// Pre-compile a regular expression to handle class searches
if ( m[1] == "." )
var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");
// We need to find all descendant elements, it is more
// efficient to use getAll() when we are already further down
// the tree - we try to recognize that here
for ( var i = 0, rl = ret.length; i < rl; i++ )
jQuery.merge( r,
m[1] != "" && ret.length != 1 ?
jQuery.getAll( ret[i], [], m[1], m[2], rec ) :
ret[i].getElementsByTagName( m[1] != "" || m[0] == "" ? "*" : m[2] )
);
// It's faster to filter by class and be done with it
if ( m[1] == "." && ret.length == 1 )
r = jQuery.grep( r, function(e) {
return rec.test(e.className);
});
// Same with ID filtering
if ( m[1] == "#" && ret.length == 1 ) {
// Remember, then wipe out, the result set
var tmp = r;
r = [];
// Then try to find the element with the ID
for ( var i = 0, tl = tmp.length; i < tl; i++ )
if ( tmp[i].getAttribute("id") == m[2] ) {
r = [ tmp[i] ];
break;
}
}
ret = r;
}
t = t.replace( re2, "" );
}
}
// If a selector string still exists
if ( t ) {
// Attempt to filter it
var val = jQuery.filter(t,r);
ret = r = val.r;
t = jQuery.trim(val.t);
}
}
// Remove the root context
if ( ret && ret[0] == context ) ret.shift();
// And combine the results
jQuery.merge( done, ret );
return done;
},
getAll: function( o, r, token, name, re ) {
for ( var s = o.firstChild; s; s = s.nextSibling )
if ( s.nodeType == 1 ) {
var add = true;
if ( token == "." )
add = s.className && re.test(s.className);
else if ( token == "#" )
add = s.getAttribute('id') == name;
if ( add )
r.push( s );
if ( token == "#" && r.length ) break;
if ( s.firstChild )
jQuery.getAll( s, r, token, name, re );
}
return r;
},
attr: function(elem, name, value){ attr: function(elem, name, value){
var fix = { var fix = {
"for": "htmlFor", "for": "htmlFor",
@ -1781,84 +1452,7 @@ jQuery.extend({
return elem[name]; return elem[name];
} }
}, },
// The regular expressions that power the parsing engine
parse: [
// Match: [@value='test'], [@foo]
"\\[ *(@)S *([!*$^=]*) *('?\"?)(.*?)\\4 *\\]",
// Match: [div], [div p]
"(\\[)\\s*(.*?)\\s*\\]",
// Match: :contains('foo')
"(:)S\\(\"?'?([^\\)]*?)\"?'?\\)",
// Match: :even, :last-chlid
"([:.#]*)S"
],
filter: function(t,r,not) {
// Look for common filter expressions
while ( t && /^[a-z[({<*:.#]/i.test(t) ) {
var p = jQuery.parse;
for ( var i = 0, pl = p.length; i < pl; i++ ) {
// Look for, and replace, string-like sequences
// and finally build a regexp out of it
var re = new RegExp(
"^" + p[i].replace("S", "([a-z*_-][a-z0-9_-]*)"), "i" );
var m = re.exec( t );
if ( m ) {
// Re-organize the first match
if ( jQuery.expr[ m[1] ]._resort )
m = jQuery.expr[ m[1] ]._resort( m );
// Remove what we just matched
t = t.replace( re, "" );
break;
}
}
// :not() is a special case that can be optimized by
// keeping it out of the expression list
if ( m[1] == ":" && m[2] == "not" )
r = jQuery.filter(m[3], r, true).r;
// Handle classes as a special case (this will help to
// improve the speed, as the regexp will only be compiled once)
else if ( m[1] == "." ) {
var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");
r = jQuery.grep( r, function(e){
return re.test(e.className || '');
}, not);
// Otherwise, find the expression to execute
} else {
var f = jQuery.expr[m[1]];
if ( typeof f != "string" )
f = jQuery.expr[m[1]][m[2]];
// Build a custom macro to enclose it
eval("f = function(a,i){" +
( jQuery.expr[ m[1] ]._prefix || "" ) +
"return " + f + "}");
// Execute it against the current filter
r = jQuery.grep( r, f, not );
}
}
// Return an array of filtered elements (r)
// and the modified expression string (t)
return { r: r, t: t };
},
/** /**
* Remove the whitespace from the beginning and end of a string. * Remove the whitespace from the beginning and end of a string.
* *
@ -1874,25 +1468,6 @@ jQuery.extend({
return t.replace(/^\s+|\s+$/g, ""); return t.replace(/^\s+|\s+$/g, "");
}, },
/**
* All ancestors of a given element.
*
* @private
* @name $.parents
* @type Array<Element>
* @param Element elem The element to find the ancestors of.
* @cat DOM/Traversing
*/
parents: function( elem ){
var matched = [];
var cur = elem.parentNode;
while ( cur && cur != document ) {
matched.push( cur );
cur = cur.parentNode;
}
return matched;
},
makeArray: function( a ) { makeArray: function( a ) {
var r = []; var r = [];

426
src/selector/selector.js Normal file
View file

@ -0,0 +1,426 @@
jQuery.extend({
expr: {
"": "m[2]== '*'||a.nodeName.toUpperCase()==m[2].toUpperCase()",
"#": "a.getAttribute('id')==m[2]",
":": {
// Position Checks
lt: "i<m[3]-0",
gt: "i>m[3]-0",
nth: "m[3]-0==i",
eq: "m[3]-0==i",
first: "i==0",
last: "i==r.length-1",
even: "i%2==0",
odd: "i%2",
// Child Checks
"nth-child": "jQuery.nth(a.parentNode.firstChild,m[3],'nextSibling')==a",
"first-child": "jQuery.nth(a.parentNode.firstChild,1,'nextSibling')==a",
"last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a",
"only-child": "jQuery.sibling(a.parentNode.firstChild).length==1",
// Parent Checks
parent: "a.firstChild",
empty: "!a.firstChild",
// Text Check
contains: "jQuery.fn.text.apply([a]).indexOf(m[3])>=0",
// Visibility
visible: "a.type!='hidden'&&jQuery.css(a,'display')!='none'&&jQuery.css(a,'visibility')!='hidden'",
hidden: "a.type=='hidden'||jQuery.css(a,'display')=='none'||jQuery.css(a,'visibility')=='hidden'",
// Form attributes
enabled: "!a.disabled",
disabled: "a.disabled",
checked: "a.checked",
selected: "a.selected || jQuery.attr(a, 'selected')",
// Form elements
text: "a.type=='text'",
radio: "a.type=='radio'",
checkbox: "a.type=='checkbox'",
file: "a.type=='file'",
password: "a.type=='password'",
submit: "a.type=='submit'",
image: "a.type=='image'",
reset: "a.type=='reset'",
button: "a.type=='button'||a.nodeName=='BUTTON'",
input: "/input|select|textarea|button/i.test(a.nodeName)"
},
".": "jQuery.className.has(a,m[2])",
"@": {
"=": "z==m[4]",
"!=": "z!=m[4]",
"^=": "z && !z.indexOf(m[4])",
"$=": "z && z.substr(z.length - m[4].length,m[4].length)==m[4]",
"*=": "z && z.indexOf(m[4])>=0",
"": "z",
_resort: function(m){
return ["", m[1], m[3], m[2], m[5]];
},
_prefix: "z=jQuery.attr(a,m[3]);"
},
"[": "jQuery.find(m[2],a).length"
},
// The regular expressions that power the parsing engine
parse: [
// Match: [@value='test'], [@foo]
"\\[ *(@)S *([!*$^=]*) *('?\"?)(.*?)\\4 *\\]",
// Match: [div], [div p]
"(\\[)\\s*(.*?)\\s*\\]",
// Match: :contains('foo')
"(:)S\\(\"?'?([^\\)]*?)\"?'?\\)",
// Match: :even, :last-chlid
"([:.#]*)S"
],
token: [
"\\.\\.|/\\.\\.", "a.parentNode",
">|/", "jQuery.sibling(a.firstChild)",
"\\+", "jQuery.nth(a,2,'nextSibling')",
"~", function(a){
var s = jQuery.sibling(a.parentNode.firstChild);
return s.slice(0, jQuery.inArray(a,s));
}
],
/**
* @name $.find
* @type Array<Element>
* @private
* @cat Core
*/
find: function( t, context ) {
// Quickly handle non-string expressions
if ( typeof t != "string" )
return [ t ];
// Make sure that the context is a DOM Element
if ( context && context.nodeType == undefined )
context = null;
// Set the correct context (if none is provided)
context = context || document;
// Handle the common XPath // expression
if ( !t.indexOf("//") ) {
context = context.documentElement;
t = t.substr(2,t.length);
// And the / root expression
} else if ( !t.indexOf("/") ) {
context = context.documentElement;
t = t.substr(1,t.length);
if ( t.indexOf("/") >= 1 )
t = t.substr(t.indexOf("/"),t.length);
}
// Initialize the search
var ret = [context], done = [], last = null;
// Continue while a selector expression exists, and while
// we're no longer looping upon ourselves
while ( t && last != t ) {
var r = [];
last = t;
t = jQuery.trim(t).replace( /^\/\//i, "" );
var foundToken = false;
// An attempt at speeding up child selectors that
// point to a specific element tag
var re = /^[\/>]\s*([a-z0-9*-]+)/i;
var m = re.exec(t);
if ( m ) {
// Perform our own iteration and filter
for ( var i = 0, rl = ret.length; i < rl; i++ )
for ( var c = ret[i].firstChild; c; c = c.nextSibling )
if ( c.nodeType == 1 && ( c.nodeName == m[1].toUpperCase() || m[1] == "*" ) )
r.push( c );
ret = r;
t = jQuery.trim( t.replace( re, "" ) );
foundToken = true;
} else {
// Look for pre-defined expression tokens
for ( var i = 0; i < jQuery.token.length; i += 2 ) {
// Attempt to match each, individual, token in
// the specified order
var re = new RegExp("^(" + jQuery.token[i] + ")");
var m = re.exec(t);
// If the token match was found
if ( m ) {
// Map it against the token's handler
r = ret = jQuery.map( ret, jQuery.token[i+1].constructor == Function ?
jQuery.token[i+1] :
function(a){ return eval(jQuery.token[i+1]); });
// And remove the token
t = jQuery.trim( t.replace( re, "" ) );
foundToken = true;
break;
}
}
}
// See if there's still an expression, and that we haven't already
// matched a token
if ( t && !foundToken ) {
// Handle multiple expressions
if ( !t.indexOf(",") || !t.indexOf("|") ) {
// Clean teh result set
if ( ret[0] == context ) ret.shift();
// Merge the result sets
jQuery.merge( done, ret );
// Reset the context
r = ret = [context];
// Touch up the selector string
t = " " + t.substr(1,t.length);
} else {
// Optomize for the case nodeName#idName
var re2 = /^([a-z0-9_-]+)(#)([a-z0-9\\*_-]*)/i;
var m = re2.exec(t);
// Re-organize the results, so that they're consistent
if ( m ) {
m = [ 0, m[2], m[3], m[1] ];
} else {
// Otherwise, do a traditional filter check for
// ID, class, and element selectors
re2 = /^([#.]?)([a-z0-9\\*_-]*)/i;
m = re2.exec(t);
}
// Try to do a global search by ID, where we can
if ( m[1] == "#" && ret[ret.length-1].getElementById ) {
// Optimization for HTML document case
var oid = ret[ret.length-1].getElementById(m[2]);
// Do a quick check for node name (where applicable) so
// that div#foo searches will be really fast
ret = r = oid &&
(!m[3] || oid.nodeName == m[3].toUpperCase()) ? [oid] : [];
// Use the DOM 0 shortcut for the body element
} else if ( m[1] == "" && m[2] == "body" ) {
ret = r = [ document.body ];
} else {
// Pre-compile a regular expression to handle class searches
if ( m[1] == "." )
var rec = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");
// We need to find all descendant elements, it is more
// efficient to use getAll() when we are already further down
// the tree - we try to recognize that here
for ( var i = 0, rl = ret.length; i < rl; i++ )
jQuery.merge( r,
m[1] != "" && ret.length != 1 ?
jQuery.getAll( ret[i], [], m[1], m[2], rec ) :
ret[i].getElementsByTagName( m[1] != "" || m[0] == "" ? "*" : m[2] )
);
// It's faster to filter by class and be done with it
if ( m[1] == "." && ret.length == 1 )
r = jQuery.grep( r, function(e) {
return rec.test(e.className);
});
// Same with ID filtering
if ( m[1] == "#" && ret.length == 1 ) {
// Remember, then wipe out, the result set
var tmp = r;
r = [];
// Then try to find the element with the ID
for ( var i = 0, tl = tmp.length; i < tl; i++ )
if ( tmp[i].getAttribute("id") == m[2] ) {
r = [ tmp[i] ];
break;
}
}
ret = r;
}
t = t.replace( re2, "" );
}
}
// If a selector string still exists
if ( t ) {
// Attempt to filter it
var val = jQuery.filter(t,r);
ret = r = val.r;
t = jQuery.trim(val.t);
}
}
// Remove the root context
if ( ret && ret[0] == context ) ret.shift();
// And combine the results
jQuery.merge( done, ret );
return done;
},
filter: function(t,r,not) {
// Look for common filter expressions
while ( t && /^[a-z[({<*:.#]/i.test(t) ) {
var p = jQuery.parse;
for ( var i = 0, pl = p.length; i < pl; i++ ) {
// Look for, and replace, string-like sequences
// and finally build a regexp out of it
var re = new RegExp(
"^" + p[i].replace("S", "([a-z*_-][a-z0-9_-]*)"), "i" );
var m = re.exec( t );
if ( m ) {
// Re-organize the first match
if ( jQuery.expr[ m[1] ]._resort )
m = jQuery.expr[ m[1] ]._resort( m );
// Remove what we just matched
t = t.replace( re, "" );
break;
}
}
// :not() is a special case that can be optimized by
// keeping it out of the expression list
if ( m[1] == ":" && m[2] == "not" )
r = jQuery.filter(m[3], r, true).r;
// Handle classes as a special case (this will help to
// improve the speed, as the regexp will only be compiled once)
else if ( m[1] == "." ) {
var re = new RegExp("(^|\\s)" + m[2] + "(\\s|$)");
r = jQuery.grep( r, function(e){
return re.test(e.className || '');
}, not);
// Otherwise, find the expression to execute
} else {
var f = jQuery.expr[m[1]];
if ( typeof f != "string" )
f = jQuery.expr[m[1]][m[2]];
// Build a custom macro to enclose it
eval("f = function(a,i){" +
( jQuery.expr[ m[1] ]._prefix || "" ) +
"return " + f + "}");
// Execute it against the current filter
r = jQuery.grep( r, f, not );
}
}
// Return an array of filtered elements (r)
// and the modified expression string (t)
return { r: r, t: t };
},
getAll: function( o, r, token, name, re ) {
for ( var s = o.firstChild; s; s = s.nextSibling )
if ( s.nodeType == 1 ) {
var add = true;
if ( token == "." )
add = s.className && re.test(s.className);
else if ( token == "#" )
add = s.getAttribute('id') == name;
if ( add )
r.push( s );
if ( token == "#" && r.length ) break;
if ( s.firstChild )
jQuery.getAll( s, r, token, name, re );
}
return r;
},
/**
* All ancestors of a given element.
*
* @private
* @name $.parents
* @type Array<Element>
* @param Element elem The element to find the ancestors of.
* @cat DOM/Traversing
*/
parents: function( elem ){
var matched = [];
var cur = elem.parentNode;
while ( cur && cur != document ) {
matched.push( cur );
cur = cur.parentNode;
}
return matched;
},
/**
* A handy, and fast, way to traverse in a particular direction and find
* a specific element.
*
* @private
* @name $.nth
* @type DOMElement
* @param DOMElement cur The element to search from.
* @param Number|String num The Nth result to match. Can be a number or a string (like 'even' or 'odd').
* @param String dir The direction to move in (pass in something like 'previousSibling' or 'nextSibling').
* @cat DOM/Traversing
*/
nth: function(cur,result,dir){
result = result || 1;
var num = 0;
for ( ; cur; cur = cur[dir] ) {
if ( cur.nodeType == 1 ) num++;
if ( num == result || result == "even" && num % 2 == 0 && num > 1 ||
result == "odd" && num % 2 == 1 ) return cur;
}
},
/**
* All elements on a specified axis.
*
* @private
* @name $.sibling
* @type Array
* @param Element elem The element to find all the siblings of (including itself).
* @cat DOM/Traversing
*/
sibling: function( n, elem ) {
var r = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType == 1 && (!elem || n != elem) )
r.push( n );
}
return r;
}
});