User:Phlsph7/Readability.js
Appearance
From Wikipedia, the free encyclopedia
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
This user script seems to have a documentation page at User:Phlsph7/Readability.
/* Userscript to highlight sentences by readability */ // Set score colors for css if they have not been defined varreadabilityScoreColors=readabilityScoreColors||[ 'rgb(255,96,96)', 'rgb(255,128,128)', 'rgb(255,192,128)', 'rgb(255,224,128)', 'rgb(255,255,128)', 'rgb(214,255,128)', 'rgb(171,255,128)', 'rgb(128,255,128)', 'rgb(128,255,171)', 'rgb(128,255,214)',]; // Goes through all the p-elements and splits their content into span-elements. Each span corresponds to a sentence. functiondivideParagraphsIntoSentences(){ letparagraphs=document.querySelectorAll('.mw-parser-output > p'); // Periods are the main guide for where sentences start and end. // However, not all periods mark sentences, like in different forms of abbreviations. // Placeholders are used for exceptions. letperiodPlaceholder='PERIOD_PLACEHOLDER'; letexceptionString='...; Mr.; Mrs.; Dr.; Jr.; Sr.; Prof.; St.; Ave.; Corp.; Inc.; Ltd.; Co.; Gov.; Capt.; Sgt.; et al.; vs.; e.t.a.; .A.; .B.; .C.; .D.; .E.; .F.; .G.; .H.; .I.; .J.; .K.; .L.; .M.; .N.; .O.; .P.; .Q.; .R.; .S.; .T.; .U.; .V.; .W.; .X.; .Y.; .Z.; A.; B.; C.; D.; E.; F.; G.; H.; I.; J.; K.; L.; M.; N.; O.; P.; Q.; R.; S.; T.; U.; V.; W.; X.; Y.; Z.; .a.; .b.; .c.; .d.; .e.; .f.; .g.; .h.; .i.; .j.; .k.; .l.; .m.; .n.; .o.; .p.; .q.; .r.; .s.; .t.; .u.; .v.; .w.; .x.; .y.; .z.; .a; .b; .c; .d; .e; .f; .g; .h; .i; .j; .k; .l; .m; .n; .o; .p; .q; .r; .s; .t; .u; .v; .w; .x; .y; .z; 0.0; 0.1; 0.2; 0.3; 0.4; 0.5; 0.6; 0.7; 0.8; 0.9; 1.0; 1.1; 1.2; 1.3; 1.4; 1.5; 1.6; 1.7; 1.8; 1.9; 2.0; 2.1; 2.2; 2.3; 2.4; 2.5; 2.6; 2.7; 2.8; 2.9; 3.0; 3.1; 3.2; 3.3; 3.4; 3.5; 3.6; 3.7; 3.8; 3.9; 4.0; 4.1; 4.2; 4.3; 4.4; 4.5; 4.6; 4.7; 4.8; 4.9; 5.0; 5.1; 5.2; 5.3; 5.4; 5.5; 5.6; 5.7; 5.8; 5.9; 6.0; 6.1; 6.2; 6.3; 6.4; 6.5; 6.6; 6.7; 6.8; 6.9; 7.0; 7.1; 7.2; 7.3; 7.4; 7.5; 7.6; 7.7; 7.8; 7.9; 8.0; 8.1; 8.2; 8.3; 8.4; 8.5; 8.6; 8.7; 8.8; 8.9; 9.0; 9.1; 9.2; 9.3; 9.4; 9.5; 9.6; 9.7; 9.8; 9.9. .0; .1; .2; .3; .4; .5; .6; .7; .8; .9;'; letexceptionStringSeparator='; '; letperiodExceptions=exceptionString.split(exceptionStringSeparator); letperiodExceptionPlaceholders=exceptionString.split('.').join(periodPlaceholder).split(exceptionStringSeparator); for(letparagraphofparagraphs){ lettextContent=paragraph.textContent.split('\r').join('').split('\n').join('').trim(); // exclude very short paragraphs if(textContent.length>20){ divideIntoSentences(paragraph,periodExceptions,periodExceptionPlaceholders); } } // remove very short sentences letsentenceElements=document.getElementsByClassName('sentence'); for(letsentenceElementofsentenceElements){ letsentenceText=getSentenceText(sentenceElement); if(sentenceText.trim().length<10){ sentenceElement.classList.remove('sentence'); } } // Split the content of a p-element into span-elements. Each span corresponds to a sentence. functiondivideIntoSentences(paragraph,periodExceptions,periodExceptionPlaceholders){ // Loop through all the nodes inside the p-element. // Span-open-tags and close-tags are placed through code. letinnerHTML=getSpanStartTag(); letcurrentChild=paragraph.firstChild; while(currentChild){ // if it is a text node, modify it if(currentChild.nodeType===Node.TEXT_NODE){ innerHTML+=adjustTextNodes(currentChild.nodeValue,periodExceptions,periodExceptionPlaceholders); } // if its an element, add outerHTML elseif(currentChild.nodeType===Node.ELEMENT_NODE){ innerHTML+=currentChild.outerHTML; } // otherwise add nodeValue else{ innerHTML+=currentChild.nodeValue; } currentChild=currentChild.nextSibling; } innerHTML+='</span>'; paragraph.innerHTML=innerHTML; // utility function to get the code for the opening span tag functiongetSpanStartTag(){ return`<span class="sentence">`; } // utility function to get the code for span tags in the middle (closing + opening) functiongetSpanEndAndStart(punctuation){ returnpunctuation+'</span>'+getSpanStartTag(); } // utility function to modify text nodes // they contain the punctuation relevant for sentences functionadjustTextNodes(text,periodExceptions,periodExceptionPlaceholders){ // use placeholders to remove all periods that do not mark sentences text=insertPlaceholders(text,periodExceptions,periodExceptionPlaceholders); // split using the remaining punctuation text=text.split('.').join(getSpanEndAndStart('.')) .split('!').join(getSpanEndAndStart('!')) .split('?').join(getSpanEndAndStart('?')); // use placeholders to return all periods that do not mark sentences text=removePlaceholders(text,periodExceptions,periodExceptionPlaceholders); returntext; functioninsertPlaceholders(text,periodExceptions,periodExceptionPlaceholders){ letmodifiedText=text; for(leti=0;i<periodExceptions.length;i++){ modifiedText=modifiedText.split(periodExceptions[i]).join(periodExceptionPlaceholders[i]); } returnmodifiedText; } functionremovePlaceholders(text,periodExceptions,periodExceptionPlaceholders){ letmodifiedText=text; for(leti=0;i<periodExceptions.length;i++){ modifiedText=modifiedText.split(periodExceptionPlaceholders[i]).join(periodExceptions[i]); } returnmodifiedText; } } } } // Function to rate the readability of sentences and give them their class accordingly. functionrateSentences(){ // class names for different scores constscoreClasses=[ 'score-10-0', 'score-20-10', 'score-30-20', 'score-40-30', 'score-50-40', 'score-60-50', 'score-70-60', 'score-80-70', 'score-90-80', 'score-100-90']; // Loop through all sentences, add their score class and their title attribute. letsentenceElements=document.body.getElementsByClassName('sentence'); for(letsentenceElementofsentenceElements){ letsentenceText=getSentenceText(sentenceElement); letscore=getSentenceScore(sentenceText); if(!isNaN(score)){ sentenceElement.title=`Score: ${score.toFixed(2)}`; sentenceElement.dataset.sentenceText=sentenceText; sentenceElement.dataset.score=score; sentenceElement.classList.add(getScoreClass(score,scoreClasses)); } else{ sentenceElement.classList.remove('sentence'); } } // Add the style sheet to color the score classes. addScoreStyleSheet(scoreClasses,readabilityScoreColors); functiongetScoreClass(score,scoreClasses){ letindex=Math.floor(score/10); if(index<0){ index=0; } if(index>9){ index=9; } returnscoreClasses[index]; } functionaddScoreStyleSheet(scoreClasses,readabilityScoreColors){ conststyle=document.createElement('style'); for(leti=0;i<scoreClasses.length;i++){ style.innerHTML+=`.${scoreClasses[i]} {background-color: ${readabilityScoreColors[i]}; } `; } document.head.appendChild(style); } } // Creates an overview at the top of the page // This overview shows the readability of the whole article and other information functioncreateOverview(){ // Readability depends on the number of syllables, words, and sentences lettotalSyllableCount=0; lettotalPolySyllableCount=0; lettotalWordCount=0; constsentenceElements=document.getElementsByClassName('sentence'); lettotalSentenceCount=sentenceElements.length; constsentenceLengthArray=[]; for(letsentenceElementofsentenceElements){ letsentenceText=getSentenceText(sentenceElement); letwords=getWords(sentenceText); totalWordCount+=words.length; sentenceLengthArray.push(words.length); for(letwordofwords){ letsyllableCount=getSyllableCount(word); totalSyllableCount+=syllableCount; if(syllableCount>=3){ totalPolySyllableCount++; } } } lettotalReadability=getFleschKincaidReadability(totalSyllableCount,totalWordCount,totalSentenceCount); lettotalGradeLevel=getFleschKincaidGradeLevel(totalSyllableCount,totalWordCount,totalSentenceCount); lettotalSmogGradeLevel=getSmogGradeLevel(totalPolySyllableCount,totalSentenceCount); constmainDiv=document.getElementById('mw-content-text'); constoverviewDiv=document.createElement('div'); mainDiv.insertBefore(overviewDiv,mainDiv.firstChild); constheadline=document.createElement('h2'); overviewDiv.appendChild(headline); headline.innerHTML='Readability overview'; consttableDiv=document.createElement('div'); overviewDiv.appendChild(tableDiv); tableDiv.style.display='flex'; insertOverviewTable(tableDiv); insertKeyTable(tableDiv); //overviewDiv.appendChild(document.createElement('br')); insertSentenceTable(overviewDiv); functioninsertOverviewTable(parent){ constoverviewTable=document.createElement('table'); parent.appendChild(overviewTable); overviewTable.classList.add('wikitable'); overviewTable.style.marginRight='20px'; /*const overviewCaption = document.createElement('caption'); overviewTable.appendChild(overviewCaption); overviewCaption.innerHTML = 'Readability overview';*/ constoverviewTableBody=document.createElement('tbody'); overviewTable.appendChild(overviewTableBody); addRow(overviewTableBody,'Readability (<a href="https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests">Flesch</a>)',totalReadability.toFixed(2)); addRow(overviewTableBody,'Grade level (<a href="https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests">Flesch</a>)',totalGradeLevel.toFixed(2)); addRow(overviewTableBody,'Grade level (<a href="https://en.wikipedia.org/wiki/SMOG">SMOG</a>)',totalSmogGradeLevel.toFixed(2)); addRow(overviewTableBody,'Sentences',totalSentenceCount); addRow(overviewTableBody,'Words',totalWordCount); addRow(overviewTableBody,'Syllables',totalSyllableCount); addRow(overviewTableBody,'Average sentence length',(totalWordCount/totalSentenceCount).toFixed(2)); addRow(overviewTableBody,'Standard deviation<br>of sentence length',(getStandardDeviation(sentenceLengthArray)).toFixed(2)); functiongetStandardDeviation(numbers){ constsum=numbers.reduce(function(sum,number){returnsum+number;}); constmean=sum/numbers.length; constvarianceSum=numbers.reduce(function(sum,number){console.log(Math.pow(number-mean,2));returnsum+Math.pow(number-mean,2);},0); constvariance=varianceSum/numbers.length; conststandardDeviation=Math.sqrt(variance); returnstandardDeviation; } } // Key for the coloring functioninsertKeyTable(parent){ constkeyTable=document.createElement('table'); parent.appendChild(keyTable); keyTable.classList.add('wikitable'); keyTable.innerHTML=`<thead> <tr> <th>Score</th> <th>School level</th> </tr> </thead> <tbody> <tr class="score-100-90"> <td>100–90</td> <td>5th grade</td> </tr> <tr class="score-90-80"> <td>90–80</td> <td>6th grade</td> </tr> <tr class="score-80-70"> <td>80–70</td> <td>7th grade</td> </tr> <tr class="score-70-60"> <td>70–60</td> <td>8th & 9th grade</td> </tr> <tr class="score-60-50"> <td>60–50</td> <td>10th to 12th grade</td> </tr> <tr class="score-50-40"> <td>50–40</td> <td>College</td> </tr> <tr class="score-40-30"> <td>40–30</td> <td>College</td> </tr> <tr class="score-30-20"> <td>30–20</td> <td>College graduate</td> </tr> <tr class="score-20-10"> <td>20–10</td> <td>College graduate</td> </tr> <tr class="score-10-0"> <td>10–0</td> <td>College graduate</td> </tr> </tbody>`; } // sentence table to display all sentences ordered by lowest score functioninsertSentenceTable(parent){ // button to show/hide the table constsentenceTableButton=document.createElement('button'); parent.append(sentenceTableButton); sentenceTableButton.innerHTML='Show sentences ordered by lowest score'; sentenceTableButton.style.fontSize="24px"; // the table itself constsentenceTable=document.createElement('table'); parent.appendChild(sentenceTable); sentenceTable.classList.add('wikitable'); sentenceTable.style.display='none'; constsentenceCaption=document.createElement('caption'); sentenceTable.appendChild(sentenceCaption); sentenceCaption.innerHTML='Sentences ordered by lowest score'; constsentenceTableBody=document.createElement('tbody'); sentenceTable.appendChild(sentenceTableBody); // matrix to store the table values constsentenceMatrix=[]; for(letsentenceElementofsentenceElements){ letsentenceText=sentenceElement.dataset.sentenceText; letscore=parseFloat(sentenceElement.dataset.score); sentenceMatrix.push([sentenceText,score]); } // sort by lowest score sentenceMatrix.sort(function(a,b){ returna[1]-b[1]; }); // loop through the matrix and add one row per index for(leti=0;i<sentenceMatrix.length;i++){ letsentenceText=sentenceMatrix[i][0]; letscore=sentenceMatrix[i][1]; addRow(sentenceTableBody,sentenceText,score.toFixed(2)); } // show/hide function of the button sentenceTableButton.onclick=function(){ if(sentenceTableButton.innerHTML.includes('Show')){ sentenceTable.style.display=''; sentenceTableButton.innerHTML=sentenceTableButton.innerHTML.split('Show').join('Hide'); } else{ sentenceTable.style.display='none'; sentenceTableButton.innerHTML=sentenceTableButton.innerHTML.split('Hide').join('Show'); } }; } // utility function to add rows to a table functionaddRow(tableBody,name,value){ letrow=document.createElement('tr'); letnameCell=document.createElement('td'); nameCell.innerHTML=name; row.appendChild(nameCell); letvalueCell=document.createElement('td'); valueCell.innerHTML=value; row.appendChild(valueCell); tableBody.appendChild(row); } } // Utility function to extract the text from a sentence element functiongetSentenceText(sentenceElement){ // hide references and certain templates letrefs=sentenceElement.querySelectorAll('.reference, .Inline-Template'); for(letrefofrefs){ ref.style.display='none'; } // the innerText attribute ignores hidden elements letsentenceText=sentenceElement.innerText; // show them again for(letrefofrefs){ ref.style.display=''; } // formatting if(sentenceText[0]=='"'){ sentenceText=sentenceText.substring(1); } sentenceText=sentenceText.trim(); returnsentenceText; } // utility function to get the readability score of a sentence functiongetSentenceScore(sentenceText){ letsyllableCount=0; letwords=getWords(sentenceText); for(letwordofwords){ syllableCount+=getSyllableCount(word); } letwordCount=words.length; letscore=getFleschKincaidReadability(syllableCount,wordCount,1); returnscore; } // utility function: this is the main metric functiongetFleschKincaidReadability(syllableCount,wordCount,sentenceCount){ letwordsPerSentence=wordCount/sentenceCount; letsyllablesPerWord=syllableCount/wordCount; letscore=206.835-(1.015*wordsPerSentence)-(84.6*syllablesPerWord); returnscore; } // utility function: this shows the grade level and is used for the overview functiongetFleschKincaidGradeLevel(syllableCount,wordCount,sentenceCount){ letwordsPerSentence=wordCount/sentenceCount; letsyllablesPerWord=syllableCount/wordCount; letscore=(0.39*wordsPerSentence)+(11.8*syllablesPerWord)-15.59; returnscore; } // utility function: get SMOG readability for the overview functiongetSmogGradeLevel(polySyllableCount,sentenceCount){ letsmogGradeLevel=1.0430*Math.sqrt(polySyllableCount*30/sentenceCount)+3.1291; returnsmogGradeLevel; } // utility function to extract words from a sentence functiongetWords(sentenceText){ letpunctuation='.?!,;:"()[]{}--./&*#$%@+-=<>|~^\\'+"'"; for(letcharacterofpunctuation){ sentenceText=sentenceText.split(character).join(''); } sentenceText=sentenceText.trim(); sentenceText=fullReplace(sentenceText,' ',' '); letwords=sentenceText.split(' '); words=words.filter(function(word){ returnword.length>0; }); returnwords; } // utility function to count the syllables of a word functiongetSyllableCount(word){ word=word.toLowerCase(); if(word.endsWith('e')){ word=word.slice(0,-1); } word=word.split('e').join('a') .split('i').join('a') .split('o').join('a') .split('u').join('a') .split('y').join('a') .split('e').join('a'); word=fullReplace(word,'aa','a'); letsyllableCount=word.split('a').length-1; if(syllableCount<1){ syllableCount=1; } returnsyllableCount; } // utility function to iteratively replace a string until no more occurrences are found functionfullReplace(string,oldSubstring,newSubstring){ letnewString=string; while(newString.includes(oldSubstring)){ newString=newString.split(oldSubstring).join(newSubstring); } returnnewString; } // anonymous main function (function(){ // restrict script to mainspace, userspace, wikipedia, help, and draftspace constnamespaceNumber=mw.config.get('wgNamespaceNumber'); constallowedNamespaces=[0,2,4,12,118]; if(allowedNamespaces.indexOf(namespaceNumber)!=-1){ // add a link to the toolbox $.when(mw.loader.using('mediawiki.util'),$.ready).then(function(){ varportletlink=mw.util.addPortletLink('p-tb','#','Readability'); // run the main function when the link is clicked portletlink.onclick=function(e){ e.preventDefault(); divideParagraphsIntoSentences(); rateSentences(); createOverview(); }; }); } })();