User:Monster Domosed/common.js: Difference between revisionsGive feedback
No edit summary |
No edit summary |
||
| Line 2: | Line 2: | ||
( function () { | ( function () { | ||
'use strict'; | 'use strict'; | ||
console.log('[PatchFormatter] script loaded'); | |||
var L = '{' + '{'; | var L = '{' + '{'; | ||
| Line 18: | Line 20: | ||
// ---- API ------------------------------------------------------------ | // ---- API ------------------------------------------------------------ | ||
function getWikiData( templateName ) { | function getWikiData( templateName ) { | ||
console.log('[PatchFormatter] getWikiData called:', templateName); | |||
var api = new mw.Api(); | var api = new mw.Api(); | ||
var text = L + '#invoke:MonsterDomosed/patchformatter|' + templateName + R; | var text = L + '#invoke:MonsterDomosed/patchformatter|' + templateName + R; | ||
return api.get( { | return api.get( { | ||
action: 'expandtemplates', | action: 'expandtemplates', | ||
| Line 27: | Line 32: | ||
formatversion: 2 | formatversion: 2 | ||
} ).then( function ( data ) { | } ).then( function ( data ) { | ||
console.log('[PatchFormatter] API response:', templateName, data); | |||
var wikitext = ( data.expandtemplates && data.expandtemplates.wikitext ) || ''; | var wikitext = ( data.expandtemplates && data.expandtemplates.wikitext ) || ''; | ||
.map( function ( item ) { return item.trim().replace( /^'+|'+$/g, '' ); } ) | var result = wikitext.split( ',' ) | ||
.filter( function ( item ) { return item.length > 0; } ); | .map( function ( item ) { | ||
return item.trim().replace( /^'+|'+$/g, '' ); | |||
} ) | |||
.filter( function ( item ) { | |||
return item.length > 0; | |||
} ); | |||
console.log('[PatchFormatter] parsed list:', templateName, result.length); | |||
return result; | |||
} ); | } ); | ||
} | } | ||
| Line 36: | Line 53: | ||
// ---- PARSING -------------------------------------------------------- | // ---- PARSING -------------------------------------------------------- | ||
function parseEntries( rawText ) { | function parseEntries( rawText ) { | ||
console.log('[PatchFormatter] parseEntries input size:', rawText.length); | |||
var entries = []; | var entries = []; | ||
var current = null; | var current = null; | ||
rawText.split( '\n' ).forEach( function ( line ) { | rawText.split( '\n' ).forEach( function ( line ) { | ||
var stripped = line.trim(); | var stripped = line.trim(); | ||
if ( stripped.indexOf( '-' ) === 0 ) { | if ( stripped.indexOf( '-' ) === 0 ) { | ||
if ( current !== null ) { entries.push( current ); } | if ( current !== null ) { | ||
entries.push( current ); | |||
} | |||
current = stripped.slice( 1 ).trim(); | current = stripped.slice( 1 ).trim(); | ||
} else if ( current !== null ) { | } else if ( current !== null ) { | ||
| Line 47: | Line 70: | ||
} | } | ||
} ); | } ); | ||
if ( current !== null ) { | |||
.map( function ( e ) { return e.replace( /\s+/g, ' ' ).trim(); } ) | entries.push( current ); | ||
.filter( function ( e ) { return e.length > 0; } ); | } | ||
var cleaned = entries | |||
.map( function ( e ) { | |||
return e.replace( /\s+/g, ' ' ).trim(); | |||
} ) | |||
.filter( function ( e ) { | |||
return e.length > 0; | |||
} ); | |||
console.log('[PatchFormatter] parsed entries:', cleaned.length); | |||
return cleaned; | |||
} | } | ||
// ---- CLASSIFY ------------------------------------------------------- | |||
function classify( entry, heroes, items, gameModes ) { | function classify( entry, heroes, items, gameModes ) { | ||
var idx = entry.indexOf( ':' ); | var idx = entry.indexOf( ':' ); | ||
if ( idx !== -1 ) { | if ( idx !== -1 ) { | ||
var prefix = entry.slice( 0, idx ).trim(); | var prefix = entry.slice( 0, idx ).trim(); | ||
var rest = entry.slice( idx + 1 ).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 ( gameModes.indexOf( prefix ) !== -1 ) { | ||
if ( items.indexOf( prefix ) !== -1 ) { return [ 'item', prefix, rest ]; } | 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 ]; | return [ 'general', null, entry ]; | ||
} | } | ||
// ---- | // ---- FORMAT BODY ---------------------------------------------------- | ||
function escapeRegExp( s ) { | function escapeRegExp( s ) { | ||
return s.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ); | return s.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' ); | ||
| Line 81: | Line 125: | ||
function wrap( terms, template ) { | function wrap( terms, template ) { | ||
terms.slice().sort( function ( a, b ) { return b.length - a.length; } ) | 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', function () { | |||
return term; | |||
} ) ); | |||
} ); | } ); | ||
} ); | |||
} | } | ||
| Line 95: | Line 144: | ||
WIKI_LINKS.forEach( function ( pair ) { | WIKI_LINKS.forEach( function ( pair ) { | ||
text = text.replace( pair[ 0 ], function () { return protect( pair[ 1 ] ); } ); | text = text.replace( pair[ 0 ], function () { | ||
return protect( pair[ 1 ] ); | |||
} ); | |||
} ); | } ); | ||
| Line 101: | Line 152: | ||
text = text.split( '\u0000' + i + '\u0000' ).join( protectedTokens[ i ] ); | text = text.split( '\u0000' + i + '\u0000' ).join( protectedTokens[ i ] ); | ||
} | } | ||
return text; | return text; | ||
} | } | ||
// ---- OUTPUT | // ---- OUTPUT --------------------------------------------------------- | ||
function buildOutput( entries, heroes, abilities, items, gameModes ) { | function buildOutput( entries, heroes, abilities, items, gameModes ) { | ||
console.log('[PatchFormatter] buildOutput start'); | |||
var general = []; | var general = []; | ||
var modes = {}, modeOrder = []; | var modes = {}, modeOrder = []; | ||
| Line 113: | Line 167: | ||
entries.forEach( function ( entry ) { | entries.forEach( function ( entry ) { | ||
var c = classify( entry, heroes, items, gameModes ); | var c = classify( entry, heroes, items, gameModes ); | ||
var kind = c[ 0 ] | |||
var kind = c[ 0 ]; | |||
var name = c[ 1 ]; | |||
var body = formatBody( c[ 2 ], heroes, abilities, items ); | var body = formatBody( c[ 2 ], heroes, abilities, items ); | ||
| Line 119: | Line 175: | ||
general.push( body ); | general.push( body ); | ||
} else if ( kind === 'mode' ) { | } else if ( kind === 'mode' ) { | ||
if ( !modes[ name ] ) { modes[ name ] = []; modeOrder.push( name ); } | if ( !modes[ name ] ) { | ||
modes[ name ] = []; | |||
modeOrder.push( name ); | |||
} | |||
modes[ name ].push( body ); | modes[ name ].push( body ); | ||
} else if ( kind === 'item' ) { | } else if ( kind === 'item' ) { | ||
if ( !itemSections[ name ] ) { itemSections[ name ] = []; itemOrder.push( name ); } | if ( !itemSections[ name ] ) { | ||
itemSections[ name ] = []; | |||
itemOrder.push( name ); | |||
} | |||
itemSections[ name ].push( body ); | itemSections[ name ].push( body ); | ||
} else if ( kind === 'hero' ) { | } else if ( kind === 'hero' ) { | ||
if ( !heroSections[ name ] ) { heroSections[ name ] = []; heroOrder.push( name ); } | if ( !heroSections[ name ] ) { | ||
heroSections[ name ] = []; | |||
heroOrder.push( name ); | |||
} | |||
heroSections[ name ].push( body ); | heroSections[ name ].push( body ); | ||
} | } | ||
| Line 132: | Line 197: | ||
var out = []; | var out = []; | ||
general.forEach( function ( entry ) { | general.forEach( function ( entry ) { | ||
out.push( '* ' + entry ); | |||
} ); | } ); | ||
console.log('[PatchFormatter] sections ready'); | |||
return out.join( '\n' ).trim() + '\n'; | return out.join( '\n' ).trim() + '\n'; | ||
| Line 166: | Line 208: | ||
// ---- UI ------------------------------------------------------------- | // ---- UI ------------------------------------------------------------- | ||
function init() { | function init() { | ||
console.log('[PatchFormatter] init started'); | |||
var app = document.getElementById( 'patchformatter' ); | var app = document.getElementById( 'patchformatter' ); | ||
var inputWidget = new OO.ui.MultilineTextInputWidget( { | if ( !app ) { | ||
console.error('[PatchFormatter] #patchformatter not found'); | |||
return; | |||
} | |||
console.log('[PatchFormatter] container found'); | |||
console.log('[PatchFormatter] OO check:', OO, OO && OO.ui); | |||
try { | |||
var inputWidget = new OO.ui.MultilineTextInputWidget( { | |||
rows: 14, | |||
placeholder: 'Raw patch notes', | |||
autofocus: true | |||
} ); | |||
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', | |||
flags: [ 'progressive' ] | |||
} ); | |||
var statusLabel = new OO.ui.LabelWidget( { | |||
label: '' | |||
} ); | |||
console.log('[PatchFormatter] widgets created'); | |||
var buttonRow = new OO.ui.HorizontalLayout( { | |||
items: [ formatButton, copyButton, statusLabel ] | |||
} ); | |||
var fieldset = new OO.ui.FieldsetLayout(); | |||
fieldset.$element.append( buttonRow.$element ); | |||
app.appendChild( fieldset.$element[ 0 ] ); | |||
console.log('[PatchFormatter] UI mounted'); | |||
formatButton.on( 'click', function () { | |||
console.log('[PatchFormatter] format clicked'); | |||
formatButton.setDisabled( true ); | |||
statusLabel.setLabel( 'Loading wiki data...' ); | |||
Promise.all( [ | |||
getWikiData( 'get_released_heroes_list' ), | getWikiData( 'get_released_heroes_list' ), | ||
getWikiData( 'get_all_released_item_names' ), | getWikiData( 'get_all_released_item_names' ), | ||
getWikiData( 'get_all_released_abilities_list' ) | getWikiData( 'get_all_released_abilities_list' ) | ||
] ); | ] ).then( function ( lists ) { | ||
console.log('[PatchFormatter] lists loaded'); | |||
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 ); | |||
statusLabel.setLabel( 'Done' ); | |||
} ).catch( function ( err ) { | |||
console.error('[PatchFormatter] ERROR:', err); | |||
statusLabel.setLabel( 'Error: ' + err ); | |||
} ).then( function () { | |||
formatButton.setDisabled( false ); | |||
} ); | |||
} ); | } ); | ||
copyButton.on( 'click', function () { | |||
console.log('[PatchFormatter] copy clicked'); | |||
navigator.clipboard.writeText( outputWidget.getValue() ).then( function () { | |||
statusLabel.setLabel( 'Copied | navigator.clipboard.writeText( | ||
outputWidget.getValue() | |||
).then( function () { | |||
statusLabel.setLabel( 'Copied' ); | |||
} ); | } ); | ||
} | } ); | ||
} catch ( e ) { | |||
console.error('[PatchFormatter] INIT CRASH:', e); | |||
} | |||
} | |||
} | } | ||
mw.loader.using( [ | |||
'oojs-ui-core', | 'oojs-ui-core', | ||
'oojs-ui-widgets', | 'oojs-ui-widgets', | ||
'oojs-ui.styles', | 'oojs-ui.styles', | ||
'mediawiki.api', | 'mediawiki.api', | ||
'mediawiki.util' | 'mediawiki.util' | ||
]).then( function () { | ] ).then( function () { | ||
console.log('[PatchFormatter] loader ready'); | |||
$( init ); | |||
} ); | |||
}() ); | |||