@ckeditor/ckeditor5-engine
Version:
The editing engine of CKEditor 5 – the best browser-based rich text editor.
153 lines (152 loc) • 6.82 kB
TypeScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
/**
* @module engine/view/observer/selectionobserver
*/
import { Observer } from './observer.js';
import { MutationObserver } from './mutationobserver.js';
import { FocusObserver } from './focusobserver.js';
import { type EditingView } from '../view.js';
import { type ViewDocumentSelection } from '../documentselection.js';
import { type ViewDomConverter } from '../domconverter.js';
import { type ViewSelection } from '../selection.js';
type DomSelection = globalThis.Selection;
/**
* Selection observer class observes selection changes in the document. If a selection changes on the document this
* observer checks if the DOM selection is different from the {@link module:engine/view/document~ViewDocument#selection view selection}.
* The selection observer fires {@link module:engine/view/document~ViewDocument#event:selectionChange} event only if
* a selection change was the only change in the document and the DOM selection is different from the view selection.
*
* This observer also manages the {@link module:engine/view/document~ViewDocument#isSelecting} property of the view document.
*
* Note that this observer is attached by the {@link module:engine/view/view~EditingView} and is available by default.
*/
export declare class SelectionObserver extends Observer {
/**
* Instance of the mutation observer. Selection observer calls
* {@link module:engine/view/observer/mutationobserver~MutationObserver#flush} to ensure that the mutations will be handled
* before the {@link module:engine/view/document~ViewDocument#event:selectionChange} event is fired.
*/
readonly mutationObserver: MutationObserver;
/**
* Instance of the focus observer. Focus observer calls
* {@link module:engine/view/observer/focusobserver~FocusObserver#flush} to mark the latest focus change as complete.
*/
readonly focusObserver: FocusObserver;
/**
* Reference to the view {@link module:engine/view/documentselection~ViewDocumentSelection} object used to compare
* new selection with it.
*/
readonly selection: ViewDocumentSelection;
/**
* Reference to the {@link module:engine/view/view~EditingView#domConverter}.
*/
readonly domConverter: ViewDomConverter;
/**
* A set of documents which have added `selectionchange` listener to avoid adding a listener twice to the same
* document.
*/
private readonly _documents;
/**
* Fires debounced event `selectionChangeDone`. It uses `es-toolkit#debounce` method to delay function call.
*/
private readonly _fireSelectionChangeDoneDebounced;
/**
* When called, starts clearing the {@link #_loopbackCounter} counter in time intervals. When the number of selection
* changes exceeds a certain limit within the interval of time, the observer will not fire `selectionChange` but warn about
* possible infinite selection loop.
*/
private readonly _clearInfiniteLoopInterval;
/**
* Unlocks the `isSelecting` state of the view document in case the selection observer did not record this fact
* correctly (for whatever reason). It is a safeguard (paranoid check), that returns document to the normal state
* after a certain period of time (debounced, postponed by each selectionchange event).
*/
private readonly _documentIsSelectingInactivityTimeoutDebounced;
/**
* Private property to check if the code does not enter infinite loop.
*/
private _loopbackCounter;
/**
* A set of DOM documents that have a pending selection change.
* Pending selection change is recorded while selection change event is detected on non focused editable.
*/
private _pendingSelectionChange;
constructor(view: EditingView);
/**
* @inheritDoc
*/
observe(domElement: HTMLElement): void;
/**
* @inheritDoc
*/
stopObserving(domElement: HTMLElement): void;
/**
* @inheritDoc
*/
destroy(): void;
private _reportInfiniteLoop;
/**
* Selection change listener. {@link module:engine/view/observer/mutationobserver~MutationObserver#flush Flush} mutations, check if
* a selection changes and fires {@link module:engine/view/document~ViewDocument#event:selectionChange} event on every change
* and {@link module:engine/view/document~ViewDocument#event:selectionChangeDone} when a selection stop changing.
*
* @param domDocument DOM document.
*/
private _handleSelectionChange;
/**
* Clears `SelectionObserver` internal properties connected with preventing infinite loop.
*/
private _clearInfiniteLoop;
}
/**
* The value of {@link ~ViewDocumentObserverSelectionChangeEvent} and {@link ~ViewDocumentObserverSelectionChangeDoneEvent} events.
*/
export type ViewDocumentObserverSelectionEventData = {
/**
* Old View selection which is {@link module:engine/view/document~ViewDocument#selection}.
*/
oldSelection: ViewDocumentSelection;
/**
* New View selection which is converted DOM selection.
*/
newSelection: ViewSelection;
/**
* Native DOM selection.
*/
domSelection: DomSelection | null;
};
/**
* Fired when a selection has changed. This event is fired only when the selection change was the only change that happened
* in the document, and the old selection is different then the new selection.
*
* Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.
*
* Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the
* {@link module:engine/view/view~EditingView} this event is available by default.
*
* @see module:engine/view/observer/selectionobserver~SelectionObserver
* @eventName module:engine/view/document~ViewDocument#selectionChange
*/
export type ViewDocumentObserverSelectionChangeEvent = {
name: 'selectionChange';
args: [ViewDocumentObserverSelectionEventData];
};
/**
* Fired when selection stops changing.
*
* Introduced by {@link module:engine/view/observer/selectionobserver~SelectionObserver}.
*
* Note that because {@link module:engine/view/observer/selectionobserver~SelectionObserver} is attached by the
* {@link module:engine/view/view~EditingView} this event is available by default.
*
* @see module:engine/view/observer/selectionobserver~SelectionObserver
* @eventName module:engine/view/document~ViewDocument#selectionChangeDone
*/
export type ViewDocumentObserverSelectionChangeDoneEvent = {
name: 'selectionChangeDone';
args: [ViewDocumentObserverSelectionEventData];
};
export {};