MediaWiki:Gadget-browse-categories.js

Z Wikisłownika – wolnego słownika wielojęzycznego

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.
/**
 * Przeglądanie zawartości kategorii w rozwijanym menu pod sekcjami językowymi
 * Autor: [[User:Peter Bowman]]
 */
 
var brcat = mw.libs.browseCategories = {};

var api;

var r = /^[ \u0530-\uFFFF]+$/;
var LIMIT = 60;

var DIR = {
	asc:  'ascending',
	desc: 'descending',
	main: ''
};

function formatNum( num ) {
	var a;
	num = '' + num;
	
	if ( num.length > 4 ) {
		a = num.split( '' );
		a[ a.length - 4 ] += ' ';
		num = a.join( '' );
	}
	
	return num;
}

function browseCategoryMembers( catname, dir, limit, cont ) {
	return api.get( {
		formatversion: 2,
		list:    'categorymembers',
		cmtitle: catname,
		cmprop:  'title',
		cmtype:  'page',
		cmlimit: limit,
		cmsort:  'sortkey',
		cmdir:   dir,
		cmstarthexsortkey: brcat.categories[ catname ].sortkey,
		cmcontinue: cont || DIR.main
	} );
}

function printResults( box ) {
	var cat = brcat.categories[ box.currentcat ],
		pagename = mw.config.get( 'wgPageName' ).replace( /_/g, ' ' ),
		$div = box.$pagelist.clone().empty(),
		path = mw.config.get( 'wgArticlePath' ),
		fragment = '';
	
	if ( box.id && box.id !== 'multilang' ) {
		fragment = '#' + box.id.replace( '-foreign', '' );
	}
	
	$.each( cat.history[ box.counter ].pages, function () {
		var $page;
		
		if ( this == pagename ) {
			$page = $( '<span>' )
				.addClass( 'catlinks-browsebox-selflink' )
				.text( this );
		} else {
			$page = $( '<a>' )
				.attr( 'href', mw.format( path, encodeURIComponent( this ) ) + fragment )
				.text( this );
		}
		
		if ( r.test( $page.text() ) ) {
			$page.addClass( 'catlinks-browsebox-nostyle' );
		}
		
		$div.append( $( '<div>' ).append( $page ) );
	} );
	
	checkContinueParameter( box );
	
	box.$pagelist.replaceWith( box.$pagelist = $div );
	box.$loadicon.hide();
	box.$navbar.children( 'a' ).each( function ( i ) {
		this.style.visibility = ( cat.cmcontinue[ ( i === 0 ) ? DIR.desc : DIR.asc ] !== undefined )
			? 'visible'
			: 'hidden';
	} );
	box.$navbar.find( 'span span' ).html(
		'&nbsp;&nbsp;(' + brcat.categories[ box.currentcat ].size + ')'
	);
}

function checkContinueParameter( box ) {
	var cat = brcat.categories[ box.currentcat ],
		count = box.counter,
		hist  = cat.history[ count ],
		cont  = cat.cmcontinue;
	
	if ( count > 0 ) {
		cont[ DIR.asc ]  = hist[ DIR.asc ];
		cont[ DIR.desc ] = ( count === 1 )
			? DIR.main
			: cat.history[ count - 1 ][ DIR.asc ];
	} else if ( count < 0 ) {
		cont[ DIR.asc ]  = ( count === -1 )
			? DIR.main
			: cat.history[ count + 1 ][ DIR.desc ];
		cont[ DIR.desc ] = hist[ DIR.desc ];
	} else {
		cont[ DIR.asc ]  = hist[ DIR.asc ];
		cont[ DIR.desc ] = hist[ DIR.desc ];
	}
}

function analyzeResults( box ) {
	var cat = brcat.categories[ box.currentcat ],
		pages = [];
	
	$.each( Array.prototype.slice.call( arguments, 1 ), function ( i, arg ) {
		for (
			var j = ( box.counter === 0 && arg.dir === DIR.asc ) ? 1 : 0;
			j < arg.data.query.categorymembers.length;
			j++
		) {
			pages.push( arg.data.query.categorymembers[ j ].title );
		}
		
		if ( arg.dir === DIR.desc ) {
			pages.reverse();
		}
		
		if ( arg.data[ 'continue' ] ) {			
			cat.history[ box.counter ][ arg.dir ] = arg
				.data[ 'continue' ].cmcontinue;
		}
	} );
	
	cat.history[ box.counter ].pages = pages;
	printResults( box );
	box.$pagelist.removeClass( 'catlinks-browsebox-pagelist-loading' );
}

