MediaWiki:Gadget-multiple-category-boxes.js

Uwaga: aby zobaczyć zmiany po opublikowaniu, może zajść potrzeba wyczyszczenia pamięci podręcznej przeglądarki.

  • Firefox / Safari: Przytrzymaj Shift podczas klikania Odśwież bieżącą stronę, lub naciśnij klawisze Ctrl+F5, lub Ctrl+R (⌘-R na komputerze Mac)
  • Google Chrome: Naciśnij Ctrl-Shift-R (⌘-Shift-R na komputerze Mac)
  • Internet Explorer / Edge: Przytrzymaj Ctrl, jednocześnie klikając Odśwież, lub naciśnij klawisze Ctrl+F5
  • Opera: Naciśnij klawisze Ctrl+F5.
/**
 * Umieszczanie listy kategorii pod każdą sekcją językową
 * Autor: Peter Bowman @ plwikt
 */

var gadget = mw.libs.multipleCategoryBoxes = {},
	config = mw.config.get( [
		'wgFormattedNamespaces',
		'wgPageName',
		'wgArticlePath'
	] );

function stripCategoryNamespace( title ) {
	return title.slice( config.wgFormattedNamespaces[ 14 ].length + 1 );
}

function testCatboxId( $catbox ) {
	var id = $catbox.attr( 'id' ).slice( 'catlinks-'.length );
	return id in gadget.sections;
}

function processCategoryInfo( data ) {
	$.each( data.query.pages[ 0 ].categories, function ( i, cat ) {
		gadget.catlist[ cat.title ] = cat.hidden ? 'hidden' : 'visible';
	} );
}

function retrieveCategoryInfo() {
	return gadget.api.get( {
		formatversion: 2,
		prop:         'categories',
		titles:       config.wgPageName,
		clprop:       'hidden',
		cllimit:      'max'
	} );
}

function purgePage() {
	var query = {
		action:          'purge',
		forcelinkupdate: true,
		titles:          config.wgPageName
	};
	
	return gadget.api.post( query );
}

function requestExpandedText() {
	return gadget.api.get( {
		formatversion: 2,
		action: 'expandtemplates',
		title:  config.wgPageName,
		text:   '{' + '{:' + config.wgPageName + '}}',
		prop:   'wikitext'
	} );
}

function requestCallback( data ) {
	analyzeExpandedText( data.expandtemplates && data.expandtemplates.wikitext || '' );
	
	if ( !gadget.retried && !gadget.catboxes.every( testCatboxId ) ) {
		resetState( false );
		gadget.retried = true;
		
		return purgePage()
			.then( retrieveCategoryInfo )
			.done( processCategoryInfo )
			.then( requestExpandedText )
			.done( requestCallback );
	} else {
		$.each( gadget.catboxes, function () {
			if ( testCatboxId( this ) ) {
				fillCatBox( this );
			} else {
				this.find( '.catlinks-spinner' ).replaceWith( generateLabel( 'błąd odczytu danych' ) );
			}
		} );
	}
}

function extractCategories( wikitext, fullname, shortname ) {
	var m, map = {};
	
	while ( m = gadget.categoryRegex.exec( wikitext ) ) {
		if (
			fullname === 'Esperanto' &&
			m[ 1 ].indexOf( 'Esperanto - morfemy' ) === 0
		) {
			return true;
		}
		
		map[ m[ 1 ] ] = true;
	}
	
	return $.map( map, function ( value, key ) {
		return key;
	} );
}

function classifyCategories( $catbox ) {
	$catbox
		.children( '.mw-normal-catlinks' )
		.find( 'li > a' )
		.each( function () {
			gadget.catlist[ this.title ] = 'visible';
		} );
	
	$catbox
		.children( '.mw-hidden-catlinks' )
		.find( 'li > a' )
		.each( function () {
			gadget.catlist[ this.title ] = 'hidden';
		} );
}

