.duplicate-citation-hover { background-color: #ffcccc; }
.duplicate-citation-clicked { border: 1px dotted red; padding: 2px; background-color: #ffe6e6; }
.grouped-references { margin-left: 20px; }
.grouped-references-toggle { cursor: pointer; color: blue; }
.grouped-references-content { display: none; }
.grouped-references-content.expanded { display: block; }
`;
document.head.appendChild(style);
var newContent = '{{Duplicate citations}}\n' + content;
// Create the edit summary.
let summary = '+{{Duplicate citations}}';
if (duplicateInfo.length > 0) {
const urlMap = new Map();
const duplicates = new Map();
const contentMap = new Map();
let totalLinks = 0;
} else {
urlMap.set(url, { refNumber, citeNote, refText });
}
// Check for similar content
let isDuplicate = false;
for (let [content, info] of contentMap) {
if (calculateSimilarity(refText, content) > 0.9) { // 90% similarity threshold
info.push({ refNumber, citeNote, refText, url });
isDuplicate = true;
break;
}
}
if (!isDuplicate) {
contentMap.set(refText, [{ refNumber, citeNote, refText, url }]);
}
}
});
if (duplicates.size > 0 || Array.from(contentMap.values()).some(group => group.length > 1)) {
if (document.querySelector('table.box-Duplicated_citations') === null) {
const editSections = parentDiv.querySelectorAll('span.mw-editsection');
}
//duplicates.forEach((refInfo, Groupurl) and=> collapse duplicate references{
let paragraphInfo = document.createElement('span');
groupAndCollapseDuplicates(duplicates, contentMap);
// Display information about duplicates
displayDuplicateInfo(duplicates, contentMap);
parentDiv.after(newParagraph);
}
}
function groupAndCollapseDuplicates(duplicates, contentMap) {
const referencesSection = document.querySelector('ol.references');
if (!referencesSection) return;
// Process URL-based duplicates
duplicates.forEach((refInfo, url) => {
if (refInfo.length > 1) {
const groupContainer = document.createElement('li');
groupContainer.className = 'grouped-references';
const toggle = document.createElement('span');
toggle.className = 'grouped-references-toggle';
toggle.textContent = `[+] ${refInfo.length} references to ${url}`;
groupContainer.appendChild(toggle);
constlet contenturlLink = document.createElement('ola');
contenturlLink.classNamehref = 'grouped-references-content'url;
refInfourlLink.forEach(reftextContent => {url;
const originalRefurlLink.target = document.getElementById(ref.citeNote)"_blank";
urlLink.rel = "noopener if (originalRef) {noreferrer";
content.appendChild(originalRef.cloneNode(true));
originalRef.remove();
}
});
groupContainer.appendChild(content);
toggleparagraphInfo.addEventListenerappendChild(document.createTextNode('click',Duplicate ()URL: => {'));
contentparagraphInfo.classList.toggleappendChild('expanded'urlLink);
toggleparagraphInfo.textContent = contentappendChild(document.classList.containscreateTextNode('expanded in refs: ') ?);
`[-] ${refInfo.length} references to ${url}` :
`[+] ${refInfo.length} references to ${url}`;
});
referencesSection.appendChild(groupContainer);
}
});
// Process content-based duplicates
contentMap.forEach((group, content) => {
if (group.length > 1) {
const groupContainer = document.createElement('li');
groupContainer.className = 'grouped-references';
const toggle = document.createElement('span');
toggle.className = 'grouped-references-toggle';
toggle.textContent = `[+] ${group.length} similar references`;
groupContainer.appendChild(toggle);
const contentDiv = document.createElement('ol');
contentDiv.className = 'grouped-references-content';
group.forEach(ref => {
const originalRef = document.getElementById(ref.citeNote);
if (originalRef) {
contentDiv.appendChild(originalRef.cloneNode(true));
originalRef.remove();
}
});
groupContainer.appendChild(contentDiv);
toggle.addEventListener('click', () => {
contentDiv.classList.toggle('expanded');
toggle.textContent = contentDiv.classList.contains('expanded') ?
`[-] ${group.length} similar references` :
`[+] ${group.length} similar references`;
});
referencesSection.appendChild(groupContainer);
}
});
}
function displayDuplicateInfo(duplicates, contentMap) {
duplicates.forEach((refInfo, url) => {
let paragraphInfo = document.createElement('span');
let urlLink = document.createElement('a');
urlLink.href = url;
urlLink.textContent = url;
urlLink.target = "_blank";
urlLink.rel = "noopener noreferrer";
paragraphInfo.appendChild(document.createTextNode('Duplicate URL: '));
paragraphInfo.appendChild(urlLink);
paragraphInfo.appendChild(document.createTextNode(' in refs: '));
refInfo.forEach((ref, index) => {
if (ref.citeNote) {
let link = document.createElement('a');
link.href = `#${ref.citeNote}`;
link.textContent = ref.refNumber;
paragraphInfo.appendChild(link);
// Highlight only the specific duplicates on hover
link.addEventListener('mouseover', () => {
refInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
if (duplicate.citeNote === ref.citeNote) {
citationElement.classList.add('duplicate-citation-hover');
} else {
citationElement.classList.add('duplicate-citation-highlight');
}
}
});
});
link.addEventListener('mouseout', () => {
refInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
citationElement.classList.remove('duplicate-citation-hover');
citationElement.classList.remove('duplicate-citation-highlight');
}
});
});
// Highlight duplicates on click and allow navigation
link.addEventListener('click', () => {
// Remove previous click highlights
document.querySelectorAll('.duplicate-citation-clicked').forEach(el => {
el.classList.remove('duplicate-citation-clicked');
});
// Add new click highlights
refInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
citationElement.classList.add('duplicate-citation-clicked');
}
});
// The default behavior (navigation) will now occur
});
} else {
paragraphInfo.appendChild(document.createTextNode(ref.refNumber));
}
// Calculate similarity with the next reference
if (index < refInfo.length - 1) {
const similarity = calculateSimilarity(ref.refText, refInfo[index + 1].refText);
const similarityPercentage = Math.round(similarity * 100);
paragraphInfo.appendChild(document.createTextNode(` (${similarityPercentage}%)`));
}
if (index < refInfo.length - 1) {
paragraphInfo.appendChild(document.createTextNode(', '));
}
});
paragraphInfo.appendChild(document.createElement('br'));
newParagraph.appendChild(paragraphInfo);
});
// Add information about similar content duplicates
contentMap.forEach((group, content) => {
if (group.length > 1) {
let paragraphInfo = document.createElement('span');
paragraphInfo.appendChild(document.createTextNode('Similar content in refs: '));
grouprefInfo.forEach((ref, index) => {
if (ref.citeNote) {
let link = document.createElement('a');
paragraphInfo.appendChild(link);
// Highlight similaronly contentthe specific duplicates on hover and click (same as URL duplicates)
link.addEventListener('mouseover', () => {
grouprefInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
});
link.addEventListener('mouseout', () => {
grouprefInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
});
// Highlight duplicates on click and allow navigation
link.addEventListener('click', () => {
// Remove previous click highlights
document.querySelectorAll('.duplicate-citation-clicked').forEach(el => {
el.classList.remove('duplicate-citation-clicked');
});
group.forEach(duplicate// =>Add {new click highlights
refInfo.forEach(duplicate => {
const citationElement = document.getElementById(duplicate.citeNote);
if (citationElement) {
}
});
// The default behavior (navigation) will now occur
});
} else {
}
if// (indexCalculate <similarity group.lengthwith -the 1)next {reference
if (index < refInfo.length - 1) {
const similarity = calculateSimilarity(ref.refText, refInfo[index + 1].refText);
const similarityPercentage = Math.round(similarity * 100);
paragraphInfo.appendChild(document.createTextNode(` (${similarityPercentage}%)`));
}
if (index < refInfo.length - 1) {
paragraphInfo.appendChild(document.createTextNode(', '));
}
paragraphInfo.appendChild(document.createElement('br'));
newParagraph.appendChild(paragraphInfo);
});
});
parentDiv.after(newParagraph);
}
}
|