packr 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/{README.txt → README.rdoc} +40 -44
- data/bin/packr +44 -38
- data/lib/packr.rb +0 -6
- data/test/assets/packed/controls.js +1 -0
- data/test/assets/packed/domready.js +1 -0
- data/test/assets/packed/dragdrop.js +1 -0
- data/test/assets/packed/effects.js +1 -0
- data/test/assets/packed/prototype.js +1 -0
- data/test/assets/packed/prototype_shrunk.js +1 -0
- data/test/assets/packed/selector.js +1 -0
- data/test/assets/src/controls.js +833 -0
- data/test/assets/src/domready.js +36 -0
- data/test/assets/src/dragdrop.js +942 -0
- data/test/assets/src/effects.js +1088 -0
- data/test/assets/src/prototype.js +2515 -0
- data/test/assets/src/selector.js +666 -0
- data/test/assets/test/controls.js +1 -0
- data/test/assets/test/domready.js +1 -0
- data/test/assets/test/dragdrop.js +1 -0
- data/test/assets/test/effects.js +1 -0
- data/test/assets/test/prototype.js +1 -0
- data/test/assets/test/prototype_shrunk.js +1 -0
- data/test/assets/test/selector.js +1 -0
- data/test/test_packr.rb +4 -1
- metadata +56 -38
- data/Manifest.txt +0 -19
- data/Rakefile +0 -12
@@ -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"});
|