Skip to content

Commit

Permalink
CHANGE Awesome, removed the parts array from the parser. Removed the …
Browse files Browse the repository at this point in the history
…type attribute on the pseudos and attributes items. Specs are passing like before and the speed remains the same.
  • Loading branch information
fabiomcosta committed May 10, 2010
1 parent 819812a commit c4e35e0
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 83 deletions.
12 changes: 6 additions & 6 deletions README.md
Expand Up @@ -109,8 +109,8 @@ SelectorObject format
{
"raw":"#foo > bar.baz",
"expressions": [[
{ "combinator":" ", "tag":"*", "id":"foo", "parts": [] },
{ "combinator":">", "tag":"bar", "classList": ["baz"], "classes": [{ "type":"class", "value":"baz", "regexp":RegExp }], "parts": [{ "type":"class", "value":"baz", "regexp":RegExp }] }
{ "combinator":" ", "tag":"*", "id":"foo" },
{ "combinator":">", "tag":"bar", "classList": ["baz"], "classes": [{"value":"baz", "regexp":RegExp }]}
]]
}

Expand All @@ -119,9 +119,9 @@ SelectorObject format
{
"raw": "h1, h2, ul > li, .things",
"expressions": [
[{ "combinator":" ", "tag": "h1", "parts": [] }],
[{ "combinator":" ", "tag": "h2", "parts": [] }],
[{ "combinator":" ", "tag": "ul", "parts": [] }, { "combinator": ">", "tag": "li", "parts": [] }],
[{ "combinator":" ", "tag": "*", "classList": ["things"], "classes": [{ "type": "class", "value": "things", "regexp":RegExp }], "parts": [{ "type": "class", "value": "things", "regexp":RegExp }] }]
[{ "combinator":" ", "tag": "h1" }],
[{ "combinator":" ", "tag": "h2" }],
[{ "combinator":" ", "tag": "ul" }, { "combinator": ">", "tag": "li" }],
[{ "combinator":" ", "tag": "*", "classList": ["things"], "classes": [{"value": "things", "regexp":RegExp }] }]
]
}
121 changes: 62 additions & 59 deletions Source/Slick.Finder.js
Expand Up @@ -234,12 +234,9 @@ local.search = function(context, expression, append, first){

// default engine

var currentExpression, currentBit;
var j, m, n;
var combinator, tag, id, parts, classes;
var currentItems;
var expressions = parsed.expressions;
var lastBit;
var combinator, tag, id, classList, classes, attributes, pseudos;
var currentItems, currentExpression, currentBit, lastBit, expressions = parsed.expressions;

search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (currentBit = currentExpression[j]); j++){

Expand All @@ -248,8 +245,10 @@ local.search = function(context, expression, append, first){

tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperCase();
id = currentBit.id;
parts = currentBit.parts;
classes = currentBit.classList;
classList = currentBit.classList;
classes = currentBit.classes;
attributes = currentBit.attributes;
pseudos = currentBit.pseudos;
lastBit = (j === (currentExpression.length - 1));

this.bitUniques = {};
Expand All @@ -263,13 +262,13 @@ local.search = function(context, expression, append, first){
}

if (j === 0){
this[combinator](context, tag, id, parts, classes);
this[combinator](context, tag, id, classes, attributes, pseudos, classList);
if (first && lastBit && found.length) break search;
} else {
if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){
this[combinator](currentItems[m], tag, id, parts, classes);
this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
if (found.length) break search;
} else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, parts, classes);
} else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](currentItems[m], tag, id, classes, attributes, pseudos, classList);
}

currentItems = this.found;
Expand Down Expand Up @@ -359,13 +358,13 @@ local.createNTHPseudo = function(child, sibling, positions, ofType){
}
};

