1 (function() {
2 /*
3 * css 1.1 - cmc3 CSS selectors JavaScript library
4 * 2009 09 16
5 * Copyright (c) 2008-2009 蔡美纯 (cmc3.cn),
6 */
7 var d = document,w = this;
8 var css = function(selector, root, noCache) {
9 if (css.c[selector] && !noCache && !root) {
10 return css.c[selector];
11 }
12
13 /* 是否缓存结果 */
14 noCache = noCache || !!root;
15 /* root默认为document */
16 root = root || d;
17 var sets = [];
18 selector = selector.replace(/^\s+|\s+$/g, "");
19 if (css.q&&root===d) sets = sets.slice.call(d.querySelectorAll(selector),0);
20 else sets=css[/[:[\s>+~.#,]+/.test(selector.slice(1)) ? "e": "s"](selector, root, sets);
21 /* 是否返回缓存结果 */
22 return noCache ? sets: css.c[selector] = sets;
23 }; //css 函数结束
24 /* 查找函数开始.. */
25 css.s = function(selector, root, array) {
26
27 var idx = 0,
28 aim;
29 /*检测选择器的第一个字符*/
30 switch (selector.charAt(0)) {
31 case '#':
32 idx = selector.slice(1);
33 aim = d.getElementById(idx);
34 /*修正IE中返回name属性而非id属性的元素*/
35 if (css.browser.ie && aim.id !== idx) {
36 aim = d.all[idx];
37 }
38 aim && (array[0] = aim);
39 break;
40 case '.':
41 var klass = selector.slice(1);
42 if (css.k) {
43 aim = root.getElementsByClassName(klass);
44 if (idx = aim.length) {
45 while (idx--) array[idx] = aim[idx];
46
47 }
48
49 } else {
50 klass = ' ' + klass + ' ';
51 var lot = root.getElementsByTagName('*'),
52 i = 0,
53 node;
54 while (node = lot[i++]) {
55 if ((' ' + node.className + ' ').indexOf(klass) > -1) {
56 array[idx++] = node;
57 }
58
59 }
60
61 }
62 break;
63 case ':':
64 var node, lot = root.getElementsByTagName('*'),
65 i = 0,
66 ind = selector.replace(/[^(]*\(([^)]*)\)/, "$1"),
67 mod = selector.replace(/\(.*/, '');
68 while (node = lot[i++]) {
69 if (css.mods[mod] && !css.mods[mod](node, ind)) {
70 array[idx++] = node;
71 }
72 }
73
74 break;
75 case '[':
76
77 var lot = root.getElementsByTagName('*'),
78 node,
79 i = 0,
80 attrs = /\[([^!~^*|$ [:=]+)([$^*|!]?=)?([^ :\]]+)?\]/.exec(selector),
81 attr = attrs[1],
82 eql = attrs[2] || '',
83 value = attrs[3];
84
85 while (node = lot[i++]) {
86
87 if (css.attr[eql] && (css.attr[eql](node, attr === 'class' ? 'className': attr, value))) {
88
89 array[idx++] = node;
90 }
91 }
92
93 break;
94 default:
95 try{array = [].slice.call(root.getElementsByTagName(selector),0)}
96 catch(e){
97 aim = root.getElementsByTagName(selector);
98 if (idx = aim.length) {
99 while (idx--) array[idx] = aim[idx];
100
101 };
102 }
103
104
105 break;
106 }
107 return array;
108 };
109 css.e = function(selector, root, sets) {
110 var row = selector.split(/ *, */),
111 findit = [],
112 rlen = row.length,csstr,crumb,laststr,look,i,bridge,lot,tag,id,klass,attr,eql,val,mod,ind,isfind,
113 J,child,end,childs,elem,g,h,out,u;
114 while (rlen--) {
115 csstr = row[rlen]
116 if (! (lot = css.c[csstr]) || noCache) {
117 //*属性选择器里面可能会有特殊符号,分为两种类型处理*//
118 if(!/\[.*\]/.test(csstr) || /\[[^ +~>]+\]/.test(csstr)) crumb = csstr.replace(/([~>+])/g, " $1 ").split(/ +/);
119 else crumb=css.spl(csstr);
120
121 laststr = crumb.length;
122 i = 0;
123 bridge = ' ';
124 lot = [root];
125
126 while (look = crumb[i++]) {
127
128 if (!/^[ >+~]$/.test(look) && lot) {
129 /*取得所有匹配结果*/
130 look = look.match(/([^[:.#]+)?(?:#([^[:.#]+))?(?:\.([^[:.]+))?(?:\[([^!&^*|$[:=]+)([!$^*|&]?=)?([^:\]]+)?\])?(?:\:([^(]+)(?:\(([^)]+)\))?)?/);
131 tag = (look[1] || '*').toLowerCase();
132 id = look[2];
133 klass = look[3] ? ' ' + look[3] + ' ': '';
134 attr = look[4];
135 eql = look[5] || '';
136 val = look[6];
137 val = val&&val.replace(/^['"]|['"]$/g,"")
138 mod = look[7];
139 ind = mod === 'nth-child' || mod === 'nth-last-child' ? /(?:(-?\d*)n)?(?:(%|-)(\d*))?/.exec(look[8] === 'even' && '2n' || look[8] === 'odd' && '2n%1' || !/\D/.test(look[8]) && '0n%' + look[8] || look[8]) : look[8];
140
141 isfind = [];
142 J = 0;
143 end = i == laststr;
144 while (child = lot[J++]) {
145 switch (bridge) {
146 case ' ':
147
148 childs = child.getElementsByTagName(tag);
149 h = 0;
150 while (elem = childs[h++]) {
151
152 if (elem.nodeType == 1) css.grep(elem, isfind, end, tag, id, klass, attr, eql, val, mod, ind);
153 }
154 break;
155 case '~':
156 while (child = child.nextSibling) {
157 if (child.nodeType == 1 ) {
158 css.grep(child, isfind, end, tag, id, klass, attr, eql, val, mod, ind);
159 }
160 }
161 break;
162 case '+':
163 while ((child = child.nextSibling) && child.nodeType != 1) {}
164 css.grep(child, isfind, end, tag, id, klass, attr, eql, val, mod, ind);
165 break;
166 case '>':
167
168 childs = child.childNodes;
169
170 g = 0;
171 while (elem = childs[g++]) {
172 if (elem.nodeType == 1) css.grep(elem, isfind, end, tag, id, klass, attr, eql, val, mod, ind);
173 }
174 break
175 }
176 }
177 lot = isfind;
178 bridge = ' ';
179 } else {
180
181 bridge = look
182 }
183 }
184 }
185 findit = findit.concat(lot);
186 }
187 u=0;
188 while(out=findit[u++]){
189 out._css = out.nodeIndex = out.nodeIndexLast = null;
190 };
191 return findit;
192 };
193 /*保存缓存结果*/
194 css.c = [];
195
196 css.attr = {
197 /*匹配包含给定属性的元素。*/
198 '': function(child, attr) {
199 return !! child.getAttribute(attr);
200 },
201 /*匹配给定的属性是某个特定值的元素*/
202 '=': function(child, attr, value) {
203
204 return (attr = child.getAttribute(attr)) && attr === value;
205 },
206 /*匹配包含给定的属性(以空格分开)值的元素*/
207 '&=': function(child, attr, value) {
208 return (attr = child.getAttribute(attr)) && (new RegExp('(^| +)' + value + '($| +)').test(attr));
209 },
210 /*匹配给定的属性是以某些值开头的元素*/
211 '^=': function(child, attr, value) {
212
213 return (attr = child.getAttribute(attr) + '') && !attr.indexOf(value);
214 },
215 /*匹配给定的属性是以某些值结尾的元素*/
216 '$=': function(child, attr, value) {
217
218 return (attr = child.getAttribute(attr) + '') && attr.indexOf(value) == attr.length - value.length;
219 },
220 /*匹配给定的属性是以包含某些值的元素*/
221 '*=': function(child, attr, value) {
222 return (attr = child.getAttribute(attr) + '') && attr.indexOf(value) != -1;
223 },
224 /*匹配含有属性(连字符相连)值的元素。*/
225 '|=': function(child, attr, value) {
226 return (attr = child.getAttribute(attr) + '') && (attr === value || !!attr.indexOf(value + '-'));
227 },
228 /*匹配所有不含有指定的属性,或者属性不等于特定值的元素。*/
229 '!=': function(child, attr, value) {
230 return ! (attr = child.getAttribute(attr)) || !(new RegExp('(^| +)' + value + '($| +)').test(attr));
231 }
232 };
233
234 css.mods = {
235 /*匹配第一个子元素*/
236 'first-child': function(child) {
237
238 return child.parentNode.getElementsByTagName('*')[0] !== child;
239 },
240 /*匹配最后一个子元素*/
241 'last-child': function(child) {
242 var brother = child;
243
244 while ((brother = brother.nextSibling) && brother.nodeType != 1) {}
245
246 return !! brother;
247 },
248 /*匹配html*/
249 root: function(child) {
250 return child.nodeName.toLowerCase() !== 'html';
251 },
252 /*匹配其父元素下的第N个子或奇偶元素
253 可以使用:
254 nth-child(even)
255 :nth-child(odd)
256 :nth-child(3n)
257 :nth-child(2)
258 :nth-child(3n+1)
259 :nth-child(3n+2)
260 */
261 'nth-child': function(child, ind) {
262 var i = child.nodeIndex || 0,
263 a = ind[3] = ind[3] ? (ind[2] === '%' ? -1 : 1) * ind[3] : 0,
264 b = ind[1];
265
266 if (i) {
267 return ! ((i + a) % b);
268 } else {
269
270 var brother = child.parentNode.firstChild;
271 i++;
272
273 do {
274
275 if (brother.nodeType == 1 && (brother.nodeIndex = ++i) && child === brother && ((i + a) % b)) {
276 return 0;
277 }
278 } while ( brother = brother . nextSibling );
279 return 1;
280 }
281 },
282 /*匹配所有不包含子元素或者文本的空元素*/
283 empty: function(child) {
284 return !! child.firstChild;
285 },
286 /*匹配含有子元素或者文本的元素*/
287 parent: function(child) {
288 return ! child.firstChild;
289 },
290 /*如果某个元素是父元素中唯一的子元素,那将会被匹配*/
291 'only-child': function(child) {
292 return child.parentNode.getElementsByTagName('*').length != 1;
293 },
294 /*匹配所有选中的被选中元素(复选框、单选框等,不包括select中的option)*/
295 checked: function(child) {
296 return ! child.checked;
297 },
298
299 /*匹配所有可用元素*/
300 enabled: function(child) {
301 return child.disabled || child.type === 'hidden';
302 },
303 /*匹配所有可用元素*/
304 disabled: function(child) {
305 return ! child.disabled;
306 },
307 /*匹配所有选中的option元素*/
308 selected: function(child) {
309
310 return ! child.selected;
311
312 },
313 /*匹配含有选择器所匹配的元素的元素*/
314 has:function(){
315 //alert('wait')
316 }
317 };
318 css.grep= function (elem, isfind, end, tag, id, klass, attr, eql, val, mod, ind) {
319 /*一次查找所有匹配结果(如果有)*/
320 ( elem.nodeName.toLowerCase() === tag || tag === '*')&&
321 (!id || elem.id === id) &&
322 (!klass || (' ' + elem.className + ' ').indexOf(klass) > -1) &&
323 (!attr || (css.attr[eql] && (css.attr[eql](elem, attr === 'class' ? 'className': attr, val)))) &&
324 !elem._css &&
325 !(css.mods[mod] ? css.mods[mod](elem, ind) : mod) &&
326 (isfind.push(elem)) &&
327 end &&
328 (elem._css = 1);
329 };
330
331 css.spl=function (n){
332 /*处理包含复杂字符的[]表达式*/
333 var t=+new Date,
334 reg=/\[(\w+)([!$^*|&]?=)\s*(['"][^'"]*['"])\s*\]/g;
335 var ar=n.match(reg),e;
336 t=t+"cmccss"
337 n=n.replace(reg,t);
338 m=n.replace(/([~>+])/g, " $1 ").split(/ +/);
339 ml=m.length;
340 x=ar.length;
341 while(ml--) if((e=m[ml]).indexOf(t)>-1) m[ml]=e.replace(t,ar[--x]);
342 return m
343 };
344
345
346 css.ua = navigator.userAgent.toLowerCase();
347 /* 是否支持getElementsByClassName */
348 css.k = !!d.getElementsByClassName;
349
350 css.browser = {
351 opera: css.ua.indexOf('opera') != -1,
352 ie: css.ua.indexOf('msie') != -1 && css.ua.indexOf('opera') == -1
353 };
354 /* 是否支持querySelectorAll */
355 css.q = !!d.querySelectorAll ;
356
357 /* 设定全局变量 window.css */
358 w.css =css;
359 })();