- From: Ojan Vafai <ojan@chromium.org>
- Date: Wed, 19 Oct 2011 19:22:23 -0700
- To: Jonas Sicking <jonas@sicking.cc>
- Cc: Alex Russell <slightlyoff@google.com>, Webapps WG <public-webapps@w3.org>, Yehuda Katz <wycats@gmail.com>, John Resig <jeresig@gmail.com>, Paul Irish <paulirish@google.com>, Lachlan Hunt <lachlan.hunt@lachy.id.au>
- Message-ID: <CANMdWTu3TerRJqmz3i-hpkta6YsLFggN3mBM0tEq730XPXt1cg@mail.gmail.com>
On Wed, Oct 19, 2011 at 7:07 PM, Jonas Sicking <jonas@sicking.cc> wrote: > On Tue, Oct 18, 2011 at 9:42 AM, Alex Russell <slightlyoff@google.com> > wrote: > > Lachlan and I have been having an...um...*spirited* twitter discussion > > regarding querySelectorAll, the (deceased?) queryScopedSelectorAll, > > and ":scope". He asked me to continue here, so I'll try to keep it > > short: > > > > The rooted forms of "querySelector" and "querySelectorAll" are > mis-designed. > > > > Discussions about a Scoped variant or ":scope" pseudo tacitly > > acknowledge this, and the JS libraries are proof in their own right: > > no major JS library exposes the QSA semantic, instead choosing to > > implement a rooted search. > > > > Related and equally important, that querySelector and querySelectorAll > > are often referred to by the abbreviation "QSA" suggests that its name > > is bloated and improved versions should have shorter names. APIs gain > > use both through naming and through use. On today's internet -- the > > one where 50% of all websites include jQuery -- you could even go with > > element.$("selector") and everyone would know what you mean: it's > > clearly a search rooted at the element on the left-hand side of the > > dot. > > > > Ceteris peribus, shorter is better. When there's a tie that needs to > > be broken, the more frequently used the API, the shorter the name it > > deserves -- i.e., the larger the component of its meaning it will gain > > through use and repetition and not naming and documentation. > > > > I know some on this list might disagree, but all of the above is > > incredibly non-controversial today. Even if there may have been > > debates about scoping or naming when QSA was originally designed, > > history has settled them. And QSA lost on both counts. > > > > I therefore believe that this group's current design for scoped > > selection could be improved significantly. If I understand the latest > > draft (http://www.w3.org/TR/selectors-api2/#the-scope-pseudo-class) > > correctly, a scoped search for multiple elements would be written as: > > > > element.querySelectorAll(":scope > div > .thinger"); > > > > Both then name and the need to specify ":scope" are punitive to > > readers and writers of this code. The selector is *obviously* > > happening in relationship to "element" somehow. The only sane > > relationship (from a modern JS hacker's perspective) is that it's > > where our selector starts from. I'd like to instead propose that we > > shorten all of this up and kill both stones by introducing a new API > > pair, "find" and "findAll", that are rooted as JS devs expect. The > > above becomes: > > > > element.findAll("> div > .thinger"); > > > > Out come the knives! You can't start a selector with a combinator! > > > > Ah, but we don't need to care what CSS thinks of our DOM-only API. We > > can live and let live by building on ":scope" and specifying find* as > > syntactic sugar, defined as: > > > > HTMLDocument.prototype.find = > > HTMLElement.prototype.find = function(rootedSelector) { > > return this.querySelector(":scope " + rootedSelector); > > } > > > > HTMLDocument.prototype.findAll = > > HTMLElement.prototype.findAll = function(rootedSelector) { > > return this.querySelectorAll(":scope " + rootedSelector); > > } > > > > Of course, ":scope" in this case is just a special case of the ID > > rooting hack, but if we're going to have it, we can kill both birds > > with it. > > > > Obvious follow up questions: > > > > Q.) Why do we need this at all? Don't the toolkits already just do > > this internally? > > A.) Are you saying everyone, everywhere, all the time should need to > > use a toolkit to get sane behavior from the DOM? If so, what are we > > doing here, exactly? > > > > Q.) Shorter names? Those are for weaklings! > > A.) And humans. Who still constitute most of our developers. Won't > > someone please think of the humans? > > > > Q.) You're just duplicating things! > > A.) If you ignore all of the things that are different, then that's > > true. If not, well, then no. This is a change. And a good one for the > > reasons listed above. > > > > Thoughts? > > I like the general idea here. And since we're changing behavior, I > think it's a good opportunity to come up with shorter names. Naming is > really hard. The shorter names we use, the more likely it is that > we're going to break webpages which are messing around with the > prototype chain and it increases the risk that we'll regret it later > when we come up with even better functions which should use those > names. Say that we come up with an even better query language than > selectors, at that point .find will simply not be available to us. > > However, it does seem like selectors are here to stay. And as much as > they have shortcomings, people seem to really like them for querying. > > So with that out of the way, I agree that the CSS working group > shouldn't be what is holding us back. However we do need a precise > definition of what the new function does. Is prepending ":scope " and > then parsing as a normal selector always going to give the behavior we > want? This is actually what I think we got stuck on when the original > querySelector was designed. > > So let's get into specifics about how things should work. According to > your proposal of simply prepending a conceptual ":scope" to each > selector group, for the following DOM: > > <body id="3"> > <div id="context" foo=bar> > <div id=1></div> > <div class="class" id=2></div> > <div class="withChildren" id=3><div class=child id=4></div></div> > </div> > </body> > > you'd get the following behavior: > > .findAll("div") // returns ids 1,2,3,4 > .findAll("") // returns the context node itself. This was > indicated undesirable > .findAll("body > :scope > div") // returns nothing > Wouldn't this return ids 1,2,3 if we're not prepending :scope as you say below? > .findAll("#3") // returns id 3, but not the body node > .findAll("> div") // returns ids 1,2,3 > .findAll("[foo=bar]") // returns nothing > .findAll("[id=1]") // returns id 1 > .findAll(":first-child") // returns id 1 > > Is this desired behavior in all cases except the empty string? If so > this seems very doable to me. We can easily make an exception for the > case when the passed in string contains no selectors and make that an > error or some such. > > I do however like the idea that if :scope appears in the selector, > then this removes the prepending of ":scope " to that selector group. > Is there a reason not to do that? > > Additionally it seems to me that we could allow the same syntax for > <style scoped>. But maybe others disagree? > Sounds good to me. A sticky case you left out is parent, sibling and reference combinators. .findAll("+ div") Assuming the context node has siblings, should that return them? If so, should it match siblings when using <style scoped>. IMO, it shouldn't match anything in either case. We should assert that only descendants of the scope element will ever be returned. This would also make it naturally match <style scoped> where only descendants of the scope element are ever affected. I think appropriate optimizations as well as extensible functions > should be out-of-scope for this thread. They are both big subjects on > their own and we're approaching 50 emails in this thread. > > / Jonas > >
Received on Thursday, 20 October 2011 02:23:08 UTC