@ckeditor/ckeditor5-collaboration-core
Version:
Base utilities used by CKEditor 5 collaboration features to support multiple users working together in a rich text editor.
170 lines (169 loc) • 5.59 kB
TypeScript
/**
* @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 collaboration-core/documentcompare
*/
import { ContextPlugin, Editor } from "@ckeditor/ckeditor5-core";
import { ModelPosition, type ModelWriter, type ModelDocumentFragment, type ModelElement, type Operation } from "@ckeditor/ckeditor5-engine";
export declare const DATA_ID_MODEL_ATTRIBUTE = "$elementId";
export declare const DATA_ID_VIEW_ATTRIBUTE = "data-id";
/**
* The `DocumentCompare` plugin provides utilities to compare two documents or documents fragments, and provide set of operations
* which need to be executed to transform one document into the other.
*/
export declare class DocumentCompare extends ContextPlugin {
/**
* @inheritDoc
*/
static get pluginName(): "DocumentCompare";
/**
* @inheritDoc
*/
static override get isOfficialPlugin(): true;
/**
* @inheritDoc
*/
static override get isPremiumPlugin(): true;
init(): Promise<void>;
get editor(): Editor;
getDiff(dataBefore: string, dataAfter: string, options?: DocumentCompareOptions): DocumentDiff;
/**
* Returns `true` if given `operation` is an operation that marks a content to be removed. This kind of operations can be
* returned by {@link module:collaboration-core/documentcompare~DocumentCompare#getOperations} if `markedDeletions` mode is enabled.
*
* @param operation
*/
isMarkedRemoveOperation(operation: Operation): boolean;
/**
* Applies the given operations (for example, the result of comparing two documents) to the model.
*
* Beyond applying the operations, this method reproduces the marker bookkeeping that the editing pipeline normally
* performs, so that existing markers behave the same as during regular editing:
*
* * markers affected by a move or merge are anchored, so they can be restored on undo;
* * marker operations have their `oldRange` reconciled with the live marker, as operations coming from a comparison
* have it set to `null`.
*
* Must be called inside a model change block; the operations are added to the given `writer`'s batch.
*
* @param writer Writer of the change block the operations are applied within.
* @param operations Operations to apply, in order.
*/
applyOperations(writer: ModelWriter, operations: Array<Operation>): void;
}
export interface DocumentCompareOptions {
anchor?: string | ModelPosition;
markDeletions: boolean;
/**
* When `DocumentCompare` runs on a context with several editors, `DocumentCompare#editor` is the first editor in the context.
* Pass the editor whose model/schema should be used for parsing and for resolving a string `anchor` (e.g. multi-root root names).
*/
targetEditor?: Editor;
}
export declare class DocumentDiff {
constructor({ editor, before, after, options }: {
editor: Editor;
before: ModelDocumentFragment;
after: ModelDocumentFragment;
options: {
markDeletions: boolean;
anchor: ModelPosition;
};
});
getOperationsData(): Array<OperationData>;
getOperations(): Array<Operation>;
}
export interface InsertOperationData {
type: "insert";
path: Path;
tokens: Array<ModelToken>;
}
export interface RemoveOperationData {
type: "remove";
path: Path;
howMany: number;
}
export interface SplitOperationData {
type: "split";
path: Path;
}
export interface MergeOperationData {
type: "merge";
path: Path;
}
export interface RenameOperationData {
type: "rename";
path: Path;
oldName: string;
newName: string;
}
export interface AttributeOperationData {
type: "attribute";
path: Path;
howMany: number;
key: string;
oldValue: string;
newValue: string;
}
export interface MarkerOperationData {
type: "marker";
name: string;
range: null | {
start: Path;
end: Path;
};
}
export interface UnwrapOperationData {
type: "unwrap";
path: Path;
howMany: number;
}
export interface WrapOperationData {
type: "wrap";
token: ModelElementToken;
range: {
start: Path;
end: Path;
};
}
export interface MarkedRemoveData {
type: "markedRemove";
range: {
start: Path;
end: Path;
};
}
export type OperationData = InsertOperationData | RemoveOperationData | SplitOperationData | MergeOperationData | RenameOperationData | AttributeOperationData | MarkerOperationData | UnwrapOperationData | WrapOperationData | MarkedRemoveData;
export type ModelToken = ModelElementToken | ModelTextToken;
export interface ModelElementToken {
type: "element";
element: ModelElement;
elementId: string;
/**
* Elements category.
*
* Describes how the element behaves and how it can change. It is used when comparing lists of model tokens to create a better diff.
*
* * `block` - elements like paragraphs, lists, or headings. Can be renamed. Can be created by splitting. Can be removed by merging.
* Its contents can be "moved around" by splitting or merging.
*
* * `container` - elements like blockquote. Cannot be renamed. Can be created by wrapping. Can be removed by unwrapping. Can be
* "resized" by having other elements be moved into or out of them.
*
* * `solid` - limit-like elements like table or image. Cannot be renamed, split or merged. Can be added by insertion and removed by
* deletion. If added or removed, all their content also should be treated as added or removed.
*/
category: "block" | "container" | "solid";
isStart: boolean;
limitId: string;
}
export interface ModelTextToken {
type: "text";
data: string;
parent: ModelElement | ModelDocumentFragment;
offset: number;
limitId: string;
}
export type Path = Array<number>;