Action
Stats
Calculate and present preview of common readability statistics for the current draft.
Steps
-
script
// Make sure draft is not blank first... if (draft.content.length == 0) { alert("Empty draft. Text required to calculate statistics."); context.cancel(); }
-
script
// Show alert displaying common text statistics for current draft // Includes syllable counts, Flesh-Kincaid, SMOG index scoring, etc. // adapted from... // TextStatistics.js // Christopher Giffard (2012) // 1:1 API Fork of TextStatistics.php by Dave Child (Thanks mate!) // https://github.com/DaveChild/Text-Statistics // BEGIN LIBRARY function cleanText(text) { // all these tags should be preceeded by a full stop. var fullStopTags = ['li', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dd']; fullStopTags.forEach(function(tag) { text = text.replace("</" + tag + ">","."); }) text = text .replace(/<[^>]+>/g, "") // Strip tags .replace(/[,:;()\-]/, " ") // Replace commans, hyphens etc (count them as spaces) .replace(/[\.!?]/, ".") // Unify terminators .replace(/^\s+/,"") // Strip leading whitespace .replace(/[ ]*(\n|\r\n|\r)[ ]*/," ") // Replace new lines with spaces .replace(/([\.])[\. ]+/,".") // Check for duplicated terminators .replace(/[ ]*([\.])/,". ") // Pad sentence terminators .replace(/\s+/," ") // Remove multiple spaces .replace(/\s+$/,""); // Strip trailing whitespace text += "."; // Add final terminator, just in case it's missing. return text; } var TextStatistics = function TextStatistics(text) { this.text = text ? cleanText(text) : this.text; }; TextStatistics.prototype.fleschKincaidReadingEase = function(text) { text = text ? cleanText(text) : this.text; return Math.round((206.835 - (1.015 * this.averageWordsPerSentence(text)) - (84.6 * this.averageSyllablesPerWord(text)))*10)/10; }; TextStatistics.prototype.fleschKincaidGradeLevel = function(text) { text = text ? cleanText(text) : this.text; return Math.round(((0.39 * this.averageWordsPerSentence(text)) + (11.8 * this.averageSyllablesPerWord(text)) - 15.59)*10)/10; }; TextStatistics.prototype.gunningFogScore = function(text) { text = text ? cleanText(text) : this.text; return Math.round(((this.averageWordsPerSentence(text) + this.percentageWordsWithThreeSyllables(text, false)) * 0.4)*10)/10; }; TextStatistics.prototype.colemanLiauIndex = function(text) { text = text ? cleanText(text) : this.text; return Math.round(((5.89 * (this.letterCount(text) / this.wordCount(text))) - (0.3 * (this.sentenceCount(text) / this.wordCount(text))) - 15.8 ) *10)/10; }; TextStatistics.prototype.smogIndex = function(text) { text = text ? cleanText(text) : this.text; return Math.round(1.043 * Math.sqrt((this.wordsWithThreeSyllables(text) * (30 / this.sentenceCount(text))) + 3.1291)*10)/10; }; TextStatistics.prototype.automatedReadabilityIndex = function(text) { text = text ? cleanText(text) : this.text; return Math.round(((4.71 * (this.letterCount(text) / this.wordCount(text))) + (0.5 * (this.wordCount(text) / this.sentenceCount(text))) - 21.43)*10)/10; }; TextStatistics.prototype.textLength = function(text) { text = text ? cleanText(text) : this.text; return text.length; }; TextStatistics.prototype.letterCount = function(text) { text = text ? cleanText(text) : this.text; text = text.replace(/[^a-z]+/ig,""); return text.length; }; TextStatistics.prototype.sentenceCount = function(text) { text = text ? cleanText(text) : this.text; // Will be tripped up by "Mr." or "U.K.". Not a major concern at this point. return text.replace(/[^\.!?]/g, '').length || 1; }; TextStatistics.prototype.wordCount = function(text) { text = text ? cleanText(text) : this.text; return text.split(/[^a-z0-9]+/i).length || 1; }; TextStatistics.prototype.averageWordsPerSentence = function(text) { text = text ? cleanText(text) : this.text; return this.wordCount(text) / this.sentenceCount(text); }; TextStatistics.prototype.averageSyllablesPerWord = function(text) { text = text ? cleanText(text) : this.text; var syllableCount = 0, wordCount = this.wordCount(text), self = this; text.split(/\s+/).forEach(function(word) { syllableCount += self.syllableCount(word); }); // Prevent NaN... return (syllableCount||1) / (wordCount||1); }; TextStatistics.prototype.wordsWithThreeSyllables = function(text, countProperNouns) { text = text ? cleanText(text) : this.text; var longWordCount = 0, self = this; countProperNouns = countProperNouns === false ? false : true; text.split(/\s+/).forEach(function(word) { // We don't count proper nouns or capitalised words if the countProperNouns attribute is set. // Defaults to true. if (!word.match(/^[A-Z]/) || countProperNouns) { if (self.syllableCount(word) > 2) longWordCount ++; } }); return longWordCount; }; TextStatistics.prototype.percentageWordsWithThreeSyllables = function(text, countProperNouns) { text = text ? cleanText(text) : this.text; return (this.wordsWithThreeSyllables(text,countProperNouns) / this.wordCount(text)) * 100; }; TextStatistics.prototype.syllableCount = function(word) { var syllableCount = 0, prefixSuffixCount = 0, wordPartCount = 0; // Prepare word - make lower case and remove non-word characters word = word.toLowerCase().replace(/[^a-z]/g,""); // Specific common exceptions that don't follow the rule set below are handled individually // Array of problem words (with word as key, syllable count as value) var problemWords = { "simile": 3, "forever": 3, "shoreline": 2 }; // Return if we've hit one of those... if (problemWords.hasOwnProperty(word)) return problemWords[word]; // These syllables would be counted as two but should be one var subSyllables = [ /cial/, /tia/, /cius/, /cious/, /giu/, /ion/, /iou/, /sia$/, /[^aeiuoyt]{2,}ed$/, /.ely$/, /[cg]h?e[rsd]?$/, /rved?$/, /[aeiouy][dt]es?$/, /[aeiouy][^aeiouydt]e[rsd]?$/, /^[dr]e[aeiou][^aeiou]+$/, // Sorts out deal, deign etc /[aeiouy]rse$/ // Purse, hearse ]; // These syllables would be counted as one but should be two var addSyllables = [ /ia/, /riet/, /dien/, /iu/, /io/, /ii/, /[aeiouym]bl$/, /[aeiou]{3}/, /^mc/, /ism$/, /([^aeiouy])\1l$/, /[^l]lien/, /^coa[dglx]./, /[^gq]ua[^auieo]/, /dnt$/, /uity$/, /ie(r|st)$/ ]; // Single syllable prefixes and suffixes var prefixSuffix = [ /^un/, /^fore/, /ly$/, /less$/, /ful$/, /ers?$/, /ings?$/ ]; // Remove prefixes and suffixes and count how many were taken prefixSuffix.forEach(function(regex) { if (word.match(regex)) { word = word.replace(regex,""); prefixSuffixCount ++; } }); wordPartCount = word .split(/[^aeiouy]+/ig) .filter(function(wordPart) { return !!wordPart.replace(/\s+/ig,"").length }) .length; // Get preliminary syllable count... syllableCount = wordPartCount + prefixSuffixCount; // Some syllables do not follow normal rules - check for them subSyllables.forEach(function(syllable) { if (word.match(syllable)) syllableCount --; }); addSyllables.forEach(function(syllable) { if (word.match(syllable)) syllableCount ++; }); return syllableCount || 1; }; function textStatistics(text) { return new TextStatistics(text); } // END LIBRARY var result = ""; var s = draft.content; var stats = textStatistics(s); var t = ["<table>"]; function addRow(key, val, link) { t.push("<tr><td class='lbl'>"); t.push(key); t.push("</td><td class='val'>"); t.push(val); t.push("</td>"); if (link) { t.push("<td>"); t.push("<a href='" + link + "'>info</a>"); t.push("</td>"); } else { t.push("<td></td>"); } t.push("</tr>") } addRow("Words", stats.wordCount()); addRow("Sentences", stats.sentenceCount()); addRow("Words per sentence", Math.round(stats.averageWordsPerSentence(), 2)); addRow("Flesch-Kincaid Ease", stats.fleschKincaidReadingEase(), "http://www.readabilityformulas.com/flesch-reading-ease-readability-formula.php"); addRow("Flesch-Kincaid Grade Level", stats.fleschKincaidGradeLevel(), "http://www.readabilityformulas.com/flesch-grade-level-readability-formula.php"); addRow("Gunning Fog", stats.gunningFogScore(), "https://en.wikipedia.org/wiki/Gunning_fog_index"); addRow("SMOG Index", stats.smogIndex(), "http://www.readabilityformulas.com/smog-readability-formula.php"); addRow("Automated Readability", stats.automatedReadabilityIndex(), "http://www.readabilityformulas.com/automated-readability-index.php"); addRow("Coleman Liau", stats.colemanLiauIndex(), "http://www.readabilityformulas.com/coleman-liau-readability-formula.php"); t.push("</table>"); draft.setTemplateTag("htmltable", t.join(""));
-
script
// create theme sensitive css for preview if (app.themeMode == 'dark') { var css = "html, body { background: #222; color: #ddd; }"; draft.setTemplateTag("bodystyle", css); } else { var css = "html, body { background: #fff; color: #444; }"; draft.setTemplateTag("bodystyle", css); }
-
htmlpreview
<!DOCTYPE html> <html dir="auto"> <head> <title>Preview</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> @import url(http://fonts.googleapis.com/css?family=Vollkorn:400,400italic,700,700italic&subset=latin); html, body { padding:0em; margin:auto; max-width:55em; text-align: center; } body { font: 1.3em "Vollkorn", Palatino, Times; color: #333; line-height: 1.4; text-align: center; } header, nav, article, footer { width: 700px; margin:0 auto; } article { margin-top: 4em; margin-bottom: 4em; min-height: 400px; } footer { margin-bottom:50px; } video { margin: 2em 0; border:1px solid #ddd; } nav { font-size: .9em; font-style: italic; border-bottom: 1px solid #ddd; padding: 1em 0; } nav p { margin: 0; } /* Typography -------------------------------------------------------- */ h1 { margin-top: 0; font-weight: normal; } h2 { font-weight: normal; } h3 { font-weight: normal; font-style: italic; margin-top:3em; } p { margin-top:0; -webkit-hypens:auto; -moz-hypens:auto; hyphens:auto; } ul { list-style: square; padding-left:1.2em; } ol { padding-left:1.2em; } blockquote { margin-left: 1em; padding-left: 1em; border-left: 1px solid #ddd; } code { font-family: "Consolas", "Menlo", "Monaco", monospace, serif; font-size: .9em; background: white; } a { color: #2484c1; text-decoration: none; } a:hover { text-decoration: underline; } a img { border:none; } h1 a, h1 a:hover { color: #333; text-decoration: none; } hr { color : #ddd; height : 1px; margin: 2em 0; border-top : solid 1px #ddd; border-bottom : none; border-left: 0; border-right: 0; } p#heart{ font-size: 2em; line-height: 1; text-align: center; color: #ccc; } .red { color:#B50000; } img { max-width: 90%; } table { margin: 1em auto; border: 1px solid #aaa; border-collapse: collapse; } th { padding:.25em .5em; background: #efefef; border: 1px solid #ccc; } td { padding:.25em .5em; text-align: left; border: 1px solid #ccc; } /* Home Page --------------------------- */ body#index li { margin-bottom: 1em; } /* iPad -------------------------------------------------------- */ @media only screen and (max-device-width: 1024px) { body { font-size: 120%; line-height: 1.4; } } /* @iPad */ /* iPhone -------------------------------------------------------- */ @media only screen and (max-device-width: 480px) { body { text-align: left; padding:.5em; } article, footer { width: auto; } article { padding: 0 10px; } } /* @iPhone */ .lbl { } .val { font-weight: bold; text-align: right; } [[bodystyle]] </style> </head> <body> <h2>Draft Statistics</h2> [[htmltable]] </body> </html>
Options
-
After Success Nothing Notification Error Log Level Error
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.