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

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 UTC