Jump to content

User:Lowellian/randomlink.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.
//  2009-09-28 23:59 revision of [[User:GregU/randomlink.js]]
//  
//  Documentation at [[Wikipedia:Random]]
//  and [[User talk:GregU/randomlink.js]]
//  
//  Travel to a random page linked in the article or listed on a special page.
//  See talk page for documentation.  Greg Ubben

//randomlink_start   = [ "Wikipedia:Featured articles", "Wikipedia:Featured pictures" ];
//randomlink_hops    = 2;
//randomlink_exclude = /^List of/;
//randomlink_paged   = true;        // cats > 200 entries or multi-paged lists
randomlink_open    = true;        // if you want to open in new windows
//randomlink_debug   = true;        // set this, to debug
randomlink_maxfrom   = 20000000;    // 10-20% less than max page id
randomlink_maxoffset = 950;         // en.wikipedia is limited to 1000

function scrapeLinks( descend )
{
    var topnode = document.getElementById('bodyContent') || document;
    var node    = document.getElementById('mw-subcategories');
    var atags   = [];
    var links   = [];
    var nspat   = /^(Talk|User|Wik\w+|File|MediaWiki|Template|Help|Category|Portal)( talk)?:/i;

    var spec = getElementsByClassName(topnode, 'div', 'mw-spcontent');
    if (spec.length == 1)  topnode = spec[0];      // skip help links at top of specials

    if (node && descend)
        topnode = node;           // pick a sub-category
    else
        for (var id in {'mw-pages':0, 'mw-category-media':0 }) {
            node = document.getElementById( id );
            if (node) {
                var nodelist = node.getElementsByTagName('a');
                for (var i=0; i < nodelist.length; i++)
                    atags.push( nodelist[i] );
            }
        }

    if (atags.length == 0)
        atags = topnode.getElementsByTagName('a');

  nextlink:
    for (var i=0; i < atags.length; i++) {
        var link  = atags[i];
        var href  = link.href;
        var title = link.title;

        if (!href)                                 // needed?
            continue;
        if (link.className.search(/^(mw-redirect|mw-userlink|Cat.*)?$/) == -1)
            continue;                              // external or image
        if (href.search(/\/Special:|\?(?!.*redirect=|.*from=.*to=)/) >= 0)
            continue;
        if (wgIsArticle && wgNamespaceNumber != 14 && title.search(/^(Category|File):|^$/) >= 0)
            continue;
        if (wgIsArticle && wgNamespaceNumber == 0 && title.search(nspat) >= 0)
            continue;
        if ((wgAction == "history") != (link.className == "mw-userlink"))
            continue;
        if (link.hostname != location.hostname)    // commons.wikimedia.org on images
            continue;
        if (link.parentNode.id == "coordinates")
            continue;                              // coords too common, or help link
        if (typeof randomlink_exclude != "undefined" && title.search(randomlink_exclude) >= 0)
            continue;

        //  Exclude message boxes and the Metadata section on Image pages.
        //  And also mw-usertool links and comments in page listings.
        //  And also top links on Recent changes and watchlists.
        //
        for (var n = link.parentNode; n != topnode; n = n.parentNode) {
            if (n.id.search(/^mw-watchlist-options|^recentchangestext/) >= 0)
                continue nextlink;
            if (n.className.search(/\b(usertool|summary|metadata|.mbox|comment)/) >= 0)
                continue nextlink;
        }
        links.push( link );
    }

    while (links.length && links[0].parentNode.id.search( /contentSub|jump-to|target/i ) >= 0)
        links.shift();                                  // breadcrumb links

    if (links.length && links[0].title == "Wikipedia:FAQ/Categories")
        links.shift();                                  // "learn more" link in cats

    return links;
}

