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

On Tue, Oct 25, 2011 at 10:43 AM, Yehuda Katz <wycats@gmail.com> 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.
> 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

I'm no longer strongly convinced that we need to support :scope not at
the front of the selector.  el.find("foo :scope bar") is equivalent to
first doing el.matches("foo :scope"), then running el.find("bar") if
it does.

This is slightly inconvenient with individual elements, but in the
ideal future when .find returns a nice NodeList class that's a subtype
of Array, the NodeList can have its own .filter and .find functions on
it that automatically runs the operations over all the children and
unions the results into a new NodeList.

Then you can do elems.filter("foo :scope").find("bar"), and you're done.

~TJ

Received on Tuesday, 25 October 2011 20:42:02 UTC