Difference between revisions of "MediaWiki:Common.js"

From Diversifying Economic Quality: A Wiki for Instructors and Departments

Jump to: navigation, search
Line 255: Line 255:
 
  * @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
 
  * @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
 
  * @license GPL2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
 
  * @license GPL2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
  */
+
   
 
( function( $, mw ) {
 
( function( $, mw ) {
 
   
 
   
Line 578: Line 578:
 
  $('.mw-collapsible').makeCollapsible();
 
  $('.mw-collapsible').makeCollapsible();
 
});
 
});
 +
*/

Revision as of 10:18, 10 September 2012

/* Any JavaScript here will be loaded for all users on every page load. */

// Add "mainpage" class to the body element
if ( wgMainPageTitle === wgPageName && wgAction === 'view' ) {
	$(document).ready(function() {
		document.body.className += ' mainpage';
	});
}
 
// switches for scripts
// TODO: migrate to JSConfig
// var load_extratabs = true;
var load_edittools = true;
 
// extra drop down menu on editing for adding special characters
importScript( 'MediaWiki:Edittools.js' );
 
// Editpage scripts
if( wgAction == 'edit' || wgAction == 'submit' ) {
	importScript( 'MediaWiki:Editpage.js' );
}
 
/* End of extra pages */
 
/* Test if an element has a certain class **************************************
 *
 * From English Wikipedia, 2008-09-15
 *
 * Description: Uses regular expressions and caching for better performance.
 * Maintainers: [[User:Mike Dillon]], [[User:R. Koot]], [[User:SG]]
 */
var hasClass = (function() {
	var reCache = {};
	return function( element, className ) {
		return ( reCache[className] ? reCache[className] : ( reCache[className] = new RegExp( "(?:\\s|^)" + className + "(?:\\s|$)" ) ) ).test( element.className );
	};
})();
 
/* Included below
  *mw.loader.load( 'http://www.mediawiki.org/w/index.php?title=MediaWiki:JQuery-makeCollapsible.js&action=raw&ctype=text/javascript' );
 */

/** Collapsible tables *********************************************************
 *
 * From English Wikipedia, 2008-09-15
 * @deprecated: Do not use this in new constructions, use class="mw-collapsible" instead
 *
 *  Description: Allows tables to be collapsed, showing only the header.
 *               See [[Wikipedia:NavFrame]].
 *  Maintainers: [[User:R. Koot]]
 */
var autoCollapse = 2;
var collapseCaption = 'see&nbsp;less';
var expandCaption = 'see&nbsp;more';
 
function collapseTable( tableIndex ) {
	var Button = document.getElementById( 'collapseButton' + tableIndex );
	var Table = document.getElementById( 'collapsibleTable' + tableIndex );
 
	if ( !Table || !Button ) {
		return false;
	}
 
	var Rows = Table.rows;
 
	if ( Button.firstChild.data == collapseCaption ) {
		for ( var i = 1; i < Rows.length; i++ ) {
			Rows[i].style.display = 'none';
		}
		Button.firstChild.data = expandCaption;
	} else {
		for ( var i = 1; i < Rows.length; i++ ) {
			Rows[i].style.display = Rows[0].style.display;
		}
		Button.firstChild.data = collapseCaption;
	}
}
 
function createCollapseButtons(){
	var tableIndex = 0;
	var NavigationBoxes = new Object();
	var Tables = document.getElementsByTagName( 'table' );
 
	for ( var i = 0; i < Tables.length; i++ ) {
		if ( hasClass( Tables[i], 'collapsible' ) ) {
			/* only add button and increment count if there is a header row to work with */
			var HeaderRow = Tables[i].getElementsByTagName( 'tr' )[0];
			if( !HeaderRow ) {
				continue;
			}
			var Header = HeaderRow.getElementsByTagName( 'th' )[0];
			if( !Header ) {
				continue;
			}
 
			NavigationBoxes[tableIndex] = Tables[i];
			Tables[i].setAttribute( 'id', 'collapsibleTable' + tableIndex );
 
			var Button     = document.createElement( 'span' );
			var ButtonLink = document.createElement( 'a' );
			var ButtonText = document.createTextNode( collapseCaption );
 
			Button.style.styleFloat = 'right';
			Button.style.cssFloat = 'right';
			Button.style.fontWeight = 'normal';
			Button.style.textAlign = 'right';
			Button.style.width = '6em';
 
			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 );
		}
	}
}
 
