मिडियाविकी:Gadget-CollapsibleTOC.js

Wiktionary कडल्यान

चत्राय: सांबाळ्ळ्या उपरांत, तुका घडयेक तुज्या ब्रावसराचो कॅश कडसरावंक पडत बदल पळोंवचे खातीर.

  • Firefox / Safari: Shift > धर Reload क्लीक करताना, वा दाम Ctrl-F5 वा Ctrl-R (⌘-R मॅक-आचेर)
  • Google Chrome: Ctrl-Shift-R दाम (⌘-Shift-R एका मॅक-आचेर)
  • Internet Explorer: Ctrl dhor Refresh क्लीक करताना, वा दाम Ctrl-F5
  • Opera: हांगा वच: Menu → Settings (Opera → Preferences मॅक-आचेर) आनी उपरांत Privacy & security → Clear browsing data → Cached images and files.‎
/**
 * Índice que por defecto solo muestra los títulos de nivel 1 (con el objetivo
 * de no congestionar demasiado la pantalla), mientras que los niveles inferiores
 * se muestran clicando en el botón [+] (o [-]), de una manera parecida a la que
 * lo hacen los navegadores de ficheros clásicos.
 * 
 * Adaptado de [[:fr:MediaWiki:Gadget-SommaireDeveloppable.js]].
 * 
 * Autores del programa original:
 * * Eiku 25 abril 2012 para el código base.
 * * ArséniureDeGallium para los detalles y los diversos añadidos.
 * 
 * Inspirado por WikiTravel (http://files.wikitravel.org/mw/skins/common/wikibits.js?0.1),
 * pero realizado de una manera diferente.
 *
 * Véase también /resources/src/mediawiki/mediawiki.toc.js de mediawiki/core.
 * 
 * Traducción de [[Usuario:Alakrano]]
 * Adaptación para Wikcionario y posterior rediseño: [[Usuario:Peter Bowman]]
 */

// Botones para mostrar/ocultar todas las secciones
var $developAll, $envelopAll;

// Contador de secciones plegadas (excluyendo las que no tienen subsecciones)
var collapsedCount = 0;

// Número total de secciones (excluyendo las que no tienen subsecciones)
var totalCount = 0;

// Contador de secciones de primer nivel plegadas (excluyendo las que no tienen subsecciones)
var collapsedfirstLevelCount = 0;

// Número total de secciones de primer nivel (excluyendo las que no tienen subsecciones)
var totalFirstLevelCount = 0;

// Enumeración que define la acción realizada por el usuario
var OPS = {
	INIT:  0,
	CLEAR: 1,
	FILL:  2,
	INCR:  3,
	DECR:  4
};

var config = {
	labels: {
		'collapsibleToc-develop':     '►',
		'collapsibleToc-envelop':     '▼',
		'collapsibleToc-empty':       '►',
		'collapsibleToc-develop-all': '►',
		'collapsibleToc-envelop-all': '▼'
	},
	messages: {
		'collapsibleToc-develop':           'Hea vibhagant up-vibhag asat, te pollovnk klik kor',
		'collapsibleToc-envelop':           'Up-vibhag lipovnk klik kor',
		'collapsibleToc-empty':             'Hea vibhagant up-vibhag nant',
		'collapsibleToc-develop-all':       'Soglle vibhag dakhovnk klik kor',
		'collapsibleToc-envelop-all':       'Soglle vibhag lipovnk klik kor',
		'collapsibleToc-develop-all-empty': 'Soglle vibhag vaddovpant keleat',
		'collapsibleToc-envelop-all-empty': 'Soglle dispi vibhag doddpant keleat'
	}
};

mw.config.set( config.labels );
mw.messages.set( config.messages );

