MediaWiki:Common.js

From Pikipedia, the Pikmin wiki
Revision as of 11:24, November 6, 2016 by Porplemontage (talk | contribs) (Test)
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/* Any JavaScript here will be loaded for all users on every page load. */

//<nowiki>

//TODO instead of a "misc" category for concept art, have a checkbox for "shows prerelease content"?
//TODO allow the user to add multiple subjects?
//TODO subjects should be in a select box?

var description_textarea;
var type_select;
var game_select;
var mode_select;
var location_select;
var subject_select;
var specific_subject_text;
var misc_select;
var source_select;
var specific_source_text;
var license_select;
var final_textarea;

var description_tr;
var type_tr;
var game_tr;
var mode_tr;
var location_tr;
var subject_tr;
var specific_subject_span;
var misc_tr;
var source_tr;
var specific_source_span;
var license_tr;
var final_tr;

var final_toggler_a;

var has_game = false;
var has_mode = false;
var has_location = false;
var has_subject = false;
var has_misc = false;
var has_license = false;


function main() {
  
  if(typeof(mw) === "undefined" || mw.config.get("wgCanonicalNamespace") != "Special" || mw.config.get("wgTitle") != "Upload") return;
  if(window.location.href.indexOf("wpForReUpload=1") != -1) return;

  //Get the table with the upload fields.
  var table = document.getElementById("mw-htmlform-description").firstChild;
  
  if(document.getElementById("wpUploadDescription") && document.getElementById("wpUploadDescription").value.length > 0) {
    //Hold on, there's already text here! Chances are this is the warning page.
    //Let's just hide the license box and quit.
    hide_license(table);
    return;
  }

  create_description_textarea(table);
  create_type_list(table);
  create_game_list(table);
  create_mode_list(table);
  create_location_list(table);
  create_subject_list(table);
  create_misc_list(table);
  create_source_list(table);
  create_license_list(table);
  
  hide_license(table);
  setup_final(table);
  replace_uploadtext();
  create_script_notification();
  
  handle_type_choice();
  
}


function create_description_textarea(table) {
  description_textarea = document.createElement("textarea");
  description_textarea.onchange = create_final_result;
  description_tr = add_field("Description:", description_textarea, table);
}


function create_type_list(table) {
  type_select = document.createElement("select");
  type_select.name = "type";
  type_select.onchange = handle_type_choice;
  
  add_option("screenshot", "Screenshot", type_select);
  add_option("boxart", "Box art", type_select);
  add_option("concept", "Concept art", type_select);
  add_option("texture", "Texture", type_select);
  add_option("audio", "Audio", type_select);
  add_option("logo", "Logo", type_select);
  add_option("map", "Map", type_select);
  add_option("icon", "Icon", type_select);
  add_option("real", "Real world image", type_select);
  add_option("user", "Non-wiki user image", type_select);
  add_option("wiki", "Pikipedia special image", type_select);
  
  type_tr = add_field("Type of file:", type_select, table);
}


function create_game_list(table) {
  game_select = document.createElement("select");
  game_select.name = "game";
  game_select.onchange = handle_game_choice;
  
  var gc_optgroup =    add_optgroup("GameCube",           game_select);
  var wii_optgroup =   add_optgroup("Wii",                game_select);
  var wiiu_optgroup =  add_optgroup("Wii U",              game_select);
  var n3ds_optgroup =  add_optgroup("Nintendo 3DS",       game_select);
  var smash_optgroup = add_optgroup("Super Smash Bros. games", game_select);
  var misc_optgroup =  add_optgroup("Other",              game_select);
  
  add_option("p1",    "<i>Pikmin</i>",                     gc_optgroup);
  add_option("p2",    "<i>Pikmin 2</i>",                   gc_optgroup);
  add_option("npcp1", "<i>New Play Control! Pikmin</i>",   wii_optgroup);
  add_option("npcp2", "<i>New Play Control! Pikmin 2</i>", wii_optgroup);
  add_option("p3",    "<i>Pikmin 3</i>",                   wiiu_optgroup);
  add_option("pa",    "<i>Pikmin Adventure</i>",           wiiu_optgroup);
  add_option("p3ds",  "<i>Pikmin for Nintendo 3DS</i>",    n3ds_optgroup);
  add_option("ssbb",  "<i>Super Smash Bros. Brawl</i>",    smash_optgroup);
  add_option("ssb4",  "<i>Super Smash Bros. for 3DS and Wii U</i>", smash_optgroup);
  add_option("psm",   "<i>Pikmin</i> Short Movies",        misc_optgroup)
  add_option("other", "Other game",                        misc_optgroup);
  add_option("none",  "N/A",                               misc_optgroup, true);
  
  game_tr = add_field("Game:", game_select, table);
}


function create_mode_list(table) {
  mode_select = document.createElement("select");
  mode_select.name = "mode";
  mode_select.onchange = handle_mode_choice;
  
  mode_tr = add_field("Game mode:", mode_select, table);
}


function create_location_list(table) {
  location_select = document.createElement("select");
  location_select.name = "location";
  location_select.onchange = handle_location_choice;
  
  location_tr = add_field("In-game location:", location_select, table);
}


