MediaWiki:Common.js

/** * This file loads for every user visiting the wiki. * For skin specific variants see MediaWiki:Monobook.js and MediaWiki:Wikia.css * for monobook and oasis respectively * * Please test any changes made to this file. * Jshint  can catch syntax errors to help testing. */

/*global importArticles:true */

/*jshint bitwise:true, browser:true, camelcase:true, curly:true, devel:false, eqeqeq:true, es3:false, forin:true, immed:true, jquery:true, latedef:true, newcap:true, noarg:true, noempty:true, nonew:true, onevar:true, plusplus:true, quotmark:single, undef:true, unused:true, strict:true, trailing:true


 * ( function ( $, mw, rs ) {

'use strict';

/**    * Global variables set for imported scripts */   window.AjaxRCRefreshText = 'Auto-refresh'; window.ajaxPages = [ 'Special:RecentChanges', 'Special:Contributions', 'Special:Log', 'Special:Log/move', 'Special:AbuseLog', 'Special:NewFiles', 'Special:NewPages', 'Special:Watchlist', 'Special:Statistics', 'Special:ListFiles', 'Category:Speedy_deletion_candidates', 'Category:Speedy_move_candidates', ];

/**    * Cache mw.config values */   var conf = mw.config.get( [        'skin',        'wgAction',        'wgCanonicalSpecialPageName',        'wgNamespaceNumber',        'wgPageName',        'wgTitle',        'wgUserName'    ] );

/**    * Reusable functions *    * Deprecated functions have been mapped to modern counterparts where applicable * @todo Use mw.log.deprecate when we get access to it    *       In the mean time find a way to add a stacktrace */   var util = { /**        * Adds commas to a number string *        * @example 123456.78 -> 123,456.78 *        * @param num {number|string} A number to add commas to         * * @returns {string} The number with commas */       addCommas: function ( num ) { num += '';

var x = num.split( '.' ), x1 = x[0], x2 = x.length > 1 ? '.' + x[1] : '', rgx = /(\d+)(\d{3})/;

while ( rgx.test( x1 ) ) { x1 = x1.replace( rgx, '$1,$2' ); }

return x1 + x2; },

/**        * Sets a cookie *        * @deprecated Use jquery.cookie instead *        * @param name {string} The name of the cookie to set * @param value {string} The value to set the cookie with * @param expires {number} How long before the cookie expires (in days) * @param path {string} The path of the cookie */       setCookie: function ( name, value, expires, path ) { console.warn( 'Use of "setCookie" is deprecated. Use "$.cookie" instead.' ); $.cookie( name, value, { expires: expires, path: path } ); },

/**        * Reads a cookie *        * @deprecated Use jquery.cookie instead *        * @param name {string} *        * @returns {string} The value of the cookie */       getCookie: function ( name ) { console.warn( 'Use of "getCookie" is deprecated. Use "$.cookie" instead.' ); return $.cookie( name ); },

/**        * Calls the mediawiki api with supplied parameters *        * @deprecated Use mediawiki.api instead *        * @param data {object} * @param _ no longer used * @param callback {function} Function to execute if the request is successful */       callAPI: function ( data, _, callback ) { console.warn( 'Use of "callAPI" is deprecated. Use "mw.Api" instead.' );

var api = new mw.Api, call = ( ['purge', 'query', 'help'].indexOf( data.action ) > -1 ) ? api.get : api.post;

call( data ).done( callback ); }   };

