Re: [selectors-api] Consider backporting find() behavior to querySelector()

On 2012-06-20 17:46, Marat Tanalin | tanalin.com wrote:
> 20.06.2012, 18:14, "Lachlan Hunt" <lachlan.hunt@lachy.id.au>:
>> 4. Support for returning elements that are not descendants of the
>>      context object.
>>
>> This feature allows a selector to be constructed such that it matches an
>> element anywhere in the tree relative to the context element. This
>> feature is not relevant to document.find(), since it can already return
>> anything from the whole tree.
>>
>>     elm.find("+span")        // span is a sibling
>>     elm.find("/for/ input")  // input could be anywhere
>>     elm.find(":not(:scope)") // Everything except the context object
>>
>> This feature cannot be supported on Element.qSA, even when using eplicit
>> :scope, because matching elements need to be descendants of the context
>> object.
>
> It's unclear why an _updated_ qSA version should have same limitation
> that "matching elements need to be descendants of the context
> object". There is nothing obvious that makes h1.querySelector('+ H2')
> impossible to work in newer implementations (in older ones it would
> not work anyway -- to the same extent as `elm.querySelector(">span")`
> that you've declared as "could work").

Supporting this without the risk of breaking compatibility would require 
switching selection behaviour based on the presence of the :scope pseudo 
class (either explicit or implied), for each individual selector in the 
group.  When :scope is present, then matching could be applied to the 
entire tree, just like it is in element.find().

That is, given the group of selectors:

   elm.querySelectorAll(":scope+p, div p")

(Note: After pre-processing, there is no difference between explicit 
:scope and implied :scope in "+p")

Only ":scope+p" would be permitted to match non-descendant elements and 
the other "div p" would have to retain the backwards compatible 
selection behaviour where the subject of the selector must be a 
descendant of the context object.

That means, the implementation would need to split the group of 
selectors such that ":scope+p" (or any other selector with explicit or 
implied :scope) is potentially compared with all elements in the tree. 
Then the other selector "div p" should only be compared with descendants 
of the context object.

It will also not work for the reference combinator in some cases.  If 
switching selection behaviour depends on the presence of :scope, then 
the reference combinator will not always work effectively.

   elm.querySelectorAll("label /for/ input")

In this case with no :scope, the matching input must be a descendant of 
the context object, but the label may or may not be.  Compare that with 
this:

   elm.findAll("label /for/ input")

In this case, :scope is implied at the beginning, so the label must be a 
descendant of the context object, but the matching input elements may 
appear anywhere in the tree.

Overall, this adds significant complexity to the implementations, so 
while it may actually be technically possible in some cases, it's far 
from ideal and doesn't address all problems.

-- 
Lachlan Hunt - Opera Software
http://lachy.id.au/
http://www.opera.com/

Received on Thursday, 21 June 2012 13:51:31 UTC