Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
/** <nowiki> <---- Please leave this alone
 * This Javascript file is automatically loaded for all users on
 * this wiki. Please make sure you have done sufficient testing
 * in your own user Javascript namespace (Special:MyPage/skin.js/
 * Special:MyPage/common.js).
 *
 * Please try to keep additions to this file at a minimum, and if
 * possible, add those code snippets as a gadget. Gadgets are
 * optimized to use ResourceLoader modules, and can be enabled by
 * default for all users.
 *
 * Please also remember to add sufficient code comments to explain
 * what you are doing for others. Also, use tabs and not spaces,
 * and follow the coding conventions of MediaWiki as well.
 */

/* DOM abbreviation function */
function newNode(tagname) {
	var node = document.createElement( tagname );

	for ( var i=1; i<arguments.length; i++ ) {

		if ( typeof arguments[i] == 'string' ) {
			// Text
			node.appendChild( document.createTextNode( arguments[i] ) );

		} else if ( typeof arguments[i] == 'object' ) { 
			if ( arguments[i].nodeName ) {
				// If it is a DOM Node
				node.appendChild( arguments[i] );

			} else {
				// Attributes (hopefully)
				for ( var j in arguments[i] ) {
					if ( j == 'class' ) {
						// Classname different because...
						node.className = arguments[i][j];

					} else if ( j == 'style' ) {
						// Style is special
						node.style.cssText = arguments[i][j];

					} else if ( typeof arguments[i][j] == 'function' ) {
						// Basic event handlers
						try {
							// W3C
							node.addEventListener(j,arguments[i][j],false);
						} catch (e) {
							try {
								// MSIE
								node.attachEvent( 'on'+j, arguments[i][j], "Language" );
							} catch (e) {
								// Legacy
								node['on'+j]=arguments[i][j];
							}
						}
					} else {
						// Normal attributes
						node.setAttribute( j,arguments[i][j] );
					}
				}
			}
		}
	}
	return node;
}
/*** END of DOM abbreviation function ***/

/* getCookies, setCookies */
// Note: This is deprecated and replaced by jQuery.cookie,
// but it is here for backward compatibility
/* @deprecated: Use $.cookie instead */
function setCookie(cookieName, cookieValue) {
	if (window.console) {
		console.warn("deprecated function setCookie called; use jQuery.cookie instead");
	}
	var today = new Date();
	var expire = new Date();
	var nDays = 30;
	expire.setTime( today.getTime() + (3600000 * 24 * nDays) );
	document.cookie = cookieName + "=" + escape(cookieValue) + ";path=/" + ";expires="+expire.toGMTString();
	// We need to delete the more specific paths for the next while. Safe to remove this by July 2011, if not before.
	document.cookie = cookieName + "=" + ";path=/w" + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
	document.cookie = cookieName + "=" + ";path=/wiki" + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
}

function getCookie(cookieName) {
	if (window.console) {
		console.warn("deprecated function getCookie called; use jQuery.cookie instead");
	}
	var start = document.cookie.indexOf( cookieName + "=" );
	if ( start == -1 ) return "";
	var len = start + cookieName.length + 1;
	if ( ( !start ) && ( cookieName != document.cookie.substring( 0, cookieName.length ) ) ) {
		return "";
	}
	var end = document.cookie.indexOf( ";", len );
	if ( end == -1 ) end = document.cookie.length;
	return unescape( document.cookie.substring( len, end ) );
}

function deleteCookie(cookieName) {
	if ( getCookie(cookieName) ) {
		document.cookie = cookieName + "=" + ";path=/" + ";expires=Thu, 01-Jan-1970 00:00:01 GMT";
	}
}

/* Dynamic Navigation Bars */
var NavigationBarHide = 'hide ▲';
var NavigationBarShow = 'show ▼';

// 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
NavigationBarShowDefault = 0;

/* NavigationBar::toggleNavigationBar */

// 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.isHidden == false ) {
		for ( var NavChild = NavFrame.firstChild; NavChild; NavChild = NavChild.nextSibling ) {
			if ( NavChild.className == 'NavPic' ) {
				NavChild.style.display = 'none';
			} else if ( NavChild.className == 'NavContent' ) {
				NavChild.style.display = 'none';
			}
		}
		NavToggle.childNodes[1].firstChild.nodeValue = NavigationBarShow;
		NavToggle.isHidden = true;

	// if hidden now
	} else if ( NavToggle.isHidden == true ) {
		for ( var NavChild = NavFrame.firstChild; NavChild; NavChild = NavChild.nextSibling ) {
			if ( NavChild.className == 'NavPic' ) {
				NavChild.style.display = 'block';
			} else if ( NavChild.className == 'NavContent' ) {
				NavChild.style.display = 'block';
			}
		}
		NavToggle.childNodes[1].firstChild.nodeValue = NavigationBarHide;
		NavToggle.isHidden = false;
	}
}

