OSDN Git Service

Version 0.6.16.
[pettanr/clientJs.git] / 0.6.x / js / dom / 18_XDomQuery.js
1 /* --------------------------------------
2  *  getByID
3  */
4 X.Dom.getByID =
5         document.getElementById ?
6                 (function( id ){
7                         return new X.Dom.Node( document.getElementById( id ) );
8                 }) :
9         document.all ?
10                 (function( id ){
11                         return new X.Dom.Node( document.all[ id ] );    
12                 }) :
13                 (function( id ){});
14
15 /* --------------------------------------
16  *  getByTag
17  */
18 Node.prototype.getByTag =
19         document.getElementsByTagName ?
20                 function( tag ){
21                         var parent = this.parent, elm, tags;
22                         if( !parent || this._xnodeType !== -1 ) return;
23                         if( !( elm = this._rawNode ) ) return;
24                         return new X.Dom.NodeList( document.getElementsByTagName( tag ) );
25                 } :
26         document.all ?
27                 (function( tag ){
28                         var parent = this.parent, elm, tags;
29                         if( !parent || this._xnodeType !== -1 ) return;
30                         if( !( elm = this._ie4getRawNode() ) ) return;
31                         Node.root._ie4reserved === true && Node.root._ie4startUpdate();
32                         return new X.Dom.NodeList( elm.all.tags( tag ) );       
33                 }) :
34                 (function( tag ){});
35
36 /* --------------------------------------
37  *  getByClass
38  */
39 Node.prototype.getByClass =
40                 document.getElementsByClassName ?
41                         (function( className ){
42                                 var parent = this.parent, elm;
43                                 if( !parent ) return;
44                                 if( !( elm = this._rawNode ) || elm.nodeType !== 1 ) return;
45                                 return new X.Dom.NodeList( elm.getElementsByClassName( className ) );
46                         }) :
47                 document.getElementsByTagName ?
48                         (function( className ){
49                                 var parent = this.parent,
50                                         live   = parent.getElementsByTagName( '*' ),
51                                         nodes  = [],
52                     test   = X.matchTest,
53                     node, i;
54                 className = className.split( ' ' );
55                 for( i = live.length; i; ){
56                         nodes[ --i ] = live[ i ];
57                 };
58                                 for( i = nodes.length; i; ){
59                                         node = nodes[ --i ];
60                                         ( node.nodeType !== 1 || !node.className || !node.className.length || !test( node.className.split( ' ' ), className ) ) && nodes.splice( i, 1 );
61                                 };
62                                 return new X.Dom.NodeList( nodes );
63                         }) :
64                 document.all ?
65                         (function( parent, className ){
66                                 var live  = parent.all,
67                                         nodes = [],
68                     test  = X.matchTest,
69                     node, i;
70                 for( i = live.length; i; ){
71                         nodes[ --i ] = live[ i ];
72                 };
73                                 for( i = nodes.length; i; ){
74                                         node = nodes[ --i ];
75                                         ( !node.className || !node.className.length || !test( node.className.split( ' ' ), className ) ) && nodes.splice( i, 1 );
76                                 };
77                                 return new X.Dom.NodeList( nodes );
78                         }) :
79                         (function(){});
80
81 X.Dom.find = Node.prototype.find = function( v ){
82         var root      = this.cnstructor === Node ? this : Node.root,
83                 selectors = X.Dom.Query._parse( v ),
84                 l, i, nodes, _nodes, selector,
85                 name, key, operator, value,
86                 j, m;
87         
88         if( !selectors ) return;
89         l     = selectors.length;
90         i     = 0;
91         nodes = [];
92         
93         for( ; i < l; ++i ){
94                 selector = selectors[ i ];
95                 if( 2 <= selector.length ){
96                         operator = selector[ 2 ];
97                         value    = selector[ 3 ];
98                         name     = key = selector[ 1 ];
99                         selector = selector[ 0 ];
100                 };
101                 switch( selector ){
102                         case 4 : // # id
103                                 nodes = [ X.Dom.getById( name ) ];
104                                 break;
105                         case 5 : // . classname
106                                 _nodes = [];
107                                 for( j = 0, m = nodes.length; j < m; ++j ){
108                                         _nodes = _nodes.concat( nodes[ j ].getByClass( name ) );
109                                 };
110                                 nodes = _nodes;
111                                 break;
112                         case 6 : // :focus, :disabled ...
113                                 switch( name ){
114                                         case 'focus' :
115                                         case 'disabled' :
116                                         case 'checked' :
117                                         case 'enabled' :
118                                         case 'empty' :
119                                         case 'only-of-type' :
120                                         case '' :
121                                         case 'target' :
122                                         case 'link' :
123                                         case 'visited' :
124                                         case 'hover' :
125                                         case 'active' :
126                                         case 'first-line' :
127                                         case 'first-letter' :
128                                         case 'before' :
129                                         case 'after' :
130                                         case ':selection' :
131                                         case 'lang()' :
132                                         case 'not()' :
133                                 };
134                                 break;
135                         case 7 : // [
136                                 
137                                 break;  
138                         case 8 : // . tagname
139                                 _nodes = [];
140                                 for( j = 0, m = nodes.length ; j < m; ++j ){
141                                         _nodes = _nodes.concat( nodes[ j ].getByTag( name ) );
142                                 };
143                                 nodes = _nodes;
144                                 break;
145                 };
146         };
147         return new X.Dom.NodeList( nodes );
148 };
149
150 X.Dom.Query = {
151         
152 };
153
154 X.Dom.Query._parse = function( query ){
155         var HASH_SELECTOR = {
156                 ' '   : 0,
157                 '>'   : 1,
158                 '+'   : 2,
159                 '~'   : 3,
160                 '#'   : 4,
161                 '.'   : 5,
162                 ':'   : 6,
163                 '['   : 7,
164                 scope : 9,
165                 root  : 10,
166                 link  : 11
167         };
168         var OPERATORS = { "!=": 2, "~=": 3, "^=": 4, "$=": 5, "*=": 6, "|=": 7 };
169         var ALPHABET  = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789\\';
170
171         query += ' ';
172         var result    = [],
173                 i         = 0,
174                 l         = query.length,
175                 phase     = 0,
176                 selector  = -1,
177                 last      = 0,
178                 chr, index, start, name, key, value, operator, nameChr, name1st, escape;
179         while( i < l ){
180                 chr     = query.charAt( i );
181                 index   = ALPHABET.indexOf( chr );
182                 nameChr = index !== -1;
183                 name1st = nameChr && index < 52;
184                 switch( phase ){
185                         case 99 :
186                                 return;
187                         case 0 :
188                                 name1st ? // tagName
189                                         ( ( selector = 8 ) && ( phase = 2 ) && ( start = i ) ) :
190                                 ( index = HASH_SELECTOR.indexOf( chr ) ) === 7 ? // [
191                                         ( ( selector = 7 ) && ( phase = 3 ) ) :
192                                 0 <= index ?
193                                         ( ( selector = index ) && ( phase = index < 4 ? 9 : 1 ) ) :
194                                 chr !== ' ' &&
195                                         ( phase = 99 );
196                                 break;
197                         case 1 :
198                                 name1st ?
199                                         ( ( start = i ) && ( phase = 2 ) ) :
200                                         ( phase = 99 );
201                                 break;
202                         case 2 :
203                                 !nameChr &&
204                                 !( escape && ( selector === 4 || selector === 5 ) &&  ( chr === ':' || chr === '.' ) ) // id or class の場合 : . を直前にエスケープした場合に限り使える
205                                         && ( name = query.substring( start, i ) ) && ( phase = 9 );
206                                 break;
207                         case 3 : // start attr filter
208                                 name1st ?
209                                         ( ( phase = 4 ) && ( start = i ) ) :
210                                         ( phase = 99 );
211                                 break;
212                         case 4 : // attr filter key
213                                 chr === '=' ?
214                                         ( ( operator = 1 ) && ( phase = 5 ) && ( key = query.substring( start, i ) ) && ( start = i ) ) :
215                                 ( index = OPERATORS[ query.substr( i, 2 ) ] ) ?
216                                         ( ( operator = index ) && ( phase = 5 ) && ( key = query.substring( start, i ) )  && ( start = i ) && ++i ) :
217                                 chr !== ' ' &&
218                                         ( phase = 99 );
219                                 break;
220                         case 5 : // attr filter value
221                                 chr === ']' ?
222                                         ( ( phase = 9 ) && ( value = query.substring( start, i ) ) ) :
223                                 !nameChr &&
224                                         ( phase = 99 );
225                                 break;
226                         default :
227                 };
228                 //alert( chr + ' ' + phase + ' ' + selector + ' ' + name + ' ' + name1st )
229                 if( phase === 9 ){
230                         if( last < 4 && selector < 4 ){
231                                 if( last === 0 ){
232                                         result[ result.length - 1 ] = selector; // override
233                                         last = selector;
234                                 } else {
235                                         return; // error
236                                 };
237                         } else { // 前回今回とも子孫セレクタの場合、保存しない
238                                 result[ result.length ] =
239                                         selector < 4 ?
240                                                 selector :
241                                         selector === 7 ?
242                                                 [ selector, key, operator, value ] :
243                                                 [ selector, name.split( '\\' ).join( '' ) ];
244                                 last = selector;
245                         };
246                         selector = -1;
247                         phase    = 0;
248                 } else
249                 if( phase === 99 ) return;
250
251                 escape = chr === '\\' && !escape;
252         };
253         return result;
254 };
255