1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/testing/mochitest/tests/MochiKit-1.4.2/MochiKit/Selector.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,415 @@ 1.4 +/*** 1.5 + 1.6 +MochiKit.Selector 1.4.2 1.7 + 1.8 +See <http://mochikit.com/> for documentation, downloads, license, etc. 1.9 + 1.10 +(c) 2005 Bob Ippolito and others. All rights Reserved. 1.11 + 1.12 +***/ 1.13 + 1.14 +MochiKit.Base._deps('Selector', ['Base', 'DOM', 'Iter']); 1.15 + 1.16 +MochiKit.Selector.NAME = "MochiKit.Selector"; 1.17 +MochiKit.Selector.VERSION = "1.4.2"; 1.18 + 1.19 +MochiKit.Selector.__repr__ = function () { 1.20 + return "[" + this.NAME + " " + this.VERSION + "]"; 1.21 +}; 1.22 + 1.23 +MochiKit.Selector.toString = function () { 1.24 + return this.__repr__(); 1.25 +}; 1.26 + 1.27 +MochiKit.Selector.EXPORT = [ 1.28 + "Selector", 1.29 + "findChildElements", 1.30 + "findDocElements", 1.31 + "$$" 1.32 +]; 1.33 + 1.34 +MochiKit.Selector.EXPORT_OK = [ 1.35 +]; 1.36 + 1.37 +MochiKit.Selector.Selector = function (expression) { 1.38 + this.params = {classNames: [], pseudoClassNames: []}; 1.39 + this.expression = expression.toString().replace(/(^\s+|\s+$)/g, ''); 1.40 + this.parseExpression(); 1.41 + this.compileMatcher(); 1.42 +}; 1.43 + 1.44 +MochiKit.Selector.Selector.prototype = { 1.45 + /*** 1.46 + 1.47 + Selector class: convenient object to make CSS selections. 1.48 + 1.49 + ***/ 1.50 + __class__: MochiKit.Selector.Selector, 1.51 + 1.52 + /** @id MochiKit.Selector.Selector.prototype.parseExpression */ 1.53 + parseExpression: function () { 1.54 + function abort(message) { 1.55 + throw 'Parse error in selector: ' + message; 1.56 + } 1.57 + 1.58 + if (this.expression == '') { 1.59 + abort('empty expression'); 1.60 + } 1.61 + 1.62 + var repr = MochiKit.Base.repr; 1.63 + var params = this.params; 1.64 + var expr = this.expression; 1.65 + var match, modifier, clause, rest; 1.66 + while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!^$*]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { 1.67 + params.attributes = params.attributes || []; 1.68 + params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); 1.69 + expr = match[1]; 1.70 + } 1.71 + 1.72 + if (expr == '*') { 1.73 + return this.params.wildcard = true; 1.74 + } 1.75 + 1.76 + while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+(?:\([^)]*\))?)(.*)/i)) { 1.77 + modifier = match[1]; 1.78 + clause = match[2]; 1.79 + rest = match[3]; 1.80 + switch (modifier) { 1.81 + case '#': 1.82 + params.id = clause; 1.83 + break; 1.84 + case '.': 1.85 + params.classNames.push(clause); 1.86 + break; 1.87 + case ':': 1.88 + params.pseudoClassNames.push(clause); 1.89 + break; 1.90 + case '': 1.91 + case undefined: 1.92 + params.tagName = clause.toUpperCase(); 1.93 + break; 1.94 + default: 1.95 + abort(repr(expr)); 1.96 + } 1.97 + expr = rest; 1.98 + } 1.99 + 1.100 + if (expr.length > 0) { 1.101 + abort(repr(expr)); 1.102 + } 1.103 + }, 1.104 + 1.105 + /** @id MochiKit.Selector.Selector.prototype.buildMatchExpression */ 1.106 + buildMatchExpression: function () { 1.107 + var repr = MochiKit.Base.repr; 1.108 + var params = this.params; 1.109 + var conditions = []; 1.110 + var clause, i; 1.111 + 1.112 + function childElements(element) { 1.113 + return "MochiKit.Base.filter(function (node) { return node.nodeType == 1; }, " + element + ".childNodes)"; 1.114 + } 1.115 + 1.116 + if (params.wildcard) { 1.117 + conditions.push('true'); 1.118 + } 1.119 + if (clause = params.id) { 1.120 + conditions.push('element.id == ' + repr(clause)); 1.121 + } 1.122 + if (clause = params.tagName) { 1.123 + conditions.push('element.tagName.toUpperCase() == ' + repr(clause)); 1.124 + } 1.125 + if ((clause = params.classNames).length > 0) { 1.126 + for (i = 0; i < clause.length; i++) { 1.127 + conditions.push('MochiKit.DOM.hasElementClass(element, ' + repr(clause[i]) + ')'); 1.128 + } 1.129 + } 1.130 + if ((clause = params.pseudoClassNames).length > 0) { 1.131 + for (i = 0; i < clause.length; i++) { 1.132 + var match = clause[i].match(/^([^(]+)(?:\((.*)\))?$/); 1.133 + var pseudoClass = match[1]; 1.134 + var pseudoClassArgument = match[2]; 1.135 + switch (pseudoClass) { 1.136 + case 'root': 1.137 + conditions.push('element.nodeType == 9 || element === element.ownerDocument.documentElement'); break; 1.138 + case 'nth-child': 1.139 + case 'nth-last-child': 1.140 + case 'nth-of-type': 1.141 + case 'nth-last-of-type': 1.142 + match = pseudoClassArgument.match(/^((?:(\d+)n\+)?(\d+)|odd|even)$/); 1.143 + if (!match) { 1.144 + throw "Invalid argument to pseudo element nth-child: " + pseudoClassArgument; 1.145 + } 1.146 + var a, b; 1.147 + if (match[0] == 'odd') { 1.148 + a = 2; 1.149 + b = 1; 1.150 + } else if (match[0] == 'even') { 1.151 + a = 2; 1.152 + b = 0; 1.153 + } else { 1.154 + a = match[2] && parseInt(match) || null; 1.155 + b = parseInt(match[3]); 1.156 + } 1.157 + conditions.push('this.nthChild(element,' + a + ',' + b 1.158 + + ',' + !!pseudoClass.match('^nth-last') // Reverse 1.159 + + ',' + !!pseudoClass.match('of-type$') // Restrict to same tagName 1.160 + + ')'); 1.161 + break; 1.162 + case 'first-child': 1.163 + conditions.push('this.nthChild(element, null, 1)'); 1.164 + break; 1.165 + case 'last-child': 1.166 + conditions.push('this.nthChild(element, null, 1, true)'); 1.167 + break; 1.168 + case 'first-of-type': 1.169 + conditions.push('this.nthChild(element, null, 1, false, true)'); 1.170 + break; 1.171 + case 'last-of-type': 1.172 + conditions.push('this.nthChild(element, null, 1, true, true)'); 1.173 + break; 1.174 + case 'only-child': 1.175 + conditions.push(childElements('element.parentNode') + '.length == 1'); 1.176 + break; 1.177 + case 'only-of-type': 1.178 + conditions.push('MochiKit.Base.filter(function (node) { return node.tagName == element.tagName; }, ' + childElements('element.parentNode') + ').length == 1'); 1.179 + break; 1.180 + case 'empty': 1.181 + conditions.push('element.childNodes.length == 0'); 1.182 + break; 1.183 + case 'enabled': 1.184 + conditions.push('(this.isUIElement(element) && element.disabled === false)'); 1.185 + break; 1.186 + case 'disabled': 1.187 + conditions.push('(this.isUIElement(element) && element.disabled === true)'); 1.188 + break; 1.189 + case 'checked': 1.190 + conditions.push('(this.isUIElement(element) && element.checked === true)'); 1.191 + break; 1.192 + case 'not': 1.193 + var subselector = new MochiKit.Selector.Selector(pseudoClassArgument); 1.194 + conditions.push('!( ' + subselector.buildMatchExpression() + ')') 1.195 + break; 1.196 + } 1.197 + } 1.198 + } 1.199 + if (clause = params.attributes) { 1.200 + MochiKit.Base.map(function (attribute) { 1.201 + var value = 'MochiKit.DOM.getNodeAttribute(element, ' + repr(attribute.name) + ')'; 1.202 + var splitValueBy = function (delimiter) { 1.203 + return value + '.split(' + repr(delimiter) + ')'; 1.204 + } 1.205 + conditions.push(value + ' != null'); 1.206 + switch (attribute.operator) { 1.207 + case '=': 1.208 + conditions.push(value + ' == ' + repr(attribute.value)); 1.209 + break; 1.210 + case '~=': 1.211 + conditions.push('MochiKit.Base.findValue(' + splitValueBy(' ') + ', ' + repr(attribute.value) + ') > -1'); 1.212 + break; 1.213 + case '^=': 1.214 + conditions.push(value + '.substring(0, ' + attribute.value.length + ') == ' + repr(attribute.value)); 1.215 + break; 1.216 + case '$=': 1.217 + conditions.push(value + '.substring(' + value + '.length - ' + attribute.value.length + ') == ' + repr(attribute.value)); 1.218 + break; 1.219 + case '*=': 1.220 + conditions.push(value + '.match(' + repr(attribute.value) + ')'); 1.221 + break; 1.222 + case '|=': 1.223 + conditions.push(splitValueBy('-') + '[0].toUpperCase() == ' + repr(attribute.value.toUpperCase())); 1.224 + break; 1.225 + case '!=': 1.226 + conditions.push(value + ' != ' + repr(attribute.value)); 1.227 + break; 1.228 + case '': 1.229 + case undefined: 1.230 + // Condition already added above 1.231 + break; 1.232 + default: 1.233 + throw 'Unknown operator ' + attribute.operator + ' in selector'; 1.234 + } 1.235 + }, clause); 1.236 + } 1.237 + 1.238 + return conditions.join(' && '); 1.239 + }, 1.240 + 1.241 + /** @id MochiKit.Selector.Selector.prototype.compileMatcher */ 1.242 + compileMatcher: function () { 1.243 + var code = 'return (!element.tagName) ? false : ' + 1.244 + this.buildMatchExpression() + ';'; 1.245 + this.match = new Function('element', code); 1.246 + }, 1.247 + 1.248 + /** @id MochiKit.Selector.Selector.prototype.nthChild */ 1.249 + nthChild: function (element, a, b, reverse, sametag){ 1.250 + var siblings = MochiKit.Base.filter(function (node) { 1.251 + return node.nodeType == 1; 1.252 + }, element.parentNode.childNodes); 1.253 + if (sametag) { 1.254 + siblings = MochiKit.Base.filter(function (node) { 1.255 + return node.tagName == element.tagName; 1.256 + }, siblings); 1.257 + } 1.258 + if (reverse) { 1.259 + siblings = MochiKit.Iter.reversed(siblings); 1.260 + } 1.261 + if (a) { 1.262 + var actualIndex = MochiKit.Base.findIdentical(siblings, element); 1.263 + return ((actualIndex + 1 - b) / a) % 1 == 0; 1.264 + } else { 1.265 + return b == MochiKit.Base.findIdentical(siblings, element) + 1; 1.266 + } 1.267 + }, 1.268 + 1.269 + /** @id MochiKit.Selector.Selector.prototype.isUIElement */ 1.270 + isUIElement: function (element) { 1.271 + return MochiKit.Base.findValue(['input', 'button', 'select', 'option', 'textarea', 'object'], 1.272 + element.tagName.toLowerCase()) > -1; 1.273 + }, 1.274 + 1.275 + /** @id MochiKit.Selector.Selector.prototype.findElements */ 1.276 + findElements: function (scope, axis) { 1.277 + var element; 1.278 + 1.279 + if (axis == undefined) { 1.280 + axis = ""; 1.281 + } 1.282 + 1.283 + function inScope(element, scope) { 1.284 + if (axis == "") { 1.285 + return MochiKit.DOM.isChildNode(element, scope); 1.286 + } else if (axis == ">") { 1.287 + return element.parentNode === scope; 1.288 + } else if (axis == "+") { 1.289 + return element === nextSiblingElement(scope); 1.290 + } else if (axis == "~") { 1.291 + var sibling = scope; 1.292 + while (sibling = nextSiblingElement(sibling)) { 1.293 + if (element === sibling) { 1.294 + return true; 1.295 + } 1.296 + } 1.297 + return false; 1.298 + } else { 1.299 + throw "Invalid axis: " + axis; 1.300 + } 1.301 + } 1.302 + 1.303 + if (element = MochiKit.DOM.getElement(this.params.id)) { 1.304 + if (this.match(element)) { 1.305 + if (!scope || inScope(element, scope)) { 1.306 + return [element]; 1.307 + } 1.308 + } 1.309 + } 1.310 + 1.311 + function nextSiblingElement(node) { 1.312 + node = node.nextSibling; 1.313 + while (node && node.nodeType != 1) { 1.314 + node = node.nextSibling; 1.315 + } 1.316 + return node; 1.317 + } 1.318 + 1.319 + if (axis == "") { 1.320 + scope = (scope || MochiKit.DOM.currentDocument()).getElementsByTagName(this.params.tagName || '*'); 1.321 + } else if (axis == ">") { 1.322 + if (!scope) { 1.323 + throw "> combinator not allowed without preceding expression"; 1.324 + } 1.325 + scope = MochiKit.Base.filter(function (node) { 1.326 + return node.nodeType == 1; 1.327 + }, scope.childNodes); 1.328 + } else if (axis == "+") { 1.329 + if (!scope) { 1.330 + throw "+ combinator not allowed without preceding expression"; 1.331 + } 1.332 + scope = nextSiblingElement(scope) && [nextSiblingElement(scope)]; 1.333 + } else if (axis == "~") { 1.334 + if (!scope) { 1.335 + throw "~ combinator not allowed without preceding expression"; 1.336 + } 1.337 + var newscope = []; 1.338 + while (nextSiblingElement(scope)) { 1.339 + scope = nextSiblingElement(scope); 1.340 + newscope.push(scope); 1.341 + } 1.342 + scope = newscope; 1.343 + } 1.344 + 1.345 + if (!scope) { 1.346 + return []; 1.347 + } 1.348 + 1.349 + var results = MochiKit.Base.filter(MochiKit.Base.bind(function (scopeElt) { 1.350 + return this.match(scopeElt); 1.351 + }, this), scope); 1.352 + 1.353 + return results; 1.354 + }, 1.355 + 1.356 + /** @id MochiKit.Selector.Selector.prototype.repr */ 1.357 + repr: function () { 1.358 + return 'Selector(' + this.expression + ')'; 1.359 + }, 1.360 + 1.361 + toString: MochiKit.Base.forwardCall("repr") 1.362 +}; 1.363 + 1.364 +MochiKit.Base.update(MochiKit.Selector, { 1.365 + 1.366 + /** @id MochiKit.Selector.findChildElements */ 1.367 + findChildElements: function (element, expressions) { 1.368 + var uniq = function(arr) { 1.369 + var res = []; 1.370 + for (var i = 0; i < arr.length; i++) { 1.371 + if (MochiKit.Base.findIdentical(res, arr[i]) < 0) { 1.372 + res.push(arr[i]); 1.373 + } 1.374 + } 1.375 + return res; 1.376 + }; 1.377 + return MochiKit.Base.flattenArray(MochiKit.Base.map(function (expression) { 1.378 + var nextScope = ""; 1.379 + var reducer = function (results, expr) { 1.380 + if (match = expr.match(/^[>+~]$/)) { 1.381 + nextScope = match[0]; 1.382 + return results; 1.383 + } else { 1.384 + var selector = new MochiKit.Selector.Selector(expr); 1.385 + var elements = MochiKit.Iter.reduce(function (elements, result) { 1.386 + return MochiKit.Base.extend(elements, selector.findElements(result || element, nextScope)); 1.387 + }, results, []); 1.388 + nextScope = ""; 1.389 + return elements; 1.390 + } 1.391 + }; 1.392 + var exprs = expression.replace(/(^\s+|\s+$)/g, '').split(/\s+/); 1.393 + return uniq(MochiKit.Iter.reduce(reducer, exprs, [null])); 1.394 + }, expressions)); 1.395 + }, 1.396 + 1.397 + findDocElements: function () { 1.398 + return MochiKit.Selector.findChildElements(MochiKit.DOM.currentDocument(), arguments); 1.399 + }, 1.400 + 1.401 + __new__: function () { 1.402 + var m = MochiKit.Base; 1.403 + 1.404 + this.$$ = this.findDocElements; 1.405 + 1.406 + this.EXPORT_TAGS = { 1.407 + ":common": this.EXPORT, 1.408 + ":all": m.concat(this.EXPORT, this.EXPORT_OK) 1.409 + }; 1.410 + 1.411 + m.nameFunctions(this); 1.412 + } 1.413 +}); 1.414 + 1.415 +MochiKit.Selector.__new__(); 1.416 + 1.417 +MochiKit.Base._exportSymbols(this, MochiKit.Selector); 1.418 +