OSDN Git Service

Version 0.6.6
[pettanr/clientJs.git] / 0.6.x / js / dom / 16_XDomQuery.js
1 X.Dom.find = function( v ){
2         var selectors = parser( v ),
3                 l, i, nodes, _nodes, selector,
4                 name, key, operator, value,
5                 j, m;
6         
7         if( !selectors ) return;
8         l     = selectors.length;
9         i     = 0;
10         nodes = [];
11         
12         for( ; i < l; ++i ){
13                 selector = selectors[ i ];
14                 if( 2 <= selector.length ){
15                         operator = selector[ 2 ];
16                         value    = selector[ 3 ];
17                         name     = key = selector[ 1 ];
18                         selector = selector[ 0 ];
19                 };
20                 switch( selector ){
21                         case 4 : // # id
22                                 nodes = [ X.Dom.getById( name ) ];
23                                 break;
24                         case 5 : // . classname
25                                 _nodes = [];
26                                 for( j = 0, m = nodes.length; j < m; ++j ){
27                                         _nodes = _nodes.concat( nodes[ j ].getByClass( name ) );
28                                 };
29                                 nodes = _nodes;
30                                 break;
31                         case 6 : // :focus, :disabled ...
32                                 switch( name ){
33                                         case 'focus' :
34                                         case 'disabled' :
35                                         case 'checked' :
36                                         case 'enabled' :
37                                         case 'empty' :
38                                         case 'only-of-type' :
39                                         case '' :
40                                         case 'target' :
41                                         case 'link' :
42                                         case 'visited' :
43                                         case 'hover' :
44                                         case 'active' :
45                                         case 'first-line' :
46                                         case 'first-letter' :
47                                         case 'before' :
48                                         case 'after' :
49                                         case ':selection' :
50                                         case 'lang()' :
51                                         case 'not()' :
52                                 };
53                                 break;
54                         case 7 : // [
55                                 
56                                 break;  
57                         case 8 : // . tagname
58                                 _nodes = [];
59                                 for( j = 0, m = nodes.length ; j < m; ++j ){
60                                         _nodes = _nodes.concat( nodes[ j ].getByTag( name ) );
61                                 };
62                                 nodes = _nodes;
63                                 break;
64                 };
65         };
66         return new X.Dom.NodeList( nodes );
67 };
68
69
70 HASH_SELECTOR = {
71         ' '   : 0,
72         '>'   : 1,
73         '+'   : 2,
74         '~'   : 3,
75         '#'   : 4,
76         '.'   : 5,
77         ':'   : 6,
78         '['   : 7,
79         scope : 9,
80         root  : 10,
81         link  : 11
82 };
83 OPERATORS = { "!=": 2, "~=": 3, "^=": 4, "$=": 5, "*=": 6, "|=": 7 };
84 ALPHABET  = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789\\';
85
86 function parser( query ){
87         query += ' ';
88         var result    = [],
89                 i         = 0,
90                 l         = query.length,
91                 phase     = 0,
92                 selector  = -1,
93                 last      = 0,
94                 chr, index, start, name, key, value, operator, nameChr, name1st, escape;
95         while( i < l ){
96                 chr     = query.charAt( i );
97                 index   = ALPHABET.indexOf( chr );
98                 nameChr = index !== -1;
99                 name1st = nameChr && index < 52;
100                 switch( phase ){
101                         case 99 :
102                                 return;
103                         case 0 :
104                                 name1st ? // tagName
105                                         ( ( selector = 8 ) && ( phase = 2 ) && ( start = i ) ) :
106                                 ( index = HASH_SELECTOR.indexOf( chr ) ) === 7 ? // [
107                                         ( ( selector = 7 ) && ( phase = 3 ) ) :
108                                 0 <= index ?
109                                         ( ( selector = index ) && ( phase = index < 4 ? 9 : 1 ) ) :
110                                 chr !== ' ' &&
111                                         ( phase = 99 );
112                                 break;
113                         case 1 :
114                                 name1st ?
115                                         ( ( start = i ) && ( phase = 2 ) ) :
116                                         ( phase = 99 );
117                                 break;
118                         case 2 :
119                                 !nameChr &&
120                                 !( escape && ( selector === 4 || selector === 5 ) &&  ( chr === ':' || chr === '.' ) ) // id or class の場合 : . を直前にエスケープした場合に限り使える
121                                         && ( name = query.substring( start, i ) ) && ( phase = 9 );
122                                 break;
123                         case 3 : // start attr filter
124                                 name1st ?
125                                         ( ( phase = 4 ) && ( start = i ) ) :
126                                         ( phase = 99 );
127                                 break;
128                         case 4 : // attr filter key
129                                 chr === '=' ?
130                                         ( ( operator = 1 ) && ( phase = 5 ) && ( key = query.substring( start, i ) ) && ( start = i ) ) :
131                                 ( index = OPERATORS[ query.substr( i, 2 ) ] ) ?
132                                         ( ( operator = index ) && ( phase = 5 ) && ( key = query.substring( start, i ) )  && ( start = i ) && ++i ) :
133                                 chr !== ' ' &&
134                                         ( phase = 99 );
135                                 break;
136                         case 5 : // attr filter value
137                                 chr === ']' ?
138                                         ( ( phase = 9 ) && ( value = query.substring( start, i ) ) ) :
139                                 !nameChr &&
140                                         ( phase = 99 );
141                                 break;
142                         default :
143                 };
144                 //alert( chr + ' ' + phase + ' ' + selector + ' ' + name + ' ' + name1st )
145                 if( phase === 9 ){
146                         if( last < 4 && selector < 4 ){
147                                 if( last === 0 ){
148                                         result[ result.length - 1 ] = selector; // override
149                                         last = selector;
150                                 } else {
151                                         return; // error
152                                 };
153                         } else { // 前回今回とも子孫セレクタの場合、保存しない
154                                 result[ result.length ] =
155                                         selector < 4 ?
156                                                 selector :
157                                         selector === 7 ?
158                                                 [ selector, key, operator, value ] :
159                                                 [ selector, name.split( '\\' ).join( '' ) ];
160                                 last = selector;
161                         };
162                         selector = -1;
163                         phase    = 0;
164                 } else
165                 if( phase === 99 ) return;
166
167                 escape = chr === '\\' && !escape;
168         };
169         return result;
170 };