if (
	mw.config.get( 'wgNamespaceNumber' ) === 0 &&
	mw.config.get( 'wgAction' ) === 'view'
) {
	$( function () {
		var $toc = $( '#toc' );
		
		// Itera sobre cada elemento <li> de la tabla de contenido
		$toc.find( 'li' ).each( doCollapsible );
		
		// Elimina la numeración de los encabezamientos
		if ( !mw.user.options.get( 'numberheadings' ) ) {
			$toc.find( 'li > a' ).each( function () {
				// La estructura HTML es <span>numeración</span> <span>título</span>.
				// No basta con un display: none; para el primer <span>, nótese el espacio
				// entre medias.
				var $this = $( this );
				var $tocText = $this.find( '.toctext' ).detach();
				$this.empty().append( $tocText );
			} );
		}
		
		if ( totalCount > 1 ) {
			// Añade los botones para mostrar/ocultar todo
			addToggleButtons( $toc );
			
			// Pliega por defecto los elementos de nivel 1 a excepción del primero
			$toc.find( '.toclevel-1 > [data-collapsible-toc-state]' ).each( function ( i ) {
				if ( i !== 0 ) {
					$( this ).trigger( 'click' );
				}
			} );
		}
	} );
}

// Callback para cada iteración del bucle .each()
function doCollapsible( i, li ) {
	var $li = $( li ), $ul = $li.children( 'ul' ), $button = $( '<span>' ),
		isFirstLevel = $li.hasClass( 'toclevel-1' );
	
	// Comprueba si existe una lista de nivel inferior dentro de la actual
	if ( $ul.length ) {
		$button
			.css( 'color', '#0645AD' )
			.attr( {
				title: mw.msg( 'collapsibleToc-envelop' ),
				'data-collapsible-toc-state': 'expanded'
			} )
			.text( config.labels[ 'collapsibleToc-envelop' ] )
			.on( 'click', function () {
				if ( $button.attr( 'data-collapsible-toc-state' ) === 'collapsed' ) {
					$ul.show();
					
					$button
						.attr( {
							title: mw.msg( 'collapsibleToc-envelop' ),
							'data-collapsible-toc-state': 'expanded'
						} )
						.text( config.labels[ 'collapsibleToc-envelop' ] );
					
					checkAndUpdateState( OPS.DECR, isFirstLevel );
				} else {
					$ul.hide();
					
					$button
						.attr( {
							title: mw.msg( 'collapsibleToc-develop' ),
							'data-collapsible-toc-state': 'collapsed'
						} )
						.text( config.labels[ 'collapsibleToc-develop' ] );
					
					checkAndUpdateState( OPS.INCR, isFirstLevel );
				}
			} );
		
		// Incrementa el contador de secciones
		totalCount++;
		
		if ( isFirstLevel ) {
			totalFirstLevelCount++;
		}
	} else {
		// No hay más subniveles
		$button
			.css( 'color', '#C0C0C0' )
			.css( 'cursor', 'default' ) // TODO: trasladar a CSS
			.attr( 'title', mw.msg( 'collapsibleToc-empty' ) )
			.text( config.labels[ 'collapsibleToc-empty' ] );
	}
	
	$button.addClass( 'collapsibleToc-button' );
	
	// Inserta el botón como el primer elemento hijo del <li> actual
	$button.prependTo( $li );
}

