Changelog

All changes in the package are documented at https://github.com/ckeditor/ckeditor5/blob/master/CHANGELOG.md.

Changes for the past releases are available below.

26.0.0 (2021-03-03)

Bug fixes

Other changes

Localization updates

Translations to the Dutch language were updated.

Released packages

Check out the Versioning policy guide for more information.

Released packages (summary)

Other releases:

25.0.0 (2021-01-27)

MAJOR BREAKING CHANGES ℹ️

See Changes in the Annotations API for more information.

MINOR BREAKING CHANGES ℹ️

See Changes in the Annotations API for more information.

Features

Other changes

Localization updates

Translations to the Dutch language were updated.

Released packages

Check out the Versioning policy guide for more information.

Released packages (summary)

Major releases (contain major breaking changes):

Other releases:

Changes in the Annotations API

The entire annotations API was redesigned in order to support multiple annotation UIs at the same time. A good example of this is an idea of displaying comments in the sidebar while showing suggestions from track changes in inline balloons when their corresponding suggestions are active. Due to that, some architectural changes were made and quite a lot of breaking changes were introduced with this release. See the migration guide below to check how to adapt to the changes.

Annotations migration guide

Conceptual and architectural changes

  • The new annotations API allows for activating (attaching) multiple annotation UIs at the same time. To allow multiple UIs at the same time, the annotation filtering function must be registered during the annotation UI activation. Though, still, one annotation can be handled only by one annotation UI at the same time.
  • New annotations API allows for setting multiple active annotations at the same time (max one per each annotation UI), so at some point more than one annotation can be active for various annotation UIs.
  • An annotation UI is now activated with its own collection of filtered annotations and became responsible for reacting to more events. This allows for more customization possibilities, however, unfortunately, it comes with more code needed to be written for the custom annotation UI class. After the changes, an annotation UI is responsible for:
    • Displaying the annotation.
    • Marking the annotation as active when it should be activated and propagating this change via an observable property.
    • Reacting to editor events (though this is planned to be changed and simplified in the future).
    • Reacting to focus changes in the annotation collection.
    • Handling newly added and removed annotations.
    • Handling the annotation activation and deactivation from external places via the setActiveAnnotation() method.
  • The Annotations class was split to the new Annotations class, which is a global collection of annotations, and the new AnnotationsUIs class, which is mainly responsible for registering and activating annotation UIs.
  • In place where the AnnotationView had been used, the new Annotation class instance is used and it exposes mainly the following properties:
    • target - The target element to which the annotation should be bound. It can be a Rect instance or an HTML Element.
    • view - The AnnotationView instance.
    • type - The type of the annotation.
    • isActive - A property that determines if the annotation view and annotation inner views are active or not. It should be changed by the annotation UI when it changes the active annotation.

The Sidebar class stopped operating on the global collection of annotations. From now, the Annotation UI that is responsible for displaying the sidebar should provide the sidebar with its collection of annotations and inform about possible actions with the new rearrange() and refresh() methods.

The EditorAnnotations started firing events instead of manipulating the global collection of annotations. From now on, every annotation UI needs to create its own integration with this class. This may change in the future as it complicates the implementation of the custom UI.

Code migration examples

Registering and activating annotation UIs

Before:

const annotations = editor.plugins.get( 'Annotations' );

annotations.register( 'myCustomUI', myCustomUI );
annotations.switchTo( 'myCustomUI' );

// Activate and deactivate the UI.
annotations.attach( 'myCustomUI' );
annotations.detach( 'myCustomUI' );

After:

const annotationsUIs = editor.plugins.get( 'AnnotationsUIs' );

annotationsUIs.register( 'myCustomUI', myCustomUI );
annotationsUIs.switchTo( 'myCustomUI' );

// Activate and deactivate the UI.
annotationsUIs.activate( 'myCustomUI' );
annotationsUIs.deactivate( 'myCustomUI' );

// Activate two different UIs for comments and suggestions.
annotationsUIs.activate( 'wideSidebar', annotation => annotation.type === 'comment' );
annotationsUIs.activate( 'inline', annotation => annotation.type !== 'comment' );
annotationsUIs.deactivateAll();
Using global collection of annotations and active annotations

Before:

const annotations = editor.plugins.get( 'Annotations' );

// An annotation view or `null`.
const activeAnnotationView = annotations.activeView;

// A collection of annotation views.
const annotationViewCollection = annotations.items;

// Adding an annotation to the collection.
const target = new Rect( { left: 0, top: 0 } );
annotations.add( innerView, target );

// Removing an annotation based on the inner view.
annotations.remove( innerView );

After:

const annotations = editor.plugins.get( 'Annotations' );

// A set of active annotations.
const activeAnnotations = annotations.activeAnnotations;

// An array of active annotation views.
Array.from( activeAnnotations, annotation => annotation.view );

// A collection of annotations (`Annotation` class items).
const annotationCollection = annotations.collection;

// Adding an annotation to the collection.
annotations.add( new Annotation( {
    view: new AnnotationView( innerView ),
    target: new Rect( { left: 0, top: 0 } ),
    type: 'comment' // The type is used only for the AnnotationsUIs filtering mechanism.
} ) );

