|
|
| Line 1: |
Line 1: |
| /* Patch Formatter */
| |
| ( function () {
| |
| 'use strict';
| |
|
| |
|
| var L = '{' + '{';
| |
| var R = '}' + '}';
| |
|
| |
| // ---- CONFIG ---------------------------------------------------------
| |
| var GAME_MODE_SECTIONS = [ 'Street Brawl' ];
| |
|
| |
| var WIKI_LINKS = [
| |
| [ /(?<!\w)Urn(?!\w)/g, '[[Urn]]' ],
| |
| [ /(?<!\w)parry(?!\w)/g, '[[Parry|parry]]' ]
| |
| ];
| |
|
| |
| var CHANGE_PREFIX = '';
| |
|
| |
| // ---- API ------------------------------------------------------------
| |
| function getWikiData( templateName ) {
| |
|
| |
| var api = new mw.Api();
| |
| var text = L + '#invoke:MonsterDomosed/patchformatter|' + templateName + R;
| |
|
| |
| return api.get( {
| |
| action: 'expandtemplates',
| |
| text: text,
| |
| prop: 'wikitext',
| |
| format: 'json',
| |
| formatversion: 2
| |
| } ).then( function ( data ) {
| |
|
| |
| var wikitext = ( data.expandtemplates && data.expandtemplates.wikitext ) || '';
| |
|
| |
| return wikitext.split( ',' )
| |
| .map( function ( item ) {
| |
| return item.trim().replace( /^'+|'+$/g, '' );
| |
| } )
| |
| .filter( Boolean );
| |
| } );
| |
| }
| |
|
| |
| // ---- PARSING --------------------------------------------------------
| |
| function parseEntries( rawText ) {
| |
|
| |
| var entries = [];
| |
| var current = null;
| |
|
| |
| rawText.split( '\n' ).forEach( function ( line ) {
| |
|
| |
| var stripped = line.trim();
| |
|
| |
| if ( stripped.indexOf( '-' ) === 0 ) {
| |
|
| |
| if ( current !== null ) {
| |
| entries.push( current );
| |
| }
| |
|
| |
| current = stripped.slice( 1 ).trim();
| |
|
| |
| } else if ( current !== null ) {
| |
|
| |
| current += ' ' + stripped;
| |
| }
| |
| } );
| |
|
| |
| if ( current !== null ) {
| |
| entries.push( current );
| |
| }
| |
|
| |
| return entries.map( function ( e ) {
| |
|
| |
| return e.replace( /\s+/g, ' ' ).trim();
| |
|
| |
| } ).filter( Boolean );
| |
| }
| |
|
| |
| // ---- CLASSIFY -------------------------------------------------------
| |
| function classify( entry, heroes, items, gameModes ) {
| |
|
| |
| var idx = entry.indexOf( ':' );
| |
|
| |
| if ( idx !== -1 ) {
| |
|
| |
| var prefix = entry.slice( 0, idx ).trim();
| |
| var rest = entry.slice( idx + 1 ).trim();
| |
|
| |
| if ( gameModes.indexOf( prefix ) !== -1 ) {
| |
| return [ 'mode', prefix, rest ];
| |
| }
| |
|
| |
| if ( heroes.indexOf( prefix ) !== -1 ) {
| |
| return [ 'hero', prefix, rest ];
| |
| }
| |
|
| |
| if ( items.indexOf( prefix ) !== -1 ) {
| |
| return [ 'item', prefix, rest ];
| |
| }
| |
| }
| |
|
| |
| return [ 'general', null, entry ];
| |
| }
| |
|
| |
| // ---- FORMAT BODY ----------------------------------------------------
| |
| function escapeRegExp( s ) {
| |
| return s.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
| |
| }
| |
|
| |
| function formatBody( text, heroes, abilities, items ) {
| |
|
| |
| var protectedTokens = [];
| |
|
| |
| function protect( value ) {
| |
| var token = '\u0000' + protectedTokens.length + '\u0000';
| |
| protectedTokens.push( value );
| |
| return token;
| |
| }
| |
|
| |
| function wrap( terms, template ) {
| |
|
| |
| terms.slice()
| |
| .sort( function ( a, b ) {
| |
| return b.length - a.length;
| |
| } )
| |
| .forEach( function ( term ) {
| |
|
| |
| var pattern = new RegExp(
| |
| '(?<!\\w)' + escapeRegExp( term ) + '(?!\\w)',
| |
| 'g'
| |
| );
| |
|
| |
| text = text.replace( pattern, function () {
| |
| return protect(
| |
| template.replace( '%s', term )
| |
| );
| |
| } );
| |
| } );
| |
| }
| |
|
| |
| wrap( abilities, L + 'AbilityIcon|%s' + R );
| |
| wrap( items, L + 'ItemIcon|%s' + R );
| |
| wrap( heroes, L + 'HeroIcon|%s' + R );
| |
|
| |
| WIKI_LINKS.forEach( function ( pair ) {
| |
| text = text.replace( pair[ 0 ], function () {
| |
| return protect( pair[ 1 ] );
| |
| } );
| |
| } );
| |
|
| |
| for ( var i = 0; i < protectedTokens.length; i++ ) {
| |
| text = text.split( '\u0000' + i + '\u0000' ).join( protectedTokens[ i ] );
| |
| }
| |
|
| |
| return text;
| |
| }
| |
|
| |
| // ---- OUTPUT ---------------------------------------------------------
| |
| function buildOutput( entries, heroes, abilities, items, gameModes ) {
| |
|
| |
| var general = [];
| |
| var modes = {}, modeOrder = [];
| |
| var itemSections = {}, itemOrder = [];
| |
| var heroSections = {}, heroOrder = [];
| |
|
| |
| entries.forEach( function ( entry ) {
| |
|
| |
| var c = classify( entry, heroes, items, gameModes );
| |
| var kind = c[ 0 ];
| |
| var name = c[ 1 ];
| |
| var body = formatBody( c[ 2 ], heroes, abilities, items );
| |
|
| |
| if ( kind === 'general' ) {
| |
|
| |
| general.push( body );
| |
|
| |
| } else if ( kind === 'mode' ) {
| |
|
| |
| if ( !modes[ name ] ) {
| |
| modes[ name ] = [];
| |
| modeOrder.push( name );
| |
| }
| |
|
| |
| modes[ name ].push( body );
| |
|
| |
| } else if ( kind === 'item' ) {
| |
|
| |
| if ( !itemSections[ name ] ) {
| |
| itemSections[ name ] = [];
| |
| itemOrder.push( name );
| |
| }
| |
|
| |
| itemSections[ name ].push( body );
| |
|
| |
| } else if ( kind === 'hero' ) {
| |
|
| |
| if ( !heroSections[ name ] ) {
| |
| heroSections[ name ] = [];
| |
| heroOrder.push( name );
| |
| }
| |
|
| |
| heroSections[ name ].push( body );
| |
| }
| |
| } );
| |
|
| |
| var out = [];
| |
|
| |
| // General
| |
| general.forEach( function ( entry ) {
| |
| out.push( '* ' + entry );
| |
| } );
| |
|
| |
| // Modes
| |
| modeOrder.forEach( function ( mode ) {
| |
|
| |
| out.push( '' );
| |
| out.push( '== [[' + mode + ']] ==' );
| |
|
| |
| modes[ mode ].forEach( function ( body ) {
| |
| out.push( '* ' + body );
| |
| } );
| |
| } );
| |
|
| |
| // Items
| |
| if ( itemOrder.length ) {
| |
|
| |
| out.push( '' );
| |
| out.push( '== Items ==' );
| |
|
| |
| itemOrder.forEach( function ( item ) {
| |
|
| |
| out.push( '=== ' + L + 'ItemIcon|' + item + R + ' ===' );
| |
|
| |
| itemSections[ item ].forEach( function ( body ) {
| |
| out.push( '* ' + body );
| |
| out.push( '' );
| |
| } );
| |
| } );
| |
| }
| |
|
| |
| // Heroes
| |
| if ( heroOrder.length ) {
| |
|
| |
| out.push( '' );
| |
| out.push( '== Heroes ==' );
| |
|
| |
| heroOrder.forEach( function ( hero ) {
| |
|
| |
| out.push( '=== ' + L + 'HeroIcon|' + hero + R + ' ===' );
| |
|
| |
| heroSections[ hero ].forEach( function ( body ) {
| |
| out.push( '* ' + body );
| |
| out.push( '' );
| |
| } );
| |
| } );
| |
| }
| |
|
| |
| return out.join( '\n' ).trim() + '\n';
| |
| }
| |
|
| |
| // ---- INIT -----------------------------------------------------------
| |
| function init() {
| |
|
| |
| var app = document.getElementById( 'patchformatter' );
| |
|
| |
| if ( !app ) {
| |
| return;
| |
| }
| |
|
| |
| var inputWidget = new OO.ui.MultilineTextInputWidget( {
| |
| rows: 14,
| |
| placeholder: 'Raw patch notes'
| |
| } );
| |
|
| |
| var outputWidget = new OO.ui.MultilineTextInputWidget( {
| |
| rows: 20,
| |
| readOnly: true
| |
| } );
| |
|
| |
| var formatButton = new OO.ui.ButtonWidget( {
| |
| label: 'Format',
| |
| flags: [ 'primary', 'progressive' ]
| |
| } );
| |
|
| |
| var copyButton = new OO.ui.ButtonWidget( {
| |
| label: 'Copy output'
| |
| } );
| |
|
| |
| var status = new OO.ui.LabelWidget();
| |
|
| |
| var container = document.createElement( 'div' );
| |
|
| |
| container.appendChild( inputWidget.$element[ 0 ] );
| |
| container.appendChild( formatButton.$element[ 0 ] );
| |
| container.appendChild( copyButton.$element[ 0 ] );
| |
| container.appendChild( status.$element[ 0 ] );
| |
| container.appendChild( outputWidget.$element[ 0 ] );
| |
|
| |
| app.appendChild( container );
| |
|
| |
| formatButton.on( 'click', function () {
| |
|
| |
| status.setLabel( 'Loading...' );
| |
|
| |
| Promise.all( [
| |
| getWikiData( 'get_released_heroes_list' ),
| |
| getWikiData( 'get_all_released_item_names' ),
| |
| getWikiData( 'get_all_released_abilities_list' )
| |
| ] ).then( function ( lists ) {
| |
|
| |
| var heroes = lists[ 0 ];
| |
| var items = lists[ 1 ];
| |
| var abilities = lists[ 2 ];
| |
|
| |
| var entries = parseEntries( inputWidget.getValue() );
| |
|
| |
| var result = buildOutput(
| |
| entries,
| |
| heroes,
| |
| abilities,
| |
| items,
| |
| GAME_MODE_SECTIONS
| |
| );
| |
|
| |
| outputWidget.setValue( result );
| |
|
| |
| status.setLabel('Done');
| |
|
| |
| } ).catch( function ( e ) {
| |
|
| |
| status.setLabel( 'Error' );
| |
|
| |
| } );
| |
| } );
| |
|
| |
| copyButton.on( 'click', function () {
| |
|
| |
| navigator.clipboard.writeText(
| |
| outputWidget.getValue()
| |
| );
| |
|
| |
| status.setLabel( 'Copied' );
| |
| } );
| |
| }
| |
|
| |
| mw.loader.using( [
| |
| 'oojs-ui-core',
| |
| 'oojs-ui-widgets',
| |
| 'mediawiki.api',
| |
| 'mediawiki.util'
| |
| ] ).then( function () {
| |
| init();
| |
| } );
| |
|
| |
| }() );
| |
|
| |
|
|
| |
|