Skip to content

Add the interesttarget attribute #11006

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 223 additions & 3 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -21795,6 +21795,7 @@ interface <dfn interface>HTMLDivElement</dfn> : <span>HTMLElement</span> {
<dd><code data-x="attr-hyperlink-hreflang">hreflang</code></dd>
<dd><code data-x="attr-hyperlink-type">type</code></dd>
<dd><code data-x="attr-hyperlink-referrerpolicy">referrerpolicy</code></dd>
<dd><code data-x="attr-interesttarget">interesttarget</code></dd>
<dt><span
data-x="concept-element-accessibility-considerations">Accessibility considerations</span>:</dt>
<dd>If the element has an <code data-x="attr-hyperlink-href">href</code> attribute: <a
Expand Down Expand Up @@ -21823,7 +21824,8 @@ interface <dfn interface>HTMLAnchorElement</dfn> : <span>HTMLElement</span> {

// <a href="#HTMLAnchorElement-partial">also has obsolete members</a>
};
<span>HTMLAnchorElement</span> includes <span>HTMLHyperlinkElementUtils</span>;</code></pre>
<span>HTMLAnchorElement</span> includes <span>HTMLHyperlinkElementUtils</span>;
<span>HTMLAnchorElement</span> includes <span>InterestInvokerElement</span>;</code></pre>
</dd>
<dd w-dev>Uses <code>HTMLAnchorElement</code>.</dd>
</dl>
Expand Down Expand Up @@ -42070,6 +42072,7 @@ interface <dfn interface>HTMLMapElement</dfn> : <span>HTMLElement</span> {
<dd><code data-x="attr-hyperlink-ping">ping</code></dd>
<dd><code data-x="attr-hyperlink-rel">rel</code></dd>
<dd><code data-x="attr-hyperlink-referrerpolicy">referrerpolicy</code></dd>
<dd><code data-x="attr-interesttarget">interesttarget</code></dd>
<dt><span
data-x="concept-element-accessibility-considerations">Accessibility considerations</span>:</dt>
<dd>If the element has an <code data-x="attr-hyperlink-href">href</code> attribute: <a
Expand All @@ -42096,7 +42099,8 @@ interface <dfn interface>HTMLAreaElement</dfn> : <span>HTMLElement</span> {

// <a href="#HTMLAreaElement-partial">also has obsolete members</a>
};
<span>HTMLAreaElement</span> includes <span>HTMLHyperlinkElementUtils</span>;</code></pre>
<span>HTMLAreaElement</span> includes <span>HTMLHyperlinkElementUtils</span>;
<span>HTMLAreaElement</span> includes <span>InterestInvokerElement</span>;</code></pre>
</dd>
<dd w-dev>Uses <code>HTMLAreaElement</code>.</dd>
</dl>
Expand Down Expand Up @@ -53518,6 +53522,7 @@ You cannot submit this form when the field is incorrect.</samp></pre>
<dd><code data-x="attr-fe-name">name</code></dd>
<dd><code data-x="attr-popovertarget">popovertarget</code></dd>
<dd><code data-x="attr-popovertargetaction">popovertargetaction</code></dd>
<dd><code data-x="attr-interesttarget">interesttarget</code></dd>
<dd><code data-x="attr-button-type">type</code></dd>
<dd><code data-x="attr-button-value">value</code></dd>
<dt><span
Expand Down Expand Up @@ -53552,7 +53557,8 @@ interface <dfn interface>HTMLButtonElement</dfn> : <span>HTMLElement</span> {

readonly attribute <span>NodeList</span> <span data-x="dom-lfe-labels">labels</span>;
};
<span>HTMLButtonElement</span> includes <span>PopoverInvokerElement</span>;</code></pre>
<span>HTMLButtonElement</span> includes <span>PopoverInvokerElement</span>;
<span>HTMLButtonElement</span> includes <span>InterestInvokerElement</span>;</code></pre>
</dd>
<dd w-dev>Uses <code>HTMLButtonElement</code>.</dd>
</dl>
Expand Down Expand Up @@ -75852,6 +75858,21 @@ contradict people?
data-x="concept-selector-active">being activated</i>.)</p>
</dd>

<dt><dfn selector noexport><code data-x="selector-has-interest">:has-interest</code></dfn></dt>
<dd>
<p>The <code data-x="selector-has-interest">:has-interest</code> <span>pseudo-class</span> is
defined to match any <span data-x="html elements">HTML element</span> whose <span>interest
state</span> is <span data-x="interest-state-full">full</span>.</p>
</dd>

<dt><dfn selector noexport><code data-x="selector-has-partial-interest">:has-partial-interest</code></dfn></dt>
<dd>
<p>The <code data-x="selector-has-partial-interest">:has-partial-interest</code>
<span>pseudo-class</span> is defined to match any <span data-x="html elements">HTML
element</span> whose <span>interest state</span> is
<span data-x="interest-state-partial">partial</span>.</p>
</dd>

<dt><dfn selector noexport><code data-x="selector-hover">:hover</code></dfn></dt>
<dd>
<p>The <code data-x="selector-hover">:hover</code> <span>pseudo-class</span> is defined to
Expand Down Expand Up @@ -75929,6 +75950,26 @@ Demos:
containing no elements, if it is. <ref>SELECTORS</ref></p>
</dd>

<dt><dfn selector noexport><code data-x="selector-target-of-interest">:target-of-interest</code></dfn></dt>
<dd>
<p>The <code data-x="selector-target-of-interest">:target-of-interest</code>
<span>pseudo-class</span> is defined to match any element that is the result of running
<span data-x="get the attr-associated element">get the
<code data-x="">interesttarget</code>-associated element</span> for any
<span data-x="html elements">HTML element</span> whose <span>interest state</span> is
<span data-x="interest-state-full">full</span>.</p>
</dd>

<dt><dfn selector noexport><code data-x="selector-target-of-partial-interest">:target-of-partial-interest</code></dfn></dt>
<dd>
<p>The <code data-x="selector-target-of-partial-interest">:target-of-partial-interest</code>
<span>pseudo-class</span> is defined to match any element that is the result of running
<span data-x="get the attr-associated element">get the
<code data-x="">interesttarget</code>-associated element</span> for any
<span data-x="html elements">HTML element</span> whose <span>interest state</span> is
<span data-x="interest-state-partial">partial</span>.</p>
</dd>

<dt><dfn selector noexport><code data-x="selector-popover-open">:popover-open</code></dfn></dt>
<dd>
<p>The <code data-x="selector-popover-open">:popover-open</code> <span>pseudo-class</span> is
Expand Down Expand Up @@ -88115,6 +88156,166 @@ dictionary <dfn dictionary>DragEventInit</dfn> : <span>MouseEventInit</span> {
</ol>


<h3 split-filename="interesttarget">Interest invokers</h3>

<h4>The <code data-x="attr-interesttarget">interesttarget</code> attribute</h4>

<p>The <dfn element-attr for="html-global"><code data-x="attr-interesttarget">interesttarget</code></dfn>
attribute on <code>a</code>, <code>area</code>, and <code>button</code> elements allows authors to
set up an invoker relationship between the triggering element and a separate target element such
as a popover. With this arrangement, when the user shows interest in the triggering element (e.g.,
by hovering or focusing it), the target element will have an
<code data-x="event-interest">interest</code> event fired on it. If the target is a popover, this
will show the popover.</p>

<p>If specified, the <code data-x="attr-interesttarget">interesttarget</code> attribute value
must be the <span data-x="concept-ID">ID</span> of an element in the same <span>tree</span> as the
element with the <code data-x="attr-interesttarget">interesttarget</code> attribute.</p>

<span data-x="concept-element-dom">DOM interface</span>:
<pre><code class="idl">interface mixin <dfn interface>InterestInvokerElement</dfn> {
[<span>CEReactions</span>] attribute Element? <span data-x="dom-interestTargetElement">interestTargetElement</span>;
};</code></pre>

<p>The <dfn attribute for="HTMLElement"><code
data-x="dom-interestTargetElement">interestTargetElement</code></dfn> IDL attribute must
<span>reflect</span> the <code data-x="attr-interesttarget">interesttarget</code> attribute.</p>

<div class="example">
<p>The following demonstrates how one might show a tooltip for a button using the
<code data-x="attr-interesttarget">interesttarget</code> attribute to associate the button with
a <code data-x="attr-popover">popover</code> representing the tooltip.</p>

<pre><code class="html">&lt;button interesttarget=tooltip>
Click me
&lt;/button>

&lt;div popover=hint id=tooltip>
I will appear when the user shows interest in the button
&lt;/div></code></pre>
</div>

<p>Every <span data-x="HTML elements">HTML element</span> has an <dfn>interest state</dfn>, initially
<span data-x="interest-state-none">none</span>, with these potential values:</p>

<ul>
<li><p><dfn export for="interest state" data-x="interest-state-none">none</dfn></p></li>

<li><p><dfn export for="interest state" data-x="interest-state-partial">partial</dfn></p></li>
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mfreed7 Chromium additionally has a "potential partial interest" state used for popovers:

https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/dom/element.cc;l=11060-11067;drc=743a82d08e59d803c94ee1b8564b8b11dd7b462f

Do we have to do the same in the spec? Or can we check if the target element is a popover when the scheduled task runs? The popover attribute could be removed before the task runs, so checking it ahead of time seems like it adds the need to double-check it later.


<li><p><dfn export for="interest state" data-x="interest-state-full">full</dfn></p></li>
</ul>


<h4>The <code>InterestEvent</code> interface</h4>

<pre><code class="idl">[Exposed=Window]
interface <dfn interface>InterestEvent</dfn> : <span>Event</span> {
constructor(DOMString type, <span>InterestEventInit</span> eventInitDict);
readonly attribute Element source;
};

dictionary <dfn dictionary>InterestEventInit</dfn> : <span>EventInit</span> {
required Element source;
};</code></pre>

<dl class="domintro">
<dt><code data-x=""><var>event</var>.<span subdfn
data-x="dom-InterestEvent-source">source</span></code></dt>

<dd>
<p>Set to an interesting element TODO.</p>
</dd>
</dl>

<p>The <dfn attribute for="InterestEvent"><code
data-x="dom-InterestEvent-source">source</code></dfn> attribute must return the value it was
initialized to.</p>

<h4 id="interest-target-processing-model">Processing model</h4>

<p>To <dfn export data-x="capture-interest">capture interest</dfn>, given an <span
data-x="HTML elements">HTML element</span> <var>invoker</var>:</p>

<ol>
<li><p>Assert: <var>invoker</var> is an <code>a</code>, <code>area</code>, or <code>button</code>
element.</p></li>

<li><p>Assert: <var>invoker</var> has the <code data-x="attr-interesttarget">interesttarget</code>
attribute specified.</p></li>

<li><p>Let <var>target</var> be the result of running <var>node</var>'s <span data-x="get
the attr-associated element">get the <code data-x="">interesttarget</code>-associated
element</span>.</p></li>

<li><p>If <var>target</var> is null, then return.</p></li>

<li><p>Let <var>continue</var> be the result of <span data-x="concept-event-fire">firing an
event</span> named <code data-x="event-interest">interest</code> at <var>target</var>, using
<code>InterestEvent</code>, with the <code data-x="dom-Event-cancelable">cancelable</code>
attribute initialized to true, and the <code data-x="dom-InterestEvent-source">source</code>
attribute initialized to <var>invoker</var>.</p></li>

<li><p>If <var>continue</var> is false, then return.</p></li>

<li><p>Set <var>invoker</var>'s <span>interest state</span> to
<span data-x="interest-state-full">full</span>.</p></li>

<!-- TODO: test that :has-interest doesn't match when the interest event is fired, but does
match when the popover toggle event fired. -->

<li><p>If <var>target</var>'s <code data-x="attr-popover">popover</code> attribute is not in the
<span data-x="attr-popover-none-state">no popover state</span>, then run <span>show popover</span>
given <var>target</var>, false, and <var>invoker</var>.</p></li>
</ol>

<p>To <dfn export data-x="lose-interest">lose interest</dfn>, given an <span
data-x="HTML elements">HTML element</span> <var>invoker</var>:</p>

<ol>
<li><p>Assert: <var>invoker</var> is an <code>a</code>, <code>area</code>, or <code>button</code>
element.</p></li>

<li><p>Note: <var>invoker</var> may no longer have the <code
data-x="attr-interesttarget">interesttarget</code> attribute specified.</p></li>

<li><p>Let <var>target</var> be the result of running <var>node</var>'s <span data-x="get
the attr-associated element">get the <code data-x="">interesttarget</code>-associated
element</span>.</p></li>

<li><p>If <var>target</var> is null, then return.</p></li>

<!-- TODO: what state is possibly left dangling if the target wasn't found? -->

<li><p>Let <var>continue</var> be the result of <span data-x="concept-event-fire">firing an
event</span> named <code data-x="event-interest">loseinterest</code> at <var>target</var>, using
<code>InterestEvent</code>, with the <code data-x="dom-Event-cancelable">cancelable</code> and
<code data-x="dom-Event-composed">composed</code> attributes initialized to true, and the
<code data-x="dom-InterestEvent-source">source</code> attribute initialized to
<var>invoker</var>.</p></li>

<li><p>If <var>continue</var> is false, then return.</p></li>

<li><p>Set <var>invoker</var>'s <span>interest state</span> to
<span data-x="interest-state-none">none</span>.</p></li>

<li><p>If <var>target</var>'s <code data-x="attr-popover">popover</code> attribute is not in the
<span data-x="attr-popover-none-state">no popover state</span>, then <span
data-x="hide popover algorithm">hide popover</span> given <var>invoker</var>, false, true, and
false.</p></li>
</ol>

<p>TODO / questions:</p>

<ul>
<li><p>Actually invoke the capture/lose algorithms.</p></li>
<li><p>Which algorithm reads the computed style for interest-target-delay?</p></li>
<li><p>Handle removal of the interesttarget attribute, or the element that has it.</p></li>
<li><p>Handle changes of the interesttarget attribute while an element has interest.</p></li>
<li><p>Handle changes to the ID attribute referenced by an interesttarget attribute.</p></li>
</ul>


<h2 split-filename="browsers" id="browsers">Loading web pages</h2>

<div w-nodev>
Expand Down Expand Up @@ -144434,6 +144635,13 @@ interface <dfn interface>External</dfn> {
<code data-x="attr-script-integrity">script</code>
<td> Integrity metadata used in <cite>Subresource Integrity</cite> checks <ref>SRI</ref>
<td> <a href="#attribute-text">Text</a>
<tr>
<th> <code data-x="">interesttarget</code>
<td> <code data-x="attr-interesttarget">a</code>;
<code data-x="attr-interesttarget">area</code>;
<code data-x="attr-interesttarget">button</code>
<td> Targets an interesting TODO
<td> <span data-x="concept-id">ID</span>* <!-- TODO: is the asterisk needed, is it really complicated? -->
<tr>
<th> <code data-x="">is</code>
<td> <span data-x="attr-is">HTML elements</span>
Expand Down Expand Up @@ -146236,6 +146444,12 @@ INSERT INTERFACES HERE
<td> Elements
<td> Fired when the user changes the <code data-x="attr-contenteditable">contenteditable</code> element's content, or the form control's value. See also the <code data-x="event-change">change</code> event for form controls.

<tr> <!-- interest -->
<td> <dfn event for="HTMLElement"><code data-x="event-interest">interest</code></dfn>
<td> <code>InterestEvent</code>
<td> Elements
<td> Fired on interesting elements because of code <code data-x="attr-interesttarget">interesttarget</code> TODO.

<tr> <!-- invalid -->
<td> <dfn event for="HTMLElement"><code data-x="event-invalid">invalid</code></dfn>
<td> <code>Event</code>
Expand All @@ -146254,6 +146468,12 @@ INSERT INTERFACES HERE
<td> <code>Window</code>, elements
<td> Fired at the <code>Window</code> when the document has finished loading; fired at an element containing a resource (e.g. <code>img</code>, <code>embed</code>) when its resource has finished loading

<tr> <!-- loseinterest -->
<td> <dfn event for="HTMLElement"><code data-x="event-loseinterest">loseinterest</code></dfn>
<td> <code>InterestEvent</code>
<td> Elements
<td> Fired on boring elements because of code <code data-x="attr-interesttarget">interesttarget</code> TODO.

<tr> <!-- message -->
<td> <dfn event for="Window,EventSource,MessagePort,BroadcastChannel,DedicatedWorkerGlobalScope,Worker,ServiceWorkerContainer"><code data-x="event-message">message</code></dfn>
<td> <code>MessageEvent</code>
Expand Down