PopoverData.cpp (3332B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "PopoverData.h" 8 9 #include "mozilla/dom/CloseWatcher.h" 10 #include "mozilla/dom/CloseWatcherManager.h" 11 #include "mozilla/dom/Document.h" 12 #include "nsGenericHTMLElement.h" 13 #include "nsIDOMEventListener.h" 14 15 namespace mozilla::dom { 16 17 class PopoverCloseWatcherListener : public nsIDOMEventListener { 18 public: 19 NS_DECL_ISUPPORTS 20 21 explicit PopoverCloseWatcherListener(nsGenericHTMLElement* aPopover) { 22 mPopover = do_GetWeakReference(aPopover); 23 }; 24 25 NS_IMETHODIMP MOZ_CAN_RUN_SCRIPT HandleEvent(Event* aEvent) override { 26 RefPtr<nsINode> node = do_QueryReferent(mPopover); 27 if (RefPtr<nsGenericHTMLElement> popover = 28 nsGenericHTMLElement::FromNodeOrNull(node)) { 29 nsAutoString eventType; 30 aEvent->GetType(eventType); 31 if (eventType.EqualsLiteral("close")) { 32 popover->HidePopover(IgnoreErrors()); 33 } 34 } 35 return NS_OK; 36 } 37 38 private: 39 virtual ~PopoverCloseWatcherListener() = default; 40 nsWeakPtr mPopover; 41 }; 42 NS_IMPL_ISUPPORTS(PopoverCloseWatcherListener, nsIDOMEventListener) 43 44 void PopoverData::EnsureCloseWatcher(nsGenericHTMLElement* aElement) { 45 if (!mCloseWatcher) { 46 RefPtr<Document> doc = aElement->OwnerDoc(); 47 if (doc->IsActive() && doc->IsCurrentActiveDocument()) { 48 if (RefPtr<nsPIDOMWindowInner> window = doc->GetInnerWindow()) { 49 mCloseWatcher = new CloseWatcher(window); 50 RefPtr<PopoverCloseWatcherListener> eventListener = 51 new PopoverCloseWatcherListener(aElement); 52 mCloseWatcher->AddSystemEventListener(u"close"_ns, eventListener, 53 false /* aUseCapture */, 54 false /* aWantsUntrusted */); 55 56 mCloseWatcher->AddToWindowsCloseWatcherManager(); 57 } 58 } 59 } 60 } 61 62 CloseWatcher* PopoverData::GetCloseWatcher() { return mCloseWatcher; } 63 64 // https://html.spec.whatwg.org/#hide-popover-algorithm 65 // Step 6.2 66 void PopoverData::DestroyCloseWatcher() { 67 // 6.2. If element's popover close watcher is not null, then: 68 if (mCloseWatcher) { 69 // 6.2.1. Destroy element's popover close watcher. 70 mCloseWatcher->Destroy(); 71 // 6.2.2. Set element's popover close watcher to null. 72 mCloseWatcher = nullptr; 73 } 74 }; 75 76 PopoverToggleEventTask::PopoverToggleEventTask(nsWeakPtr aElement, 77 nsWeakPtr aSource, 78 PopoverVisibilityState aOldState) 79 : Runnable("PopoverToggleEventTask"), 80 mElement(std::move(aElement)), 81 mSource(std::move(aSource)), 82 mOldState(aOldState) {} 83 84 NS_IMETHODIMP 85 PopoverToggleEventTask::Run() { 86 nsCOMPtr<Element> element = do_QueryReferent(mElement); 87 nsCOMPtr<Element> source = do_QueryReferent(mSource); 88 if (!element) { 89 return NS_OK; 90 } 91 if (auto* htmlElement = nsGenericHTMLElement::FromNode(element)) { 92 MOZ_KnownLive(htmlElement) 93 ->RunPopoverToggleEventTask(this, mOldState, source); 94 } 95 return NS_OK; 96 }; 97 98 } // namespace mozilla::dom