function create_subject_list(table) {
  var subject_span = document.createElement("span");
  
  subject_select = document.createElement("select");
  subject_select.name = "subject";
  subject_select.onchange = handle_subject_choice;
  
  add_option("none", "N/A", subject_select);
  
  var spec_optgroup = add_optgroup("A specific creature", subject_select);
  var collectible_optgroup = add_optgroup("A collectible", subject_select);
  var object_optgroup = add_optgroup("An in-game object", subject_select);
  
  add_option("character",  "Character",           spec_optgroup);
  add_option("pikmin",     "Pikmin",              spec_optgroup);
  add_option("enemy",      "Enemy",               spec_optgroup);
  add_option("ship_part",  "Ship part",           collectible_optgroup);
  add_option("treasure",   "Treasure",            collectible_optgroup);
  add_option("fruit",      "Fruit",               collectible_optgroup);
  add_option("onion",      "Onion",               object_optgroup);
  add_option("plant",      "Plant",               object_optgroup);
  add_option("obstacle",   "Obstacle",            object_optgroup);
  
  specific_subject_span = document.createElement("span");
  
  var specific_subject_label = document.createTextNode(" Specifically what? ");
  specific_subject_span.appendChild(specific_subject_label);
  
  specific_subject_text = document.createElement("input");
  specific_subject_text.style.width = "100px";
  specific_subject_text.onchange = create_final_result;
  specific_subject_span.appendChild(specific_subject_text);
  
  subject_span.appendChild(subject_select);
  subject_span.appendChild(specific_subject_span);
  
  subject_tr = add_field("Main subject:", subject_span, table);
}


function create_misc_list(table) {
  misc_select = document.createElement("select");
  misc_select.name = "misc";
  misc_select.onchange = update_fields;
  
  add_option("none",        "N/A",                                      misc_select);
  add_option("glitch",      "This image shows a glitch",                misc_select);
  add_option("prerelease",  "This image shows prerelease content",      misc_select);
  add_option("menu",        "This image shows an in-game menu",         misc_select);
  add_option("promotional", "This image is about promotional material", misc_select);
  
  misc_tr = add_field("Misc. categories:", misc_select, table);
}


function create_source_list(table) {
  var source_span = document.createElement("span");
  
  source_select = document.createElement("select");
  source_select.name = "source";
  source_select.onchange = handle_source_choice;
  source_span.appendChild(source_select);
  
  add_option("none", "N/A", source_select);
  add_option("self", "I made this myself", source_select);
  add_option("web",  "Off a website", source_select);
  
  specific_source_span = document.createElement("span");
  source_span.appendChild(specific_source_span);
  
  specific_source_text = document.createElement("input");
  specific_source_text.onchange = create_final_result;
  specific_source_span.appendChild(document.createTextNode(" Please link to the page: "));
  specific_source_span.appendChild(specific_source_text);
  
  source_tr = add_field("Source:", source_span, table);
}


function create_license_list(table) {
  license_select = document.createElement("select");
  license_select.name = "license";
  license_select.onchange = create_final_result;
  
  add_option("unknown", "I don't know...",    license_select);
  add_option("fairuse", "Fair use",           license_select)
  add_option("cc-a2.5", "CC-Attribution 2.5", license_select);
  add_option("pd",      "Public domain",      license_select);
  
  license_tr = add_field("License:", license_select, table);
}


function handle_type_choice() {
  handle_game_choice();
  handle_subject_choice();
  handle_source_choice();
  update_fields();
}


function handle_game_choice() {
  clear_el(mode_select);
  
  var modes = [];
  var cur_game = get_option(game_select);
  
  if(cur_game == "p1" || cur_game == "npcp1") {
    modes = [
      "Story mode",
      "Challenge Mode"
    ];
  } else if(cur_game == "p2" || cur_game == "npcp2") {
    modes = [
      "Story mode",
      "Challenge Mode",
      "2-Player Battle"
    ];
  } else if(cur_game == "p3") {
    modes = [
      "Story mode",
      "Mission Mode",
      "Bingo Battle"
    ];
  }
  
  add_option("N/A", "N/A", mode_select);
  for(m = 0; m < modes.length; m++) {
    add_option(modes[m], modes[m], mode_select);
  }
  
  has_mode = (modes.length > 0);
  handle_mode_choice();
}


function handle_mode_choice() {
  clear_el(location_select);
  
  var locations = [];
  var cur_game = get_option(game_select);
  var cur_mode = get_option(mode_select);
  
  if(cur_game == "p1" || cur_game == "npcp1") {
    locations = [
      "The Impact Site",
      "The Forest of Hope",
      "The Forest Navel",
      "The Distant Spring",
      "The Final Trial"
    ];
  } else if(cur_game == "p2" || cur_game == "npcp2") {
    locations = [
      "Valley of Repose",
      "Awakening Wood",
      "Perplexing Pool",
      "Wistful Wild",
      "Story mode cave"
    ];
  } else if(cur_game == "p3") {
    locations = [
      "Tropical Wilds",
      "Garden of Hope",
      "Distant Tundra",
      "Twilight River",
      "Formidable Oak"
    ];
  }
  
  locations.splice(0, 0, "N/A");
  
  for(l = 0; l < locations.length; l++) {
    add_option(locations[l], locations[l], location_select);
  }
  
  has_location = (locations.length > 0);
  update_fields();
}


