/* * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include namespace Web::DOM { // https://w3c.github.io/selection-api/#dfn-has-scheduled-selectionchange-event template concept SelectionChangeTarget = DerivedFrom && requires(T t) { { t.has_scheduled_selectionchange_event() } -> SameAs; { t.set_scheduled_selectionchange_event(bool()) } -> SameAs; }; // https://w3c.github.io/selection-api/#scheduling-selectionchange-event template void schedule_a_selectionchange_event(T& target, Document& document) { // 1. If target's has scheduled selectionchange event is true, abort these steps. if (target.has_scheduled_selectionchange_event()) return; // AD-HOC: See https://github.com/w3c/selection-api/issues/338 // Set target's has scheduled selectionchange event to true target.set_scheduled_selectionchange_event(true); // 2. Queue a task on the user interaction task source to fire a selectionchange event on // target. queue_global_task(HTML::Task::Source::UserInteraction, relevant_global_object(document), GC::create_function(document.heap(), [&] { fire_a_selectionchange_event(target, document); })); } // https://w3c.github.io/selection-api/#firing-selectionchange-event template void fire_a_selectionchange_event(T& target, Document& document) { // 1. Set target's has scheduled selectionchange event to false. target.set_scheduled_selectionchange_event(false); // 2. If target is an element, fire an event named selectionchange, which bubbles and not // cancelable, at target. // 3. Otherwise, if target is a document, fire an event named selectionchange, which does not // bubble and not cancelable, at target. Bindings::EventInit event_init; event_init.bubbles = DerivedFrom; event_init.cancelable = false; auto event = DOM::Event::create(document.realm(), HTML::EventNames::selectionchange, event_init); target.dispatch_event(event); // AD-HOC: When the selection changes, inform the UI to update the primary pasteboard. if (auto& page = document.page(); page.enable_primary_paste()) { if (auto text = page.focused_navigable().selected_text(); !text.is_empty()) page.client().page_did_update_primary_selection(text); } } }