Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Monster performance improvements, add "div,span" syntax

  • Loading branch information...
commit 5121efbb6e2ddb191d783a162861cd80cff36e4c 1 parent 79feafa
@pyrsmk authored
View
14 README.markdown
@@ -1,10 +1,9 @@
-Nut 0.1.3
-=========
+Nut 0.4
+=======
Nut is a concise query selector engine that just allows you to do extremely simple queries.
-Syntax
-------
+First of all, nut is, most of the time, faster than `querySelectorAll` (take a look at the benchmark) and then faster than all selector engines. But please note that nut doesn't implement request caching to avoid unnecessary code additions and performance loss: the user can easily keep a request and pass it as a context to another request.
Here's it can handle:
@@ -12,11 +11,11 @@ Here's it can handle:
section
.bar p
section #foo .bar p
+ div , #foo , .bar
And here's it can't:
div#foo div.bar
- div#foo.bar
div *
div > p
div + p
@@ -33,7 +32,4 @@ Of course, queries can have a context:
// Get nodes from the #foo context
nut('.bar p',nut('#foo'));
-Performance
------------
-
-Nut, is faster than `querySelectorAll` (take a look at the benchmark) and then faster than all selector engines. But, nut doesn't implement request caching to avoid unnecessary code additions and performance loss: the user can easily keep a request and pass it as a context to another request.
+And that's all you need to know ;)
View
6 benchmark/index.html
@@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <title>nut unit testing</title>
+ <title>nut - benchmark</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
@@ -19,5 +19,9 @@
</p>
<p></p>
</div>
+ <table>
+ <tr></tr>
+ <tr></tr>
+ </table>
</body>
</html>
View
26 benchmark/runner.js
@@ -1,25 +1,25 @@
domReady(function(){
- var suite=new Benchmark.Suite;
+ var suite=new Benchmark.Suite();
// p
- suite.add('[querySelectorAll] p',function(){
+ suite.add('[querySelectorAll: p]',function(){
document.querySelectorAll('p');
})
- .add('[nut] p',function(){
+ .add('[nut: p]',function(){
nut('p');
})
// #foo
- .add('[querySelectorAll] #foo',function(){
+ .add('[querySelectorAll: #foo]',function(){
document.querySelectorAll('#foo');
})
- .add('[nut] #foo',function(){
+ .add('[nut: #foo]',function(){
nut('#foo');
})
// .bar from #foo context
- .add('[querySelectorAll] .bar from #foo context',function(){
+ .add('[querySelectorAll: .bar from #foo context]',function(){
var foo=document.querySelectorAll('#foo'),
nodes=[],
bar,i,
@@ -33,18 +33,26 @@ domReady(function(){
}
}
})
- .add('[nut] .bar from #foo context',function(){
+ .add('[nut: .bar from #foo context]',function(){
nut('.bar',nut('#foo'));
})
// #foo .bar span
- .add('[querySelectorAll] #foo .bar span',function(){
+ .add('[querySelectorAll: #foo .bar span]',function(){
document.querySelectorAll('#foo .bar span');
})
- .add('[nut] #foo .bar span',function(){
+ .add('[nut: #foo .bar span]',function(){
nut('#foo .bar span');
})
+ // #foo span,table tr
+ .add('[querySelectorAll: #foo span,table tr]',function(){
+ document.querySelectorAll('#foo span,table tr');
+ })
+ .add('[nut: #foo span,table tr]',function(){
+ nut('#foo span,table tr');
+ })
+
// Display results
.on('complete',function(){
var j=this.length;
View
2  nut.min.js
@@ -1 +1 @@
-this.nut=function(a,b){if(a.match(/^(\s*[#.]?\w+\s*)+$/)===null)return[];b||(b=[this.document]),b.length===undefined&&(b=[b]);var c,d=function(a,b){var c=[],e=b.childNodes.length,f;for(var g=0;g<e;++g)(f=b.childNodes[g].className)&&f.match(new RegExp("(^|s+)"+a+"($|s+)"))&&c.push(b.childNodes[g]),c=c.concat(d(a,b.childNodes[g]));return c};for(var e in b){c=[b[e]],a=a.split(/\s+/);for(var f in a){var g=[],h,i=a[f].match(/^([#.])?(.+)/);if(!i)return[];for(var j in c){switch(i[1]){case".":h=c[j].getElementsByClassName?c[j].getElementsByClassName(i[2]):d(i[2],c[j]);break;case"#":h=[this.document.getElementById(i[2])];break;default:h=c[j].getElementsByTagName(i[2])}var k=h.length;for(var l=0;l<k;++l)g.push(h[l])}c=g}}return c}
+(function(a,b){function c(a,b){var d=[],e,f=-1;while(e=b.childNodes[++f])e.className&&e.className.match("\\b"+a+"\\b")&&d.push(e),d=d.concat(c(a,e));return d}a.nut=function(a,d){a=a.split(","),d||(d=[this.document]),d.length===undefined&&(d=[d]);var e=[],f,g,h,i,j,k,l,m,n,o,p=-1,q,r,s,t;while(f=d[++p]){q=-1;while(g=a[++q]){i=[f],l=g.split(/\s+/),r=-1;while((k=l[++r])!==undefined){if(!k)continue;m=k.match(/^([#.])?(.+)/),j=[],s=-1;while(h=i[++s]){switch(m[1]){case".":h.getElementsByClassName?n=h.getElementsByClassName(m[2]):n=c(m[2],h);break;case"#":n=[b.getElementById(m[2])];break;default:n=h.getElementsByTagName(m[2])}t=-1;while(o=n[++t])j.push(o)}i=j}e=e.concat(i)}}return e}})(this,this.document)
View
175 src/nut.js
@@ -1,121 +1,124 @@
/*
nut, the concise CSS selector engine
- Version : 0.1.3
+ Version : 0.4
Author : Aurélien Delogu (dev@dreamysource.fr)
URL : https://github.com/pyrsmk/nut
License : MIT
-
- TODO
- [/] lint
- [ ] #foo,div syntax
*/
(function(window,document){
/*
- Select DOM nodes
+ Get nodes corresponding to a class name (for IE<9)
Parameters
- string selectors : CSS selectors
- array, object contexts : context nodes
+ string name : class name
+ object context : contextual node
Return
- array : found nodes
+ array : found nodes
*/
- window.nut=function(selectors,contexts){
- // No selectors or contains forbidden chars
- if(!selectors.match(/^[#.\w\s]+$/)){
- return [];
- }
- // Format
- if(!contexts){
- contexts=[this.document];
- }
- if(contexts.length===undefined){
- contexts=[contexts];
- }
+ function getNodesByClassName(name,context){
// Init vars
var nodes=[],
- elements,
- nodelist,
- node,
- re_selectors=/\s+/,
- re_tokens=/^([#.])?(.+)/,
- tokens,
- i=0,
- j,k,l;
- // Browse contexts
- while(context=contexts[i++]){
- // Set context
- nodes.push(context);
- // Browse selectors
- selectors=selectors.split(re_selectors);
- j=0;
- while(selector=selectors[j++]){
- // Split selector
- tokens=selector.match(re_tokens);
- // No tokens? Goodbye!
- if(!tokens){
- return [];
- }
- // Apply current selector to all current nodes
- elements=[];
- k=0;
- while(node=nodes[k++]){
- switch(tokens[1]){
- // Get elements by class
- case '.':
- nodelist=node.getElementsByClassName?
- node.getElementsByClassName(tokens[2]):
- getNodesByClassName(tokens[2],node);
- break;
- // Get elements by id
- case '#':
- nodelist=[document.getElementById(tokens[2])];
- break;
- // Get elements by tag
- default:
- nodelist=node.getElementsByTagName(tokens[2]);
- }
- // Push new elements
- l=0;
- while(node=nodelist[l++]){
- elements.push(node);
- }
- }
- // Update nodes
- nodes=elements;
+ child,
+ i=-1;
+ // Browse children
+ while(child=context.childNodes[++i]){
+ // Match the class
+ if(child.className && child.className.match('\\b'+name+'\\b')){
+ nodes.push(child);
}
+ // Get nodes from child's children
+ nodes=nodes.concat(getNodesByClassName(name,child));
}
return nodes;
- };
+ }
/*
- Define a getElementsByClassName replacement function for IE<9
+ Select DOM nodes
Parameters
- string name : class name
- object context : context node
+ string expressions : CSS selectors
+ array, object contexts : contextual nodes
Return
- array : found nodes
+ array : found nodes
*/
- function getNodesByClassName(name,context){
+ window.nut=function(expressions,contexts){
+ // Format
+ expressions=expressions.split(',');
+ if(!contexts){
+ contexts=[this.document];
+ }
+ if(contexts.length===undefined){
+ contexts=[contexts];
+ }
// Init vars
var nodes=[],
- j=context.childNodes.length,
- classname;
- // Browse children
- for(var i=0;i<j;++i){
- if(classname=context.childNodes[i].className){
- // Match the class
- if(classname.match(new RegExp('(^|\s+)'+name+'($|\s+)'))){
- nodes.push(context.childNodes[i]);
+ context,
+ expression,
+ local_context,
+ local_contexts,
+ future_local_contexts,
+ selector,
+ selectors,
+ tokens,
+ elements,
+ element,
+ i=-1,
+ j,k,l,m;
+ // Evaluate expressions for each global context
+ while(context=contexts[++i]){
+ j=-1;
+ while(expression=expressions[++j]){
+ // Init local context
+ local_contexts=[context];
+ // Evaluate expression
+ selectors=expression.split(/\s+/);
+ k=-1;
+ while((selector=selectors[++k])!==undefined){
+ // Drop empty selectors
+ if(!selector){
+ continue;
+ }
+ // Tokenize current selector
+ tokens=selector.match(/^([#.])?(.+)/);
+ // Evaluate current selector for each local context
+ future_local_contexts=[];
+ l=-1;
+ while(local_context=local_contexts[++l]){
+ switch(tokens[1]){
+ // Get elements by class
+ case '.':
+ if(local_context.getElementsByClassName){
+ elements=local_context.getElementsByClassName(tokens[2]);
+ }
+ else{
+ elements=getNodesByClassName(tokens[2],local_context);
+ }
+ break;
+ // Get elements by id
+ case '#':
+ elements=[document.getElementById(tokens[2])];
+ break;
+ // Get elements by tag
+ default:
+ elements=local_context.getElementsByTagName(tokens[2]);
+ }
+ // Add new nodes to the future local context list
+ m=-1;
+ while(element=elements[++m]){
+ future_local_contexts.push(element);
+ }
+ }
+ // Set new local contexts
+ local_contexts=future_local_contexts;
}
+ // Append new nodes
+ nodes=nodes.concat(local_contexts);
}
- // Browse child children
- nodes=nodes.concat(getNodesByClassName(name,context.childNodes[i]));
}
return nodes;
};
View
6 unit/index.html
@@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
- <title>nut unit testing</title>
+ <title>nut - unit testing</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
@@ -19,5 +19,9 @@
</p>
<p></p>
</div>
+ <table>
+ <tr></tr>
+ <tr></tr>
+ </table>
</body>
</html>
View
5 unit/runner.js
@@ -2,7 +2,7 @@ domReady(function(){
sink('nut',function(test,ok,before,after){
- test('Acceptable selectors',5,function(){
+ test('Acceptable selectors',6,function(){
// p
var nodes=nut('p');
ok(nodes.length==3 && (typeof nodes[0]=='object') && (typeof nodes[1]=='object') && (typeof nodes[2]=='object'),'p');
@@ -18,6 +18,9 @@ domReady(function(){
// #foo .bar span
nodes=nut('#foo .bar span');
ok(nodes.length==2 && (typeof nodes[0]=='object') && (typeof nodes[1]=='object'),'#foo .bar span');
+ // #foo span,table tr
+ nodes=nut(' #foo span , table tr ');
+ ok(nodes.length==4 && (typeof nodes[0]=='object') && (typeof nodes[1]=='object') && (typeof nodes[2]=='object') && (typeof nodes[3]=='object'),'#foo span,table tr');
});
test('Non acceptable selectors',1,function(){
Please sign in to comment.
Something went wrong with that request. Please try again.