Skip to content

Commit

Permalink
Bug 1823359 - Implement beforetoggle event for popover. r=emilio,smaug
Browse files Browse the repository at this point in the history
  • Loading branch information
ziransun committed Mar 24, 2023
1 parent a47e766 commit d31e401
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 57 deletions.
20 changes: 17 additions & 3 deletions dom/base/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@
#include "mozilla/dom/StyleSheetApplicableStateChangeEventBinding.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/dom/TimeoutManager.h"
#include "mozilla/dom/ToggleEvent.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/dom/TreeOrderedArrayInlines.h"
Expand Down Expand Up @@ -14895,25 +14896,38 @@ void Document::HideAllPopoversUntil(nsINode& aEndpoint,
}
}

// https://html.spec.whatwg.org/#dom-hidepopover
void Document::HidePopover(Element& aPopover, bool aFocusPreviousElement,
bool aFireEvents, ErrorResult& aRv) {
auto* popoverHTMLEl = nsGenericHTMLElement::FromNode(aPopover);
RefPtr<nsGenericHTMLElement> popoverHTMLEl =
nsGenericHTMLElement::FromNode(aPopover);
NS_ASSERTION(popoverHTMLEl, "Not a HTML element");

if (!popoverHTMLEl->CheckPopoverValidity(PopoverVisibilityState::Hidden,
if (!popoverHTMLEl->CheckPopoverValidity(PopoverVisibilityState::Showing,
aRv)) {
return;
}

// TODO: Run auto popover steps.
// TODO: Fire beforetoggle event and re-check popover validity.
// Fire beforetoggle event and re-check popover validity.
if (aFireEvents) {
// Intentionally ignore the return value here as only on open event the
// cancelable attribute is initialized to true.
popoverHTMLEl->FireBeforeToggle(true);
if (!popoverHTMLEl->CheckPopoverValidity(PopoverVisibilityState::Showing,
aRv)) {
return;
}
}

// TODO: Remove from Top Layer.

popoverHTMLEl->PopoverPseudoStateUpdate(false, true);
popoverHTMLEl->GetPopoverData()->SetPopoverVisibilityState(
PopoverVisibilityState::Hidden);

// TODO: Queue popover toggle event task.
// TODO: Handle element focus.
}

nsTArray<Element*> Document::AutoPopoverList() const {
Expand Down
1 change: 1 addition & 0 deletions dom/events/EventNameList.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
#endif /* BEFOREUNLOAD_EVENT */

EVENT(abort, eImageAbort, EventNameType_All, eBasicEventClass)
EVENT(beforetoggle, eBeforeToggle, EventNameType_HTMLXUL, eBasicEventClass)
EVENT(bounce, eMarqueeBounce, EventNameType_HTMLMarqueeOnly, eBasicEventClass)
EVENT(canplay, eCanPlay, EventNameType_HTML, eBasicEventClass)
EVENT(canplaythrough, eCanPlayThrough, EventNameType_HTML, eBasicEventClass)
Expand Down
55 changes: 46 additions & 9 deletions dom/html/nsGenericHTMLElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
#include "nsTextFragment.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/ToggleEvent.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/ErrorResult.h"
#include "nsHTMLDocument.h"
Expand Down Expand Up @@ -673,14 +674,17 @@ nsresult nsGenericHTMLElement::AfterSetAttr(
// The missing value default is the no popover state.
newState = PopoverState::None;
}
if (newState != GetPopoverState()) {
if (PopoverOpen()) {
HidePopover(IgnoreErrors());
PopoverState oldState = GetPopoverState();
if (newState != oldState) {
if (oldState != PopoverState::None) {
HidePopoverInternal(/* aFireEvents = */ false, IgnoreErrors());
}
if (newState == PopoverState::None) {
ClearPopoverData();
} else {
if (newState != PopoverState::None) {
EnsurePopoverData().SetPopoverState(newState);
PopoverPseudoStateUpdate(false, true);
} else {
ClearPopoverData();
RemoveStates(ElementState::OPEN | ElementState::CLOSED);
}
}
} else if (aName == nsGkAtoms::dir) {
Expand Down Expand Up @@ -3182,24 +3186,57 @@ void nsGenericHTMLElement::PopoverPseudoStateUpdate(bool aOpen, bool aNotify) {
ToggleStates(changedStates, aNotify);
}

bool nsGenericHTMLElement::FireBeforeToggle(bool aIsOpen) {
ToggleEventInit init;
init.mBubbles = false;
if (aIsOpen) {
init.mCancelable = false;
init.mOldState = u"open"_ns;
init.mNewState = u"closed"_ns;
} else {
init.mCancelable = true;
init.mOldState = u"closed"_ns;
init.mNewState = u"open"_ns;
}
RefPtr<ToggleEvent> event =
ToggleEvent::Constructor(this, u"beforetoggle"_ns, init);
event->SetTrusted(true);

EventDispatcher::DispatchDOMEvent(MOZ_KnownLive(ToSupports(this)), nullptr,
event, nullptr, nullptr);
return event->DefaultPrevented();
}

// https://html.spec.whatwg.org/#dom-showpopover
void nsGenericHTMLElement::ShowPopover(ErrorResult& aRv) {
if (!CheckPopoverValidity(PopoverVisibilityState::Hidden, aRv)) {
return;
}
// TODO: Fire beforetoggle event and re-check popover validity.
// Fire beforetoggle event and re-check popover validity.
if (FireBeforeToggle(false)) {
return;
}
if (!CheckPopoverValidity(PopoverVisibilityState::Hidden, aRv)) {
return;
}
// TODO: Run auto popover steps.
// TODO: Add to Top Layer.
GetPopoverData()->SetPopoverVisibilityState(PopoverVisibilityState::Showing);

PopoverPseudoStateUpdate(true, true);
GetPopoverData()->SetPopoverVisibilityState(PopoverVisibilityState::Showing);

// TODO: Handle popover focusing.
// TODO: Queue popover toggle event task.
}

// https://html.spec.whatwg.org/#dom-hidepopover
void nsGenericHTMLElement::HidePopover(ErrorResult& aRv) {
OwnerDoc()->HidePopover(*this, true, true, aRv);
HidePopoverInternal(true, aRv);
}

void nsGenericHTMLElement::HidePopoverInternal(bool aFireEvents,
ErrorResult& aRv) {
OwnerDoc()->HidePopover(*this, true, aFireEvents, aRv);
}

// https://html.spec.whatwg.org/multipage/popover.html#dom-togglepopover
Expand Down
6 changes: 5 additions & 1 deletion dom/html/nsGenericHTMLElement.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,11 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
bool PopoverOpen() const;
bool CheckPopoverValidity(mozilla::dom::PopoverVisibilityState aExpectedState,
ErrorResult& aRv);
void ShowPopover(ErrorResult& aRv);
/** Returns true if the event has been cancelled. */
MOZ_CAN_RUN_SCRIPT bool FireBeforeToggle(bool aIsOpen);
MOZ_CAN_RUN_SCRIPT void ShowPopover(ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT void HidePopoverInternal(bool aFireEvents,
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT void HidePopover(ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT void TogglePopover(bool force, ErrorResult& aRv);

Expand Down
2 changes: 2 additions & 0 deletions dom/webidl/EventHandler.webidl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ interface mixin GlobalEventHandlers {
attribute EventHandler onauxclick;
[Pref="dom.input_events.beforeinput.enabled"]
attribute EventHandler onbeforeinput;
[Pref="dom.element.popover.enabled"]
attribute EventHandler onbeforetoggle;
attribute EventHandler oncanplay;
attribute EventHandler oncanplaythrough;
attribute EventHandler onchange;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,6 @@
[Removing a visible popover=auto element from the document should close the popover]
expected: FAIL

[A showing popover=auto does not match :modal]
expected: FAIL

[Removing a visible popover=hint element from the document should close the popover]
expected: FAIL

Expand All @@ -75,9 +72,6 @@
[Removing a visible popover=manual element from the document should close the popover]
expected: FAIL

[A showing popover=manual does not match :modal]
expected: FAIL

[Changing the popover type in a "beforetoggle" event handler should throw an exception (during showPopover())]
expected: FAIL

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@

[Popover focus returns when popover is hidden by invoker]
expected: FAIL

[Circular reference tab navigation]
expected: FAIL
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
[popover-focus-child-dialog.html]
max-asserts: 2
expected:
if (os == "android") and fission: [ERROR, TIMEOUT]
ERROR
max-asserts: 2
[Popovers should not initially focus child popover elements.]
expected: NOTRUN
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
[Clicking inside a parent popover should close child popover]
expected: FAIL

[Clicking on invoking element, after using it for activation, shouldn't close its popover]
expected: FAIL

[Clicking on invoking element, after using it for activation, shouldn't close its popover (nested case)]
expected: FAIL

Expand Down Expand Up @@ -60,9 +57,6 @@
[Scrolling within a popover should not close the popover]
expected: FAIL

[Moving focus back to the anchor element should not dismiss the popover]
expected: FAIL

[Ensure circular/convoluted ancestral relationships are functional]
expected: FAIL

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
[popover-shadow-dom.html]
[Popovers located inside shadow DOM can still be shown]
expected: FAIL

[anchor references do not cross shadow boundaries]
expected: FAIL

Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
[popover-top-layer-interactions.html]
expected: ERROR
[A Popover API should close a Popover API]
expected: FAIL

[A Modal Dialog should close a Popover API]
expected: NOTRUN
expected: FAIL

[A Fullscreen Element should close a Popover API]
expected: NOTRUN

[A Popover API should *not* close a Modal Dialog]
expected: NOTRUN

[A Popover API should *not* close a Fullscreen Element]
expected: NOTRUN
expected: FAIL

[A Fullscreen Element should *not* close a Fullscreen Element]
expected: NOTRUN

[A Modal Dialog should *not* close a Modal Dialog]
expected: NOTRUN

[A Fullscreen Element should *not* close a Modal Dialog]
expected: NOTRUN

[A Modal Dialog should *not* close a Fullscreen Element]
expected: NOTRUN
expected: FAIL
2 changes: 2 additions & 0 deletions widget/EventMessageList.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ NS_EVENT_MESSAGE(eContextMenu)

NS_EVENT_MESSAGE(eCueChange)

NS_EVENT_MESSAGE(eBeforeToggle)

NS_EVENT_MESSAGE(eLoad)
NS_EVENT_MESSAGE(eUnload)
NS_EVENT_MESSAGE(eHashChange)
Expand Down
1 change: 1 addition & 0 deletions xpcom/ds/StaticAtoms.py
Original file line number Diff line number Diff line change
Expand Up @@ -1980,6 +1980,7 @@
Atom("onmozshowdropdown_sourcetouch", "onmozshowdropdown-sourcetouch"),
Atom("onprintPreviewUpdate", "onprintPreviewUpdate"),
Atom("onscrollend", "onscrollend"),
Atom("onbeforetoggle", "onbeforetoggle"),
# WebExtensions
Atom("moz_extension", "moz-extension"),
Atom("all_urlsPermission", "<all_urls>"),
Expand Down

0 comments on commit d31e401

Please sign in to comment.