Jump to content

How to import TinyMCE Custom Plugin?


kuba
 Share

Recommended Posts

I created a script for TinyMCE that calculates the readability of a given text using the Flesch Reading Ease formula based on a 0-100 scale. A high score means the text is easier to read for users (recommended score 60+). Low scores suggest the text is complicated to understand with too long paragraphs.

It works with standard TinyMCE, however the question is how to make it run with ProcessWire?

tinymce.init({
            selector: 'textarea#template',
            plugins: 'readability',
            toolbar: 'readability',
            menubar: 'tools',
            menu: {
                tools: { title: 'Tools', items: 'readabilityTool' }
            }
        });

tinymce.PluginManager.add('readability', (editor, url) => {
    editor.ui.registry.addButton('readability', {
        text: 'Readability',
        icon: 'book',
        onAction: function() {
            const content = editor.getContent({format: 'text'});
            const readabilityScore = calculateReadability(content);
            alert('Readability Score: ' + readabilityScore);
        }
    });

    editor.ui.registry.addMenuItem('readability', {
        text: 'Readability',
        icon: 'book',
        onAction: function() {
            const content = editor.getContent({format: 'text'});
            const readabilityScore = calculateReadability(content);
            alert('Readability Score: ' + readabilityScore);
        }
    });

    editor.ui.registry.addMenuItem('readabilityTool', {
        text: 'Readability',
        context: 'tools',
        icon: 'book',
        onAction: function() {
            const content = editor.getContent({format: 'text'});
            const readabilityScore = calculateReadability(content);
            alert('Readability Score: ' + readabilityScore);
        }
    });

    return {
        getMetadata: () => ({ name: 'Readability' })
    };
});

function calculateReadability(text) {
    var sentences = text.split(/[\.\!\?]/).filter(Boolean);
    var numSentences = sentences.length;
    var words = text.split(/\s+/).filter(Boolean).length;
    var syllables = 0;

    var wordArray = text.split(/\s+/).filter(Boolean);
    wordArray.forEach(function(word) {
        syllables += countSyllables(word);
    });

    if (words > 0 && numSentences > 0) {
        var wordsPerSentence = words / numSentences;
        var syllablesPerWord = syllables / words;

        var readability = 206.835 - (1.015 * wordsPerSentence) - (84.6 * syllablesPerWord);
        return readability.toFixed(2);
    } else {
        return 0;
    }
}

function countSyllables(word) {
    word = word.toLowerCase();
    var vowels = 'aeiouy';
    var numVowels = 0;
    var prevCharWasVowel = false;

    if (word.length > 2 && word.substr(-2) == 'es') {
        word = word.slice(0, -2);
    } else if (word.length > 1 && word.substr(-1) == 'e') {
        word = word.slice(0, -1);
    }

    for (var i = 0; i < word.length; i++) {
        if (vowels.indexOf(word[i]) !== -1) {
            if (!prevCharWasVowel) {
                numVowels++;
            }
            prevCharWasVowel = true;
        } else {
            prevCharWasVowel = false;
        }
    }

    return numVowels > 0 ? numVowels : 1;
}

 

  • Like 1
Link to comment
Share on other sites

Neat! I like the readability score - it provides some useful context back to the authors. I was originally looking to see if it'd be possible to integrate the hemingwayapp(.com) interface as a field for similar reasons, but gave up. I instead just created a "Estimated Reading Time" field for site visitors as a feel-good (for me) feature. (I'll share it in case it's useful. The $page->reading_time is a hidden integer field in the template.) Multilingual sites could use the referenced source study to define times based on available data.

<?php
// ready.php

// Blog/News Post Page - set reading time
$wire->addHookBefore('Pages::saveReady(template=news-post)', function(HookEvent $event) {
	// Get values of arguments sent to hook (and optionally modify them)
	$page = $event->arguments(0);

	// Get the word count of the summary and body fields (combined)
	$summary_word_count = count(wire('sanitizer')->wordsArray(strip_tags($page->summary_textarea)));
	$article_word_count = count(wire('sanitizer')->wordsArray(strip_tags($page->rte)));

	// Set the value for the reading time field (number) based on word count
	// To provide a range, a text value would have to be returned (and stored), but is possible by calculating cpm,
	// wpm_top, wpm_bot and determining variance
	// Source Study: https://iovs.arvojournals.org/article.aspx?articleid=2166061
	$cpm = 987;     // average characters per minute, for English
	$wpm_bot = 161;	// English values for reading speeds
	$wpm_top = 228;
	$wpm_ave = ceil(($wpm_bot + $wpm_top) / 2);
	$page->reading_time = ceil(($summary_word_count + $article_word_count) / $wpm_ave);

	// Populate back arguments (assuming they've been modified)
	$event->arguments(0, $page);
});

As for your actual question... I haven't done this myself, but looking at the module and the field's settings, I believe you need to:

  1. Edit the settings of the "InputfieldTinyMCE" module. Look for the (image below) External Plugin files section, expand it if necessary, and it'll show you where to place your necessary file(s) for your additional plugins.
  2. Once your additional plugin(s) have been added properly to the InputfieldTinyMCE module's settings correctly, I do believe you'd then need to go to your TinyMCE field(s) that you want to take advantage of the plugin(s), and add/enable them. To do so, edit your field(s), go to the Input tab, and configure the necessary section(s) (I would assume the "External plugins to enable" would be the first to change) - my example image is blank only because I haven't added any plugins to my system.

InputfieldTinyMCE module config:

image.thumb.png.1109bf4523320f98a65195ccc51f27b4.png

TinyMCE field Input tab setting:

image.png.266ce0cfc5e3742f612498332a6d422f.png

Link to comment
Share on other sites

I followed the steps exactly. The plugin appears in the External Plugins section, but when I enable it, it's not accessible. It should add a button and show up in the Tools drop-down menu.

Link to comment
Share on other sites

After enabling it, you'd then need to add it. I copy/pasted your plugin's code into a file in my test PW site, followed my steps, but then also added it to the list of items in the toolbar. It (unfortunately) doesn't show up as a suggested item, so you have to type it manually and make sure you don't misspell it. Afterward, it should be enabled on your configured field(s).

My field's Tools Menu is disabled, so I didn't test against that, but it does work, at the very least, for the toolbar/icon area when added.

image.png.48afc5687907639db0fc7762645d5ef0.png

image.png.942651585c4b7a5cd2968f070be96b87.png

image.png.cfb0b336f6517e72f1dad2157686397b.png

  • Thanks 1
Link to comment
Share on other sites

Thank you for the update. I did exactly that.

The file permission of the .js file was the issue. There was no execution allowed. Now it works ?

To calculate reading time I use this code on my website. 250 words per minute is the recommended value for English language.

function calculateReadTime($text) {
   // Average reading speed in words per minute
   $averageReadingSpeed = 200;

   // Strip HTML tags and count the words
   $wordCount = str_word_count(strip_tags($text));

   // Calculate the read time in minutes
   $readTime = ceil($wordCount / $averageReadingSpeed);

   return $readTime;
}
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...