8d1240fc6300f6769711557511f6882f0a3d3139Matt Sweeney/**
8d1240fc6300f6769711557511f6882f0a3d3139Matt Sweeney * The selector css3 module provides support for css3 selectors.
4f15171c562757e8d3e2b8882e04d6b5a2291732Matt Sweeney * @module dom
4f15171c562757e8d3e2b8882e04d6b5a2291732Matt Sweeney * @submodule selector-css3
4f15171c562757e8d3e2b8882e04d6b5a2291732Matt Sweeney * @for Selector
8d1240fc6300f6769711557511f6882f0a3d3139Matt Sweeney */
8d1240fc6300f6769711557511f6882f0a3d3139Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney/*
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney an+b = get every _a_th node starting at the _b_th
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 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
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n")
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney an+0 = get every _a_th element, "0" may be omitted
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney*/
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
6244b09179e0efbecc704ba75b5323ee0f5b38d3Matt SweeneyY.Selector._reNth = /^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;
7bd6c48178788dd4f19fa028e0294192ee2c7278Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt SweeneyY.Selector._getNth = function(node, expr, tag, reverse) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney Y.Selector._reNth.test(expr);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_)
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney n = RegExp.$2, // "n"
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney oddeven = RegExp.$3, // "odd" or "even"
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney result = [],
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney siblings = Y.DOM._children(node.parentNode, tag),
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney op;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if (oddeven) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney a = 2; // always every other
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney op = '+';
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney n = 'n';
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney b = (oddeven === 'odd') ? 1 : 0;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney } else if ( isNaN(a) ) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney a = (n) ? 1 : 0; // start from the first or no repeat
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if (a === 0) { // just the first
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if (reverse) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney b = siblings.length - b + 1;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if (siblings[b - 1] === node) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return true;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney } else {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return false;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney } else if (a < 0) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney reverse = !!reverse;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney a = Math.abs(a);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if (!reverse) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney for (var i = b - 1, len = siblings.length; i < len; i += a) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if ( i >= 0 && siblings[i] === node ) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return true;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney } else {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney if ( i < len && siblings[i] === node ) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return true;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return false;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney};
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt SweeneyY.mix(Y.Selector.pseudos, {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'root': function(node) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return node === node.ownerDocument.documentElement;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney 'nth-child': function(node, expr) {
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return Y.Selector._getNth(node, expr);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney 'nth-last-child': function(node, expr) {
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return Y.Selector._getNth(node, expr, null, true);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney 'nth-of-type': function(node, expr) {
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return Y.Selector._getNth(node, expr, node.tagName);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
6244b09179e0efbecc704ba75b5323ee0f5b38d3Matt Sweeney 'nth-last-of-type': function(node, expr) {
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return Y.Selector._getNth(node, expr, node.tagName, true);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'last-child': function(node) {
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney var children = Y.DOM._children(node.parentNode);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return children[children.length - 1] === node;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'first-of-type': function(node) {
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney return Y.DOM._children(node.parentNode, node.tagName)[0] === node;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'last-of-type': function(node) {
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney var children = Y.DOM._children(node.parentNode, node.tagName);
0fa21f434cf7d4ed63d790f8fb2a9c68e656d00eMatt Sweeney return children[children.length - 1] === node;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'only-child': function(node) {
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney var children = Y.DOM._children(node.parentNode);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return children.length === 1 && children[0] === node;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'only-of-type': function(node) {
8023f8dbcd1b40edf283b984c103ea7651e2549bMatt Sweeney var children = Y.DOM._children(node.parentNode, node.tagName);
0fa21f434cf7d4ed63d790f8fb2a9c68e656d00eMatt Sweeney return children.length === 1 && children[0] === node;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'empty': function(node) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney return node.childNodes.length === 0;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney 'not': function(node, expr) {
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return !Y.Selector.test(node, expr);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney 'contains': function(node, expr) {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney var text = node.innerText || node.textContent || '';
d59c625bc91380e7d3458db5e7e9a581d670684aMatt Sweeney return text.indexOf(expr) > -1;
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney },
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney 'checked': function(node) {
891267ad40d74f1e123d09a6278fdba826002779Matt Sweeney return (node.checked === true || node.selected === true);
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney },
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney enabled: function(node) {
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney return (node.disabled !== undefined && !node.disabled);
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney },
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney disabled: function(node) {
8906dd44d6aa2a5092388e0c2e80d8dc9aae397cMatt Sweeney return (node.disabled);
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney }
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney});
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt SweeneyY.mix(Y.Selector.operators, {
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney '^=': '^{val}', // Match starts with value
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney '$=': '{val}$', // Match ends with value
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney '*=': '{val}' // Match contains value as substring
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney});
1e4299e83b45ff5cf2fc6b545f0186ecf831ec87Matt Sweeney
63942f7c9f6be91fe24a7b40e76d436847ec9b7bMatt SweeneyY.Selector.combinators['~'] = {
63942f7c9f6be91fe24a7b40e76d436847ec9b7bMatt Sweeney axis: 'previousSibling'
63942f7c9f6be91fe24a7b40e76d436847ec9b7bMatt Sweeney};