@ckeditor/ckeditor5-comments
Version:
Collaborative comments feature for CKEditor 5.
1,123 lines (1,122 loc) • 42.5 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 comments/comments/commentsrepository
* @publicApi
*/
import { PendingActions, ContextPlugin, Editor, type Context } from 'ckeditor5/src/core.js';
import { Collection } from 'ckeditor5/src/utils.js';
import { Users, type User } from 'ckeditor5-collaboration/src/collaboration-core.js';
import { CommentThreadController } from './ui/commentthreadcontroller.js';
import '../../theme/comment.css';
import '../../theme/commentthread.css';
import '../../theme/commentinput.css';
import { Annotation, type AnnotationTarget } from '../annotations/annotation.js';
import { Annotations } from '../annotations/annotations.js';
import type { BaseCommentThreadView } from './ui/view/basecommentthreadview.js';
/**
* Stores the list of {@link module:comments/comments/commentsrepository~CommentThread}
* and provides event-driven API for managing them. It is also responsible for using the comments adapter
* to communicate with the data source.
*
* {@link module:comments/comments/commentsrepository~CommentsRepository} is a context plugin.
* It can be added to a context or to an editor. Add it to the context configuration if you use
* {@link module:core/context~Context} in your integration.
*
* The event-driven API makes it possible to attach a listener to each action that changes comment data.
* Using different event priorities allows to attach an action before the main action ('low' priority)
* or after the main action ('high' priority). It works very similar to
* {@link module:utils/observablemixin~Observable#decorate}.
*
* Sample usage:
*
* ```ts
* // Get the comments repository:
* const commentsRepository = editor.plugins.get( 'CommentsRepository' );
*
* // Create a new, empty comment thread on a DOM form field element:
* commentsRepository.openNewCommentThread( { channelId, target: formFieldElement } );
*
* // Get all comment threads:
* commentsRepository.getCommentThreads();
*
* // Set the adapter:
* commentsRepository.adapter = {
* // ...
* };
* ```
*
* For more information about the comments adapter see {@link module:comments/comments/commentsrepository~CommentsAdapter}.
*/
export declare class CommentsRepository extends ContextPlugin {
/**
* The currently active comment thread.
* An annotation with this thread will be marked as active.
*
* @observable
*/
activeCommentThread: CommentThread | null;
/**
* @inheritDoc
*/
static get requires(): readonly [typeof Annotations, typeof PendingActions, typeof Users];
/**
* @inheritDoc
*/
static get pluginName(): "CommentsRepository";
/**
* @inheritDoc
*/
static get isOfficialPlugin(): true;
/**
* @inheritDoc
*/
static get isPremiumPlugin(): true;
/**
* @inheritDoc
*/
constructor(context: Context | Editor);
/**
* @inheritDoc
*/
init(): void;
/**
* An adapter object that should communicate with the data source to fetch or save the comments data.
*/
set adapter(adapter: CommentsAdapter);
get adapter(): CommentsAdapter;
/**
* Adds a new comment thread.
*
* When a target is provided, the comment annotation will be attached to this target.
*
* Use this method to load the comments data during the editor initialization
* if you do not use the adapter integration.
*
* **Note:** This method fires the {@link #event:addCommentThread} event and the default behavior
* is added as a `'normal'` priority listener. It makes it possible to cancel the method
* or call some custom code before or after the default behavior is executed.
*
* **Note:** The comments adapter will send the data only if `commentThreadData.comments`
* is not empty and `commentThreadData.isFromAdapter` is set to `false`.
*
* See also `CommentsRepository#openNewCommentThread()`.
*
* An example of loading a comment thread on editor initialization:
*
* ```ts
* commentsRepository.addCommentThread( {
* threadId: 'thread-id',
* channelId: 'channel-id',
* comments: [
* {
* commentId: 'comment-1', // String
* authorId: 'author-id', // String
* content: 'First comment', // String
* createdAt: new Date( ... ) // Date instance
* },
* // ...
* ],
* target: () => ...,
* // Added during initialization, so do not call the adapter:
* isFromAdapter: true
* } );
* ```
*
* See also {@link module:comments/comments/commentsrepository~CommentThread#setAttribute} and
* {@link module:comments/comments/commentsrepository~CommentThread#removeAttribute}.
*
* @fires addCommentThread
* @param data The data of the comment thread to add.
* @param data.channelId The ID of a document or context to which the comment thread is added.
* @param data.threadId The ID of the added comment thread.
* @param data.comments Comments in the comment thread. See the example above.
* @param data.unlinkedAt The date when the content related to the comment thread was lost (usually, the commented content was
* removed from the document).
* @param data.resolvedAt The date when the comment thread has been resolved.
* @param data.resolvedBy The ID of user who resolved the comment thread.
* @param data.target The target that the comment
* balloon should be attached to. If a function is passed, it should return a DOM element or `Rect`.
* @param data.context The text on which the comment thread was created on or similar contextual information for the comment thread.
* To be displayed as an additional hint for archived comment threads.
* @param data.attributes Custom comment attributes.
* @param data.isResolvable Indicates whether the comment thread can become resolved.
* Set this flag to `false` to disable the possibility of resolving given comment thread.
* @param data.isSubmitted Indicates whether the comment thread has been submitted.
* Comment thread is submitted after adding the first comment, however, in some cases,
* it could be necessary to manage it in a custom way (e.g. track changes).
* @param data.isFromAdapter A flag describing whether the added data
* comes from an adapter (`true`) or is a new data (`false`). If set to `true`, the
* comment data will be added only in the editor and will not be sent to the adapter.
* @returns The added comment thread.
*/
addCommentThread({ channelId, threadId, comments, unlinkedAt, resolvedAt, resolvedBy, target, context, attributes, isResolvable, isSubmitted, isFromAdapter }?: Partial<AddCommentThreadEventData>): CommentThread | undefined;
/**
* Creates a new, empty comment thread.
*
* Displays a new comment annotation attached to the target and focuses the comment editor.
* When the comment data is submitted, the comment thread is added to the editor
* and sent to the adapter.
*
* Use this method to start a new comment thread after a user performed an action
* (clicked a button, etc.).
*
* @param commentThreadData The data of the comment thread to add.
* @returns The created comment thread or `null` if there was a problem
* creating the thread (for example, if the comments repository was in the read-only mode).
* @fires addCommentThread
*/
openNewCommentThread({ channelId, threadId, target, context, isResolvable }: AddCommentThreadEventData): CommentThread | null;
/**
* Checks if a comment thread with a given ID is added to the repository.
*/
hasCommentThread(threadId: string): boolean;
/**
* Updates an existing comment thread. See also
* {@link module:comments/comments/commentsrepository~CommentThread#setAttribute} and
* {@link module:comments/comments/commentsrepository~CommentThread#removeAttribute}.
*
* @param data The data of the comment thread to add.
* @returns The updated comment thread.
* @fires updateCommentThread
*/
updateCommentThread({ channelId, threadId, context, unlinkedAt, attributes, isFromAdapter }: UpdateCommentThreadEventData): CommentThread;
/**
* Returns comment thread of given id.
*/
getCommentThread(threadId: string): CommentThread | undefined;
/**
* Gets the comment thread data using the adapter and adds the thread to the editor.
*
* When the comment thread is already present in the repository,
* then the adapter will not be used but the result will be asynchronous as well.
*/
fetchCommentThread({ channelId, threadId }?: BaseCommentThread): Promise<CommentThread | undefined>;
getCommentThreads(data?: {
channelId?: string | symbol;
skipNotAttached?: boolean;
skipEmpty?: boolean;
toJSON?: false;
}): Array<CommentThread>;
getCommentThreads(data: {
channelId?: string | symbol;
skipNotAttached?: boolean;
skipEmpty?: boolean;
toJSON: true;
}): Array<CommentThreadDataJSON>;
/**
* Returns the annotation associated with the given comment thread.
*/
getAnnotationForCommentThread(thread: CommentThread): Annotation | null;
/**
* Returns the comment thread associated with the given annotation.
*/
getCommentThreadForAnnotation(annotation: Annotation): CommentThread | null;
/**
* Marks a comment thread with the given ID as active.
* When `threadId` is `null`, the currently active comment thread will be deactivated.
*/
setActiveCommentThread(threadId: string | null): void;
/**
* Changes the read-only state for comment threads.
*
* When the value is `true` then all comment threads will be switched to read-only,
* when the value is `false` then all comment threads will be switched to editing mode.
*
* Optionally new state can be applied to a comment threads limited to a given channel.
* This function has precedence over any permission settings.
*/
switchReadOnly(value: boolean, channelId?: string | symbol): void;
/**
* Returns `true` if a given channel is set to read-only mode, returns `false` otherwise.
*/
isReadOnly(channelId: string | symbol): boolean;
/**
* Create an instance of the {@link module:comments/comments/ui/commentthreadcontroller~CommentThreadController} class.
*
* @param commentThreadModel Comment thread model.
* @param commentThreadView Comment thread view.
*/
createCommentThreadController(commentThreadModel: CommentThread, commentThreadView: BaseCommentThreadView): CommentThreadController;
/**
* Gets permissions set for repository (or default if permissions was not set).
*/
getPermissions(channelId?: string | symbol): CommentPermissionsConfig;
}
export interface CommentPermissionsConfig {
/**
* Allows for removing other users' threads.
*/
admin: boolean;
/**
* Allows for editing and removing any comments created by other users.
*/
modifyAll: boolean;
/**
* Allows for adding new comments as well as editing and removing comments created by this user.
*/
write: boolean;
/**
* Allows for resolving and reopening comment threads.
*/
resolve: boolean;
}
declare const CommentThread_base: {
new (): import("ckeditor5/src/utils.js").Observable;
prototype: import("ckeditor5/src/utils.js").Observable;
};
/**
* Comment thread representation.
* Stores a list of {@link module:comments/comments/commentsrepository~Comment `Comments`}.
*/
export declare class CommentThread extends /* #__PURE__ -- @preserve */ CommentThread_base {
/**
* Informs if the comment thread is in read-only state (`true`) or not (`false`).
*
* @observable
*/
isReadOnly: boolean;
/**
* Informs if the comment thread can be removed by the local user.
*
* @observable
*/
isRemovable: boolean;
/**
* Informs if a user has permission to add a new comment to the comment thread.
*
* @observable
*/
canComment: boolean;
/**
* Date when the comment thread has been archived.
*
* Comment threads become archived after they are {@link #resolvedAt resolved} or {@link #unlinkedAt unlinked}.
* If the comment thread is resolved and/or unlinked, this value is set to the earliest of the dates. Otherwise, it is `null`.
*
* @observable
*/
archivedAt: Date | null;
/**
* The date when the content related to the comment thread was lost (usually, the commented content was removed from the document).
*
* @observable
*/
unlinkedAt: Date | null;
/**
* User id which resolved the comment thread.
*
* @observable
*/
resolvedBy: User | null;
/**
* Date when the comment thread has been resolved.
*
* @observable
*/
resolvedAt: Date | null;
/**
* Informs if the comment thread is resolved.
*
* @observable
*/
readonly isResolved: boolean;
/**
* Custom comment thread attributes. See also {@link #setAttribute} and {@link #removeAttribute}.
*
* @observable
*/
attributes: Record<string, unknown>;
/**
* The channel where the comment thread was created.
*/
channelId: string | symbol;
/**
* The comment thread ID.
*/
id: string;
/**
* A collection of {@link module:comments/comments/commentsrepository~Comment}s belonging to this thread.
*
* @readonly
*/
readonly comments: Collection<Comment>;
constructor(commentsRepository: CommentsRepository, data: {
channelId: string | symbol;
id: string;
context: CommentThreadContext;
attributes: Record<string, unknown>;
unlinkedAt: Date | null;
resolvedAt: Date | null;
resolvedBy: User | null;
isResolvable: boolean;
isSubmitted: boolean;
});
/**
* Sum of {@link module:comments/comments/commentsrepository~Comment#weight weights of all comments} in this thread.
*/
get weight(): number;
/**
* The number of {@link module:comments/comments/commentsrepository~Comment comments} in the comment thread.
*/
get length(): number;
/**
* Informs if the comment thread is attached to any target at the moment.
*/
get isAttached(): boolean;
/**
* Informs if the comment thread has been submitted.
*/
get isSubmitted(): boolean;
/**
* Submits the locally created comment thread draft.
*/
submit(): void;
/**
* Updates the unlinked date.
*/
setUnlinkedAt(unlinkedAt: Date | null): void;
/**
* Resolves the comment thread.
*/
resolve({ resolvedAt, resolvedBy, isFromAdapter }?: {
resolvedAt?: Date | undefined;
resolvedBy?: string | undefined;
isFromAdapter?: boolean | undefined;
}): void;
/**
* Reopens the resolved comment thread.
*/
reopen({ isFromAdapter }?: {
isFromAdapter?: boolean | undefined;
}): void;
/**
* Set the context on the comment thread.
* This method should be called only when the context has been not set during initialization.
*
* @param context Text context of comment thread.
*/
setContext(context: CommentThreadContext): void;
/**
* Adds attribute to the comment thread.
*
* Comment thread attributes are custom data that can be set and used by features
* built around comments. Use it to store your feature data with other comment thread data.
* You can also group multiple values in an object, using dot notation:
*
* ```ts
* commentThread.setAttribute( 'customData.isImportant', true );
* ```
*
* Attributes set on the comment can be accessed through the `attribute` property:
*
* ```ts
* const isImportant = commentThread.attributes.customData.isImportant;
* ```
*
* You can also observe the `attributes` property or bind other properties to it:
*
* ```ts
* myObj.bind( 'customData' ).to( commentThread, 'attributes', attributes => attributes.customData );
* ```
*
* Whenever `setAttribute()` or `removeAttribute()` is called, the `attributes` property
* is re-set and observables are refreshed.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:updateCommentThread
* @param name Attribute name.
* @param value Attribute value.
*/
setAttribute(name: string, value: unknown): void;
/**
* Removes a comment attribute.
*
* See also {@link module:comments/comments/commentsrepository~CommentThread#setAttribute}.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:updateCommentThread
* @param name The attribute name.
*/
removeAttribute(name: string): void;
/**
* Removes comment thread.
*
* **Note** This method is event-driven. It means it fires an event then a normal priority listener catches
* it and executes an action. It makes it possible to add some actions before and after method will be executed.
*
* @fires module:comments/comments/commentsrepository~RemoveCommentThreadEvent
*/
remove({ isFromAdapter }?: {
isFromAdapter?: boolean | undefined;
}): void;
/**
* Creates comment annotations and displays it attached to the given target.
*
* @returns Created annotation.
*/
attachTo(target: AnnotationTarget): Annotation;
/**
* Creates a new comment inside the comment thread.
*
* **Note** This method is event-driven. It means it fires an event then a normal priority listener catches
* it and executes an action. It makes it possible to add some actions before and after method will be executed.
*
* See also
* {@link module:comments/comments/commentsrepository~Comment#setAttribute} and
* {@link module:comments/comments/commentsrepository~Comment#removeAttribute}.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:addComment
* @param data Data object.
*/
addComment(data: CommentData): void;
/**
* Returns comment of given id.
*/
getComment(commentId: string): Comment | null;
toJSON(): CommentThreadDataJSON;
}
declare const Comment_base: {
new (): import("ckeditor5/src/utils.js").Observable;
prototype: import("ckeditor5/src/utils.js").Observable;
};
/**
* Single comment representation. A part of a {@link module:comments/comments/commentsrepository~CommentThread commentThread}.
*/
export declare class Comment extends /* #__PURE__ -- @preserve */ Comment_base {
/**
* When is set to `true`, editing the comment is blocked.
*
* @observable
*/
readonly isEditable: boolean;
/**
* When is set to `false`, removing the comment is blocked.
*
* @observable
*/
readonly isRemovable: boolean;
/**
* The read-only state inherited from the parent {@link module:comments/comments/commentsrepository~CommentThread}.
* When is set to `true`, then removing and editing the comment thread is blocked.
*
* In contrast to {@link #isEditable} and {@link #isRemovable}, this state can be used to
* hide some UI parts instead of temporarily disabling them.
*
* @observable
*/
readonly isReadOnly: boolean;
/**
* The comment content.
*/
content: string;
/**
* Date when the comment was made.
*
* Usually the same as {@link #createdAt `createdAt`} but may be different in some cases
* (e.g. when comment was added from an external source).
*
* @observable
*/
authoredAt: Date;
/**
* The date when the comment thread was resolved or `null` if it is not resolved.
*
* @observable
*/
resolvedAt: Date | null;
/**
* Custom comment attributes. See also {@link #setAttribute} and {@link #removeAttribute}.
*
* @observable
*/
attributes: Record<string, any>;
/**
* The comment ID.
*/
readonly id: string;
/**
* The ID of the comment thread that contains this comment.
*/
readonly threadId: string;
/**
* The comment author.
*/
readonly author: User;
/**
* The user which saved the comment data in the database.
*
* Usually the same as author but may be different in some cases (e.g. when comment was added from an external source).
*/
readonly creator: User;
/**
* The flag indicating whether the comment comes from an external source.
*/
readonly isExternal: boolean;
/**
* Date when the comment was saved in the database.
*/
createdAt: Date;
/**
* @param commentsRepository
* @param data Configuration object.
* @param data.id Comment id.
* @param data.threadId Comment thread id.
* @param data.content Comment content.
* @param data.author Comment author.
* @param data.creator The user which saved the comment data.
* Usually the same as author but may be different in some cases (e.g. when comment was added from an external source).
* @param data.createdAt Date when the comment was saved in the database.
* @param data.authoredAt Date when the comment was made.
* @param data.attributes Custom comment attributes. See also
* {@link module:comments/comments/commentsrepository~Comment#setAttribute} and
* {@link module:comments/comments/commentsrepository~Comment#removeAttribute}.
*/
constructor(commentsRepository: CommentsRepository, data: {
id: string;
threadId: string;
content: string;
author: User;
creator: User;
createdAt: Date;
authoredAt: Date;
attributes: Record<string, unknown>;
});
/**
* The comment weight.
*
* It is equal to the length of the comment content, however it is never smaller than `200`.
* This limit is set to avoid a long list of very short not collapsed comments.
*/
get weight(): number;
/**
* Updates the comment with provided data.
*
* **Note:** This method fires the {@link module:comments/comments/commentsrepository~CommentsRepository#event:updateComment}
* event and the default behavior is added as a normal priority listener. It makes it
* possible to cancel the method or call some custom code before or after the default
* behavior is executed.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:updateComment
* @param data Data object.
* @param data.content Comment content.
* @param data.createdAt Creation date.
* @param data.attributes Custom comment attributes. See also
* {@link module:comments/comments/commentsrepository~Comment#setAttribute} and
* {@link module:comments/comments/commentsrepository~Comment#removeAttribute}.
* @param data.isFromAdapter
*/
update(data: UpdateCommentData): void;
/**
* Adds attribute to the comment.
*
* Comment attributes are custom data that can be set and used by features
* built around comments. Use it to store your feature data with other comment data.
*
* comment.setAttribute( 'isImportant', true );
*
* You can group multiple values in an object, using dot notation:
*
* comment.setAttribute( 'customData.type', 'image' );
* comment.setAttribute( 'customData.src', 'foo.jpg' );
*
* Attributes set on the comment can be accessed through the `attribute` property:
*
* const isImportant = comment.attributes.isImportant;
* const type = comment.attributes.customData.type;
*
* You can also observe the `attributes` property or bind other properties to it:
*
* myObj.bind( 'customData' ).to( comment, 'attributes', attributes => attributes.customData );
*
* Whenever `setAttribute()` or `removeAttribute()` is called, the `attributes` property
* is re-set and observables are refreshed.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:updateComment
* @param name Attribute name.
* @param value Attribute value.
*/
setAttribute(name: string, value: unknown): void;
/**
* Removes a comment attribute.
*
* See also {@link module:comments/comments/commentsrepository~Comment#setAttribute}.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:updateComment
* @param name The attribute name.
*/
removeAttribute(name: string): void;
/**
* Removes the comment.
*
* **Note:** This method fires the {@link module:comments/comments/commentsrepository~CommentsRepository#event:updateComment}
* event and the default behavior is added as a normal priority listener. It makes it
* possible to cancel the method or call some custom code before or after the default
* behavior is executed.
*
* @fires module:comments/comments/commentsrepository~CommentsRepository#event:removeComment
* @param data.isFromAdapter A flag describing whether the comment was
* updated from an adapter (`true`) or from the UI (`false`). If set to `true`, the adapter will not be called.
*/
remove(data?: {
isFromAdapter?: boolean;
}): void;
toJSON(): CommentDataJSON;
/**
* Destroys the comment instance.
*/
destroy(): void;
}
export type CommentThreadContext = null | {
type: string;
value: unknown;
};
/**
* @param channelId The ID of a document or context that the comment thread is handled.
* @param threadId The ID of the comment thread.
* @param isFromAdapter A flag describing whether the operation was done on a remote client (`true`) or a local one (`false`).
*/
export interface BaseCommentThread {
channelId: string | symbol;
threadId: string;
isFromAdapter?: boolean;
}
/**
* @param commentId The comment ID.
*/
export interface BaseComment extends BaseCommentThread {
commentId: string;
}
/**
* @param content The comment content.
* @param attributes Comment custom attributes.
*/
export interface BaseCommentData {
content: string;
attributes: Record<string, any>;
}
/**
* Fired whenever a comment thread is added to the comments repository.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* ```ts
* const channelId = 'foo';
*
* commentsRepository.on( `addCommentThread:${ channelId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#addCommentThread
*/
export type AddCommentThreadEvent = {
name: string;
args: [Required<AddCommentThreadEventData>];
};
/**
* @param context The comment ID.
* @param attributes Comment thread custom attributes.
* @param resolvedAt ID of the comment author.
* @param resolvedBy The comment creation date.
*/
export type CommentThreadData = BaseCommentThread & Partial<{
context: CommentThreadContext;
attributes: Record<string, any>;
unlinkedAt: Date | null;
resolvedAt: Date | null;
resolvedBy: string | null;
}>;
/**
* @param comments Comments in the comment thread.
* @param target The target that the comment balloon should be attached to.
*/
export type AddCommentThreadEventData = CommentThreadData & {
comments?: Array<CommentData>;
target?: AnnotationTarget;
isResolvable?: boolean;
isSubmitted?: boolean;
};
/**
* Fired whenever a new comment thread is submitted and occurs after creating the first comment.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* ```ts
* const channelId = 'foo';
*
* commentsRepository.on( `submitCommentThread:${ channelId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#submitCommentThread
*/
export type SubmitCommentThreadEvent = {
name: string;
args: [BaseCommentThread];
};
/**
* Fired whenever a comment thread is updated in comments repository.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* @eventName ~CommentsRepository#updateCommentThread
*/
export type UpdateCommentThreadEvent = {
name: string;
args: [UpdateCommentThreadEventData];
};
export type UpdateCommentThreadEventData = Omit<CommentThreadData, 'resolvedAt' | 'resolvedBy'>;
/**
* Fired whenever a comment thread is resolved.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* ```ts
* const channelId = 'foo';
*
* commentsRepository.on( `resolveCommentThread:${ channelId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#resolveCommentThread
*/
export type ResolveCommentThreadEvent = {
name: string;
args: [ResolveCommentThreadEventData];
};
export type ResolveCommentThreadEventData = BaseCommentThread & {
resolvedAt: Date | null;
resolvedBy: string | null;
};
/**
* Fired whenever a comment thread is reopened.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* ```ts
* const channelId = 'foo';
*
* commentsRepository.on( `reopenCommentThread:${ channelId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#reopenCommentThread
*/
export type ReopenCommentThreadEvent = {
name: string;
args: [BaseCommentThread];
};
/**
* Fired whenever a comment thread is removed from the comments repository.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* ```ts
* const channelId = 'foo';
*
* commentsRepository.on( `removeCommentThread:${ channelId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#removeCommentThread
*/
export type RemoveCommentThreadEvent = {
name: string;
args: [BaseCommentThread];
};
/**
* Fired whenever a comment is added.
*
* The event name includes `channelId` so it is possible to listen only
* on changes happening in the specified channel.
*
* It is also possible to listen to events from the given thread ID by appending `:[threadId]` part to the event name
*
* ```ts
* const channelId = 'foo';
* const threadId = '1234';
*
* commentsRepository.on( `addComment:${ channelId }:${ threadId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#addComment
*/
export type AddCommentEvent = {
name: string;
args: [CommentEventData];
};
/**
* @param commentId The comment ID.
* @param authorId ID of the comment author.
* @param createdAt The comment creation date.
* @param isFromAdapter A flag describing whether the comment was updated on a remote client (`true`) or a local one (`false`).
*/
export type CommentData = BaseCommentData & {
commentId?: string;
authorId: string;
createdAt: Date;
isFromAdapter?: boolean;
};
export type CommentEventData = BaseCommentThread & CommentData;
/**
* Fired whenever a comment is updated.
*
* The event name includes `channelId` so it is possible to listen only
* to changes happening in the specified channel.
*
* It is also possible to listen to events from the given thread ID by appending `:[threadId]` part to the event name
*
* ```ts
* const channelId = 'foo';
* const threadId = '1234';
*
* commentsRepository.on( `updateComment:${ channelId }:${ threadId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#updateComment
*/
export type UpdateCommentEvent = {
name: string;
args: [UpdateCommentEventData];
};
export type UpdateCommentData = Partial<CommentEventData>;
export type UpdateCommentEventData = UpdateCommentData & BaseComment;
/**
* Fired whenever a comment is removed.
*
* The event name includes `channelId` so it is possible to listen only
* to changes happening in the specified channel.
*
* It is also possible to listen to events from the given thread ID by appending `:[threadId]` part to the event name
*
* ```ts
* const channelId = 'foo';
* const threadId = '1234';
*
* commentsRepository.on( `removeComment:${ channelId }:${ threadId }`, ( evt, data ) => {
* console.log( evt, data );
* } );
* ```
*
* @eventName ~CommentsRepository#removeComment
*/
export type RemoveCommentEvent = {
name: string;
args: [BaseComment];
};
export type CommentDataJSON = Omit<CommentData, 'isFromAdapter'>;
export type CommentThreadDataJSON = {
threadId: string;
context: CommentThreadContext;
unlinkedAt: Date | null;
resolvedAt: Date | null;
resolvedBy: string | null;
archivedAt: Date | null;
comments: Array<CommentDataJSON>;
attributes: Record<string, unknown>;
};
/**
* Comments adapter.
*
* The comments adapter is an object that communicates asynchronously with the data source to fetch or save
* the comment data. It is used internally by the comments feature whenever a comment is loaded, created or deleted.
* The adapter is optional. You might need to provide it if you are {@glink features/collaboration/comments/comments-integration
* using the comments feature without real-time collaboration}.
* To set the adapter, overwrite the `CommentsRepository#adapter` property.
*/
export interface CommentsAdapter {
/**
* Called whenever a new comment thread is created.
*
* The object which is passed as a parameter can contain the following properties:
* * channelId: string | symbol;
* * threadId: string;
* * context?: {@link module:comments/comments/commentsrepository~CommentThreadContext CommentThreadContext};
* * comments?: Array<{@link module:comments/comments/commentsrepository~CommentDataJSON CommentDataJSON}>;
* * resolvedAt?: Date | null;
* * resolvedBy?: string | null;
* * attributes?: Record<string, any> | null;
*
* It should return a promise that resolves with the new comment thread data.
* The resolved data object should contain the following properties:
* * threadId: string;
* * comments: Array<\{ commentId: string; createdAt: Date; \}>;
*/
addCommentThread: (data: Omit<CommentThreadData, 'isFromAdapter'> & {
comments: Array<CommentDataJSON>;
}) => Promise<{
threadId: string;
comments: Array<{
commentId: string;
createdAt: Date;
}>;
}>;
/**
* Called when the editor needs the data for a comment thread.
*
* It should return a promise that resolves with the comment thread data.
* The resolved data object should contain the following properties:
* * threadId: string;
* * comments: Array<\{ commentId?: string; authorId: string; createdAt: Date; content: string; attributes: Record<string, any>; \}>;
* * resolvedAt?: Date | null;
* * resolvedBy?: string | null;
* * attributes: Record<string, unknown>;
*
* @param data.channelId The ID of the document or context to which the comment is added.
* @param data.threadId The ID of the comment thread that the comment is added to.
*/
getCommentThread: (data: Omit<BaseCommentThread, 'isFromAdapter'>) => Promise<{
threadId: string;
comments: Array<CommentData>;
resolvedAt?: Date | null;
resolvedBy?: string | null;
attributes: Record<string, unknown>;
} | null>;
/**
* Called each time the user changes the existing comment thread.
*
* Keep in mind that for security reasons, the `authorId`, `createdAt`, `resolvedBy` and `resolvedAt` properties
* are not passed in the `updateCommentThread()` call and you should not set them as a result of this call.
*
* It updates the comment data in the database and returns a promise
* that will be resolved when the update is completed.
*
* The object which is passed as a parameter can contain the following properties:
* * channelId: string | symbol;
* * threadId: string;
* * context?: {@link module:comments/comments/commentsrepository~CommentThreadContext};
* * attributes?: Record<string, any> | null;
*/
updateCommentThread: (data: Omit<UpdateCommentThreadEventData, 'isFromAdapter'>) => Promise<void>;
/**
* Called each time the user resolves a comment thread.
*
* Should set `resolvedAt` and `resolvedBy` properties in your database and should resolve with an object
* containing these two properties and returns a promise that will be resolved when the operation is completed.
*
* The resolved data object should contain the following properties:
* * threadId: string;
* * resolvedAt: Date;
* * resolvedBy: string;
*
* @param data.channelId The ID of the document or context that the comment thread is removed from.
* @param data.threadId The ID of the thread to remove.
*/
resolveCommentThread: (data: Omit<BaseCommentThread, 'isFromAdapter'>) => Promise<{
threadId: string;
resolvedAt: Date;
resolvedBy: string;
}>;
/**
* Called when the user reopens a resolved comment thread.
*
* Should set `resolvedAt` and `resolvedBy` properties to `null` in your database and returns a promise
* that will be resolved when the operation is completed.
*
* @param data.channelId The ID of the document or context that the comment thread is removed from.
* @param data.threadId The ID of the thread to remove.
*/
reopenCommentThread: (data: Omit<BaseCommentThread, 'isFromAdapter'>) => Promise<void>;
/**
* Called each time the user removes a comment thread.
*
* It should return a promise that resolves when the thread is removed.
*
* @param data.channelId The ID of the document or context that the comment thread is removed from.
* @param data.threadId The ID of the thread to remove.
*/
removeCommentThread: (data: Omit<BaseCommentThread, 'isFromAdapter'>) => Promise<void>;
/**
* Called each time the user adds a new comment to a thread.
*
* It saves the comment data in the database and returns a promise
* that should get resolved when the save is completed.
*
* If the promise resolves with an object with the `createdAt` property, the
* comment property will be updated in the comment in the editor.
* This is to update the comment data with the server-side information.
*
* The `data` object does not expect the `authorId` property.
* For security reasons, the author of the comment should be set
* on the server side.
*
* The `data` object does not expect the `createdAt` property either.
* You should use the server-side time generator to ensure that all users
* see the same date.
*
* It is recommended to stringify the `data.attributes` value to JSON
* and to save it as a string in your database and then to parse the
* value from JSON when loading comments.
*
* The object which is passed as a parameter can contain the following properties:
* * channelId: string | symbol;
* * threadId: string;
* * commentId: string;
* * content: string;
* * attributes: Record<string, any>;
*
* The resolved data object should contain the following properties:
* * commentId: string;
* * createdAt: Date;
*
* @param data.channelId The ID of the document or context to which the comment is added.
* @param data.threadId The ID of the comment thread that the comment is added to.
* @param data.commentId The comment ID.
* @param data.content The comment content.
* @param data.attributes Comment custom attributes.
*/
addComment: (data: Omit<BaseComment, 'isFromAdapter'> & BaseCommentData) => Promise<{
commentId: string;
createdAt: Date;
}>;
/**
* Called each time the user changes the existing comment.
*
* It updates the comment data in the database and returns a promise
* that will be resolved when the update is completed.
*
* Keep in mind that the `data` parameter only contains the
* properties of a comment that have changed.
*
* The object which is passed as a parameter can contain the following properties:
* * channelId: string | symbol;
* * threadId: string;
* * commentId: string;
* * content?: string;
* * attributes?: Record<string, any>;
*
* @param data.channelId The ID of the document or context where the comment is updated.
* @param data.threadId The ID of the comment thread where the comment is updated.
* @param data.commentId The ID of the comment to update.
* @param data.content The new content of the comment.
* @param data.attributes Custom comment attributes.
*/
updateComment: (data: Omit<BaseComment, 'isFromAdapter'> & Partial<BaseCommentData>) => Promise<void>;
/**
* Called each time the user removes a comment from the thread.
*
* It removes the comment from the database and returns a promise
* that will be resolved when the removal is completed.
*
* @param data.channelId The ID of the document or context that the comment is removed from.
* @param data.threadId The ID of the comment thread that the comment is removed from.
* @param data.commentId The ID of the comment to remove.
*/
removeComment: (data: Omit<BaseComment, 'isFromAdapter'>) => Promise<void>;
}
export {};