Jump to content

User:GregU/randomlink.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by GregU (talk | contribs) at 19:16, 7 September 2009 (fix last). 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.
//  Travel to a random page linked in the article or listed on a special page.
//  Rewritten from [[User:Proteins/followrandomlinkonpage.js]] and improved so
//  it does the right thing on all special pages, using only the main item links.
//
//  For example, on recent changes or user contributions (among many others),
//  it will choose a title from the list, excluding user links and other links.
//  But on history pages, it will follow ONLY user page links, as they are the
//  main thing there.  In categories, it will choose only items... if there are
//  any pages or files in the category. Else, it will use content links and
//  subcategories (and parent categories, currently).
//
//  To enable this tool, add "importScript('User:GregU/randomlink.js')" to your
//  monobook.js subpage under your user page.  This adds the "Random link"
//  option to the navigation menu.
//
//  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

function scrapeLinks()
{
    var topnode = document.getElementById('bodyContent') || document;
    var atags   = [];
    var links   = [];
    var nspat   = /^(Talk|User|Wikipedia|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

    for (var id in {'mw-pages':0, 'mw-category-media':0 }) {
        var node = document.getElementById( id );
        if (node) {
            var nodelist = node.getElementsByTagName('a');
            atags = atags.concat( Array.prototype.slice.call( nodelist ));
        }
    }
    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.host != location.host)            // 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 = 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();
    }

    if (typeof randomlink_debug != "undefined") {       // DEBUG
        var msg = links.length + " links:";
        for (i=0; i < links.length; i++) {
            msg += "\n   " + links[i];
        }
        alert( msg );
        return;
    }

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

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

    if (typeof randomlink_paged == "undefined")
        randomlink_paged = false;

    if (randomlink_paged && newpage.search( /\/Category[:%]/ ) >= 0) {
        var alphabet = "!abcdefghijklmnoprstuvwy~";
        var key = alphabet.charAt(alphabet.length * Math.random()).toUpperCase()
                + alphabet.charAt(alphabet.length * Math.random());
        newpage += "?" + (key < "M" ? "from" : "until") + "=" + key;
    }

    if (randomlink_paged && newpage.indexOf("Special:WhatLinksHere") >= 0) {
        // Clustering will hurt randomness, but better than nothing
        var from = Math.floor( randomlink_maxfrom * Math.random() );
        newpage += (newpage.indexOf("?") >= 0) ? "&" : "?";
        newpage += "from=" + from;
    }

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

    //  WikiProjects organize by talk pages, but go to the article page.
    //
    if ((wgCanonicalNamespace == "Category" || wgCanonicalSpecialPageName == "Whatlinkshere")
             && continuing && hops <= 0)
        newpage = newpage.replace("/Talk:", "/");

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

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

    addPortletLink('p-navigation', 'javascript:randomLink()', 'Random link',
                   'n-randomlink', 'Follow a randomly chosen link on this page', '@');
});