addOnloadHook( createCollapseButtons );
 
/** Dynamic Navigation Bars (experimental) *************************************
 *
 * From English Wikipedia, 2008-09-15
 *
 *  Description: See [[Wikipedia:NavFrame]].
 *  Maintainers: UNMAINTAINED
 */
 
// set up the words in your language
var NavigationBarHide = '[' + collapseCaption + ']';
var NavigationBarShow = '[' + expandCaption + ']';
 
// 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 ( hasClass( NavChild, 'NavPic' ) ) {
				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;
	}
}
 
// adds show/hide-button to navigation bars
function createNavigationBarToggleButton() {
	var indexNavigationBar = 0;
	// iterate over all < div >-elements
	var divs = document.getElementsByTagName( 'div' );
	for( var i = 0; NavFrame = divs[i]; i++ ) {
		// if found a navigation bar
		if( hasClass( NavFrame, '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 );
			for( var NavChild = NavFrame.firstChild; NavChild != null; NavChild = NavChild.nextSibling ) {
				if ( hasClass( NavChild, 'NavPic' ) || hasClass( NavChild, 'NavContent' ) ) {
					if( NavChild.style.display == 'none' ) {
						NavToggleText = document.createTextNode( NavigationBarShow );
						break;
					}
				}
			}
 
			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 );
		}
	}
}
addOnloadHook( createNavigationBarToggleButton );
 
/**
 * Hide prefix in category
 *
 * @source: http://www.mediawiki.org/wiki/Snippets/Hide_prefix_in_category
 * @rev: 1
 * @author: Krinkle
 */
/*var $tplHideCategoryPrefix = $( '#mw-cat-hideprefix' );
if ( $tplHideCategoryPrefix.length ) {
	var prefix = $tplHideCategoryPrefix.text();
	$( '#mw-pages' ).find( 'a' ).text( function( i, val ){
		return val.replace( new RegExp( '^' + $.escapeRE( prefix ) ), '' );
	});
}
 */
/**
 * Load the CodeReview 'tooltips' gadget on [[MediaWiki roadmap]] subpages,
 * so it's available for the revision reports where it's particularly useful
 * @author: Happy-melon
 */
/*if( mw.config.get( 'wgPageName' ).match( /^MediaWiki_roadmap/ ) ) {
	mw.loader.using( ['ext.codereview.tooltips'], function(){} );
}*/

