/** * @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"; /** * Constructor returned by {@link ~BubblingEmitterMixin}. Use it to name a mixin base class before extending it. * * ```ts * const MyBubblingEmitterBase: BubblingEmitterMixinConstructor = BubblingEmitterMixin( BaseClass ); * * class MyBubblingEmitter extends MyBubblingEmitterBase {} * ``` */ export type BubblingEmitterMixinConstructor> = Mixed; /** * 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: Base): BubblingEmitterMixinConstructor; /** * 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 *

Foo[]bar

* ``` * * 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 *

Foo[]bar

* ``` * * 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 *

Foo[]bar

* ``` * * 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 & { eventInfo: BubblingEventInfo; 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; }