User:Nw520/SummaryFloskeln.js

From Meta, a Wikimedia project coordination wiki

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)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
$.when( mw.loader.using( 'mediawiki.util' ), $.ready ).then( function () {
	function main() {
		if( [ 'edit', 'submit' ].includes( mw.config.get('wgAction') ) ) {
			mw.util.addCSS( `.nw520-summaryfloskeln {
				background-color: #f0f2f7;
				border: 1px solid #c8ccd1;
				border-top: 0;
				margin: 0;
				padding: .3em 1em;
			}
			.nw520-summaryfloskeln-group {
				display: inline;
				margin-left: 0;
			}
			.nw520-summaryfloskeln-group:not(:last-child) {
				margin-right: .8em;
			}
			.nw520-summaryfloskeln-grouplabel {
				font-weight: bold;
			}
			.nw520-summaryfloskeln-item {
				display: inline-block;
				margin-left: .3em;
				list-style: none;
			}
			.nw520-summaryfloskeln-item:not(:last-child)::after {
				content: ',';
			}` );
			const $container = createContainer( window.nw520_config?.summaryFloskeln_floskeln ?? null );
			$( '.editOptions' ).before( $container );
		}
	}

	/**
	 * c.f. User:Nw520/AutoReplace.js
	 *
	 * @param {string} text
	 * @param {string} group
	 */
	function appendSummary( text, group ) {
		let summaryValue = document.forms.editform.wpSummary.value;
		const groups = {};

		// Parse
		let section = null;
		const sectionParts = summaryValue.match( /^\/\* (?<section>[^*]+) \*\/(?: *)(?<summaryValue>.*)$/ );
		if ( sectionParts !== null ) {
			section = sectionParts.groups.section;
			summaryValue = sectionParts.groups.summaryValue;
		}

		for ( let groupSegment of summaryValue.split( '; ' ).filter( ( segment ) => segment !== '' ) ) {
			let groupName;
			const groupParts = groupSegment.match( /^(?<group>.+?): (?<text>.+?)$/ );
			if ( groupParts === null ) {
				groupName = groupSegment;
				groupSegment = '';
			} else {
				groupName = groupParts.groups.group;
				groupSegment = groupParts.groups.text;
			}

			if ( groups[ groupName ] === undefined ) {
				groups[ groupName ] = [];
			}
			groups[ groupName ] = [ ...groups[ groupName ], ...groupSegment.split( ', ' ).filter( ( segment ) => segment !== '' ) ];
		}

		// Append
		if ( groups[ group ?? text ] === undefined ) {
			groups[ group ?? text ] = [];
		}
		if ( group !== null && !groups[ group ].includes( text ) ) {
			groups[ group ].push( text );
		}

		// Stringify
		const newSummary = `${section === null ? '' : `/* ${section} */ `}${Object.entries( groups ).map( ( [ groupName, groupValues ] ) => {
			const valueDelimiter = groupName === '' ? '; ' : ', ';

			if ( groupValues.length === 0 ) {
				return `${groupName}`;
			} else {
				return `${groupName}: ${groupValues.join( valueDelimiter )}`;
			}
		} ).join( '; ' )}`;

		document.forms.editform.wpSummary.value = newSummary;
	}

	function createContainer( snippets ) {
		const $container = $( '<ul class="nw520-summaryfloskeln"></ul>' );
		snippets.forEach( function( groupSpec ) {
			$container.append( createGroup( groupSpec ) );
		} );
		return $container;
	}

	function createGroup( groupSpec ) {
		var label;
		var items;

		if( Array.isArray( groupSpec ) && groupSpec.length == 2 ) {
			label = groupSpec[0];
			items = groupSpec[1];
		} else if( Array.isArray( groupSpec ) ) {
			label = null;
			items = groupSpec;
		} else {
			mw.log.error( 'Invalid group specification: ', groupSpec );
			throw 'Invalid group specification';
		}

		items = items.map( item => createItem( item ) );

		const $group = $( '<ul class="nw520-summaryfloskeln-group"></ul>' );
		if ( label !== null ) {
			$group.append( $( '<span class="nw520-summaryfloskeln-grouplabel"></span>' ).text( label ) );
		}
		items.forEach( function( item ) {
			$group.append( item );
		} );

		return $group;
	}

	function createItem( itemSpec ) {
		var label;
		var value;

		if( Array.isArray( itemSpec ) && itemSpec.length == 2 ) {
			label = itemSpec[0];
			value = itemSpec[1];
		} else if( typeof itemSpec === 'string' ) {
			label = itemSpec;
			value = itemSpec;
		} else {
			mw.log.error( 'Invalid item specification: ', itemSpec );
			throw 'Invalid item specification';
		}

		const $link = $( '<a href="#"></a>' ).text( label );
		return $( '<li class="nw520-summaryfloskeln-item"></li>' ).append( $link ).on( 'click', async ( e ) => {
			e.preventDefault();
			
			let summary = null;
			let group = null;
			if ( typeof value === 'function' ) {
				summary = await Promise.resolve( value() );
			} else if ( Array.isArray( value ) && value.length == 2 ) {
				group = value[ 0 ];
				summary = value[ 1 ];
			} else {
				summary = value;
			}
			
			if ( ( summary ?? null ) === null ) {
				return;
			}

			appendSummary( summary, group );
			$( '#wpSummary' ).focus();
		} );
	}

	main();
} );