function handle_location_choice() {
  update_fields();
}


function handle_subject_choice() {
  var cur_subject = get_option(subject_select);
  
  if(cur_subject == "character" || cur_subject == "pikmin" || cur_subject == "enemy") {
    specific_subject_span.style.display = "inline";
  } else {
    specific_subject_span.style.display = "none";
  }
  
  update_fields();
}


function handle_source_choice() {
  var cur_source = get_option(source_select);
  
  if(cur_source == "web") {
    specific_source_span.style.display = "inline";
  } else {
    specific_source_span.style.display = "none";
  }
  
  update_fields();
}


function update_fields() {
  
  var cur_type = get_option(type_select);
  var cur_game = get_option(game_select);
  var cur_mode = get_option(mode_select);
  var cur_source = get_option(source_select);
  
  has_game = false;
  has_mode = false;
  has_location = false;
  has_subject = false;
  has_misc = false;
  has_source = false;
  has_license = false;
  
  if(
    cur_type == "screenshot" || cur_type == "boxart" ||
    cur_type == "concept" || cur_type == "texture" ||
    cur_type == "audio" || cur_type == "logo" || cur_type == "map"
  ) {
    has_game = true;
  }
  
  if(cur_type == "screenshot") {
    if(get_game_has_location(cur_game)) {
      has_mode = true;
      has_location = true;
      has_subject = true;
      has_misc = true;
    }
    if((cur_game == "p2" || cur_game == "npcp2") && cur_mode != "Story mode") {
      has_location = false;
    }
    if(cur_game == "p3" && cur_mode != "Story mode") {
      has_location = false;
    }
    if(cur_mode == "N/A") {
      has_location = false;
    }
    
  } else if (cur_type == "concept") {
    has_location = get_game_has_location(cur_game);
    has_subject = true;
    has_misc = true;
    
  } else if (cur_type == "map") {
    has_location = get_game_has_location(cur_game);
    has_source = true;
    has_license = true;
    
  } else if (cur_type == "icon") {
    has_source = true;
    has_license = true;
    
  } else if (cur_type == "real" || cur_type == "user" || cur_type == "wiki") {
    has_source = true;
    has_license = true;
    
  }
  
  game_tr.style.display =
    has_game ? "table-row" : "none";
  mode_tr.style.display =
    has_game && has_mode ? "table-row" : "none";
  location_tr.style.display =
    has_game && has_location ? "table-row" : "none";
  subject_tr.style.display =
    has_subject ? "table-row" : "none";
  misc_tr.style.display =
    has_misc ? "table-row" : "none";
  source_tr.style.display =
    has_source ? "table-row" : "none";
  license_tr.style.display =
    has_license ? "table-row" : "none";
  
  create_final_result();
}


function get_game_has_location(g) {
  var r =
    g == "p1" || g == "npcp1" ||
    g == "p2" || g == "npcp2" ||
    g == "p3";
  return r;
}


function create_final_result() {
  var t = "";
  var cur_type = get_option(type_select);
  var cur_game = get_option(game_select);
  var cur_mode = get_option(mode_select);
  var cur_location = get_option(location_select);
  var cur_subject = get_option(subject_select);
  var cur_misc = get_option(misc_select);
  var cur_source = get_option(source_select);
  var cur_license = get_option(license_select);
  
  t += "{{file info\n";
  t += "|summary = " + description_textarea.value + "\n";
  t += "|type = " + cur_type + "\n";
  
  if(has_game && cur_game != "none") {
    t += "|game = " + cur_game + "\n";
  }
  
  if(has_location && cur_location != "N/A") {
    t += "|location = " + cur_location + "\n";
  }
  
  if(has_source && cur_source != "N/A") {
    t += "|source = " + (cur_source == "self" ? "self" : specific_source_text.value) + "\n";
  }
  
  if(has_license) {
    t += "|license = " + cur_license + "\n";
  }
  
  t += "}}\n\n"
  
  if(has_mode) {
    if(cur_mode != "N/A" && cur_mode != "Story mode") {
      t += "[[Category:" + cur_mode + " images]]\n";
    }
  }
  
  if(has_subject && cur_subject != "N/A") {
    if(cur_subject == "pikmin" || cur_subject == "character" || cur_subject == "enemy") {
      t += "[[Category:" + specific_subject_text.value + " images]]\n";
    } else if(cur_subject == "ship_part") {
      t += "[[Category:Ship part images]]\n";
    } else if(cur_subject == "treasure") {
      t += "[[Category:Treasure images]]\n";
    } else if(cur_subject == "fruit") {
      t += "[[Category:Fruit images]]\n";
    } else if(cur_subject == "onion") {
      t += "[[Category:Onion images]]\n";
    } else if(cur_subject == "plant") {
      t += "[[Category:Vegetation images]]\n";
    } else if(cur_subject == "obstacle") {
      t += "[[Category:Obstacle images]]\n";
    }
  }
  
  if(has_misc) {
    if(cur_misc == "glitch") {
      t += "[[Category:Glitch images]]\n";
    } else if(cur_misc == "prerelease") {
      t += "[[Category:Prerelease images]]\n";
    } else if(cur_misc == "menu") {
      t += "[[Category:Menu images]]\n";
    } else if(cur_misc == "promotional") {
      t += "[[Category:Promotional material]]\n";
    }
  }
  
  //NOTE: This code is only valid until Pikmin for Nintendo 3DS releases
  if(has_game && cur_game == "p3ds") {
    t += "[[Category:Pikmin for Nintendo 3DS prerelease images]]\n";
  }
  
  
  if(t.substr(t.length - 2) == "\n\n") {
      t = t.slice(0, t.length - 1);
  }
  
  final_textarea.value = t;
}


