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

On 26/10/11 4:43 AM, Yehuda Katz wrote:
> 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.
>

I think allowing explicit :scope in findAll() will be perpetually 
confusing. I can imagine someone looking at old code like:

     e.findAll("div.foo span, div.bar :scope span")

and asking themselves "what's the rule again? If there's :scope in the 
selector then there's no :scope implied? Or was that just on each single 
selector? Or is :scope always implied at the start of the whole selector 
list and that's why it's explicit in the second part? Dammit, why didn't 
we just use querySelectorAll() if we wanted explicit :scope?"

> 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 <mailto: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 20:48:02 UTC