1 /** 2 * @description 3 * Package: jet.mini 4 * 5 * Need package: 6 * jet.core.js 7 * 8 */ 9 10 Jx().$package(function(J){ 11 12 13 /** 14 * "mini" Selector Engine 15 * Copyright (c) 2009 James Padolsey 16 * ------------------------------------------------------- 17 * Dual licensed under the MIT and GPL licenses. 18 * - http://www.opensource.org/licenses/mit-license.php 19 * - http://www.gnu.org/copyleft/gpl.html 20 * ------------------------------------------------------- 21 * Version: 0.01 (BETA) 22 */ 23 24 25 var mini = (function(){ 26 27 var snack = /(?:[\w\-\\.#]+)+(?:\[\w+?=([\'"])?(?:\\\1|.)+?\1\])?|\*|>/ig, 28 exprClassName = /^(?:[\w\-_]+)?\.([\w\-_]+)/, 29 exprId = /^(?:[\w\-_]+)?#([\w\-_]+)/, 30 exprNodeName = /^([\w\*\-_]+)/, 31 na = [null,null]; 32 33 function _find(selector, context) { 34 35 /* 36 * This is what you call via x() 37 * Starts everything off... 38 */ 39 40 context = context || document; 41 42 var simple = /^[\w\-_#]+$/.test(selector); 43 44 if (!simple && context.querySelectorAll) { 45 return realArray(context.querySelectorAll(selector)); 46 } 47 48 if (selector.indexOf(',') > -1) { 49 var split = selector.split(/,/g), ret = [], sIndex = 0, len = split.length; 50 for(; sIndex < len; ++sIndex) { 51 ret = ret.concat( _find(split[sIndex], context) ); 52 } 53 return unique(ret); 54 } 55 56 var parts = selector.match(snack), 57 part = parts.pop(), 58 id = (part.match(exprId) || na)[1], 59 className = !id && (part.match(exprClassName) || na)[1], 60 nodeName = !id && (part.match(exprNodeName) || na)[1], 61 collection; 62 63 if (className && !nodeName && context.getElementsByClassName) { 64 65 collection = realArray(context.getElementsByClassName(className)); 66 67 } else { 68 69 collection = !id && realArray(context.getElementsByTagName(nodeName || '*')); 70 71 if (className) { 72 collection = filterByAttr(collection, 'className', RegExp('(^|\\s)' + className + '(\\s|$)')); 73 } 74 75 if (id) { 76 var byId = context.getElementById(id); 77 return byId?[byId]:[]; 78 } 79 } 80 81 return parts[0] && collection[0] ? filterParents(parts, collection) : collection; 82 83 } 84 85 function realArray(c) { 86 87 /** 88 * Transforms a node collection into 89 * a real array 90 */ 91 92 try { 93 return Array.prototype.slice.call(c); 94 } catch(e) { 95 var ret = [], i = 0, len = c.length; 96 for (; i < len; ++i) { 97 ret[i] = c[i]; 98 } 99 return ret; 100 } 101 102 } 103 104 function filterParents(selectorParts, collection, direct) { 105 106 /** 107 * This is where the magic happens. 108 * Parents are stepped through (upwards) to 109 * see if they comply with the selector. 110 */ 111 112 var parentSelector = selectorParts.pop(); 113 114 if (parentSelector === '>') { 115 return filterParents(selectorParts, collection, true); 116 } 117 118 var ret = [], 119 r = -1, 120 id = (parentSelector.match(exprId) || na)[1], 121 className = !id && (parentSelector.match(exprClassName) || na)[1], 122 nodeName = !id && (parentSelector.match(exprNodeName) || na)[1], 123 cIndex = -1, 124 node, parent, 125 matches; 126 127 nodeName = nodeName && nodeName.toLowerCase(); 128 129 while ( (node = collection[++cIndex]) ) { 130 131 parent = node.parentNode; 132 133 do { 134 135 matches = !nodeName || nodeName === '*' || nodeName === parent.nodeName.toLowerCase(); 136 matches = matches && (!id || parent.id === id); 137 matches = matches && (!className || RegExp('(^|\\s)' + className + '(\\s|$)').test(parent.className)); 138 139 if (direct || matches) { break; } 140 141 } while ( (parent = parent.parentNode) ); 142 143 if (matches) { 144 ret[++r] = node; 145 } 146 } 147 148 return selectorParts[0] && ret[0] ? filterParents(selectorParts, ret) : ret; 149 150 } 151 152 153 var unique = (function(){ 154 155 var uid = +new Date(); 156 157 var data = (function(){ 158 159 var n = 1; 160 161 return function(elem) { 162 163 var cacheIndex = elem[uid], 164 nextCacheIndex = n++; 165 166 if(!cacheIndex) { 167 elem[uid] = nextCacheIndex; 168 return true; 169 } 170 171 return false; 172 173 }; 174 175 })(); 176 177 return function(arr) { 178 179 /** 180 * Returns a unique array 181 */ 182 183 var length = arr.length, 184 ret = [], 185 r = -1, 186 i = 0, 187 item; 188 189 for (; i < length; ++i) { 190 item = arr[i]; 191 if (data(item)) { 192 ret[++r] = item; 193 } 194 } 195 196 uid += 1; 197 198 return ret; 199 200 }; 201 202 })(); 203 204 function filterByAttr(collection, attr, regex) { 205 206 /** 207 * Filters a collection by an attribute. 208 */ 209 210 var i = -1, node, r = -1, ret = []; 211 212 while ( (node = collection[++i]) ) { 213 if (regex.test(node[attr])) { 214 ret[++r] = node; 215 } 216 } 217 218 return ret; 219 } 220 221 return _find; 222 223 })(); 224 225 226 227 228 /* 229 * //////////////////////////////////////////////////////////////// 230 * 231 * Adapter to JET 232 * 233 * //////////////////////////////////////////////////////////////// 234 */ 235 /** 236 * 一个据说比jq还快的筛选器,可以满足日常99%的筛选需要 237 * @function 238 * @memberOf dom 239 * @name mini 240 * 241 * @param {String} query string 筛选器语法 242 * @returns {Element} 返回筛选出的dom元素 243 * 244 * @example 245 * //创建一个匿名package包: 246 * Jx().$package(function(J){ 247 * //这时上下文对象this指向全局window对象 248 * var lists = J.dom.mini(".list"); 249 * }; 250 * 251 */ 252 J.dom.mini = mini; 253 254 255 256 }); 257