Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CKEditor Add new list plugin using UL tag

I'm trying to add a new list plugin similar to bulletedlist so I've created a new button but as i'm trying to use the UL tag it pairs the new button called arrowedlist with the bulletedlist button.

The reason I am doing this is so I can add a class to it (which I know how to do) so I can have 2 different buttons where 1 applies the default bullet list and the other applies UL tags with a class.

The basic question is: is there a way I can add a button that uses UL the same way as bulletedlist does without it pairing the buttons together?

    // Register commands.
        editor.addCommand( 'numberedlist', new listCommand( 'numberedlist', 'ol' ) );
        editor.addCommand( 'bulletedlist', new listCommand( 'bulletedlist', 'ul' ) );
        editor.addCommand( 'arrowedlist', new listCommand( 'arrowedlist', 'ul' ) );


        // Register the toolbar button.
        if ( editor.ui.addButton ) {
            editor.ui.addButton( 'NumberedList', {
                label: editor.lang.list.numberedlist,
                command: 'numberedlist',
                directional: true,
                toolbar: 'list,10'
            });
            editor.ui.addButton( 'BulletedList', {
                label: editor.lang.list.bulletedlist,
                command: 'bulletedlist',
                directional: true,
                toolbar: 'list,20'
            });
            editor.ui.addButton( 'ArrowedList', {
                label: editor.lang.list.arrowedlist,
                command: 'arrowedlist',
                directional: true,
                toolbar: 'list,30'
            });

        }

Hopefully I'm not missing something obvious, thanks!

like image 508
Matthew Shine Avatar asked Mar 18 '26 02:03

Matthew Shine


1 Answers

Although this is not straightforward as list system wasn't designed to do such things, you can do something about that. You got to modify the code of the list plugin (plugins/list/plugin.js). These are basic assumptions to be implemented:

  • Distinguish between different lists:
    • Each <ol> gets data-numberedlist attribute.
    • Each <ul> gets data-bulletedlist or data-arrowedlist attribute depending on your custom class.
  • Add custom CSS for your class.
  • Add custom class to newly created lists if the command defines one.
  • Add custom attribute to every single list created with the button (see the first point).
  • Make command's refresh distinguish between <ul data-bulletedlist="true> and <ul data-arrowedlist="true>.

I'm assuming that you have the latest CKEdtor (4.2). I'll do my best to guide you here. While reading this, please take a look on The Gist implementing the following changes. This will definitely help you to get the context of what is different. So... good luck and let's go! ;)


Things to be modified

Add specific styles for your list

Put it outside of plugin definition, this is gonna be global for all editors:

CKEDITOR.addCss( 'ul.myclass { color: red } ' );

Make listCommand() function accept custom class as parameter.

We got to allow the custom class and data-name attribute in Advanced Content Filter.

function listCommand( name, type, className ) {
    this.name = name;
    this.type = type;
    this.context = type;

    // Remember the class of this command.
    this.className = className;

    this.allowedContent = {};
    this.allowedContent[ type ] = {
        classes: className || '',
        attributes: 'data-' + name
    };
    this.allowedContent.li = true;
    this.requiredContent = type;
}

Add the command for arrowedlist

Note myclass here.

editor.addCommand( 'arrowedlist', new listCommand( 'arrowedlist', 'ul', 'myclass' ) );

Add the button

editor.ui.addButton( 'ArrowedList', {
    label: editor.lang.list.bulletedlist,
    command: 'arrowedlist',
    directional: true,
    toolbar: 'list,20'
});

Add data-name attribute to all NEW lists

To distinguish between list types, add data-name attribute to the element:

listNode = doc.createElement( this.type );
listNode.data( this.name, true );

Add your custom class to NEW arrowed lists.

if ( this.className )
    listNode.addClass( this.className );

Extend refresh() in the prototype of listCommand

This ensures that arrowedlist button will change its state only if the <ul> has data-arrowedlist. Similar behavior for bulletedlist and numberedlist, of course.

if ( list && limit.contains( list ) ) {
    var isList = list.is( this.type ) && list.data( this.name );

    this.setState( isList ? CKEDITOR.TRISTATE_ON : CKEDITOR.TRISTATE_OFF );
}

Add dataprocessor rules

During editor's lifetime, each <ol> gets data-numberedlist. Accordingly each <ul> gets data-arrowedlist or data-bulletedlist depending on whether class myclass is set.

On the output, custom attributes are filtered out so data that you save is totally clean.

editor.dataProcessor.dataFilter.addRules( {
    elements: {
        ol: function( element ) {
            element.attributes[ 'data-numberedlist' ] = true;
        },
        ul: function( element ) {
            var className = element.attributes.class;

            if ( className && className.match( /myclass/g ) )
                element.attributes[ 'data-arrowedlist' ] = true;
            else
                element.attributes[ 'data-bulletedlist' ] = true;
        }
    }
} );

editor.dataProcessor.htmlFilter.addRules( {
    elements: {
        ol: function( element ) {
            delete element.attributes[ 'data-numberedlist' ];
        },
        ul: function( element ) {
            delete element.attributes[ 'data-arrowedlist' ];
            delete element.attributes[ 'data-bulletedlist' ];
        }
    }
} );

Testing

Try setting the following HTML in source view:

<ul class="myclass">
    <li>Foo</li>
    <li>Bar</li>
</ul>

It should become a red list when goind back to WYSIWYG. Also the arrowedlist button will be the only one associated to such list.

like image 109
oleq Avatar answered Mar 20 '26 16:03

oleq