Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

MediaWiki:Common.js

MediaWiki interface page
Revision as of 14:04, 27 June 2026 by Palindromayd (talk | contribs)

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
( function () {
	'use strict';

	/* ---------- Live auto-updating grid (Platforms, Countries, Cities, etc.) ---------- */

	function renderAutoGrid( $container ) {
		var category = $container.data( 'category' );
		if ( !category ) {
			return;
		}

		$container.text( 'Loading...' );

		mw.loader.using( 'mediawiki.api' ).then( function () {
			return new mw.Api().get( {
				action: 'query',
				list: 'categorymembers',
				cmtitle: 'Category:' + category,
				cmlimit: 500,
				cmsort: 'sortkey',
				format: 'json'
			} );
		} ).then( function ( data ) {
			var members = ( data.query && data.query.categorymembers ) || [];
			$container.empty();

			if ( members.length === 0 ) {
				$container.append( $( '<p>' ).text( 'Nothing has been added here yet.' ) );
				return;
			}

			members.forEach( function ( member ) {
				var title = member.title;
				var displayName = title.split( ':' ).slice( 1 ).join( ':' ).split( '/' ).pop();
				var $link = $( '<a>' )
					.attr( 'href', mw.util.getUrl( title ) )
					.text( displayName );
				$container.append( $link );
			} );
		}, function () {
			$container.text( 'Could not load this list right now.' );
		} );
	}

	/* ---------- Instant-create forms (Country, City, Person, Case) ---------- */

	function fallbackToManualEditor( newTitle, preloadTitle, $status ) {
		$status.text( ' Opening the normal editor instead...' );
		window.location.href = mw.util.getUrl( newTitle, { action: 'edit', preload: preloadTitle } );
	}

	function safeReplacement( str ) {
		// Prevents literal "$" sequences a user types from being
		// misread as regex backreferences by String.replace().
		return str.replace( /\$/g, '$$$$' );
	}

	function applyExtraFields( rawText, fields ) {
		var text = rawText;

		if ( fields.image ) {
			text = text.replace( /\|image(\s*)=\s*\n/, function ( match, spacing ) {
				return '|image' + spacing + '= ' + safeReplacement( fields.image ) + '\n';
			} );
		}

		if ( fields.evidence ) {
			text = text.replace( '<Add Picture Here>', safeReplacement( fields.evidence ) );
		}

		if ( fields.description ) {
			text = text.replace( '<Write Text Here>', safeReplacement( fields.description ) );
		}

		return text;
	}

	function runInstantCreate( newTitle, preloadTitle, fields, $status ) {
		$status.text( ' Creating...' );

		mw.loader.using( 'mediawiki.api' ).then( function () {
			var api = new mw.Api();

			api.get( {
				action: 'query',
				titles: newTitle,
				format: 'json'
			} ).then( function ( data ) {
				var pages = data.query.pages;
				var exists = false;
				for ( var id in pages ) {
					if ( !pages[ id ].missing ) {
						exists = true;
					}
				}

				if ( exists ) {
					$status.text( ' Already exists, opening it...' );
					window.location.href = mw.util.getUrl( newTitle );
					return;
				}

				api.get( {
					action: 'query',
					titles: preloadTitle,
					prop: 'revisions',
					rvprop: 'content',
					rvslots: 'main',
					format: 'json'
				} ).then( function ( tplData ) {
					var tplPages = tplData.query.pages;
					var rawText = '';
					for ( var id in tplPages ) {
						var revs = tplPages[ id ].revisions;
						if ( revs && revs[ 0 ] && revs[ 0 ].slots && revs[ 0 ].slots.main ) {
							rawText = revs[ 0 ].slots.main[ '*' ];
						}
					}

					var finalText = applyExtraFields( rawText, fields );

					api.postWithToken( 'csrf', {
						action: 'edit',
						title: newTitle,
						text: finalText,
						createonly: true,
						summary: 'Auto-created'
					} ).then( function ( editResult ) {
						if ( editResult && editResult.edit && editResult.edit.result === 'Success' ) {
							window.location.href = mw.util.getUrl( newTitle );
						} else {
							fallbackToManualEditor( newTitle, preloadTitle, $status );
						}
					}, function () {
						fallbackToManualEditor( newTitle, preloadTitle, $status );
					} );
				}, function () {
					fallbackToManualEditor( newTitle, preloadTitle, $status );
				} );
			}, function () {
				fallbackToManualEditor( newTitle, preloadTitle, $status );
			} );
		} );
	}

	function buildForm( $container ) {
		var prefix = $container.data( 'prefix' );
		var preloadTitle = $container.data( 'preload' );
		var placeholder = $container.data( 'placeholder' ) || 'Enter a name';
		var buttonLabel = $container.data( 'buttonlabel' ) || 'Add';
		var extraFieldsRaw = $container.data( 'extrafields' ) || '';

		var $input = $( '<input>' ).attr( 'type', 'text' ).attr( 'placeholder', placeholder ).css( 'width', '100%' ).css( 'margin-bottom', '6px' );
		var $wrapper = $( '<div>' ).append( $input );

		var extraInputs = {};
		if ( extraFieldsRaw ) {
			extraFieldsRaw.split( ';' ).forEach( function ( pair ) {
				var parts = pair.split( ':' );
				var key = $.trim( parts[ 0 ] );
				var label = $.trim( parts[ 1 ] || key );
				var $extra;
				if ( key === 'description' ) {
					$extra = $( '<textarea>' ).attr( 'placeholder', label ).attr( 'rows', 3 ).css( 'width', '100%' ).css( 'margin-bottom', '6px' );
				} else {
					$extra = $( '<input>' ).attr( 'type', 'text' ).attr( 'placeholder', label ).css( 'width', '100%' ).css( 'margin-bottom', '6px' );
				}
				extraInputs[ key ] = $extra;
				$wrapper.append( $( '<div>' ).append( $extra ) );
			} );
		}

		var $button = $( '<button>' ).text( buttonLabel );
		var $status = $( '<span>' ).addClass( 'gar-instant-status' );
		$wrapper.append( $button, ' ', $status );

		$container.empty().append( $wrapper );

		$button.on( 'click', function () {
			var name = $.trim( $input.val() );
			if ( !name ) {
				return;
			}
			var fields = {};
			for ( var key in extraInputs ) {
				fields[ key ] = $.trim( extraInputs[ key ].val() );
			}
			runInstantCreate( prefix + name, preloadTitle, fields, $status );
		} );
	}

	/* ---------- Wire everything up once the page content is ready ---------- */

	mw.hook( 'wikipage.content' ).add( function ( $content ) {
		$content.find( '.gar-auto-grid' ).each( function () {
			renderAutoGrid( $( this ) );
		} );
		$content.find( '.gar-instant-create' ).each( function () {
			buildForm( $( this ) );
		} );
	} );
}() );