- From: Sean Hogan <shogun70@westnet.com.au>
- Date: Thu, 18 Sep 2014 13:46:36 +1000
- To: Anne van Kesteren <annevk@annevk.nl>
- CC: Boris Zbarsky <bzbarsky@mit.edu>, "Tab Atkins Jr." <jackalmage@gmail.com>, "www-style@w3.org" <www-style@w3.org>, "www-dom@w3.org" <www-dom@w3.org>, David Håsäther <hasather@gmail.com>
On 4/09/14 7:54 PM, Anne van Kesteren wrote:
> On Tue, Sep 2, 2014 at 6:53 PM, Boris Zbarsky <bzbarsky@mit.edu> 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
Received on Thursday, 18 September 2014 03:47:19 UTC