function hide_license(table) {
  document.getElementById("wpLicense").parentNode.parentNode.style.display = "none";
}


function setup_final(table) {
  var final_toggler_div = document.createElement("div");
  final_toggler_div.style.marginTop = "64px";
  
  final_toggler_a = document.createElement("a");
  final_toggler_a.href = "#";
  final_toggler_a.innerHTML = "Show"
  final_toggler_a.onclick = function(e) { e.preventDefault(); toggle_final(); };
  final_toggler_div.appendChild(document.createTextNode("["));
  final_toggler_div.appendChild(final_toggler_a);
  final_toggler_div.appendChild(document.createTextNode("] final result box (if you need fine tuning)"));
  
  add_field("", final_toggler_div, table);
  final_tr = document.getElementById("wpUploadDescription").parentNode.parentNode;
  final_textarea = final_tr.getElementsByTagName("textarea")[0];
  final_tr.style.display = "none";
}


function replace_uploadtext() {
  var uploadtext = document.getElementById("uploadtext");
  clear_el(uploadtext);
  
  uploadtext.innerHTML =
    "<p>Use this form to upload new files. Please follow every step in the form. " +
    "Also, use a descriptive name, like <code>Pikmin 3 Burgeoning Spiderwort closeup.jpg</code> " +
    "instead of <code>xGFW34.JPG</code>, and make sure " +
    "your file does not <a href=\"/Special:ListFiles\">already exist</a>.</p>" +
    "<p>Helpful links:</p>" +
    "<ul><li><a href=\"/Help:Files\">Help about files</a></li>" +
    "<li><a href=\"/Special:Log/upload\">Upload log</a></li>" +
    "<li><a href=\"/Special:Log/delete\">Delete log</a></li></ul>";
}


function create_script_notification() {
  var notification_div = document.createElement("div");
  notification_div.style.float = "right";
  notification_div.style.margin = "10px";
  notification_div.style.border = "1px solid";
  notification_div.style.padding = "2px";
  notification_div.style.fontSize = "75%";
  notification_div.style.fontStyle = "italic";
  notification_div.innerHTML = "This page is running the <a href=\"/User:Espyo/PikipediaUpload\">PikipediaUpload</a> script.";
  
  var upload_text = document.getElementById("uploadtext");
  upload_text.parentNode.insertBefore(notification_div, upload_text);
}


function toggle_final() {
  if(final_tr.style.display == "none") {
    final_tr.style.display = "table-row";
    final_toggler_a.innerHTML = "Hide";
  } else {
    final_tr.style.display = "none";
    final_toggler_a.innerHTML = "Show";
  }
}


function clear_el(el) {
  while(el.firstChild){
    el.removeChild(el.firstChild);
  }
}


function get_option(sel) {
  if (sel.options.length == 0) return null;
  return sel.options[sel.selectedIndex].value;
}


function add_option(value, innerHTML, parent, selected) {
  var opt = document.createElement("option");
  opt.value = value;
  opt.innerHTML = innerHTML;
  parent.appendChild(opt);
  if(typeof(selected) != "undefined") {
    opt.setAttribute("selected", "");
  }
  return opt;
}


function add_optgroup(label, parent) {
  var optgroup = document.createElement("optgroup");
  optgroup.label = label;
  parent.appendChild(optgroup);
  return optgroup;
}


function add_field(label, content, table) {
  var tr = document.createElement("tr");
  var td1 = document.createElement("td");
  td1.className = "mw-label";
  td1.innerHTML = label;
  tr.appendChild(td1);
  var td2 = document.createElement("td");
  td2.className = "mw-input";
  td2.appendChild(content);
  tr.appendChild(td2);
  
  var ref = table.children[table.children.length - 3];
  table.insertBefore(tr, ref);
  return tr;
}


main();

