Automatic more tag insertion in TinyMCE4/WordPress

I’m in the process of creating a WordPress theme including a version of TinyMCE that allows “automatic more tag insertion”. By that I mean a special function which inserts a “Read more” tag after a specified number of characters (e g. 400) in the WordPress editor. The reason for this is, that every article listed on the WordPress blog homepage is displayed next to a quadratic teaser image, and unexperienced authors need an easy way of making their teaser text take up roughly the same height as the image.

I partly realized this functionality by creating a simple TinyMCE-Plugin, which is very error-prone though, and probably an unelegant solution. You can check out the full code here.

Read More

The plugin works by getting the HTML content of the editor, slicing the html on the 400th character (in this example), subsequently removing any html tags from the first part and calculating the difference in length of the two beginning sections:

function insertMore(ed, offset) {

    var content = ed.getContent();
    var contentStripped = ed.getContent({format:'text'});
    if (content.length > offset) {

        content = content.replace(/<!--more-->/g,'');

        var firstHalfUnstripped = content.slice(0, offset);
        var firstHalfStripped = firstHalfUnstripped.replace(/<(?:.|n)*?>/gm, '');

        var diff = firstHalfUnstripped.length - firstHalfStripped.length;

        offset = offset + diff;

        var beg = null;
        var realOffset = offset;
        while(beg !== " ") {
            beg = content.slice(realOffset, realOffset+1);
            realOffset++;
            if(beg === "") {
                break;
            }
        }

        content = [content.slice(0, realOffset), '<!--more-->',
        content.slice(realOffset)].join('');

        ed.setContent(content);

    }

}

The difference in length is then added to the originally calculated split position, so that the actual teaser text can be limited to the predefined character count more or less correctly.

Finally, the script searches for the closest whitespace following the offset, splits the HTML content again at this position and joins the two halfes together with a string representing the more tag in the middle.

This sort of works, but as you can probably imagine, not very well. It removes html tags like <p> and </p> fine, but is likely to fail when there is an html element in the editor that contains spaces itself.

For example, if we have an image wrapped in a link, which is very common for wordpress posts, it could end up being split in half, if it happens to contain something like the 400th letter like so:

<a href="image.png"><img class="alignright wp-image-543 size-full" src="image.png" alt="Image" width="250" height="250" /></a>

--> <a href="image.png"><img class="alignright wp-image-543 size-full" 
    <!--more-->
    src="image.png" alt="Image" width="250" height="250" /></a>

This will break the code generated by WordPress and therefore is not acceptable. However, I can’t figure out a way to do it better or even differently. I tried to use TinyMCE4s setCursorLocation in order to change the Cursor position to 400 characters so as to be able to use the “insert more tag at cursor position” feature, but couldn’t get it to work at all.

This

tinyMCE.get(0).selection.setCursorLocation(tinyMCE.get(0).getBody(), 400)

just returned IndexSizeError: Failed to execute 'setStart' on 'Range': There is no child at offset 400.

The same thing happend when I tried setting range manually.

Ignoring TinyMCE and trying to set the cursor position in the textarea as explained here had no effect at all.

How can I make this work properly? Thanks in advance!

Related posts

Leave a Reply