/* NavigationBar::createNavigationBarToggleButton */

var wgNavBarArray = [];

// adds show/hide-button to navigation bars
function createNavigationBarToggleButton() {
	// Are we previewing an translation section?
	var preview = document.getElementById( 'wikiPreview' );

	if ( preview != null ) {
		var p = preview.getElementsByTagName('p');
		if ( p != null && p.length >= 2 && p[1].firstChild.id == 'Translations' ) {
			NavigationBarShowDefault = 999;
		}
	}

	var indexNavigationBar = 0;

	// iterate over all < div >-elements
	for ( var i=0; NavFrame = document.getElementsByTagName("div")[i]; i++ ) {
		// if found a navigation bar
		// (Note that a navigation bar is a div whose *sole* class is
		// "NavFrame". That might not be the best approach, but currently
		// {{trans-see}} exploits it, so be cautious in changing that.)
		if ( NavFrame.className == "NavFrame" ) {
			indexNavigationBar++;
			var NavToggle = document.createElement("span");
			NavToggle.className = 'NavToggle';
			NavToggle.setAttribute( 'id', 'NavToggle' + indexNavigationBar );

			NavToggle.appendChild( document.createTextNode('[') );
			NavToggle.appendChild( document.createElement("a") );
			var NavToggleText = document.createTextNode( NavigationBarHide );
			// These need an href, but must do nothing
			NavToggle.childNodes[1].setAttribute( 'href', 'javascript:(function(){})()' );
			NavToggle.childNodes[1].appendChild( NavToggleText );
			NavToggle.appendChild(document.createTextNode(']'));
			NavToggle.isHidden = false;

			wgNavBarArray[indexNavigationBar - 1] = NavToggle;

			// 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 ( NavFrame.childNodes[j].className == "NavHead" ) {
					var NavHead = NavFrame.childNodes[j];
					for ( var k=0; k < NavHead.childNodes.length; k++ ) {
						if (NavHead.childNodes[k].nodeType == 1) { 
							NavHead.childNodes[k].onclick = function (e) {
								if (e) {
									e.stopPropagation ()
								} else {
									window.event.cancelBubble = true;
								}
							}
						}
					}
					NavHead.style.cursor = "pointer";
					NavHead.onclick = ( function (i) { return function () { toggleNavigationBar(i); } } )( indexNavigationBar )
					if ( NavHead.childNodes[0] ) {
						NavHead.insertBefore(NavToggle,NavHead.childNodes[0]);
					} else {
						NavHead.appendChild(NavToggle);
					}
				}
			}
			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);
		}
	}
}

$( createNavigationBarToggleButton );
/*** END of Dynamic Navigation Bars ***/

/**
 * jQuery UI on-demand loader
 * Loads jQuery UI modules on demand and allows users making use of
 * (some) of the awesome jQuery UI widgets (such as in Template:Clickable button)
 * 
 * Note: This code is from Commons' MediaWiki:Common.js
 */
mw.hook( 'wikipage.content' ).add( function($c) {
	var $accordion = $( '.accordion', $c ),
		$button = $( '.ui-button', $c );

	if ( $accordion.length ) {
		mw.loader.using( 'jquery.ui', function () {
			$accordion.accordion( { autoHeight: false } );
		} );
	}
	if ( $button.length ) {
		mw.loader.load( 'jquery.ui' );
	}
} );
/*** END of jQuery UI on-demand loader ***/

