diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc new file mode 100644 index 00000000000..77385084d33 --- /dev/null +++ b/chromium/third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.cc @@ -0,0 +1,125 @@ +// Copyright 2021 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/modalclosewatcher/modal_close_watcher.h" + +#include "third_party/blink/public/platform/interface_registry.h" +#include "third_party/blink/renderer/core/dom/events/event.h" +#include "third_party/blink/renderer/core/events/keyboard_event.h" +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/modules/event_target_modules.h" +#include "third_party/blink/renderer/platform/keyboard_codes.h" + +namespace blink { + +const char ModalCloseWatcher::WatcherStack::kSupplementName[] = + "ModalCloseWatcher::WatcherStack"; + +ModalCloseWatcher::WatcherStack& ModalCloseWatcher::WatcherStack::From( + LocalDOMWindow& window) { + auto* stack = Supplement<LocalDOMWindow>::From<WatcherStack>(window); + if (!stack) { + stack = MakeGarbageCollected<WatcherStack>(window); + Supplement<LocalDOMWindow>::ProvideTo(window, stack); + } + return *stack; +} + +ModalCloseWatcher::WatcherStack::WatcherStack(LocalDOMWindow& window) + : Supplement<LocalDOMWindow>(window), receiver_(this, &window) {} + +void ModalCloseWatcher::WatcherStack::Add(ModalCloseWatcher* watcher) { + if (watchers_.IsEmpty()) { + GetSupplementable()->addEventListener(event_type_names::kKeyup, this); + auto& host = GetSupplementable()->GetFrame()->GetLocalFrameHostRemote(); + host.SetModalCloseListener(receiver_.BindNewPipeAndPassRemote( + GetSupplementable()->GetTaskRunner(TaskType::kMiscPlatformAPI))); + } + watchers_.insert(watcher); +} + +void ModalCloseWatcher::WatcherStack::Remove(ModalCloseWatcher* watcher) { + watchers_.erase(watcher); + if (watchers_.IsEmpty()) { + GetSupplementable()->removeEventListener(event_type_names::kKeyup, this); + receiver_.reset(); + } +} + +void ModalCloseWatcher::WatcherStack::Trace(Visitor* visitor) const { + NativeEventListener::Trace(visitor); + Supplement<LocalDOMWindow>::Trace(visitor); + visitor->Trace(watchers_); + visitor->Trace(receiver_); +} + +void ModalCloseWatcher::WatcherStack::Invoke(ExecutionContext*, Event* e) { + DCHECK(!watchers_.IsEmpty()); + KeyboardEvent* event = DynamicTo<KeyboardEvent>(e); + if (event && event->isTrusted() && event->keyCode() == VKEY_ESCAPE) + Signal(); +} + +ModalCloseWatcher* ModalCloseWatcher::Create(ScriptState* script_state, + ExceptionState& exception_state) { + LocalDOMWindow* window = LocalDOMWindow::From(script_state); + WatcherStack& stack = WatcherStack::From(*window); + if (stack.HasActiveWatcher() && + !LocalFrame::HasTransientUserActivation(window->GetFrame())) { + exception_state.ThrowDOMException( + DOMExceptionCode::kNotAllowedError, + "Creating more than one ModalCloseWatcher at a time requires a user " + "activation."); + return nullptr; + } + + ModalCloseWatcher* watcher = MakeGarbageCollected<ModalCloseWatcher>(window); + stack.Add(watcher); + return watcher; +} + +ModalCloseWatcher::ModalCloseWatcher(LocalDOMWindow* window) + : ExecutionContextClient(window) {} + +void ModalCloseWatcher::signalClosed() { + if (IsClosed() || dispatching_beforeclose_) + return; + Event& before_close_event = + *Event::CreateCancelable(event_type_names::kBeforeclose); + { + base::AutoReset<bool> scoped_committing(&dispatching_beforeclose_, true); + DispatchEvent(before_close_event); + } + if (before_close_event.defaultPrevented()) { + state_ = State::kModal; + // TODO(japhet): Make an async dialog here. + } + Close(); +} + +void ModalCloseWatcher::Close() { + if (IsClosed()) + return; + WatcherStack::From(*DomWindow()).Remove(this); + state_ = State::kClosed; + DispatchEvent(*Event::Create(event_type_names::kClose)); +} + +void ModalCloseWatcher::destroy() { + if (IsClosed()) + return; + WatcherStack::From(*DomWindow()).Remove(this); + state_ = State::kClosed; +} + +const AtomicString& ModalCloseWatcher::InterfaceName() const { + return event_target_names::kModalCloseWatcher; +} + +void ModalCloseWatcher::Trace(Visitor* visitor) const { + EventTargetWithInlineData::Trace(visitor); + ExecutionContextClient::Trace(visitor); +} + +} // namespace blink |