UNPKG

@ckeditor/ckeditor5-engine

Version:

The editing engine of CKEditor 5 – the best browser-based rich text editor.

167 lines (166 loc) 5.24 kB
/** * @license Copyright (c) 2003-2026, 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/bubblingemittermixin */ import { type ArrayOrItem, type Emitter, type BaseEvent, type CallbackOptions, type Constructor, type Mixed } from '@ckeditor/ckeditor5-utils'; import { BubblingEventInfo } from './bubblingeventinfo.js'; import { type ViewNode } from '../node.js'; /** * Bubbling emitter mixin for the view document as described in the {@link ~BubblingEmitter} interface. * * This function creates a class that inherits from the provided `base` and implements `Emitter` interface. * The base class must implement {@link module:utils/emittermixin~Emitter} interface. * * ```ts * class BaseClass extends EmitterMixin() { * // ... * } * * class MyClass extends BubblingEmitterMixin( BaseClass ) { * // This class derives from `BaseClass` and implements the `BubblingEmitter` interface. * } * ``` */ export declare function BubblingEmitterMixin<Base extends Constructor<Emitter>>(base: Base): Mixed<Base, BubblingEmitter>; /** * Bubbling emitter for the view document. * * Bubbling emitter is triggering events in the context of specified {@link module:engine/view/element~ViewElement view element} name, * predefined `'$text'`, `'$root'`, `'$document'` and `'$capture'` contexts, and context matchers provided as a function. * * Before bubbling starts, listeners for `'$capture'` context are triggered. Then the bubbling starts from the deeper selection * position (by firing event on the `'$text'` context) and propagates the view document tree up to the `'$root'` and finally * the listeners at `'$document'` context are fired (this is the default context). * * Examples: * * ```ts * // Listeners registered in the context of the view element names: * this.listenTo( viewDocument, 'enter', ( evt, data ) => { * // ... * }, { context: 'blockquote' } ); * * this.listenTo( viewDocument, 'enter', ( evt, data ) => { * // ... * }, { context: 'li' } ); * * // Listeners registered in the context of the '$text' and '$root' nodes. * this.listenTo( view.document, 'arrowKey', ( evt, data ) => { * // ... * }, { context: '$text', priority: 'high' } ); * * this.listenTo( view.document, 'arrowKey', ( evt, data ) => { * // ... * }, { context: '$root' } ); * * // Listeners registered in the context of custom callback function. * this.listenTo( view.document, 'arrowKey', ( evt, data ) => { * // ... * }, { context: isWidget } ); * * this.listenTo( view.document, 'arrowKey', ( evt, data ) => { * // ... * }, { context: isWidget, priority: 'high' } ); * ``` * * Example flow for selection in text: * * ```xml * <blockquote><p>Foo[]bar</p></blockquote> * ``` * * Fired events on contexts: * 1. `'$capture'` * 2. `'$text'` * 3. `'p'` * 4. `'blockquote'` * 5. `'$root'` * 6. `'$document'` * * Example flow for selection on element (i.e., Widget): * * ```xml * <blockquote><p>Foo[<widget/>]bar</p></blockquote> * ``` * * Fired events on contexts: * 1. `'$capture'` * 2. *widget* (custom matcher) * 3. `'p'` * 4. `'blockquote'` * 5. `'$root'` * 6. `'$document'` * * There could be multiple listeners registered for the same context and at different priority levels: * * ```html * <p>Foo[]bar</p> * ``` * * 1. `'$capture'` at priorities: * 1. `'highest'` * 2. `'high'` * 3. `'normal'` * 4. `'low'` * 5. `'lowest'` * 2. `'$text'` at priorities: * 1. `'highest'` * 2. `'high'` * 3. `'normal'` * 4. `'low'` * 5. `'lowest'` * 3. `'p'` at priorities: * 1. `'highest'` * 2. `'high'` * 3. `'normal'` * 4. `'low'` * 5. `'lowest'` * 4. `'$root'` at priorities: * 1. `'highest'` * 2. `'high'` * 3. `'normal'` * 4. `'low'` * 5. `'lowest'` * 5. `'$document'` at priorities: * 1. `'highest'` * 2. `'high'` * 3. `'normal'` * 4. `'low'` * 5. `'lowest'` */ export type BubblingEmitter = Emitter; /** * A context matcher function. * * Should return true for nodes that that match the custom context. */ export type BubblingEventContextFunction = (node: ViewNode) => boolean; /** * Helper type that allows describing bubbling event. Extends `TEvent` so that: * * * the event is called with {@link module:engine/view/observer/bubblingeventinfo~BubblingEventInfo}` * instead of {@link module:utils/eventinfo~EventInfo}, and * * {@link ~BubblingCallbackOptions} can be specified as additional options. * * @typeParam TEvent The event description to extend. */ export type BubblingEvent<TEvent extends BaseEvent> = TEvent & { eventInfo: BubblingEventInfo<TEvent['name'], (TEvent extends { return: infer TReturn; } ? TReturn : unknown)>; callbackOptions: BubblingCallbackOptions; }; /** * Additional options for registering a callback. */ export interface BubblingCallbackOptions extends CallbackOptions { /** * Specifies the context in which the event should be triggered to call the callback. * * @see ~BubblingEmitter */ context?: ArrayOrItem<string | BubblingEventContextFunction>; }