~robcee/ more than just sandwiches

Posted
3 August 2012 @ 1pm

Tagged
Code, devtools, Firebug, Firefox, Mozilla

WebConsole’s $() convenience function: querySelector

tl;dr If you’re used to using $("id") in the WebConsole to lookup nodes with a given id, prepare to get used to doing it with $("#id").

There was a short discussion in the #firebug channel in IRC this week about the usefulness (or lack thereof) of the $() convenience function in the Console (Firebug’s, Firefox’ Web Console, Chrome’s Console, all of ‘em). They currently map to getElementById. Way back in ought-five, when Firebug was still a twinkle in Joe Hewitt’s eye, getElementById probably made more sense than it does today. These days, you don’t see a lot of nodes in a webpage carrying the ID attribute. There are probably some good reasons for this. Having a rich selector API in all browsers is certainly at the top of that list of reasons.

Paul Irish’s initial suggestion was to use querySelectorAll for $(). I felt this would be kind of annoying for users used to getting back a single node. We compromised on using the querySelector function for $() and leaving querySelectorAll on $$(). I think this gives them both a useful purpose and will provide the least breakage for users of $().

It’s a pretty innocuous fix and it’ll be in Firefox Nightly sometime this weekend. Some of the discussions this has spawned have been pretty interesting. It would be nice to have a better iterable interface on NodeLists for example (Array.forEach(list, function...) is way more annoying to type than just list.forEach(function...)). With a proxy object, we could combine the results of $() and return a NodeList in the case where there were non-unique matches and return a single element if there were an exact ID match (without having to prepend the octothorpe to the query).

Leave a comment with your own magical $() wishes or ideas.

You can see the initial discussion in bug 778732. Firebug’s issue 5764 and Webkit’s bug 92648.


6 Comments

Posted by
jonathan
3 August 2012 @ 2pm

I usually do for each (let [, y] in Iterator(…)) where … is the result of querySelectorAll. I assume the web console has the latest javascript features, so maybe you can apply a similar trick? Like return [y for each ([, y] in Iterator($(…))]? Or maybe the newest let of construct is smart enough to be able to iterate over an HTMLCollection?

(Trying to find something less fancy than resorting to ES6 Proxies.)


Posted by
robcee
3 August 2012 @ 5pm

yeah, that would work, but it’s still a lot wordier than just $$(“div”).forEach(…). :)


Posted by
Sean Hogan
3 August 2012 @ 7pm

IDs can have characters that need to be escaped if using querySelector. e.g.

document.getElementById(‘note:ID’)

has to be written as

document.querySelector(‘*[id="note:ID"]‘)

It would be nice to still have a short-cut for document.getElementById. How about $id().

Regarding iteration on node-lists…
I don’t think anyone needs the console’s $$ to blazingly fast, so why not copy the result into an array, something like:

function $$(sel) {
return [].slice.call(document.querySelectorAll(sel),0);
}


Posted by
tom jones
3 August 2012 @ 7pm

how about a backward-compatible $ function that would function like the old one if you provide a string that “looks like an id”, but without the ‘#’ prefix.

so $(‘something’) would be equivalent to $(‘#something’)

but $(‘div’) would still return all the DIVs and not an element with an id=’div’.

so essentially, special-casing simple css selectors that look like simple tag names (but that are *not* the name of a standard html element) to behave like the old $ function..


Posted by
squib
3 August 2012 @ 10pm

Simpler than for each (let [, y] in Iterator(…)) would be this (which works on NodeLists in Firefox 14):

for (y of …)


Posted by
robcee
4 August 2012 @ 2pm

Simpler than for each (let [, y] in Iterator(…)) would be this (which works on NodeLists in Firefox 14):

for (y of …)

we have a winner! *dingding* :)