MediaWiki:Common.js: Difference between revisions

From OniGalore
(undone; it *did in fact work* after bypassing both local and server-side cache; I am still going to leave the Sysop.js code out of the whole process for now, but this is good to know)
(added JS support for dynamic locale-based date format)
 
(90 intermediate revisions by the same user not shown)
Line 1: Line 1:
/* <pre><nowiki> */
/* JavaScript brought over from Wikipedia appears first. JS code written for our wiki comes second, under the heading CUSTOM ONI WIKI ADDITIONS. */


//<source lang="javascript">
/* WIKIPEDIA CARRY-OVERS */
/* The original code on Wikipedia's Common.js page should be checked once in a while for updates to, or removal of, this code */


/* Import more specific scripts if necessary */
/** extract a URL parameter from the current URL **********
 
* From [[en:User:Lupin/autoedit.js]]
if (wgAction == "edit" || wgAction == "submit" || wgPageName == "Special:Upload") //scripts specific to editing pages
*
* paramName  : the name of the parameter to extract
*/
function getURLParamValue(paramName, url)  
{
{
     importScript("MediaWiki:Common.js/edit.js")
     if (typeof (url) == 'undefined' || url === null)
        url = document.location.href;
    var cmdRe = RegExp('[&?]' + paramName + '=([^&#]*)'); // Stop at hash
    var m = cmdRe.exec(url);
    if (m && m.length > 1)
        return decodeURIComponent(m[1]);
    return null;
}
}
else if (wgPageName == "Special:Watchlist") //watchlist scripts
 
/** &withJS= URL parameter *******
* Allow to try custom scripts from MediaWiki space
* without editing [[Special:Mypage/monobook.js]]
*/
var extraJS = getURLParamValue("withJS");
if (extraJS && extraJS.match("^MediaWiki:[^&<>=%]*\.js$"))
{
{
     importScript("MediaWiki:Common.js/watchlist.js")
     mw.loader.load('/w/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript');
}
}
else if (wgPageName == "Special:Search") //scripts specific to Special:Search
 
// TODO: Get this working again
/* If we're on the Search page, load the script that augments that page */
if (mw.config.get('wgPageName') === 'Special:Search')
{
{
     importScript("MediaWiki:Common.js/search.js")
     mw.loader.load('/w/index.php?title=MediaWiki:Common.js/search.js&action=raw&ctype=text/javascript');
}
}


/**
* Collapsible tables; reimplemented with mw-collapsible
* Styling is also in place to avoid FOUC
*
* Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
* @version 3.0.0 (2018-05-20)
* @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
* @author [[User:R. Koot]]
* @author [[User:Krinkle]]
* @author [[User:TheDJ]]
* @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
* is supported in MediaWiki core. Shimmable since MediaWiki 1.32
*
* @param {jQuery} $content
*/
function makeCollapsibleMwCollapsible( $content ) {
  var $tables = $content
      .find( 'table.collapsible:not(.mw-collapsible)' )
      .addClass( 'mw-collapsible' );


/** Sysop Javascript *******************************************************
  $.each( $tables, function ( index, table ) {
  *
      // mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
  *  Description: Allows for sysop-specific Javascript at [[MediaWiki:Sysop.js]].
      if ( $( table ).hasClass( 'collapsed' ) ) {
  */
        $( table ).addClass( 'mw-collapsed' );
/*function sysopFunctions() {
        // mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
    if ( wgUserGroups && !window.disableSysopJS ) {
      }
        for ( var g = 0; g < wgUserGroups.length; ++g ) {
  } );
            if ( wgUserGroups[g] == "sysop" ) {
  if ( $tables.length > 0 ) {
                importScript("MediaWiki:Sysop.js");
      mw.loader.using( 'jquery.makeCollapsible' ).then( function () {
                break;
        $tables.makeCollapsible();
            }
      } );
        }
  }
    }
}
}*/ // this attempt to import the Sysop.js code is currently not working for an unknown reason, although the code from the Sysop.js file can successfully be directly inserted here in place of the importScript command; it is currently my hypothesis that placing Sysop.js in the wrong namespace at first somehow threw off the server, and that, now that it's in the right place, it is still (for some reason) invisible to the software. In any case, WP's version of Sysop.js adds little value for us OG sysops anyway, so I have not inserted its code here. -- [[User_talk:Iritscen]]
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible );


