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;
}