The last couple of weeks I took some time to draft a Selectors API. Indeed, an API for the Selectors specification. Example of usage:
var x = document.matchAll("div.section > p"); for(i=0; i < x.length; i++){ // do something with x[i] }
You can use namespaces as well by passing an XPathNSResolver
object (or Function
) as second (optional) argument to document.matchAll
. There is also document.match
which returns the first Element
node encountered in the document (using specific traversal). Both methods take a group of selectors as argument, so the following is possible as well:
var y = document.match("#bar, #foo, #baz");
y contains a reference to Element
node first in the document that had one of those ID values. I hope to get it on Recommendation track soonish, the document is pretty stable. The biggest problem is probably document.matchAll(":visited")
, but that is already possible more or less anyway.
Regarding the :visited
pseudo class, you can already hack a user’s history by using getComputedStyle
on a link. Add a bit of Ajax magic and well, you can see where I’m going...
Any particular reason for not choosing a name that is more in par with the existing DOM names, e.g. getElementsBySelector
?
~Grauw
(.match
makes me think more of regular expressions, both because XPath uses the term and JavaScript has a similar-named function for strings.)
~Grauw
Laurens there's nothing stopping you from prototyping your own, you know. It's hardly a big deal if it's not already there.
Anne, it would be nice if the interface would be implemented by Element instead of Document. That is, something like var div = document.getElementById('x'); var list = div.matchAll('something'); Of course this example could be rewritten to document.matchAll('#x something'), the point is that you might have a reference to an element without an id (say, after an event using e.target) and you'd like to get some children of that node. This is similair to getElementsByTagName, which is also implemented by Element. (And I agree that .match is confusing with the String.match method for regexps. I'd prefer something like .select)
jbot, aren’t we talking about a work-in-progress of an official W3C specification here? I’d say that deserves some careful thinking of sensible and consistent naming, and I’m just giving my 2 eurocents. Of course I know I can prototype everything, but that’s a bit of a cop-out answer, and beside the point.
Salar, imho it would be nice if it wer both implemented by Element and Document (just like getElementsByTagName
). But otoh, that might not make sense from a CSS specification point of view.
Why was a StaticNodeList
chosen over a normal live NodeList
? Are there any specific implementation concerns with the live list? If so, what are they? Or is it because a static list is easier to work with from an authoring perspective, in that it doesn't inadvertently change content when the script modifes the DOM, which can cause problems when you're iterating over the list?
What's the reason for having two separate methods: match()
and matchAll()
? Is there something that match()
can do that matchAll().item(0)
can't? Is there a use case for where the the author would only want to work with the first matching node that warrants having a special method for it?
I can imagine that as being a source of confusion for authors, where they use match()
without thinking, when they want to select all matching nodes, not just the first, and then have trouble trying to work out why their script isn't working properly.
Salar, you could always set an ID
on the event target, but it seems to be worth considering.
Lachlan, implementors told me a live NodeList
is probably not really feasible. Think of document.matchAll(":hover")
for example (and more complicated variants). match
is there for speed mostly.
I think if the user wants to get only one node, he/she will prefer getElementById
, instead of using selector. Or perheps getElementsByCSS().items(0)
is good enough too.
But I agree that it should be implemented by Document
, not Element
.
Lachlan, Live lists are trouble. They are problematic from the implementation point of view. (Check out the source code of a DOM implementation.) Moreover, they don’t work intuitively for the API user.
I think XOM-style comatose lists make the most sense from the API user point of view. (The list itself is not live but it holds references to the live nodes—not copies of the nodes.)
BTW Anne, the autocomplete of Opera 9 allowed me to pick a value for the email field that was later rejected. I chose ‘"Henri Sivonen" <hsivonen@iki.fi>’ from the dropdown. It showed up as ‘"Henri Sivonen"’ and was rejected when I clicked Preview.
Laurens, you're right. I didn't mean to write "Element instead of Document" but Element along with Document, just like getElementsByTagName indeed.
I agree that the names match
and matchAll
doesn't quite fit. select
and selectSingleNode
or rather getElementsBySelector
and getElementBySelector
are much better. Other than that, this looks good.
Having thought about it. I agree with Salar. This should be extended to elements as well.
But I'm just glad that you didn't call it "$". ;-)
I want to point you at Simon Willison's getElementsBySelector() function, which is also used in Ben Nolan's Behaviour. Although not a full implementation of the CSS3 selectors, it is extremely useful. In Willison's words:
It has been pointed out that the function does not have the capability to deal with chained selectors such as div#main.layoutDiv. I have no intention of supporting this kind of advanced CSS syntax - one of my principle design aims is to keep the code short and simple, and implementing a full parser would add a lot of bulk and complexity without significantly improving the utility of the function.