//</nowiki>


 /* Test if an element has a certain class **************************************
  *
  * Description: Uses regular expressions and caching for better performance.
  * Maintainers: [[Wikipedia:User:Mike Dillon]], [[Wikipedia:User:R. Koot]], [[Wikipedia:User:SG]]
  */
 
 var hasClass = (function () {
     var reCache = {};
     return function (element, className) {
         return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className);
     };
 })();

 /** Collapsible tables *********************************************************
  *
  *  Description: Allows tables to be collapsed, showing only the header. See
  *               [[Wikipedia:NavFrame]].
  *  Maintainers: [[User:R. Koot]]
  */
 
 var autoCollapse = 2;
 var collapseCaption = "hide";
 var expandCaption = "show";
 
 function collapseTable( tableIndex )
 {
     var Button = document.getElementById( "collapseButton" + tableIndex );
     var Table = document.getElementById( "collapsibleTable" + tableIndex );
 
     if ( !Table || !Button ) {
         return false;
     }
 
     var Rows = Table.rows;
 
     if ( Button.firstChild.data == collapseCaption ) {
         for ( var i = 1; i < Rows.length; i++ ) {
             Rows[i].style.display = "none";
         }
         Button.firstChild.data = expandCaption;
     } else {
         for ( var i = 1; i < Rows.length; i++ ) {
             Rows[i].style.display = Rows[0].style.display;
         }
         Button.firstChild.data = collapseCaption;
     }
 }
 
 function createCollapseButtons()
 {
     var tableIndex = 0;
     var NavigationBoxes = new Object();
     var Tables = document.getElementsByTagName( "table" );
 
     for ( var i = 0; i < Tables.length; i++ ) {
         if ( hasClass( Tables[i], "collapsible" ) ) {
 
             var Header = null;
             /* the editor can override which table header element gets the button with a class */
             var OverrideHeader = Tables[i].getElementsByClassName("collapsiblebutton");
             if(OverrideHeader) OverrideHeader = OverrideHeader[0];
             if(OverrideHeader) Header = OverrideHeader;
 
             /* only add button and increment count if there is a header row to work with */
             if (!Header){
                 var HeaderRow = Tables[i].getElementsByTagName( "tr" )[0];
                 if (!HeaderRow) continue;
                 Header = HeaderRow.getElementsByTagName( "th" )[0];
                 if (!Header) continue;
             }

             NavigationBoxes[ tableIndex ] = Tables[i];
             Tables[i].setAttribute( "id", "collapsibleTable" + tableIndex );
 
             var Button     = document.createElement( "span" );
             var ButtonLink = document.createElement( "a" );
             var ButtonText = document.createTextNode( collapseCaption );
 
             Button.style.styleFloat = "right";
             Button.style.cssFloat = "right";
             Button.style.fontWeight = "normal";
             Button.style.textAlign = "right";
             Button.style.width = "6em";
             Button.style.marginLeft = "-100%";
             Button.setAttribute( "class", "collapsible-button" );
 
             ButtonLink.style.color = Header.style.color;
             ButtonLink.setAttribute( "id", "collapseButton" + tableIndex );
             ButtonLink.setAttribute( "href", "javascript:collapseTable(" + tableIndex + ");" );
             ButtonLink.appendChild( ButtonText );
 
             Button.appendChild( document.createTextNode( "[" ) );
             Button.appendChild( ButtonLink );
             Button.appendChild( document.createTextNode( "]" ) );
 
             Header.insertBefore( Button, Header.childNodes[0] );
             tableIndex++;
         }
     }
 
     for ( var i = 0;  i < tableIndex; i++ ) {
         if ( hasClass( NavigationBoxes[i], "collapsed" ) || ( tableIndex >= autoCollapse && hasClass( NavigationBoxes[i], "autocollapse" ) ) ) {
             collapseTable( i );
         }
     }
 }
 
 $( createCollapseButtons );

/* Content tabber, version 1.0.5 by Greenpickle (GPL3) */

var switchableAnchorPrefix = '';
var switchableClass = 'switchable';
var switchableSectionClass = 'switch';
var switchableTabsClass = 'switchabletabs';
var switchableSectionTitleAttr = 'title';

function initialiseSwitchable () {
    // get the elements we care about
    switchable = myGetElementsByClassName(document, switchableClass);

    // some functions
    switchable.createTab = function (label, isAnchor, i, j) {
        var tab = document.createElement('li');
        var child;
        if (isAnchor) {
            child = document.createElement('a');
            child.href =
                'javascript:switchable.setVisible(' + i + ', ' + j + ');';
        } else child = document.createElement('strong');
        child.appendChild(document.createTextNode(label));
        tab.appendChild(child);
        return tab;
    }

    switchable.getVisible = function (i) {
        var visible = this[i].getAttribute('visiblesection');
        if (visible) visible = parseInt(visible);
        if (visible === null || isNaN(visible)) {
            visible = 0;
            this[i].setAttribute('visiblesection', visible.toString());
        }
        return Math.max(0, Math.min(visible, this[i].sections.length - 1));
    }

    switchable.updateVisible = function (i) {
        if (isNaN(parseInt(i))) {
            // update all switchables if no valid number given
            for (var i = 0; i < this.length; i++)
                this.updateVisible(i);
        } else {
            var visible = this.getVisible(i);
            var sections = this[i].sections;
            var tc = this[i].tabContainer;
            var currentTab;
            for (var j = 0; j < sections.length; j++) {
                if (j == visible) {
                    // change 'show' link
                    currentTab = this.createTab(sections[j].sectionName,
                                                    false);
                    currentTab.j = j;
                    tc.replaceChild(currentTab, tc.tabs[j]);
                    // show section
                    sections[j].style.display = '';
                } else {
                    // change 'show' link
                    if (tc.currentTab !== undefined && tc.currentTab.j == j)
                        tc.replaceChild(tc.tabs[j], tc.currentTab);
                    // hide section
                    sections[j].style.display = 'none';
                }
            }
            if (currentTab !== undefined) tc.currentTab = currentTab;
        }
    }

    switchable.setVisible = function (i, j) {
        this[i].setAttribute('visiblesection', j);
        this.updateVisible(i);
    }

    // initialise
    for (var i = 0; i < switchable.length; i++) {
        var sections = myGetElementsByClassName(switchable[i],
                                                switchableSectionClass);
        switchable[i].sections = sections;
        // create show/hide anchors
        var tabContainer = document.createElement('ul');
        tabContainer.className = switchableTabsClass;
        switchable[i].appendChild(tabContainer);
        switchable[i].tabContainer = tabContainer;
        tabContainer.tabs = [];
        for (var j = 0; j < sections.length; j++) {
            // re-append section to place it after links
            switchable[i].appendChild(sections[j]);
            // use section's name if it has one
            var sectionName = sections[j].getAttribute(
                                                switchableSectionTitleAttr);
            if (!sectionName) sectionName = j.toString();
            sections[j].sectionName = sectionName;
            // create anchor
            var tab = switchable.createTab(
                            switchableAnchorPrefix + sectionName, true, i, j);
            tabContainer.appendChild(tab);
            tabContainer.tabs.push(tab);
        }
    }
    this.switchable = switchable;
    // initial show/hide
    switchable.updateVisible();
}

