MediaWiki:Common.js: Difference between revisions
Jump to navigation
Jump to search
(Test 2) |
No edit summary |
||
Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
/* 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'))}) | |||
/* Upload page script */ | /* Upload page script */ | ||
mw.loader.load('//www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js' | mw.loader.load('//www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js' | ||
+ '&action=raw&ctype=text/javascript'); | + '&action=raw&ctype=text/javascript'); |
Revision as of 11:27, November 6, 2016
/* Any JavaScript here will be loaded for all users on every page load. */
/* 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'))})
/* Upload page script */
mw.loader.load('//www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js'
+ '&action=raw&ctype=text/javascript');