MediaWiki:Common.js

/* Any JavaScript here will be loaded for all users on every page load. */ /** onload handlers ************ * Simple fix such that crashes in one handler don't prevent later handlers from running. * * Maintainer: User:Lupo */ if (typeof (onloadFuncts) != 'undefined') { // Enhanced version of jsMsg from wikibits.js. jsMsg can display only one message, subsequent // calls overwrite any previous message. This version appends new messages after already // existing ones. function jsMsgAppend (msg, className) {   var msg_div = document.getElementById ('mw-js-message'); var msg_log = document.getElementById ('mw-js-exception-log'); if (!msg_log) { msg_log = document.createElement ('ul'); msg_log.id = 'mw-js-exception-log'; if (msg_div && msg_div.firstChild) { // Copy contents of msg_div into first li of msg_log var wrapper = msg_div.cloneNode (true); wrapper.id = ""; wrapper.className = ""; var old_stuff = document.createElement ('li'); old_stuff.appendChild (wrapper); msg_log.appendChild (old_stuff); }   }    var new_item = document.createElement ('li'); new_item.appendChild (msg); msg_log.appendChild (new_item); jsMsg (msg_log, className); } var Logger = { // Log an exception. If present, try to use a JS console (e.g., Firebug's). If no console is   // present, or the user is a sysop, also put the error message onto the page itself. logException : function (ex) { try { var name = ex.name || ""; var msg = ex.message || ""; var file = ex.fileName || ex.sourceURL || null; // Gecko, Webkit, others var line = ex.lineNumber || ex.line || null;   // Gecko, Webkit, others var logged = false; if (typeof (console) != 'undefined' && typeof (console.log) != 'undefined') { // Firebug, Firebug Lite, or browser-native or other JS console present. At the very // least, these will allow us to print a simple string. var txt = name + ': ' + msg; if (file) { txt = txt + '; ' + file; if (line) txt = txt + ' (' + line + ')'; }         if (typeof (console.error) != 'undefined') { if (  console.firebug                || (   console.provider && console.provider.indexOf && console.provider.indexOf ('Firebug') >= 0)              ) {             console.error (txt + " %o", ex); // Use Firebug's object dump to write the exception } else { console.error (txt); }         } else console.log (txt); logged = true; }        if (!logged || wgUserGroups.join (' ').indexOf ('sysop') >= 0) { if (name.length == 0 && msg.length == 0 && !file) return; // Don't log if there's no info if (name.length == 0) name = 'Unknown error'; // Also put it onto the page for sysops. var log = document.createElement ('span'); if (msg.indexOf ('\n') >= 0) { var tmp = document.createElement ('span'); msg = msg.split ('\n'); for (var i = 0; i < msg.length; i++) { tmp.appendChild (document.createTextNode (msg[i])); if (i+1 < msg.length) tmp.appendChild (document.createElement ('br')); }           log.appendChild (document.createTextNode (name + ': ')); log.appendChild (tmp); } else { log.appendChild (document.createTextNode (name + ': ' + msg)); }         if (file) { log.appendChild (document.createElement ('br')); var a = document.createElement ('a'); a.href = file; a.appendChild (document.createTextNode (file)); log.appendChild (a); if (line) log.appendChild (document.createTextNode (' (' + line + ')')); }         jsMsgAppend (log, 'error'); }     } catch (anything) { // Swallow }   }  } // end Logger // Wrap a function with an exception handler and exception logging. function makeSafe (f) { return function { try { return f.apply (this, arguments); } catch (ex) { Logger.logException (ex); return null; }          };  }  // Wrap the already registered onload hooks for (var i = 0; i < onloadFuncts.length; i++) onloadFuncts[i] = makeSafe (onloadFuncts[i]); // Redefine addOnloadHook to catch future additions function addOnloadHook (hookFunct) { // Allows add-on scripts to add onload functions if (!doneOnloadHook) { onloadFuncts[onloadFuncts.length] = makeSafe (hookFunct); } else { makeSafe (hookFunct); // bug in MSIE script loading } } } // end onload hook improvements /** JSconfig ************ * Global configuration options to enable/disable and configure * specific script features from MediaWiki:Common.js and * MediaWiki:Monobook.js * This framework adds config options (saved as cookies) to Special:Preferences * For a more permanent change you can override the default settings in your * Special:Mypage/monobook.js * for Example: JSconfig.keys[loadAutoInformationTemplate] = false; * * Maintainer: User:Dschwen */ var JSconfig = { prefix : 'jsconfig_', keys : {}, meta : {}, // // Register a new configuration item // * name          : String, internal name // * default_value : String or Boolean (type determines configuration widget) // * description   : String, text appearing next to the widget in the preferences, or an hash-object //                   containing translations of the description indexed by the language code // * prefpage      : Integer (optional), section in the preferences to insert the widget: //                    0 : User profile         User profile //                    1 : Skin                 Appearance //                    2 : Math                 Date and Time //                    3 : Files                Editing //                    4 : Date and time        Recent Changes //                    5 : Editing              Watchlist //                    6 : Recent changes       Search Options //                    7 : Watchlist            Misc //                    8 : Search               Gadgets //                    9 : Misc // // Access keys through JSconfig.keys[name] // registerKey : function( name, default_value, description, prefpage ) { if( typeof JSconfig.keys[name] == 'undefined' ) JSconfig.keys[name] = default_value; else { // all cookies are read as strings, // convert to the type of the default value switch( typeof default_value ) {   case 'boolean' : JSconfig.keys[name] = ( JSconfig.keys[name] == 'true' ); break; case 'number' : JSconfig.keys[name] = JSconfig.keys[name]/1; break; } }  JSconfig.meta[name] = { 'description' : description[wgUserLanguage] || description.en || ( typeof(description) == "string" && description ) || "en translation missing", 'page' : prefpage || 0, 'default_value' : default_value }; // if called after setUpForm, we'll have to add an extra input field if( JSconfig.prefsTabs ) JSconfig.addPrefsInput( name ); }, readCookies : function { var cookies = document.cookie.split("; "); var p =JSconfig.prefix.length; var i; for( var key in cookies ) {  if( cookies[key].substring(0,p) == JSconfig.prefix ) {   i = cookies[key].indexOf('='); //alert( cookies[key] + ',' + key + ',' + cookies[key].substring(p,i) ); JSconfig.keys[cookies[key].substring(p,i)] = cookies[key].substring(i+1); } } }, writeCookies : function { var expdate = new Date; expdate.setTime(expdate.getTime+1000*60*60*24*3650); // expires in 3560 days for( var key in JSconfig.keys ) document.cookie = JSconfig.prefix + key + '=' + JSconfig.keys[key] + '; path=/; expires=' + expdate.toUTCString; }, evaluateForm : function { var w_ctrl,wt; //alert('about to save JSconfig'); for( var key in JSconfig.meta ) { w_ctrl = document.getElementById( JSconfig.prefix + key ) if( w_ctrl ) {   wt = typeof JSconfig.meta[key].default_value; switch( wt ) { case 'boolean' : JSconfig.keys[key] = w_ctrl.checked; break; case 'string' : JSconfig.keys[key] = w_ctrl.value; break; }  }  }  JSconfig.writeCookies; return true; }, prefsTabs : false, setUpForm : function {  var prefChild = document.getElementById('preferences'); if( !prefChild ) return; prefChild = prefChild.childNodes; // // make a list of all preferences sections // var tabs = new Array; var len = prefChild.length; for( var key = 0; key < len; key++ ) { if( prefChild[key].tagName &&      prefChild[key].tagName.toLowerCase == 'fieldset' ) tabs.push(prefChild[key]); } JSconfig.prefsTabs = tabs; // // Create Widgets for all registered config keys // for( var key in JSconfig.meta ) JSconfig.addPrefsInput(key); addEvent(document.getElementById('preferences').parentNode, 'submit', JSconfig.evaluateForm ); }, addPrefsInput : function( key ) { var w_div = document.createElement( 'DIV' ); var w_label = document.createElement( 'LABEL' ); var wt = typeof JSconfig.meta[key].default_value; switch ( wt ) { case 'boolean': JSconfig.meta[key].description = " " + JSconfig.meta[key].description; break; case 'string': default: JSconfig.meta[key].description += ": "; break; } w_label.appendChild( document.createTextNode( JSconfig.meta[key].description ) ); w_label.htmlFor = JSconfig.prefix + key; var w_ctrl = document.createElement( 'INPUT' ); w_ctrl.id = JSconfig.prefix + key; // before insertion into the DOM tree switch( wt ) { case 'boolean': w_ctrl.type = 'checkbox'; w_div.appendChild( w_ctrl ); w_div.appendChild( w_label ); break; case 'string': default: w_ctrl.type = 'text'; w_div.appendChild( w_label ); w_div.appendChild( w_ctrl ); break; } JSconfig.prefsTabs[JSconfig.meta[key].page].appendChild( w_div ); // after insertion into the DOM tree switch( wt ) { case 'boolean' : w_ctrl.defaultChecked = w_ctrl.checked = JSconfig.keys[key]; break; case 'string' : w_ctrl.defaultValue = w_ctrl.value = JSconfig.keys[key]; break; } } }; JSconfig.readCookies; if( wgNamespaceNumber == -1 && wgCanonicalSpecialPageName == "Preferences" ) addOnloadHook(JSconfig.setUpForm); /** extract a URL parameter from the current URL ********** * From en:User:Lupin/autoedit.js * * paramName : the name of the parameter to extract * url       : optional URL to extract the parameter from, document.location.href if not given. * * Local Maintainer: User:Dschwen, User:Lupo */ function getParamValue( 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 on the MediaWiki namespace without * editing Special:Mypage/monobook.js * * Maintainer: User:Platonides, User:Lupo */ var extraJS = getParamValue("withJS"); // Leave here for backwards compatibility (function (extraJS) { if (!extraJS) return; if (extraJS.match("^MediaWiki:[^&<>=%#]*\\.js$")) // Disallow some characters in file name importScript (extraJS); else {  // Dont use alert but the jsMsg system. Run jsMsg only once the DOM is ready.  addOnloadHook (function  { jsMsgAppend (document.createTextNode (extraJS + " javascript not allowed to be loaded."),'error'); }); } })(extraJS); /** Attach (or remove) an Event to a specific object ********** * Cross-browser event attachment (John Resig) * http://www.quirksmode.org/blog/archives/2005/10/_and_the_winner_1.html * * obj : DOM tree object to attach the event to * type : String, event type ("click", "mouseover", "submit", etc.) * fn  : Function to be called when the event is triggered (the this *        keyword points to obj inside fn when the event is triggered) * * Local Maintainer: User:Dschwen */ function addEvent( obj, type, fn ) { if (obj.addEventListener) obj.addEventListener( type, fn, false ); else if (obj.attachEvent) { obj["e"+type+fn] = fn; obj[type+fn] = function { obj["e"+type+fn]( window.event ); } obj.attachEvent( "on"+type, obj[type+fn] ); } } function removeEvent( obj, type, fn ) { if (obj.removeEventListener) obj.removeEventListener( type, fn, false ); else if (obj.detachEvent) { obj.detachEvent( "on"+type, obj[type+fn] ); obj[type+fn] = null; obj["e"+type+fn] = null; } } /** Extra toolbar options *********** * Append custom buttons to the edit mode toolbar. * This is a modified copy of a script by User:MarkS for extra features added by User:Voice of All. * This is based on the original code on Wikipedia:Tools/Editing tools * To disable this script, add mwCustomEditButtons = []; to Special:Mypage/monobook.js *  *  Maintainers: User:MarkS?, User:Voice of All, User:R. Koot */ if (mwCustomEditButtons) { mwCustomEditButtons.push({   "imageFile": "/skins/common/images/button_redirect.png",    "speedTip": "Redirect",    "tagOpen": "#REDIRECT ",    "tagClose": "",    "sampleText": "Insert text"  }); mwCustomEditButtons.push({   "imageFile": "/skins/common/images/button_strike.png",    "speedTip": "Strike",    "tagOpen": " ",    "tagClose": " ",    "sampleText": "Strikethrough"  }); } /***** Edittools ******** * Formatting buttons for special characters below the edit field * Also enables these buttons on any textarea or input field on * the page. Moved here from Monobook.js on 2009-09-09. * * Maintainers: User:Lupo */ var load_edittools = true; // Legacy... importScript('MediaWiki:Edittools.js');

// // Collapsible tables // importScript('MediaWiki:CollapsibleTables.js');

/**** Special:Upload enhancements ****** * moved to MediaWiki:Upload.js * *  Maintainer: User:Lupo ****/ JSconfig.registerKey('UploadForm_loadform', true, {  'bg': 'Използване на логиката на новия формуляр за качвания',  'en': 'Use new upload form logic', // default  'ru': 'Использовать новую логику формы загрузки' }, 3); JSconfig.registerKey('UploadForm_newlayout', true, {  'bg': 'Използване на облика на новия формуляр за качвания',  'en': 'Use new form layout', // default  'ru': 'Использовать новый интерфейс формы загрузки' }, 3);

function enableNewUploadForm { var match = navigator.userAgent.match(/AppleWebKit\/(\d+)/); if (match) { var webKitVersion = parseInt(match[1]); if (webKitVersion < 420) return; // Safari 2 crashes hard with the new upload form... }

// honor JSConfig user settings if( !JSconfig.keys['UploadForm_loadform'] ) return;

importScript( 'MediaWiki:UploadForm.js' ); }

if (wgPageName == 'Special:Upload') { importScript( 'MediaWiki:Upload.js' ); // Uncomment the following line (the call to enableNewUploadForm) to globally enable the // new upload form. Leave the line *above* (the include of MediaWiki:Upload.js) untouched; // that script provides useful default behavior if the new upload form is disabled or // redirects to the old form in case an error occurs. enableNewUploadForm ; }

/***** subPagesLink ******** * Adds a link to subpages of current page * * Maintainers: he:משתמש:ערן, User:Dschwen * * JSconfig items: bool JSconfig.subPagesLink *                      (true=enabled (default), false=disabled) ****/ var subPagesLink = { // // Translations of the menu item // i18n : { 'bg': 'Подстраници', 'ca': 'Subpàgines', 'cs': 'Podstránky', 'de': 'Unterseiten', 'en': 'Subpages',   // default 'et': 'Alamlehed', 'eo': 'Subpaĝoj', 'eu': 'Azpiorrialdeak', 'es': 'Subpáginas', 'fi': 'Alasivut', 'fr': 'Sous-pages', 'gl': 'Subpáxinas', 'he': 'דפי משנה', 'hr': 'Podstranice', 'it': 'Sottopagine', 'is': 'Undirsíður', 'ko': '하위 문서 목록', 'nl': "Subpagina's", 'no': 'Undersider', 'pl': 'Podstrony', 'ru': 'Подстраницы' }, install: function { // honor user configuration if( !JSconfig.keys['subPagesLink'] ) return; if ( document.getElementById("t-whatlinkshere")       &&  wgNamespaceNumber != -2   // Media: (upcoming)       &&  wgNamespaceNumber != -1   // Special:       && wgNamespaceNumber != 6     // Image:       &&  wgNamespaceNumber != 14   // Category:     ) {  var subpagesText = subPagesLink.i18n[wgUserLanguage] || subPagesLink.i18n['en']; var subpagesLink = wgArticlePath.replace('$1','Special:Prefixindex/' + wgPageName +'/'); addPortletLink( 'p-tb', subpagesLink, subpagesText, 't-subpages' ); } } } JSconfig.registerKey('subPagesLink', true, {  'bg': 'Показване на връзката Подстраници в менюто с инструменти',  'cs': 'Zobrazovat v panelu nástrojů odkaz Podstránky',  'en': 'Show a Subpages link in the toolbox', // default  'pl': 'Pokaż w panelu bocznym link do podstron',  'ru': 'Показывать ссылку на подстраницы в меню инструментов' }, 7); addOnloadHook(subPagesLink.install);

function WEAddStyles(a) { var ss = document.createElement('style'); ss.type = 'text/css'; ss.media = 'screen'; ss.title = 'WE'; if (ss.stylesheet) ss.stylesheet.cssText = a; //IE else ss.appendChild(document.createTextNode(a)); document.getElementsByTagName('head')[0].appendChild(ss); }

addOnloadHook(function { /* hide some navigation and other unnecessary elements if displayed in an iFrame */  if (window.self != window.top) {    var content = document.getElementById('content');    if (content) {      content.style.margin = 0;      content.style.borderStyle = 'none';    }    var removals = ['column-one', 'siteNotice', 'contentSub', 'siteSub', 'catlinks', 'page-base', 'head-base', 'head', 'panel', 'footer-info-lastmod', 'footer-info-viewcount', 'footer-places', 'footer-icon-poweredby', 'f-poweredbyico', 'lastmod', 'viewcount', 'privacy', 'about', 'disclaimer'];    for (var i=0; i<removals.length; i++) {      var g = document.getElementById(removals[i])      if (g) {        g.style.display = 'none';      }    }    $('.editsection').css('visibility', 'hidden');    document.body.style.background='none';    var divs = document.getElementsByTagName('div');    for (i=0; i' + g + ''; li.style.display = 'block'; foot.insertBefore(li, document.getElementById('copyright') || document.getElementById('footer-info-copyright')); }   var q = {}; var qs = document.location.search; qs = qs.substring(1).toLowerCase.split('&'); for (i=0; i<qs.length; i++) { g = qs[i].split('='); if (g[0] == 'links') { var largs = g[1].split('|'); for (var j=0; j<largs.length; j++) { q[largs[j]] = true; }       var hilight = q.highlight ? ' background: yellow;' : ''; var hover = q.hover ? ' background: yellow;' : ''; if (q.none || q.highlight || q.hover) { WEAddStyles('a.link {text-decoration: none; padding: 0px; background: none; ' + hilight + '} a.visited {text-decoration: none;' + hilight +'} a:active {text-decoration: none;' + hilight + '} a:hover {text-decoration: none;' + hilight + hover + '}'); }       var as = document.getElementsByTagName('a'); for (j=0; j<as.length; j++) { var href = as[j].getAttribute('href'); if (href) { if (q.none || q.show || q.hover || q.highlight) { as[j].setAttribute('onclick', 'return false;'); }           if (q.window) { as[j].setAttribute('target', '_WE'); }         }        }      } else if ((g[0] == 'editable') && ((g[1] == '1') || (g[1].toLowerCase == 'yes') || (g[1].toLowerCase == 'true'))) { $('.editsection').css('visibility', 'visible'); }   }    // if postMessage is supported, try to let the parent know our size if (parent.postMessage) { var ht = content.offsetHeight; var ftr = document.getElementById('footer'); if (ftr) { ht = ht + ftr.offsetHeight; } var loc = document.location.href; parent.postMessage(ht + '^' + loc, "*"); } } });

/* add Links button with permanent link, short link, and iframe snippets for each * 2010-12-21 http://WikiEducator.org/User:JimTittsler * short links derived from commons:Bugzilla:021572 -- commons:meta:user:Platonides */ function weSelectMe(node) { var selection, range, doc, win; if ((doc = node.ownerDocument) && (win=doc.defaultView) && typeof win.getSelection != 'undefined' && typeof doc.createRange != 'undefined' && (selection = window.getSelection) && typeof selection.removeAllRanges != 'undefined') { range = doc.createRange; range.selectNode(node); selection.removeAllRanges; selection.addRange(range); } else if (document.body && typeof document.body.createTextRange != 'undefined' && (range = document.body.createTextRange)) { /* IE */ range.moveToElementText(node); range.select; } }

addOnloadHook( function { var plink = document.getElementById("t-permalink");  if (wgArticleId && plink) {    var permanent_link = wgScript + '?oldid=' + wgCurRevisionId;    var short_url = wgScript + '?curid=' + wgArticleId;    plink.innerHTML = ['Links'     , ''      , 'Permanent Link'      , 'IFrame snippet to this revision: '      , '&lt;iframe src="' + wgServer + permanent_link + '" width="100%" height="300"&gt;WikiEducator &lt;/iframe&gt; ' , 'Short URL' , 'IFrame snippet to this page: ' , '<span id="we_page_iframe" onClick="weSelectMe(this);">&lt;iframe src="' + wgServer + short_url + '" width="100%" height="300"&gt;WikiEducator &lt;/iframe&gt; </li>' , '</ul>' ].join(''); } } );

// BEGIN Dynamic Navigation Bars // NEEDS Enable multiple onload functions // set up the words in your language var NavigationBarHide = 'Collapse'; var NavigationBarShow = 'Expand'; // set up max count of Navigation Bars on page, // if there are more, all will be hidden // NavigationBarShowDefault = 0; // all bars will be hidden // NavigationBarShowDefault = 1; // on pages with more than 1 bar all bars will be hidden var NavigationBarShowDefault = 0; // shows and hides content and picture (if available) of navigation bars // Parameters: //    indexNavigationBar: the index of navigation bar to be toggled function toggleNavigationBar(indexNavigationBar) {   var NavToggle = document.getElementById("NavToggle" + indexNavigationBar); var NavFrame = document.getElementById("NavFrame" + indexNavigationBar); if (!NavFrame || !NavToggle) { return false; }   // if shown now if (NavToggle.firstChild.data == NavigationBarHide) { for (               var NavChild = NavFrame.firstChild;                NavChild != null;                NavChild = NavChild.nextSibling            ) { if (NavChild.className == 'NavPic') { NavChild.style.display = 'none'; }           if (NavChild.className == 'NavContent') { NavChild.style.display = 'none'; }           if (NavChild.className == 'NavToggle') { NavChild.firstChild.data = NavigationBarShow; }       }    // if hidden now } else if (NavToggle.firstChild.data == NavigationBarShow) { for (               var NavChild = NavFrame.firstChild;                NavChild != null;                NavChild = NavChild.nextSibling            ) { if (NavChild.className == 'NavPic') { NavChild.style.display = 'block'; }           if (NavChild.className == 'NavContent') { NavChild.style.display = 'block'; }           if (NavChild.className == 'NavToggle') { NavChild.firstChild.data = NavigationBarHide; }       }    } } // adds show/hide-button to navigation bars function createNavigationBarToggleButton {   var indexNavigationBar = 0; // iterate over all -elements for(           var i=0;             NavFrame = document.getElementsByTagName("div")[i];             i++        ) { // if found a navigation bar if (NavFrame.className == "NavFrame") { indexNavigationBar++; var NavToggle = document.createElement("a"); NavToggle.className = 'NavToggle'; NavToggle.setAttribute('id', 'NavToggle' + indexNavigationBar); NavToggle.setAttribute('href', 'javascript:toggleNavigationBar(' + indexNavigationBar + ');'); var NavToggleText = document.createTextNode(NavigationBarHide); NavToggle.appendChild(NavToggleText); // add NavToggle-Button as first div-element // in            NavFrame.insertBefore(                NavToggle,                NavFrame.firstChild            ); NavFrame.setAttribute('id', 'NavFrame' + indexNavigationBar); }   }    // if more Navigation Bars found than Default: hide all if (NavigationBarShowDefault < indexNavigationBar) { for(               var i=1;                 i<=indexNavigationBar;                 i++        ) { toggleNavigationBar(i); }   } } addOnloadHook(createNavigationBarToggleButton);