W3C home > Mailing lists > Public > public-webapps@w3.org > October to December 2011

Re: QSA, the problem with ":scope", and naming

From: Yehuda Katz <wycats@gmail.com>
Date: Tue, 25 Oct 2011 10:43:12 -0700
Message-ID: <CAMFeDTXABJ9EA7D49uUvxrwNcPQUAQARaOpoVZGBWC2EZeV7uA@mail.gmail.com>
To: Jonas Sicking <jonas@sicking.cc>
Cc: Lachlan Hunt <lachlan.hunt@lachy.id.au>, "Tab Atkins Jr." <jackalmage@gmail.com>, Boris Zbarsky <bzbarsky@mit.edu>, Ojan Vafai <ojan@chromium.org>, Alex Russell <slightlyoff@google.com>, Webapps WG <public-webapps@w3.org>, John Resig <jeresig@gmail.com>, Paul Irish <paulirish@google.com>
Your guesses are all right in terms of existing jQuery but one:

'div': [1, 2, 3, 4]
'': []
'#3': [3]
'> div': [1, 2, 3]
'[foo=bar]': []
'[id=1]': [1]
':first-child': [1, 4]
'+ div': [5]
'~ div': [5, 6]

You can see the results live at http://jsfiddle.net/Dj3Ab/.

The basic rule is that if there is no combinator, a descendent combinator is
implied.

jQuery returns an empty list with an empty String, but querySelectorAll
throws an exception (the spec says that the selector SHOULD match a slightly
loosened version of the selector production in
http://www.w3.org/TR/2009/PR-css3-selectors-20091215/#w3cselgrammar, which
disallows the empty string). It probably makes sense for find or findAll to
raise an exception too, but an empty list is fine too.

I'm not as sure about the :scope cases. I can make some guesses:

e.findAll(":scope") // context
e.findAll("div:scope") // context
e.findAll("[foo=bar]:scope") // context
e.findAll(":scope div") // 1,2,3,4
e.findAll("div:scope div") // 1,2,3,4
e.findAll("div:scope #3") // 3
e.findAll("body > :scope > div") // 1,2,3
e.findAll("div, :scope") // 0,context,1,2,3,4,5,6
e.findAll("body > :scope > div, :scope") // context,1,2,3
e.findAll(":not(:scope)") // all elements except context

In cases where :scope is used, I would say that the selector behaves
identically to the "id hack" used by most JavaScript libraries. In
particular, the selector is relative to the root element, and the :scope
element simply represents the context element.

So you could change the :scope rules to be:

e.findAll("#context") // context
e.findAll("div#context") // context
e.findAll("[foo=bar]#context") // context
e.findAll("#context div") // 1,2,3,4
e.findAll("div#context div") // 1,2,3,4
e.findAll("div#context #3") // 3
e.findAll("body > #context > div") // 1,2,3
e.findAll("div, #context") // 0,context,1,2,3,4,5,6
e.findAll("body > #context > div, #context") // context,1,2,3
e.findAll(":not(#context)") // all elements except context

This also means that the above (non-:scope) rule could (I think) be restated
as:

   - Each selector in a selector group passed to find or findAll has an
   implied leading :scope
   - If no initial combinator is supplied, a descendent combinator is
   implied

Yehuda Katz
(ph) 718.877.1325


On Fri, Oct 21, 2011 at 12:41 AM, Jonas Sicking <jonas@sicking.cc> wrote:

> On Thu, Oct 20, 2011 at 2:33 PM, Lachlan Hunt <lachlan.hunt@lachy.id.au>
> wrote:
> > Not necessarily.  It depends what exactly it means for a selector to
> contain
> > :scope for determining whether or not to enable the implied :scope
> > behaviour.  Consider:
> >
> >  foo.find(":not(:scope)");
>
> Ooh, this is an interesting case too. So here's the full list of cases
> which we need defined behavior for (again looking at Alex and Yehuda here).
>
> In the following DOM
>
> <body id="3">
>  <div id=0></div>
>  <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>
>  <div id=5></div>
>  <div id=6></div>
> </body>
>
> What would each of the following .findAll calls return. I've included my
> guessed based on the discussions so far:
>
> var e = document.getElementById('context');
>
> e.findAll("div")  // returns ids 1,2,3,4
> e.findAll("")      // returns an empty list
> e.findAll("#3")  // returns id 3, but not the body node
> e.findAll("> div") // returns ids 1,2,3
> e.findAll("[foo=bar]") // returns nothing
> e.findAll("[id=1]") // returns id 1
> e.findAll(":first-child") // returns id 1
> e.findAll("+ div") // returns id 5
> e.findAll("~ div") // returns id 5, 6
> e.findAll(":scope")
> e.findAll("div:scope")
> e.findAll("[foo=bar]:scope")
> e.findAll(":scope div")
> e.findAll("div:scope div")
> e.findAll("div:scope #3")
> e.findAll("body > :scope > div")
> e.findAll("div, :scope")
> e.findAll("body > :scope > div, :scope")
> e.findAll(":not(:scope)")
>
> / Jonas
Received on Tuesday, 25 October 2011 17:43:59 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 18:49:48 GMT