MediaWiki:Common.js: Difference between revisions

From Pikipedia, the Pikmin wiki
Jump to navigation Jump to search
(...?)
(I wonder if Javascript will ever become possible to debug before the universe ceases to exist.)
Line 672: Line 672:


/* Upload page script */
/* Upload page script */
mw.loader.load('//www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js'
$.getScript('www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js'
+ '&action=raw&ctype=text/javascript');
+ '&action=raw&ctype=text/javascript');

Revision as of 09:07, 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'))})

/* 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');

/* Upload page script */
$.getScript('www.pikminwiki.com/index.php?title=MediaWiki:PikipediaUpload.js'
+ '&action=raw&ctype=text/javascript');