/**    * Settings of each script run/imported * Based on  */   var includes = { /*       example: { // {function|boolean} Conditional to pass for the scripts/styles // to be imported or exec to run // Can be something that evaluates to a boolean if required // if it should always load, set to true conditional: true,

// {array|string} Scripts to import // Remove if unused scripts: [],

// {array|string} Styles to import // Remove if unused styles: [],

// {boolean} Whether to expose exec under the rswiki global // Defaults to false expose: true,

// {function} Function to run // Typically used for small scripts that aren't imported // or for minor things that need to run before importing another script // Will execute before any scripts are imported exec: function { console.log( 'loaded' ); }       }        */

/**        * Inserts  on new talk pages *        * @todo Get this approved as a bot task instead */       addTalkheader: { conditional: true, exec: function { var params = '&preload=Template:Talkheader/preload';

// for redlinks // make sure this is only selecting anchor tags // otherwise this selects li tags used for monobook discussion tab $( 'a.new' ).attr( 'href', function ( _, attr ) {                   if ( attr.indexOf( 'Talk:' ) > -1 || attr.indexOf( '_talk' ) > -1 ) {                        // User_talk doesn't get the template                        if ( attr.indexOf( 'User_talk:' ) > -1 ) {                            return;                        }                        return attr + params;                    }                } );

// for talk pages if (                   conf.wgNamespaceNumber % 2 === 1 &&                    conf.wgNamespaceNumber !== 3 &&                    $( '#noarticletext' ).length                ) { // oasis support if ( conf.skin === 'oasis' ) { $( '#ca-addsection' ).attr( 'href', function ( _, attr ) {                           return attr + params;                        } ); // monobook support } else { // create page and new section tabs $( '#ca-edit a, #ca-addsection a' ).attr( 'href', function ( _, attr ) {                           return attr + params;                        } ); }               }            }        },

/**        * Ajax refresh for various pages */       ajaxrc: { conditional: ( window.ajaxPages.indexOf( conf.wgPageName ) > -1 ), scripts: 'u:dev:AjaxRC/code.js' },

/**        * Google analytics */       analytics: { conditional: true, exec: function { window._gaq = window._gaq || []; window._gaq.push( ['local._setAccount', 'UA-48165410-1'] ); window._gaq.push( ['local._trackPageview'] );

var ga = document.createElement( 'script' ), s;               ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' === document.location.protocol ? 'https://' : 'http://') + 'stats.g.doubleclick.net/dc.js'; s = document.getElementsByTagName( 'script' )[0]; s.parentNode.insertBefore( ga, s ); }       },

/**        * Embeds .ogg files */       audioEmbed: { conditional: $( '.embedMe' ).length, scripts: 'MediaWiki:Common.js/embedding.js' },

/**        * For autosorting sortable tables * @example  */       autosort: { conditional: $( '.sortable' ).length, expose: true, exec: function { mw.loader.using( 'jquery.tablesorter', function {                    // this isn't technically part of our autosort function                    // but it's a handy place to keep it so it loads before any sorting actually happens                    // fixes issues with  in sortable table                    // poke Cqm if you want a more detailed explanation                    $( '.sortable .coins-templ noscript' ).remove;

$( '.sortable[class*="autosort="]' ).each( function ( i ) {                       var $this = $( this ),                            /*                            // @todo test this                            matched = ( ' ' + $( this ).attr( 'class' ) + ' ' )                                .match( / autosort=(\d+)[,-]{1}(a|d) / ),                            */                            matched = /(?:^| )autosort=(\d+)(?:,|-)(a|d)(?: |$)/.exec( $this.attr( 'class' ) ),                            /*                            // @todo test this                            $sortCol = $this                                .find( '> thead th nth-child( ' + matched[1] + ')' )                                .eq( i );                            */                            $sortCol = $( $this.find( '> thead th:nth-child(' + matched[1] + ')' )[i] );

if ( matched[2] === 'd' ) { // descending $sortCol.click.click; } else { // ascending $sortCol.click; }                   } );                } );            }        },

/**        * For adding events team notifications */       bubble: { condtional: true, scripts: 'User:Suppa_chuppa/bubble.js' },

/**        * Calculators */       calc: { conditional: $( '.jcConfig' ).length, scripts: 'MediaWiki:Common.js/calc.js', styles: 'MediaWiki:Common.css/calc.css' },

/**        * For adding to charm logs */       charmAdd: { conditional: (               ( $( '#charmguide' ).length && conf.wgPageName.match( '/Charm_log' ) ) ||                ( $( '.charmtable' ).length && !conf.wgPageName.match( '/Charm_log' ) )            ), scripts: 'User:Joeytje50/Dropadd.js', },

/**        * Countdown timer *        * @todo Import directly from dev wiki */       countdown: { conditional: $( '.countdown' ).length, scripts: 'MediaWiki:Common.js/countdowntimer.js' },

/**        * Adds custom edit buttons to the editor */       customEditButtons: { conditional: ( ['edit', 'submit'].indexOf( conf.wgAction ) > -1 ), exec: function { var more; // redirect mw.toolbar.addButton(                   'http://images.wikia.com/central/images/c/c8/Button_redirect.png',                    'Redirect',                    '#REDIRECT ',                    '',                    'Insert text',                    'mw-editbutton-redirect'                );

// wikitable mw.toolbar.addButton(                   'http://images3.wikia.nocookie.net/central/images/4/4a/Button_table.png',                    'Insert a table',                    '{| class="wikitable"\n|-\n',                    '\n|}',                    '! header 1\n! header 2\n! header 3\n|-\n| row 1, cell 1\n| row 1, cell 2\n| row 1, cell 3\n|-\n| row 2, cell 1\n| row 2, cell 2\n| row 2, cell 3',                    'mw-editbutton-wikitable'                );

// line break mw.toolbar.addButton(                   'http://images2.wikia.nocookie.net/central/images/1/13/Button_enter.png',                    'Line break',                    ' ',                    ,                    ,                    'mw-editbutton-linebreak'                );

// gallery mw.toolbar.addButton(                   'http://images2.wikia.nocookie.net/central/images/1/12/Button_gallery.png',                    'Insert a picture gallery',                    '\n  ',                    'File:Example.jpg|Caption1\nFile:Example.jpg|Caption2',                    'mw-editbutton-gallery'                ); // move edittools expand to end of buttons in oasis editor if ( conf.skin === 'oasis' ) { // pass true to .clone to keep event listeners more = $( '.cke_toolbar_expand' ).clone( true ); $( '.cke_toolbar_expand' ).remove; $( '.cke_toolbar_source' ).append( more ); }           }        },

/**        * Form for reporting vandals in RS:CVU */       cvu: { conditional: ( conf.wgPageName === 'RuneScape:Counter-Vandalism_Unit' ), scripts: 'User:Suppa_chuppa/cvu.js' },

/**        * Database script */       database: { conditional: $( '.DBQuery' ).length, scripts: 'User:Yitzi/database.js' },

/**        * Embeds IRC access into RS:IRC */       embedIrc: { conditional: ( conf.wgPageName === 'RuneScape:Off-site/IRC' ), scripts: 'MediaWiki:Common.js/embedirc.js' },

/**        * Adds an editintro when editing exchange pages */       exchangeIntro: { conditional: (               conf.wgNamespaceNumber === 112 &&                conf.wgPageName.split( '/' )[1] === 'Data'            ), scripts: 'MediaWiki:Common.js/exchangeintro.js' },

/**        * Exchange data charts */       geCharts: { conditional: $( '.GEdatachart').length, scripts: 'MediaWiki:Common.js/GECharts.js' },

/**        * Semi-automatic exchange updating */       gemwUpdate: { conditional: ( conf.wgNamespaceNumber === 112 ), scripts: 'MediaWiki:Common.js/gemwupdate.js' },

/**        * Highlight tables */       highlightTable: { conditional: $( '.lighttable' ).length, scripts: 'MediaWiki:Common.js/highlightTable.js' },

/**        * Remove the fade animation from mw-collapsible */       instantCollapsible: { conditional: $( '.mw-collapsible' ).length, scripts: 'MediaWiki:Common.js/instantCollapsible.js' },

/**        * Script for */       insertUsername: { conditional: (               conf.wgUserName &&                conf.wgNamespaceNumber === 2 &&                conf.wgTitle.indexOf( '/' ) > -1            ), exec: function { $( '.insertusername' ).text( conf.wgUserName ); }       },

/**        * Compares equipment stats */       itemCompare: { conditional: $( '.cioCompareLink' ).length, scripts: 'MediaWiki:Common.js/compare.js', styles: 'MediaWiki:Common.css/compare.css' },

/**        * Konami code easter egg */       konami: { conditional: true, scripts: 'MediaWiki:Common.js/Konami.js' },

/**        * Adds calcs to infoboxes */       monsterCalc: { conditional: $( '#XPEach, #GEPrice, #killXP' ).length, scripts: 'User:Joeytje50/monstercalc.js' },

/**        * Collapses navboxes under certain conditions */       navbox: { conditional: ( conf.wgNamespaceNumber === 0 && $( '.navbox' ).length ), exec: function { // should be defined by MediaWiki:Collapsible-expand // currently hardcoded into template due to wikia bug var expand = 'show', $navbox = $( '.navbox' ), // maximum number of navboxes before they all get collapsed maxShow = 2, // maximum allowable height of navbox before it gets collapsed maxHeight = 300; function collapseNavbox( navbox ) { var $navbox = $( navbox ), $rows, $toggle; if ( $navbox.hasClass( 'mw-collapsed' ) ) { return; }                   // add the collapsed class $navbox.addClass( 'mw-collapsed' ); // make sure we aren't selecting any nested navboxes $rows = $navbox.find( '> tbody > tr' ); $rows.each( function ( i ) {                       // first row is the header                        if ( i === 0 ) {                            return;                        }

$( this ).hide; } );                   // toggle is always in header                    $toggle = $rows.first.find( '.mw-collapsible-toggle' );                    // this class is required to make expand work properly                    $toggle.addClass( 'mw-collapsible-toggle-collapsed' );                    $toggle.children( 'a' ).text( expand );

}               // collapse if more than `maxShow` if ( $navbox.length > ( maxShow - 1 ) ) { $navbox.each( function {                        collapseNavbox( this );                    } ); }               // collapse if taller than `maxHeight` $navbox.each( function {                    if ( $( this ).height > maxHeight ) {                        collapseNavbox( this );                    }                } ); }       },

/**        * Lists namespace numbers at MediaWiki:Namespace numbers */       nsNumbers: { conditional: ( conf.wgPageName === 'MediaWiki:Namespace_numbers' ), scripts: 'MediaWiki:Common.js/namespaceNumbersList.js' },

/**        * Peng hunting highlight table */       pengLocations: { conditional: (               [ 'Distractions_and_Diversions_Locations', 'Distractions_and_Diversions_Locations/Penguin_Hide_and_Seek' ]                    .indexOf( conf.wgPageName ) > -1            ), scripts: 'MediaWiki:Common.js/pengLocations.js' },

/**        * Ratings sidebar module (oasis) */       ratings: { conditional: ( conf.skin === 'oasis' && conf.wgNamespaceNumber === 0 && conf.wgAction === 'view' ), scripts: 'MediaWiki:Wikia.js/ratings.js' },

/**        * Script for RuneScape:RC patrol */       rcPatrol: { conditional: ( conf.wgPageName === 'RuneScape:RC_Patrol' ), scripts: 'User:Suppa_chuppa/rcpatrol.js', styles: 'User:Suppa_chuppa/rcp.css' },

/**        * Custom osis sidebar module(s) */       sidebar: { conditional: ( conf.skin === 'oasis' && conf.wgAction === 'view' ), scripts: 'MediaWiki:Wikia.js/sidebar.js' },

/**        * Signature reminder on forum and talk pages */       sigReminder: { conditional: (               ['edit', 'submit'].indexOf( conf.wgAction ) > -1 &&                ( conf.wgNamespaceNumber % 2 === 1 || conf.wgNamespaceNumber === 110 )            ), exec: function { $( '#wpSave' ).on( 'click', function ( e ) {                   var text = $( '#wpTextbox1' ).val,                        reminder = 'It looks like you forgot to sign your comment. You can sign by placing 4 tildes (~) to the end of your message.\nAre you sure you want to post it?';                    if ( // don't trigger on minor edits $( '#wpMinoredit' ).prop( 'checked' ) ||

// check for signature text.replace( /( .*?<\/nowiki>)/g,  ).match(  ) ||

// check for &undo= or ?undo= in URL as summary can be altered // @todo Use mw.util.getParamValue here location.search.match( /[\?&]undo=/ ) ||

// check for user welcome notice in edit summary // since those often don't need signatures $( '#wpSummary' ).val.match( /welcome/i ) ) {                       return;                    }                    mw.log( 'sigreminder activated' );                    if ( !confirm( reminder ) ) {                        mw.log( 'prevent no sig' );                        e.preventDefault;                    }                } ); }       },

/**        * Redirects skin.js/css to correct skin name */       skinRedirect: { conditional: ( conf.wgUserName && conf.wgNamespaceNumber === 2 ), exec: function { // @todo this might need to be replaces with venus at some point var skinpage = '/' + conf.skin.replace( 'oasis', 'wikia' ) + '.', pagename = 'User:' + conf.wgUserName.replace( / /g, '_' ) + '/skin.'; switch ( conf.wgPageName ) { case pagename + 'js': location.replace(                           location.href.replace( /\/skin\.js/i, skinpage + 'js' )                        ); break;

case pagename + 'css': location.replace(                           location.href.replace( /\/skin\.css/i, skinpage + 'css' )                        ); break; }           }        },

/**        * Adds a report of special maintenance pages to         * Special:SpecialPages and RS:MAINTENANCE */       spReport: { conditional: (               $( '.specialMaintenance' ).length ||                conf.wgCanonicalSpecialPageName === 'Specialpages'            ), scripts: 'MediaWiki:Common.js/spreport.js' },

/**        * Script for */       switchInfobox: { conditional: $( '.switch-infobox' ).length, scripts: 'User:-Matt/SwitchInfobox.js' },

/**        * More calculators */       stewCalc: { conditional: $( '.jcInput, [class*="jcPane"], .skiplinkcontainer' ).length, scripts: 'User:Stewbasic/calc.js' },

/**        * Prevents uploading videos through youtube tags * by switching them to         */ tagSwitch: { conditional: ( ['edit', 'submit'].indexOf( conf.wgAction ) > -1 ), exec: function { $( '#wpSave' ).on( 'click', function {                    // Stop it changing the docs on here (monobook issue)                    if ( conf.skin === 'monobook' && /\.js$/.test( conf.wgTitle ) ) {                        return;                    }                    var wikitext = $( '#wpTextbox1' )                        .val                        // @todo can these be condensed down into a callback for .replace ?                        .replace( / /g, '{{youtube|' )                        .replace( //g, '{{youtube|height=$1|' )                       .replace( //g, '{{youtube|width=$1|' )                       .replace( //g, '{{youtube|height=$1|width=$2|' )                       .replace( //g, '{{youtube|height=$2|width=$1|' )                       .replace( /<\/youtube>/g, '}}' );                    $( '#wpTextbox1' ).val( wikitext );                } ); }       },

/**        * Moves topicons outside #mw-content-text to get around alignment issues *        * @notes Requires additional CSS in MediaWiki:Wikia.css * @todo Add a fade in animation to make loading smoother *        * @author The 888th Avatar (Avatar Wiki) * @author Cqm */       topIcon: { conditional: $( '.topright-icon' ).length, exec: function { // insert container into pageheader $( '#firstHeading, #WikiaPageHeader' ).append(                   $( ' ' ).attr( 'id', 'rs-header-icons' )                );

var $icons = $( '#rs-header-icons' ); $( '.topright-icon' ).each( function {                    $icons.append( $( this ).html );                } ); }       },

/**        * Adds an editintro when editing update pages */       updateIntro: { conditional: ( conf.wgNamespaceNumber === 100 ), scripts: 'MediaWiki:Common.js/updateintro.js' },

/**        * Adds a timer to Warbands */       warbandsTimer: { conditional: $( '#wb-timer' ).length, scripts: 'MediaWiki/Common.js/warbandstimer.js' },

/**        * Add edit links to Special:WhatLinksHere *        * @todo Move to gadget */       wlhEdit: { conditional: ( conf.wgCanonicalSpecialPageName === 'Whatlinkshere' ), scripts: 'MediaWiki:Common.js/WLH_edit.js' },

/**        * Youtube embedding */       youtube: { conditional: $( '.youtube' ).length, scripts: 'MediaWiki:Common.js/youtube.js' }   };

var scripts = [], styles = [], loaded = [], expose = {};

/**    * Used to detect incorrectly spelt keys for each include *    * @param obj {object} * @param key {string} */   function checkKeys( obj, key ) { var inclKeys = Object.keys( obj ), allowKeys = ['conditional', 'scripts', 'styles', 'expose', 'exec'];

allowKeys.forEach( function ( elem ) {           var index = inclKeys.indexOf( elem );

if ( index > -1 ) { inclKeys.splice( index, 1 ); }       } );

if ( inclKeys.length ) { console.warn( 'Error in MediaWiki:Common.js: `includes.' + key + '` contains unknown key(s): ' + inclKeys.toString ); }   }

function init { $.each( includes, function ( k, v ) {

var check = $.isFunction( v.conditional ) ? v.conditional : v.conditional;

if ( check ) {

// used for tracking which includes are loading loaded.push( 'common.' + k );

if ( v.scripts ) { scripts = scripts.concat( v.scripts ); }

if ( v.styles ) { styles = styles.concat( v.styles ); }

if ( v.exec ) { v.exec;

if ( v.expose ) { expose[k] = v.exec; }               }

}

checkKeys( v, k ); } );

$.extend( rs, util, expose ); rs.loaded = ( rs.loaded || [] ).concat( loaded );

// map globals from previous versions to new methods // @todo remove these at some point rs.common = {}; rs.reusable = {}; rs.common.autosort = rs.autosort; window.addCommas = rs.reusable.addCommas = util.addCommas; // everything below here is deprecated // keep these until everything sitewide has been moved over to new methods window.getCookie = rs.reusable.getCookie = util.getCookie; window.setCookie = rs.reusable.setCookie = util.setCookie; window.callAPI = rs.reusable.callAPI = util.callAPI; // load stylesheets before scripts importArticles( {           type: 'style',            articles: styles        }, {            type: 'script',            articles: scripts        } );

}

$( init );

}( this.jQuery, this.mediaWiki, this.rswiki = this.rswiki || {} ) );