Re: Behavior of matches() and closest() with :scope()

Sean Hogan <[email protected]>
Newsgroups gmane.comp.web.dom.general,gmane.comp.web.css.general
Message-ID <[email protected]>
On 4/09/14 7:54 PM, Anne van Kesteren wrote:
> On Tue, Sep 2, 2014 at 6:53 PM, Boris Zbarsky <[email protected]> wrote:
>> ...
> So let's see. If we don't pass a :scope elements argument we get
>
>    E.matches(":scope") -> false
>    E.closest(":scope") -> null
>    E.closest(":has(> :scope)" -> null
>
> If we pass E as :scope elements we get
>
>    E.matches(":scope") -> true
>    E.closest(":scope") -> E
>    E.closest(":has(> :scope)" -> E's parent
>
> Now for closest() we could also pass the current ancestor A as :scope
> elements, then we get
>
>    E.closest(":scope") -> E
>    E.closest(":has(> :scope)" -> null
>
> It seems to me that passing the element on which the method is invoked
> as :scope elements (i.e. E) makes the most sense. That argues for 1).
>
>

It doesn't sound like you are considering the explicit passing of a 
scope element yet, but for when you do, here is a use-case for 
element.closest(scopedSelector, ancestor).

Say I want to use event delegation by registering an event listener on 
ancestor (A) to respond to events that would have bubbled through some 
descendant (D) which matches a selector scoped to A, say ":scope > 
li.enabled > a[href]".

Now say D (in this case <a href="...">) has a child <span> element (E) 
on which a click occurs.

When the click event propagates to the listener on A, it has a target of 
E and a currentTarget of A.
I want to find if it bubbled through some descendant D. Ideally I could 
call:
     D = E.closest(':scope > li.enabled > a[href]', A);
or even with a relative selector
     D = E.closest('> li.enabled > a[href]', A);

The explicit or implicit ':scope' would refer to A.

For this use-case, the upwards DOM traversal for matching would also 
terminate on reaching **the- scope-boundary**, A. This seems intuitive 
to me, and implies that
     E.closest(scopedSelector) // no explicit scope element
is the equivalent of
     E.closest(scopedSelector, document-or-fragment-or-root)

Or maybe it implies that the ':scope' selector is a nonsense for 
.matches() and .closest() when there is no explicit scope element.

I can't recall for sure, but I thought the original discussion of 
matches() did conclude that if there was an explicit scope element
     E.matches(selector, A)
then selector was a scoped-selector - loosely the inverse of 
A.query(selector) - and otherwise
     E.matches(selector)
the selector was unscoped - and loosely the inverse of 
A.querySelector(selector)

I would expect:
     E = A.query('> ul > li'); // assuming E exists ...
     E.matches('> ul > li', A) // true

And I would expect:
     E = A.querySelector('ul > li'); // assuming E (a descendant of A) 
exists ...
     E.matches('ul > li') // true

I might even expect:
     E = A.query(':scope ul > li'); // assuming E exists ...
     E.matches(':scope ul > li') // true - equivalent of 
E.matches(':scope ul > li', document)

But I wouldn't expect:
     E = A.query(':scope ul > li'); // assuming E exists ...
     E.matches(':scope ul > li') // false - equivalent of 
E.matches(':scope ul > li', E)

Sean
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.