function getCategorymembers( box ) {
	var upper = parseInt( LIMIT / 2 ),
		lower = LIMIT - upper;
		
	$.when(
		browseCategoryMembers( box.currentcat, 'desc', lower ),
		browseCategoryMembers( box.currentcat, 'asc',  upper + 1 )
	).done( function ( data1, data2 ) {
		brcat.categories[ box.currentcat ].cmcontinue = {};
		brcat.categories[ box.currentcat ].history = {
			'0': {}
		};
		
		analyzeResults( box, {
			dir:  DIR.desc,
			data: data1[ 0 ]
		}, {
			dir:  DIR.asc,
			data: data2[ 0 ]
		} );
	} );
}

function tryPurgePage( catname, callback ) {
	if ( brcat.purged || brcat.cannotPurge ) {
		return;
	}
	
	mw.user.getRights( function ( rights ) {
		if ( rights.indexOf( 'purge' ) !== -1 ) {
			api.post( {
				action:          'purge',
				forcelinkupdate: true,
				titles:          mw.config.get( 'wgPageName' )
			} )
			.done( function () {
				brcat.purged = true;
				getCategories( catname, callback );
			} );
		} else {
			brcat.cannotPurge = true;
		}
	} );
}

function getCategories( catname, callback ) {
	api.get( {
		formatversion: 2,
		prop:         'categories',
		clprop:       'sortkey',
		cllimit:      'max',
		titles:        mw.config.get( 'wgPageName' )
	} )
	.done( function ( data ) {
		var found = false;
		
		$.each(
			data.query && data.query.pages &&
			data.query.pages[ 0 ].categories
		, function ( i, category ) {
			if ( !brcat.categories[ category.title ] )
				brcat.categories[ category.title ] = {
					sortkey: category.sortkey
				};
			
			if ( category.title === catname ) {
				found = true;
			}
		} );
		
		if ( !found ) {
			tryPurgePage( catname, callback );
			return;
		}
		
		// Nie można scalić tego zapytania z poprzednim, parametr
		// 'gclprop=sortkey' nie działa (phab:T145280)
		api.get( {
			formatversion: 2,
			prop:      'categoryinfo',
			titles:    mw.config.get( 'wgPageName' ),
			generator: 'categories',
			gcllimit:  'max'
		} )
		.done( function ( data ) {
			$.each( data.query.pages, function ( i, info ) {
				brcat.categories[ info.title ].size = formatNum( info.categoryinfo.pages );
				brcat.launched = true;
			} );
		} )
		.done( callback );
	} );
}

function openBrowseArea( box ) {
	var callback = function () {
		getCategorymembers( box );
	};
	
	box.$navbar.children( 'span' ).empty().append(
		$( '<a>' )
			.attr( 'href', mw.format( mw.config.get( 'wgArticlePath' ), box.currentcat ) )
			.text(
				box.currentcat
					.slice( box.currentcat.indexOf( ':' ) + 1 )
					// [[Specjalna:Niezmienny link/4318644#Typografia nazw stron (półpauza)]]
					// WYŁĄCZONE, zob. wątek w Barze
					//.replace( ' - ', ' – ' )
			),
		$( '<span>' )
	);
	
	box.$navbar.children( 'a' ).css( 'visibility', 'hidden' );
	box.$pagelist.empty();
	box.$loadicon.show();
	box.$parent.show();
	
	box.counter = 0;
	
	if ( !brcat.launched ) {
		getCategories( box.currentcat, callback );
	} else if ( !brcat.categories[ box.currentcat ] ) {
		tryPurgePage( box.currentcat, callback );
	} else if ( brcat.categories[ box.currentcat ].history ) {
		printResults( box );
	} else {
		getCategorymembers( box );
	}
}

function closeBrowseArea( box ) {
	box.$parent.hide();
}

