UNPKG

@ckeditor/ckeditor5-clipboard

Version:

Clipboard integration feature for CKEditor 5.

203 lines (202 loc) 9.44 kB
/** * @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 */ import { Plugin, type NonEmptyArray } from '@ckeditor/ckeditor5-core'; import { Range, type DocumentFragment, type Element, type DocumentSelection, type Selection, type Writer } from '@ckeditor/ckeditor5-engine'; /** * Part of the clipboard logic. Responsible for collecting markers from selected fragments * and restoring them with proper positions in pasted elements. * * @internal */ export default class ClipboardMarkersUtils extends Plugin { /** * Map of marker names that can be copied. * * @internal */ private _markersToCopy; /** * @inheritDoc */ static get pluginName(): "ClipboardMarkersUtils"; /** * @inheritDoc */ static get isOfficialPlugin(): true; /** * Registers marker name as copyable in clipboard pipeline. * * @param markerName Name of marker that can be copied. * @param config Configuration that describes what can be performed on specified marker. * @internal */ _registerMarkerToCopy(markerName: string, config: ClipboardMarkerConfiguration): void; /** * Performs copy markers on provided selection and paste it to fragment returned from `getCopiedFragment`. * * 1. Picks all markers in provided selection. * 2. Inserts fake markers to document. * 3. Gets copied selection fragment from document. * 4. Removes fake elements from fragment and document. * 5. Inserts markers in the place of removed fake markers. * * Due to selection modification, when inserting items, `getCopiedFragment` must *always* operate on `writer.model.document.selection'. * Do not use any other custom selection object within callback, as this will lead to out-of-bounds exceptions in rare scenarios. * * @param action Type of clipboard action. * @param selection Selection to be checked. * @param getCopiedFragment Callback that performs copy of selection and returns it as fragment. * @internal */ _copySelectedFragmentWithMarkers(action: ClipboardMarkerRestrictedAction, selection: Selection | DocumentSelection, getCopiedFragment?: (writer: Writer) => DocumentFragment): DocumentFragment; /** * Performs paste of markers on already pasted element. * * 1. Inserts fake markers that are present in fragment element (such fragment will be processed in `getPastedDocumentElement`). * 2. Calls `getPastedDocumentElement` and gets element that is inserted into root model. * 3. Removes all fake markers present in transformed element. * 4. Inserts new markers with removed fake markers ranges into pasted fragment. * * There are multiple edge cases that have to be considered before calling this function: * * * `markers` are inserted into the same element that must be later transformed inside `getPastedDocumentElement`. * * Fake marker elements inside `getPastedDocumentElement` can be cloned, but their ranges cannot overlap. * * If `duplicateOnPaste` is `true` in marker config then associated marker ID is regenerated before pasting. * * @param markers Object that maps marker name to corresponding range. * @param getPastedDocumentElement Getter used to get target markers element. * @internal */ _pasteMarkersIntoTransformedElement(markers: Record<string, Range> | Map<string, Range>, getPastedDocumentElement: (writer: Writer) => Element): Element; /** * Pastes document fragment with markers to document. * If `duplicateOnPaste` is `true` in marker config then associated markers IDs * are regenerated before pasting to avoid markers duplications in content. * * @param fragment Document fragment that should contain already processed by pipeline markers. * @internal */ _pasteFragmentWithMarkers(fragment: DocumentFragment): Range; /** * In some situations we have to perform copy on selected fragment with certain markers. This function allows to temporarily bypass * restrictions on markers that we want to copy. * * This function executes `executor()` callback. For the duration of the callback, if the clipboard pipeline is used to copy * content, markers with the specified name will be copied to the clipboard as well. * * @param markerName Which markers should be copied. * @param executor Callback executed. * @param config Optional configuration flags used to copy (such like partial copy flag). * @internal */ _forceMarkersCopy(markerName: string, executor: VoidFunction, config?: ClipboardMarkerConfiguration): void; /** * Checks if marker can be copied. * * @param markerName Name of checked marker. * @param action Type of clipboard action. If null then checks only if marker is registered as copyable. * @internal */ _isMarkerCopyable(markerName: string, action: ClipboardMarkerRestrictedAction | null): boolean; /** * Checks if marker has any clipboard copy behavior configuration. * * @param markerName Name of checked marker. */ _hasMarkerConfiguration(markerName: string): boolean; /** * Returns marker's configuration flags passed during registration. * * @param markerName Name of marker that should be returned. * @internal */ _getMarkerClipboardConfig(markerName: string): ClipboardMarkerConfiguration | null; /** * First step of copying markers. It looks for markers intersecting with given selection and inserts `$marker` elements * at positions where document markers start or end. This way `$marker` elements can be easily copied together with * the rest of the content of the selection. * * @param writer An instance of the model writer. * @param selection Selection to be checked. * @param action Type of clipboard action. */ private _insertFakeMarkersIntoSelection; /** * Returns array of markers that can be copied in specified selection. * * If marker cannot be copied partially (according to `copyPartiallySelected` configuration flag) and * is not present entirely in any selection range then it will be skipped. * * @param writer An instance of the model writer. * @param selection Selection which will be checked. * @param action Type of clipboard action. If null then checks only if marker is registered as copyable. */ private _getCopyableMarkersFromSelection; /** * Picks all markers from markers map that can be pasted. * If `duplicateOnPaste` is `true`, it regenerates their IDs to ensure uniqueness. * If marker is not registered, it will be kept in the array anyway. * * @param markers Object that maps marker name to corresponding range. * @param action Type of clipboard action. If null then checks only if marker is registered as copyable. */ private _getPasteMarkersFromRangeMap; /** * Inserts specified array of fake markers elements to document and assigns them `type` and `name` attributes. * Fake markers elements are used to calculate position of markers on pasted fragment that were transformed during * steps between copy and paste. * * @param writer An instance of the model writer. * @param markers Array of markers that will be inserted. */ private _insertFakeMarkersElements; /** * Removes all `$marker` elements from the given document fragment. * * Returns an object where keys are marker names, and values are ranges corresponding to positions * where `$marker` elements were inserted. * * If the document fragment had only one `$marker` element for given marker (start or end) the other boundary is set automatically * (to the end or start of the document fragment, respectively). * * @param writer An instance of the model writer. * @param rootElement The element to be checked. */ private _removeFakeMarkersInsideElement; /** * Returns array that contains list of fake markers with corresponding `$marker` elements. * * For each marker, there can be two `$marker` elements or only one (if the document fragment contained * only the beginning or only the end of a marker). * * @param writer An instance of the model writer. * @param rootElement The element to be checked. */ private _getAllFakeMarkersFromElement; /** * When copy of markers occurs we have to make sure that pasted markers have different names * than source markers. This functions helps with assigning unique part to marker name to * prevent duplicated markers error. * * @param name Name of marker */ private _getUniqueMarkerName; } /** * Specifies which action is performed during clipboard event. * * @internal */ export type ClipboardMarkerRestrictedAction = 'copy' | 'cut' | 'dragstart'; /** * Specifies behavior of markers during clipboard actions. * * @internal */ export type ClipboardMarkerConfiguration = { allowedActions: NonEmptyArray<ClipboardMarkerRestrictedAction> | 'all'; copyPartiallySelected?: boolean; duplicateOnPaste?: boolean; };