/**
 * jQuery makeCollapsible
 *
 * This will enable collapsible-functionality on all passed elements.
 * Will prevent binding twice to the same element.
 * Initial state is expanded by default, this can be overriden by adding class
 * "mw-collapsed" to the "mw-collapsible" element.
 * Elements made collapsible have class "mw-made-collapsible".
 * Except for tables and lists, the inner content is wrapped in "mw-collapsible-content".
 *
 * @author Krinkle <krinklemail@gmail.com>
 *
 * Dual license:
 * @license CC-BY 3.0 <http://creativecommons.org/licenses/by/3.0>
 * @license GPL2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
 
( function( $, mw ) {
 
$.fn.makeCollapsible = function() {
 
	return this.each(function() {
		var _fn = 'jquery.makeCollapsible> ';
 
		// Define reused variables and functions
		var	$that = $(this).addClass( 'mw-collapsible' ), // case: $( '#myAJAXelement' ).makeCollapsible()
			that = this,
			collapsetext = $(this).attr( 'data-collapsetext' ),
			expandtext = $(this).attr( 'data-expandtext' ),
			toggleElement = function( $collapsible, action, $defaultToggle, instantHide ) {
				// Validate parameters
				if ( !$collapsible.jquery ) { // $collapsible must be an instance of jQuery
					return;
				}
				if ( action != 'expand' && action != 'collapse' ) {
					// action must be string with 'expand' or 'collapse'
					return;
				}
				if ( typeof $defaultToggle == 'undefined' ) {
					$defaultToggle = null;
				}
				if ( $defaultToggle !== null && !($defaultToggle instanceof jQuery) ) {
					// is optional (may be undefined), but if defined it must be an instance of jQuery.
					// If it's not, abort right away.
					// After this $defaultToggle is either null or a valid jQuery instance.
					return;
				}
 
				var $containers = null;
 
				if ( action == 'collapse' ) {
 
					// Collapse the element
					if ( $collapsible.is( 'table' ) ) {
						// Hide all table rows of this table
						// Slide doens't work with tables, but fade does as of jQuery 1.1.3
						// http://stackoverflow.com/questions/467336#920480
						$containers = $collapsible.find( '>tbody>tr' );
						if ( $defaultToggle ) { 
							// Exclude tablerow containing togglelink
							$containers.not( $defaultToggle.closest( 'tr' ) ).stop(true, true).fadeOut();
						} else {
							if ( instantHide ) {	
								$containers.hide();
							} else {
								$containers.stop( true, true ).fadeOut();
							}
						}
 
					} else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
						$containers = $collapsible.find( '> li' );
						if ( $defaultToggle ) {
							// Exclude list-item containing togglelink
							$containers.not( $defaultToggle.parent() ).stop( true, true ).slideUp();
						} else {
							if ( instantHide ) {
								$containers.hide();
							} else {
								$containers.stop( true, true ).slideUp();
							}
						}
 
					} else { // <div>, <p> etc.
						var $collapsibleContent = $collapsible.find( '> .mw-collapsible-content' );
 
						// If a collapsible-content is defined, collapse it
						if ( $collapsibleContent.length ) {
							if ( instantHide ) {
								$collapsibleContent.hide();
							} else {
								$collapsibleContent.slideUp();
							}
 
						// Otherwise assume this is a customcollapse with a remote toggle
						// .. and there is no collapsible-content because the entire element should be toggled
						} else {
							if ( $collapsible.is( 'tr' ) || $collapsible.is( 'td' ) || $collapsible.is( 'th' ) ) {
								$collapsible.fadeOut();
							} else {
								$collapsible.slideUp();
							}
						}
					}
 
				} else {
 
					// Expand the element
					if ( $collapsible.is( 'table' ) ) {
						$containers = $collapsible.find( '>tbody>tr' );
						if ( $defaultToggle ) {
							// Exclude tablerow containing togglelink
							$containers.not( $defaultToggle.parent().parent() ).stop(true, true).fadeIn();
						} else {
							$containers.stop(true, true).fadeIn();
						}
 
					} else if ( $collapsible.is( 'ul' ) || $collapsible.is( 'ol' ) ) {
						$containers = $collapsible.find( '> li' );
						if ( $defaultToggle ) {
							// Exclude list-item containing togglelink
							$containers.not( $defaultToggle.parent() ).stop( true, true ).slideDown();
						} else {
							$containers.stop( true, true ).slideDown();
						}
 
					} else { // <div>, <p> etc.
						var $collapsibleContent = $collapsible.find( '> .mw-collapsible-content' );
 
						// If a collapsible-content is defined, collapse it
						if ( $collapsibleContent.length ) {
							$collapsibleContent.slideDown();
 
						// Otherwise assume this is a customcollapse with a remote toggle
						// .. and there is no collapsible-content because the entire element should be toggled
						} else {
							if ( $collapsible.is( 'tr' ) || $collapsible.is( 'td' ) || $collapsible.is( 'th' ) ) {
								$collapsible.fadeIn();
							} else {
								$collapsible.slideDown();
							}
						}
					}
				}
			},
			// Toggles collapsible and togglelink class and updates text label
			toggleLinkDefault = function( that, e ) {
				var	$that = $(that),
					$collapsible = $that.closest( '.mw-collapsible.mw-made-collapsible' ).toggleClass( 'mw-collapsed' );
				e.preventDefault();
				e.stopPropagation();
 
				// It's expanded right now
				if ( !$that.hasClass( 'mw-collapsible-toggle-collapsed' ) ) {
					// Change link to "Show"
					$that.removeClass( 'mw-collapsible-toggle-expanded' ).addClass( 'mw-collapsible-toggle-collapsed' );
					if ( $that.find( '> a' ).length ) {
						$that.find( '> a' ).text( expandtext );
					} else {
						$that.text( expandtext );
					}
					// Collapse element
					toggleElement( $collapsible, 'collapse', $that );
 
				// It's collapsed right now
				} else {
					// Change link to "Hide"
					$that.removeClass( 'mw-collapsible-toggle-collapsed' ).addClass( 'mw-collapsible-toggle-expanded' );
					if ( $that.find( '> a' ).length ) {
						$that.find( '> a' ).text( collapsetext );
					} else {
						$that.text( collapsetext );
					}
					// Expand element
					toggleElement( $collapsible, 'expand', $that );
				}
				return;
			},
			// Toggles collapsible and togglelink class
			toggleLinkPremade = function( $that, e ) {
				var	$collapsible = $that.eq(0).closest( '.mw-collapsible.mw-made-collapsible' ).toggleClass( 'mw-collapsed' );
				e.preventDefault();
				e.stopPropagation();
 
				// It's expanded right now
				if ( !$that.hasClass( 'mw-collapsible-toggle-collapsed' ) ) {
					// Change toggle to collapsed
					$that.removeClass( 'mw-collapsible-toggle-expanded' ).addClass( 'mw-collapsible-toggle-collapsed' );
					// Collapse element
					toggleElement( $collapsible, 'collapse', $that );
 
				// It's collapsed right now
				} else {
					// Change toggle to expanded
					$that.removeClass( 'mw-collapsible-toggle-collapsed' ).addClass( 'mw-collapsible-toggle-expanded' );
					// Expand element
					toggleElement( $collapsible, 'expand', $that );
				}
				return;
			},
			// Toggles customcollapsible
			toggleLinkCustom = function( $that, e, $collapsible ) {
				// For the initial state call of customtogglers there is no event passed
				if (e) {
					e.preventDefault();
				e.stopPropagation();
				}
				// Get current state and toggle to the opposite
				var action = $collapsible.hasClass( 'mw-collapsed' ) ? 'expand' : 'collapse';
				$collapsible.toggleClass( 'mw-collapsed' );
				toggleElement( $collapsible, action, $that );
 
			};
 
		// Use custom text or default ?
		if( !collapsetext || collapsetext === '' ){
			collapsetext = mw.msg( 'collapsible-collapse' );
		}
		if ( !expandtext || expandtext === '' ){
			expandtext = mw.msg( 'collapsible-expand' );
		}
 
		// Create toggle link with a space around the brackets (&nbsp;[text]&nbsp;)
		var $toggleLink = $( '<a href="#"></a>' ).text( collapsetext ).wrap( '<span class="mw-collapsible-toggle"></span>' ).parent().prepend( '&nbsp;[' ).append( ']&nbsp;' ).bind( 'click.mw-collapse', function(e){
			toggleLinkDefault( this, e );
		} );
 
		// Return if it has been enabled already.
		if ( $that.hasClass( 'mw-made-collapsible' ) ) {
			return;
		} else {
			$that.addClass( 'mw-made-collapsible' );
		}
 
		// Check if this element has a custom position for the toggle link
		// (ie. outside the container or deeper inside the tree)
		// Then: Locate the custom toggle link(s) and bind them
		if ( $that.attr( 'id' ).indexOf( 'mw-customcollapsible-' ) === 0 ) {
 
			var thatId = $that.attr( 'id' ),
				$customTogglers = $( '.' + thatId.replace( 'mw-customcollapsible', 'mw-customtoggle' ) );
			mw.log( _fn + 'Found custom collapsible: #' + thatId );
 
			// Double check that there is actually a customtoggle link
			if ( $customTogglers.length ) {
				$customTogglers.bind( 'click.mw-collapse', function( e ) {
					toggleLinkCustom( $(this), e, $that );
				} );
			} else {
				mw.log( _fn + '#' + thatId + ': Missing toggler!' );
			}
 
			// Initial state
			if ( $that.hasClass( 'mw-collapsed' ) ) {
				$that.removeClass( 'mw-collapsed' );
				toggleLinkCustom( $customTogglers, null, $that );
			}
 
		// If this is not a custom case, do the default:
		// Wrap the contents add the toggle link 
		} else {
 
			// Elements are treated differently
			if ( $that.is( 'table' ) ) {
				// The toggle-link will be in one the the cells (td or th) of the first row
				var	$firstRowCells = $( 'tr:first th, tr:first td', that ),
					$toggle = $firstRowCells.find( '> .mw-collapsible-toggle' );
 
				// If theres no toggle link, add it to the last cell
				if ( !$toggle.length ) {
					$firstRowCells.eq(-1).prepend( $toggleLink );
				} else {
					$toggleLink = $toggle.unbind( 'click.mw-collapse' ).bind( 'click.mw-collapse', function( e ){
						toggleLinkPremade( $toggle, e );
					} );
				}
 
			} else if ( $that.is( 'ul' ) || $that.is( 'ol' ) ) {
				// The toggle-link will be in the first list-item
				var	$firstItem = $( 'li:first', $that),
					$toggle = $firstItem.find( '> .mw-collapsible-toggle' );
 
				// If theres no toggle link, add it
				if ( !$toggle.length ) {
					// Make sure the numeral order doesn't get messed up, reset to 1 unless value-attribute is already used
					// WebKit return '' if no value, Mozilla returns '-1' is no value.
					// Needs ==, will fail with ===
					if ( $firstItem.attr( 'value' ) == '' || $firstItem.attr( 'value' ) == '-1' ) { 
						$firstItem.attr( 'value', '1' );
					}
					$that.prepend( $toggleLink.wrap( '<li class="mw-collapsible-toggle-li"></li>' ).parent() );
				} else {
					$toggleLink = $toggle.unbind( 'click.mw-collapse' ).bind( 'click.mw-collapse', function( e ){
						toggleLinkPremade( $toggle, e );
					} );
				}
 
			} else { // <div>, <p> etc.
 
				// The toggle-link will be the first child of the element
				var $toggle = $that.find( '> .mw-collapsible-toggle' );
 
				// If a direct child .content-wrapper does not exists, create it
				if ( !$that.find( '> .mw-collapsible-content' ).length ) {
					$that.wrapInner( '<div class="mw-collapsible-content"></div>' );
				}
 
				// If theres no toggle link, add it
				if ( !$toggle.length ) {
					$that.prepend( $toggleLink );
				} else {
					$toggleLink = $toggle.unbind( 'click.mw-collapse' ).bind( 'click.mw-collapse', function( e ){
						toggleLinkPremade( $toggle, e );
					} );
				}
			}
		}
 
		// Initial state (only for those that are not custom)
		if ( $that.hasClass( 'mw-collapsed' ) && $that.attr( 'id' ).indexOf( 'mw-customcollapsible-' ) !== 0 ) {
			$that.removeClass( 'mw-collapsed' );
			// The collapsible element could have multiple togglers
			// To toggle the initial state only click one of them (ie. the first one, eq(0) )
			// Else it would go like: hide,show,hide,show for each toggle link.
			toggleElement( $that, 'collapse', $toggleLink.eq(0), /* instantHide = */ true );
			$toggleLink.eq(0).click();
		}
	} );
};
} )( jQuery, mediaWiki );
 
 
 
 
// Remove this file when it is deployed for real (and the import from Common.js)
// The following four lines are not in the original module and are required since it is not deployed
importStylesheet('MediaWiki:JQuery-makeCollapsible.css');mw.messages.set({"collapsible-collapse":"Collapse","collapsible-expand":"Expand"});
$(document).ready(function(){
 $('.mw-collapsible').makeCollapsible();
});
*/