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 <[email protected]> wrote:
On Thu, Oct 20, 2011 at 2:33 PM, Lachlan Hunt
<[email protected] <mailto:[email protected]>> 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