function addToggleButtons( $toc ) {
	var $tocToggle;
	
	// Botón para mostrar todas las secciones
	$developAll = $( '<span>' )
		.text( config.labels[ 'collapsibleToc-develop-all' ] )
		.on( 'click', function () {
			if ( $developAll.data( 'collapsibleToc-toggle-active' ) ) {
				$toc
					.find( '[data-collapsible-toc-state="collapsed"]' )
					.trigger( 'click' );
			
				checkAndUpdateState( OPS.CLEAR );
			}
		} );
	
	// Botón para ocultar todas las secciones
	$envelopAll = $( '<span>' )
		.text( config.labels[ 'collapsibleToc-envelop-all' ] )
		.on( 'click', function () {
			if ( $envelopAll.data( 'collapsibleToc-toggle-active' ) ) {
				$toc
					.find( '[data-collapsible-toc-state="expanded"]' )
					.trigger( 'click' );
				
				checkAndUpdateState( OPS.FILL );
			}
		} );
	
	// Inicializa el estado de los botones
	checkAndUpdateState( OPS.INIT );
	
	// "Cajetín" del ToC que contiene ambos botones
	$tocToggle = $( '<span>' )
		.addClass( 'toctoggle toctoggle-ct' )
		.append(
			'[',
			$developAll,
			'&nbsp;',
			$envelopAll,
			']'
		);
	
	// El ToC está inicialmente oculto, no muestres el cajetín
	if ( !$toc.find( 'ul' ).eq( 0 ).is( ':visible' ) ) {
		$tocToggle.hide();
	}
	
	$tocToggle.appendTo( $toc.find( '.toctitle' ) );
	
	// Configura la animación del cajetín, ejecutándose a la par que el slideUp/Down del ToC
	$toc.find( '#togglelink' ).on( 'click', function ( e ) {
		e.preventDefault();
		$tocToggle.fadeToggle( 'fast' );
	} );
}

function checkAndUpdateState( op, isFirstLevel ) {
	switch ( op ) {
		case OPS.INIT:
			updateDevelopAllButton( collapsedCount !== 0 );
			updateEnvelopAllButton( collapsedCount !== totalCount );
			break;
		case OPS.CLEAR:
			collapsedCount = 0;
			collapsedfirstLevelCount = 0;
			updateDevelopAllButton( false );
			updateEnvelopAllButton( true );
			break;
		case OPS.FILL:
			collapsedCount = totalCount;
			collapsedfirstLevelCount = totalFirstLevelCount;
			updateDevelopAllButton( true );
			updateEnvelopAllButton( false );
			break;
		case OPS.INCR:
			collapsedCount++;
			
			if ( isFirstLevel ) {
				collapsedfirstLevelCount++;
			}
			
			if ( collapsedCount === 1 ) {
				updateDevelopAllButton( true );
			}
			
			if (
				collapsedCount === totalCount ||
				// Este es un caso especial, pues debe tener en cuenta si la sección plegada es
				// de primer nivel. Si esta y sus hermanas se pliegan, ejecuta
				// updateEnvelopAllButton( false ) independientemente del estado de las secciones hijas.
				isFirstLevel && collapsedfirstLevelCount === totalFirstLevelCount
			) {
				updateEnvelopAllButton( false );
			}
			
			break;
		case OPS.DECR:
			collapsedCount--;
			
			if ( isFirstLevel ) {
				collapsedfirstLevelCount--;
			}
			
			if ( collapsedCount === 0 ) {
				updateDevelopAllButton( false );
			}
			
			if (
				collapsedCount === totalCount - 1 ||
				// Ver comentario en OPS.INCR
				isFirstLevel && collapsedfirstLevelCount === totalFirstLevelCount - 1
			) {
				updateEnvelopAllButton( true );
			}
			
			break;
	}
}

function updateDevelopAllButton( isActive ) {
	$developAll
		// TODO: trasladar a CSS
		.css( isActive ? { color: '#0645AD', cursor: 'pointer' } : { color: '#C0C0C0', cursor: 'default' } )
		.data( 'collapsibleToc-toggle-active', isActive ? true : false )
		.attr( 'title', mw.msg( isActive ? 'collapsibleToc-develop-all' : 'collapsibleToc-develop-all-empty' ) );
}

function updateEnvelopAllButton( isActive ) {
	$envelopAll
		// TODO: trasladar a CSS
		.css( isActive ? { color: '#0645AD', cursor: 'pointer' } : { color: '#C0C0C0', cursor: 'default' } )
		.data( 'collapsibleToc-toggle-active', isActive ? true : false )
		.attr( 'title', mw.msg( isActive ? 'collapsibleToc-envelop-all' : 'collapsibleToc-envelop-all-empty' ) );
}