Jump to content

User:Enterprisey/parsoid-jump.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.
( function () {
    var queryString = window.location.search,
        targetIdMatch = /[?&]parsoid_jump=(.+?)($|&)/.exec( queryString ),
        targetId = null;
    if( targetIdMatch ) {
        targetId = targetIdMatch[1];
    } else if( document.cookie.indexOf( "parsoid_jump=" ) >= 0 ) {
        targetId = /parsoid_jump=([^;]+)/.exec( document.cookie )[1];
        document.cookie = "parsoid_jump=; expires=Thu, 01 Jan 1970 00:00:01 GMT";
    } else {
        return;
    }

    var liveTarget = document.getElementById( targetId );
    if( liveTarget ) {
        liveTarget.scrollIntoView();
        return;
    }

    mw.notify( "Jumping to the new content..." );

    var CONTENT_SLICE_LEN = 20,
        parsoidEndpoint = "https:" + mw.config.get( "wgServer" ) +
        "/api/rest_v1/page/html/",
        parsoidUrl = parsoidEndpoint + encodeURIComponent( mw.config.get( "wgPageName" ) ) +
        "/" + mw.config.get( "wgCurRevisionId" );
    $.get( parsoidUrl ).then( function ( domString ) {
        var domParser = new DOMParser(),
            dom = domParser.parseFromString( domString, "text/html" ),
            target = dom.getElementById( targetId );
        if( !target ) {
            console.error( "[parsoid-jump] Couldn't locate element with ID " +
                targetId + " in " + parsoidUrl );
            return;
        }

        var tag = target.tagName.toLowerCase(),
            classesSelector = target.className ? "." +
            Array.prototype.join.call( target.classList, "." ) : "",
            fullSelector = tag + classesSelector,
            partialContent = target.textContent.slice(0, CONTENT_SLICE_LEN),
            hasSimilarContent = function ( el ) {
                return el.textContent.slice( 0, CONTENT_SLICE_LEN ) === partialContent;
            },

            // Neat trick from https://medium.com/@chuckdries/traversing-the-dom-with-filter-map-and-arrow-functions-1417d326d2bc
        similarEls = Array.prototype.filter.call( dom.querySelectorAll( fullSelector ),
            hasSimilarContent ),
            targetIdx = similarEls.indexOf( target );

        // Now, try to find the element in the live DOM
        var liveSimilarEls = Array.prototype.filter.call( document.querySelectorAll( fullSelector ),
            hasSimilarContent );
        if( !liveSimilarEls ) {
            console.error( "[parsoid-jump] Couldn't locate any live elements with tag " +
                tag + " and partial content " + partialContent );
            return;
        }

        var liveEl = liveSimilarEls[targetIdx];
        if( !liveEl ) {
            console.error( "[parsoid-jump] Tried to get the live similar element at index " +
                targetIdx + ", but there were only " + liveSimilarEls.length + " of them" );
            return;
        }

        liveEl.scrollIntoView();
        if( !window.parsoidJumpNoHighlight ) {
            mw.loader.addStyleTag( "@keyframes highlight { from { background-color: #ffb; } to { background-color: transparent; } } .psj-highlight { animation: highlight 2s; }" );
            liveEl.className += " psj-highlight";
        }
    } );
} )();