local.pushArray = function(node, tag, id, selector, classes){
if (this.matchSelector(node, tag, id, selector, classes)) this.found.push(node);
local.pushArray = function(node, tag, id, classes, attributes, pseudos){
if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.found.push(node);
};

local.pushUID = function(node, tag, id, selector, classes){
local.pushUID = function(node, tag, id, classes, attributes, pseudos){
var uid = this.getUID(node);
if (!this.uniques[uid] && this.matchSelector(node, tag, id, selector, classes)){
if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attributes, pseudos)){
this.uniques[uid] = true;
this.found.push(node);
}
Expand All @@ -378,11 +377,11 @@ local.matchNode = function(node, selector){
// simple (single) selectors
if(parsed.length == 1 && parsed.expressions[0].length == 1){
var exp = parsed.expressions[0][0];
return this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.parts);
return this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUpperCase(), exp.id, exp.classes, exp.attributes, exp.pseudos);
}

var nodes = this.search(this.document, parsed);
for (var i=0, item; item = nodes[i++];){
for (var i = 0, item; item = nodes[i++];){
if (item === node) return true;
}
return false;
Expand All @@ -395,7 +394,7 @@ local.matchPseudo = function(node, name, argument){
return (argument) ? argument == attribute : !!attribute;
};

local.matchSelector = function(node, tag, id, parts, classes){
local.matchSelector = function(node, tag, id, classes, attributes, pseudos){
if (tag){
if (tag == '*'){
if (node.nodeName < '@') return false; // Fix for comment nodes and closed nodes
Expand All @@ -404,23 +403,28 @@ local.matchSelector = function(node, tag, id, parts, classes){
}
}
if (id && node.getAttribute('id') != id) return false;
if (parts) for (var i = 0, l = parts.length, part, cls; i < l; i++){
part = parts[i];
if (part.type == 'class' && classes !== false){
cls = ('className' in node) ? node.className : node.getAttribute('class');
if (!(cls && part.regexp.test(cls))) return false;
}
if (part.type == 'pseudo' && (!this.matchPseudo(node, part.key, part.value))) return false;
if (part.type == 'attribute' && (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key))) return false;

var i, part, cls;
if (classes) for (i = classes.length; i--;){
cls = ('className' in node) ? node.className : node.getAttribute('class');
if (!(cls && classes[i].regexp.test(cls))) return false;
}
if (attributes) for (i = attributes.length; i--;){
part = attributes[i];
if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.hasAttribute(node, part.key)) return false;
}
if (pseudos) for (i = pseudos.length; i--;){
part = pseudos[i];
if (!this.matchPseudo(node, part.key, part.value)) return false;
}
return true;
};

var combinators = {

' ': function(node, tag, id, parts, classes){ // all child nodes, any level
' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all child nodes, any level

var i, l, item, children;
var i, item, children;

if (!this.isXMLDocument){
getById: if (id){
Expand All @@ -432,7 +436,7 @@ var combinators = {
if (!children) return;
if (!children[0]) children = [children];
for (i = 0; item = children[i++];) if (item.getAttributeNode('id').nodeValue == id){
this.push(item, tag, null, parts);
this.push(item, tag, null, classes, attributes, pseudos);
break;
}
return;
Expand All @@ -442,98 +446,97 @@ var combinators = {
if (this.contains(this.document.documentElement, node)) return;
else break getById;
} else if (this.document !== node && !this.contains(node, item)) return;
this.push(item, tag, null, parts);
this.push(item, tag, null, classes, attributes, pseudos);
return;
}
getByClass: if (node.getElementsByClassName && classes && !this.brokenGEBCN){
children = node.getElementsByClassName(classes.join(' '));
children = node.getElementsByClassName(classList.join(' '));
if (!(children && children.length)) break getByClass;
for (i = 0, l = children.length; i < l; i++) this.push(children[i], tag, id, parts, false);
for (i = 0; item = children[i++];) this.push(item, tag, id, null, attributes, pseudos);
return;
}
}
getByTag: {
children = node.getElementsByTagName(tag);
if (!(children && children.length)) break getByTag;
if (!this.brokenStarGEBTN) tag = null;
var child;
for (i = 0; child = children[i++];) this.push(child, tag, id, parts);
for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attributes, pseudos);
}
},

'!': function(node, tag, id, parts){ // all parent nodes up to document
while ((node = node.parentNode)) if (node !== document) this.push(node, tag, id, parts);
'!': function(node, tag, id, classes, attributes, pseudos){ // all parent nodes up to document
while ((node = node.parentNode)) if (node !== document) this.push(node, tag, id, classes, attributes, pseudos);
},

'>': function(node, tag, id, parts){ // direct children
'>': function(node, tag, id, classes, attributes, pseudos){ // direct children
if ((node = node.firstChild)) do {
if (node.nodeType === 1) this.push(node, tag, id, parts);
if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
} while ((node = node.nextSibling));
},

'!>': function(node, tag, id, parts){ // direct parent (one level)
'!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent (one level)
node = node.parentNode;
if (node !== document) this.push(node, tag, id, parts);
if (node !== document) this.push(node, tag, id, classes, attributes, pseudos);
},

'+': function(node, tag, id, parts){ // next sibling
'+': function(node, tag, id, classes, attributes, pseudos){ // next sibling
while ((node = node.nextSibling)) if (node.nodeType === 1){
this.push(node, tag, id, parts);
this.push(node, tag, id, classes, attributes, pseudos);
break;
}
},

'!+': function(node, tag, id, parts){ // previous sibling
'!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibling
while ((node = node.previousSibling)) if (node.nodeType === 1){
this.push(node, tag, id, parts);
this.push(node, tag, id, classes, attributes, pseudos);
break;
}
},

'^': function(node, tag, id, parts){ // first child
'^': function(node, tag, id, classes, attributes, pseudos){ // first child
node = node.firstChild;
if (node){
if (node.nodeType === 1) this.push(node, tag, id, parts);
else this['combinator:+'](node, tag, id, parts);
if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
else this['combinator:+'](node, tag, id, classes, attributes, pseudos);
}
},

'!^': function(node, tag, id, parts){ // last child
'!^': function(node, tag, id, classes, attributes, pseudos){ // last child
node = node.lastChild;
if (node){
if (node.nodeType === 1) this.push(node, tag, id, parts);
else this['combinator:!+'](node, tag, id, parts);
if (node.nodeType === 1) this.push(node, tag, id, classes, attributes, pseudos);
else this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
}
},

'~': function(node, tag, id, parts){ // next siblings
'~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
while ((node = node.nextSibling)){
if (node.nodeType !== 1) continue;
var uid = this.getUID(node);
if (this.bitUniques[uid]) break;
this.bitUniques[uid] = true;
this.push(node, tag, id, parts);
this.push(node, tag, id, classes, attributes, pseudos);
}
},

'!~': function(node, tag, id, parts){ // previous siblings
'!~': function(node, tag, id, classes, attributes, pseudos){ // previous siblings
while ((node = node.previousSibling)){
if (node.nodeType !== 1) continue;
var uid = this.getUID(node);
if (this.bitUniques[uid]) break;
this.bitUniques[uid] = true;
this.push(node, tag, id, parts);
this.push(node, tag, id, classes, attributes, pseudos);
}
},

'++': function(node, tag, id, parts){ // next sibling and previous sibling
this['combinator:+'](node, tag, id, parts);
this['combinator:!+'](node, tag, id, parts);
'++': function(node, tag, id, classes, attributes, pseudos){ // next sibling and previous sibling
this['combinator:+'](node, tag, id, classes, attributes, pseudos);
this['combinator:!+'](node, tag, id, classes, attributes, pseudos);
},

'~~': function(node, tag, id, parts){ // next siblings and previous siblings
this['combinator:~'](node, tag, id, parts);
this['combinator:!~'](node, tag, id, parts);
'~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings and previous siblings
this['combinator:~'](node, tag, id, classes, attributes, pseudos);
this['combinator:!~'](node, tag, id, classes, attributes, pseudos);
}

};
Expand Down
28 changes: 10 additions & 18 deletions Source/Slick.Parser.js
Expand Up @@ -13,7 +13,6 @@ var exports = this;
var parsed,
separatorIndex,
combinatorIndex,
partIndex,
reversed,
cache = {},
reverseCache = {},
Expand Down Expand Up @@ -129,8 +128,7 @@ function parser(
var currentSeparator = parsed.expressions[separatorIndex];
if (reversed && currentSeparator[combinatorIndex])
currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*', parts: []};
partIndex = -1;
currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
}

var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
Expand All @@ -142,32 +140,26 @@ function parser(
currentParsed.id = id.replace(reUnescape, '');

} else if (className){
if (!currentParsed.classes) currentParsed.classes = [];
if (!currentParsed.classList) currentParsed.classList = [];

className = className.replace(reUnescape, '');

if (!currentParsed.classList) currentParsed.classList = [];
if (!currentParsed.classes) currentParsed.classes = [];
currentParsed.classList.push(className);

currentParsed.classes.push(currentParsed.parts[++partIndex] = {
type: 'class',
currentParsed.classes.push({
value: className,
regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
});

} else if (pseudoClass){
if (!currentParsed.pseudos) currentParsed.pseudos = [];

pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;

currentParsed.pseudos.push(currentParsed.parts[++partIndex] = {
type: 'pseudo',
if (!currentParsed.pseudos) currentParsed.pseudos = [];
currentParsed.pseudos.push({
key: pseudoClass.replace(reUnescape, ''),
value: pseudoClassValue
});

} else if (attributeKey){
if (!currentParsed.attributes) currentParsed.attributes = [];

attributeKey = attributeKey.replace(reUnescape, '');
attributeValue = (attributeValue || '').replace(reUnescape, '');

Expand Down Expand Up @@ -196,8 +188,8 @@ function parser(
return value && regexp.test(value);
};

currentParsed.attributes.push(currentParsed.parts[++partIndex] = {
type: 'attribute',
if (!currentParsed.attributes) currentParsed.attributes = [];
currentParsed.attributes.push({
key: attributeKey,
operator: attributeOperator,
value: attributeValue,
Expand Down

0 comments on commit c4e35e0

Please sign in to comment.