function randomLink( links, hops )
{
    var continuing = (typeof links == "object" && links == null);

    if (typeof links == "undefined" && typeof randomlink_start != "undefined")
        links = randomlink_start;

    if (typeof hops == "undefined" && typeof randomlink_hops != "undefined")
        hops = randomlink_hops;

    if (typeof hops == "undefined")
        hops = 1;

    if (hops > 4)       // sanity check; 4 needed for Special:AllPages
        hops = 4;

    if (typeof links == "string" &&
        links.search(/^Special:(WhatLinksHere|RecentChangesLinked)$/i) >= 0)
    {
        links += "/" + wgPageName + "?limit=250";
        if (wgNamespaceNumber == 0)
            links += "&namespace=0";    // stay in article space if in it now
    }

    //  Random contrib: Toggles between user, page, user, page, ...
    //
    if (typeof links == "string" && links == "Special:Contributions")
        if (wgPageName.search(/^User:[^\/]+$/) >= 0)
            links += "/" + wgPageName.slice(5) + "?namespace=0";
        else
            links = wgPageName + "?action=history";

    if (typeof links == "string")
        links = links.split("|");

    if (typeof links == "object" && links != null) {
        for (var i=0; i < links.length; i++)
            links[i] = wgArticlePath.replace("$1", links[i]).replace(/ /g, "_");
        hops++;
    }
    else {
        links = scrapeLinks( hops > 1 );
    }

    if (typeof randomlink_debug != "undefined" && randomlink_debug) {
        var msg = links.slice(0);
        if (msg.length > 36)
            msg.splice( 20, msg.length-35, "..." );
        alert( links.length + " links:\n   " + msg.join("\n   "));
    }

    if (links.length == 0)
        return alert("I am unable to comply.");

    var newpage = links[ Math.floor(links.length * Math.random()) ].toString();

    if (typeof randomlink_paged != "undefined" && randomlink_paged)
        newpage = pagedUrl( newpage );

    if (wgCanonicalNamespace == "Category" && newpage.indexOf("/Category:") == -1)
        hops = 1;

    if (--hops > 0) {
        newpage += (newpage.indexOf("?") >= 0) ? "&" : "?";
        newpage += "random_hops=" + hops;
    }

    //  WikiProjects organize by talk pages, but let's end on the subject page.
    //
    if ((wgCanonicalNamespace == "Category" || wgCanonicalSpecialPageName == "Whatlinkshere")
             && continuing && hops <= 0)
        newpage = newpage.replace("/Talk:", "/").replace("_talk:", ":");

    if (typeof randomlink_open != "undefined" && randomlink_open && !continuing)
        window.open( newpage );
    else
        window.location = newpage;
}

function pagedUrl( url )
{
    var param = "";
    var value;
    var alphabet = "!abcdefghijklmnoprstuvwy~";

    if (url.indexOf("/Category:") >= 0) {
        value = alphabet.charAt(alphabet.length * Math.random()).toUpperCase()
              + alphabet.charAt(alphabet.length * Math.random());
        param = (value < "M" ? "from" : "until");
    }
    if (url.indexOf("Special:WhatLinksHere") >= 0) {
        param = "from";
        value = Math.floor( randomlink_maxfrom * Math.random() );
        // Clustering will hurt randomness, but better than nothing
    }
    if (url.search(/Special:\w+s\b/) >= 0) {
        param = "offset";
        value = Math.floor( randomlink_maxoffset * Math.random() );
    }
    if (param) {
        url += (url.indexOf("?") >= 0) ? "&" : "?";
        url += param + "=" + encodeURIComponent(value);
    }
    return url;
}

$( function()
{
    var hops = document.URL.match( /[?&]random_hops=(\d+)/ );
    if (hops)  randomLink( null, hops[1] );

    var where = 'this page';
    if (typeof randomlink_start != 'undefined')
        where = randomlink_start.toString().slice(0,500);

    mw.util.addPortletLink('p-navigation', 'javascript:randomLink()', 'Random link',
                   'n-randomlink', 'Follow a randomly chosen link on ' + where, '@');
});