// Removing an annotation based on the inner view.
const annotation = annotations.getByInnerView( innerView );
annotations.remove( annotation );
Creating a custom Annotations UI

Before:

class CustomAnnotationUI {
    attach() {
        const annotations = this.editor.plugins.get( 'Annotations' );

        // The code responsible for displaying annotations
        // based on the global collection of annotations.
    }

    detach() {
        // The code responsible for hiding the UI and detaching
        // listeners from the global annotation collection.
    }
}

After:

class CustomAnnotationUI extends ContextPlugin {
    constructor() {
        this.set( 'activeAnnotation', null );
    }

    setActiveAnnotation( annotation ) {
        // The code responsible for reacting to annotation changes.
        if ( annotation === this.activeAnnotation ) {
            return;
        }

        if ( this.activeAnnotation ) {
            this.activeAnnotation.isActive = false;
        }

        if ( annotation ) {
            annotation.isActive = true;
        }

        this.activeAnnotation = annotation;
    }

    attach( annotations ) {
        // The code responsible for displaying annotations
        // based on the annotation collection passed to this UI.

        // The code responsible for setting an active and non-active annotation based on the annotation focus changes.
        this.listenTo( annotations, 'focus', ( evt, annotation ) => {
            this.setActiveAnnotation( annotation );
        } );

        this.listenTo( annotations, 'blur', () => {
            this.setActiveAnnotation( null );
        } );

        // The code responsible for the integration with editor annotation markers,
        // editor events and the editor selection changes.
        // The requirement of this integration might change in the future.
        // // If the plugin was initialized as an editor plugin, the integration should look like the following:
        const editorAnnotations = editor.plugins.get( 'EditorAnnotations' );

        this.listenTo( editorAnnotations, 'refresh', () => refreshActiveAnnotation.bind( this ) );
        this.listenTo( editorAnnotations, 'blur' ( evt, { isAnnotationTracked } ) => {
            if ( this.activeAnnotation && isAnnotationTracked( this.activeAnnotation ) ) {
                this.setActiveAnnotation( null );
            }
        } );
        this.listenTo( editorAnnotations, 'uiUpdate' () => annotations._refreshPositioning();

        function refreshActiveAnnotation() {
            const selectedAnnotations = editorAnnotations.getOrderedSelectedAnnotations( {
                annotations: this._annotations,
                activeAnnotation: this.activeAnnotation
            } );

            this.setActiveAnnotation( selectedAnnotations[ 0 ] || null );
        }
    }

    detach() {
        // The code responsible for hiding the UI and detaching
        // listeners from the annotation collection, editor annotations and others.
    }
}

24.0.0 (2020-12-09)

Features

Bug fixes

Other changes

Localization updates

New translations are available for the following languages:

Hungarian, German, Australian English, French, Estonian, Ukrainian, Galician, Italian, Slovak, Serbian, Serbian (Latin), Chinese

Released packages

Check out the Versioning policy guide for more information.

Released packages (summary)

23.1.0 (2020-10-26)

Features

Bug fixes

Other changes

Localization updates

New translations are available for the following languages:

Chinese, French, Italian, Persian

23.0.0 (2020-09-25)

Features

Bug fixes

Other changes

22.0.0 (2020-08-25)

Features

Other

Localization updates

New translations are available for the following languages:

Dutch, Korean, Russian, Ukrainian

21.0.0 (2020-07-24)

BREAKING CHANGES

Features

Bug fixes

Other changes

Localization updates

New translations are available for the following languages:

Brazilian Portuguese, Chinese, Polish, Turkmen, Uighur

20.0.1 (2020-06-26)

Bug fixes

Fixed an error that occurred under certain conditions when opening a document with comments and real-time collaboration enabled. It could lead to losing all comments added to the document.

This was a regression that occurred only in version 20.0.0. It is strongly recommended to upgrade this package to version 20.0.1.

20.0.0 (2020-06-23)

BREAKING CHANGES

Features

Bug fixes

Notes

At the moment, multi-cell selection and multi-cell comments are supported only without real-time collaboration and when track changes is turned off.

Localization updates

New translations are available for the following languages:

Chinese (China), Slovak.

19.1.0 (2020-05-25)

Features

Localization updates

New translations are available for the following languages:

Australian English, Brazilian Portuguese, Croatian, French, Galician, German, Hungarian, Italian, Japanese, Norwegian, Russian, Serbian, Serbian (Latin), Turkish.

We would like to thank everyone who contributed to these translations!

19.0.1 (2020-04-30)

BREAKING CHANGES

Features

Bug fixes

Other changes

18.0.0 (2020-03-19)

Features

Bug fixes

Other

17.0.0 (2020-02-20)

BREAKING CHANGES

Comments

Track changes

Real-time collaboration

Refer to the Sessions API documentation to learn about the new API.

Known issues

Features

Comments

Track changes

Real-time collaboration

Bug fixes

Track changes

Other changes

Track changes

Real-time collaboration

Trusted and approved by

Philips
Microsoft
IBM
Novartis
Siemens
Volvo
Thomson
Disney
Citi
Drupal
Mozilla
Unicef
Accenture
TATA
Deloitte

Subscribe to our newsletter