function analyzeExpandedText( text ) {
	// zob. [[Moduł:nagłówek języka]]
	var sections = text.split( /(?=<span class="lang-code primary-lang-code)/ );
	sections.shift(); // sekcja zerowa, czyli interwiki, podobne oraz TOC
	
	$.each( sections, function ( i, section ) {
		var shortname, fullname,
			index = section.indexOf( 'id=' ),
			idAttr = section.slice( index, section.indexOf( '>', index ) ),
			id = idAttr.match( /^id="(.+?)"$/ )[ 1 ];
		
		shortname = mw.libs.langData.code2lang[ id ];
		
		if ( !id || !shortname ) {
			return true;
		}
		
		if ( mw.libs.langData.shortLangs.indexOf( shortname ) === -1 ) {
			fullname = 'Język ' + shortname;
		} else {
			fullname = shortname.charAt( 0 ).toUpperCase() + shortname.slice( 1 );
		}
		
		gadget.sections[ id ] = {
			text:       section,
			fullname:   fullname,
			shortname:  shortname,
			categories: extractCategories( section, fullname, shortname )
		};
	} );
}

function fillCatBox( $catbox ) {
	var id, visible, hidden;
	
	id = $catbox.attr( 'id' ).slice( 'catlinks-'.length );
	$catbox.data( 'spinner' ).remove();
	gadget.sections[ id ].$box = $catbox;
	
	visible = [];
	hidden  = [];
	
	$.each( gadget.sections[ id ].categories, function ( i, cat ) {
		var $el = $( '<li>' ).append(
			$( '<a>' )
				.attr( {
					href:  config.wgArticlePath.replace( '$1', cat ),
					title: cat
				} )
				.text( stripCategoryNamespace( cat ) )
		);
		
		if ( !( cat in gadget.catlist ) || gadget.catlist[ cat ] === 'hidden' ) {
			hidden.push( $el.prop( 'outerHTML' ) );
		} else {
			visible.push( $el.prop( 'outerHTML' ) );
		}
	} );
	
	if ( !visible.length ) {
		if ( !hidden.length || !Number( mw.user.options.get( 'showhiddencats' ) ) ) {
			$catbox.children( '.mw-normal-catlinks' ).append( generateLabel( 'brak' ) );
		} else {
			$catbox.children( '.mw-normal-catlinks' ).remove();
		}
	} else {
		$catbox.children( '.mw-normal-catlinks' )
			.find( 'ul' )
			.append( visible );
	}
	
	if ( !hidden.length ) {
		$catbox.children( '.mw-hidden-catlinks' ).remove();
	} else {
		$catbox.children( '.mw-hidden-catlinks' )
			.find( 'ul' )
			.append( hidden );
		
		if ( Number( mw.user.options.get( 'showhiddencats' ) ) ) {
			$catbox.children( '.mw-hidden-catlinks' ).removeClass( 'mw-hidden-cats-hidden' );
		}
	}
}

function createCatBox( id, $catbox ) {
	var $spinner = $.createSpinner( id )
		.addClass( 'catlinks-spinner' );
	
	$catbox
		.attr( 'id', 'catlinks-' + id )
		.addClass( 'catlinks-section' )
		.data( 'spinner', $spinner );
	
	$catbox
		.children( '.mw-normal-catlinks' )
		.attr( 'id', 'mw-normal-catlinks-' + id )
		.append( $spinner )
		.find( 'ul' )
		.empty();
	
	$catbox
		.children( '.mw-hidden-catlinks' )
		.attr( 'id', 'mw-hidden-catlinks-' + id )
		.addClass( 'mw-hidden-cats-hidden' )
		.find( 'ul' )
		.empty();
	
	gadget.catboxes.push( $catbox );

	return $catbox;
}

function insertCatBoxes( $content, $catbox ) {
	var $fields = $content.children(),
		currentId = null,
		isFirstSection = true;
	
	$fields.each( function ( i ) {
		if ( this.nodeName === 'H2' ) {
			if ( isFirstSection ) {
				isFirstSection = false;
			} else if ( currentId ) {
				$( this ).before( createCatBox( currentId, $catbox.clone() ) );
			}
			
			currentId = $( this ).find( '.primary-lang-code' ).attr( 'id' );
		} else if ( i === $fields.length - 1 && currentId ) {
			$( this ).after( createCatBox( currentId, $catbox.clone() ) );
		}
	} );
	
	resetHash( true );
}

function generateLabel( message ) {
	return $( '<span>' )
		.addClass( 'catlinks-message' )
		.text( message );
}

function resetHash( check ) {
	if ( location.hash && check ) {
		location.hash = location.hash;
	}
}

function resetState( hardReset ) {
	gadget.sections = {};
	gadget.catlist = {};
	gadget.scrolled = false;
	gadget.retried = false;
	
	if ( hardReset ) {
		gadget.catboxes = [];
	}
}

mw.libs.langData = require( 'ext.gadget.langdata' );

gadget.api = new mw.Api();
gadget.categoryRegex = new RegExp( '\\[\\[(' + config.wgFormattedNamespaces[ 14 ] +
	':.+?)(?:\\|.*?)?\\]\\]', 'g' );

// TODO: użycie wikipage.content oraz wikipage.categories
$( function () {
	var $catbox = gadget.$originalCatbox = $( '#catlinks' ),
		$content = $( '#mw-content-text' );
	
	if ( $catbox.hasClass( 'catlinks-allhidden' ) ) {
		return;
	}
	
	if ( $content.find( '.primary-lang-code' ).length < 2 ) {
		mw.hook( 'multipleCategoryBoxes.ready' ).fire( $catbox );
		return;
	}
	
	resetState( true );
	
	classifyCategories( $catbox );
	insertCatBoxes( $content.find( '.mw-parser-output' ).first(), $catbox );
	$catbox.detach();
	
	requestExpandedText().then( requestCallback )
		.done( function () {
			resetHash( !gadget.scrolled );
			mw.hook( 'multipleCategoryBoxes.ready' ).fire( $content.find( '.catlinks' ) );
		} )
		.fail( function () {
			$content.find( '.catlinks-spinner' ).replaceWith( generateLabel( 'błąd API' ) );
		} );
	
	$( window ).on( 'mousedown wheel DOMMouseScroll mousewheel keyup', function () {
		gadget.scrolled = true;
	} );
} );