function navigationButtonHandler( box, dir ) {
	return function ( evt ) {
		var history = brcat.categories[ box.currentcat ].history,
			counter = box.counter = ( dir === DIR.asc )
				? box.counter + 1
				: box.counter - 1;
		
		history[ counter ] = history[ counter ] || {};
		
		if ( history[ counter ].pages ) {
			printResults( box );
		} else {
			box.$navbar.children( 'a' ).css( 'visibility', 'hidden' );
			box.$pagelist.addClass( 'catlinks-browsebox-pagelist-loading' );
			
			browseCategoryMembers(
				box.currentcat,
				dir,
				LIMIT,
				brcat.categories[ box.currentcat ].cmcontinue[ dir ]
			).done( function ( data ) {
				analyzeResults( box, {
					dir:  dir,
					data: data
				} );
			} );
		}
	};
}

brcat.init = function ( $catlinks ) {
	var localCatname = mw.config.get( 'wgFormattedNamespaces' )[ 14 ];
	
	brcat.categories = {};
	brcat.launched = false;
	brcat.purged   = false;
	brcat.catboxes = {};
	
	api = new mw.Api();
	
	$catlinks.each( function () {
		var $primaryLangCodes,
			$catbox = $( this ),
			id = $catbox.attr( 'id' );
		
		if ( id === 'catlinks' ) {
			// FIXME: nie można użyć $content.find( '.primary-lang-code' )
			$primaryLangCodes = $( '.primary-lang-code' );
			
			if ( $primaryLangCodes.length === 1 ) {
				id = $primaryLangCodes.eq( 0 ).attr( 'id' );
			} else {
				id = 'multilang';
			}
		} else {
			id = id.slice( 'catlinks-'.length );
		}
		
		var browsebox = brcat.catboxes[ id ] = {
			activebuttons: {
				$show: $(),
				$hide: $()
			},
			$activelink: $(),
			id: id
		};
				
		browsebox.$parent = $( '<div>' )
			.addClass( 'catlinks-browsebox' )
			.attr( 'id', 'catlinks-' + id + '-browsebox' )
			.append(
				browsebox.$navbar = $( '<div>' )
					.addClass( 'catlinks-browsebox-navbar' )
					.append(
						$( '<a>' )
							.text( '<<' )
							.on( 'click', navigationButtonHandler( browsebox, DIR.desc ) ),
						$( '<span>' ),
						$( '<a>' )
							.text( '>>' )
							.on( 'click', navigationButtonHandler( browsebox, DIR.asc ) )
					),
				browsebox.$pagelist = $( '<div>' )
					.addClass( 'catlinks-browsebox-pagelist' ),
				browsebox.$loadicon = $.createSpinner( {
						id:   id,
						size: 'large',
						type: 'block'
					} )
					.hide()
			)
			.hide()
			.appendTo( $catbox );
		
		$catbox.find( 'ul' ).find( 'a' ).each( function () {
			var $showButton, $hideButton,
				$this = $( this ),
				href = $this.attr( 'href' ),
				name = localCatname + ':' + decodeURI(
					href.slice( href.indexOf( localCatname + ':' ) + localCatname.length + 1 )
				).replace( /_/g, ' ' );
			
			$this.after( $( '<span>' )
				.addClass( 'catlinks-browsebuttons' )
				.append(
					$showButton = $( '<a>' )
						.text( '(↓)' )
						.on( 'click', function () {
							browsebox.activebuttons.$show.show();
							browsebox.activebuttons.$hide.hide();
							browsebox.$activelink.removeClass( 'catlinks-browsedcatlink' );
							
							browsebox.activebuttons.$show = $showButton.hide();
							browsebox.activebuttons.$hide = $hideButton.show();
							browsebox.$activelink = $this.addClass( 'catlinks-browsedcatlink' );
							
							browsebox.currentcat = name;
							
							openBrowseArea( browsebox );
						} ),
					$hideButton = $( '<a>' )
						.text( '(↑)' )
						.on( 'click', function () {
							$showButton.show();
							$hideButton.hide();
							browsebox.$activelink.removeClass( 'catlinks-browsedcatlink' );
							
							closeBrowseArea( browsebox );
						} )
						.hide()
				)	
			);
		} );
	} );
};

mw.hook( Number( mw.user.options.get( 'gadget-multiple-category-boxes' ) )
	? 'multipleCategoryBoxes.ready'
	: 'wikipage.categories'
).add( brcat.init );