Jump to content
Wikipedia The Free Encyclopedia

User:Phlsph7/Readability.js

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 user script seems to have a documentation page at User:Phlsph7/Readability.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
 /* 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();
 };
 });
 }
 })();

AltStyle によって変換されたページ (->オリジナル) /