S R
S R

Reputation: 167

Add an HTML element only once in CKEditor

In my ckeditor instance, I want to let my users insert a horizontal rule but only once. If there is an existing line, it should be replaced by the new one (same as the Read-More functionality on Wordpress). I can get it to work if I want only the last HR tag to remain, but what if a user wants to insert his HR tag higher up in the document than an existing one?

I used a variable (say, savedContent) to store the default content (without any HR) on instantiation. Following the steps in Set cursor to specific position in CKEditor , my idea was to use the savedContent variable to revert the CKEditor contents to the default HR-less content before (using the ranges or bookmarks) to insert a new HR at the cursor position.

This is the code:

CKEDITOR.on('instanceReady', function() {
    $(".cke_button__horizontalrule").attr("title","End Preview here");
    var savedContent = CKEDITOR.instances['pro_story'].getData();

    $(".cke_button__horizontalrule").on("click",function(){
        var ranges = editor.getSelection().getRanges();
        CKEDITOR.instances['pro_story'].setData(savedContent);
        editor.getSelection().selectRanges( ranges );
        editor.insertHtml("<hr />");
    });
});

Now the problem with this code is that, for some reason, it gives me the following error: The given range isn't in document.

What do I do?

Upvotes: 0

Views: 461

Answers (1)

Wizard
Wizard

Reputation: 3151

Get an array of existing <hr /> tags before inserting a new one. Then, remove all these tags after inserting the new one.

let hrArray;

CKEDITOR.instances['pro_story'].on('beforeCommandExec', function(evt) {
    if (evt.data.name == 'horizontalrule') {
        hrArray = evt.editor.document.getElementsByTag('hr').toArray();
    }
});

CKEDITOR.instances['pro_story'].on('afterCommandExec', function(evt) {
    if (evt.data.name == 'horizontalrule') {
        hrArray.forEach(el => el.remove());
    }
});

Upvotes: 1

Related Questions