MediaWiki:Gadget-translation-editor.js: Różnice pomiędzy wersjami
Wygląd
Usunięta treść Dodana treść
staroegipski w sumie jest OK, tez powiela strukture '(1.1) tlumaczenie', mimo ze wewnatrz czasem umieszczany jest plik |
jedyny pewny sposob na odswiezenie strony to location.reload(); calkowicie wylaczam gadzet w trybie podgladu (diff), aby unikac koniecznosci parsowania URL |
||
Linia 66: | Linia 66: | ||
'wgRevisionId', |
'wgRevisionId', |
||
'wgCurRevisionId', |
'wgCurRevisionId', |
||
'wgArticleId' |
'wgArticleId', |
||
'wgDiffNewId', |
|||
'wgDiffOldId' |
|||
] ); |
] ); |
||
Linia 883: | Linia 885: | ||
gui.$submit.attr( 'value', mw.msg( 'transl-reloading' ) ); |
gui.$submit.attr( 'value', mw.msg( 'transl-reloading' ) ); |
||
mw.cookie.set( cookieKey, 'saved', postEditCookieOpts ); |
mw.cookie.set( cookieKey, 'saved', postEditCookieOpts ); |
||
location.reload(); |
|||
} ) |
} ) |
||
.fail( function () { |
.fail( function () { |
||
Linia 1297: | Linia 1299: | ||
config.wgNamespaceNumber === 0 && config.wgAction === 'view' && |
config.wgNamespaceNumber === 0 && config.wgAction === 'view' && |
||
config.wgRevisionId === config.wgCurRevisionId && |
config.wgRevisionId === config.wgCurRevisionId && |
||
config.wgDiffNewId === null && config.wgDiffNewId === null && |
|||
!mw.util.getParamValue( 'printable' ) |
!mw.util.getParamValue( 'printable' ) |
||
) { |
) { |
Wersja z 20:37, 1 gru 2019
var gadget = mw.libs.translationEditor = {};
var PREFERRED_LANG_OPTION_KEY = 'userjs-translation-editor-preferred-lang';
var PREFERRED_LANG_COOKIE = 'TranslationEditorPreferredLang';
var POST_EDIT_COOKIE_KEY = 'PostEditTranslationEditor';
var EDITBOX_TOP_OFFSET = 100;
var EDITBOX_SCROLL_DURATION = 500;
var forbiddenLanguageNames = [ 'polski', 'termin obcy w języku polskim', 'użycie międzynarodowe' ];
var forbiddenLanguageCodes = [];
var forbiddenTranslations = [ 'polski język migowy' ];
var postEditCookieOpts = {
expires: 1200 // za EditPage::POST_EDIT_COOKIE_DURATION w EditPage.php
};
var api = null;
var messages = {
'transl-edit-launcher': '(edytuj)',
'transl-api-error': 'Błąd API. Kod: $1. Komunikat: $2.',
'transl-save-error': 'Prawdopodobnie nastąpił konflikt edycji. Przeładuj stronę i spróbuj ponownie.',
'transl-parse-error': 'Nie udało się odczytać kodu strony. Przejdź na tryb edycji wikikodu i sprawdź, czy nie ma błędów składniowych.',
'transl-validate-error': 'Lista tłumaczeń zawiera niewspierane języki albo błędy składniowe.',
'transl-load-error': 'Istnieje nowsza wersja strony. Przeładuj ją i spróbuj ponownie.',
'transl-invalid-lang': 'Niewspierany język lub wykryto błedy składniowe w wikikodzie.',
'transl-invalid-code': 'Nie rozpoznano kodu języka.',
'transl-select-lang': 'Wybierz język:',
'transl-lang-label': 'Tłumaczysz na<br><strong>$1</strong> <small>(<strong>nieznany kod</strong>)</small>',
'transl-lang-label-iso': 'Tłumaczysz na<br><strong>$1</strong> <small>(<a href="/wiki/Wikis%C5%82ownik:Kody_j%C4%99zyk%C3%B3w" target="_blank">$2</a>)</small>',
'transl-load-button': 'Załaduj',
'transl-save-button': 'Zapamiętaj',
'transl-forget-button': 'Zapomnij',
'transl-save-save': 'Zapisz',
'transl-save-cancel': 'Anuluj',
'transl-prompt-title': 'Ustawienia domyślnego języka',
'transl-save-prompt': 'Język o nazwie „$1” zostanie załadowany domyślnie podczas następnego uruchomienia edytora tłumaczeń.',
'transl-save-current': 'Twoje obecne ustawienie to „$1”.',
'transl-forget-prompt': 'Język o nazwie „$1” przestanie być ładowany domyślnie.',
'transl-save-success': 'Zapisano preferencje.',
'transl-save-fail': 'Wystąpił błąd podczas zapisywania preferencji.',
'transl-preview-label': 'Podgląd zmian',
'transl-apply-button': 'Pokaż zmiany',
'transl-submit-button': 'Zapisz',
'transl-watch-article': 'Obserwuj',
'transl-submitting': 'Zapisywanie',
'transl-reloading': 'Przeładowywanie',
'transl-draft-change': '(przejdź)',
'transl-draft-remove': '(usuń)',
'transl-draft-abort': '(wstrzymaj)',
'transl-keyboard': '(klawiatura ekranowa)',
'transl-keyboard-close': 'Zamknij',
'transl-report-error': '(<a href="//pl.wiktionary.org/w/index.php?title=Dyskusja_wikipedysty:Peter_Bowman&action=edit§ion=new&preloadtitle=Edytor%20t%C5%82umacze%C5%84%20%28b%C5%82%C4%85d%29&nosummary=" target="_blank">zgłoś błąd</a>)',
'transl-help-syntax': '(<a href="//upload.wikimedia.org/wiktionary/pl/1/1d/Edytor_t%C5%82umacze%C5%84_%28sk%C5%82adnia%29.png" target="_blank">składnia</a>)',
'transl-lang-suggest-code': 'Język z kodem <strong>$1</strong>',
'transl-forbidden-lang': 'Brak wsparcia dla języka: $1.',
'transl-confirm-close': 'Masz niezapisane tłumaczenia. Czy na pewno chcesz opuścić stronę?',
'transl-preview-parsing': 'poczekaj, trwa parsowanie wikikodu'
};
var config = mw.config.get( [
'wgPageName',
'wgNamespaceNumber',
'wgAction',
'wgRevisionId',
'wgCurRevisionId',
'wgArticleId',
'wgDiffNewId',
'wgDiffOldId'
] );
function initialize( $content ) {
var $transl, $defs, $buttonHolder;
gadget.activeLang = '';
gadget.drafts = {};
gadget.draftMetadata = {};
gadget.currentRequest = null;
gadget.preferredLang = !mw.user.isAnon()
? mw.user.options.get( PREFERRED_LANG_OPTION_KEY )
: mw.cookie.get( PREFERRED_LANG_COOKIE );
$transl = $content.find( 'dt.lang-pl.fldt-tlumaczenia' ).first();
$defs = $content.find( 'dd.lang-pl.fldt-znaczenia' ).not( ':empty' ).has( '.term-num' );
if ( !$transl.length || !$defs.length ) {
return;
}
gadget.$translList = $transl.parent().next( 'ul' );
$transl
.attr( 'id', 'transl-field' )
.children( '#transl' )
.css( 'display', 'inline' );
$buttonHolder = $( '<div>' )
.attr( 'id', 'transl-buttons' )
.appendTo( $transl );
if ( !!gadget.preferredLang && typeof hideTranslations === 'function' ) {
hideTranslations( gadget.preferredLang );
}
gadget.$defn = $defs.find( '.term-num:first' );
if ( gadget.$defn.length !== $defs.length ) {
return;
}
$( '<small>' )
.text( mw.msg( 'transl-edit-launcher' ) )
.attr( 'id', 'transl-addbutton' )
.attr( 'accesskey', '+' )
.appendTo( $buttonHolder )
.one( 'click', $.proxy( loadEditor, null, $content, $transl ) )
.on( 'click', function () {
var $editbox = $content.find( '#transl-editbox' );
if ( $editbox.length ) {
gadget.$translList.toggle();
$editbox.toggle();
$content.find( '#transl-langselector' ).trigger( 'focus' );
}
} );
$transl.parent().show();
}
function loadEditor( $content, $transl, evt ) {
var $spinner = $.createSpinner( {
size: 'large',
type: 'block'
} ).appendTo( $transl );
makeRequests( function () {
var $editbox = $content.find( '#transl-editbox' );
$spinner.remove();
$editbox.fadeIn();
if ( !$editbox.length ) {
$( '#transl-addbutton' ).hide();
return;
}
gadget.$translList.hide();
if ( $editbox.offset().top - $( window ).scrollTop() > EDITBOX_TOP_OFFSET ) {
$( 'html, body' ).animate( {
scrollTop: $editbox.offset().top - EDITBOX_TOP_OFFSET
}, EDITBOX_SCROLL_DURATION );
}
} );
}
function makeRequests( callback ) {
mw.loader.using( [
'mediawiki.api',
'mediawiki.language.specialCharacters',
'mediawiki.String',
'mediawiki.notify',
'mediawiki.confirmCloseWindow',
'jquery.suggestions',
'jquery.textSelection',
'jquery.ui',
'ext.gadget.langdata',
'ext.gadget.term-preview'
] )
.then( function ( require ) {
mw.libs.String = require( 'mediawiki.String' );
mw.libs.termPreview = require( 'ext.gadget.term-preview' );
mw.libs.specialCharacters = require( 'mediawiki.language.specialCharacters' );
api = new mw.Api();
config.lang2code = mw.config.get( 'lang2code' );
config.code2lang = mw.config.get( 'code2lang' );
$.each( forbiddenLanguageNames, function ( i, lang ) {
if ( lang in config.lang2code ) {
forbiddenLanguageCodes.push( config.lang2code[ lang ] );
}
} );
return api.get( {
formatversion: 2,
prop: 'revisions',
rvprop: [ 'timestamp', 'content', 'ids' ],
rvslots: 'main',
titles: config.wgPageName,
curtimestamp: true
} );
} )
.done( function ( res ) {
var revision = res.query.pages[ 0 ].revisions[ 0 ];
if ( revision.revid !== config.wgCurRevisionId ) {
mw.notify( mw.msg( 'transl-load-error' ), { type: 'error' } );
} else {
gadget.content = revision.slots.main.content;
gadget.starttimestamp = res.curtimestamp;
gadget.basetimestamp = revision.timestamp;
if ( analyzePage() ) {
createMenu();
} else {
mw.notify( mw.msg( 'transl-parse-error' ), { type: 'error' } );
}
}
} )
.done( callback )
.fail( function ( code, details ) {
if ( typeof details === 'object' ) {
details = details.error && details.error.info || details.textStatus || '---';
}
mw.notify( mw.msg( 'transl-api-error', code, details ), { type: 'error' } );
} );
}
function analyzePage() {
var a2, a3, a4, b, translations, langSection, langs, targetLang, targetRow, drafts,
pageContent = gadget.content,
a = pageContent.indexOf( ' ({' + '{język polski' );
if ( a === -1 ) {
a = pageContent.indexOf( ' ({' + '{termin obcy w języku polskim' );
}
if ( a === -1 ) {
return false;
}
b = pageContent.indexOf( '\n== ', a );
b = ( b !== -1 ) ? b : pageContent.length;
langSection = pageContent.slice( 0, b );
a2 = langSection.indexOf( '{' + '{tłumaczenia}}\n', a );
b = langSection.indexOf( '{' + '{źródła}}', a2 );
if ( a2 === -1 || b === -1 ) {
return false;
}
translations = langSection.slice( 0, b );
a3 = translations.indexOf( '\n*', a2 );
if (
a3 !== -1 &&
translations.slice( a3 ).indexOf( '{{zobtłum' ) !== -1
) {
a3 = translations.lastIndexOf( '{{zobtłum' );
a3 = translations.indexOf( '\n*', a3 );
}
if ( a3 !== -1 ) {
langs = [];
drafts = {};
metadata = {};
$.each( translations.slice( a3 + 1, b ).split( '\n' ), function ( i, line ) {
var lang, terms,
res = line.match( /^\* *([^:]+): *(.+)/ );
if ( res && res[ 1 ] && res[ 2 ] ) {
lang = res[ 1 ].trim();
terms = res[ 2 ].trim();
langs.push( lang );
metadata[ lang ] = { $original: gadget.$translList.children().eq( i ) };
if ( forbiddenTranslations.indexOf( lang ) !== -1 ) {
drafts[ lang ] = terms;
metadata[ lang ].invalid = true;
} else {
drafts[ lang ] = parseTerms( terms );
}
}
} );
if ( !langs.length || langs.length !== gadget.$translList.children().length ) {
return false;
}
if ( !validateDrafts( drafts, metadata ) ) {
mw.notify( mw.msg( 'transl-validate-error' ), { type: 'warn' } );
}
gadget.drafts = drafts;
gadget.draftMetadata = metadata;
a3++;
} else {
a3 = b;
}
gadget.initialDrafts = $.extend( {}, gadget.drafts );
gadget.startIndex = a3;
gadget.endIndex = b;
return true;
}
function parseTerms( terms ) {
var obj = {},
reTerm = /^(\(\d+\.\d+\)) *(.+)/,
reSubterm = /^\[\[([^\]]+?)\]\](?: +\{\{([^\}]+?)\}\})?$/;
terms.split( / *; */ ).forEach( function ( term ) {
var m = term.match( reTerm );
if ( m === null || m[ 1 ] in obj ) {
obj = null;
return false;
}
obj[ m[ 1 ] ] = m[ 2 ].trim().split( / *, */ ).map( function ( subterm ) {
var base, template,
mm = subterm.match( reSubterm );
if ( mm !== null ) {
base = mw.format( '[[$1]]', mm[ 1 ].trim() );
template = mm[ 2 ] && mw.format( '{{$1}}', mm[ 2 ].trim() );
} else {
base = subterm
}
return { base: base, template: template };
} );
} );
return obj || terms;
}
function validateDrafts( drafts, metadata ) {
var lang, term;
langs:
for ( lang in drafts ) {
if ( 'invalid' in metadata[ lang ] ) {
continue;
}
if (
!$.isPlainObject( drafts[ lang ] ) ||
$.isEmptyObject( drafts[ lang ] )
) {
metadata[ lang ].invalid = true;
continue;
}
terms:
for ( term in drafts[ lang ] ) {
if ( !gadget.$defn.filter( function () {
return $( this ).text() === term;
} ).length ) {
metadata[ lang ].invalid = true;
continue langs;
}
if ( drafts[ lang ][ term ].some( function ( subterm ) {
return /\(\d+\.\d+\)/.test( subterm.base );
} ) ) {
metadata[ lang ].invalid = true;
continue langs;
}
}
}
return !Object.keys( metadata ).some( function ( lang ) {
return 'invalid' in metadata[ lang ];
} );
}
function comparatorPl( a, b ) {
return a.localeCompare( b, 'pl' );
}
function prepareDraft() {
return Object.keys( gadget.drafts ).sort( comparatorPl ).map( function ( lang ) {
return mw.format( '* $1: $2\n', lang, serializeDraft( gadget.drafts[ lang ] ) );
} ).join( '' );
}
function resetForms( gui ) {
gadget.activeLang = null;
gui.$langLabel.html( mw.msg( 'transl-select-lang' ) ),
gui.$langSelector.val( '' ).trigger( 'focus' );
gui.$saveButton.prop( 'disabled', true );
gui.$textInputs.find( 'input' ).val( '' );
gui.$apply.prop( 'disabled', true );
gui.$textInputs.find( 'input' ).prop( 'disabled', true );
}
function resetSubmitButtons( gui ) {
var hasChanged = testDraftDivergence();
gui.$watch.prop( 'disabled', !hasChanged );
gui.$submit.prop( 'disabled', !hasChanged );
}
function testDraftDivergence() {
return JSON.stringify( gadget.initialDrafts ) !== JSON.stringify( gadget.drafts );
}
function onLoadLang( gui, targetLang, evt ) {
var lang = targetLang || gui.$langSelector.val();
evt && evt.preventDefault();
if ( !lang ) {
return;
}
if ( gadget.currentRequest ) {
gadget.currentRequest.abort();
}
resetForms( gui );
if ( lang in gadget.draftMetadata && gadget.draftMetadata[ lang ].invalid ) {
mw.notify( mw.msg( 'transl-invalid-lang' ), { type: 'error' } );
return;
}
if ( forbiddenLanguageNames.indexOf( lang ) !== -1 ) {
mw.notify( mw.msg( 'transl-forbidden-lang', lang ), { type: 'error' } );
return;
}
gadget.activeLang = lang;
gui.$langLabel.html( lang in config.lang2code
? mw.msg( 'transl-lang-label-iso', lang, config.lang2code[ lang ] )
: mw.msg( 'transl-lang-label', lang )
);
if ( !( lang in config.lang2code ) ) {
mw.notify( mw.msg( 'transl-invalid-code' ), { type: 'warn' } );
}
gui.$saveButton
.prop( 'disabled', false )
.attr( 'value', gadget.preferredLang === lang
? mw.msg( 'transl-forget-button' )
: mw.msg( 'transl-save-button' )
);
gui.$textInputs.find( 'input' ).prop( 'disabled', false );
if ( lang in gadget.drafts ) {
gui.$textInputs.children().each( $.proxy( loadDrafts, null, gadget.drafts[ lang ] ) );
}
refreshPreview( gui, lang );
gui.$apply.prop( 'disabled', false );
setTimeout( function () {
gui.$textInputs.find( 'input' ).first().trigger( 'focus' );
}, 1 );
}
function loadDrafts( draft, i, el ) {
var $el = $( el ),
defn = $el.data( 'defn' ),
$inputs = $el.children( 'input' ),
$text = $inputs.first(),
$tmpl = $inputs.last(),
text = [],
tmpl = [];
if ( !draft[ defn ] ) {
return true;
}
$.each( draft[ defn ], function ( i, obj ) {
text.push( stripBrackets( obj.base ) );
tmpl.push( stripBrackets( obj.template || '' ) );
} );
$text.val( text.join( ', ' ) );
if ( tmpl.join( '' ) !== '' ) {
$tmpl.val( tmpl.join( ',' ) );
}
}
function onSaveLang( gui, evt ) {
var message, updateLang, newValue;
if ( gadget.activeLang !== gadget.preferredLang ) {
message = mw.msg( 'transl-save-prompt', gadget.activeLang );
if ( !!gadget.preferredLang ) {
message += ' ' + mw.msg( 'transl-save-current', gadget.preferredLang );
}
updateLang = true;
} else {
message = mw.msg( 'transl-forget-prompt', gadget.preferredLang );
updateLang = false;
}
newValue = updateLang ? gadget.activeLang : null;
gui.$confirmDialog.append( message ).data( {
newValue: newValue,
updateLang: updateLang
} ).dialog( 'open' );
}
function savePreferredLangRequest( gui ) {
var newValue = gui.$confirmDialog.data( 'newValue' ),
updateLang = gui.$confirmDialog.data( 'updateLang' );
if ( !mw.user.isAnon() ) {
return api.saveOption( PREFERRED_LANG_OPTION_KEY, newValue )
.done( function () {
gadget.preferredLang = newValue;
gui.$saveButton.attr( 'value', mw.msg( updateLang
? 'transl-forget-button'
: 'transl-save-button'
) );
mw.notify( mw.msg( 'transl-save-success' ) );
} );
} else {
mw.cookie.set( PREFERRED_LANG_COOKIE, newValue );
gadget.preferredLang = newValue;
gui.$saveButton.attr( 'value', mw.msg( updateLang
? 'transl-forget-button'
: 'transl-save-button'
) );
mw.notify( mw.msg( 'transl-save-success' ) );
return $().promise();
}
}
function stripBrackets( s ) {
return s.replace( /^[\[\{]{2}([^\|\[\]\{\}]+?)[\]\}]{2}$/, '$1' );
}
function onApplyChanges( gui, evt ) {
var apiPromise,
draft = {},
metadata = gadget.draftMetadata[ gadget.activeLang ] || {},
isFreshDraft = !( gadget.activeLang in gadget.drafts );
evt && evt.preventDefault();
gui.$textInputs.children().each( $.proxy( constructDrafts, null, draft ) );
if ( $.isEmptyObject( draft ) ) {
return;
}
gui.$watch.prop( 'disabled', true );
gui.$submit.prop( 'disabled', true );
gadget.drafts[ gadget.activeLang ] = draft;
if ( isFreshDraft ) {
sortDrafts();
gadget.draftMetadata[ gadget.activeLang ] = metadata;
}
apiPromise = api.get( {
formatversion: 2,
action: 'parse',
text: serializeDraft( draft ),
contentmodel: 'wikitext',
disablelimitreport: true
} );
gadget.currentRequest = metadata.request = apiPromise
.then( function ( data ) {
return parsedWikitextCallback( data, gadget.activeLang );
} )
.always( function () {
gadget.currentRequest = null;
delete metadata.request;
resetSubmitButtons( gui );
} )
.promise( {
abort: apiPromise.abort
} );
refreshPreview( gui, gadget.activeLang );
}
function sortDrafts() {
// https://stackoverflow.com/a/31102605
var temp = {};
Object.keys( gadget.drafts ).sort( comparatorPl ).forEach( function ( lang ) {
temp[ lang ] = gadget.drafts[ lang ];
} );
gadget.drafts = temp;
}
function constructDrafts( draft, i, el ) {
var terms, tmpls, temp, arr,
$this = $( el ),
$inputs = $this.children( 'input' ),
text = $.trim( $inputs.first().val() ),
tmpl = $.trim( $inputs.last().val() );
if ( !text ) {
return true;
}
terms = text.split( / *, */ );
tmpls = tmpl ? tmpl.split( / *, */ ) : null;
arr = [];
$.each( terms, function ( j, term ) {
var base, template;
if ( /[\[\]\(\)\{\}<>\/]/.test( term ) ) {
base = term;
} else {
base = '[' + '[' + term.trim() + ']]';
}
if ( tmpls && tmpls[ j ] ) {
template = '{' + '{' + tmpls[ j ].trim() + '}}';
}
if ( template === "{{f}}" ) {
// [[Special:PermaLink/7109640#Hiperonimy i hiponimy oraz femininum.]]
template = "{{ż}}";
}
arr.push( {
base: base,
template: template
} );
} );
draft[ $this.data( 'defn' ) ] = arr;
}
function parsedWikitextCallback( data, lang ) {
var $parsed, $els, links;
$parsed = $( data.parse.text ).filter( '.mw-parser-output' ).children( 'p' ).first();
$els = $parsed.find( 'a' );
if ( !$els.length || !( lang in config.lang2code ) ) {
return $parsed;
}
// TODO: użycie modułu sectionLinks
$els.each( function () {
var href = $( this ).attr( 'href' );
if ( href.indexOf( '#' ) === -1 ) {
href += '#' + config.lang2code[ lang ];
$( this ).attr( 'href', href );
}
} );
if ( Number( mw.user.options.get( 'gadget-false-blue-links' ) ) ) {
links = data.parse.links.filter( function ( obj ) {
return obj.ns === 0 && obj.exists;
} ).map( function ( obj ) {
return obj.title;
} );
// TODO: sprawdzić, czy da się wstrzymać ('abort') z poziomu metadata.request
gadget.currentRequest = mw.libs.falseBlueLinks.inspectTitles( links );
return gadget.currentRequest.then( function () {
mw.libs.falseBlueLinks.processElements( $parsed );
return $parsed;
} );
} else {
return $parsed;
}
}
function serializeDraft( draft ) {
var copy;
if ( typeof( draft ) === 'string' ) {
return draft;
}
copy = $.extend( true, {}, draft );
return $.map( copy, function ( data, defn ) {
return defn + ' ' + $.map( data, function ( word ) {
return ( word.template
? word.base + ' ' + word.template
: word.base
);
} ).join( ', ' );
} ).join( '; ' );
}
function refreshPreview( gui, active ) {
var $ul = $( '<ul>' );
Object.keys( gadget.drafts ).sort( comparatorPl ).forEach( function ( lang ) {
var $li, $change, $remove, $abort, $preview, $serializedPreview, metadata,
draft = gadget.drafts[ lang ];
if ( lang in gadget.draftMetadata ) {
metadata = gadget.draftMetadata[ lang ];
} else {
gadget.draftMetadata[ lang ] = metadata = {};
}
$serializedPreview = $( '<code>' )
.addClass( 'transl-preview-entry' )
.text( serializeDraft( draft ) );
$change = $( '<small>' ).text( mw.msg( 'transl-draft-change' ) );
$remove = $( '<small>' ).text( mw.msg( 'transl-draft-remove' ) );
$abort = $( '<small>' ).text( mw.msg( 'transl-draft-abort' ) );
if ( metadata.request ) {
metadata.$parsed = metadata.$parsed || null; // dummy temporary value
$change.hide();
$remove.hide();
$preview = $( '<span>' )
.addClass( 'transl-parsing transl-preview-entry' )
.text( mw.msg( 'transl-preview-parsing' ) );
metadata.request
.done( function ( $parsed ) {
$preview.removeClass( 'transl-parsing' ).html( $parsed.html() );
metadata.$parsed = $preview;
} )
.fail( function () {
$preview.replaceWith( $serializedPreview );
delete metadata.$parsed;
} )
.always( function () {
$change.show();
$remove.show();
$abort.hide();
} );
} else {
$abort.hide();
$preview = metadata.$parsed || $serializedPreview;
}
$li = $( '<li>' );
if ( '$parsed' in metadata ) {
$li.append( $( '<span>' ).text( mw.format( '$1: ', lang ) ), $preview );
} else {
$li.append( $( '<span>' )
.addClass( 'transl-preview-entry' )
.html( metadata.$original.html() )
);
}
$li.append( $change, $remove, $abort ).appendTo( $ul );
if ( lang === active ) {
$li.addClass( 'transl-active' );
$change.addClass( 'disabled' );
} else if ( metadata.invalid ) {
$change.addClass( 'disabled' );
} else {
$change.on( 'click', function () {
gadget.activeLang = lang;
onLoadLang( gui, lang );
$ul.children().removeClass( 'transl-active' );
$li.addClass( 'transl-active' );
} );
}
$remove.on( 'click', function () {
delete gadget.drafts[ lang ];
$li.remove();
if ( lang === active ) {
if ( gadget.currentRequest ) {
gadget.currentRequest.abort();
}
resetForms( gui );
}
resetSubmitButtons( gui );
} );
$abort.on( 'click', function () {
if ( gadget.currentRequest ) {
gadget.currentRequest.abort();
}
} );
} );
gui.$preview.replaceWith( $ul );
gui.$preview = $ul;
}
function makeSummary() {
var s, addedLangs, deletedLangs, modifiedLangs, buildString, addedDrafts,
initialLangs = Object.keys( gadget.initialDrafts ),
draftLangs = Object.keys( gadget.drafts );
buildString = function ( added, modified, deleted, delimiter ) {
var out = [];
if ( addedLangs.length ) {
out.push( 'dodano ' + added.join( delimiter || ', ' ) );
}
if ( modifiedLangs.length ) {
out.push( 'zmodyfikowano ' + modified.join( ', ' ) );
}
if ( deletedLangs.length ) {
out.push( 'usunięto ' + deleted.join( ', ' ) );
}
return out.join( ' •• ' );
};
addedLangs = draftLangs.filter( function ( lang ) {
return initialLangs.indexOf( lang ) === -1;
} );
deletedLangs = initialLangs.filter( function ( lang ) {
return draftLangs.indexOf( lang ) === -1;
} );
modifiedLangs = draftLangs.filter( function ( lang ) {
var helper = function ( draft ) {
return JSON.stringify( Object.keys( draft ).map( function ( key ) {
return { num: key, val: draft[ key ] };
} ) );
};
return (
initialLangs.indexOf( lang ) !== -1 &&
helper( gadget.initialDrafts[ lang ] ) !== helper( gadget.drafts[ lang ] )
);
} );
addedDrafts = addedLangs.map( function ( lang ) {
return mw.format( '$1: $2', lang, serializeDraft( gadget.drafts[ lang ] ) );
} );
s = buildString( addedDrafts, modifiedLangs, deletedLangs, ' • ' );
if ( mw.libs.String.byteLength( s ) > 1000 ) {
s = buildString( addedLangs, modifiedLangs, deletedLangs );
}
return s;
}
function onSubmit( gui, evt ) {
var translationsDraft = prepareDraft(),
pageDraft =
gadget.content.slice( 0, gadget.startIndex ) +
translationsDraft +
gadget.content.slice( gadget.endIndex, gadget.content.length );
evt.preventDefault();
gui.$submit
.prop( 'disabled', true )
.attr( 'value', mw.msg( 'transl-submitting' ) );
api.postWithEditToken( {
action: 'edit',
title: config.wgPageName,
text: pageDraft,
tags: 'translation-editor',
summary: makeSummary(),
watchlist: gui.$watch.prop( 'checked' ) ? 'watch' : 'nochange',
notminor: true,
starttimestamp: gadget.starttimestamp,
basetimestamp: gadget.basetimestamp
} )
.done( function () {
var cookieKey = POST_EDIT_COOKIE_KEY + config.wgArticleId;
gui.$submit.attr( 'value', mw.msg( 'transl-reloading' ) );
mw.cookie.set( cookieKey, 'saved', postEditCookieOpts );
location.reload();
} )
.fail( function () {
mw.notify( mw.msg( 'transl-save-error' ), { type: 'error' } );
} );
}
// [mediawiki/extensions/WikiEditor] / modules / jquery.wikiEditor.toolbar.js
function buildCharacter( character, actions ) {
if ( typeof character === 'string' ) {
character = {
label: character,
action: {
type: 'replace',
options: {
peri: character,
selectPeri: false
}
}
};
// In some cases the label for the character isn't the same as the
// character that gets inserted (e.g. Hebrew vowels)
} else if ( character && 0 in character && 1 in character ) {
character = {
label: character[ 0 ],
action: {
type: 'replace',
options: {
peri: character[ 1 ],
selectPeri: false
}
}
};
}
if ( character && 'action' in character && 'label' in character ) {
actions[ character.label ] = character.action;
if ( character.titleMsg !== undefined ) {
return mw.html.element( 'span', {
rel: character.label,
title: mw.msg( character.titleMsg )
}, character.label );
} else {
return mw.html.element( 'span', {
rel: character.label
}, character.label );
}
}
mw.log( 'A character for the toolbar was undefined. This is not supposed to happen. Double check the config.' );
// bug 31673; also an additional fix for bug 24208...
return '';
}
function unicodeToAscii( s ) {
var n, ch, index,
out = '',
utf = 'ąåãáćçęèłńóõüśźż',
ascii = 'aaaacceelnoouszz';
for ( n = 0; n < s.length; n++ ) {
ch = s.charAt( n );
index = utf.indexOf( ch );
if ( index !== -1 ) {
out += ascii.charAt( index );
} else {
out += ch;
}
}
return out;
}
function createMenu() {
var allowCloseWindow,
gui = {},
$activeTextInput = $( [] ),
charActions = {};
allowCloseWindow = mw.confirmCloseWindow( {
test: testDraftDivergence,
message: mw.msg( 'transl-confirm-close' ),
namespace: 'translationeditor-editwarning'
} );
gui.$langSelector = $( '<input>' )
.attr( {
id: 'transl-langselector',
type: 'text',
size: 22
} );
gui.$textInputs = $( '<div>' )
.attr( 'id', 'transl-textinputs' );
gadget.$defn.each( function ( i, el ) {
var $num,
$defn = $( el );
$( '<div>' )
.data( 'defn', $defn.text() )
.append(
$num = $( '<span>' )
.addClass( 'transl-def-label' )
.text( $defn.text() ),
$( '<input>' )
.attr( {
type: 'text',
size: 50
} ),
$( '<input>' )
.attr( {
type: 'text',
size: 1
} )
)
.appendTo( gui.$textInputs );
mw.libs.termPreview.enablePreview( $num, 'pl' );
} );
gui.$loadButton = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-load-button' )
} )
.on( 'click', $.proxy( onLoadLang, this, gui, null ) );
gui.$saveButton = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-save-button' )
} )
.on( 'click', $.proxy( onSaveLang, this, gui ) );
gui.$apply = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-apply-button' )
} )
.on( 'click', $.proxy( onApplyChanges, this, gui ) );
gui.$submit = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-submit-button' )
} )
.prop( 'disabled', true )
.on( 'click', allowCloseWindow.release )
.on( 'click', $.proxy( onSubmit, this, gui ) );
gui.$watch = $( '<input>' )
.attr( {
type: 'checkbox',
id: 'transl-watch'
} )
.prop( {
checked: !!Number( mw.user.options.get( 'watchdefault' ) ),
disabled: true
} );
gui.$specialCharsButton = $( '<small>' )
.html( mw.msg( 'transl-keyboard' ) )
.on( 'click', function () {
gui.$keyboard.show();
} );
gui.$previewbox = $( '<div>' )
.attr( 'id', 'transl-preview' )
.append(
$( '<center>' ).append(
$( '<strong>' ).text( mw.msg( 'transl-preview-label' ) )
),
gui.$preview = $( '<ul>' )
);
gui.$keyboard = $( '<div>' )
.attr( 'id', 'transl-keyboard' )
.hide()
.append(
gui.$keyboardSelect = $( '<select>' ),
$( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-keyboard-close' )
} )
.on( 'click', function ( evt ) {
evt.preventDefault();
gui.$keyboard.hide();
} ),
gui.$keyboardChars = $( '<div>' )
.attr( 'id', 'transl-special-chars' )
)
.appendTo( mw.util.$content );
$.each( mw.libs.specialCharacters, function ( group, chars ) {
var $group = $( '<div>' )
.hide()
.attr( 'data-group', group )
.appendTo( gui.$keyboardChars );
$( '<option>' )
.attr( 'value', group )
.text( mw.msg( 'special-characters-group-' + group ) )
.appendTo( gui.$keyboardSelect );
$.each( chars, function ( i, character ) {
$( buildCharacter( character, charActions ) ).appendTo( $group );
} );
} );
gui.$keyboardSelect.on( 'change', function () {
var group = $( this ).find( ':selected' ).attr( 'value' );
gui.$keyboardChars.children().hide();
gui.$keyboardChars.find( '[data-group=' + group + ']' ).show();
mw.cookie.set( 'TranslatorKeyboardGroup', group );
} );
gui.$keyboardSelect
.find( mw.format(
'[value="$1"]',
mw.cookie.get( 'TranslatorKeyboardGroup', null, 'latin' )
) )
.prop( 'selected', true )
.end()
.trigger( 'change' );
gui.$keyboardChars.on( 'click', 'span', function () {
var label = $( this ).text(),
action = charActions[ label ],
replace = ( action.type === 'replace' );
// jquery.wikiEditor.toolbar.js, doAction()
$activeTextInput.textSelection(
'encapsulateSelection',
$.extend( {}, action.options, {
replace: replace
} )
).trigger( 'keypress' );
} );
gui.$editbox = $( '<div>' )
.attr( 'id', 'transl-editbox' )
.hide()
.append(
$( '<div>' ).append(
gui.$langLabel = $( '<p>' )
.attr( 'id', 'transl-lang-label' ),
gui.$langSelector,
$( '<div>' )
.attr( 'id', 'transl-selector-buttons' )
.append(
gui.$loadButton, gui.$saveButton
)
),
gui.$textInputs,
$( '<div>' )
.attr( 'id', 'transl-edit-buttons' )
.append(
gui.$apply, gui.$submit, gui.$watch,
$( '<label>' )
.attr( 'for', 'transl-watch' )
.text( mw.msg( 'transl-watch-article' ) )
),
$( '<div>' ).append(
gui.$specialCharsButton,
' ',
$( '<small>' ).html( mw.msg( 'transl-report-error' ) ),
' ',
$( '<small>' ).html( mw.msg( 'transl-help-syntax' ) )
),
$( '<hr>' ),
gui.$previewbox
)
.insertAfter( $( '#transl-field' ).parent() );
gui.$editbox.on( 'focus', 'input[type="text"]', function () {
$activeTextInput = $( this );
} );
gui.$langSelector.suggestions( {
fetch: function ( input, response, maxRows ) {
var langs = $.map( config.lang2code, function ( code, lang ) {
return lang;
} );
input = unicodeToAscii( input.toLowerCase() );
response( $.grep( langs, function ( lang ) {
var normalized = unicodeToAscii( lang.toLowerCase() );
return (
normalized.indexOf( input ) === 0 &&
forbiddenLanguageNames.indexOf( lang ) === -1
);
} ) );
},
result: {
render: function ( suggestion, context ) {
context.data.$container.find( '.suggestions-special' ).hide();
this.text( suggestion );
},
select: function ( $input ) {
onLoadLang( gui, null );
}
},
special: {
render: function ( query, context ) {
var $label, $result;
if ( !this.children().length ) {
this.append(
$label = $( '<div>' ).addClass( 'special-label' ),
$result = $( '<div>' ).addClass( 'special-query' )
);
} else {
$label = this.find( '.special-label' );
$result = this.find( '.special-query' );
}
query = query.toLowerCase();
if (
query in config.code2lang &&
forbiddenLanguageCodes.indexOf( query ) === -1
) {
$label.html( mw.msg( 'transl-lang-suggest-code', query ) );
$result.text( config.code2lang[ query ] );
this.show();
}
},
select: function ( $input ) {
var lang = this.find( '.special-query' ).text();
$input.val( lang );
onLoadLang( gui, null );
}
},
highlightInput: true
} )
.on( 'keypress', function ( evt ) {
if ( evt.keyCode === 13 ) { // Enter
onLoadLang( gui, null );
}
} )
.on( 'paste cut drop', function ( evt ) {
$( this ).trigger( 'keypress' );
} );
gui.$confirmSpinner = $.createSpinner().css( 'margin-right', '1em' ).hide();
gui.$confirmDialog = $( '<p>' ).dialog( {
resizable: false,
minHeight: 150,
modal: true,
autoOpen: false,
draggable: false,
title: mw.msg( 'transl-prompt-title' ),
dialogClass: 'transl-dialog-no-close',
buttons: [
{
text: mw.msg( 'transl-save-save' ),
click: function () {
if ( gui.$confirmDialog.data( 'hasPendingRequest' ) ) {
return;
} else {
gui.$confirmSpinner.show();
gui.$confirmDialog.data( 'hasPendingRequest', true );
}
savePreferredLangRequest( gui )
.fail( function () {
mw.notify( mw.msg( 'transl-save-fail' ), { type: 'error' } );
} )
.always( function () {
gui.$confirmDialog.dialog( 'close' );
} );
}
},
{
text: mw.msg( 'transl-save-cancel' ),
click: function () {
if ( !gui.$confirmDialog.data( 'hasPendingRequest' ) ) {
gui.$confirmDialog.dialog( 'close' );
}
}
}
],
close: function ( event, ui ) {
gui.$confirmDialog.empty().removeData( 'hasPendingRequest' );
gui.$confirmSpinner.hide();
}
} );
gui.$textInputs.find( 'input' ).on( 'keypress', function ( evt ) {
if ( evt.keyCode === 13 ) { // Enter
onApplyChanges( gui );
}
} );
gui.$confirmSpinner.prependTo( gui.$confirmDialog.parent().find( '.ui-dialog-buttonset' ) );
resetForms( gui );
if ( !!gadget.preferredLang ) {
gadget.activeLang = gadget.preferredLang;
gui.$langSelector.val( gadget.activeLang );
onLoadLang( gui, gadget.activeLang );
}
}
if (
config.wgNamespaceNumber === 0 && config.wgAction === 'view' &&
config.wgRevisionId === config.wgCurRevisionId &&
config.wgDiffNewId === null && config.wgDiffNewId === null &&
!mw.util.getParamValue( 'printable' )
) {
if ( mw.cookie.get( POST_EDIT_COOKIE_KEY + config.wgArticleId ) === 'saved' ) {
mw.loader.using( 'mediawiki.action.view.postEdit' ).done( function () {
mw.hook( 'postEdit' ).fire();
mw.cookie.set( POST_EDIT_COOKIE_KEY + config.wgArticleId, null );
} );
}
mw.messages.set( messages );
mw.hook( 'sectionLinks.ready' ).add( initialize );
}