File: interestfor-pseudo-classes.tentative.html

package info (click to toggle)
firefox 144.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 4,637,504 kB
  • sloc: cpp: 7,576,692; javascript: 6,430,831; ansic: 3,748,119; python: 1,398,978; xml: 628,810; asm: 438,679; java: 186,194; sh: 63,212; makefile: 19,159; objc: 13,086; perl: 12,986; yacc: 4,583; cs: 3,846; pascal: 3,448; lex: 1,720; ruby: 1,003; exp: 762; php: 436; lisp: 258; awk: 247; sql: 66; sed: 53; csh: 10
file content (165 lines) | stat: -rw-r--r-- 7,572 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
<!DOCTYPE html>
<meta charset="utf-8" />
<meta name="timeout" content="long">
<link rel="author" href="mailto:masonf@chromium.org">
<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-actions.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/invoker-utils.js"></script>
<script src="/html/semantics/popovers/resources/popover-utils.js"></script>

<div id=unrelated tabindex=0>Unrelated</div>
<button id=invoker interestfor=target>Invoker</button>
<div id=target popover>Target popover with all kinds of focusable things
  <button id=target_button>contained button</button>
  <button id=target_button_2>contained button 2</button>
  <a href=foo>Link</a>
  <dialog open>Dialog</dialog>
  <textarea></textarea>
  <input type=text>
  <input type=checkbox>
  <input type=radio>
  <input type=button>
  <input type=range>
  <map name="mymap">
    <area shape="circle" coords="75,75,75" href=foo>
  </map>
  <img usemap="#mymap" src="../../embedded-content/the-img-element/resources/green.png">
  <div tabindex=0>tabindex=0</div>
</div>
<button id=after>Button after</button>
<style>
  button {
    interest-delay: 0s;
  }
</style>
<script>
function checkPseudos(invoker,target,expectHasInterest,expectTargetHasInterest,msg) {
  msg = msg ?? 'Error';
  assert_equals(invoker.matches(':interest-source'),expectHasInterest,`${msg}: :interest-source mismatch`);
  assert_equals(target.matches(':interest-target'),expectTargetHasInterest,`${msg}: :interest-target mismatch`);
  assert_false(invoker.matches(':interest-target'),'invoker should never match :interest-target');
  assert_false(target.matches(':interest-source'),'target should never match :interest-source');
  assert_equals(target.matches(':popover-open'),expectTargetHasInterest,'Popover should be open if target has interest');
}
// Note that add_cleanup does not wait for async functions.
async function do_cleanup(t) {
  invoker.removeAttribute('style');
  await focusOn(unrelated);
  await hoverOver(unrelated);
  await sendLoseInterestHotkey();
  target.hidePopover();
  await waitForRender();
}

promise_test(async (t) => {
  let hasInterest = false;
  target.addEventListener('interest',() => (hasInterest=true));
  target.addEventListener('loseinterest',() => (hasInterest=false));
  checkPseudos(invoker,target,false,false,'initial');
  assert_false(hasInterest);
  await hoverOver(invoker);
  checkPseudos(invoker,target,true,true,'hovering invoker shows full interest');
  assert_true(hasInterest,'event was fired');
  await hoverOver(target);
  checkPseudos(invoker,target,true,true,'hovering the target maintains interest');
  assert_true(hasInterest,'loseinterest event was not yet fired');
  await hoverOver(unrelated);
  checkPseudos(invoker,target,false,false,'hovering unrelated loses interest');
  assert_false(hasInterest,'loseinterest event was fired');
  await do_cleanup();
},'Basic pseudo class function, with mouse hover triggering');

