User:Phlsph7/HighlightUnreferencedPassages.js
Appearance
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/HighlightUnreferencedPassages. |
/*** Highlight unreferenced passages ***/
(function(){
// finds passages that lack references and marks them
function markUnreferencedPassages(){
// stylesheet to color passages lacking references
function addStylesheet(){
const stylesheet = document.createElement('style');
stylesheet.innerHTML = `
.has-no-references, .Template-Fact {
background: LightPink;
}
`;
document.head.appendChild(stylesheet);
}
// check whether references are relevant to the element
function isEligible(element, excludedSections){
// exclude elements that are part of navboxes, sidebars, and the like
// references do not matter for them
if(hasParentClass(element, 'navbox')
|| hasParentClass(element, 'sidebar')
|| hasParentClass(element, 'infobox')
|| hasParentClass(element, 'side-box-flex')
|| hasParentClass(element, 'noprint')
|| hasParentClass(element, 'refbegin')
|| hasParentClass(element, 'gallery')
|| hasParentClass(element, 'toc')
|| hasParentClass(element, 'reflist')){
return false;
}
// exclude elements that belong to certain sections where references do not matter
const sectionName = getSectionName(element);
if(excludedSections.indexOf(sectionName) != -1){
return false;
}
return true;
}
// utility function to check whether the elements parents and grand parents have a certain class
function hasParentClass(element, className){
return element.closest('.' + className) != null;
}
// utility function to get the section name to which an element belongs
function getSectionName(element){
var mainContainerChildElement = getGrandchildOfMainContainer(element);
var sectionName = ''; // default section name, this corresponds to the lead
var previousElement = mainContainerChildElement.previousElementSibling;
// sections always start with an h2 element
// the script loops back from an element to the previous element until an h2 element is discovered
while(previousElement != null){
// check whether it is an h2 element
if(previousElement.classList.contains('mw-heading2')){
// extract the section name
sectionName = previousElement.innerText.split('[edit]').join('');
break;
}
previousElement = previousElement.previousElementSibling;
}
return sectionName;
}
// utility function: for any element, return the parent that is a grandchild of the main container
function getGrandchildOfMainContainer(element){
const mainContainer = document.getElementById('mw-content-text');
if(element.parentElement.parentElement == mainContainer){
return element;
}
else{
return getGrandchildOfMainContainer(element.parentElement);
}
}
// utility function to check whether the lead section of the article should be marked
function shouldMarkLead(){
// if it is a draft then the lead should be highlighted
var pageTitleNamespace = document.getElementsByClassName('mw-page-title-namespace')[0];
if(pageTitleNamespace != null){
if(pageTitleNamespace.innerText === 'User' || pageTitleNamespace.innerText === 'Draft'){
return true;
}
}
// if it is a stub then the lead should be highlighted
else if(document.getElementsByClassName('stub').length > 0){
return true;
}
// otherwise not
else {
return false;
}
}
// marks elements that lack references
function mark(element){
// mark elements without any reference elements
if(element.getElementsByClassName('reference').length == 0){
element.classList.add("has-no-references");
}
// mark elements with some reference elements
else{
// if the last element is not a reference then start marking it
markUntilPreviousReference(element.lastChild);
// starts from each "citation needed" tag, goes backwards and marks until it reaches a reference
var citationNeededTags = element.getElementsByClassName('Template-Fact');
for(var citationNeededTag of citationNeededTags){
markUntilPreviousReference(citationNeededTag);
}
}
}
// Function to mark unreferenced passages. It starts with one node and loops back to previous nodes until it hits a reference
function markUntilPreviousReference(childNode){
var currentNode = childNode;
while(currentNode != null){
// handle nodes that are not HTML elements
if(currentNode.classList == null){
// create a span element and classify it
var span = document.createElement('span');
span.classList.add("has-no-references");
// copy the node's text into the span element and replace the node with the span element
span.innerHTML = currentNode.data;
currentNode.parentElement.replaceChild(span, currentNode);
currentNode = span;
}
// handle nodes that are HTML elements
// if the node is a reference
else if(currentNode.classList.contains('reference')){
// check whether the node is an actual reference: they contain numbers
if(currentNode != null &&
currentNode.innerText != null &&
/[0-9]/.test(currentNode.innerText) &&
!currentNode.innerText.toLowerCase().includes('note') &&
!currentNode.innerText.toLowerCase().includes('nb')){
break;
}
// otherwise it is an explanatory footnote and not a reference
else{
currentNode.classList.add('has-no-references');
}
}
// if the node is an element but not a reference then classify it
else {
currentNode.classList.add('has-no-references');
}
// set the current node to the previous one to continue the loop
currentNode = currentNode.previousSibling;
}
}
// removes the red background from elements that were falsely highlighted
function excludeFalsePositives(){
// exclude references used in nested lists
var unreferencedElements = document.getElementsByClassName('has-no-references');
for(let unreferencedElement of unreferencedElements){
// if the element contains a reference inside then it is not unreferenced, so remove the class
if(unreferencedElement.getElementsByClassName('reference').length > 0){
unreferencedElement.classList.remove('has-no-references');
}
}
// exclude quoteboxes
unreferencedElements = document.getElementsByClassName('has-no-references');
for(let unreferencedElement of unreferencedElements){
// see if the the element is part of a quotebox that has a citation
var quoteboxParent = unreferencedElement.closest('.quotebox');
if(quoteboxParent != null && quoteboxParent.getElementsByTagName('cite').length > 0){
unreferencedElement.classList.remove('has-no-references');
}
}
// do not mark empty elements
unreferencedElements = document.getElementsByClassName('has-no-references');
for(let unreferencedElement of unreferencedElements){
if(unreferencedElement.innerHTML == "\n" || unreferencedElement.innerHTML == " \n"){
unreferencedElement.classList.remove('has-no-references');
}
}
// exclude the template {{rp}}
var referenceElements = document.getElementsByClassName('reference');
for(let referenceElement of referenceElements){
if(referenceElement.classList.contains('has-no-references')){
referenceElement.classList.remove('has-no-references');
}
}
// blockquotes often use a different reference style, so false positives need to be excluded separately
const unreferencedParagraphsInsideBlockquotes = document.querySelectorAll('blockquote > p.has-no-references');
for(var unreferencedParagraphInsideBlockquotes of unreferencedParagraphsInsideBlockquotes){
const parent = unreferencedParagraphInsideBlockquotes.parentElement;
// check whether the parent blockquote contains a citation element
if(parent.getElementsByClassName('templatequotecite').length > 0){
// if it does then the paragraph is not unreferenced
unreferencedParagraphInsideBlockquotes.classList.remove('has-no-references');
}
}
// ignore elements in the template "ombox"
let unreferencedElementsInOmboxes = document.querySelectorAll(".ombox .has-no-references");
for (let element of unreferencedElementsInOmboxes) {
element.classList.remove("has-no-references");
}
// for drafts: exclude comments
var pageTitleNamespace = document.getElementsByClassName('mw-page-title-namespace')[0];
if(pageTitleNamespace != null){
if(pageTitleNamespace.innerText === 'User' || pageTitleNamespace.innerText === 'Draft'){
let unreferencedComments = document.querySelectorAll(".has-no-references:has(.localcomments)");
for (let unreferencedComment of unreferencedComments) {
unreferencedComment.classList.remove("has-no-references");
}
}
}
}
addStylesheet();
// all paragraphs and list entries should have references
const paragraphs = document.getElementById('mw-content-text').getElementsByTagName('p');
const listEntries = document.getElementById('mw-content-text').getElementsByTagName('li');
const elements = Array.from(paragraphs).concat(Array.from(listEntries));
// these sections are not checked for references
var excludedSections = ['Plot', 'Plots', 'Plot summary', 'Plot synopsis', 'Synopsis', 'Storylines', 'Further reading', 'See also', 'External links', 'References', 'Bibliography', 'Notes', 'Selected publications', 'Selected works', 'Cited sources', 'Sources', 'Footnotes'];
// dedice whether the lead should be checked for references
if(!shouldMarkLead()){
excludedSections.push('');
}
for(var element of elements){
// check whether the element should be excluded
if(isEligible(element, excludedSections)){
// mark the element if it lacks references
mark(element);
}
}
excludeFalsePositives();
}
// restrict script to mainspace, userspace, and draftspace
var namespaceNumber = mw.config.get('wgNamespaceNumber');
if (namespaceNumber === 0 || namespaceNumber === 2 || namespaceNumber === 118) {
// add a link to the toolbox
$.when(mw.loader.using('mediawiki.util'), $.ready).then(function (){
var portletlink = mw.util.addPortletLink('p-tb', '#', 'Highlight unreferenced passages');
// run the main function when the link is clicked
portletlink.onclick = function(e) {
e.preventDefault();
markUnreferencedPassages();
const unreferencedElements = document.getElementsByClassName('has-no-references');
//mw.notify(`${unreferencedElements.length} elements were highlighted`);
mw.notify('Highlighting finished.');
};
});
}
if (namespaceNumber === 0 || namespaceNumber === 118) {
if(typeof highlightUnreferencedPassagesAutomatic != 'undefined' && highlightUnreferencedPassagesAutomatic == true){
markUnreferencedPassages();
}
}
})();