/*******************************************************************************
* Visibility Toggling                                                          *
*                                                                              *
* Often, you want certain content to be hidden by default, with a link to show *
* or re-hide it (i.e., to toggle its visibility). This bit of code provides    *
* infrastructure to help you do that in a consistent way. The idea is that     *
* there are certain "categories" of hidden content: "synonyms", for example.   *
* So, in addition to letting users toggle the visibility of a *specific* bit   *
* of content, we also want them to be able to toggle the visibility of an      *
* entire *category* of content. And we want this to be "sticky": if the user   *
* desides to show all synonyms, then that should be stored in a cookie, so     *
* that synonyms *stay* shown. This bit of code handles all that.               *
*                                                                              *
* Still, you have to handle a lot yourself:                                    *
*                                                                              *
*  - You have to write the code that finds all the hideable bits of content.   *
*  - For each hideable bit of content, you have to create a show/hide link.    *
*    (But this part is pretty easy. The hardest part is putting the link in    *
*    the right place.)                                                         *
*  - For a given hideable bit of content, you have to write a function to hide *
*    it and a function to show it. (These functions should also set the text   *
*    of the show/hide link.)                                                   *
*                                                                              *
* Once you've done that, you just find all the hideable bits of content; for   *
* each one, you create a show/hide link, and you call                          *
*                                                                              *
*   VisibilityToggles.register(category, show_function, hide_function)         *
*                                                                              *
* and set the show/hide link's "onClick" attribute to whatever that returns.   *
*******************************************************************************/
 
var VisibilityToggles = {
	// toggles[category] = [[show, hide],...]; statuses[category] = [true, false,...]; buttons = <li>
	toggles: {}, statuses: {}, buttons: null,

	// Add a new toggle, adds a Show/Hide category button in the toolbar,
	// and will call show_function and hide_function once on register, and every alternate click.
	register: function (category, show_function, hide_function) {

		var id = 0;
		if (!this.toggles[category]) {
			this.toggles[category] = [];
			this.statuses[category] = [];
		} else {
			id = this.toggles[category].length;
		}
		this.toggles[category].push([show_function, hide_function]);
		this.statuses[category].push(this.currentStatus(category));
		this.addGlobalToggle(category);

		(this.statuses[category][id] ? show_function : hide_function)();

		return function () {
			var statuses = VisibilityToggles.statuses[category];
			statuses[id] = !statuses[id]
			VisibilityToggles.checkGlobalToggle(category);
			return (statuses[id] ? show_function : hide_function)();
		}

	},

	// Add a new global toggle to the side bar
	addGlobalToggle: function(category) {
		if (document.getElementById('p-visibility-'+category))
			return;
		if (!this.buttons) {
			this.buttons = newNode('ul');
			var collapsed = $.cookie("vector-nav-p-visibility") == "false", toolbox = newNode('div', {'class': "portal portlet "+(collapsed?"collapsed":"expanded"), 'id': 'p-visibility'},
							newNode('h3', 'Visibility'),
							newNode('div', {'class': "pBody body"}, collapsed?undefined:{'style':'display:block;'}, this.buttons)
						  );
			var sidebar = document.getElementById('mw-panel') || document.getElementById('column-one');
			var insert = null;
			if (insert = (document.getElementById('p-lang') || document.getElementById('p-feedback')))
				sidebar.insertBefore(toolbox, insert);
			else
				sidebar.appendChild(toolbox);

		}
		var status = this.currentStatus(category);
		var newToggle = newNode('li', newNode('a', {
			id: 'p-visibility-' + category, 
			style: 'cursor: pointer',
			href: '#visibility-' + category,
			click: function(e)
			{
				VisibilityToggles.toggleGlobal(category); 
				if (e && e.preventDefault)
					e.preventDefault();
				else 
					window.event.returnValue = false;
				return false; 
			}},
			(status ? 'Hide ' : 'Show ') + category));
		for (var i=0; i < this.buttons.childNodes.length; i++) {
			if (this.buttons.childNodes[i].id < newToggle.id) {
				this.buttons.insertBefore(newToggle, this.buttons.childNodes[i]);
				return;
			}
		}
		this.buttons.appendChild(newToggle);
	},

	// Update the toggle-all buttons when all things are toggled one way
	checkGlobalToggle: function(category) {
		var statuses = this.statuses[category];
		var status = statuses[0];
		for (var i = 1; i < statuses.length; i++) {
			if (status != statuses[i])
				return;
		}
		document.getElementById('p-visibility-' + category).innerHTML = (status ? 'Hide ' : 'Show ') + category;
	},

	// Toggle all un-toggled elements when the global button is clicked
	toggleGlobal: function(category) {
		var status = document.getElementById('p-visibility-' + category).innerHTML.indexOf('Show ') == 0;
		for (var i = 0; i < this.toggles[category].length; i++ ) {
			if (this.statuses[category][i] != status) {
				this.toggles[category][i][status ? 0 : 1]();
				this.statuses[category][i] = status;
			}
		}
		document.getElementById('p-visibility-' + category).innerHTML = (status ? 'Hide ' : 'Show ') + category;
		var current = getCookie('Visibility');
		if (!current)
			current = ";";
		current = current.replace(';' + category + ';', ';');
		if (status)
			current = current + category + ";";
		setCookie('Visibility', current);
	},

	currentStatus: function(category) {
		if (window.location.hash.toLowerCase().split('_')[0] == '#' + category.toLowerCase())
			return true;
		if (window.location.href.search(/[?](.*&)?hidecats=/) > 0)
		{
			var hidecats = window.location.href;
			hidecats = hidecats.replace(/^[^?]+[?]((?!hidecats=)[^&]*&)*hidecats=/, '');
			hidecats = hidecats.replace(/&.*/, '');
			hidecats = hidecats.split(',');
			for (var i = 0; i < hidecats.length; ++i)
				if (hidecats[i] == category || hidecats[i] == 'all')
					return false;
				else if (hidecats[i] == '!' + category || hidecats[i] == 'none')
					return true;
		}
		if (getCookie('WiktionaryPreferencesShowNav') == 'true')
			return true;
		if (getCookie('Visibility').indexOf(';' + category + ';') >= 0)
			return true;
		// TODO check category-specific cookies
		return false;
	}
};
 
 
 