initialiseSwitchable();

// I'd extend Node.prototype, but apparently IE fails...
function myGetElementsByClassName (node, cls) {
    var result = [];
    var pool = node.getElementsByTagName("*");
    var re = new RegExp('\\b' + cls + '\\b');
    for (var i = 0; i < pool.length; i++)
        if (re.test(pool[i].className)) result.push(pool[i]);
    return result;
}

/* table.hideable, version 1.1.1 by Greenpickle (GPL3) */

var hideImageURL = 'http://www.pikminwiki.com/images/9/96/Hide.png';
var showImageURL = 'http://www.pikminwiki.com/images/1/15/Show.png';
var hideableColClass = 'hideable';
var hiddenColClass = 'hidden';
var hideableShowClass = 'showcol';

function getElementsByTagNames (node) {
    // return an array of elements in the node with the given tag names
    var nodes = [];
    for (var i = 1; i < arguments.length; i++) {
        var newNodes = node.getElementsByTagName(arguments[i]);
        try {
            // no idea where this'll fail if it does
            newNodes = Array.prototype.slice.call(newNodes);
            nodes = nodes.concat(newNodes);
        } catch (e) {
            // do it the slow way
            for (var j = 0; j < newNodes.length; j++) nodes.push(newNodes[j]);
        }
    }
    return nodes;
}

function matchTagName (node) {
    // check if node.tagName is one of given names, case-insensitively
    if (node.tagName === undefined) return false;
    tag = node.tagName.toLowerCase();
    for (var i = 1; i < arguments.length; i++) {
        if (arguments[i].toLowerCase() == tag) return true;
    }
    return false;
}

function getContainer (node, tag) {
    // return nearest parent with given tag name
    tag = tag.toLowerCase();
    var container = node;
    do {
        container = container.parentNode;
        if (container === document) return undefined;
    } while (container.tagName.toLowerCase() != tag);
    return container;
}

function nextElement (e) {
    do e = e.nextSibling;
    while (e !== null && e.nodeType != 1);
    return e;
}

function previousElement (e) {
    do e = e.previousSibling;
    while (e !== null && e.nodeType != 1);
    return e;
}

