Jump to content

User:Polygnotus/Scripts/ScrollToMe.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.
// =====================================================================
// Scroll-to-username on search results
// Adds a link above each search result title. The target username is
// passed via URL parameter so new-tab navigation works correctly.
// =====================================================================

( function () {
    'use strict';

    var USERNAME   = mw.config.get( 'wgUserName' );
    var PARAM_NAME = 'wpScrollTo';

    if ( !USERNAME ) {
        return;
    }

    // ------------------------------------------------------------------
    // PART 1 – On the destination page: scroll to the first occurrence
    // ------------------------------------------------------------------
    function checkAndScroll() {
        var target = mw.util.getParamValue( PARAM_NAME );
        if ( !target ) {
            return;
        }

        mw.hook( 'wikipage.content' ).add( function () {
            scrollToFirstOccurrence( target );
        } );
    }

    function scrollToFirstOccurrence( username ) {
        var contentRoot = document.getElementById( 'mw-content-text' ) || document.body;
        var titleHeading = document.getElementById( 'firstHeading' );

        var walker = document.createTreeWalker(
            contentRoot,
            NodeFilter.SHOW_TEXT,
            {
                acceptNode: function ( node ) {
                    var tag = node.parentElement && node.parentElement.tagName;
                    if ( tag === 'SCRIPT' || tag === 'STYLE' ) {
                        return NodeFilter.FILTER_REJECT;
                    }
                    // Skip anything inside the page title heading.
                    if ( titleHeading && titleHeading.contains( node ) ) {
                        return NodeFilter.FILTER_REJECT;
                    }
                    return node.nodeValue.indexOf( username ) !== -1
                        ? NodeFilter.FILTER_ACCEPT
                        : NodeFilter.FILTER_SKIP;
                }
            },
            false
        );

        var node = walker.nextNode();
        if ( !node ) {
            return;
        }

        var el = node.parentElement;
        el.scrollIntoView( { behavior: 'smooth', block: 'center' } );

        var originalBg = el.style.backgroundColor;
        el.style.transition = 'background-color 0.3s';
        el.style.backgroundColor = '#ff9';
        setTimeout( function () {
            el.style.backgroundColor = originalBg;
        }, 2500 );
    }

    // ------------------------------------------------------------------
    // PART 2 – On the search results page: add scroll links
    // ------------------------------------------------------------------
    function addScrollLinks() {
        var resultHeadings = document.querySelectorAll( '.mw-search-result-heading' );

        resultHeadings.forEach( function ( heading ) {
            var titleLink = heading.querySelector( 'a' );
            if ( !titleLink ) {
                return;
            }

            // Build the destination URL with the scroll parameter baked in.
            var destUrl = new URL( titleLink.href );
            destUrl.searchParams.set( PARAM_NAME, USERNAME );

            var scrollLink = document.createElement( 'a' );
            scrollLink.href        = destUrl.href;
            scrollLink.title       = 'Go to this page and scroll to "' + USERNAME + '"';
            scrollLink.textContent = '↓ scroll to "' + USERNAME + '"';
            scrollLink.style.cssText = [
                'display: block',
                'margin-bottom: 0.25em',
                'font-size: 0.82em',
                'font-weight: normal'
            ].join( ';' );

            // Insert above the title link, not after it.
            heading.insertBefore( scrollLink, titleLink );
        } );
    }

    // ------------------------------------------------------------------
    // Entry point
    // ------------------------------------------------------------------
    var specialPage = mw.config.get( 'wgCanonicalSpecialPageName' );

    if ( specialPage === 'Search' ) {
        var query = mw.util.getParamValue( 'search' ) || '';
        if ( query.toLowerCase().indexOf( USERNAME.toLowerCase() ) !== -1 ) {
            $( function () {
                addScrollLinks();
            } );
        }
    } else {
        checkAndScroll();
    }

}() );