| <!DOCTYPE html> |
| <meta charset="utf-8"> |
| <link rel="author" href="mailto:masonf@chromium.org"> |
| <link rel=help href="https://open-ui.org/components/popover.research.explainer"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| |
| <div> |
| <div popover>Popover</div> |
| <div popover=hint>Hint</div> |
| <div popover=manual>Async</div> |
| <div popover=manual>Async</div> |
| <script> |
| { |
| const auto = document.currentScript.parentElement.querySelector('[popover=""]'); |
| const hint = document.currentScript.parentElement.querySelector('[popover=hint]'); |
| const manual = document.currentScript.parentElement.querySelectorAll('[popover=manual]')[0]; |
| const manual2 = document.currentScript.parentElement.querySelectorAll('[popover=manual]')[1]; |
| function assert_state_1(autoOpen,hintOpen,manualOpen,manual2Open) { |
| assert_equals(auto.matches(':popover-open'),autoOpen,'auto open state is incorrect'); |
| assert_equals(hint.matches(':popover-open'),hintOpen,'hint open state is incorrect'); |
| assert_equals(manual.matches(':popover-open'),manualOpen,'manual open state is incorrect'); |
| assert_equals(manual2.matches(':popover-open'),manual2Open,'manual2 open state is incorrect'); |
| } |
| test(() => { |
| assert_state_1(false,false,false,false); |
| auto.showPopover(); |
| assert_state_1(true,false,false,false); |
| hint.showPopover(); |
| assert_state_1(true,true,false,false); |
| manual.showPopover(); |
| assert_state_1(true,true,true,false); |
| manual2.showPopover(); |
| assert_state_1(true,true,true,true); |
| hint.hidePopover(); |
| assert_state_1(true,false,true,true); |
| auto.hidePopover(); |
| assert_state_1(false,false,true,true); |
| auto.showPopover(); |
| hint.showPopover(); |
| assert_state_1(true,true,true,true); |
| auto.hidePopover(); // Non-nested tooltips can stay open when unrelated popovers are hidden. |
| assert_state_1(false,true,true,true); |
| hint.hidePopover(); |
| manual.hidePopover(); |
| assert_state_1(false,false,false,true); |
| manual2.hidePopover(); |
| assert_state_1(false,false,false,false); |
| },'manuals do not close popovers'); |
| |
| test(() => { |
| assert_state_1(false,false,false,false); |
| hint.showPopover(); |
| manual.showPopover(); |
| manual2.showPopover(); |
| assert_state_1(false,true,true,true); |
| auto.showPopover(); |
| assert_state_1(true,false,true,true); |
| auto.hidePopover(); |
| assert_state_1(false,false,true,true); |
| manual.hidePopover(); |
| manual2.hidePopover(); |
| assert_state_1(false,false,false,false); |
| },'autos close hints but not manuals'); |
| } |
| </script> |
| </div> |
| |
| <div> |
| <div popover>popover 1 |
| <div popover>popover 2 |
| <p id=anchorid>Anchor</p> |
| <div popover>popover 3</div> |
| </div> |
| </div> |
| <div popover=hint anchor=anchorid>Hint anchored to popover</div> |
| <script> |
| { |
| const popover1 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[0]; |
| const popover2 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[1]; |
| const popover3 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[2]; |
| const hint = document.currentScript.parentElement.querySelector('[popover=hint]'); |
| function assert_state_2(popover1Open,popover2Open,popover3Open,hintOpen) { |
| assert_equals(popover1.matches(':popover-open'),popover1Open,'popover1 open state is incorrect'); |
| assert_equals(popover2.matches(':popover-open'),popover2Open,'popover2 open state is incorrect'); |
| assert_equals(popover3.matches(':popover-open'),popover3Open,'popover3 open state is incorrect'); |
| assert_equals(hint.matches(':popover-open'),hintOpen,'hint open state is incorrect'); |
| } |
| test(() => { |
| assert_state_2(false,false,false,false); |
| popover1.showPopover(); |
| popover2.showPopover(); |
| popover3.showPopover(); |
| assert_state_2(true,true,true,false); |
| hint.showPopover(); // Because hint is nested in popover2, popover3 should be hidden |
| assert_state_2(true,true,false,true); |
| popover1.hidePopover(); // Should close the hint, which is anchored to popover2 |
| assert_state_2(false,false,false,false); |
| },'hint is not closed by pre-existing auto'); |
| } |
| </script> |
| </div> |
| |
| <div> |
| <div popover=hint>Hint |
| <div popover=hint>Nested hint</div> |
| </div> |
| <script> |
| test(() => { |
| const hint1 = document.currentScript.parentElement.querySelectorAll('[popover=hint]')[0]; |
| const hint2 = document.currentScript.parentElement.querySelectorAll('[popover=hint]')[1]; |
| hint1.showPopover(); |
| assert_true(hint1.matches(':popover-open')); |
| assert_false(hint2.matches(':popover-open')); |
| hint2.showPopover(); |
| assert_false(hint1.matches(':popover-open')); |
| assert_true(hint2.matches(':popover-open')); |
| hint2.hidePopover(); |
| },'If a popover=hint is shown, it should hide any other open popover=hint popovers, including ancestral popovers. (You can\'t nest popover=hint)'); |
| </script> |
| </div> |
| |
| <div> |
| <div popover="hint">Hint |
| <div popover>Nested auto (note - never visible, since inside display:none subtree)</div> |
| </div> |
| <script> |
| test(() => { |
| const hint = document.currentScript.parentElement.querySelector('[popover=hint]'); |
| const auto = document.currentScript.parentElement.querySelector('[popover=""]'); |
| hint.showPopover(); |
| assert_true(hint.matches(':popover-open')); |
| assert_false(auto.matches(':popover-open')); |
| auto.showPopover(); |
| assert_false(hint.matches(':popover-open')); |
| assert_true(auto.matches(':popover-open')); |
| auto.hidePopover(); |
| },'If a popover=auto is shown, it should hide any open popover=hint, including if the popover=hint is an ancestral popover of the popover=auto. (You can\'t nest a popover=auto inside a popover=hint)'); |
| </script> |
| </div> |
| |
| <div> |
| <div popover>Auto |
| <div popover>Nested Auto</div> |
| <div popover=hint>Nested hint</div> |
| </div> |
| <script> |
| test(() => { |
| const auto = document.currentScript.parentElement.querySelectorAll('[popover=""]')[0]; |
| const auto2 = document.currentScript.parentElement.querySelectorAll('[popover=""]')[1]; |
| const hint = document.currentScript.parentElement.querySelector('[popover=hint]'); |
| auto.showPopover(); |
| auto2.showPopover(); |
| assert_true(auto.matches(':popover-open')); |
| assert_true(auto2.matches(':popover-open')); |
| hint.showPopover(); // This should hide auto2, since it is nested in auto1. |
| assert_true(auto.matches(':popover-open')); |
| assert_false(auto2.matches(':popover-open')); |
| assert_true(hint.matches(':popover-open')); |
| auto.hidePopover(); // Should hide both auto and hint. |
| assert_false(auto.matches(':popover-open')); |
| assert_false(hint.matches(':popover-open')); |
| },'If you: a) show a popover=auto (call it D), then b) show a descendent popover=hint of D (call it T), then c) hide D, then T should be hidden. (A popover=hint can be nested inside a popover=auto)'); |
| </script> |
| </div> |
| |
| <div> |
| <div popover>Auto</div> |
| <div popover=hint>Non-Nested hint</div> |
| <script> |
| test(() => { |
| const auto = document.currentScript.parentElement.querySelector('[popover=""]'); |
| const hint = document.currentScript.parentElement.querySelector('[popover=hint]'); |
| auto.showPopover(); |
| hint.showPopover(); |
| assert_true(auto.matches(':popover-open')); |
| assert_true(hint.matches(':popover-open')); |
| auto.hidePopover(); |
| assert_false(auto.matches(':popover-open')); |
| assert_true(hint.matches(':popover-open')); |
| hint.hidePopover(); |
| },'If you: a) show a popover=auto (call it D), then b) show a non-descendent popover=hint of D (call it T), then c) hide D, then T should be left showing. (Non-nested popover=hint can stay open when unrelated popover=autos are hidden)'); |
| </script> |
| </div> |