Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(297)

Side by Side Diff: chrome/test/data/dromaeo/lib/yui-selector.js

Issue 269054: Importing dromaeo performance tests to src/chrome/test/data.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/test/data/dromaeo/lib/yui-event.js ('k') | chrome/test/data/dromaeo/pngfix.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 Copyright (c) 2008, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.6.0
6 */
7 /**
8 * The selector module provides helper methods allowing CSS3 Selectors to be use d with DOM elements.
9 * @module selector
10 * @title Selector Utility
11 * @namespace YAHOO.util
12 * @requires yahoo, dom
13 */
14
15 (function() {
16 /**
17 * Provides helper methods for collecting and filtering DOM elements.
18 * @namespace YAHOO.util
19 * @class Selector
20 * @static
21 */
22 var Selector = function() {};
23
24 var Y = YAHOO.util;
25
26 var reNth = /^(?:([-]?\d*)(n){1}|(odd|even)$)*([-+]?\d*)$/;
27
28 Selector.prototype = {
29 /**
30 * Default document for use queries
31 * @property document
32 * @type object
33 * @default window.document
34 */
35 document: window.document,
36 /**
37 * Mapping of attributes to aliases, normally to work around HTMLAttributes
38 * that conflict with JS reserved words.
39 * @property attrAliases
40 * @type object
41 */
42 attrAliases: {
43 },
44
45 /**
46 * Mapping of shorthand tokens to corresponding attribute selector
47 * @property shorthand
48 * @type object
49 */
50 shorthand: {
51 //'(?:(?:[^\\)\\]\\s*>+~,]+)(?:-?[_a-z]+[-\\w]))+#(-?[_a-z]+[-\\w]*)': ' [id=$1]',
52 '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
53 '\\.(-?[_a-z]+[-\\w]*)': '[class~=$1]'
54 },
55
56 /**
57 * List of operators and corresponding boolean functions.
58 * These functions are passed the attribute and the current node's value of the attribute.
59 * @property operators
60 * @type object
61 */
62 operators: {
63 '=': function(attr, val) { return attr === val; }, // Equality
64 '!=': function(attr, val) { return attr !== val; }, // Inequality
65 '~=': function(attr, val) { // Match one of space seperated words
66 var s = ' ';
67 return (s + attr + s).indexOf((s + val + s)) > -1;
68 },
69 '|=': function(attr, val) { return getRegExp('^' + val + '[-]?').test(at tr); }, // Match start with value followed by optional hyphen
70 '^=': function(attr, val) { return attr.indexOf(val) === 0; }, // Match starts with value
71 '$=': function(attr, val) { return attr.lastIndexOf(val) === attr.length - val.length; }, // Match ends with value
72 '*=': function(attr, val) { return attr.indexOf(val) > -1; }, // Match c ontains value as substring
73 '': function(attr, val) { return attr; } // Just test for existence of a ttribute
74 },
75
76 /**
77 * List of pseudo-classes and corresponding boolean functions.
78 * These functions are called with the current node, and any value that was parsed with the pseudo regex.
79 * @property pseudos
80 * @type object
81 */
82 pseudos: {
83 'root': function(node) {
84 return node === node.ownerDocument.documentElement;
85 },
86
87 'nth-child': function(node, val) {
88 return getNth(node, val);
89 },
90
91 'nth-last-child': function(node, val) {
92 return getNth(node, val, null, true);
93 },
94
95 'nth-of-type': function(node, val) {
96 return getNth(node, val, node.tagName);
97 },
98
99 'nth-last-of-type': function(node, val) {
100 return getNth(node, val, node.tagName, true);
101 },
102
103 'first-child': function(node) {
104 return getChildren(node.parentNode)[0] === node;
105 },
106
107 'last-child': function(node) {
108 var children = getChildren(node.parentNode);
109 return children[children.length - 1] === node;
110 },
111
112 'first-of-type': function(node, val) {
113 return getChildren(node.parentNode, node.tagName.toLowerCase())[0];
114 },
115
116 'last-of-type': function(node, val) {
117 var children = getChildren(node.parentNode, node.tagName.toLowerCase ());
118 return children[children.length - 1];
119 },
120
121 'only-child': function(node) {
122 var children = getChildren(node.parentNode);
123 return children.length === 1 && children[0] === node;
124 },
125
126 'only-of-type': function(node) {
127 return getChildren(node.parentNode, node.tagName.toLowerCase()).leng th === 1;
128 },
129
130 'empty': function(node) {
131 return node.childNodes.length === 0;
132 },
133
134 'not': function(node, simple) {
135 return !Selector.test(node, simple);
136 },
137
138 'contains': function(node, str) {
139 var text = node.innerText || node.textContent || '';
140 return text.indexOf(str) > -1;
141 },
142 'checked': function(node) {
143 return node.checked === true;
144 }
145 },
146
147 /**
148 * Test if the supplied node matches the supplied selector.
149 * @method test
150 *
151 * @param {HTMLElement | String} node An id or node reference to the HTMLEle ment being tested.
152 * @param {string} selector The CSS Selector to test the node against.
153 * @return{boolean} Whether or not the node matches the selector.
154 * @static
155
156 */
157 test: function(node, selector) {
158 node = Selector.document.getElementById(node) || node;
159
160 if (!node) {
161 return false;
162 }
163
164 var groups = selector ? selector.split(',') : [];
165 if (groups.length) {
166 for (var i = 0, len = groups.length; i < len; ++i) {
167 if ( rTestNode(node, groups[i]) ) { // passes if ANY group match es
168 return true;
169 }
170 }
171 return false;
172 }
173 return rTestNode(node, selector);
174 },
175
176 /**
177 * Filters a set of nodes based on a given CSS selector.
178 * @method filter
179 *
180 * @param {array} nodes A set of nodes/ids to filter.
181 * @param {string} selector The selector used to test each node.
182 * @return{array} An array of nodes from the supplied array that match the g iven selector.
183 * @static
184 */
185 filter: function(nodes, selector) {
186 nodes = nodes || [];
187
188 var node,
189 result = [],
190 tokens = tokenize(selector);
191
192 if (!nodes.item) { // if not HTMLCollection, handle arrays of ids and/or nodes
193 for (var i = 0, len = nodes.length; i < len; ++i) {
194 if (!nodes[i].tagName) { // tagName limits to HTMLElements
195 node = Selector.document.getElementById(nodes[i]);
196 if (node) { // skip IDs that return null
197 nodes[i] = node;
198 } else {
199 }
200 }
201 }
202 }
203 result = rFilter(nodes, tokenize(selector)[0]);
204 clearParentCache();
205 return result;
206 },
207
208 /**
209 * Retrieves a set of nodes based on a given CSS selector.
210 * @method query
211 *
212 * @param {string} selector The CSS Selector to test the node against.
213 * @param {HTMLElement | String} root optional An id or HTMLElement to start the query from. Defaults to Selector.document.
214 * @param {Boolean} firstOnly optional Whether or not to return only the fir st match.
215 * @return {Array} An array of nodes that match the given selector.
216 * @static
217 */
218 query: function(selector, root, firstOnly) {
219 var result = query(selector, root, firstOnly);
220 return result;
221 }
222 };
223
224 var query = function(selector, root, firstOnly, deDupe) {
225 var result = (firstOnly) ? null : [];
226 if (!selector) {
227 return result;
228 }
229
230 var groups = selector.split(','); // TODO: handle comma in attribute/pseudo
231
232 if (groups.length > 1) {
233 var found;
234 for (var i = 0, len = groups.length; i < len; ++i) {
235 found = arguments.callee(groups[i], root, firstOnly, true);
236 result = firstOnly ? found : result.concat(found);
237 }
238 clearFoundCache();
239 return result;
240 }
241
242 if (root && !root.nodeName) { // assume ID
243 root = Selector.document.getElementById(root);
244 if (!root) {
245 return result;
246 }
247 }
248
249 root = root || Selector.document;
250 var tokens = tokenize(selector);
251 var idToken = tokens[getIdTokenIndex(tokens)],
252 nodes = [],
253 node,
254 id,
255 token = tokens.pop() || {};
256
257 if (idToken) {
258 id = getId(idToken.attributes);
259 }
260
261 // use id shortcut when possible
262 if (id) {
263 node = Selector.document.getElementById(id);
264
265 if (node && (root.nodeName == '#document' || contains(node, root))) {
266 if ( rTestNode(node, null, idToken) ) {
267 if (idToken === token) {
268 nodes = [node]; // simple selector
269 } else {
270 root = node; // start from here
271 }
272 }
273 } else {
274 return result;
275 }
276 }
277
278 if (root && !nodes.length) {
279 nodes = root.getElementsByTagName(token.tag);
280 }
281
282 if (nodes.length) {
283 result = rFilter(nodes, token, firstOnly, deDupe);
284 }
285
286 clearParentCache();
287 return result;
288 };
289
290 var contains = function() {
291 if (document.documentElement.contains && !YAHOO.env.ua.webkit < 422) { // I E & Opera, Safari < 3 contains is broken
292 return function(needle, haystack) {
293 return haystack.contains(needle);
294 };
295 } else if ( document.documentElement.compareDocumentPosition ) { // gecko
296 return function(needle, haystack) {
297 return !!(haystack.compareDocumentPosition(needle) & 16);
298 };
299 } else { // Safari < 3
300 return function(needle, haystack) {
301 var parent = needle.parentNode;
302 while (parent) {
303 if (needle === parent) {
304 return true;
305 }
306 parent = parent.parentNode;
307 }
308 return false;
309 };
310 }
311 }();
312
313 var rFilter = function(nodes, token, firstOnly, deDupe) {
314 var result = firstOnly ? null : [];
315
316 for (var i = 0, len = nodes.length; i < len; i++) {
317 if (! rTestNode(nodes[i], '', token, deDupe)) {
318 continue;
319 }
320
321 if (firstOnly) {
322 return nodes[i];
323 }
324 if (deDupe) {
325 if (nodes[i]._found) {
326 continue;
327 }
328 nodes[i]._found = true;
329 foundCache[foundCache.length] = nodes[i];
330 }
331
332 result[result.length] = nodes[i];
333 }
334
335 return result;
336 };
337
338 var rTestNode = function(node, selector, token, deDupe) {
339 token = token || tokenize(selector).pop() || {};
340
341 if (!node.tagName ||
342 (token.tag !== '*' && node.tagName.toUpperCase() !== token.tag) ||
343 (deDupe && node._found) ) {
344 return false;
345 }
346
347 if (token.attributes.length) {
348 var attribute;
349 for (var i = 0, len = token.attributes.length; i < len; ++i) {
350 attribute = node.getAttribute(token.attributes[i][0], 2);
351 if (attribute === null || attribute === undefined) {
352 return false;
353 }
354 if ( Selector.operators[token.attributes[i][1]] &&
355 !Selector.operators[token.attributes[i][1]](attribute, token .attributes[i][2])) {
356 return false;
357 }
358 }
359 }
360
361 if (token.pseudos.length) {
362 for (var i = 0, len = token.pseudos.length; i < len; ++i) {
363 if (Selector.pseudos[token.pseudos[i][0]] &&
364 !Selector.pseudos[token.pseudos[i][0]](node, token.pseudos[i ][1])) {
365 return false;
366 }
367 }
368 }
369
370 return (token.previous && token.previous.combinator !== ',') ?
371 combinators[token.previous.combinator](node, token) :
372 true;
373 };
374
375
376 var foundCache = [];
377 var parentCache = [];
378 var regexCache = {};
379
380 var clearFoundCache = function() {
381 for (var i = 0, len = foundCache.length; i < len; ++i) {
382 try { // IE no like delete
383 delete foundCache[i]._found;
384 } catch(e) {
385 foundCache[i].removeAttribute('_found');
386 }
387 }
388 foundCache = [];
389 };
390
391 var clearParentCache = function() {
392 if (!document.documentElement.children) { // caching children lookups for ge cko
393 return function() {
394 for (var i = 0, len = parentCache.length; i < len; ++i) {
395 delete parentCache[i]._children;
396 }
397 parentCache = [];
398 };
399 } else return function() {}; // do nothing
400 }();
401
402 var getRegExp = function(str, flags) {
403 flags = flags || '';
404 if (!regexCache[str + flags]) {
405 regexCache[str + flags] = new RegExp(str, flags);
406 }
407 return regexCache[str + flags];
408 };
409
410 var combinators = {
411 ' ': function(node, token) {
412 while (node = node.parentNode) {
413 if (rTestNode(node, '', token.previous)) {
414 return true;
415 }
416 }
417 return false;
418 },
419
420 '>': function(node, token) {
421 return rTestNode(node.parentNode, null, token.previous);
422 },
423
424 '+': function(node, token) {
425 var sib = node.previousSibling;
426 while (sib && sib.nodeType !== 1) {
427 sib = sib.previousSibling;
428 }
429
430 if (sib && rTestNode(sib, null, token.previous)) {
431 return true;
432 }
433 return false;
434 },
435
436 '~': function(node, token) {
437 var sib = node.previousSibling;
438 while (sib) {
439 if (sib.nodeType === 1 && rTestNode(sib, null, token.previous)) {
440 return true;
441 }
442 sib = sib.previousSibling;
443 }
444
445 return false;
446 }
447 };
448
449 var getChildren = function() {
450 if (document.documentElement.children) { // document for capability test
451 return function(node, tag) {
452 return (tag) ? node.children.tags(tag) : node.children || [];
453 };
454 } else {
455 return function(node, tag) {
456 if (node._children) {
457 return node._children;
458 }
459 var children = [],
460 childNodes = node.childNodes;
461
462 for (var i = 0, len = childNodes.length; i < len; ++i) {
463 if (childNodes[i].tagName) {
464 if (!tag || childNodes[i].tagName.toLowerCase() === tag) {
465 children[children.length] = childNodes[i];
466 }
467 }
468 }
469 node._children = children;
470 parentCache[parentCache.length] = node;
471 return children;
472 };
473 }
474 }();
475
476 /*
477 an+b = get every _a_th node starting at the _b_th
478 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" o r "1", not "0+1"), return only the _b_th element
479 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+ 0" or "n+0" or "n")
480 an+0 = get every _a_th element, "0" may be omitted
481 */
482 var getNth = function(node, expr, tag, reverse) {
483 if (tag) tag = tag.toLowerCase();
484 reNth.test(expr);
485 var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means n o repeat, just first _a_)
486 n = RegExp.$2, // "n"
487 oddeven = RegExp.$3, // "odd" or "even"
488 b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
489 result = [];
490
491 var siblings = getChildren(node.parentNode, tag);
492
493 if (oddeven) {
494 a = 2; // always every other
495 op = '+';
496 n = 'n';
497 b = (oddeven === 'odd') ? 1 : 0;
498 } else if ( isNaN(a) ) {
499 a = (n) ? 1 : 0; // start from the first or no repeat
500 }
501
502 if (a === 0) { // just the first
503 if (reverse) {
504 b = siblings.length - b + 1;
505 }
506
507 if (siblings[b - 1] === node) {
508 return true;
509 } else {
510 return false;
511 }
512
513 } else if (a < 0) {
514 reverse = !!reverse;
515 a = Math.abs(a);
516 }
517
518 if (!reverse) {
519 for (var i = b - 1, len = siblings.length; i < len; i += a) {
520 if ( i >= 0 && siblings[i] === node ) {
521 return true;
522 }
523 }
524 } else {
525 for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
526 if ( i < len && siblings[i] === node ) {
527 return true;
528 }
529 }
530 }
531 return false;
532 };
533
534 var getId = function(attr) {
535 for (var i = 0, len = attr.length; i < len; ++i) {
536 if (attr[i][0] == 'id' && attr[i][1] === '=') {
537 return attr[i][2];
538 }
539 }
540 };
541
542 var getIdTokenIndex = function(tokens) {
543 for (var i = 0, len = tokens.length; i < len; ++i) {
544 if (getId(tokens[i].attributes)) {
545 return i;
546 }
547 }
548 return -1;
549 };
550
551 var patterns = {
552 tag: /^((?:-?[_a-z]+[\w-]*)|\*)/i,
553 attributes: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
554 //attributes: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^'"\]]*)['"]?\]*/i,
555 pseudos: /^:([-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
556 combinator: /^\s*([>+~]|\s)\s*/
557 };
558
559 /**
560 Break selector into token units per simple selector.
561 Combinator is attached to left-hand selector.
562 */
563 var tokenize = function(selector) {
564 var token = {}, // one token per simple selector (left selector holds co mbinator)
565 tokens = [], // array of tokens
566 id, // unique id for the simple selector (if found)
567 found = false, // whether or not any matches were found this pass
568 match; // the regex match
569
570 selector = replaceShorthand(selector); // convert ID and CLASS shortcuts to attributes
571
572 /*
573 Search for selector patterns, store, and strip them from the selector st ring
574 until no patterns match (invalid selector) or we run out of chars.
575
576 Multiple attributes and pseudos are allowed, in any order.
577 for example:
578 'form:first-child[type=button]:not(button)[lang|=en]'
579 */
580 do {
581 found = false; // reset after full pass
582 for (var re in patterns) {
583 if (!YAHOO.lang.hasOwnProperty(patterns, re)) {
584 continue;
585 }
586 if (re != 'tag' && re != 'combinator') { // only one allowed
587 token[re] = token[re] || [];
588 }
589 if (match = patterns[re].exec(selector)) { // note assignment
590 found = true;
591 if (re != 'tag' && re != 'combinator') { // only one allowed
592 //token[re] = token[re] || [];
593
594 // capture ID for fast path to element
595 if (re === 'attributes' && match[1] === 'id') {
596 token.id = match[3];
597 }
598
599 token[re].push(match.slice(1));
600 } else { // single selector (tag, combinator)
601 token[re] = match[1];
602 }
603 selector = selector.replace(match[0], ''); // strip current matc h from selector
604 if (re === 'combinator' || !selector.length) { // next token or done
605 token.attributes = fixAttributes(token.attributes);
606 token.pseudos = token.pseudos || [];
607 token.tag = token.tag ? token.tag.toUpperCase() : '*';
608 tokens.push(token);
609
610 token = { // prep next token
611 previous: token
612 };
613 }
614 }
615 }
616 } while (found);
617
618 return tokens;
619 };
620
621 var fixAttributes = function(attr) {
622 var aliases = Selector.attrAliases;
623 attr = attr || [];
624 for (var i = 0, len = attr.length; i < len; ++i) {
625 if (aliases[attr[i][0]]) { // convert reserved words, etc
626 attr[i][0] = aliases[attr[i][0]];
627 }
628 if (!attr[i][1]) { // use exists operator
629 attr[i][1] = '';
630 }
631 }
632 return attr;
633 };
634
635 var replaceShorthand = function(selector) {
636 var shorthand = Selector.shorthand;
637 var attrs = selector.match(patterns.attributes); // pull attributes to avoid false pos on "." and "#"
638 if (attrs) {
639 selector = selector.replace(patterns.attributes, 'REPLACED_ATTRIBUTE');
640 }
641 for (var re in shorthand) {
642 if (!YAHOO.lang.hasOwnProperty(shorthand, re)) {
643 continue;
644 }
645 selector = selector.replace(getRegExp(re, 'gi'), shorthand[re]);
646 }
647
648 if (attrs) {
649 for (var i = 0, len = attrs.length; i < len; ++i) {
650 selector = selector.replace('REPLACED_ATTRIBUTE', attrs[i]);
651 }
652 }
653 return selector;
654 };
655
656 Selector = new Selector();
657 Selector.patterns = patterns;
658 Y.Selector = Selector;
659
660 if (YAHOO.env.ua.ie) { // rewrite class for IE (others use getAttribute('class')
661 Y.Selector.attrAliases['class'] = 'className';
662 Y.Selector.attrAliases['for'] = 'htmlFor';
663 }
664
665 })();
666 YAHOO.register("selector", YAHOO.util.Selector, {version: "2.6.0", build: "1321" });
OLDNEW
« no previous file with comments | « chrome/test/data/dromaeo/lib/yui-event.js ('k') | chrome/test/data/dromaeo/pngfix.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698