Search code examples
ckeditorckeditor5

Register click listener on ckeditor5 dropdown items


I am currently trying to write a plugin for the CKEditor 5 to support automatic translations. I was able to find out how to write plugins and how to create dropdowns in the documentation.

But in the documentation there is no mention (or I missed it) how to be informed about a click on the values:

  • There is an Execute Handler for the button that opens the dropdown, but how do I register a listener for a click on one of the values?
  • Can I assign an id or similar to my items to recognize the click on the right element of the dropdown?

Here's the code that I was able to build based on the documentation:

class Translation extends Plugin {
    init() {
        this.editor.ui.componentFactory.add('translate', (locale) => {
            const dropdownView = createDropdown(locale);
            dropdownView.buttonView.set({
                icon: languageIcon,
                label: 'Translate',
                tooltip: true,
            });

            const items = new Collection();
            items.add({
                id: 'en', // how to assign id ???
                type: 'button',
                model: new Model({
                    withText: true,
                    label: 'English'
                }),
            });
            items.add({
                id: 'es', // how to assign id ???
                type: 'button',
                model: new Model({
                    withText: true,
                    label: 'Spanish'
                }),
            });
            addListToDropdown(dropdownView, items);

            // callback for click on item ????
            dropdownView.on('click', (event) => {
                console.log('click', event);
            });

            return dropdownView;
        });
    }
}

Solution

  • You can use DropdownView.on() method to listen to the execute event.

    And, use EventInfo.source property to get the object that is clicked and then use its property e.g. id or label to identify it.

    For example:

    const items = new Collection();
    items.add( {
        type: 'button',
        model: new Model({
            id: 'en',                // id 
            withText: true,
            label: 'English',
        })
    } );
    items.add( {
        type: 'button',
        model: new Model({
            id: 'es',               // id
            withText: true,
            label: 'Spanish'
        })
    } );
    
    addListToDropdown(dropdownView, items);
    
    dropdownView.on('execute', (eventInfo) => {
        const { id, label } = eventInfo.source;
    
        if ( id === 'en' ) {
            console.log('Object (en):', label);
        } else if ( id === 'es' ) {
            console.log('Object (es):', label);
        }
    });
    

    Here's the complete working example with ClassicEditor (tested):

    import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
    import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
    import Model from '@ckeditor/ckeditor5-ui/src/model';
    import Collection from '@ckeditor/ckeditor5-utils/src/collection';
    import { createDropdown, addListToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
    import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
    
    const Translate = 'translate';
    
    class Translation extends Plugin {
        init() {
            console.log('Translation initialized!');
    
            this.editor.ui.componentFactory.add(Translate, (locale) => {
                const dropdownView = createDropdown(locale);
                dropdownView.buttonView.set({
                    label: 'Translate',
                    withText: true,
                });
    
                const items = new Collection();
                items.add( {
                    type: 'button',
                    model: new Model({
                        id: 'en',
                        withText: true,
                        label: 'English',
                    })
                } );
                items.add( {
                    type: 'button',
                    model: new Model({
                        id: 'es',
                        withText: true,
                        label: 'Spanish'
                    })
                } );
    
                addListToDropdown(dropdownView, items);
    
                dropdownView.on('execute', (eventInfo) => {
                    const { id, label } = eventInfo.source;
    
                    if ( id === 'en' ) {
                        console.log('Object (en):', label);
                    } else if ( id === 'es' ) {
                        console.log('Object (es):', label);
                    }
                });
    
                return dropdownView;
            });
        }
    }
    
    ClassicEditor
        .create( document.querySelector( '#editor' ), {
            plugins: [ Essentials, Translation ],
            toolbar: [ Translate ]
        } )
        .then( editor => {
            console.log( 'Editor was initialized', editor );
        } )
        .catch( error => {
            console.error( error.stack );
        } );
    

    Console output after clicking both items:

    Object (en): English
    Object (es): Spanish