User:Polygnotus/DuplicateReferences.js

This is an old revision of this page, as edited by Polygnotus (talk | contribs) at 09:44, 16 July 2024. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
mw.loader.using(['mediawiki.util'], function () {
    $(document).ready(function () {
        console.log("Script started");

        if ((mw.config.get('wgNamespaceNumber') !== 0 && mw.config.get('wgPageName') !== 'User:Polygnotus/dupreftest') || mw.config.get('wgAction') !== 'view') {
            console.log("Not the correct page or action, script terminated");
            return;
        }

        console.log("Page title:", document.title);
        console.log("URL:", window.___location.href);

        function findNextReflistDiv(element) {
            let nextElement = element.nextElementSibling;
            while (nextElement) {
                if (nextElement.tagName.toLowerCase() === 'div' && 
                    (nextElement.classList.contains('reflist') || nextElement.classList.contains('mw-references-wrap'))) {
                    return nextElement;
                }
                nextElement = nextElement.nextElementSibling;
            }
            return null;
        }

        const referencesHeader = document.querySelector("h2#References");
        if (!referencesHeader) {
            console.log("References heading not found, script terminated");
            return;
        }

        const containerDiv = referencesHeader.closest("div");
        if (!containerDiv) {
            console.log("Container div not found, script terminated");
            return;
        }

        const reflistDiv = findNextReflistDiv(containerDiv);
        if (!reflistDiv) {
            console.log("Reflist div not found, script terminated");
            return;
        }

        const referencesList = reflistDiv.querySelector('ol.references');
        if (!referencesList) {
            console.log("ol.references not found within reflist div");
            return;
        }

        const style = document.createElement('style');
        style.textContent = `
            li:target { border: 1px dotted red; padding: 2px; background-color: #ffcccc !important;}
            .duplicate-citation-highlight { background-color: #ffe6e6; }
            .duplicate-citation-hover { background-color: #ffcccc; }
            .duplicate-citation-clicked { border: 1px dotted red; padding: 2px; background-color: #ffe6e6; }
        `;
        document.head.appendChild(style);

        let newParagraph = document.createElement("p");
        newParagraph.style.color = "red";

        function addDuplicateCitationsTemplate() {
            console.log("Adding duplicate citations template");
            var api = new mw.Api();
            var pageTitle = mw.config.get('wgPageName');

            let duplicateInfo = getDuplicateInfo();

            api.get({
                action: 'query',
                prop: 'revisions',
                titles: pageTitle,
                rvprop: 'content',
                rvslots: 'main',
                formatversion: 2
            }).then(function(data) {
                var page = data.query.pages[0];
                var content = page.revisions[0].slots.main.content;

                var newContent = '{{Duplicate citations}}\n' + content;

                let summary = '+{{Duplicate citations}}';
                if (duplicateInfo.length > 0) {
                    summary += ': ';
                    duplicateInfo.forEach((info, index) => {
                        summary += `${info.url} (refs: ${info.refs.join(', ')})`;
                        if (index < duplicateInfo.length - 1) {
                            summary += '; ';
                        }
                    });
                }

                return api.postWithToken('csrf', {
                    action: 'edit',
                    title: pageTitle,
                    text: newContent,
                    summary: summary
                });
            }).then(function() {
                mw.notify('Successfully added the Duplicate citations template!');
                ___location.reload();
            }).catch(function(error) {
                console.error('Error:', error);
                mw.notify('Failed to add the template. See console for details.', {type: 'error'});
            });
        }

        function getDuplicateInfo() {
            console.log("Getting duplicate info");
            
            const referenceItems = referencesList.querySelectorAll('li');
            console.log("Number of reference items:", referenceItems.length);
            
            const urlMap = new Map();
            const duplicates = [];

            referenceItems.forEach((item, index) => {
                const refNumber = index + 1;
                console.log(`Processing reference item ${refNumber}`);
                const span = item.querySelector('span.reference-text');
                if (!span) {
                    console.log(`  No reference-text span found in item ${refNumber}`);
                    return;
                }
                const links = span.querySelectorAll('a');
                console.log(`  Number of links in this span: ${links.length}`);

                let validLink = null;
                for (let link of links) {
                    const url = link.href;
                    const linkText = link.textContent.trim();
                    
                    if (
                        linkText !== "Archived" &&
                        (!url.includes("wikipedia.org/wiki/") || url.includes("Special:BookSources")) &&
                        !url.includes("_(identifier)")
                    ) {
                        validLink = link;
                        console.log(`  Valid link found: ${url}`);
                        break;
                    }
                }

                if (validLink) {
                    const url = validLink.href;
                    if (urlMap.has(url)) {
                        urlMap.get(url).push(refNumber.toString());
                        console.log(`  Duplicate found for URL: ${url}`);
                    } else {
                        urlMap.set(url, [refNumber.toString()]);
                        console.log(`  New URL added to map: ${url}`);
                    }
                } else {
                    console.log(`  No valid link found in this item`);
                }
            });

            urlMap.forEach((refs, url) => {
                if (refs.length > 1) {
                    duplicates.push({ url, refs });
                }
            });

            console.log("Number of duplicate sets found:", duplicates.length);
            console.log("Duplicate sets:", duplicates);
            return duplicates;
        }

        function checkDuplicateReferenceLinks() {
            console.log("Checking for duplicate reference links");
            const duplicateInfo = getDuplicateInfo();
            
            if (duplicateInfo.length > 0) {
                console.log("Duplicates found, creating list");
                
                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);
                    });
                }
                
                duplicateInfo.forEach(({ url, refs }) => {
                    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: '));
                    
                    refs.forEach((refNumber, index) => {
                        let link = document.createElement('a');
                        link.href = `#cite_note-${refNumber}`;
                        link.textContent = refNumber;
                        paragraphInfo.appendChild(link);

                        link.addEventListener('mouseover', () => {
                            refs.forEach(ref => {
                                const citationElement = document.getElementById(`cite_note-${ref}`);
                                if (citationElement) {
                                    if (ref === refNumber) {
                                        citationElement.classList.add('duplicate-citation-hover');
                                    } else {
                                        citationElement.classList.add('duplicate-citation-highlight');
                                    }
                                }
                            });
                        });
                        link.addEventListener('mouseout', () => {
                            refs.forEach(ref => {
                                const citationElement = document.getElementById(`cite_note-${ref}`);
                                if (citationElement) {
                                    citationElement.classList.remove('duplicate-citation-hover');
                                    citationElement.classList.remove('duplicate-citation-highlight');
                                }
                            });
                        });

                        link.addEventListener('click', () => {
                            document.querySelectorAll('.duplicate-citation-clicked').forEach(el => {
                                el.classList.remove('duplicate-citation-clicked');
                            });
                            refs.forEach(ref => {
                                const citationElement = document.getElementById(`cite_note-${ref}`);
                                if (citationElement) {
                                    citationElement.classList.add('duplicate-citation-clicked');
                                }
                            });
                        });
                        
                        if (index < refs.length - 1) {
                            paragraphInfo.appendChild(document.createTextNode(', '));
                        }
                    });
                    
                    paragraphInfo.appendChild(document.createElement('br'));
                    newParagraph.appendChild(paragraphInfo);
                });
                
                console.log("Appending duplicate list to page");
                containerDiv.after(newParagraph);
            } else {
                console.log("No duplicates found");
            }
        }
        
        checkDuplicateReferenceLinks();
        console.log("Script execution completed");
    });
});