OSDN Git Service

Version 0.6.49, fix for xnode.attr(name).
[pettanr/clientJs.git] / 0.6.x / js / dom / 18_XDomQuery.js
index 2ea6a34..7dc8d9c 100644 (file)
-/* --------------------------------------
- *  getByID
- */
-X.Dom.getByID =
-       document.getElementById ?
-               (function( id ){
-                       return new X.Dom.Node( document.getElementById( id ) );
-               }) :
-       document.all ?
-               (function( id ){
-                       return new X.Dom.Node( document.all[ id ] );    
-               }) :
-               (function( id ){});
-
-/* --------------------------------------
- *  getByTag
- */
-Node.prototype.getByTag =
-       document.getElementsByTagName ?
-               function( tag ){
-                       var parent = this.parent, elm, tags;
-                       if( !parent || this._xnodeType !== -1 ) return;
-                       if( !( elm = this._rawNode ) ) return;
-                       return new X.Dom.NodeList( document.getElementsByTagName( tag ) );
-               } :
-       document.all ?
-               (function( tag ){
-                       var parent = this.parent, elm, tags;
-                       if( !parent || this._xnodeType !== -1 ) return;
-                       if( !( elm = this._ie4getRawNode() ) ) return;
-                       Node.root._ie4reserved === true && Node.root._ie4startUpdate();
-                       return new X.Dom.NodeList( elm.all.tags( tag ) );       
-               }) :
-               (function( tag ){});
-
-/* --------------------------------------
- *  getByClass
- */
-Node.prototype.getByClass =
-               document.getElementsByClassName ?
-                       (function( className ){
-                               var parent = this.parent, elm;
-                               if( !parent ) return;
-                               if( !( elm = this._rawNode ) || elm.nodeType !== 1 ) return;
-                               return new X.Dom.NodeList( elm.getElementsByClassName( className ) );
-                       }) :
-               document.getElementsByTagName ?
-                       (function( className ){
-                               var parent = this.parent,
-                                       live   = parent.getElementsByTagName( '*' ),
-                                       nodes  = [],
-                    test   = X.matchTest,
-                    node, i;
-                className = className.split( ' ' );
-                for( i = live.length; i; ){
-                       nodes[ --i ] = live[ i ];
-                };
-                               for( i = nodes.length; i; ){
-                                       node = nodes[ --i ];
-                                       ( node.nodeType !== 1 || !node.className || !node.className.length || !test( node.className.split( ' ' ), className ) ) && nodes.splice( i, 1 );
-                               };
-                               return new X.Dom.NodeList( nodes );
-                       }) :
-               document.all ?
-                       (function( parent, className ){
-                               var live  = parent.all,
-                                       nodes = [],
-                    test  = X.matchTest,
-                    node, i;
-                for( i = live.length; i; ){
-                       nodes[ --i ] = live[ i ];
-                };
-                               for( i = nodes.length; i; ){
-                                       node = nodes[ --i ];
-                                       ( !node.className || !node.className.length || !test( node.className.split( ' ' ), className ) ) && nodes.splice( i, 1 );
-                               };
-                               return new X.Dom.NodeList( nodes );
-                       }) :
-                       (function(){});
-
-X.Dom.find = Node.prototype.find = function( v ){
-       var root      = this.cnstructor === Node ? this : Node.root,
-               selectors = X.Dom.Query._parse( v ),
-               l, i, nodes, _nodes, selector,
-               name, key, operator, value,
-               j, m;
-       
-       if( !selectors ) return;
-       l     = selectors.length;
-       i     = 0;
-       nodes = [];
-       
-       for( ; i < l; ++i ){
-               selector = selectors[ i ];
-               if( 2 <= selector.length ){
-                       operator = selector[ 2 ];
-                       value    = selector[ 3 ];
-                       name     = key = selector[ 1 ];
-                       selector = selector[ 0 ];
-               };
-               switch( selector ){
-                       case 4 : // # id
-                               nodes = [ X.Dom.getById( name ) ];
-                               break;
-                       case 5 : // . classname
-                               _nodes = [];
-                               for( j = 0, m = nodes.length; j < m; ++j ){
-                                       _nodes = _nodes.concat( nodes[ j ].getByClass( name ) );
-                               };
-                               nodes = _nodes;
-                               break;
-                       case 6 : // :focus, :disabled ...
-                               switch( name ){
-                                       case 'focus' :
-                                       case 'disabled' :
-                                       case 'checked' :
-                                       case 'enabled' :
-                                       case 'empty' :
-                                       case 'only-of-type' :
-                                       case '' :
-                                       case 'target' :
-                                       case 'link' :
-                                       case 'visited' :
-                                       case 'hover' :
-                                       case 'active' :
-                                       case 'first-line' :
-                                       case 'first-letter' :
-                                       case 'before' :
-                                       case 'after' :
-                                       case ':selection' :
-                                       case 'lang()' :
-                                       case 'not()' :
-                               };
-                               break;
-                       case 7 : // [
-                               
-                               break;  
-                       case 8 : // . tagname
-                               _nodes = [];
-                               for( j = 0, m = nodes.length ; j < m; ++j ){
-                                       _nodes = _nodes.concat( nodes[ j ].getByTag( name ) );
-                               };
-                               nodes = _nodes;
-                               break;
-               };
-       };
-       return new X.Dom.NodeList( nodes );
-};
-
-X.Dom.Query = {
-       
-};
-
-X.Dom.Query._parse = function( query ){
-       var HASH_SELECTOR = {
-               ' '   : 0,
-               '>'   : 1,
-               '+'   : 2,
-               '~'   : 3,
-               '#'   : 4,
-               '.'   : 5,
-               ':'   : 6,
-               '['   : 7,
-               scope : 9,
-               root  : 10,
-               link  : 11
-       };
-       var OPERATORS = { "!=": 2, "~=": 3, "^=": 4, "$=": 5, "*=": 6, "|=": 7 };
-       var ALPHABET  = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789\\';
-
-       query += ' ';
-       var result    = [],
-               i         = 0,
-               l         = query.length,
-               phase     = 0,
-               selector  = -1,
-               last      = 0,
-               chr, index, start, name, key, value, operator, nameChr, name1st, escape;
-       while( i < l ){
-               chr     = query.charAt( i );
-               index   = ALPHABET.indexOf( chr );
-               nameChr = index !== -1;
-               name1st = nameChr && index < 52;
-               switch( phase ){
-                       case 99 :
-                               return;
-                       case 0 :
-                               name1st ? // tagName
-                                       ( ( selector = 8 ) && ( phase = 2 ) && ( start = i ) ) :
-                               ( index = HASH_SELECTOR.indexOf( chr ) ) === 7 ? // [
-                                       ( ( selector = 7 ) && ( phase = 3 ) ) :
-                               0 <= index ?
-                                       ( ( selector = index ) && ( phase = index < 4 ? 9 : 1 ) ) :
-                               chr !== ' ' &&
-                                       ( phase = 99 );
-                               break;
-                       case 1 :
-                               name1st ?
-                                       ( ( start = i ) && ( phase = 2 ) ) :
-                                       ( phase = 99 );
-                               break;
-                       case 2 :
-                               !nameChr &&
-                               !( escape && ( selector === 4 || selector === 5 ) &&  ( chr === ':' || chr === '.' ) ) // id or class の場合 : . を直前にエスケープした場合に限り使える
-                                       && ( name = query.substring( start, i ) ) && ( phase = 9 );
-                               break;
-                       case 3 : // start attr filter
-                               name1st ?
-                                       ( ( phase = 4 ) && ( start = i ) ) :
-                                       ( phase = 99 );
-                               break;
-                       case 4 : // attr filter key
-                               chr === '=' ?
-                                       ( ( operator = 1 ) && ( phase = 5 ) && ( key = query.substring( start, i ) ) && ( start = i ) ) :
-                               ( index = OPERATORS[ query.substr( i, 2 ) ] ) ?
-                                       ( ( operator = index ) && ( phase = 5 ) && ( key = query.substring( start, i ) )  && ( start = i ) && ++i ) :
-                               chr !== ' ' &&
-                                       ( phase = 99 );
-                               break;
-                       case 5 : // attr filter value
-                               chr === ']' ?
-                                       ( ( phase = 9 ) && ( value = query.substring( start, i ) ) ) :
-                               !nameChr &&
-                                       ( phase = 99 );
-                               break;
-                       default :
-               };
-               //alert( chr + ' ' + phase + ' ' + selector + ' ' + name + ' ' + name1st )
-               if( phase === 9 ){
-                       if( last < 4 && selector < 4 ){
-                               if( last === 0 ){
-                                       result[ result.length - 1 ] = selector; // override
-                                       last = selector;
-                               } else {
-                                       return; // error
-                               };
-                       } else { // 前回今回とも子孫セレクタの場合、保存しない
-                               result[ result.length ] =
-                                       selector < 4 ?
-                                               selector :
-                                       selector === 7 ?
-                                               [ selector, key, operator, value ] :
-                                               [ selector, name.split( '\\' ).join( '' ) ];
-                               last = selector;
-                       };
-                       selector = -1;
-                       phase    = 0;
-               } else
-               if( phase === 99 ) return;
-
-               escape = chr === '\\' && !escape;
-       };
-       return result;
-};
-
+/**\r
+ * Original code by ofk ( kQuery, ksk )\r
+ * http://d.hatena.ne.jp/ofk/comment/20090106/1231258010\r
+ * http://d.hatena.ne.jp/ofk/20090111/1231668170 \r
+ *\r
+ * セレクタ Level 3\r
+ * http://standards.mitsue.co.jp/resources/w3c/TR/css3-selectors/#nth-child-pseudo\r
+ */\r
+\r
+X.Dom.Query = {\r
+       _PSEUDO    : {\r
+               'nth-child'        : 9,\r
+               'nth-last-child'   : 14,\r
+               'nth-of-type'      : 11,\r
+               'nth-last-of-type' : 16,\r
+               root               : 4,\r
+               link               : 4,\r
+               lang               : 4,\r
+               empty              : 5,\r
+               target             : 6,\r
+               invalid            : 7,\r
+               enabled            : 7,\r
+               checked            : 7,\r
+               disabled           : 8,\r
+               contains           : 8,\r
+               'last-child'       : 10,\r
+               'only-child'       : 10,                        \r
+               'first-child'      : 11,\r
+               'last-of-type'     : 12,\r
+               'only-of-type'     : 12,                \r
+               'first-of-type'    : 13\r
+       },\r
+       \r
+       _COMBINATOR : {\r
+               ''    : 0, // none\r
+               ' '   : 1, // 子孫セレクタ\r
+               '>'   : 2, // 子セレクタ\r
+               '+'   : 3, // 兄弟セレクタ,共通の親を持つ、1番目要素が2番目要素の1つ前にある\r
+               '~'   : 4, // 一般兄弟セレクタ,共通の親を持つ、1番目要素が2番目要素の前 (直前でなくともよい) にある\r
+               ','   : 5\r
+       },\r
+       _SELECTOR : {\r
+               ''    : 0, // none\r
+               tag   : 1,\r
+               '#'   : 2,\r
+               '.'   : 3,\r
+               ':'   : 4,\r
+               '['   : 5,\r
+               not   : 6,\r
+               scope : 7,\r
+               root  : 8,\r
+               link  : 9\r
+       },\r
+       _OPERATORS : { '==' : 1, '!=': 2, '~=': 3, '^=': 4, '$=': 5, '*=': 6, '|=': 7 },\r
+       _ALPHABET  : 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789\\',\r
+       _NUMBER    : '+-0123456789'\r
+};\r
+                       \r
+/*\r
+ * セレクタ文字の解析\r
+ * 結合子 + 単体セレクタ( タグ,*,#,.,[],: )\r
+ * ' ' 子孫セレクタ, '>' 直下,'+','~' の場合、tagName|* を返す\r
+ * return [ pointer, [ selector, ... ] ] error: return pointer\r
+ */\r
+X.Dom.Query._parse = function( query, last ){\r
+       var COMBINATOR = X.Dom.Query._COMBINATOR,\r
+               SELECTOR   = X.Dom.Query._SELECTOR,\r
+               OPERATORS  = X.Dom.Query._OPERATORS,\r
+               ALPHABET   = X.Dom.Query._ALPHABET,\r
+               NUMBER     = X.Dom.Query._NUMBER,\r
+               result     = [],\r
+               i          = -1,\r
+               l          = query.length,\r
+               phase      = 0x0,\r
+               combinator = 0,\r
+               selector   = 0,\r
+               chr, chrCode, nameChr, name1st,\r
+               tmp, escape, quot, start,\r
+               name, key, value, operator, a, b, not;\r
+       query += ' ';\r
+       while( i < l ){\r
+               chr     = query.charAt( ++i );\r
+               chrCode = ALPHABET.indexOf( chr );\r
+               nameChr = chrCode !== -1;\r
+               name1st = nameChr && chrCode < 52;\r
+               switch( phase ){\r
+                       case 0x0 :\r
+                               name1st ? // tagName\r
+                                       ( ( selector = 1 ) && ( phase = 0x2 ) && ( start = i ) ) :\r
+                               !not && ( tmp = COMBINATOR[ chr ] ) ? (\r
+                                       ( 1 < tmp && 1 < combinator ) ?\r
+                                               ( phase = 0xf ) :\r
+                                               ( phase = tmp === 5 ? 0xe : 0x0 ) & ( ( 1 < tmp || combinator < 1 ) && ( combinator = tmp ) ) & ( tmp === 5 && ++i ) ) : // ' ' でない結合子の上書きはエラー\r
+                               ( tmp = SELECTOR[ chr ] ) ? // [\r
+                                       ( selector = tmp ) && ( phase = selector === 5 ? 0x4 : 0x1 ) : // 7:[, 0<:\r
+                               chr === '*' ?\r
+                                       ( ( selector = 1 ) && ( name = chr ) && ( phase = 0xe ) && ++i ) :\r
+                                       chr !== ' ' && ( phase = 0xf );\r
+                               //console.log( '0x0: ' + name1st + ' ' + chrCode + ' ' + chr + ' ' + phase + ' tmp:' + tmp + ' comb:' + combinator );\r
+                               break;\r
+                       case 0x1 :\r
+                               name1st ?\r
+                                       ( ( start = i ) && ( phase = 0x2 ) ) :\r
+                                       chr !== ' ' && ( phase = 0xf );\r
+                               break;\r
+                       case 0x2 :\r
+                               !nameChr && !( escape && ( selector === 2 || selector === 3 ) && ( chr === ':' || chr === '.' ) ) ? // id or class の場合 : . を直前にエスケープした場合に限り使える\r
+                                       ( name = query.substring( start, i ) ) && ( phase = selector === 4 && name !== 'not' && chr === '(' ? 0x8 : 0xe ) :\r
+                               SELECTOR[ chr ] < 4 && ( phase = 0xe );\r
+                               break;\r
+                       \r
+                       case 0x3 : //:nth-\r
+                               break;\r
+                       \r
+                       case 0x4 : // start attr filter\r
+                               name1st ?\r
+                                       ( ( phase = 0x5 ) && ( start = i ) ) :\r
+                                       ( phase = 0xf );\r
+                               break;\r
+                       case 0x5 : // attr filter key\r
+                               chr === '=' ?\r
+                                       ( ( operator = 1 ) && ( phase = 0x6 ) && ( key || ( key = query.substring( start, i ) ) ) && ( start = i + 1 ) ) :\r
+                               chr === ']' ?\r
+                                       ( !( operator = 0 ) && ( phase = 0xe ) && ( key || ( key = query.substring( start, i ) ) ) && ++i ) :\r
+                               chr === ' ' ?\r
+                                       ( key || ( key = query.substring( start, i ) ) ) :\r
+                               ( operator = OPERATORS[ query.substr( i, 2 ) ] ) ?\r
+                                       ( ( phase = 0x6 ) && ( key || ( key = query.substring( start, i ) ) ) && ( start = ++i ) ) :\r
+                                       !nameChr && ( phase = 0xf );\r
+                               //console.log( name1st + ' ' + chrCode + chr + phase );\r
+                               break;\r
+                       case 0x6 :\r
+                               ( chr === '"' || chr === "'" ) && !escape && !quot ?\r
+                                       ( quot = chr ) && ( start = i + 1 ) && ( phase = 0x7 ) :\r
+                                       chr !== ' ' && ( start = i ) && ( phase = 0x7 );\r
+                               break;\r
+                               \r
+                       case 0x7 : // attr filter value\r
+                               chr === quot ?\r
+                                       !escape && !value && ( value = query.substring( start, i ) ) :\r
+                               chr === ']' ?\r
+                                       ( ( value || ( value = query.substring( start, i ) ) ) && ( phase = 0xe ) && ++i ) :    \r
+                               chr === ' ' && !quot && !value && ( value = query.substring( start, i ) );                      \r
+                                       //( chr === '"' || chr === "'" ) && !quot && ( quot = chr ) && ( start = i + 1 );\r
+                               break;\r
+                               \r
+                       case 0x8 : // 4, 2n, even, odd, -n+4,\r
+                               NUMBER.indexOf( chr ) !== -1 ?\r
+                                       ( start = i ) && ( phase = 0x9 ) :\r
+                               chr === 'n' ?\r
+                                       ( phase = 0xa ) && ( a = 1 ) && ( start = i + 1 ) :\r
+                               query.substr( i, 4 ) === 'even' ?\r
+                                       ( ( a = 2 ) && !( b = 0 ) && ( i += 3 ) ) :\r
+                               query.substr( i, 3 ) === 'odd' ?\r
+                                       ( ( a = 2 ) && ( b = 1 ) && ( i += 2 ) ) :                                      \r
+                               chr === ')' && ( phase = a ? 0xe : 0xf ) && ++i;\r
+                               //console.log( '0x8: ' + name1st + ' ' + chrCode + ' ' + chr + ' ' + phase );\r
+                               break;\r
+                       case 0x9 :\r
+                               tmp = query.substring( start, i );\r
+                               chr === 'n' ?\r
+                                       ( phase = 0xa ) && ( start = i + 1 ) && ( a = tmp === '+' ? 1 : tmp === '-' ? -1 : parseFloat( tmp ) ) :\r
+                               chr === ')' && ( phase = 0xe ) && ( b = parseFloat( tmp ) ) && ++i && ( a = 0 );\r
+                               //console.log( '0x9: ' + name1st + ' ' + chrCode + ' ' + chr + ' ' + phase );\r
+                               break;\r
+                       case 0xa :\r
+                               chr === ')' && ( phase = 0xe ) && ++i && ( b = parseFloat( query.substring( start, i ) ) || 0 );\r
+                               //console.log( '0xa: ' + start + ' ' + i );\r
+                               break;\r
+                       default :\r
+               };\r
+               //alert( chr + ' ' + phase + ' ' + selector + ' ' + name + ' ' + name1st )\r
+               if( phase === 0xe ){\r
+                       if( selector === 4 ){// :not\r
+                               if( name === 'not' ){\r
+                                       if( not ) return i; // error\r
+                                       not      = true;\r
+                                       selector = 0;\r
+                                       phase    = 0x0;\r
+                                       name     = null;\r
+                                       continue;\r
+                               } else {\r
+                                       if( a !== a || b !== b ) return i;\r
+                                       result = [ not ? 0 : combinator, selector, name, a, b ];\r
+                                       break;  \r
+                               };\r
+                               // lang result = [ not ? 0 : combinator, selector, name, lan ];\r
+                               // contains result = [ not ? 0 : combinator, selector, name, text ];\r
+                       };\r
+                       result =\r
+                               combinator === 5 ?\r
+                                       5 :\r
+                               selector === 5 ?\r
+                                       [ not ? 0 : combinator, selector, key, operator, value ] :\r
+                                       [ not ? 0 : combinator, selector, name.split( '\\' ).join( '' ) ];\r
+                       break;\r
+               } else\r
+               if( phase === 0xf ) return i;\r
+\r
+               escape = chr === '\\' && !escape;\r
+       };\r
+       //if( phase !== 0xe ) return i;\r
+       if( not && ( tmp = query.substr( i ).indexOf( ')' ) ) === -1 ) return i;\r
+       return not ? [ i + tmp + 1, [ combinator, 6, result ] ] : [ i, result ];\r
+};\r
+\r
+       // セレクター\r
+       X.Dom.find = X._shortcut = Node.prototype.find = X.Dom.NodeList.prototype.find = function( queryString ){\r
+               var HTML      = Node._html,\r
+                       scope     = this.constructor === X.Dom.NodeList && this.length ? this : [ this.constructor === Node ? this : Node.root ],\r
+                       parents   = scope, // 探索元の親要素 XNodeList の場合あり\r
+                       noLower   = 'title id name class for action archive background cite classid codebase data href longdesc profile src usemap',// + X.Dom.DTD.ATTR_VAL_IS_URI.join( ' ' ),\r
+                       ARY_PUSH  = Array.prototype.push,\r
+                       ret       = [], // 結果要素\r
+                       root      = X.Dom.Node.getRoot( scope[ 0 ] ),\r
+                       isXML     = !!X.Dom.Node.isXmlDocument( root ),\r
+                       isMulti   = 1 < scope.length,// 要素をマージする必要がある\r
+                       isStart   = true,\r
+                       _         = ' ',\r
+                       isAll, isNot, hasRoot,\r
+                       l, i, n, parsed,\r
+                       xnodes, // 一時保存用\r
+                       merge, // 要素がコメントノードで汚染されている場合使う\r
+                       combinator, selector, name, tagName,\r
+                       uid, tmp, xnode, filter, key, op, val, toLower, useName,\r
+            links, className, attr, flag;\r
+\r
+               /*@+debug[*/\r
+               if( X.Dom.readyState < X.Dom.Event.XDOM_READY ){\r
+                       alert( 'not ready! use X.Dom.listenOnce( X.Dom.Event.XDOM_READY, callback )' );\r
+                       return;\r
+               };\r
+               /*]@+debug*/\r
+\r
+               // 文字列以外は空で返す\r
+               if( typeof queryString !== 'string' ) return ret;\r
+               \r
+               xnodes = [];\r
+               \r
+               // 以下、パースと探索\r
+               for( ; queryString.length; ){\r
+                       //console.log( 'queryString[' + queryString + ']' );\r
+                       \r
+                       // 初期化処理\r
+                       if( !parsed ){\r
+                               parsed = X.Dom.Query._parse( queryString );\r
+                               \r
+                               if( typeof parsed === 'number' ){\r
+                                       // error\r
+                                       return [];\r
+                               };\r
+                               \r
+                               queryString = queryString.substr( parsed[ 0 ] );\r
+                               parsed      = parsed[ 1 ];\r
+                               \r
+                               //console.log( 'X.Dom.Query._parse ' + parsed );\r
+                               \r
+                               if( parsed === 5 ){\r
+                                       isMulti = true;\r
+                                       parents = scope;\r
+                                       xnodes && xnodes.length && ARY_PUSH.apply( ret, xnodes );\r
+                                       parsed  = null;\r
+                                       xnodes  = [];\r
+                                       isStart = true;\r
+                                       continue;\r
+                               };\r
+                       };\r
+                       \r
+                       combinator  = parsed[ 0 ];\r
+                       selector    = parsed[ 1 ];\r
+                       name        = parsed[ 2 ];\r
+                       tagName     = selector === 1 ? ( isXML ? name : name.toUpperCase() ) : '*';\r
+                       isAll       = tagName === '*';\r
+       \r
+                       if( !isStart ){\r
+                               if( !xnodes.length ){\r
+                                       parsed = null;\r
+                                       continue;                                       \r
+                               } else\r
+                               if( combinator !== 0 ){\r
+                                       parents = xnodes;\r
+                                       xnodes  = [];\r
+                                       //console.log( 'cobinator !== 0 ' + parents.length + ' : ' + xnodes.length );\r
+                               };\r
+                       };\r
+                       \r
+                       i = 0;\r
+                       l = parents.length;\r
+                       n = -1; \r
+                       isMulti = isMulti || 1 < l;\r
+                       \r
+                       //console.log( 'combinator ' + combinator );\r
+       \r
+                       switch( combinator ){\r
+                               // > TagName|*\r
+                               case 2 :\r
+                                       for( ; i < l; ++i ){\r
+                                               for( xnode = parents[ i ].firstChild(); xnode; xnode = xnode.nextNode() ){\r
+                                                       if( xnode._xnodeType === 1 && ( isAll || tagName === xnode._tag ) ) xnodes[ ++n ] = xnode;\r
+                                               };                              \r
+                                       };\r
+                                       break;\r
+                               // + TagName|*\r
+                               case 3 :\r
+                                       for( ; i < l; ++i ){\r
+                                               for( xnode = parents[ i ].nextNode(); xnode; xnode = xnode.nextNode() ){\r
+                                                       if( xnode._xnodeType === 1 ){\r
+                                                               if( isAll || tagName === xnode._tag ) xnodes[ ++n ] = xnode;\r
+                                                               break;\r
+                                                       };                                                                      \r
+                                               };                                                              \r
+                                       };\r
+                                       break;\r
+                               // ~ TagName|*\r
+                               case 4 :\r
+                                       merge  = {};\r
+                                       for( ; i < l; ++i ){\r
+                                               for( xnode = parents[ i ].nextNode(); xnode; xnode = xnode.nextNode() ){\r
+                                                       if( xnode._xnodeType === 1 && ( isAll || tagName === xnode._tag ) ){\r
+                                                               uid = xnode._uid;\r
+                                                               if( merge[ uid ] ){\r
+                                                                       break;\r
+                                                               } else {\r
+                                                                       merge[ uid ] = true;\r
+                                                                       xnodes[ ++n ] = xnode;\r
+                                                               };\r
+                                                       };                                                                      \r
+                                               };                                                              \r
+                                       };\r
+                                       break;\r
+                                       \r
+                               default :\r
+                                       if( combinator === 1 || ( isStart && selector < 7 ) ){\r
+                                               //console.log( l + ' > ' + xnodes.length + ' tag:' + tagName );\r
+                                               for( ; i < l; ++i ){\r
+                                                       xnode = parents[ i ];\r
+                                                       xnode._xnodes && xnode._xnodes.length && X.Dom.Query._fetchElements( xnodes, xnode, isAll ? null : tagName );\r
+                                               };\r
+                                               //console.log( l + ' >> ' + xnodes.length + ' tag:' + tagName );\r
+                                       };\r
+                       };\r
+                       \r
+                       isStart = false;\r
+                       \r
+                       //alert( 'pre-selector:' + ( xnodes && xnodes.length ) )\r
+                       \r
+                       switch( selector ){\r
+                               // #, ID\r
+                               case 2 :\r
+                                       filter = [ 'id', 1, name ]; break;\r
+                               // ., class\r
+                               case 3 :\r
+                                       filter = [ 'class', 3 /*'~='*/, name ]; break;\r
+                               // :, 擬似クラス\r
+                               case 4 :\r
+                                       if( !( filter = X.Dom.Query._filter[ name ] ) ){\r
+                                               return [];\r
+                                       };\r
+                                       break;\r
+                               // [] 属性\r
+                               case 5 :\r
+                                       filter = [ name, parsed[ 3 ], parsed[ 4 ] ]; break;\r
+                               // :not\r
+                               case 6 :\r
+                                       isNot  = true;\r
+                                       parsed = parsed[ 2 ];\r
+                                       continue;\r
+                               // scope\r
+                               case 7 :\r
+                                       xnodes = scope; break;\r
+                               // root\r
+                               case 8 :\r
+                                       hasRoot = true;\r
+                                       xnodes = [ HTML ]; break;\r
+                               // link\r
+                               case 9 :\r
+                                       if( links = document.links ){\r
+                                               for( xnodes = [], i = links.length; i; ){\r
+                                                       xnodes[ --i ] = new Node( links[ i ] );\r
+                                               };\r
+                                       } else {\r
+                                               // area[href],a[href]\r
+                                       }\r
+                       };\r
+                       \r
+                       if( filter && xnodes.length ){\r
+                               // filter.mが関数の場合\r
+                               if( filter.m ){\r
+                                       xnodes = filter.m(\r
+                                               {\r
+                                                       not : isNot,\r
+                                                       xml : isXML\r
+                                               },\r
+                                               xnodes,\r
+                                               parsed[ 3 ], parsed[ 4 ]\r
+                                       );\r
+                               } else\r
+                               // filterが関数の場合\r
+                               if( typeof filter === 'function' ){\r
+                                       tmp = [];\r
+                                       for( i = 0, n = -1; xnode = xnodes[ i ]; ++i ){\r
+                                               if( ( !!filter( xnode ) ) ^ isNot ) tmp[ ++n ] = xnode; \r
+                                       };\r
+                                       xnodes = tmp;\r
+                               } else {\r
+                               // 属性セレクター                        \r
+                                       tmp = [];\r
+                                       key = filter[ 0 ];\r
+                                       op  = filter[ 1 ];\r
+                                       val = filter[ 2 ];\r
+                                       \r
+                                       key = X.Dom.Attr.renameForTag[ key ] || key;\r
+                                       \r
+                                       // [class~='val']\r
+                                       if( !isXML && key === 'class' && op === 3 ){\r
+                                               val = _ + val + _;\r
+                                               for( i = 0, n = -1; xnode = xnodes[ i ]; ++i ){\r
+                                                       className = xnode._className;\r
+                                                       if( !!( className && ( _ + className + _ ).indexOf( val ) > -1 ) ^ isNot ) tmp[ ++n ] = xnode;\r
+                                               };\r
+                                       } else {\r
+                                       // 通常\r
+                                               // 諦めて、funcAttrを呼ぶ\r
+                                               // flag_call  = ($.browser.safari && key === 'selected');\r
+                                               // getAttributeを使わない\r
+                                               useName = X.UA.IE && key !== 'href' && key !== 'src';\r
+                                               toLower = !!val && !isXML && noLower.indexOf( key ) === -1; //!noLower.test(key);\r
+                                               if( toLower ) val = val.toLowerCase();\r
+                                               if( op === 3 ) val = _ + val + _;\r
+\r
+                                               for( i = 0, n = -1, l = xnodes.length; i < l; ++i ){\r
+                                                       xnode = xnodes[ i ];\r
+                                                       attr =\r
+                                                               key === 'id' ? xnode._id :\r
+                                                               key === 'class' ? xnode._className :\r
+                                                               xnode._attrs && xnode._attrs[ key ];\r
+                                                               //flag_call ?\r
+                                                               //      funcAttr( elem, key ) :\r
+                                                               //useName ?\r
+                                                               //      elem[ X.Dom.Attr.renameForDOM[ key ] || key ] :\r
+                                                               //      elem.getAttribute( key, 2 );\r
+                                                       flag = attr != null;// && ( !useName || attr !== '' );\r
+                                                       if( flag && op ){\r
+                                                               if( toLower ) attr = attr.toLowerCase();\r
+                                                               \r
+                                                               switch( op ){\r
+                                                                       case 1: // =\r
+                                                                               flag = attr === val;\r
+                                                                               break;\r
+                                                                       case 2: // !=\r
+                                                                               flag = attr !== val;\r
+                                                                               break;\r
+                                                                       case 3: // ~=\r
+                                                                               flag = ( _ + attr + _ ).indexOf( val ) !== -1;\r
+                                                                               break;\r
+                                                                       case 4: // ^=\r
+                                                                               flag = attr.indexOf( val ) === 0;\r
+                                                                               break;\r
+                                                                       case 5: // $=\r
+                                                                               flag = attr.lastIndexOf( val ) + val.length === attr.length;\r
+                                                                               break;\r
+                                                                       case 6: // *=\r
+                                                                               flag = attr.indexOf( val ) !== -1;\r
+                                                                               break;\r
+                                                                       case 7: // |=\r
+                                                                               flag = attr === val || attr.substring( 0, val.length + 1 ) === val + '-';\r
+                                                                               break;\r
+                                                               };\r
+                                                       };\r
+                                                       if( !!flag ^ isNot ) tmp[ ++n ] = xnode;\r
+                                               };\r
+                                       };\r
+                                       xnodes = tmp;\r
+                               };\r
+                       };\r
+                       filter  = null;\r
+                       isNot   = false;\r
+                       parsed  = null;\r
+                       \r
+                       //console.log( '//end :' + ( xnodes && xnodes.length ) );\r
+               };\r
+               //console.log( 'multi:' + ( xnodes && xnodes.length ) );\r
+               \r
+               // tree 順に並び替え、同一要素の排除\r
+               if( isMulti ){\r
+                       xnodes && xnodes.length && ARY_PUSH.apply( ret, xnodes );\r
+                       l = ret.length;\r
+                       if( l < 2 ) return ret[ 0 ] || Node.none;\r
+                       \r
+                       xnodes = [];\r
+                       merge  = {};\r
+                       for( i = 0, n = -1; i < l; ++i ){\r
+                               //alert( 'multi:' + i )\r
+                               xnode = ret[ i ];\r
+                               if( !merge[ uid = xnode._uid ] ){\r
+                                       merge[ uid ] = true;\r
+                                       xnodes[ ++n ] = xnode;\r
+                               };\r
+                       };\r
+                       X.Dom.Query._sortElementOrder( ret = [], xnodes, hasRoot ? [ HTML ] : HTML._xnodes );\r
+                       xnodes = ret;\r
+               };\r
+\r
+               return xnodes.length === 1 ? xnodes[ 0 ] : new X.Dom.NodeList( xnodes );\r
+       };\r
+       \r
+       X.Dom.Query._sortElementOrder = function( newList, list, xnodes ){\r
+               var l = xnodes.length,\r
+                       i = 0,\r
+                       j, child, _xnodes;\r
+               for( ; i < l; ++i ){\r
+                       child = xnodes[ i ];\r
+                       if( child._xnodeType !== 1 ) continue;\r
+                       //console.log( child._tag );\r
+                       if( ( j = list.indexOf( child ) ) !== -1 ){\r
+                               newList[ newList.length ] = child;\r
+                               list.splice( j, 1 );\r
+                               if( list.length === 1 ){\r
+                                       newList[ newList.length ] = list[ 0 ];\r
+                                       list.length = 0;\r
+                                       return true;\r
+                               };\r
+                               if( list.length === 0 ) return true;\r
+                       };\r
+                       if( ( _xnodes = child._xnodes ) && X.Dom.Query._sortElementOrder( newList, list, _xnodes ) ){\r
+                               return true;\r
+                       };\r
+               };\r
+       };\r
+       \r
+       X.Dom.Query._fetchElements = function( list, parent, tag ){\r
+               var xnodes = parent._xnodes,\r
+                       l      = xnodes.length,\r
+                       i      = 0,\r
+                       child;\r
+               for( ; i < l; ++i ){\r
+                       child = xnodes[ i ];\r
+                       if( child._xnodeType === 1 ){\r
+                               ( !tag || child._tag === tag ) && ( list[ list.length ] = child );\r
+                               //console.log( parent._tag + ' > ' + child._tag + ' == ' + tag+ ' l:' + list.length );\r
+                               child._xnodes && child._xnodes.length && X.Dom.Query._fetchElements( list, child, tag );\r
+                       };\r
+               };\r
+       };\r
+\r
+       X.Dom.Query._funcSelectorChild = function( type, flag_all, flags, xnodes ){\r
+               var res      = [],\r
+                       flag_not = flags.not,\r
+                       i = 0, n = -1, xnode, node,\r
+                       tagName, tmp;\r
+               for( ; xnode = xnodes[ i ]; ++i ){\r
+                       tagName = flag_all || xnode._tag;\r
+                       tmp     = null;\r
+                       if( /* tmp === null && */ type <= 0 ){\r
+                               for( node = xnode.prevNode(); node; node = node.prevNode() ){\r
+                                       if( node._xnodeType === 1 && ( flag_all || tagName === node._tag ) ){\r
+                                               tmp = false;\r
+                                               break;\r
+                                       };\r
+                               };\r
+                       };\r
+                       if( tmp === null && 0 <= type ){\r
+                               for( node = xnode.nextNode(); node; node = node.nextNode() ){\r
+                                       if( node._xnodeType === 1 && ( flag_all || tagName === node._tag ) ){\r
+                                               tmp = false;\r
+                                               break;\r
+                                       };              \r
+                               };                                              \r
+                       };\r
+                       if( tmp === null ) tmp = true;\r
+                       if( tmp ^ flag_not ) res[ ++n ] = xnode;\r
+               };\r
+               return res;\r
+       };\r
+       X.Dom.Query._funcSelectorNth = function( pointer, sibling, flag_all, flags, xnodes, a, b ){\r
+               var _data    = funcData,\r
+                       res      = [],\r
+                       checked  = {},\r
+                       flag_not = flags.not,\r
+                       i = 0, n = -1, uid,\r
+                       c, xnode, tmp, node, tagName;\r
+               for( ; xnode = xnodes[ i ]; ++i ){\r
+                       uid = xnode._uid;\r
+                       tmp = checked[ uid ];\r
+                       if( tmp === void 0 ){\r
+                               for( c = 0, node = xnode.parent[ pointer ](), tagName = flag_all || xnode._tag; node; node = node[ sibling ]() ){\r
+                                       if( node._xnodeType === 1 && ( flag_all || tagName === node._tag ) ){\r
+                                               ++c;\r
+                                               checked[ node._uid ] = a === 0 ? c === b : (c - b) % a === 0 && (c - b) / a >= 0;\r
+                                       };                                                      \r
+                               };\r
+                               tmp = checked[ uid ];\r
+                       };\r
+                       if( tmp ^ flag_not ) res[ ++n ] = xnode;\r
+               };\r
+               return res;\r
+       };\r
+       X.Dom.Query._funcSelectorProp = function( prop, flag, flags, xnodes ){\r
+               var res = [],\r
+                       flag_not = flag ? flags.not : !flags.not,\r
+                       i = 0, n = -1, xnode;\r
+               for( ; xnode = xnodes[ i ]; ++i ){\r
+                       if( xnode._attrs && xnode._attrs[ prop ] ^ flag_not ) res[ ++n ] = xnode;\r
+               };\r
+               return res;\r
+       };\r
+\r
+X.Dom.Query._filter = {\r
+       root : function( elem ){\r
+               return elem === ( elem.ownerDocument || elem.document ).documentElement;\r
+       },\r
+       target : {\r
+               m : function( flags, xnodes ){\r
+                       var res  = [],\r
+                               hash = location.hash.slice( 1 ),\r
+                               flag_not = flags.not,\r
+                               i = 0, n = -1, xnode;\r
+                       for ( ; xnode = xnodes[ i ]; ++i ){\r
+                               if( ( ( xnode._id || xnode._attrs && xnode._attrs.name ) === hash ) ^ flag_not ) res[ ++n ] = xnode;                                            \r
+                       };\r
+                       return res;\r
+               }\r
+       },\r
+       'first-child' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( -1, true, flags, xnodes ); }\r
+       },\r
+       'last-child' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( 1, true, flags, xnodes ); }\r
+       },\r
+       'only-child' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( 0, true, flags, xnodes ); }\r
+       },\r
+       'first-of-type' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( -1, false, flags, xnodes ); }\r
+       },\r
+       'last-of-type' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( 1, false, flags, xnodes ); }\r
+       },\r
+       'only-of-type' : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorChild( 0, false, flags, xnodes ); }\r
+       },\r
+       'nth-child' : {\r
+               m : function( flags, xnodes, a, b ){ return X.Dom.Query._funcSelectorNth( 'firstChild', 'nextNode', true, flags, xnodes, a, b ); }\r
+       },\r
+       'nth-last-child' : {\r
+               m : function( flags, xnodes, a, b ){ return X.Dom.Query._funcSelectorNth( 'lastChild', 'prevNode', true, flags, xnodes, a, b ); }\r
+       },\r
+       'nth-of-type' : {\r
+               m : function( flags, xnodes, a, b ){ return X.Dom.Query._funcSelectorNth( 'firstChild', 'nextNode', false, flags, xnodes, a, b ); }\r
+       },\r
+       'nth-last-of-type' : {\r
+               m : function( flags, xnodes, a, b ){ return X.Dom.Query._funcSelectorNth( 'lastChild', 'prevNode', false, flags, xnodes, a, b ); }\r
+       },\r
+       empty : {\r
+               m : function( flags, xnodes ){\r
+                       var res = [],\r
+                               flag_not = flags.not,\r
+                               i = 0, n = -1, xnode, tmp, node;\r
+                       for( ; xnode = xnodes[i]; ++i ){\r
+                               tmp = true;\r
+                               for( node = xnode.firstChild(); node; node = node.nextSibling() ){\r
+                                       if( node._xnodeType === 1 || ( node._xnodeType === 3 && node._text ) ){\r
+                                               tmp = false;\r
+                                               break;\r
+                                       };                              \r
+                               };\r
+                               if( tmp ^ flag_not ) res[ ++n ] = xnode;\r
+                       };\r
+                       return res;\r
+               }\r
+       },\r
+       link : {\r
+               m : function( flags, xnodes ){\r
+                       var links = ( xnodes[ 0 ].ownerDocument || xnodes[ 0 ].document ).links,\r
+                               _data = funcData,\r
+                               res   = [],\r
+                               checked, flag_not, i, link, xnode, n;\r
+                       if( !links ) return res;\r
+                       checked = {};\r
+                       flag_not = flags.not;\r
+                       for( i = 0; link = links[ i ]; ++i ){\r
+                               checked[ ( new Node( link ) )._uid ] = true;\r
+                       };\r
+                       for( i = 0, n = -1; xnode = xnodes[ i ]; ++i ){\r
+                               if( checked[ xnode._uid ] ^ flag_not ) res[ ++n ] = xnode;\r
+                       };\r
+                       return res;\r
+               }\r
+       },\r
+       lang : {\r
+               m : function( flags, xnodes, arg ){\r
+                       var res = [],\r
+                               //reg = new RegExp('^' + arg, 'i'),\r
+                               flag_not = flags.not,\r
+                               i = 0, n = -1, xnode, tmp, lang;\r
+                       arg = arg.toLowerCase();\r
+                       for( ; tmp = xnode = xnodes[ i ]; ++i ){\r
+                               while( tmp && !( lang = tmp._attrs && tmp._attrs[ 'lang' ] ) ){\r
+                                       tmp = tmp.parent;\r
+                               };\r
+                               //tmp = !!(tmp && reg.test(tmp.getAttribute('lang')));\r
+                               if( ( !!lang && lang.toLowerCase().indexOf( arg ) === 0 ) ^ flag_not ) res[ ++n ] = xnode;\r
+                       };\r
+                       return res;\r
+               }\r
+       },\r
+       enabled : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorProp( 'disabled', false, flags, xnodes ); }\r
+       },\r
+       disabled : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorProp( 'disabled', true, flags, xnodes ); }\r
+       },\r
+       checked : {\r
+               m : function( flags, xnodes ){ return X.Dom.Query._funcSelectorProp( 'checked', true, flags, xnodes ); }\r
+       },\r
+       contains : {\r
+               m : function( flags, xnodes, arg ){\r
+                       var res = [],\r
+                               flag_not = flags.not,\r
+                               i = 0, n = -1, xnode;\r
+                       for( ; xnode = xnodes[ i ]; ++i ){\r
+                               if ( ( -1 < ( xnode.text() ).indexOf( arg ) ) ^ flag_not ) res[ ++n ] = xnode;                                          \r
+                       };\r
+                       return res;\r
+               }\r
+       }\r
+};\r
+\r
+\r
+\r