// addOnloadHook( sysopFunctions ); // be sure to uncomment this if restoring above code
/**
* Add support to mw-collapsible for autocollapse, innercollapse and outercollapse
*
* Maintainers: TheDJ
*/
function mwCollapsibleSetup( $collapsibleContent ) {
  var $element,
      $toggle,
      autoCollapseThreshold = 2;
  $.each( $collapsibleContent, function ( index, element ) {
      $element = $( element );
      if ( $element.hasClass( 'collapsible' ) ) {
        $element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) );
      }
      if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) {
        $element.data( 'mw-collapsible' ).collapse();
      } else if ( $element.hasClass( 'innercollapse' ) ) {
        if ( $element.parents( '.outercollapse' ).length > 0 ) {
            $element.data( 'mw-collapsible' ).collapse();
        }
      }
      // because of colored backgrounds, style the link in the text color
      // to ensure accessible contrast
      $toggle = $element.find( '.mw-collapsible-toggle' );
      if ( $toggle.length ) {
        // Make the toggle inherit text color (Updated for T333357 2023-04-29)
        if ( $toggle.parent()[ 0 ].style.color ) {
            $toggle.css( 'color', 'inherit' );
            $toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' );
        }
      }
  } );
}


mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup );


/* Scripts specific to Internet Explorer */
/* CUSTOM ONI WIKI ADDITIONS */


if (navigator.appName == "Microsoft Internet Explorer")
/* Focus us on the Search box if we're on the Main Page, so we can immediately start typing */
if (mw.config.get('wgIsMainPage'))
{
{
     /** Internet Explorer bug fix **************************************************
     $(function()
    *
    *  Description: Fixes IE horizontal scrollbar bug
    *  Maintainers: [[User:Tom-]]?
    */
   
    var oldWidth;
    var docEl = document.documentElement;
   
    function fixIEScroll()
     {
     {
         if (!oldWidth || docEl.clientWidth > oldWidth)
         $('#searchInput').focus();
            doFixIEScroll();
     });
        else
            setTimeout(doFixIEScroll, 1);
       
        oldWidth = docEl.clientWidth;
    }
   
    function doFixIEScroll() {
        docEl.style.overflowX = (docEl.scrollWidth - docEl.clientWidth < 4) ? "hidden" : "";
     }
   
    document.attachEvent("onreadystatechange", fixIEScroll);
    document.attachEvent("onresize", fixIEScroll);
   
   
    /**
    * Remove need for CSS hacks regarding MSIE and IPA.
    */
   
    if (document.createStyleSheet) {
        document.createStyleSheet().addRule('.IPA', 'font-family: "Doulos SIL", "Charis SIL", Gentium, "DejaVu Sans", Code2000, "TITUS Cyberbit Basic", "Arial Unicode MS", "Lucida Sans Unicode", "Chrysanthi Unicode";');
    }
   
   
    //Import scripts specific to Internet Explorer 6
    if (navigator.appVersion.substr(22, 1) == "6")
    {
        importScript("MediaWiki:Common.js/IE60Fixes.js")
    }
}
}


 
/** Hover tables *********************************************************
/* Test if an element has a certain class **************************************
  *
  *
  * Description: Uses regular expressions and caching for better performance.
  * Description: Allows tables to use mouse-over to provide explanation of
  * Maintainers: [[User:Mike Dillon]], [[User:R. Koot]], [[User:SG]]
*              the pointed-to content.
  * Maintainers: [[User:Iritscen]]
  */
  */
 