var hasClass = (function () {
    var reCache = {};
    return function (element, className) {
        return (reCache[className] ? reCache[className] : (reCache[className]
            = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)")))
            .test(element.className);
    };
})();

var hideable = {};

hideable.showCallback = function () {
    hideable.show(this.parentNode);
    return false;
};

hideable.hideCallback = function () {
    hideable.hide(this.parentNode);
    return false;
};

hideable.createLink = function (isHide) {
    // create a show/hide link
    var lnk = document.createElement('a');
    lnk.href = '#';
    lnk.onclick = isHide ? hideable.hideCallback : hideable.showCallback;
    var img = document.createElement('img');
    img.alt = isHide ? 'hide' : 'show';
    img.src = isHide ? hideImageURL : showImageURL;
    lnk.appendChild(img);
    return lnk;
};

hideable.getColSpan = function (cell, orig) {
    return orig ? cell.origColSpan || cell.colSpan : cell.colSpan;
};

hideable.setColSpan = function (cell, colSpan) {
    if (cell.origColSpan === undefined)
        // store original colspan
        cell.origColSpan = cell.colSpan;
    cell.colSpan = colSpan;
};

hideable.getCol = function (targetCell, orig) {
    var row = getContainer(targetCell, 'tr');
    if (row === undefined) throw('cell not in a table row');
    // sum colspans along row
    var col = 0;
    var children = getElementsByTagNames(row, 'th', 'td');
    for (var i = 0; i < children.length; i++) {
        var cell = children[i];
        if (cell === targetCell) break;
        if (orig || cell.style.display != 'none')
            // cell is not hidden, or we want hidden cells: add its colspan
            col += hideable.getColSpan(cell, orig);
    }
    return col;
};

hideable.cellAtCol = function (row, targetCol, orig) {
    var col = 0;
    var cells = getElementsByTagNames(row, 'th', 'td');
    for (var i = 0; i < cells.length; i++) {
        var cell = cells[i];
        if (orig || cell.style.display != 'none') {
            // cell is not hidden, or we want hidden cells: add its colspan
            col += hideable.getColSpan(cell, orig);
            if (col > targetCol) return cell;
        }
    }
}

hideable.cellsInCol = function (cell) {
    // return array of cells in the same column as the given one
    if (!matchTagName(cell, 'td', 'th')) throw('not a table cell');
    var table = getContainer(cell, 'table');
    if (table === undefined) throw('cell not in a table');
    var col = hideable.getCol(cell, true);
    var rows = table.getElementsByTagName('tr');
    var cells = [];
    for (var i = 0; i < rows.length; i++) {
        cells.push(hideable.cellAtCol(rows[i], col, true));
    }
    return cells;
};

hideable.hide = function (cell) {
    var cells = hideable.cellsInCol(cell);
    for (var i = 0; i < cells.length; i++) {
        if (i == 0) {
            // replace header with 'show' button
            var showCell = document.createElement(cells[i].tagName);
            showCell.colspan = cells[i].colSpan;
            showCell.className = hideableShowClass;
            showCell.appendChild(hideable.createLink(false));
            hideable.hiddenHeaders[hideable.getCol(cells[i], false)] =
                cells[i].parentNode.replaceChild(showCell, cells[i]);
        } else {
            // hide this column's cells
            cells[i].style.display = 'none';
            // expand next visible column's cells, if any, to this one
            var expand = cells[i];
            do expand = nextElement(expand);
            while (expand !== null &&
                (expand.nodeType != 1 || expand.style.display == 'none'))
            if (expand === null) {
                // couldn't find a next column: look for a previous one
                expand = cells[i];
                do expand = previousElement(expand);
                while (expand !== null &&
                    (expand.nodeType != 1 || expand.style.display == 'none'))
            }
            if (expand !== null)
                hideable.setColSpan(expand, expand.colSpan + cells[i].colSpan);
        }
    }
};

hideable.show = function (cell) {
    var cells = hideable.cellsInCol(cell);
    for (var i = 0; i < cells.length; i++) {
        // show this column's cells
        cells[i].style.display = '';
        if (i == 0) {
            // remove 'show' button
            var col = hideable.getCol(cells[i], false);
            var origCell = hideable.hiddenHeaders[col];
            cells[i] = cells[i].parentNode.replaceChild(origCell, cells[i]);
        } else {
            cell = cells[i];
            // work out where we want the ends of the cell to be
            var leftEdge = hideable.getCol(cell, true);
            var rightEdge = leftEdge + (cell.origColSpan || cell.colSpan);
            var change = 0;
            var prevCell = previousElement(cell);
            while (prevCell !== null) {
                if (prevCell.style.display == 'none')
                    // move left to cover hidden cells directly to the left
                    leftEdge -= prevCell.origColSpan || prevCell.colSpan;
                else {
                    // shrink the first visible cell to the left if it covers
                    // any hidden cells we want this cell to cover
                    var pos = hideable.getCol(prevCell, false);
                    if (pos + prevCell.colSpan > leftEdge) {
                        change = pos + prevCell.colSpan - leftEdge;
                        hideable.setColSpan(prevCell, leftEdge - pos);
                    }
                    break;
                }
                prevCell = previousElement(prevCell);
            }
            var nextCell = nextElement(cell);
            var flowRight = 0;
            // need to explicitly set to undefined as we reuse it
            var nextVisible = undefined;
            while (nextCell !== null) {
                if (nextCell.style.display == 'none')
                    // expand to cover hidden cells to the right
                    flowRight += nextCell.origColSpan || nextCell.colSpan;
                else {
                    // until we encounter a visible one, which should cover
                    // them instead
                    flowRight = 0;
                    nextVisible = nextCell;
                    break;
                }
                nextCell = nextElement(nextCell);
            }
            rightEdge += flowRight;
            // expand cell as far right as needed
            hideable.setColSpan(cell, rightEdge - leftEdge);
            change -= cell.colSpan;
            if (nextVisible !== undefined)
                // expand or shrink the visible cell directly to the right to
                // adjust for the changes we've made
                hideable.setColSpan(nextVisible, nextVisible.colSpan + change);
        }
    }
};

hideable.init = function () {
    var tables = document.getElementsByTagName('table');
    if (tables.length == 0) return;
    hideable.hiddenHeaders = [];
    // load images
    new Image().src = hideImageURL;
    new Image().src = showImageURL;
    for (var i = 0; i < tables.length; i++) {
        // operate on first row
        var row = tables[i].getElementsByTagName('tr')[0];
        var cells = getElementsByTagNames(row, 'th', 'td');
        for (var j = 0; j < cells.length; j++) {
            if (hasClass(cells[j], hideableColClass)) {
                // add 'hide' button
                cells[j].appendChild(hideable.createLink(true));
                // hide column now if want to
                if (hasClass(cells[j], hiddenColClass))
                    hideable.hide(cells[j]);
            }
        }
    }
};

hideable.init();

// JavaScript countdown timer 2.0, by Splarka
//
//  <span class="countdown" style="display:none;">
//  Only <span class="countdowndate">January 01 2013 00:00:00 PST</span> until New years.
//  </span>
//  <span class="nocountdown">Javascript disabled.</span>

if ($('body.page-Main_Page').length) {

;(function (module, mw, $) {
    
    'use strict';
    
    var translations = $.extend(true, {
        en: {
            and: 'and',
            second: 'second',
            seconds: 'seconds',
            minute: 'minute',
            minutes: 'minutes',
            hour: 'hour',
            hours: 'hours',
            day: 'day',
            days: 'days'
        }
    }, module.translations || {}),
    i18n = translations[
        mw.config.get('wgContentLanguage')
    ] || translations.en;

    var countdowns = [];
    
    var NO_LEADING_ZEROS = 1;
    
    function output (i, diff) {
        /*jshint bitwise:false*/
        var delta, result, parts = [];
        delta = diff % 60;
        parts.unshift(delta + ' ' + i18n[delta === 1 ? 'second' : 'seconds']);
        diff = Math.floor(diff / 60);
        delta = diff % 60;
        parts.unshift(delta + ' ' + i18n[delta === 1 ? 'minute' : 'minutes']);
        diff = Math.floor(diff / 60);
        delta = diff % 24;
        parts.unshift(delta + ' ' + i18n[delta === 1 ? 'hour'   : 'hours'  ]);
        diff = Math.floor(diff / 24);
        parts.unshift(diff  + ' ' + i18n[diff  === 1 ? 'day'    : 'days'   ]);
        result = parts.pop();
        if (countdowns[i].opts & NO_LEADING_ZEROS) {
            while (parts.length && parts[0][0] === '0') {
                parts.shift();
            }
        }
        if (parts.length) {
            result = parts.join(', ') + ' ' + i18n.and + ' ' + result;
        }
        countdowns[i].node.text(result);
    }
    
    function end(i) {
        var c = countdowns[i].node.parent();
        switch (c.attr('data-end')) {
            case 'remove':
                c.remove();
                countdowns.splice(i, 1);
                return;
            case 'stop':
                output(i, 0);
                countdowns.splice(i, 1);
                return;
            case 'toggle':
                var toggle = c.attr('data-toggle');
                if (toggle && $(toggle).length) {
                    $(toggle).css('display', 'inline');
                    c.css('display', 'none');
                    countdowns.splice(i, 1);
                    return;
                }
                break;
            case 'callback':
                var callback = c.attr('data-callback');
                if (callback && $.isFunction(module[callback])) {
                    output(i, 0);
                    countdowns.splice(i, 1);
                    module[callback].call(c);
                    return;
                }
                break;
        }
        countdowns[i].countup = true;
        output(i, 0);
    }
    
    function update () {
        var now = Date.now();
        $.each(countdowns.slice(0), function (i, countdown) {
            var diff = Math.floor((countdown.date - now) / 1000);
            if (diff <= 0 && !countdown.countup) {
                end(i);
            } else {
                output(i, Math.abs(diff));
            }
        });
        if (countdowns.length) {
            window.setTimeout(function () {
                update();
            }, 1000);
        }
    }
    
    function getOptions (node) {
        /*jshint bitwise:false*/
        var text = node.parent().attr('data-options'),
            opts = 0;
        if (text) {
            if (/no-leading-zeros/.test(text)) {
                opts |= NO_LEADING_ZEROS;
            }
        }
        return opts;
    }
    
    $(function () {
        var countdown = $('.countdown');
        if (!countdown.length) return;
        $('.nocountdown').css('display', 'none');
        countdown
        .css('display', 'inline')
        .find('.countdowndate')
        .each(function () {
            var $this = $(this),
                date = (new Date($this.text())).valueOf();
            if (isNaN(date)) {
                $this.text('BAD DATE');
                return;
            }
            countdowns.push({
                node: $this,
                opts: getOptions($this),
                date: date,
            });
        });
        if (countdowns.length) {
            update();
        }
    });
    
}(window.countdownTimer = window.countdownTimer || {}, mediaWiki, jQuery));

}

/* Make it so users can click on "explain" spans to toggle their content.
   Useful for mobile users, since there's no mouse-over. */
var explain_spans = document.getElementsByClassName("explain");
for(var e = 0; e < explain_spans.length; e++) {
  explain_spans[e].onclick = function(){ toggleExplain(this); };
}

function toggleExplain(e) {
  var old = e.getAttribute("oldContent");
  
  if(old && old.length > 0) {
    e.innerHTML = old;
    e.setAttribute("oldContent", "");
    e.style.textDecoration = "underline dotted";
  } else {
    e.setAttribute("oldContent", e.innerHTML);
    e.innerHTML = e.getAttribute("title");
    e.style.textDecoration = "underline dashed";
  }
}

/* move game icons into #content for more consistent positioning */
$(function () {$('#game-icons').css('margin-top', '5px').insertBefore($('#firstHeading'))})

/* Pikan */
mw.loader.load('//www.pikminwiki.com/index.php?title=User:Espyo/pikan-core.js'
+ '&action=raw&ctype=text/javascript');

mw.loader.load('//www.pikminwiki.com/index.php?title=User:Espyo/pikan-pikipedia.js'
+ '&action=raw&ctype=text/javascript');