User:Polygnotus/DuplicateReferences.js: Difference between revisions

Content deleted Content added
reporting false positives
move "add {{duplicated citations}}" into table, add status indicators (working/done/error)
Line 4:
mw.loader.using(['mediawiki.util'], function () {
$(document).ready(function () {
 
const DEBUG = false;
 
function debug(...args) {
if (DEBUG) {
Line 23 ⟶ 24:
let nextElement = element.nextElementSibling;
while (nextElement) {
if (nextElement.tagName.toLowerCase() === 'div' &&
(nextElement.classList.contains('reflist') || nextElement.classList.contains('mw-references-wrap'))) {
return nextElement;
Line 70 ⟶ 71:
document.head.appendChild(style);
 
function addDuplicateCitationsTemplate(linkElement) {
debug("Adding duplicate citations template");
showLoading(linkElement);
var api = new mw.Api();
var pageTitle = mw.config.get('wgPageName');
 
let duplicateInfo = getDuplicateInfo();
 
// Get current date
const currentDate = new Date();
Line 93 ⟶ 95:
rvslots: 'main',
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var content = page.revisions[0].slots.main.content;
Line 141 ⟶ 143:
summary: summary
});
}).then(function () {
mw.notifyshowSuccess('Successfully added the Duplicate citations template!'linkElement);
___location.reloadsetTimeout(function (); {
}) ___location.catchreload(function(error) {;
}, 100); // Reload after 0.1 second
}).catch(function (error) {
console.error('Error:', error);
showError(linkElement);
mw.notify('Failed to add the template. See console for details.', {type: 'error'});
});
}
 
function showLoading(element) {
element.innerHTML = '<sup><small>[ Working... ]</small></sup>';
}
 
function showSuccess(element) {
element.innerHTML = '<sup><small>[ Done ]</small></sup>';
}
 
function showError(element) {
element.innerHTML = '<sup><small>[ Error ]</small></sup>';
}
 
Line 171 ⟶ 188:
debug("Text 1:", a);
debug("Text 2:", b);
 
if (a.length === 0) return b.length;
if (b.length === 0) return a.length;
Line 216 ⟶ 233:
function getDuplicateInfo() {
debug("Getting duplicate info");
 
const duplicates = [];
const urlMap = new Map();
Line 228 ⟶ 245:
const refNumber = index + 1;
debug(`Processing reference item ${refNumber} (${refId})`);
 
// Get the visible text of the entire reference item
const refText = getVisibleText(item);
Line 238 ⟶ 255:
for (let link of links) {
const url = link.href;
 
// Skip this reference if the URL doesn't contain 'http'
if (!url.includes('http')) {
Line 245 ⟶ 262:
}
const linkText = link.textContent.trim();
 
if (
// (!url.includes("wikipedia.org/wiki/") || url.includes("Special:BookSources")) &&
linkText !== "Archived" &&
!url.includes("wikipedia.org") &&
Line 253 ⟶ 270:
!url.startsWith("https://www.bbc.co.uk/news/live/") && // BBC live articles get frequent updates
!url.startsWith("https://books.google.com/") && //may be 2 different pages of the same book
!url.startsWith("https://archive.org/details/isbn_")
) {
validLink = link;
Line 289 ⟶ 306:
}
}
duplicates.push({ url, refs });
}
});
Line 302 ⟶ 319:
table.className = 'wikitable mw-collapsible duplicate-references-table';
table.setAttribute('role', 'presentation');
 
const tbody = document.createElement('tbody');
table.appendChild(tbody);
 
const headerRow = document.createElement('tr');
const headerCell = document.createElement('td');
headerCell.innerHTML = '<strong>Duplicate References</strong>';
 
const toggleSpan = document.createElement('span');
toggleSpan.className = 'mw-collapsible-toggle';
toggleSpan.innerHTML = '[<a href="#" class="mw-collapsible-text">hide</a>]';
headerCell.appendChild(toggleSpan);
 
 
// Check if the {{Duplicated citations}} template is already present
const duplicatedCitationsTemplate = document.querySelector('table.box-Duplicated_citations');
 
// Only add the link if the template is not present
if (!duplicatedCitationsTemplate) {
 
// Add the "add {{duplicated citations}}" link to the header
const addTemplateLink = document.createElement('a');
addTemplateLink.textContent = ' add {{duplicated citations}} ';
addTemplateLink.href = '#';
addTemplateLink.addEventListener('click', function (e) {
e.preventDefault();
addDuplicateCitationsTemplate(this);
});
//headerCell.appendChild(document.createTextNode(' ['));
headerCell.appendChild(addTemplateLink);
//headerCell.appendChild(document.createTextNode(']'));
}
headerRow.appendChild(headerCell);
tbody.appendChild(headerRow);
 
const pageTitle = mw.config.get('wgPageName').replace(/_/g, ' ');
 
duplicateInfo.forEach(({ url, refs }) => {
const row = document.createElement('tr');
const cell = document.createElement('td');
 
// Create report icon
const reportIcon = document.createElement('a');
Line 330 ⟶ 366:
reportIcon.style.marginRight = '5px';
cell.appendChild(reportIcon);
 
let urlLink = document.createElement('a');
urlLink.href = url;
Line 336 ⟶ 372:
urlLink.target = "_blank";
urlLink.rel = "noopener noreferrer";
 
cell.appendChild(urlLink);
cell.appendChild(document.createTextNode(' in refs: '));
 
const originalRef = refs[0];
refs.forEach((ref, index) => {
Line 346 ⟶ 382:
link.textContent = ref.number;
cell.appendChild(link);
 
// Add similarity information
if (index > 0) {
Line 378 ⟶ 414:
});
});
 
link.addEventListener('click', () => {
document.querySelectorAll('.duplicate-citation-clicked').forEach(el => {
Line 390 ⟶ 426:
});
});
 
if (index < refs.length - 1) {
cell.appendChild(document.createTextNode(', '));
}
});
 
row.appendChild(cell);
tbody.appendChild(row);
});
 
return table;
}
 
function checkDuplicateReferenceLinks() {
debug("Checking for duplicate reference links");
const duplicateInfo = getDuplicateInfo();
 
if (duplicateInfo.length > 0) {
debug("Duplicates found, creating collapsible table");
 
if (document.querySelector('table.box-Duplicated_citations') === null) {
const editSections = containerDiv.querySelectorAll('span.mw-editsection');
editSections.forEach(editSection => {
let spanBefore = document.createElement('span');
spanBefore.className = 'mw-editsection-bracket';
spanBefore.textContent = '[';
let addTemplateLink = document.createElement('a');
addTemplateLink.textContent = ' add {{duplicated citations}} ';
addTemplateLink.href = '#';
addTemplateLink.addEventListener('click', function(e) {
e.preventDefault();
addDuplicateCitationsTemplate();
});
let spanAfter = document.createElement('span');
spanAfter.className = 'mw-editsection-bracket';
spanAfter.textContent = ']';
editSection.appendChild(spanBefore);
editSection.appendChild(addTemplateLink);
editSection.appendChild(spanAfter);
});
}
const table = createCollapsibleTable(duplicateInfo);
containerDiv.after(table);
Line 458 ⟶ 469:
setTableState(initialState);
 
toggleLink.addEventListener('click', function (e) {
e.preventDefault();
const isCurrentlyCollapsed = tableBody.is(':hidden');
Line 467 ⟶ 478:
}
}
 
checkDuplicateReferenceLinks();
debug("Script execution completed");