ded / qwery Goto Github PK
View Code? Open in Web Editor NEWa query selector engine
License: Other
a query selector engine
License: Other
Global variable found
is declared at https://github.com/ded/qwery/blob/master/src/qwery.js#L207
If you want to support the use of the root/context element to narrow the scope of a id selector then you could change this line of code in the boilerPlate
function:
return (el = doc.getElementById(m[1])) ? [el] : [];
to this:
return (el = doc.getElementById(m[1])) ? (isAncestor(el, root) ? [el] : []) : [];
As it is now, an id selector invocation that includes a scoping element has the scoping element ignored, e.g.,
qwery("#myId", someAncestorNode); // ignores someAncestorNode and doesn't scope the query to it
Maybe a weird use-case but the use-case is "I want to get this element X that I have an id for, but only if the element X is currently a descendant of element Y."
define(['qwery'], function(qwery) {
console.log(qwery)
})
// -> undefined
isNode (typeOf el === 'object') breaks compatibility with old browser
I use a browser written in java called ice browser and this check in the isNode function breaks compatibility with it. The type is coming across as a function for some reason. Any way this check can be removed or to also include typeOf el === 'function'.
function isNode(el) {
return el && typeof el === 'object' && el.nodeType && (el.nodeType == 1 || el.nodeType == 9)
}
Hi,
Right now I'm using Sizzle as part of my event system. On my event system, you do not register an event to an existing node, but you register an event to a "selector" (so it does not matter if you modify the DOM, you don't need to re-attach events to nodes you may have removed/re-added).
To do so, I'm relying on the "match" method of Sizzle, that let me check if the element I clicked/hovered/etc. or any of its parents matches my selectors.
It is a possibility to add a match method to qwery?
I noticed that the root parameter for the _qwery function on 81 is not used. Correct me if I'm wrong, but I think this function intends to use the root parameter on line 83, in the assignment of the current context? While the only usage of this function is within the qwery function, (which guarantees a value for root as at least the document), perhaps a proper fix would be:
currentContext = [root || doc];
? Otherwise the function would search through the document, even if a root were specified, no?
Sorry, this was intended to be a bonzo issue. Added here by mistake.
Leverage native qSA for more than just simple cases, perhaps first test for existence of non-CSS3 qSA and then regex the selector to see if it matches a broader range of non-CSS3 cases and can be handled by the native implementation. At the moment it's just tag and/or class (tag.class or .class) being given to qSA so performance is terrible across other common cases.
And, IE8 aint going away any time soon.
When selecting something that doesn't exist, why do I get back an object? Shouldn't I get back undefined or see an error?
For example, say I have an element:
<div id='awesome'></div>
I'll select it, but I accidentally mistype it:
var myDiv = qwery('#awesom');
It is really hard to debug this (especially in large applications), and this is one of the reasons why I switched from jQuery.
Errors are nice because they show line numbers and originating files. I think returning undefined in this case makes the most sense.
IE does not return the correct elements on those tests http://jsfiddle.net/Calou/amp6J/12/
cast TypeError
error when query only tag on the DocumentFragment
example:
var f = document.createDocumentFragment();
qwery( 'p a', f ); // success
qwery( 'p', f ); // TypeError: Object #<DocumentFragment> has no method 'getElementsByTagName'
Tests don't run in IE (IETester anyway).
I was using qwery as the selector engine for my new tiny framework, but was running into issues in IE < 8. Tried to run the tests in IE to see if they all pass or not, turns out you can't even run the tests, even in IE 8 :(
PR #57 turned the feature-detect for CSS3 qSA from simply ':nth-of-type(1)'
to 'body:nth-of-type(1)'
for performance reasons however since BODY won't be available if Qwery is loaded in HEAD it'll always fail and revert to non-native selection for most cases, which is seriously slow compared to native.
Alternative feature-detect in PR #54 that resolves this problem: https://github.com/ded/qwery/pull/54/files#L1R310
I have a ie 7-8 bug fix
fix for getelementbyeclassname IE error
in qwery function
change
if (hasByClass && m[3]) return arrayify(rootbyClass)
to
if (hasByClass && m[3] && window.addEventListener) return arrayify(rootbyClass)
Simulate error with this bean integration, it does not like ".thumbClickItem" so when you try to delegate context for ajax content.
$(".thumbViewerUL").on("click", ".thumbClickItem", function (evt) {
self.handleEvent(evt);
});
Context should support passing in qwery results:
var el = qwery("#Parent");
var child = qwery(".child", el);
Hi,
I have found a bug(?) in qwery when trying to select an element when using an custom HTML element as context. I noticed this while porting from Sizzle to qwery. Try the following code to reproduce.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:surf="">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="//github.com/jquery/sizzle/raw/master/sizzle.js"></script>
<script src="//github.com/ded/qwery/raw/master/qwery.js"></script>
</head>
<body>
<surf:container id="hello">
<div id="world"></div>
</surf:container>
<script>
console.debug("Sizzle #hello", Sizzle("#hello"));
console.debug("Sizzle #world", Sizzle("#world", Sizzle("#hello")[0]));
console.debug("qwery #hello", qwery("#hello"));
console.debug("qwery #world", qwery("#world", qwery("#hello")[0]));
</script>
</body>
</html>
I get the following console output (using Chrome):
Sizzle #hello [<surf:container id="hello">…</surf:container>]
Sizzle #world [<div id="world"></div>]
qwery #hello [<surf:container id="hello">…</surf:container>]
Uncaught TypeError: Object #<HTMLUnknownElement> has no method 'getElementById'
As you can see Sizzle is able to handle this, but qwery is unable to select the inner element.
Properties like RegExp.$1 are not covered by ES3 or ES5 and may not be implemented in an environment.
I'm just going to put this out there as something for someone to do at some point in the future if they feel so inclined. I don't think it'd be a particularly easy job, especially while maintaining current performance.
Native querySelectorAll()
works, conceptually at least, by scanning all nodes from top to bottom and checking them against the selector, each match gets added to the return list and then we end up with a list of elements in proper document order. Qwery does this except in the case of grouped selectors because we split the selector up into component parts with selector.split(',')
and process them separately with _qwery()
. This split is also done for all browsers in the case of element-rooted queries with a relationship selector first (e.g. Q('>.yee, .haa', element)
).
Take a fragment: <p><a/><b/><i/><em/></p>
and query it for 'b,a'
. qSA will give you [<a/>,<b/>]
because this is document-order while Qwery will give you [<b/>,<a/>]
because we first process the 'b'
and then the 'a
' and append the results together. Sizzle and NW manage to do this properly. There are some cases where it matters but it mainly matters because that's the de-facto standard that's emerged and been written into the actual standard.
Here's a snippet that you can run in the console of a modern browser to demonstrate the issue and could form the basis of a simple unit test:
var e = document.createElement('p');
e.innerHTML = '<a/><i/><b/>';
e.querySelectorAll = null; // comment this out to run with the native qSA
var r = qwery('b,a', e); // insert other selector engine here if you want to see if it works properly
if (r.length !== 2 || !/[aA]/.test(r[0].tagName)) console.log("Bzzt! Wrong answer", r);
else console.log('correct:',r);
This mainly matters for IE <= 7, it matters in IE8 when you're using CSS3+ selectors (otherwise it uses the in-built CSS2-compliant qSA) and I think it'll matter for all browsers with element-rooted queries with relationship selectors first (see above). IE6&7 will hopefully not matter soon so fixing it just for the CSS3 qSA case might be a bit simpler.
I am not sure why there is a check for "el === window" in the isNode() function, it could be because it is use in other contexts elsewhere but it surely isn't needed for qwery.js. I don't see the need to convert nodeType to string and matching against 1/9 either. A simple OR expression will be shorter and faster too.
Current code:
function isNode(el) {
return (el === window || el && el.nodeType && el.nodeType.toString().match(/[19]/));
}
possible improvement in speed and code size if the "el === window" is to be kept:
function isNode(el) {
return (el === window || (el && el.nodeType == 1 || el.nodeType == 9));
}
alternative improvement in speed and code size if the "el === window" is not needed:
function isNode(el) {
return el && el.nodeType == 1 || el.nodeType == 9;
}
happy coding.
It throws an error in IE8
When I want to show an element via $('some-selector').show()
, I expect it to set the element's display
property to block
. It looks like the .show()
function wants you to pass in the display type, which is fine. the problem is that if you fail to pass in a display type, the default is an empty string.
It may just be that I'm used to jQuery's behavior, but to me it seems like a more reasonable default, since setting an element's display
to ""
doesn't seem to show the element. I, for one, think it's confusing that I can call the function show
and I get neither an error nor a visible element.
Thoughts?
Because you inject attribute values directly into dynamically created regexps you should escape any special regexp chars before hand.
As per ded/bonzo#98, and fix e0b349d#L10L10, can this also be done on the qwery-mobile
src
After the fix, could you also tag (so bower
can pull it in)
If you pass a non-existant node as root, as a string (so, for example qwerty("li[class='aClass']", "ul#two"), where there is no ul with ID two on the document) an error is thrown, since root returns undefined. A simple fix would be to add a root && ...
to the line root = isFinite(root.length) && root[0] && !root.nodeName ? root[0] : root
Example:
$('#button').listen('click', function(e) {
$(this).remove('click');
});
This will work in jquery, but just throws an error here. It would be nice to get the same functionality.
Hi,
It seems I have an issue on IE7 using a dom node context with a html5 tag, if that makes sense...
Note that if I change the tags from "section" to "div", it works.
Articles tags don't work either.
Is that a bug or I'm missing something?
See the code below.
Romu
<!doctype html>
<html>
<head>
<title>title</title>
</head>
<body>
<section id="main">
<section class="test">
</section>
<section class="test">
</section>
</section>
<script type="text/javascript" src="qwery.js"></script>
<script type="text/javascript">
var main = qwery("#main")[0];
alert(main)
alert(main.id)
var tests = qwery(".test", main);
alert(tests)
alert(tests.length)
</script>
</body>
</html>
Event delegation is awesome, and a big part of that is being able to match an element. A match API that may also hook into native match API supplied by some browsers would be nice.
Trying with rev dc2455332f6c03102da47aff44d9697da299e468
:
<div id=fixture>
<a>Should Match</a>
</div>
and the JS
qwery('a', '#fixture')
Getting "object does not support this property or method" in IE8, line 161 of qwery.js
return array((root || doc).querySelectorAll(selector), 0);
Will report any findings.
Attempting to create a second element in chrome response with the above error. The same code works fine in Safari. Doing the same with ender.js/qwery responds with Uncaught TypeError: Cannot read property 'nextSibling'.
$.domReady(function () {
var table = $("<table>");
var thead = $("<thead>");
var th = $("<th>");
});
The 'element' variable is not declared in the 'select' function so it becomes global.
It is in the last part of the ternary operator:
for (j = 0, m = collection.length; j < m && (element = collection[j]); j++) {
// make sure element is a descendent of root
isAncestor(element, root) && ret.push(element);
Hello
This isn't a bug in the qwery code, but an issue with document.querySelector which I'm hoping you could code around.
$('foo') returns []
But...
$('foo[') returns 'DOM Exception 12'
This obviously is an error with document.querySelector. Any chance you could put a try / catch around the document.querySelector line?
This error will only occur with browsers that have document.querySelector so I'd imagine this doesn't happen for non querySelector compatible browsers so the qwery interface will be inconsistent.
This will be affecting qwery-mobile too.
Regards,
Tom.
Time for a qwery-pseudos package eh?
$ ender build qwery qwery-pseudos bonzo bean
For an additional pseudos-only package or perhaps:
$ ender build qwery++ bonzo bean
For a full Qwery + pseudos package as an alternative to vanilla Qwery.
I don't mind putting in a PR in for this to prepare the groundwork if you want.
getAttribute(...), though defined by spec to return an empty string, may in most browsers return null
. So somthing like qwery('[foo^="bar"]')
will throw an error because you assume e.getAttribute(attrName)
is a string.
If I do this:
$('form').each(function () {
var form = this,
submit = $('button[type=submit]', form);
submit.click(function () {
// do stuff
});
});
It doesn't work. The problem is that (at least in Chrome) html form elements have a length. Therefore, when qwery is trying to determine the root element, it looks at the form element as a qwery selector and returns form[0]
, which in this case turns out to be an input element of the form. The temporary way around this is to wrap the bare html form element in a qwery:
// instead of
var form = this;
// do
var form = $(this);
querySelectorAll is buggy and may throw errors. Other engines like Sizzle, will wrap the call in a try-catch
and then attempt a selector via it's secondary engine. Qwery will simply error.
Hi!
Let us collect here the subj. First,
<input data-id="1" type="text"/>
$('input[data-id=1]')
results in Error: SYNTAX_ERR: DOM Exception 12
What do I do wrong?
TIA,
--Vladimir
This is a feature request for adding support with a fallback for document.documentElement.matchesSelector (moz,webkit,ms prefixes available). The fallback provided in Sizzle is implemented by an optional argument on the main function that is a set of elements to filter with the given query. This would mean a filtering function would have to be added to qwery, but the loss to performance would not be more than an extra if statement in qwery to see if that set argument was present. The size added would depend on the brevity of the filter function.
The main advantage to this addition is that a method like this would be required in order to implement not only matchesSelector, but a filter method in ender.
Awsome code! THANKS for sharing!!!
With that said...
Is there a Google group I could join to ask questions?
For example, I would like to use the mobile version, but I have some implementation questions... Is there an official Google group I could query?
Thanks!
Micky
Hi,
I cloned qwery and have edited qwery-mobile to be AMD compatible in the same way as qwery, bonzo and reqwest are.
I'd like to run the tests before making a pull request. The mobile test page is referencing a build folder which doesn't exist in the project. Should I add this myself or is this supposed to point at the vendor directory?
Thanks,
Tom.
making a note of this for book-keeping. this test is failing in our suite.
#foo a[rel^="hello world"] strong
The README gives an example of creating a custom pseudo selector :foo(bar), but no custom pseudo selectors can be added to qwery unless they are already supported by default in querySelectorAll. You do say later that querySelectorAll is used where supported, but it isn't very clear that custom pseduo selectors will not be supported in that case. If you wanted to implement this, I think you could with no performance loss and probably no more than three lines (I'm just picturing in my head). But if not, the README should probably be updated.
I know querySelectorAll (QSA) will return a match document.body.querySelectorAll('body p')
including the context when it evaluates the selector instead of just the descendants. Sizzle and other popular libs take a different approach where $('body p', document.body)
would not return a match. Currently your lib follows the QSA behavior.
I see src/sizzlr.js
attempts to simulate Sizzles context behavior. Maybe a doc note should be created for this.
In IE if an element in a nodeList has an id="length", or some other browsers if a form element has a name/id ="length", you won't be able to access the length property. You can iterate without knowing the length.
those are the only selectors i would need... doesnt even has to be CSS3 compliant. something like ul>li[3] would be fine too.
any ideas where to hook this into?
as a start:
simple = /^([a-z0-9]+)?(?:([.#]+[\w-.#]+)?(?:(:nth-[\w-+()]+))?)/,
var div = document.createElement('div');
div.innerHTML = '<p>' + Array(16).join('<div>') + '<code></code>' + Array(16).join('</div>') + '</p>';
var selector = 'span > div div div div code';
var element = div.querySelector('code');
console.time('qwery.is');
qwery.is(element, selector, div);
console.timeEnd('qwery.is');
i believe, dynamic programming can be used to increase performance of "ancestorMatch"
I want to get p.p0 by doing this query but returns [ ]
.
qwery("#container p:first-child")
<div id="container">
...
<div id="div">div#div</div>
<p class="p0">The p0</p>
<p class="p1">The p1</p>
<p class="p2">The p2</p>
<p class="p3">The p3</p>
</div>
@benvinegar's query on Twitter about being able to return the first match only got me thinking that it may not be that difficult to implement and would actually be quite helpful in many situations.
So here's a first go at hacking a solution, no tests and begging for review by other eyes: https://github.com/rvagg/qwery/compare/master...first
The basic idea is to use querySelector()
where available, then we fall back to _qwery()
for odd queries or where querySelector()
isn't available. We then shortcut the various paths to matches when we have asked for a first
and have found a result. There's a few places this needs to be done and my implementation isn't quite optimal because there's currently no way to halt an each()
call so we end up doing a bunch of useless loops, but that could be easily fixed by special handling of return false
.
Of course, there's still the document-order problem (see #63), so any documentation around use of this functionality would need to stress that you may not get the same result for queries with groups in old vs new browsers because of the differences between querySelector()
and what selectNonNative
does with splitting the query... Or, someone could fix #63.
Also put in a simple $.first('selector')
to the Ender bridge.
In its current form it adds 109 bytes to minified gzipped Qwery.
And, FWIW, NWMatcher has a neat callback feature where you pass in a function that gets called on each match so you can process elements one by one but if you return a false
then it'll halt processing so you can use it to implement a first()
which halts on first match, see the NW Ender bridge.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.