Jump to content

User:Polygnotus/Scripts/NextComment.js

From Wikipedia, the free encyclopedia
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.
// <nowiki>
// Navigate between your own comments on Wikipedia talk pages
// Add this to your common.js file

(function() {
    'use strict';
    
    // Only run on talk pages
    if (mw.config.get('wgNamespaceNumber') % 2 !== 1) {
        return;
    }
    
    mw.loader.using(['mediawiki.util'], function() {
        var username = mw.config.get('wgUserName');
        
        if (!username) {
            return; // Not logged in
        }
        
        // Find all comment signatures using data-mw-comment-sig attribute
        var signatures = [];
        var processedComments = new Set();
        var commentSigs = document.querySelectorAll('[data-mw-comment-sig]');
        
        commentSigs.forEach(function(sigSpan) {
            // Get the comment ID from the data attribute
            var commentId = sigSpan.getAttribute('data-mw-comment-sig');
            
            // Skip if already processed
            if (processedComments.has(commentId)) {
                return;
            }
            
            // Check if this comment is by the current user
            var authorMatch = commentId.match(/^c-([^-]+)-/);
            if (!authorMatch || authorMatch[1] !== username.replace(/ /g, '_')) {
                return;
            }
            
            // Find the User: link (not User_talk:) in the signature
            var userLink = sigSpan.parentElement.querySelector('a[href^="/wiki/User:' + username.replace(/ /g, '_') + '"]');
            
            if (userLink && !userLink.getAttribute('href').includes('User_talk:')) {
                // Find the parent container (usually <dd> or <li>)
                var commentContainer = sigSpan.closest('dd, li');
                
                signatures.push({
                    link: userLink,
                    container: commentContainer,
                    commentId: commentId
                });
                
                processedComments.add(commentId);
            }
        });
        
        if (signatures.length === 0) {
            return; // No signatures found
        }
        
        // Sort by position in document
        signatures.sort(function(a, b) {
            return a.link.compareDocumentPosition(b.link) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
        });
        
        // Function to highlight a comment
        function highlightComment(sig, duration) {
            duration = duration || 2000;
            
            // Find the start and end markers
            var startMarker = document.querySelector('[data-mw-comment-start][id="' + sig.commentId + '"]');
            var endMarker = document.querySelector('[data-mw-comment-end="' + sig.commentId + '"]');
            
            if (!startMarker || !endMarker) {
                return;
            }
            
            // Find the container (dd or li) that holds this comment
            var container = startMarker.closest('dd, li');
            if (!container) {
                return;
            }
            
            // Collect all block elements in this container up to (but not including) nested replies
            var elementsToHighlight = [];
            
            function collectElements(node) {
                if (node === endMarker) {
                    return true; // Stop when we hit end marker
                }
                
                if (node.nodeType === Node.ELEMENT_NODE) {
                    var tagName = node.tagName;
                    
                    // If we hit a nested dl/ul/ol, stop - that's a reply
                    if ((tagName === 'DL' || tagName === 'UL' || tagName === 'OL') && node !== container) {
                        return true;
                    }
                    
                    // Collect block elements
                    if (tagName === 'P' || tagName === 'DD' || tagName === 'DIV') {
                        elementsToHighlight.push(node);
                    }
                    
                    // Recursively check children
                    for (var i = 0; i < node.childNodes.length; i++) {
                        if (collectElements(node.childNodes[i])) {
                            return true;
                        }
                    }
                }
                
                return false;
            }
            
            // Start collecting from the container
            for (var i = 0; i < container.childNodes.length; i++) {
                if (collectElements(container.childNodes[i])) {
                    break;
                }
            }
            
            // If no block elements found, just highlight the container
            if (elementsToHighlight.length === 0) {
                elementsToHighlight = [container];
            }
            
            // Apply highlighting
            var originalStyles = [];
            elementsToHighlight.forEach(function(elem) {
                originalStyles.push({
                    element: elem,
                    backgroundColor: elem.style.backgroundColor,
                    transition: elem.style.transition
                });
                elem.style.backgroundColor = '#ffff99';
                elem.style.transition = 'background-color 0.3s';
            });
            
            // Fade out
            setTimeout(function() {
                originalStyles.forEach(function(item) {
                    item.element.style.backgroundColor = item.backgroundColor;
                });
                setTimeout(function() {
                    originalStyles.forEach(function(item) {
                        item.element.style.transition = item.transition;
                    });
                }, 300);
            }, duration);
        }
        
        // Add navigation buttons before each signature
        signatures.forEach(function(sig, index) {
            var navSpan = document.createElement('span');
            navSpan.style.marginRight = '5px';
            navSpan.style.fontSize = '0.9em';
            
            // Previous button
            if (index > 0) {
                var prevBtn = document.createElement('a');
                prevBtn.href = '#';
                prevBtn.textContent = '<';
                prevBtn.title = 'Previous comment by ' + username;
                prevBtn.style.textDecoration = 'none';
                prevBtn.style.fontWeight = 'bold';
                prevBtn.style.padding = '0 3px';
                prevBtn.onclick = function(e) {
                    e.preventDefault();
                    var targetSig = signatures[index - 1];
                    targetSig.link.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    highlightComment(targetSig);
                };
                navSpan.appendChild(prevBtn);
            } else {
                var prevPlaceholder = document.createElement('span');
                prevPlaceholder.textContent = ' ';
                prevPlaceholder.style.padding = '0 3px';
                navSpan.appendChild(prevPlaceholder);
            }
            
            // Next button
            if (index < signatures.length - 1) {
                var nextBtn = document.createElement('a');
                nextBtn.href = '#';
                nextBtn.textContent = '>';
                nextBtn.title = 'Next comment by ' + username;
                nextBtn.style.textDecoration = 'none';
                nextBtn.style.fontWeight = 'bold';
                nextBtn.style.padding = '0 3px';
                nextBtn.onclick = function(e) {
                    e.preventDefault();
                    var targetSig = signatures[index + 1];
                    targetSig.link.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    highlightComment(targetSig);
                };
                navSpan.appendChild(nextBtn);
            }
            
            // Insert navigation before the signature link
            sig.link.parentNode.insertBefore(navSpan, sig.link);
        });
        
        // Add indicator to show total comments
        mw.util.addPortletLink('p-tb', '#', 'Your comments: ' + signatures.length, 'pt-mycomments', 'Jump to your first comment');
        document.getElementById('pt-mycomments').addEventListener('click', function(e) {
            e.preventDefault();
            if (signatures.length > 0) {
                signatures[0].link.scrollIntoView({ behavior: 'smooth', block: 'center' });
                highlightComment(signatures[0]);
            }
        });
    });
})();
// </nowiki>