Report an issue

guideComment-only mode

CKEditor 5 Collaboration Features enable users to edit the document and add their comments in real-time.

However, in many applications, the document creation workflow consist of several precisely defined steps such as: content creation, discussion, proof-reading, etc.

The users of such application may have certain roles and rights. This guide describes how to run the editor in the comment-only mode, where users are allowed to add and edit comments but not to change the document content.

# Solution overview

Read-only mode comes to mind first when describing the above business need. However, in this use case the editor cannot be in the read-only mode as comments are handled through markers whose changes are treated in the same way as typing or any other content change. It means that it is not possible to add any comments in the read-only mode.

Instead, to achieve the expected result, it will be necessary to disable all editing possibilities “by hand”. Most features use commands to change the editor content. By disabling them, you will prevent the user from changing the editor content.

# Developing comment-only mode

Follow the steps below to create a solution with the editor in the comment-only mode.

# Setting up the editor

First, make sure that you correctly installed CKEditor 5 together with collaborative editing and collaborative comments plugins.

This tutorial starts where the Collaborative comments tutorial ends, so if you do not have a working collaboration setup with comments ready yet, go there first.

Your code for the editor initialization should look similar to this:

// app.js
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';

import CollaborativeComments from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments';

ClassicEditor
    .create( document.querySelector( '.editor' ), {
        plugins: [ Essentials, Paragraph, Bold, Italic, CollaborativeComments ],
        cloudServices: {
            // PROVIDE CORRECT VALUES HERE:
            tokenUrl: 'https://example.com/cs-token-endpoint',
            uploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/',
            webSocketUrl: 'your-organization-id.cke-cs.com/ws/',
            documentId: 'commentsOnlyMode'
        },
        sidebar: {
            container: document.querySelector( '.sidebar' )
        },
        toolbar: [ 'bold', 'italic', '|', 'comment' ]
    } )
    .catch( error => console.error( error ) );

# Creating a plugin

Features should be introduced to the editor as plugins. Refer to the Creating a simple plugin guide for some general tips on creating CKEditor 5 Framework plugins.

The plugin created in this guide will be a simple one.

// commentonly.js
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

export default class CommentOnly extends Plugin {
    init() {
        // The actual code will go here.
    }
}

Enable the plugin in the editor by importing it and adding to the plugins configuration option.

# Disabling editing

Disabling a command is possible by forcing the command’s isEnabled observable property to be false:

command.on( 'change:isEnabled', () => {
    command.isEnabled = false;
}, { priority: 'lowest' } );

All the commands in the editor need to be disabled (except those added by the comments plugin):

// commentonly.js
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import CollaborativeComments from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments';

import AddCommentCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/addcommentcommand';
import AddCommentThreadCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/addcommentthreadcommand';
import RemoveCommentCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/removecommentcommand';
import RemoveCommentThreadCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/removecommentthreadcommand';

export default class CommentOnly extends Plugin {
    static get requires() {
        // Require CollaborativeComments to be loaded before this plugin initializes.
        // You need to be sure that collaborative comments commands are already available in the editor.
        return [ CollaborativeComments ];
    }

    init() {
        // These commands should stay enabled.
        const commentsCommands = [
            AddCommentCommand,
            AddCommentThreadCommand,
            RemoveCommentCommand,
            RemoveCommentThreadCommand
        ];

        // Disable commands.
        // Iterate through all the commands added to the editor.
        for ( const command of this.editor.commands.commands() ) {
            if ( commentsCommands.includes( command.constructor ) ) {
                // Do not disable commands from the comments plugin.
                continue;
            }

            // Force them to be disabled.
            command.on( 'change:isEnabled', evt => {
                command.isEnabled = false;
                evt.stop();
            }, { priority: 'highest' } );

            command.isEnabled = false;
        }
    }
}

The last step would be to disable other ways to change the editor content, such as clipboard:

const viewDocument = editor.editing.view.document;

// Prevent cutting and pasting. These actions happen during certain events.
viewDocument.on( 'cut', evt => evt.stop(), { priority: 'highest' } );
viewDocument.on( 'clipboardInput', evt => evt.stop(), { priority: 'highest' } );

// Prevent doing any changes on Delete key.
viewDocument.on( 'delete', evt => evt.stop(), { priority: 'highest' } );

At this point, the plugin is ready and the editor will work in the comment-only mode:

// commentonly.js
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';

import CollaborativeComments from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments';

import AddCommentCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/addcommentcommand';
import AddCommentThreadCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/addcommentthreadcommand';
import RemoveCommentCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/removecommentcommand';
import RemoveCommentThreadCommand from '@ckeditor/ckeditor5-collaboration/src/collaborativecomments/removecommentthreadcommand';

export default class CommentOnly extends Plugin {
    static get requires() {
        // Require CollaborativeComments to be loaded before this plugin initializes.
        // You need to be sure that collaborative comments commands are already available in the editor.
        return [ CollaborativeComments ];
    }

    init() {
        // These commands should stay enabled.
        const commentsCommands = [
            AddCommentCommand,
            AddCommentThreadCommand,
            RemoveCommentCommand,
            RemoveCommentThreadCommand
        ];

        // Disable commands.
        // Iterate through all the commands added to the editor.
        for ( const command of this.editor.commands.commands() ) {
            if ( commentsCommands.includes( command.constructor ) ) {
                // Do not disable commands from the comments plugin.
                continue;
            }

            // Force them to be disabled.
            command.on( 'change:isEnabled', evt => {
                command.isEnabled = false;
                evt.stop();
            }, { priority: 'highest' } );

            command.isEnabled = false;
        }

        const viewDocument = this.editor.editing.view.document;

        // Prevent cutting and pasting. These actions happen during certain events.
        viewDocument.on( 'cut', evt => evt.stop(), { priority: 'highest' } );
        viewDocument.on( 'clipboardInput', evt => evt.stop(), { priority: 'highest' } );

        // Prevent doing any changes on Delete key.
        viewDocument.on( 'delete', evt => evt.stop(), { priority: 'highest' } );
    }
}
// app.js
import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';

// CollaborativeEditing and CollaborativeComments have been removed as they are already required by CommentOnly.

import CommentOnly from './commentonly.js';

ClassicEditor
    .create( document.querySelector( '.editor' ), {
        plugins: [ Essentials, Paragraph, Bold, Italic, CommentOnly ],
        cloudServices: {
            // PROVIDE CORRECT VALUES HERE:
            tokenUrl: 'https://example.com/cs-token-endpoint',
            uploadUrl: 'https://your-organization-id.cke-cs.com/easyimage/upload/',
            webSocketUrl: 'your-organization-id.cke-cs.com/ws/',
            documentId: 'commentsOnlyMode'
        },
        sidebar: {
            container: document.querySelector( '.sidebar' )
        },
        toolbar: [ 'bold', 'italic', '|', 'comment' ]
    } )
    .catch( error => console.error( error ) );

# Live demo

Check out the comment-only mode in action!

# Security

Please remember that your application should be secured both on front-end and back-end. Even though the users will not be able to introduce their changes through the editor, you should still take care of preventing that in your back-end code.