/*******************************************************************************
* Hidden 'Onyms                                                                *
*                                                                              *
* This bit of code allows 'onyms (synonyms or antonyms or whatnot) to be       *
* hidden (collapsed) by default. For each hidden group of 'onyms, there will   *
* be a link to show it (which, once clicked, becomes a link to re-hide it).    *
*                                                                              *
* This code makes use of the "Visibility Toggling" infrastructure (see above), *
* so it creates toolbar-links and cookies and whatnot as appropriate. It uses  *
* separate categories for different types of 'onyms; for example, all synonyms *
* can be shown or hidden at once.                                              *
*                                                                              *
* To use it, create a template on the model of {{synonyms}} (q.v.). The        *
* category is controlled by the class-name of the <ul> element (for example,   *
* class="onyms-collapse onyms-collapse-synonyms" assigns the list to the       *
* "synonyms" category in the toolbar), and the text of the show/hide link is   *
* controlled by the bold text at the head of the first <li> element.           *
*******************************************************************************/
 
function setupHiddenOnyms(onyms)
{
   var li = onyms.parentNode;
   var endOfLine = li.firstChild;
   while(true)
   {
      if(endOfLine == null) // should never happen
         break;
      if(endOfLine.nodeName.search(/^(dl|ul|ol|menu)$/i) > -1)
         break;
      endOfLine = endOfLine.nextSibling;
   }
 
   var HQToggle = newNode('a', {href: 'javascript:(function(){})()'}, '');
   var toggleLink = newNode('span', {'class': 'HQToggle', 'style': 'font-size:0.65em'}, ' [', HQToggle, ']');
   if(endOfLine == null) // should never happen
      li.appendChild(toggleLink);
   else
      li.insertBefore(toggleLink, endOfLine);
 
   var category = onyms.className.match(/(^| )onyms-collapse-([^ ]+)/)[2];
   var text = onyms.getElementsByTagName('b')[0].innerHTML.replace(/:/g, '').toLowerCase();
 
   HQToggle.onclick =
   (
      VisibilityToggles.register
      (
         category,
         function show()
         {
            HQToggle.innerHTML = text + ' ▲';
            onyms.style.display = '';
         },
         function hide()
         {
            HQToggle.innerHTML = text + ' ▼';
            onyms.style.display = 'none';
         }
      )
   );
}
 
function initHiddenOnyms() {
	var ols = document.getElementsByTagName('ol');
	for(var i = 0; i < ols.length; ++i) {
		for(var li = ols[i].firstChild; li !== null; li = li.nextSibling) {
			if(li.nodeName.toUpperCase() != 'LI') {
				continue;
			}
			var uls = li.getElementsByTagName('ul');
			for(var j = 0; j < uls.length; ++j) {
				if(uls[j].parentNode == li && $(uls[j]).hasClass('onyms-collapse')) {
					setupHiddenOnyms(uls[j]);
				}
			}
		}
	}
}
$(document).ready(initHiddenOnyms);
/*** NOTHING BELOW THIS LINE </nowiki> ***/