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 })();