selector.js revision 744aec5933ba55f438dc42a241edb3c95df5abff
64ea5fd972c9946a3fe56cbc0bf897266d3f8747Andreas GustafssonYUI.add('selector', function(Y) {
64ea5fd972c9946a3fe56cbc0bf897266d3f8747Andreas Gustafsson
05a4a299b599195ca6ede9395b245956a8c3a790Mark Andrews/**
3ad07fa335d40330cd1859da42e67f2457443990Andreas Gustafsson * Provides helper methods for collecting and filtering DOM elements.
3ad07fa335d40330cd1859da42e67f2457443990Andreas Gustafsson * @module dom
3ad07fa335d40330cd1859da42e67f2457443990Andreas Gustafsson * @submodule selector
1094dec52a86e57df53f6167d86de94360a7a382Mark Andrews */
1094dec52a86e57df53f6167d86de94360a7a382Mark Andrews
64ea5fd972c9946a3fe56cbc0bf897266d3f8747Andreas Gustafsson/**
1094dec52a86e57df53f6167d86de94360a7a382Mark Andrews * Provides helper methods for collecting and filtering DOM elements.
fa2fb620c7c0a907b220c257007d8fb6d38bb3a4Andreas Gustafsson * @class Selector
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson * @static
fa2fb620c7c0a907b220c257007d8fb6d38bb3a4Andreas Gustafsson */
fa2fb620c7c0a907b220c257007d8fb6d38bb3a4Andreas Gustafsson
fa2fb620c7c0a907b220c257007d8fb6d38bb3a4Andreas Gustafssonvar TAG = 'tag',
62a3dbe63e833f2eaf613393399ea4667d8de28dAndreas Gustafsson PARENT_NODE = 'parentNode',
62a3dbe63e833f2eaf613393399ea4667d8de28dAndreas Gustafsson PREVIOUS_SIBLING = 'previousSibling',
62a3dbe63e833f2eaf613393399ea4667d8de28dAndreas Gustafsson LENGTH = 'length',
62a3dbe63e833f2eaf613393399ea4667d8de28dAndreas Gustafsson NODE_TYPE = 'nodeType',
62a3dbe63e833f2eaf613393399ea4667d8de28dAndreas Gustafsson TAG_NAME = 'tagName',
9bdb01e6c382e897572791b12190472955994d87Mark Andrews ATTRIBUTES = 'attributes',
9bdb01e6c382e897572791b12190472955994d87Mark Andrews PSEUDOS = 'pseudos',
9bdb01e6c382e897572791b12190472955994d87Mark Andrews COMBINATOR = 'combinator';
e69b9ffb0f8b4d1117a682908c9143ebe3efcd6bAndreas Gustafsson
e69b9ffb0f8b4d1117a682908c9143ebe3efcd6bAndreas Gustafssonvar reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
e69b9ffb0f8b4d1117a682908c9143ebe3efcd6bAndreas Gustafsson
417872b98aec720d587a9ef0197e25e78a2b7ee9Mark Andrewsvar patterns = {
417872b98aec720d587a9ef0197e25e78a2b7ee9Mark Andrews tag: /^((?:-?[_a-z]+[\w\-]*)|\*)/i,
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson attributes: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i,
a77ad145d0109081c5da6ac40a2303369db89735Andreas Gustafsson pseudos: /^:([\-\w]+)(?:\(['"]?(.+)['"]?\))*/i,
8ba4e82f5358815fd94f34fde408ffd047ba3430Andreas Gustafsson combinator: /^\s*([>+~]|\s)\s*/
8ba4e82f5358815fd94f34fde408ffd047ba3430Andreas Gustafsson};
61d5bfc06be978ea962b1c64309894ac80351771Mark Andrews
ada9b8ab20b81716c7ff1f4f3365929b2f7c8ff8Mark Andrewsvar Selector = {
ada9b8ab20b81716c7ff1f4f3365929b2f7c8ff8Mark Andrews /**
ada9b8ab20b81716c7ff1f4f3365929b2f7c8ff8Mark Andrews * Default document for use queries
3c9b2e62502460c34c2e0ceba1a5d138b3a13cc1Andreas Gustafsson * @property document
3c9b2e62502460c34c2e0ceba1a5d138b3a13cc1Andreas Gustafsson * @type object
3c9b2e62502460c34c2e0ceba1a5d138b3a13cc1Andreas Gustafsson * @default window.document
1beaa9e45738ad18cb7cae55aea95a1b16a14f94Andreas Gustafsson */
bb60abb44549428414cd55a022f2b8cc4488f7adAndreas Gustafsson document: Y.config.doc,
bb60abb44549428414cd55a022f2b8cc4488f7adAndreas Gustafsson /**
bb60abb44549428414cd55a022f2b8cc4488f7adAndreas Gustafsson * Mapping of attributes to aliases, normally to work around HTMLAttributes
bb60abb44549428414cd55a022f2b8cc4488f7adAndreas Gustafsson * that conflict with JS reserved words.
024face21cdfbfc7a862a3be061e6780533ef755Andreas Gustafsson * @property attrAliases
024face21cdfbfc7a862a3be061e6780533ef755Andreas Gustafsson * @type object
024face21cdfbfc7a862a3be061e6780533ef755Andreas Gustafsson */
1beaa9e45738ad18cb7cae55aea95a1b16a14f94Andreas Gustafsson attrAliases: {},
1beaa9e45738ad18cb7cae55aea95a1b16a14f94Andreas Gustafsson
1beaa9e45738ad18cb7cae55aea95a1b16a14f94Andreas Gustafsson /**
f953788d75c7df2db43907c68da18ed75c235dd3Andreas Gustafsson * Mapping of shorthand tokens to corresponding attribute selector
f953788d75c7df2db43907c68da18ed75c235dd3Andreas Gustafsson * @property shorthand
f953788d75c7df2db43907c68da18ed75c235dd3Andreas Gustafsson * @type object
9df7cf8ea31d8d26f9c1be55f2cdafdc68d63c53Andreas Gustafsson */
cf638fc378d74dd4afa59fe11d04da7b0cddca88Andreas Gustafsson shorthand: {
fbdde79262a4ba2bdf4bfae61167026b3220488aAndreas Gustafsson '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]',
4fa5d53e750b4e34e19b9648900d489315b185eaAndreas Gustafsson '\\.(-?[_a-z]+[-\\w]*)': '[class~=$1]'
4fa5d53e750b4e34e19b9648900d489315b185eaAndreas Gustafsson },
fbdde79262a4ba2bdf4bfae61167026b3220488aAndreas Gustafsson
fbdde79262a4ba2bdf4bfae61167026b3220488aAndreas Gustafsson /**
a7e1dcd84ada7e4e4c78f3f281e8a4d99adaf4d1Andreas Gustafsson * List of operators and corresponding boolean functions.
a7e1dcd84ada7e4e4c78f3f281e8a4d99adaf4d1Andreas Gustafsson * These functions are passed the attribute and the current node's value of the attribute.
a7e1dcd84ada7e4e4c78f3f281e8a4d99adaf4d1Andreas Gustafsson * @property operators
a7e1dcd84ada7e4e4c78f3f281e8a4d99adaf4d1Andreas Gustafsson * @type object
3fc4c1434d7ac377c720640e2e925a3af567cccbMark Andrews */
2975d0f819762614526c650b9c2077ef22f81328Andreas Gustafsson operators: {
2975d0f819762614526c650b9c2077ef22f81328Andreas Gustafsson '=': function(attr, val) { return attr === val; }, // Equality
0aba41458d345ea901cf945d47162e5f23647de9Mark Andrews '!=': function(attr, val) { return attr !== val; }, // Inequality
0bd2ea544e95601e0f0b056acfa079c99d5f6b57Andreas Gustafsson '~=': function(attr, val) { // Match one of space seperated words
0bd2ea544e95601e0f0b056acfa079c99d5f6b57Andreas Gustafsson var s = ' ';
0bd2ea544e95601e0f0b056acfa079c99d5f6b57Andreas Gustafsson return (s + attr + s).indexOf((s + val + s)) > -1;
5f7516bee5ace9542701f23fc7723a3e3196802aMark Andrews },
79432444e84d2d104119fe6a3d5cbc04b1375bd4Andreas Gustafsson '|=': function(attr, val) { return Y.DOM._getRegExp('^' + val + '[-]?').test(attr); }, // Match start with value followed by optional hyphen
79432444e84d2d104119fe6a3d5cbc04b1375bd4Andreas Gustafsson '^=': function(attr, val) { return attr.indexOf(val) === 0; }, // Match starts with value
2e24e82fc3551e3228bcacaa7c45cb61daa49195Mark Andrews '$=': function(attr, val) { return attr.lastIndexOf(val) === attr[LENGTH] - val[LENGTH]; }, // Match ends with value
3c17010ba5a6b8dd8a2bbc550813c7f051f45a08Andreas Gustafsson '*=': function(attr, val) { return attr.indexOf(val) > -1; }, // Match contains value as substring
3c17010ba5a6b8dd8a2bbc550813c7f051f45a08Andreas Gustafsson '': function(attr, val) { return attr; } // Just test for existence of attribute
3c17010ba5a6b8dd8a2bbc550813c7f051f45a08Andreas Gustafsson },
d5169236b7260d447e672db8256fdd7c70f5ee1dMark Andrews
df7596a03eea7f1c2df89bd63d3bd4b73f274565Mark Andrews /**
df7596a03eea7f1c2df89bd63d3bd4b73f274565Mark Andrews * List of pseudo-classes and corresponding boolean functions.
df7596a03eea7f1c2df89bd63d3bd4b73f274565Mark Andrews * These functions are called with the current node, and any value that was parsed with the pseudo regex.
df7596a03eea7f1c2df89bd63d3bd4b73f274565Mark Andrews * @property pseudos
f08782f0923d11227983a352c26301cf703383cfMark Andrews * @type object
f08782f0923d11227983a352c26301cf703383cfMark Andrews */
b923e278535b4e8d264998a85a6ae1eb4b3aa4c6Andreas Gustafsson pseudos: {
ed2cefaf0ea367ee408cb7f6a54a413814240fa7Andreas Gustafsson 'root': function(node) {
ed2cefaf0ea367ee408cb7f6a54a413814240fa7Andreas Gustafsson return node === node.ownerDocument.documentElement;
ed2cefaf0ea367ee408cb7f6a54a413814240fa7Andreas Gustafsson },
ed2cefaf0ea367ee408cb7f6a54a413814240fa7Andreas Gustafsson
b923e278535b4e8d264998a85a6ae1eb4b3aa4c6Andreas Gustafsson 'nth-child': function(node, val) {
b923e278535b4e8d264998a85a6ae1eb4b3aa4c6Andreas Gustafsson return Selector.getNth(node, val);
b923e278535b4e8d264998a85a6ae1eb4b3aa4c6Andreas Gustafsson },
b923e278535b4e8d264998a85a6ae1eb4b3aa4c6Andreas Gustafsson
edf97be2b54cbdc4f3f3a46776df3e912892e960Andreas Gustafsson 'nth-last-child': function(node, val) {
edf97be2b54cbdc4f3f3a46776df3e912892e960Andreas Gustafsson return Selector.getNth(node, val, null, true);
769ef0b7bdc9520dd62d2f440ea36bc020e88934Andreas Gustafsson },
9e46f410e716f73abb345be215ccb4c61782b718Andreas Gustafsson
9e46f410e716f73abb345be215ccb4c61782b718Andreas Gustafsson 'nth-of-type': function(node, val) {
9e46f410e716f73abb345be215ccb4c61782b718Andreas Gustafsson return Selector.getNth(node, val, node[TAG_NAME]);
769ef0b7bdc9520dd62d2f440ea36bc020e88934Andreas Gustafsson },
769ef0b7bdc9520dd62d2f440ea36bc020e88934Andreas Gustafsson
b09f4e054cbe67b93a5ff62d511ee25945038943Mark Andrews 'nth-last-of-type': function(node, val) {
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson return Selector.getNth(node, val, node[TAG_NAME], true);
b09f4e054cbe67b93a5ff62d511ee25945038943Mark Andrews },
3d3445447225ab63f49fc24362963ea49ce94901Andreas Gustafsson
3d3445447225ab63f49fc24362963ea49ce94901Andreas Gustafsson 'first-child': function(node) {
3d3445447225ab63f49fc24362963ea49ce94901Andreas Gustafsson return Y.DOM.firstChild(node[PARENT_NODE]) === node;
40dd9cb8cc240c33d820fe79f176ed51e4c06a1aMark Andrews },
96ea98af241ef00395f4e61de7e2dacfd9941afcMark Andrews
96ea98af241ef00395f4e61de7e2dacfd9941afcMark Andrews 'last-child': function(node) {
3dff229f5dd223568476acec4df1f513acb00b1dAndreas Gustafsson return Y.DOM.lastChild(node[PARENT_NODE]) === node;
3dff229f5dd223568476acec4df1f513acb00b1dAndreas Gustafsson },
54c4aa0f62aebeb01b6861ee068c1044433fe8feMark Andrews
792de65053d8a48d05746b35a21a9fa1792e71acAndreas Gustafsson 'first-of-type': function(node, val) {
792de65053d8a48d05746b35a21a9fa1792e71acAndreas Gustafsson return Y.DOM.firstChildByTag(node[PARENT_NODE], node[TAG_NAME]) === node;
792de65053d8a48d05746b35a21a9fa1792e71acAndreas Gustafsson },
808b909f27c30d36b27efb5aa5ef2d18f83b6d4bAndreas Gustafsson
846474d5a6aa21cebb3e94243a11faa5c20200bfAndreas Gustafsson 'last-of-type': function(node, val) {
3e934267660cb13029bcdbddf318fe1cc27b6718Andreas Gustafsson return Y.DOM.lastChildByTag(node[PARENT_NODE], node[TAG_NAME]) === node;
3e934267660cb13029bcdbddf318fe1cc27b6718Andreas Gustafsson },
846474d5a6aa21cebb3e94243a11faa5c20200bfAndreas Gustafsson
7655e78c366cc0d25e24e2a96ba58e04a96042faAndreas Gustafsson 'only-child': function(node) {
7655e78c366cc0d25e24e2a96ba58e04a96042faAndreas Gustafsson var children = Y.DOM.children(node[PARENT_NODE]);
7655e78c366cc0d25e24e2a96ba58e04a96042faAndreas Gustafsson return children[LENGTH] === 1 && children[0] === node;
6859033d425170380bcfac4809257bc6e9b60383Andreas Gustafsson },
6859033d425170380bcfac4809257bc6e9b60383Andreas Gustafsson
6859033d425170380bcfac4809257bc6e9b60383Andreas Gustafsson 'only-of-type': function(node) {
f558da602e8b74ed181d9189f20bf32dfa6d8723Brian Wellington return Y.DOM.childrenByTag(node[PARENT_NODE], node[TAG_NAME])[LENGTH] === 1;
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson },
f558da602e8b74ed181d9189f20bf32dfa6d8723Brian Wellington
ff4322d44f8404683b6fb6c86a38a2bc14f6c083Andreas Gustafsson 'empty': function(node) {
ff4322d44f8404683b6fb6c86a38a2bc14f6c083Andreas Gustafsson return node.childNodes[LENGTH] === 0;
ff4322d44f8404683b6fb6c86a38a2bc14f6c083Andreas Gustafsson },
8d146b6e1156f5b562af9a4a9aba76b09650412cAndreas Gustafsson
8d146b6e1156f5b562af9a4a9aba76b09650412cAndreas Gustafsson 'not': function(node, simple) {
8d146b6e1156f5b562af9a4a9aba76b09650412cAndreas Gustafsson return !Selector.test(node, simple);
8d146b6e1156f5b562af9a4a9aba76b09650412cAndreas Gustafsson },
808b909f27c30d36b27efb5aa5ef2d18f83b6d4bAndreas Gustafsson
808b909f27c30d36b27efb5aa5ef2d18f83b6d4bAndreas Gustafsson 'contains': function(node, str) {
808b909f27c30d36b27efb5aa5ef2d18f83b6d4bAndreas Gustafsson var text = node.innerText || node.textContent || '';
595a14576ea14884c35b3726f054f2065365620bMark Andrews return text.indexOf(str) > -1;
595a14576ea14884c35b3726f054f2065365620bMark Andrews },
595a14576ea14884c35b3726f054f2065365620bMark Andrews 'checked': function(node) {
640923da589bc5b8492ac407ef89ea1ee9a1c358Andreas Gustafsson return node.checked === true;
d9e690eb71bde3c748208733ba40a34e9d0ba29dAndreas Gustafsson }
d9e690eb71bde3c748208733ba40a34e9d0ba29dAndreas Gustafsson },
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson /**
640923da589bc5b8492ac407ef89ea1ee9a1c358Andreas Gustafsson * Test if the supplied node matches the supplied selector.
640923da589bc5b8492ac407ef89ea1ee9a1c358Andreas Gustafsson * @method test
640923da589bc5b8492ac407ef89ea1ee9a1c358Andreas Gustafsson *
640923da589bc5b8492ac407ef89ea1ee9a1c358Andreas Gustafsson * @param {HTMLElement | String} node An id or node reference to the HTMLElement being tested.
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson * @param {string} selector The CSS Selector to test the node against.
0bd1b2fbfed4aa489e9d5fcbc7f48acb96ba7248Mark Andrews * @return{boolean} Whether or not the node matches the selector.
aa30ee42c4b6da9bab4fb84d6cbbda6036a4d426Mark Andrews * @static
aa30ee42c4b6da9bab4fb84d6cbbda6036a4d426Mark Andrews
aa30ee42c4b6da9bab4fb84d6cbbda6036a4d426Mark Andrews */
1de63e34f163b7a4708a6ad1779f93ae7636b92eAndreas Gustafsson test: function(node, selector) {
01446841be2b73f9a2ead74056df2d5342414041Andreas Gustafsson if (!node) {
01446841be2b73f9a2ead74056df2d5342414041Andreas Gustafsson return false;
01446841be2b73f9a2ead74056df2d5342414041Andreas Gustafsson }
01446841be2b73f9a2ead74056df2d5342414041Andreas Gustafsson
28cf7340b9c82fc62ca1a1782cb1bd7b0de11aebAndreas Gustafsson var groups = selector ? selector.split(',') : [];
28cf7340b9c82fc62ca1a1782cb1bd7b0de11aebAndreas Gustafsson if (groups[LENGTH]) {
28cf7340b9c82fc62ca1a1782cb1bd7b0de11aebAndreas Gustafsson for (var i = 0, len = groups[LENGTH]; i < len; ++i) {
1de63e34f163b7a4708a6ad1779f93ae7636b92eAndreas Gustafsson if ( Selector._testNode(node, groups[i]) ) { // passes if ANY group matches
1de63e34f163b7a4708a6ad1779f93ae7636b92eAndreas Gustafsson return true;
feb1f6a4ac42988558ecb8dc5dc0c974ec1f0509Brian Wellington }
feb1f6a4ac42988558ecb8dc5dc0c974ec1f0509Brian Wellington }
ea34bcc6376555296a08e4c9e2f9c2cbe58378a9Andreas Gustafsson return false;
ea34bcc6376555296a08e4c9e2f9c2cbe58378a9Andreas Gustafsson }
d1a6976967d6cfd93f5a8d80878215691ac8fe74Mark Andrews return Selector._testNode(node, selector);
5e4c83cfec3f267ea8f22fbb535c61434c94d43cDanny Mayer },
06f12c290c7904f0723094b5cbd11e2a1d49e95eAndreas Gustafsson
06f12c290c7904f0723094b5cbd11e2a1d49e95eAndreas Gustafsson /**
5e4c83cfec3f267ea8f22fbb535c61434c94d43cDanny Mayer * Filters a set of nodes based on a given CSS selector.
6e1b2ebcd65c6d0cc90d7789f884aea11184eb5dAndreas Gustafsson * @method filter
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson *
e6f17474cb43a138bf7fc9ad30c6b3a2847cb7a7Mark Andrews * @param {array} nodes A set of nodes/ids to filter.
5fe21da364d4397c9a413fe689ce82dea36a7b29Mark Andrews * @param {string} selector The selector used to test each node.
5fe21da364d4397c9a413fe689ce82dea36a7b29Mark Andrews * @return{array} An array of nodes from the supplied array that match the given selector.
5fe21da364d4397c9a413fe689ce82dea36a7b29Mark Andrews * @static
a5aca6df165c601d755b8c5f5727048078bf0db5Andreas Gustafsson */
43efd9fa56b03e3e285fb58859efc9348c7f4a9fMark Andrews filter: function(nodes, selector) {
43efd9fa56b03e3e285fb58859efc9348c7f4a9fMark Andrews nodes = nodes || [];
43efd9fa56b03e3e285fb58859efc9348c7f4a9fMark Andrews
5c831a1a1b14470037de6d8bc0501aea5dc6cacdAndreas Gustafsson var result = Selector._filter(nodes, Selector._tokenize(selector)[0]);
36e37042c6c9252cdf6eb99bd71ccb6e6c43ba6dBrian Wellington return result;
98e231525fda817d393ef0c529b50bfc08cebe47Mark Andrews },
98e231525fda817d393ef0c529b50bfc08cebe47Mark Andrews
98e231525fda817d393ef0c529b50bfc08cebe47Mark Andrews /**
d4196128b31d511c8513edacc70dea7e8d0c053aMark Andrews * Retrieves a set of nodes based on a given CSS selector.
d4196128b31d511c8513edacc70dea7e8d0c053aMark Andrews * @method query
d4196128b31d511c8513edacc70dea7e8d0c053aMark Andrews *
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson * @param {string} selector The CSS Selector to test the node against.
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson * @param {HTMLElement | String} root optional An id or HTMLElement to start the query from. Defaults to Selector.document.
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson * @param {Boolean} firstOnly optional Whether or not to return only the first match.
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson * @return {Array} An array of nodes that match the given selector.
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson * @static
4a20a92f4f96cf2b2fd77898c6afec6c45e481b3Andreas Gustafsson */
56d69016f4fae2eda4d39c92fe13595251aaadd3Mark Andrews query: function(selector, root, firstOnly) {
e60b3717f0e6f28d6fb2c5124ffb3bd31cc3a746Mark Andrews var result = Selector._query(selector, root, firstOnly);
e60b3717f0e6f28d6fb2c5124ffb3bd31cc3a746Mark Andrews return result;
0262406cea5802a717539247cbaa596ac808efa9Mark Andrews },
3d8ab44d14f3de797b8454fc2edb7421a6bfc874Andreas Gustafsson
3d8ab44d14f3de797b8454fc2edb7421a6bfc874Andreas Gustafsson _query: function(selector, root, firstOnly, deDupe) {
3d8ab44d14f3de797b8454fc2edb7421a6bfc874Andreas Gustafsson var result = (firstOnly) ? null : [];
3426f7118c92cab8714a7fddc9e721ff09554447Andreas Gustafsson if (!selector) {
db235e65884c04058cc6e99ca485170d67cf9538Andreas Gustafsson return result;
db235e65884c04058cc6e99ca485170d67cf9538Andreas Gustafsson }
3426f7118c92cab8714a7fddc9e721ff09554447Andreas Gustafsson
3426f7118c92cab8714a7fddc9e721ff09554447Andreas Gustafsson root = root || Selector.document;
64a5004a66accd190bfd5ddf115667726537be50Andreas Gustafsson var groups = selector.split(','); // TODO: handle comma in attribute/pseudo
64a5004a66accd190bfd5ddf115667726537be50Andreas Gustafsson
64a5004a66accd190bfd5ddf115667726537be50Andreas Gustafsson if (groups[LENGTH] > 1) {
64a5004a66accd190bfd5ddf115667726537be50Andreas Gustafsson var found;
64a5004a66accd190bfd5ddf115667726537be50Andreas Gustafsson for (var i = 0, len = groups[LENGTH]; i < len; ++i) {
b1ae7a591a4b99a26036e919b87247b65abfcd77Mark Andrews found = arguments.callee(groups[i], root, firstOnly, true);
b1ae7a591a4b99a26036e919b87247b65abfcd77Mark Andrews result = firstOnly ? found : result.concat(found);
b1ae7a591a4b99a26036e919b87247b65abfcd77Mark Andrews }
b1ae7a591a4b99a26036e919b87247b65abfcd77Mark Andrews Selector._clearFoundCache();
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson return result;
cab0ee644db604d56b45ec39429d505d635da347Andreas Gustafsson }
cab0ee644db604d56b45ec39429d505d635da347Andreas Gustafsson
cab0ee644db604d56b45ec39429d505d635da347Andreas Gustafsson var tokens = Selector._tokenize(selector);
cab0ee644db604d56b45ec39429d505d635da347Andreas Gustafsson var idToken = tokens[Selector._getIdTokenIndex(tokens)],
7780a3e5a4659bb8fc44f8915d20a8d3ffa33e00Andreas Gustafsson nodes = [],
7780a3e5a4659bb8fc44f8915d20a8d3ffa33e00Andreas Gustafsson node,
7780a3e5a4659bb8fc44f8915d20a8d3ffa33e00Andreas Gustafsson id,
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson token = tokens.pop() || {};
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson if (idToken) {
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson id = Selector._getId(idToken[ATTRIBUTES]);
6dbc6fae496db1f584c055e63bcd7afd332fe8f6Andreas Gustafsson }
a24d253a3f4e6f4036800744b348fba858d4959eMark Andrews
a24d253a3f4e6f4036800744b348fba858d4959eMark Andrews // use id shortcut when possible
847169dab2d0496df1d66842b2cce67c66bf9680Andreas Gustafsson if (id) {
3f543c371fff724d1fb05eb564f732476e946b5bBrian Wellington node = Selector.document.getElementById(id);
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson
3f543c371fff724d1fb05eb564f732476e946b5bBrian Wellington if (node && (root[NODE_TYPE] === 9 || Y.DOM.contains(root, node))) {
847169dab2d0496df1d66842b2cce67c66bf9680Andreas Gustafsson if ( Selector._testNode(node, null, idToken) ) {
847169dab2d0496df1d66842b2cce67c66bf9680Andreas Gustafsson if (idToken === token) {
847169dab2d0496df1d66842b2cce67c66bf9680Andreas Gustafsson nodes = [node]; // simple selector
9aba20edee4e704433a464ae43b070b0775de506Mark Andrews } else {
9aba20edee4e704433a464ae43b070b0775de506Mark Andrews root = node; // start from here
ed03e26c44347ec20aff6608de6082e3594d95fbMark Andrews }
ed03e26c44347ec20aff6608de6082e3594d95fbMark Andrews }
9aba20edee4e704433a464ae43b070b0775de506Mark Andrews } else {
e8d86192fc424f49e43df9cee439ca5c793e6000Mark Andrews return result;
e8d86192fc424f49e43df9cee439ca5c793e6000Mark Andrews }
e8d86192fc424f49e43df9cee439ca5c793e6000Mark Andrews }
bae5d9fcb4616005fbc861e327b0a48b7bd4d89aMark Andrews
bae5d9fcb4616005fbc861e327b0a48b7bd4d89aMark Andrews if (root && !nodes[LENGTH]) {
e8d86192fc424f49e43df9cee439ca5c793e6000Mark Andrews nodes = root.getElementsByTagName(token[TAG]);
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson }
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson if (nodes[LENGTH]) {
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson result = Selector._filter(nodes, token, firstOnly, deDupe);
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson }
5af0708e7fd78976a33de70f9380785f4086a1f0Andreas Gustafsson return result;
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson },
98a5dc52bf668b093cda7901c057f7b54e18a2fcAndreas Gustafsson
452b30ddb32dd9370b2e5ee10427dd3758ef98b4Mark Andrews _filter: function(nodes, token, firstOnly, deDupe) {
452b30ddb32dd9370b2e5ee10427dd3758ef98b4Mark Andrews var result = firstOnly ? null : [];
452b30ddb32dd9370b2e5ee10427dd3758ef98b4Mark Andrews
452b30ddb32dd9370b2e5ee10427dd3758ef98b4Mark Andrews result = Y.DOM.filterElementsBy(nodes, function(node) {
6668eca26bf3123750afda48b69991bd29d83807Mark Andrews if (! Selector._testNode(node, '', token, deDupe)) {
1299e93989afbe1fee0739811b05fd1641ea14aeAndreas Gustafsson return false;
6668eca26bf3123750afda48b69991bd29d83807Mark Andrews }
06a960c681566a163af5b9a655cf36023075ddcbMark Andrews
06a960c681566a163af5b9a655cf36023075ddcbMark Andrews if (deDupe) {
cb8fd52bbeaf40c9166a0144541c4ff2bafc2dd6Andreas Gustafsson if (node._found) {
1eaad22e111709254c70953a4dc768b6d4d31646Mark Andrews return false;
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson }
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson node._found = true;
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson Selector._foundCache[Selector._foundCache[LENGTH]] = node;
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson }
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson return true;
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson }, firstOnly);
cad3210bb95057a37aaed20bc8a1542e0534422cAndreas Gustafsson
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer return result;
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer },
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer _testNode: function(node, selector, token, deDupe) {
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer token = token || Selector._tokenize(selector).pop() || {};
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer var ops = Selector.operators,
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer pseudos = Selector.pseudos,
afeded2289de8d193b072da2b44a2d580cc235c1Danny Mayer prev = token.previous,
f462b9aed23b77bda867301f80ead6990df6f4f8Andreas Gustafsson i, len;
89555ff443c8127a533f6c742316c9b1a713cfd5Mark Andrews
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson if (!node[TAG_NAME] ||
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson (token[TAG] !== '*' && node[TAG_NAME].toUpperCase() !== token[TAG]) ||
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson (deDupe && node._found) ) {
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson return false;
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson }
aa9a67adeb48069f5c2e5d8936a8ed5aac7d6ad7Andreas Gustafsson
73ac1894ea64bc50aff7406872d0e9c5df6d9cf6Mark Andrews if (token[ATTRIBUTES][LENGTH]) {
539cad8f49b38540b7c20c64d1ef456cb2fa7914Andreas Gustafsson var attribute;
330b421487d7c3a5e699472fe889aa633772057fMark Andrews for (i = 0, len = token[ATTRIBUTES][LENGTH]; i < len; ++i) {
e22dca2a9ad30d493a869586abed86f7268204f9Mark Andrews attribute = node.getAttribute(token[ATTRIBUTES][i][0], 2);
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson if (attribute === undefined) {
e22dca2a9ad30d493a869586abed86f7268204f9Mark Andrews return false;
2c0b26955ee32fcee1757ec1be5a8caf8fe695a6Mark Andrews }
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson if ( ops[token[ATTRIBUTES][i][1]] &&
2c0b26955ee32fcee1757ec1be5a8caf8fe695a6Mark Andrews !ops[token[ATTRIBUTES][i][1]](attribute, token[ATTRIBUTES][i][2])) {
2449f41e75d3b3f1c0ec3f05b1603fd8f80d8ae0Mark Andrews return false;
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson }
2449f41e75d3b3f1c0ec3f05b1603fd8f80d8ae0Mark Andrews }
ea72586fc5c360539117119ee35e4c3a04b912bcAndreas Gustafsson }
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson
6f7660093e70d3a7c80738b681ac0f5c1b661c00Mark Andrews if (token[PSEUDOS][LENGTH]) {
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson for (i = 0, len = token[PSEUDOS][LENGTH]; i < len; ++i) {
1fdbadc594a49b423052ea342dac74ff1a36089dMark Andrews if (pseudos[token[PSEUDOS][i][0]] &&
a1898260ad19d02e88ab76c1855d33c67add9defMark Andrews !pseudos[token[PSEUDOS][i][0]](node, token[PSEUDOS][i][1])) {
a1898260ad19d02e88ab76c1855d33c67add9defMark Andrews return false;
a1898260ad19d02e88ab76c1855d33c67add9defMark Andrews }
305b0eda33b16493355db1f1c86313a6f5fbfc3bDanny Mayer }
305b0eda33b16493355db1f1c86313a6f5fbfc3bDanny Mayer }
305b0eda33b16493355db1f1c86313a6f5fbfc3bDanny Mayer return (prev && prev[COMBINATOR] !== ',') ?
305b0eda33b16493355db1f1c86313a6f5fbfc3bDanny Mayer Selector.combinators[prev[COMBINATOR]](node, token) :
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson true;
d16b4e8ba885a45933dc6a46f340b76811d60c74Andreas Gustafsson },
d16b4e8ba885a45933dc6a46f340b76811d60c74Andreas Gustafsson
de9833be77ef92c17b35c02d138a0ad8df34dd91Mark Andrews
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson _foundCache: [],
de9833be77ef92c17b35c02d138a0ad8df34dd91Mark Andrews _regexCache: {},
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson _clearFoundCache: function() {
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson for (var i = 0, len = Selector._foundCache[LENGTH]; i < len; ++i) {
4e400cb7a2edd25af98ebc25fcbb5b36ca08f9a0Mark Andrews try { // IE no like delete
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson delete Selector._foundCache[i]._found;
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson } catch(e) {
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson Selector._foundCache[i].removeAttribute('_found');
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson }
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson }
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson Selector._foundCache = [];
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson },
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson
c0b6c1a5ab50722793cb99b0d8a1e9e910c146a5Andreas Gustafsson combinators: {
ec5a06ccf7b15f07d20fd872c3dc1ab8f82f2ceaMark Andrews ' ': function(node, token) {
907ec2c618d08d8322b04729779b24bd778d49e7Mark Andrews while ((node = node[PARENT_NODE])) {
907ec2c618d08d8322b04729779b24bd778d49e7Mark Andrews if (Selector._testNode(node, '', token.previous)) {
907ec2c618d08d8322b04729779b24bd778d49e7Mark Andrews return true;
23a020bc1312fc35e7c4ea36df846c550cb13634Andreas Gustafsson }
0a532842050020a1b0577c65f91f38bd022daa78Andreas Gustafsson }
0a532842050020a1b0577c65f91f38bd022daa78Andreas Gustafsson return false;
0a532842050020a1b0577c65f91f38bd022daa78Andreas Gustafsson },
0a532842050020a1b0577c65f91f38bd022daa78Andreas Gustafsson
23a020bc1312fc35e7c4ea36df846c550cb13634Andreas Gustafsson '>': function(node, token) {
23a020bc1312fc35e7c4ea36df846c550cb13634Andreas Gustafsson return Selector._testNode(node[PARENT_NODE], null, token.previous);
23a020bc1312fc35e7c4ea36df846c550cb13634Andreas Gustafsson },
44c141f9471a6bb1fac0cba7880ba768ede2f0c8Brian Wellington '+': function(node, token) {
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson var sib = node[PREVIOUS_SIBLING];
ab3eaa20e9a7e56208408563c79b4f8ac01d5e84Andreas Gustafsson while (sib && sib[NODE_TYPE] !== 1) {
e1a153c3f095e217eea29958950fea36e54862ceAndreas Gustafsson sib = sib[PREVIOUS_SIBLING];
e1a153c3f095e217eea29958950fea36e54862ceAndreas Gustafsson }
7250c1a2616761395bdb9ae7cd1ba43f20d3edc4Andreas Gustafsson
7250c1a2616761395bdb9ae7cd1ba43f20d3edc4Andreas Gustafsson if (sib && Selector._testNode(sib, null, token.previous)) {
7250c1a2616761395bdb9ae7cd1ba43f20d3edc4Andreas Gustafsson return true;
ab3eaa20e9a7e56208408563c79b4f8ac01d5e84Andreas Gustafsson }
c38b92000c0f1a95daaad5468777e165b8047de9Mark Andrews return false;
4d77dbcfa052c065a87d2d35b116f17b74bae573Andreas Gustafsson },
c38b92000c0f1a95daaad5468777e165b8047de9Mark Andrews
c38b92000c0f1a95daaad5468777e165b8047de9Mark Andrews '~': function(node, token) {
c38b92000c0f1a95daaad5468777e165b8047de9Mark Andrews var sib = node[PREVIOUS_SIBLING];
a5b9c2b208b51b039c8f4006cddf3d37dd781561Brian Wellington while (sib) {
22f0b13f28a7df3b348b18848d0ccd745ea88c3cAndreas Gustafsson if (sib[NODE_TYPE] === 1 && Selector._testNode(sib, null, token.previous)) {
22f0b13f28a7df3b348b18848d0ccd745ea88c3cAndreas Gustafsson return true;
22f0b13f28a7df3b348b18848d0ccd745ea88c3cAndreas Gustafsson }
22f0b13f28a7df3b348b18848d0ccd745ea88c3cAndreas Gustafsson sib = sib[PREVIOUS_SIBLING];
ee3ab6063dd13b5947d3fbe88b9ce8f38d65df9dBrian Wellington }
9261ca5fc8a564968f34e108eb862157471ca50eAndreas Gustafsson
ee3ab6063dd13b5947d3fbe88b9ce8f38d65df9dBrian Wellington return false;
d81622b537be1971530cfb459acdbbe7d82d883bBrian Wellington }
d81622b537be1971530cfb459acdbbe7d82d883bBrian Wellington },
a5b9c2b208b51b039c8f4006cddf3d37dd781561Brian Wellington
9261ca5fc8a564968f34e108eb862157471ca50eAndreas Gustafsson
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson /*
a5b9c2b208b51b039c8f4006cddf3d37dd781561Brian Wellington an+b = get every _a_th node starting at the _b_th
2da0b7dfbd02fab454b8ba60f1fdb7e2a5cbd2dbMark Andrews 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
2da0b7dfbd02fab454b8ba60f1fdb7e2a5cbd2dbMark Andrews 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
2da0b7dfbd02fab454b8ba60f1fdb7e2a5cbd2dbMark Andrews an+0 = get every _a_th element, "0" may be omitted
1cb6e8cbe41afade950837319e04da4ccf8649e0Brian Wellington */
9261ca5fc8a564968f34e108eb862157471ca50eAndreas Gustafsson getNth: function(node, expr, tag, reverse) {
1cb6e8cbe41afade950837319e04da4ccf8649e0Brian Wellington reNth.test(expr);
2033e305852d4b76772885ea73ebfb6776c1f820Mark Andrews
6443201354efa09f16ada26dab99e9b7f8271521Andreas Gustafsson var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
6443201354efa09f16ada26dab99e9b7f8271521Andreas Gustafsson n = RegExp.$2, // "n"
6443201354efa09f16ada26dab99e9b7f8271521Andreas Gustafsson oddeven = RegExp.$3, // "odd" or "even"
e980502db40155234b4e8d320b748b34dbaba3a2Brian Wellington b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
5419c0c2d0b77682021084c69f2a5c5e2f9a5525Andreas Gustafsson op, i, len, siblings;
e980502db40155234b4e8d320b748b34dbaba3a2Brian Wellington
e980502db40155234b4e8d320b748b34dbaba3a2Brian Wellington if (tag) {
ecd1addb86319bacc6c0bff2c68373619eebbffcMark Andrews siblings = Y.DOM.childrenByTag(node[PARENT_NODE], tag);
ecd1addb86319bacc6c0bff2c68373619eebbffcMark Andrews } else {
0176adc7c58bb8bd60ec71eeae94dbfbbc4018a8Mark Andrews siblings = Y.DOM.children(node[PARENT_NODE]);
0176adc7c58bb8bd60ec71eeae94dbfbbc4018a8Mark Andrews }
ea20115e347264b9bc1c686d6dfc1b5af3a5516bAndreas Gustafsson
ea20115e347264b9bc1c686d6dfc1b5af3a5516bAndreas Gustafsson if (oddeven) {
ea20115e347264b9bc1c686d6dfc1b5af3a5516bAndreas Gustafsson a = 2; // always every other
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews op = '+';
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews n = 'n';
aa0dc8d920a1f79626c3564408db9c5c9a5319a7Andreas Gustafsson b = (oddeven === 'odd') ? 1 : 0;
aa0dc8d920a1f79626c3564408db9c5c9a5319a7Andreas Gustafsson } else if ( isNaN(a) ) {
aa0dc8d920a1f79626c3564408db9c5c9a5319a7Andreas Gustafsson a = (n) ? 1 : 0; // start from the first or no repeat
aa0dc8d920a1f79626c3564408db9c5c9a5319a7Andreas Gustafsson }
47d48791fc352fcdf9019200070221be41a8d77cMark Andrews
aec9f4d0723b0cffcfa9152533fb8f616ec7313bAndreas Gustafsson if (a === 0) { // just the first
35db8a8eda6a889675138eb125d366c8851f68a5Andreas Gustafsson if (reverse) {
0d5e7cd0afaee07302f8364aa454f09b4c63ea79Andreas Gustafsson b = siblings[LENGTH] - b + 1;
0d5e7cd0afaee07302f8364aa454f09b4c63ea79Andreas Gustafsson }
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson if (siblings[b - 1] === node) {
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson return true;
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson } else {
22815444822da17fab82d4ab115da6e055ea1754Brian Wellington return false;
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson }
22815444822da17fab82d4ab115da6e055ea1754Brian Wellington
22815444822da17fab82d4ab115da6e055ea1754Brian Wellington } else if (a < 0) {
35db8a8eda6a889675138eb125d366c8851f68a5Andreas Gustafsson reverse = !!reverse;
35db8a8eda6a889675138eb125d366c8851f68a5Andreas Gustafsson a = Math.abs(a);
35db8a8eda6a889675138eb125d366c8851f68a5Andreas Gustafsson }
c6de6524d777c90ae8011af8b10f5cac044081e5Mark Andrews
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington if (!reverse) {
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington for (i = b - 1, len = siblings[LENGTH]; i < len; i += a) {
5e88852b94830bf71e37dc700d568cb35e2e6f7eAndreas Gustafsson if ( i >= 0 && siblings[i] === node ) {
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington return true;
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington }
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington }
bd6504aa9aa16a912412fbe010046aaf4bf23621Brian Wellington } else {
e9596e1fb3dfa560216776acdbfac3cf5ef97157Mark Andrews for (i = siblings[LENGTH] - b, len = siblings[LENGTH]; i >= 0; i -= a) {
e9596e1fb3dfa560216776acdbfac3cf5ef97157Mark Andrews if ( i < len && siblings[i] === node ) {
1e289d3cca5cdd01dda650fa6e4c1de1aa8b4196Andreas Gustafsson return true;
c54210716ee55b55e22d8dad56fd696a641fc98dBob Halley }
c54210716ee55b55e22d8dad56fd696a641fc98dBob Halley }
c54210716ee55b55e22d8dad56fd696a641fc98dBob Halley }
c54210716ee55b55e22d8dad56fd696a641fc98dBob Halley return false;
3fcf6b956f47405750724bd84e1b2290b61c9186Brian Wellington },
82c65f4f62819340ef8198932d3eab8a308a4874Andreas Gustafsson
3fcf6b956f47405750724bd84e1b2290b61c9186Brian Wellington _getId: function(attr) {
1e289d3cca5cdd01dda650fa6e4c1de1aa8b4196Andreas Gustafsson for (var i = 0, len = attr[LENGTH]; i < len; ++i) {
1e289d3cca5cdd01dda650fa6e4c1de1aa8b4196Andreas Gustafsson if (attr[i][0] == 'id' && attr[i][1] === '=') {
0a2d5c990559ce2b9f95df752db6e93024d9a250Brian Wellington return attr[i][2];
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson }
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson }
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson },
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson _getIdTokenIndex: function(tokens) {
96ed62425310854fd6f6f06bfb7651b3e4c17ee7Andreas Gustafsson for (var i = 0, len = tokens[LENGTH]; i < len; ++i) {
5733d25b06b46067b3751d10436d82aef09cd705Brian Wellington if (Selector._getId(tokens[i][ATTRIBUTES])) {
82c65f4f62819340ef8198932d3eab8a308a4874Andreas Gustafsson return i;
5733d25b06b46067b3751d10436d82aef09cd705Brian Wellington }
5733d25b06b46067b3751d10436d82aef09cd705Brian Wellington }
82c65f4f62819340ef8198932d3eab8a308a4874Andreas Gustafsson return -1;
5733d25b06b46067b3751d10436d82aef09cd705Brian Wellington },
debff476ad3512687a354499c25d2793e2009acdBrian Wellington
debff476ad3512687a354499c25d2793e2009acdBrian Wellington /**
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson Break selector into token units per simple selector.
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson Combinator is attached to left-hand selector.
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson */
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson _tokenize: function(selector) {
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson var token = {}, // one token per simple selector (left selector holds combinator)
eb6e3b04169a766d2b968bcc978191605c2ef24cAndreas Gustafsson tokens = [], // array of tokens
7d8c3693d0426b56750b14d80c47df5e42fc75e4Andreas Gustafsson found = false, // whether or not any matches were found this pass
fed846067d265db1037483d81d01f3651c8a3f28Brian Wellington match; // the regex match
82c65f4f62819340ef8198932d3eab8a308a4874Andreas Gustafsson
fed846067d265db1037483d81d01f3651c8a3f28Brian Wellington selector = Selector._replaceShorthand(selector); // convert ID and CLASS shortcuts to attributes
a26ad011f382d12058478704cb5e90e6f4366d01Andreas Gustafsson
a26ad011f382d12058478704cb5e90e6f4366d01Andreas Gustafsson /*
a26ad011f382d12058478704cb5e90e6f4366d01Andreas Gustafsson Search for selector patterns, store, and strip them from the selector string
a26ad011f382d12058478704cb5e90e6f4366d01Andreas Gustafsson until no patterns match (invalid selector) or we run out of chars.
57188b5ff2397c0517e55f622879e69ee547918dAndreas Gustafsson
7d8c3693d0426b56750b14d80c47df5e42fc75e4Andreas Gustafsson Multiple attributes and pseudos are allowed, in any order.
7d8c3693d0426b56750b14d80c47df5e42fc75e4Andreas Gustafsson for example:
7d8c3693d0426b56750b14d80c47df5e42fc75e4Andreas Gustafsson 'form:first-child[type=button]:not(button)[lang|=en]'
9a72459b6040b30d043c5fd9e283441b847e569aAndreas Gustafsson */
9a72459b6040b30d043c5fd9e283441b847e569aAndreas Gustafsson do {
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson found = false; // reset after full pass
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson for (var re in patterns) {
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson if (patterns.hasOwnProperty(re)) {
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson if (re != TAG && re != COMBINATOR) { // only one allowed
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson token[re] = token[re] || [];
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson }
07c336a9a85791dff886b1e28514589a25d9b720Andreas Gustafsson if ((match = patterns[re].exec(selector))) { // note assignment
712fa28946312882a60b0c6a913914d3e8c69867Mark Andrews found = true;
712fa28946312882a60b0c6a913914d3e8c69867Mark Andrews if (re != TAG && re != COMBINATOR) { // only one allowed
f2a16ec2e8970615d39f8fe339b215ad0a893b85Mark Andrews //token[re] = token[re] || [];
8bcf7a157900c3a05168aaec708b8c664b96d797Andreas Gustafsson
63fd201fde27ce408cde1c73a054e401fcfb9e3bDavid Lawrence // capture ID for fast path to element
f8644da8d948dbc973f6dd4c94a79774e16ec07bDavid Lawrence if (re === ATTRIBUTES && match[1] === 'id') {
f8644da8d948dbc973f6dd4c94a79774e16ec07bDavid Lawrence token.id = match[3];
9bfa90768ab83ea5a8571c98d3774377da4bdcbeDavid Lawrence }
9bfa90768ab83ea5a8571c98d3774377da4bdcbeDavid Lawrence
9bfa90768ab83ea5a8571c98d3774377da4bdcbeDavid Lawrence token[re].push(match.slice(1));
9bfa90768ab83ea5a8571c98d3774377da4bdcbeDavid Lawrence } else { // single selector (tag, combinator)
9bfa90768ab83ea5a8571c98d3774377da4bdcbeDavid Lawrence token[re] = match[1];
2d67c2474475acf52c8251dc48bfb7565ee5f2ffDavid Lawrence }
2d67c2474475acf52c8251dc48bfb7565ee5f2ffDavid Lawrence selector = selector.replace(match[0], ''); // strip current match from selector
2d67c2474475acf52c8251dc48bfb7565ee5f2ffDavid Lawrence if (re === COMBINATOR || !selector[LENGTH]) { // next token or done
2d67c2474475acf52c8251dc48bfb7565ee5f2ffDavid Lawrence token[ATTRIBUTES] = Selector._fixAttributes(token[ATTRIBUTES]);
6a7a69e9f764812872ec2db775be2ac8bb073102Andreas Gustafsson token[PSEUDOS] = token[PSEUDOS] || [];
6a7a69e9f764812872ec2db775be2ac8bb073102Andreas Gustafsson token[TAG] = token[TAG] ? token[TAG].toUpperCase() : '*';
6a7a69e9f764812872ec2db775be2ac8bb073102Andreas Gustafsson tokens.push(token);
0a9a3d8c6daf9ffcfb62dbe366e26f521cbb9736Brian Wellington
8bcf7a157900c3a05168aaec708b8c664b96d797Andreas Gustafsson token = { // prep next token
0a9a3d8c6daf9ffcfb62dbe366e26f521cbb9736Brian Wellington previous: token
f5ebf2f0c9e9d2068ace1dbcc2ef2ed3ebdbfde5Andreas Gustafsson };
8bcf7a157900c3a05168aaec708b8c664b96d797Andreas Gustafsson }
34d5676aac483e00e16056a6834a27b52bed42f0Brian Wellington }
1d9ab721315555ac75e7d4f57585323909283688Andreas Gustafsson }
1d9ab721315555ac75e7d4f57585323909283688Andreas Gustafsson }
1d9ab721315555ac75e7d4f57585323909283688Andreas Gustafsson } while (found);
63fd201fde27ce408cde1c73a054e401fcfb9e3bDavid Lawrence
ef8d97818f0d30a4e09db97af695f504b311372cMark Andrews return tokens;
112d9875bf33e2382f9a986d3e58fce08f1935fcOlafur Gudmundsson },
63fd201fde27ce408cde1c73a054e401fcfb9e3bDavid Lawrence
63fd201fde27ce408cde1c73a054e401fcfb9e3bDavid Lawrence _fixAttributes: function(attr) {
63fd201fde27ce408cde1c73a054e401fcfb9e3bDavid Lawrence var aliases = Selector.attrAliases;
6af5c66df334c4e275e07b03c9b35e40dbaa4f31Andreas Gustafsson attr = attr || [];
519f8475ff8218e3981ae2b249eb1403da7c52f6Andreas Gustafsson for (var i = 0, len = attr[LENGTH]; i < len; ++i) {
519f8475ff8218e3981ae2b249eb1403da7c52f6Andreas Gustafsson if (aliases[attr[i][0]]) { // convert reserved words, etc
edc1c60621b44fbc8131ad1542f657dd129f9a30Andreas Gustafsson attr[i][0] = aliases[attr[i][0]];
edc1c60621b44fbc8131ad1542f657dd129f9a30Andreas Gustafsson }
edc1c60621b44fbc8131ad1542f657dd129f9a30Andreas Gustafsson if (!attr[i][1]) { // use exists operator
edc1c60621b44fbc8131ad1542f657dd129f9a30Andreas Gustafsson attr[i][1] = '';
41626c0997c89dcdecf67c931f0031aadd507977Andreas Gustafsson }
41626c0997c89dcdecf67c931f0031aadd507977Andreas Gustafsson }
41626c0997c89dcdecf67c931f0031aadd507977Andreas Gustafsson return attr;
4f4e44c98f315bfadc6dded1b86b465222a83967David Lawrence },
464c2e4bb960d15bd60d53c3ef3ae7414b129037David Lawrence
464c2e4bb960d15bd60d53c3ef3ae7414b129037David Lawrence _replaceShorthand: function(selector) {
464c2e4bb960d15bd60d53c3ef3ae7414b129037David Lawrence var shorthand = Selector.shorthand;
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence var attrs = selector.match(patterns[ATTRIBUTES]); // pull attributes to avoid false pos on "." and "#"
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence if (attrs) {
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence selector = selector.replace(patterns[ATTRIBUTES], 'REPLACED_ATTRIBUTE');
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence }
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence for (var re in shorthand) {
6112718b0dbb01ffbfd3fabc61e30c7e4485b0a7David Lawrence if (shorthand.hasOwnProperty(re)) {
04260c5c48d234734863f0222e207b6564cd41a8David Lawrence selector = selector.replace(Y.DOM._getRegExp(re, 'gi'), shorthand[re]);
04260c5c48d234734863f0222e207b6564cd41a8David Lawrence }
04260c5c48d234734863f0222e207b6564cd41a8David Lawrence }
f479c9ff5576b3d138c7e52cfc2319b185b7ebcfDavid Lawrence
f479c9ff5576b3d138c7e52cfc2319b185b7ebcfDavid Lawrence if (attrs) {
f479c9ff5576b3d138c7e52cfc2319b185b7ebcfDavid Lawrence for (var i = 0, len = attrs[LENGTH]; i < len; ++i) {
6c35e4dd17e6562a6b4d106cbf1d824b9f529356David Lawrence selector = selector.replace('REPLACED_ATTRIBUTE', attrs[i]);
504f7802d4c9b43db4820f496c4d00e078effa18David Lawrence }
504f7802d4c9b43db4820f496c4d00e078effa18David Lawrence }
504f7802d4c9b43db4820f496c4d00e078effa18David Lawrence return selector;
504f7802d4c9b43db4820f496c4d00e078effa18David Lawrence }
6af5c66df334c4e275e07b03c9b35e40dbaa4f31Andreas Gustafsson
6af5c66df334c4e275e07b03c9b35e40dbaa4f31Andreas Gustafsson};
3b6bcedffe1d326fd9f6aa3bfb1537af0975fab8Brian Wellington
c2c275f5f4ead0943c76b6463cf7a93095559c64Andreas Gustafssonif (Y.UA.ie && Y.UA.ie < 8) { // rewrite class for IE (others use getAttribute('class')
3b6bcedffe1d326fd9f6aa3bfb1537af0975fab8Brian Wellington Selector.attrAliases['class'] = 'className';
3b6bcedffe1d326fd9f6aa3bfb1537af0975fab8Brian Wellington Selector.attrAliases['for'] = 'htmlFor';
841179549b6433e782c164a562eb3422f603533dAndreas Gustafsson}
f808bd34fbd3dd9508e8183e8025635bc330c34aAndreas Gustafsson
f808bd34fbd3dd9508e8183e8025635bc330c34aAndreas GustafssonY.Selector = Selector;
7fe2ead2b3e23f68c1d3c79da51ef5af4f678f7dAndreas GustafssonY.Selector.patterns = patterns;
c2c275f5f4ead0943c76b6463cf7a93095559c64Andreas Gustafsson
f808bd34fbd3dd9508e8183e8025635bc330c34aAndreas Gustafsson
841179549b6433e782c164a562eb3422f603533dAndreas Gustafsson
841179549b6433e782c164a562eb3422f603533dAndreas Gustafsson}, '@VERSION@' ,{requires:['dom-base'], skinnable:false});
841179549b6433e782c164a562eb3422f603533dAndreas Gustafsson