packr 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,666 @@
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 used 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(attr); }, // 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 contains value as substring
73
+ '': function(attr, val) { return attr; } // Just test for existence of attribute
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()).length === 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 HTMLElement 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 matches
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 given 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 first 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) { // IE & 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 gecko
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" or "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 no 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 combinator)
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 string
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 match 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"});