MediaWiki:Gadget-ll-script-loader.js

Z Wikipedii, wolnej encyklopedii

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.
/**
	Uniwersalny gadżet do automatycznego wczytywania modułów wspierających
	dzialanie różnych szablonów. Powstał po dyskusji w kawiarence technicznej:
	
	https://pl.wikipedia.org/w/index.php?oldid=54598545#Szablon:podzi%C4%99kowanie
	
	Wspierane moduły powinny deklarować następujące funkcje w obiekcie
	`module.exports` automatycznie eksponowanym przez mechanizmy ResourceLoader:
	
	  ///
	  /// Sprawdza warunki konieczne do uruchomienia gadżetu.
	  ///
	  /// @return {boolean}
	  testPreconditions()
	
	  ///
	  /// Przeprowadza wstępną konfigurację gadżetu, np. tworzenie obiektów
	  /// globalnych, rejestrowanie komunikatów itd.
	  ///
	  initialize()
	
	  ///
	  /// Odrzuca elementy, które nie spełniają określonych warunków.
	  ///
	  /// @param {jQuery} $els
	  /// @return {jQuery}
	  filter( $els )
	
	  ///
	  /// Przetwarza poszczególne elementy.
	  ///
	  /// @param {jQuery} $els
	  process( $els )
	
	W zależności od modułu niektóre z powyższych nie będą wykorzystywane. Zaleca
	się oznaczanie pustych definicji funkcji za pomocą `$.noop`.
	
	Zasada działania algorytmu:
	
	1. wyszukaj elementy HTML, które mają atrybut `class="ll-script"`
	2. w znalezionych elementach znajdź atrybut(y) `class="ll-script-<jakaś-nazwa>"`
	3. znajdź moduł(y) "ll-script-<jakaś-nazwa>" ("MediaWiki:Gadget-ll-script-<jakaś-nazwa>.js")
	4. uruchom funkcję `testPreconditions` z gadżetu, pomijając dalsze kroki,
	   jeżeli zostanie zwrócona wartość logiczna `false`; skrypty mogą na tym
	   etapie sprawdzić m.in. czy przestrzeń nazw jest odpowiednia; ta funkcja
	   zostanie wywołana tylko raz
	5. uruchom funkcję `initialize` z gadżetu, przeprowadzając wstępną
	   konfigurację skryptu; ta funkcja zostanie wywołana tylko raz
	6. uruchom funkcję `filter` z gadżetu, przekazując jej znalezione elementy;
	   skrypty mogą odrzucić niepasujące elementy za pośrednictwem metod jQuery
	   takich jak `.filter()` albo `.not()`
	7. uruchom funkcję `process` z gadżetu, przekazując jej elementy wynikające
	   z poprzedniego kroku
	
	Algorytm jest wykonywany za każdym razem, gdy zostaje wywołane zdarzenie
	`wikipage.content`, przykładowo w trakcie korzystania z Suwaka Wersji lub
	Live Preview.
	
	Lista obecnie dostępnych skryptów:
	https://pl.wikipedia.org/wiki/Specjalna:Strony_wed%C5%82ug_prefiksu?prefix=Gadget-ll-script&namespace=8
*/

var re,
	prefix = 'll-script',
	loader = prefix + '-loader',
	moduleRegistry = {};

// https://stackoverflow.com/a/1232046/10404307
function clearArray( arr ) {
	arr.length = 0;
}

mw.hook( 'wikipage.content' ).add( function ( $content ) {
	var $els = $content.find( '.' + prefix );
	
	if ( $els.length ) {
		re = re || new RegExp( prefix + '-(\\S+)', 'g' );
		
		$els.each( function ( i, el ) {
			var m, obj, arr;
			
			while ( ( m = re.exec( el.className ) ) !== null ) {
				obj = moduleRegistry[ m[ 1 ] ] || {};
				arr = obj.nodes || [];
				arr.push( el );
				obj.nodes = arr;
				moduleRegistry[ m[ 1 ] ] = obj;
			}
		} );
		
		delete moduleRegistry[ loader ]; // na wszelki wypadek
		
		Object.keys( moduleRegistry ).filter( function ( script ) {
			var nodes = this[ script ].nodes;
			return Array.isArray( nodes ) && nodes.length !== 0;
		}, moduleRegistry ).forEach( function ( script ) {
			var module,
				obj = this[ script ],
				$nodes = $( [] ).add( obj.nodes );
			
			if ( obj.hasOwnProperty( 'exports' ) ) {
				if ( obj.load ) {
					$nodes = obj.exports.filter( $nodes ) || $nodes;
					
					if ( $nodes.length ) {
						obj.exports.process( $nodes );
					}
				}
				
				clearArray( obj.nodes );
			} else {
				module = mw.format( 'ext.gadget.$1-$2', prefix, script );
				
				if ( mw.loader.getModuleNames().indexOf( module ) !== -1 ) {
					mw.loader.using( module ).done( function ( require ) {
						obj.exports = require( module );
						obj.load = obj.exports.testPreconditions() !== false;
						
						if ( obj.load ) {
							obj.exports.initialize();
							
							$nodes = obj.exports.filter( $nodes ) || $nodes;
							
							if ( $nodes.length ) {
								obj.exports.process( $nodes );
							}
						}
						
						clearArray( obj.nodes );
					} );
				} else {
					clearArray( obj.nodes );
				}
			}
		}, moduleRegistry );
	}
} );