diff --git a/html/semantics/popovers/popover-animation-corner-cases.tentative.html b/html/semantics/popovers/popover-animation-corner-cases.tentative.html
index 16426bc2ab953f..f41f7a68df9058 100644
--- a/html/semantics/popovers/popover-animation-corner-cases.tentative.html
+++ b/html/semantics/popovers/popover-animation-corner-cases.tentative.html
@@ -100,7 +100,9 @@
assert_true(isElementVisible(popover));
assert_equals(popover.getAnimations({subtree: true}).length,0);
let animation;
- popover.addEventListener('popoverhide', () => {
+ popover.addEventListener('beforetoggle', (e) => {
+ if (e.newState !== "closed")
+ return;
animation = popover.animate([{opacity: 1},{opacity: 0}],1000000);
});
assert_equals(popover.getAnimations({subtree: true}).length,0,'There should be no animations yet');
@@ -111,7 +113,7 @@
animation.finish();
await waitForRender();
assert_false(isElementVisible(popover),'Once the animation ends, the popover is hidden');
-},'It should be possible to use the "popoverhide" event handler to animate the hide');
+},'It should be possible to use the "beforetoggle" event handler to animate the hide');
promise_test(async (t) => {
@@ -121,8 +123,10 @@
popover.showPopover();
assert_true(isElementVisible(popover));
assert_equals(popover.getAnimations({subtree: true}).length,0);
- let animation
- popover.addEventListener('popoverhide', () => {
+ let animation;
+ popover.addEventListener('beforetoggle', (e) => {
+ if (e.newState !== "closed")
+ return;
animation = popover.animate([{opacity: 1},{opacity: 0}],1000000);
});
assert_equals(popover.getAnimations({subtree: true}).length,0,'There should be no animations yet');
@@ -133,19 +137,17 @@
animation.finish();
await waitForRender();
assert_false(isElementVisible(popover),'Once the animation ends, the popover is hidden');
-},'It should be possible to use the "popoverhide" event handler to animate the hide, even when the hide is due to dialog.showModal');
+},'It should be possible to use the "beforetoggle" event handler to animate the hide, even when the hide is due to dialog.showModal');
promise_test(async (t) => {
const {popover, descendent} = createPopover(t,'');
popover.showPopover();
assert_true(isElementVisible(popover));
- popover.addEventListener('popoverhide', (e) => {
- e.preventDefault();
- });
+ popover.addEventListener('beforetoggle', (e) => e.preventDefault());
popover.hidePopover();
await waitForRender();
assert_false(isElementVisible(popover),'Even if hide event is cancelled, the popover still closes');
-},'hide event cannot be cancelled');
+},'toggle event cannot be cancelled');
promise_test(async (t) => {
const {popover, descendent} = createPopover(t,'animation');
@@ -173,7 +175,9 @@
popover.showPopover();
assert_true(isElementVisible(popover));
assert_equals(popover.getAnimations({subtree: true}).length,0);
- popover.addEventListener('popoverhide', () => {
+ popover.addEventListener('beforetoggle', (e) => {
+ if (e.newState !== "closed")
+ return;
popover.animate([{opacity: 1},{opacity: 0}],1000000);
});
assert_equals(popover.getAnimations({subtree: true}).length,0,'There should be no animations yet');
@@ -197,7 +201,9 @@
promise_test(async (t) => {
const {popover, descendent} = createPopover(t,'');
popover.showPopover();
- popover.addEventListener('popoverhide', () => {
+ popover.addEventListener('beforetoggle', (e) => {
+ if (e.newState !== "closed")
+ return;
popover.animate([{opacity: 1},{opacity: 0}],1000000);
});
popover.hidePopover();
diff --git a/html/semantics/popovers/popover-attribute-basic.tentative.html b/html/semantics/popovers/popover-attribute-basic.tentative.html
index ba09380f0195b7..ae4807974619d4 100644
--- a/html/semantics/popovers/popover-attribute-basic.tentative.html
+++ b/html/semantics/popovers/popover-attribute-basic.tentative.html
@@ -275,7 +275,8 @@
other_popover.showPopover();
const popover = createPopover(t);
popover.setAttribute('popover','auto');
- other_popover.addEventListener('popoverhide',() => {
+ other_popover.addEventListener('toggle', (e) => {
+ if (e.state !== "closing") return;
popover.setAttribute('popover','manual');
},{once: true});
assert_true(other_popover.matches(':open'));
@@ -283,7 +284,7 @@
popover.showPopover();
assert_false(other_popover.matches(':open'),'unrelated popover is hidden');
assert_false(popover.matches(':open'),'popover is not shown if its type changed during show');
- },`Changing the popover type in a "popoverhide" event handler should not cause problems (during showPopover())`);
+ },`Changing the popover type in a "toggle" event handler should not cause problems (during showPopover())`);
test((t) => {
const popover = createPopover(t);
@@ -294,11 +295,13 @@
popover.showPopover();
other_popover.showPopover();
let nested_popover_hidden=false;
- other_popover.addEventListener('popoverhide',() => {
+ other_popover.addEventListener('toggle', (e) => {
+ if (e.state !== "closing") return;
nested_popover_hidden = true;
popover.setAttribute('popover','manual');
},{once: true});
- popover.addEventListener('popoverhide',() => {
+ popover.addEventListener('toggle', (e) => {
+ if (e.state !== "closing") return;
assert_true(nested_popover_hidden,'The nested popover should be hidden first');
},{once: true});
assert_true(popover.matches(':open'));
@@ -307,7 +310,7 @@
assert_false(other_popover.matches(':open'),'unrelated popover is hidden');
assert_false(popover.matches(':open'),'popover is still hidden if its type changed during hide event');
assert_throws_dom("InvalidStateError",() => other_popover.hidePopover(),'Nested popover should already be hidden');
- },`Changing the popover type in a "popoverhide" event handler should not cause problems (during hidePopover())`);
+ },`Changing the popover type in a "toggle" event handler should not cause problems (during hidePopover())`);
function interpretedType(typeString,method) {
if (validTypes.includes(typeString))
@@ -344,7 +347,8 @@
popover.showPopover();
assert_true(popover.matches(':open'));
let gotEvent = false;
- popover.addEventListener('popoverhide',() => {
+ popover.addEventListener('toggle', (e) => {
+ if (e.state !== "closing") return;
gotEvent = true;
setPopoverValue(popover,inEventType,method);
},{once:true});
@@ -380,7 +384,7 @@
}
}
}
- },`Changing a popover from ${type} to ${newType} (via ${method}), and then ${inEventType} during 'popoverhide' works`);
+ },`Changing a popover from ${type} to ${newType} (via ${method}), and then ${inEventType} during 'toggle' works`);
});
});
});
diff --git a/html/semantics/popovers/popover-show-event.tentative.html b/html/semantics/popovers/popover-beforetoggle-opening-event.tentative.html
similarity index 82%
rename from html/semantics/popovers/popover-show-event.tentative.html
rename to html/semantics/popovers/popover-beforetoggle-opening-event.tentative.html
index 69996bd65daba3..b2c3fa5d68bf05 100644
--- a/html/semantics/popovers/popover-show-event.tentative.html
+++ b/html/semantics/popovers/popover-beforetoggle-opening-event.tentative.html
@@ -14,7 +14,9 @@
requestAnimationFrame(() => {++frameCount;});
const popover = document.querySelector('[popover]');
const testText = 'Show Event Occurred';
- popover.addEventListener('popovershow',() => {
+ popover.addEventListener('beforetoggle',(e) => {
+ if (e.newState !== "open")
+ return;
popover.textContent = testText;
})
popover.offsetHeight;
@@ -25,5 +27,5 @@
assert_equals(popover.textContent,testText);
assert_equals(frameCount,0,'nothing should be rendered before the popover is updated');
popover.hidePopover(); // Cleanup
-},'Ensure the `show` event can be used to populate content before the popover renders');
+},'Ensure the `beforetoggle` event can be used to populate content before the popover renders');
diff --git a/html/semantics/popovers/popover-events.tentative.html b/html/semantics/popovers/popover-events.tentative.html
index 78d4a22c78e7be..7d63ce74b7f681 100644
--- a/html/semantics/popovers/popover-events.tentative.html
+++ b/html/semantics/popovers/popover-events.tentative.html
@@ -17,31 +17,32 @@
assert_false(popover.matches(':open'));
let showCount = 0;
let hideCount = 0;
- function showListener(e) {
- assert_true(e.target.matches(':closed'),'The popover should be in the :closed state when the popovershow event fires.');
- assert_false(e.target.matches(':open'),'The popover should *not* be in the :open state when the popovershow event fires.');
- ++showCount;
- };
- function hideListener(e) {
- assert_true(e.target.matches(':open'),'The popover should be in the :open state when the popoverhide event fires.');
- assert_false(e.target.matches(':closed'),'The popover should *not* be in the :closed state when the popoverhide event fires.');
- ++hideCount;
+ function listener(e) {
+ if (e.newState === "open") {
+ assert_equals(e.currentState,"closed",'Popover toggleevent states should be "open" and "closed"')
+ assert_true(e.target.matches(':closed'),'The popover should be in the :closed state when the opening event fires.');
+ assert_false(e.target.matches(':open'),'The popover should *not* be in the :open state when the opening event fires.');
+ ++showCount;
+ } else {
+ assert_equals(e.currentState,"open",'Popover toggleevent states should be "open" and "closed"')
+ assert_equals(e.newState,"closed",'Popover toggleevent states should be "open" and "closed"')
+ assert_true(e.target.matches(':open'),'The popover should be in the :open state when the hiding event fires.');
+ assert_false(e.target.matches(':closed'),'The popover should *not* be in the :closed state when the hiding event fires.');
+ ++hideCount;
+ }
};
switch (method) {
case "listener":
const controller = new AbortController();
const signal = controller.signal;
t.add_cleanup(() => controller.abort());
- document.addEventListener('popovershow',showListener, {signal});
- document.addEventListener('popoverhide',hideListener, {signal});
+ // The 'beforetoggle' event bubbles.
+ document.addEventListener('beforetoggle', listener, {signal});
break;
case "attribute":
- assert_false(popover.hasAttribute('onpopovershow'));
- assert_false(popover.hasAttribute('onpopoverhide'));
- t.add_cleanup(() => popover.removeAttribute('onpopovershow'));
- t.add_cleanup(() => popover.removeAttribute('onpopoverhide'));
- popover.onpopovershow = showListener;
- popover.onpopoverhide = hideListener;
+ assert_false(popover.hasAttribute('onbeforetoggle'));
+ t.add_cleanup(() => popover.removeAttribute('onbeforetoggle'));
+ popover.onbeforetoggle = listener;
break;
default: assert_unreached();
}
@@ -62,7 +63,7 @@
assert_false(popover.matches(':open'));
assert_equals(1,showCount);
assert_equals(1,hideCount);
- }, `Popovershow and popoverhide events (${method}) get properly dispatched for popovers`);
+ }, `Toggle event (${method}) get properly dispatched for popovers`);
}
promise_test(async t => {
@@ -71,18 +72,20 @@
const signal = controller.signal;
t.add_cleanup(() => controller.abort());
let cancel = true;
- popover.addEventListener('popovershow',(e) => {
+ popover.addEventListener('beforetoggle',(e) => {
+ if (e.newState !== "open")
+ return;
if (cancel)
e.preventDefault();
}, {signal});
assert_false(popover.matches(':open'));
popover.showPopover();
- assert_false(popover.matches(':open'),'The "popovershow" event should be cancelable');
+ assert_false(popover.matches(':open'),'The "beforetoggle" event should be cancelable for the "opening" transition');
cancel = false;
popover.showPopover();
assert_true(popover.matches(':open'));
popover.hidePopover();
assert_false(popover.matches(':open'));
- }, 'Popovershow event is cancelable');
+ }, 'Toggle event is cancelable for the "opening" transition');
};
diff --git a/html/semantics/popovers/popover-invoking-attribute.tentative.html b/html/semantics/popovers/popover-invoking-attribute.tentative.html
index affe201b69a4a2..5ce315ef1d9ea7 100644
--- a/html/semantics/popovers/popover-invoking-attribute.tentative.html
+++ b/html/semantics/popovers/popover-invoking-attribute.tentative.html
@@ -175,8 +175,12 @@
const button = document.querySelector('button');
let showCount = 0;
let hideCount = 0;
-popover.addEventListener('popovershow',() => ++showCount);
-popover.addEventListener('popoverhide',() => ++hideCount);
+popover.addEventListener('beforetoggle',(e) => {
+ if (e.newState === "open")
+ ++showCount;
+ else
+ ++hideCount;
+ });
async function assertState(expectOpen,expectShow,expectHide) {
assert_equals(popover.matches(':open'),expectOpen,'Popover open state is incorrect');
diff --git a/html/semantics/popovers/popover-light-dismiss-on-scroll.tentative.html b/html/semantics/popovers/popover-light-dismiss-on-scroll.tentative.html
index 7a09712d8149a6..73b3a2d6193bc6 100644
--- a/html/semantics/popovers/popover-light-dismiss-on-scroll.tentative.html
+++ b/html/semantics/popovers/popover-light-dismiss-on-scroll.tentative.html
@@ -44,7 +44,9 @@
}
async_test(t => {
for(let popover of popovers) {
- popover.addEventListener('popoverhide',e => {
+ popover.addEventListener('beforetoggle',e => {
+ if (e.newState !== "closed")
+ return;
assert_unreached('Scrolling should not light-dismiss a popover');
});
}
diff --git a/html/semantics/popovers/popover-light-dismiss.tentative.html b/html/semantics/popovers/popover-light-dismiss.tentative.html
index 2a101483cb8c8e..bdd0d12545f03e 100644
--- a/html/semantics/popovers/popover-light-dismiss.tentative.html
+++ b/html/semantics/popovers/popover-light-dismiss.tentative.html
@@ -47,14 +47,18 @@
const afterp1 = document.querySelector('#after_p1');
let popover1HideCount = 0;
- popover1.addEventListener('popoverhide',(e) => {
+ popover1.addEventListener('beforetoggle',(e) => {
+ if (e.newState !== "closed")
+ return;
++popover1HideCount;
- e.preventDefault(); // 'popoverhide' should not be cancellable.
+ e.preventDefault(); // 'beforetoggle' should not be cancellable.
});
let popover2HideCount = 0;
- popover2.addEventListener('popoverhide',(e) => {
+ popover2.addEventListener('beforetoggle',(e) => {
+ if (e.newState !== "closed")
+ return;
++popover2HideCount;
- e.preventDefault(); // 'popoverhide' should not be cancellable.
+ e.preventDefault(); // 'beforetoggle' should not be cancellable.
});
promise_test(async () => {
assert_false(popover1.matches(':open'));
@@ -482,7 +486,9 @@
p13.showPopover();
p14.showPopover();
p15.showPopover();
- p15.addEventListener('popoverhide',() => {
+ p15.addEventListener('beforetoggle', (e) => {
+ if (e.newState !== "closed")
+ return;
p14.hidePopover();
},{once:true});
assert_true(p13.matches(':open') && p14.matches(':open') && p15.matches(':open'),'all three should be open');
diff --git a/html/semantics/popovers/toggleevent-interface.tentative.html b/html/semantics/popovers/toggleevent-interface.tentative.html
new file mode 100644
index 00000000000000..8ee63c4071856c
--- /dev/null
+++ b/html/semantics/popovers/toggleevent-interface.tentative.html
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+