promise_test(async (t) => {
  let hasInterest = false;
  target.addEventListener('interest',() => (hasInterest=true));
  target.addEventListener('loseinterest',() => (hasInterest=false));
  checkPseudos(invoker,target,false,false,'initial');
  assert_false(hasInterest);
  await focusOn(invoker);
  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
  assert_true(hasInterest,'event was fired');
  await focusOn(invoker);
  checkPseudos(invoker,target,true,true,'focusing back on invoker keeps full interest');
  assert_true(hasInterest,'loseinterest event was not yet fired');
  await focusOn(unrelated);
  checkPseudos(invoker,target,false,false,'focusing unrelated loses interest');
  assert_false(hasInterest,'loseinterest event was fired');
  await do_cleanup();
},'Basic pseudo class function, with keyboard focus triggering');

promise_test(async (t) => {
  checkPseudos(invoker,target,false,false,'initial');
  await focusOn(invoker);
  checkPseudos(invoker,target,true,true,'invoker now has full interest');
  await sendTab();
  assert_equals(document.activeElement,target_button,'focus should now be able to move within the target');
  await sendTab();
  assert_equals(document.activeElement,target_button_2,'focus should be able to move within the target');
  await sendShiftTab();
  await sendShiftTab();
  assert_equals(document.activeElement,invoker,'focus should go back to invoker');
  checkPseudos(invoker,target,true,true,'focusing back on invoker keeps full interest');
  await focusOn(unrelated);
  checkPseudos(invoker,target,false,false,'focusing unrelated loses interest');
  await do_cleanup();
},'Contents of target popover are keyboard focusable');

promise_test(async (t) => {
  checkPseudos(invoker,target,false,false,'initial');
  await focusOn(invoker);
  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
  invoker.setAttribute('style',`interest-delay: 10000s`);
  await sendLoseInterestHotkey();
  checkPseudos(invoker,target,false,false,'Hot key loses interest immediately (no delays)');
  await do_cleanup();
},`Lose interest hotkey works`);

promise_test(async (t) => {
  checkPseudos(invoker,target,false,false,'initial');
  await focusOn(invoker);
  checkPseudos(invoker,target,true,true,'focusing invoker shows interest');
  invoker.setAttribute('style',`interest-delay: 10000s`);
  target.hidePopover();
  checkPseudos(invoker,target,false,false,'closing the popover loses interest');
  assert_equals(document.activeElement,invoker,'focus does not move');
  await do_cleanup();
},'Closing the target popover loses interest, without any delays (keyboard activation)');

promise_test(async (t) => {
  checkPseudos(invoker,target,false,false,'initial');
  await hoverOver(invoker);
  checkPseudos(invoker,target,true,true,'hovering invoker shows full interest');
  invoker.setAttribute('style',`interest-delay: 10000s`);
  target.hidePopover();
  checkPseudos(invoker,target,false,false,'closing the popover loses interest');
  await do_cleanup();
},'Closing the target popover loses interest, without any delays (mouse activation)');

const invokerDelayMs = 100; // The CSS delay setting.
const hoverWaitTime = 200; // How long to wait to cover the delay for sure.
promise_test(async (t) => {
  invoker.setAttribute('style',`interest-delay: ${invokerDelayMs}ms`);
  checkPseudos(invoker,target,false,false,'initial');
  const token1 = await mouseOverAndRecord(t,invoker);
  const immediate_result = invoker.matches(':interest-source') ||
      target.matches(':interest-target');
  if (msSinceMouseOver(token1) < invokerDelayMs) {
    assert_false(immediate_result,'No pseudos should match before the show delay elapses');
  }
  await waitForHoverTime(hoverWaitTime);
  checkPseudos(invoker,target,true,true,'pseudos should match after hover delay');
  const token2 = await mouseOverAndRecord(t,unrelated);
  const immediate_result2 =  invoker.matches(':interest-source') &&
      target.matches(':interest-target');
  if (msSinceMouseOver(token2) < invokerDelayMs) {
    assert_true(immediate_result2,'all pseudos should still match before the hide delay elapses');
  }
  await waitForHoverTime(hoverWaitTime);
  checkPseudos(invoker,target,false,false,'no pseudos should match after de-hover delay');
  await do_cleanup();
},'The pseudo classes only match after delays, once interest is shown');
</script>