Re: [selectors-api] Scoped Selectors

Sean Hogan wrote:
> Here's a proposal.
>
> querySelector*(selector, context) // allows selectors with :scope
> pseudo-class
> queryScopedSelector*(selector, context) // allows selectors with implied
> :scope
> matchesSelector(selector, context) // allows selectors with :scope
> pseudo-class

Yes, this is effectively the same as option #2 that I described, except 
you haven't provided a way to support implied scope there.

> To check if the :scope pseudo-class is available, use:
>
> try { document.body.matchesSelector(":scope", document.body); }
> catch (error) { /* not supported */ }

I'm not sure that relying on exceptions for feature testing is an ideal 
way to provide that functionality.

> Now, querySelector*() can't accept selectors with implied :scope because
> while "> em" is unambiguously ":scope > em", "p em" would become
> ambiguous. (is it "p em" or ":scope p em")
> So we need a new method, such as queryScopedSelector*().

Well, we at least need some way to tell the implementation to 
pre-process the selector to imply the presence of :scope. 
queryScopedSelector*() would do this, as would providing an explicit 
pre-processing step, the result of which can be passed to the 
querySelector*() methods.

> element.querySelector*() limits selection to descendants of elements,
> and element.queryScopedSelector*() should be consistent.
> If element is the scope then element.queryScopedSelector*("~p") will
> return no elements.
> If we want to support sibling queries then we need to provide a scope
> explicitly, so:
>
> element.parentNode.queryScopedSelector*("~p", element);
>
> Notes:
> 1. I don't think browsers should provide queryScopedSelector*()

This seems contradictory.  You seemed to be proposing that we use 
queryScopedSelector, and now you're saying we shouldn't.  Personally, I 
agree that we shouldn't.  It's my least favourite solution of them all.

> 2. I think :context is a better name than :scope

Yeah, the name of :scope is a complicated issue. :context isn't ideal 
either.  It would be slightly confusing because selectors API defines 
the term "context node" as being the node upon which the method is being 
invoked.  Maybe something like :ref or :reference might work.

> 3. If the context argument of these methods could be an element or a
> NodeList it might satisfy some of the other feature requests.

Yes, the reference elements parameter will accept either a single 
element, Array or NodeList.

I have checked in a new draft containing my first attempt at supporting 
scoped selectors, with support for both :scope (or whatever it gets 
called) and implied scope selectors.  I've opted for a combination of 
options 1 and 2 that I previously described, using the createSelector() 
and SelectorExpression object for being able to represent implied scoped 
selectors easily, and optional refNodes parameters on querySelector*() 
and matchesSelector() methods for supplying contextual reference 
elements (that match :scope).

Basically, for the simple case, it works as illustrated in these examples:

elm.querySelector(":scope>p");
document.querySelectorAll(":scope>p", elm);
document.querySelectorAll(":scope>p", [elm1, elm2]);

To provide the functionality of JS libraries supporting implied scope 
selectors, you first create a SelectorExpression object like this:

document.createSelector(">em,>strong", true);

That object can then be passed to either the querySelector*() or 
matchesSelector() methods.

The effect of this is basically that JavaScript libraries can mostly use 
document.createSelector(str, true) as a direct replacement their own 
custom selector parsing libraries (except for the cases where they're 
using custom pseudo-classes not supported by the browser)

One possible modification I'm considering is introducing a separate 
factory method for creating implied scope selectors: 
createScopedSelector(selector); rather than using a boolean parameter.

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

Received on Friday, 25 September 2009 14:00:16 UTC