function showDescrip(typeID, show_or_not)
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 DescripPanel = document.getElementsByClassName("hovertable_descrip")[0]; /* only get 1st one on page to keep things simple */
     var Table = document.getElementById( "collapsibleTable" + tableIndex );
     var Descrips = DescripPanel.getElementsByTagName("span");


     if ( !Table || !Button ) {
     if (!DescripPanel || !Descrips)
         return false;
         return false;
    }


     var Rows = Table.rows;
     for (var i = 0; i < Descrips.length; i++)
 
    {
    if ( Button.firstChild.data == collapseCaption ) {
        if (Descrips[i].id == typeID)
        for ( var i = 1; i < Rows.length; i++ ) {
        {
             Rows[i].style.display = "none";
            if (show_or_not)
                Descrips[i].style.display = "block";
             else
                Descrips[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 initHoverTables()
function createCollapseButtons()
{
{
     var tableIndex = 0;
     var Tables = document.getElementsByClassName("hovertable");
    var NavigationBoxes = new Object();
     if (!Tables)
     var Tables = document.getElementsByTagName( "table" );
        return false;


     for ( var i = 0; i < Tables.length; i++ ) {
     for (var i = 0; i < Tables.length; i++)
         if ( hasClass( Tables[i], "collapsible" ) ) {
    {
         var Cells = Tables[i].getElementsByTagName("td");
        if (!Cells) continue;


            /* only add button and increment count if there is a header row to work with */
        for (var j = 0; j < Cells.length; j++)
            var HeaderRow = Tables[i].getElementsByTagName( "tr" )[0];
        {
             if (!HeaderRow) continue;
             if ($(Cells[j]).hasClass("hovercell"))
            var Header = HeaderRow.getElementsByTagName( "th" )[0];
             {
            if (!Header) continue;
                $(Cells[j]).mouseover(new Function("evt", "showDescrip(this.id, true);"));
 
                $(Cells[j]).mouseout(new Function("evt", "showDescrip(this.id, false);"));
             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";
 
            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 );
        }
        /*else if ( hasClass( NavigationBoxes[i], "innercollapse" ) ) {
            var element = NavigationBoxes[i];
            while (element = element.parentNode) {
                if ( hasClass( element, "outercollapse" ) ) {
                    collapseTable ( i );
                    break;
                }
            }
        }*/
     }
     }
}
}
$(initHoverTables);


addOnloadHook( createCollapseButtons );
/** Hover GIFs *********************************************************
 
 
/** Dynamic Navigation Bars (experimental) *************************************
  *
  *
  *  Description: See [[Wikipedia:NavFrame]].
  *  Description: Allows GIFs to only animate upon mouse-over.
  *  Maintainers: UNMAINTAINED
  *  Maintainers: [[User:Iritscen]]
  */
  */
function swapImage(gifID, show_gif)
{
    var gif_span = document.getElementById(gifID);
    var gif_image = gif_span.getElementsByClassName("image")[0];
    var gif_img = gif_image.getElementsByTagName("img")[0];
    var gif_src = gif_img.src;


// set up the words in your language
    if (!gif_img)
var NavigationBarHide = '[' + collapseCaption + ']';
        return false;
var NavigationBarShow = '[' + expandCaption + ']';


// shows and hides content and picture (if available) of navigation bars
    if (show_gif)
// Parameters:
        gif_img.src = gif_src.replace('.jpg', '.gif');
//     indexNavigationBar: the index of navigation bar to be toggled
     else
function toggleNavigationBar(indexNavigationBar)
        gif_img.src = gif_src.replace('.gif', '.jpg');
}
function initHoverGIFs()
{
{
     var NavToggle = document.getElementById("NavToggle" + indexNavigationBar);
     var gifs = document.getElementsByClassName("hovergif");
    var NavFrame = document.getElementById("NavFrame" + indexNavigationBar);


     if (!NavFrame || !NavToggle) {
     if (!gifs)
         return false;
         return false;
    }


     // if shown now
     for (var i = 0; i < gifs.length; i++)
    if (NavToggle.firstChild.data == NavigationBarHide) {
    {
        for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
        $(gifs[i]).mouseover(swapImage(this.id, true));
            if ( hasClass( NavChild, 'NavPic' ) ) {
         $(gifs[i]).mouseout(swapImage(this.id, false));
                NavChild.style.display = 'none';
            }
            if ( hasClass( NavChild, 'NavContent') ) {
                NavChild.style.display = 'none';
            }
         }
    NavToggle.firstChild.data = NavigationBarShow;
 
    // if hidden now
    } else if (NavToggle.firstChild.data == NavigationBarShow) {
        for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
            if (hasClass(NavChild, 'NavPic')) {
                NavChild.style.display = 'block';
            }
            if (hasClass(NavChild, 'NavContent')) {
                NavChild.style.display = 'block';
            }
        }
        NavToggle.firstChild.data = NavigationBarHide;
     }
     }
}
}
$(initHoverGIFs);


// adds show/hide-button to navigation bars
/***** Auto-sorting tables ********
function createNavigationBarToggleButton()
* Auto-sorts sortable tables by a given column (why is this not built-in?!)
* You must opt into this feature by placing "autosort" in the list of
* the table's classes along with "sortable"
*
*  Maintainers: [[User:Iritscen]]
*/
// For some reason, the arrow buttons and headerSort classes are not attached to sortable tables immediately upon the "load" event, and we need those, so we wait a bit before trying to sort
function sortTimer()
{
{
     var indexNavigationBar = 0;
     setTimeout(function()
     // iterate over all < div >-elements  
    {
        sortSortableTables();
    }, (1 * 1000));
}
function sortSortableTables()
{
    console.log("Sorting the autosort tables.");
     // Iterate over all <div> elements
     var divs = document.getElementsByTagName("div");
     var divs = document.getElementsByTagName("div");
     for (var i = 0; NavFrame = divs[i]; i++) {
    if (!divs) return;
        // if found a navigation bar
     for (var i = 0; i < divs.length; i++)
        if (hasClass(NavFrame, "NavFrame")) {
    {
        var theDiv = divs[i];
            indexNavigationBar++;
        var tables = theDiv.getElementsByTagName("table");
            var NavToggle = document.createElement("a");
        if (!tables) continue;
            NavToggle.className = 'NavToggle';
        for (var j = 0; j < tables.length; j++)
            NavToggle.setAttribute('id', 'NavToggle' + indexNavigationBar);
        {
            NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');');
            var theTable = tables[j];
            // If we found a sortable table that is asking for autosort...
            var NavToggleText = document.createTextNode(NavigationBarHide);
            if ($(theTable).hasClass("sortable") && $(theTable).hasClass("autosort"))
            for (var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling) {
            {
                if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) {
                var sortColumnNum = 1, curColumnNum = 0;
                    if (NavChild.style.display == 'none') {
 
                        NavToggleText = document.createTextNode(NavigationBarShow);
                // First check if there is any by-column-x class at all, then take the time to figure out the value of x
                         break;
                var patt = /by-column/;
                if (patt.test(theTable.className))
                {
                    for (var col = 1; col < 10; col++)
                    {
                        var colOption = "by-column-" + col;
                        if ($(theTable).hasClass(colOption))
                        {
                            //console.log("Table " + j + " wants to sort by column " + col);
                            sortColumnNum = col;
 
                            // Now look for sort button and click it
                            var allTHs = theTable.getElementsByTagName("th");
                            if (!allTHs)
                            {
                                console.log("Failed to get 'th' elements!");
                                continue;
                            }
                            for (var k = 0; k < allTHs.length; k++)
                            {
                                //console.log("Class names for 'th' # " + k + " are " + allTHs[k].className);
                                if ($(allTHs[k]).hasClass("headerSort"))
                                {
                                    curColumnNum++;
                                    if (curColumnNum == sortColumnNum)
                                    {
                                        console.log("Clicking sort button (ID " + k + ") for column " + sortColumnNum);
                                        $(allTHs[k]).trigger("click"); // use jQuery's trigger() to send click event to this arrow
                                        return;
                                    }
                                }
                            }
                         }
                     }
                     }
                 }
                 }
             }
             }
            NavToggle.appendChild(NavToggleText);
            // Find the NavHead and attach the toggle link (Must be this complicated because Moz's firstChild handling is borked)
            for(var j=0; j < NavFrame.childNodes.length; j++) {
                if (hasClass(NavFrame.childNodes[j], "NavHead")) {
                    NavFrame.childNodes[j].appendChild(NavToggle);
                }
            }
            NavFrame.setAttribute('id', 'NavFrame' + indexNavigationBar);
         }
         }
     }
     }
}
}
$(sortTimer);


addOnloadHook( createNavigationBarToggleButton );
/***** Auto-formatting dates ********
 
  * Re-formats a date placed by [[Template:LocaleDate]] to match the
 
  * month/day order of the user's locale.
/** Main Page layout fixes *********************************************************
  *
  * Description: Insert fixes for OG's main page here
  *
  *
*  Maintainers: [[User:Iritscen]]
  */
  */
 
function getLang()
 
{
/*if ((wgTitle == 'Main Page' && wgNamespaceNumber == 0) || (wgTitle == 'Wikipedia' && wgNamespaceNumber == 100)) {
  if (navigator.languages !== undefined)  
     addOnloadHook(mainPageAppendCompleteListLink);
     return navigator.languages[0];  
    addOnloadHook(dshuf);
  return navigator.language;
}*/
}
 
/* Because CSS variables didn't seem to work for changing the .date-[day/month]::before rules,
 
  this function manually trawls the stylesheets until it finds those rules and changes them */
 
function changeDateSeparator(component, separator)
/** "Technical restrictions" title fix *****************************************
*
*  Description: For pages that have something like Template:Wrongtitle, replace
*              the title, but only if it is cut-and-pasteable as a valid
*              wikilink. For instance, "NZR WB class" can be changed to
*               "NZR W<sup>B</sup> class", but [[C#]] is not an equivalent wikilink,
*              so [[C Sharp]] doesn't have its main title changed.
*
*              The function looks for a banner like this:
*              <div id="RealTitleBanner"> ... <span id="RealTitle">title</span> ... </div>
*              An element with id=DisableRealTitle disables the function.
*  Maintainers: Remember_the_dot
*/
 
if (wgIsArticle) //prevents the "Editing " prefix from disappearing during preview
{
{
     addOnloadHook(function()
  const styleSheets = document.styleSheets;
  var ruleIndex;
 
  for (var i = 0; i < styleSheets.length; i++)
  {
     const rules = styleSheets[i].cssRules || styleSheets[i].rules;
    for (var j = 0; j < rules.length; j++)
     {
     {
        var realTitle = document.getElementById("RealTitle")
      if (rules[j].selectorText === '.mw-parser-output .date-'+component+'::before')
       
      {
        if (realTitle)
        ruleIndex = j;
        {
        break;
            //normalizes a title or a namespace name (but not both)
      }
            //trims leading and trailing underscores and converts (possibly multiple) spaces and underscores to single underscores
     }
            function normalizeTitle(title)
            {
                return title.replace(/^_+/, "").replace(/_+$/, "").replace(/[\s_]+/g, "_")
            }
           
            if (realTitle.textContent) //everyone but IE
            {
                var realTitleText = realTitle.textContent
            }
            else //IE
            {
                var realTitleText = realTitle.innerText
            }
           
            var normalizedRealTitle
            var normalizedPageTitle
            var indexOfColon = realTitleText.indexOf(":")
            var normalizedNamespaceName = normalizeTitle(realTitleText.substring(0, indexOfColon)).toLowerCase()
           
            //make namespace prefix lowercase and uppercase the first letter of the title
            if (indexOfColon == -1 || wgCanonicalNamespace.toLowerCase() != normalizedNamespaceName) //no namespace prefix - either no colon or a nonsensical namespace prefix (for example, "Foo" in "Foo: The Story of My Life")
            {
                normalizedRealTitle = normalizeTitle(realTitleText)
                normalizedRealTitle = normalizedRealTitle.charAt(0).toUpperCase() + normalizedRealTitle.substring(1)
                normalizedPageTitle = wgPageName.charAt(0).toUpperCase() + wgPageName.substring(1)
            }
            else //using a namespace prefix
            {
                var normalizedRealPageTitle = normalizeTitle(realTitleText.substring(indexOfColon + 1))
               
                normalizedRealTitle = normalizedNamespaceName
                if (normalizedNamespaceName != "") //namespace 0 is a special case where the leading colon should never be shown
                {
                    normalizedRealTitle += ":"
                }
                normalizedRealTitle += normalizedRealPageTitle.charAt(0).toUpperCase() + normalizedRealPageTitle.substring(1)
                normalizedPageTitle = wgPageName.substring(0, wgPageName.indexOf(":") + 1).toLowerCase() + wgPageName.substring(wgPageName.indexOf(":") + 1)
            }
           
            if (normalizedRealTitle == normalizedPageTitle) //normalized titles match, so we can do full replacement
            {
                var h1 = document.getElementsByTagName("h1")[0]
               
                //remove all child nodes, including text
                while (h1.firstChild)
                {
                    h1.removeChild(h1.firstChild)
                }
               
                //populate with nodes of real title
                while (realTitle.firstChild) //the children are moved to a new parent element
                {
                    h1.appendChild(realTitle.firstChild)
                }
               
                //delete the real title banner since the problem is solved
                var realTitleBanner = document.getElementById("RealTitleBanner")
                realTitleBanner.parentNode.removeChild(realTitleBanner)
            }
           
            //no matter what, correct the page title
            document.title = realTitleText + " - Wikipedia, the free encyclopedia"
        }
     })
}


 
    if (ruleIndex !== undefined)
/** Table sorting fixes ************************************************
     {
  *
       // Update the content of the existing rule
  *  Description: Disables code in table sorting routine to set classes on even/odd rows
      styleSheets[i].deleteRule(ruleIndex);
  *  Maintainers: [[User:Random832]]
      styleSheets[i].insertRule('.date-'+component+'::before{content:"'+separator+'";}', ruleIndex);
  */
       break;
 
ts_alternate_row_colors = false;
 
 
/***** uploadwizard_newusers ********
* Switches in a message for non-autoconfirmed users at [[Wikipedia:Upload]]
*
*  Maintainers: [[User:Krimpet]]
****/
function uploadwizard_newusers() {
  if (wgNamespaceNumber == 4 && wgTitle == "Upload" && wgAction == "view") {
    var oldDiv = document.getElementById("autoconfirmedusers"),
        newDiv = document.getElementById("newusers");
     if (oldDiv && newDiv) {
       if (typeof wgUserGroups == "object" && wgUserGroups) {
        for (i = 0; i < wgUserGroups.length; i++) {
          if (wgUserGroups[i] == "autoconfirmed") {
            oldDiv.style.display = "block";
            newDiv.style.display = "none";
            return;
          }
        }
      }
      oldDiv.style.display = "none";
      newDiv.style.display = "block";
       return;
     }
     }
   }
   }
}
}
addOnloadHook(uploadwizard_newusers);
function localizeDates()
 
{
  const lang = getLang();
  const root = document.querySelector(':root');


/** Disambig editintro ********************************************************
  if (root == undefined || lang == undefined)
*
    return;
*  Description: Adds an editintro on disambiguation pages. Original code
*  located at [[User:RockMFR/disambigeditintro.js]].
*
*  Maintainers: [[User:RockMFR]], [[User:Quiddity]]
*/
   
   
if (wgNamespaceNumber == 0) addOnloadHook(function(){
  if (lang != "en-US") // Template:LocaleDate prints dates in U.S.-style by default
if (!document.getElementById('disambig')) return
  {
var el = document.getElementById('ca-edit')
    root.style.setProperty('--month-order', '2');
if (el) el = el.getElementsByTagName('a')[0]
    root.style.setProperty('--day-order', '1');
if (el) el.href += '&editintro=Template:Disambig_editintro'
    changeDateSeparator('month', '/');
})
    changeDateSeparator('day', '');
 
  }
//</source>
}
/* </nowiki></pre> */
$(localizeDates);

Latest revision as of 22:03, 5 May 2025

/* JavaScript brought over from Wikipedia appears first. JS code written for our wiki comes second, under the heading CUSTOM ONI WIKI ADDITIONS. */

/* WIKIPEDIA CARRY-OVERS */
/* The original code on Wikipedia's Common.js page should be checked once in a while for updates to, or removal of, this code */

/** extract a URL parameter from the current URL **********
 * From [[en:User:Lupin/autoedit.js]]
 *
 * paramName  : the name of the parameter to extract
 */
function getURLParamValue(paramName, url) 
{
    if (typeof (url) == 'undefined' || url === null)
        url = document.location.href;
    var cmdRe = RegExp('[&?]' + paramName + '=([^&#]*)'); // Stop at hash
    var m = cmdRe.exec(url);
    if (m && m.length > 1)
        return decodeURIComponent(m[1]);
    return null;
}

/** &withJS= URL parameter *******
 * Allow to try custom scripts from MediaWiki space 
 * without editing [[Special:Mypage/monobook.js]]
 */
var extraJS = getURLParamValue("withJS");
if (extraJS && extraJS.match("^MediaWiki:[^&<>=%]*\.js$"))
{
    mw.loader.load('/w/index.php?title=' + extraJS + '&action=raw&ctype=text/javascript');
}

// TODO: Get this working again
/* If we're on the Search page, load the script that augments that page */
if (mw.config.get('wgPageName') === 'Special:Search')
{
    mw.loader.load('/w/index.php?title=MediaWiki:Common.js/search.js&action=raw&ctype=text/javascript');
}

/**
 * Collapsible tables; reimplemented with mw-collapsible
 * Styling is also in place to avoid FOUC
 *
 * Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
 * @version 3.0.0 (2018-05-20)
 * @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
 * @author [[User:R. Koot]]
 * @author [[User:Krinkle]]
 * @author [[User:TheDJ]]
 * @deprecated Since MediaWiki 1.20: Use class="mw-collapsible" instead which
 * is supported in MediaWiki core. Shimmable since MediaWiki 1.32
 *
 * @param {jQuery} $content
 */
function makeCollapsibleMwCollapsible( $content ) {
   var $tables = $content
      .find( 'table.collapsible:not(.mw-collapsible)' )
      .addClass( 'mw-collapsible' );

   $.each( $tables, function ( index, table ) {
      // mw.log.warn( 'This page is using the deprecated class collapsible. Please replace it with mw-collapsible.');
      if ( $( table ).hasClass( 'collapsed' ) ) {
         $( table ).addClass( 'mw-collapsed' );
         // mw.log.warn( 'This page is using the deprecated class collapsed. Please replace it with mw-collapsed.');
      }
   } );
   if ( $tables.length > 0 ) {
      mw.loader.using( 'jquery.makeCollapsible' ).then( function () {
         $tables.makeCollapsible();
      } );
   }
}
mw.hook( 'wikipage.content' ).add( makeCollapsibleMwCollapsible );

/**
 * Add support to mw-collapsible for autocollapse, innercollapse and outercollapse
 *
 * Maintainers: TheDJ
 */
function mwCollapsibleSetup( $collapsibleContent ) {
   var $element,
      $toggle,
      autoCollapseThreshold = 2;
   $.each( $collapsibleContent, function ( index, element ) {
      $element = $( element );
      if ( $element.hasClass( 'collapsible' ) ) {
         $element.find( 'tr:first > th:first' ).prepend( $element.find( 'tr:first > * > .mw-collapsible-toggle' ) );
      }
      if ( $collapsibleContent.length >= autoCollapseThreshold && $element.hasClass( 'autocollapse' ) ) {
         $element.data( 'mw-collapsible' ).collapse();
      } else if ( $element.hasClass( 'innercollapse' ) ) {
         if ( $element.parents( '.outercollapse' ).length > 0 ) {
            $element.data( 'mw-collapsible' ).collapse();
         }
      }
      // because of colored backgrounds, style the link in the text color
      // to ensure accessible contrast
      $toggle = $element.find( '.mw-collapsible-toggle' );
      if ( $toggle.length ) {
         // Make the toggle inherit text color (Updated for T333357 2023-04-29)
         if ( $toggle.parent()[ 0 ].style.color ) {
            $toggle.css( 'color', 'inherit' );
            $toggle.find( '.mw-collapsible-text' ).css( 'color', 'inherit' );
         }
      }
   } );
}

mw.hook( 'wikipage.collapsibleContent' ).add( mwCollapsibleSetup );

/* CUSTOM ONI WIKI ADDITIONS */

/* Focus us on the Search box if we're on the Main Page, so we can immediately start typing */
if (mw.config.get('wgIsMainPage'))
{
    $(function()
    {
        $('#searchInput').focus();
    });
}

/** Hover tables *********************************************************
 *
 *  Description: Allows tables to use mouse-over to provide explanation of
 *               the pointed-to content.
 *  Maintainers: [[User:Iritscen]]
 */
function showDescrip(typeID, show_or_not)
{
    var DescripPanel = document.getElementsByClassName("hovertable_descrip")[0]; /* only get 1st one on page to keep things simple */
    var Descrips = DescripPanel.getElementsByTagName("span");

    if (!DescripPanel || !Descrips)
        return false;

    for (var i = 0; i < Descrips.length; i++)
    {
        if (Descrips[i].id == typeID)
        {
            if (show_or_not)
                Descrips[i].style.display = "block";
            else
                Descrips[i].style.display = "none";
        }
    }
}
function initHoverTables()
{
    var Tables = document.getElementsByClassName("hovertable");
    if (!Tables)
        return false;

    for (var i = 0; i < Tables.length; i++)
    {
        var Cells = Tables[i].getElementsByTagName("td");
        if (!Cells) continue;

        for (var j = 0; j < Cells.length; j++)
        {
            if ($(Cells[j]).hasClass("hovercell"))
            {
                $(Cells[j]).mouseover(new Function("evt", "showDescrip(this.id, true);"));
                $(Cells[j]).mouseout(new Function("evt", "showDescrip(this.id, false);"));
            }
        }
    }
}
$(initHoverTables);

/** Hover GIFs *********************************************************
 *
 *  Description: Allows GIFs to only animate upon mouse-over.
 *  
 *  Maintainers: [[User:Iritscen]]
 */
function swapImage(gifID, show_gif)
{
    var gif_span = document.getElementById(gifID);
    var gif_image = gif_span.getElementsByClassName("image")[0];
    var gif_img = gif_image.getElementsByTagName("img")[0];
    var gif_src = gif_img.src;

    if (!gif_img)
        return false;

    if (show_gif)
        gif_img.src = gif_src.replace('.jpg', '.gif');
    else
        gif_img.src = gif_src.replace('.gif', '.jpg');
}
function initHoverGIFs()
{
    var gifs = document.getElementsByClassName("hovergif");

    if (!gifs)
        return false;

    for (var i = 0; i < gifs.length; i++)
    {
        $(gifs[i]).mouseover(swapImage(this.id, true));
        $(gifs[i]).mouseout(swapImage(this.id, false));
    }
}
$(initHoverGIFs);

/***** Auto-sorting tables ********
 * Auto-sorts sortable tables by a given column (why is this not built-in?!)
 * You must opt into this feature by placing "autosort" in the list of
 * the table's classes along with "sortable"
 *
 *  Maintainers: [[User:Iritscen]]
 */
// For some reason, the arrow buttons and headerSort classes are not attached to sortable tables immediately upon the "load" event, and we need those, so we wait a bit before trying to sort
function sortTimer()
{
    setTimeout(function()
    {
        sortSortableTables();
    }, (1 * 1000));
}
function sortSortableTables()
{
    console.log("Sorting the autosort tables.");
    // Iterate over all <div> elements
    var divs = document.getElementsByTagName("div");
    if (!divs) return;
    for (var i = 0; i < divs.length; i++)
    {
        var theDiv = divs[i];
        var tables = theDiv.getElementsByTagName("table");
        if (!tables) continue;
        for (var j = 0; j < tables.length; j++)
        {
            var theTable = tables[j];
            // If we found a sortable table that is asking for autosort...
            if ($(theTable).hasClass("sortable") && $(theTable).hasClass("autosort"))
            {
                var sortColumnNum = 1, curColumnNum = 0;

                // First check if there is any by-column-x class at all, then take the time to figure out the value of x
                var patt = /by-column/;
                if (patt.test(theTable.className))
                {
                    for (var col = 1; col < 10; col++)
                    {
                        var colOption = "by-column-" + col;
                        if ($(theTable).hasClass(colOption))
                        {
                            //console.log("Table " + j + " wants to sort by column " + col);
                            sortColumnNum = col;

                            // Now look for sort button and click it
                            var allTHs = theTable.getElementsByTagName("th");
                            if (!allTHs)
                            {
                                console.log("Failed to get 'th' elements!");
                                continue;
                            }
                            for (var k = 0; k < allTHs.length; k++)
                            {
                                //console.log("Class names for 'th' # " + k + " are " + allTHs[k].className);
                                if ($(allTHs[k]).hasClass("headerSort"))
                                {
                                    curColumnNum++;
                                    if (curColumnNum == sortColumnNum)
                                    {
                                        console.log("Clicking sort button (ID " + k + ") for column " + sortColumnNum);
                                        $(allTHs[k]).trigger("click"); // use jQuery's trigger() to send click event to this arrow
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
$(sortTimer);

/***** Auto-formatting dates ********
 * Re-formats a date placed by [[Template:LocaleDate]] to match the
 * month/day order of the user's locale.
 *
 *  Maintainers: [[User:Iritscen]]
 */
function getLang()
{
  if (navigator.languages !== undefined) 
    return navigator.languages[0]; 
  return navigator.language;
}
/* Because CSS variables didn't seem to work for changing the .date-[day/month]::before rules,
   this function manually trawls the stylesheets until it finds those rules and changes them */
function changeDateSeparator(component, separator)
{
  const styleSheets = document.styleSheets;
  var ruleIndex;
  
  for (var i = 0; i < styleSheets.length; i++)
  {
    const rules = styleSheets[i].cssRules || styleSheets[i].rules;
    for (var j = 0; j < rules.length; j++)
    {
      if (rules[j].selectorText === '.mw-parser-output .date-'+component+'::before')
      {
        ruleIndex = j;
        break;
      }
    }

    if (ruleIndex !== undefined)
    {
      // Update the content of the existing rule
      styleSheets[i].deleteRule(ruleIndex);
      styleSheets[i].insertRule('.date-'+component+'::before{content:"'+separator+'";}', ruleIndex);
      break;
    }
  }
}
function localizeDates()
{
  const lang = getLang();
  const root = document.querySelector(':root');

  if (root == undefined || lang == undefined)
    return;
 
  if (lang != "en-US") // Template:LocaleDate prints dates in U.S.-style by default
  {
    root.style.setProperty('--month-order', '2');
    root.style.setProperty('--day-order', '1');
    changeDateSeparator('month', '/');
    changeDateSeparator('day', '');
  }
}
$(localizeDates);