Wikisłownikarz:Peter Bowman/add-translations.js
Uwaga: aby zobaczyć zmiany po opublikowaniu, może zajść potrzeba wyczyszczenia pamięci podręcznej przeglądarki.
- Firefox / Safari: Przytrzymaj Shift podczas klikania Odśwież bieżącą stronę, lub naciśnij klawisze Ctrl+F5, lub Ctrl+R (⌘-R na komputerze Mac)
- Google Chrome: Naciśnij Ctrl-Shift-R (⌘-Shift-R na komputerze Mac)
- Internet Explorer / Edge: Przytrzymaj Ctrl, jednocześnie klikając Odśwież, lub naciśnij klawisze Ctrl+F5
- Opera: Naciśnij klawisze Ctrl+F5.
( function ( mw, $ ) {
var gadget = window.addTranslations = {};
var pageContent, pageDraft, translations, api;
var $transl, $defs;
var starttimestamp, basetimestamp;
var startIndex, endIndex;
var css = [
'#transl-buttons { display: inline; margin: 0 5px; }',
'#transl-buttons > small { cursor: pointer; font-weight: normal; margin: 0 5px; }',
'#transl-editbox { border: 1px solid black; background-color: #F9F9F9; margin-top: 5px; font-weight: normal; }',
'#transl-editbox > div { text-align: center; vertical-align: middle; margin: 5px; display: inline-block; }',
'#transl-textinputs > div input:first-child { margin: 0 5px; }',
'#transl-preview > ul { text-align: left; margin-right: 1em; }',
'#transl-preview > ul small { cursor: pointer; }',
'#transl-preview > ul code { margin: 0 0.5em; }',
'.transl-active { background-color: #F0F0F0; }'
];
var messages = {
'transl-add-translation': '(dodaj)',
'transl-api-error': 'Prawdopodobnie nastąpił konflikt edycji. Przeładuj stronę i spróbuj ponownie.',
'transl-edit-error': 'Możliwość edytowania istniejących tlumaczeń zostanie wdrożona w przyszłości.',
'transl-parsing-error': 'Nie udało się odczytać kodu strony. Przejdź na widok edycji i sprawdź, czy nie ma błędów w formacie.',
'transl-select-lang': 'Wybierz język',
'transl-lang-label': 'tłumaczysz na<br><strong>$1</strong>',
'transl-load-button': 'Załaduj',
'transl-preview-label': 'Podgląd zmian',
'transl-apply-button': 'Pokaż zmiany',
'transl-submit-button': 'Zapisz',
'transl-watch-article': 'Dodaj do obserwowanych',
'transl-submitting': 'Zapisywanie...',
'transl-reloading': 'Przeładowywanie strony...',
'transl-draft-change': '(przejdź)',
'transl-draft-remove': '(usuń)',
};
function initialize( $content ) {
var $buttonHolder;
gadget.activeLang = '';
gadget.defn = [];
gadget.langs = [];
gadget.drafts = {};
$transl = $content.find( 'dt.lang-pl.fldt-tlumaczenia' ).first();
$defs = $content.find( 'dd.lang-pl.fldt-znaczenia' );
if ( !$transl.length || !$defs.length ) {
return;
}
$transl
.children( '#transl' )
.css( 'display', 'inline' );
$buttonHolder = $( '<div>' )
.attr( 'id', 'transl-buttons' )
.appendTo( $transl );
if ( window.customLang && typeof hideTranslations === 'function' ) {
hideTranslations( customLang );
}
extractDefNums();
if ( gadget.defn.length !== $defs.length ) {
return;
}
$( '<small>' )
.text( mw.msg( 'transl-add-translation' ) )
.attr( 'id', 'transl-addbutton' )
.appendTo( $buttonHolder )
.on( 'click', function () {
var $spinner;
if ( !pageContent ) {
$spinner = $.createSpinner( {
size: 'large',
type: 'block'
} ).appendTo( $transl );
fetchContent( function () {
$spinner.remove();
$content.find( '#transl-editbox' ).show();
} );
}
$content.find( '#transl-editbox' ).toggle();
} );
}
function fetchContent( callback ) {
$.when(
api.get( {
prop: 'revisions',
rvprop: [ 'timestamp', 'content' ],
titles: mw.config.get( 'wgPageName' ),
indexpageids: true,
curtimestamp: true
} ),
mw.loader.using( [
'mediawiki.user',
'mediawiki.util',
'mediawiki.api.edit',
'jquery.suggestions',
'jquery.mwExtension',
'jquery.byteLength',
'ext.gadget.langdata',
'ext.gadget.section-links'
] )
)
.done( function ( res ) {
var data = res[ 0 ];
var id = data.query.pageids[ 0 ];
var page = data.query.pages[ id ];
pageContent = page.revisions[ 0 ][ '*' ];
starttimestamp = data.curtimestamp;
basetimestamp = page.revisions[ 0 ].timestamp;
} )
.done( function () {
if ( analyzePage() ) {
createMenu();
} else {
alert( mw.msg( 'transl-parsing-error' ) );
}
} )
.done( callback );
}
function extractDefNums() {
$defs.each( function () {
var m, def = $( this ).children( 'dfn' ).text();
if ( !def ) {
def = $( this ).text();
}
m = def.match( /^(\(.+?\))/ );
if ( m && m[ 0 ] && m[ 1 ] ) {
gadget.defn.push( m[ 1 ] );
} else {
return false;
}
} );
}
function analyzePage() {
var a2, a3, a4, b, langSection, langs, targetLang, targetRow;
var 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 = [];
$.each(
translations.slice( a3 + 1, b ).split( '\n' ),
function ( i, line ) {
var res = line.match( /^\* +([^:]+):/ );
if ( res && res[ 1 ] ) {
langs.push( res[ 1 ] );
}
} );
if ( !langs.length ) {
return false;
}
gadget.langs = langs;
startIndex = a3 + 1;
} else {
startIndex = b;
}
endIndex = b;
translations = pageContent.substring( startIndex, endIndex );
return true;
}
function getLangPos( target ) {
var n, lang, _char, p1, p2;
var abc = 'aąbcćdeęfghijklłmnńoópqrsśtuvwxyzźż';
var index = -1;
outer:
for ( n = 0; n < gadget.langs.length; n++ ) {
lang = gadget.langs[ n ];
inner:
for ( _char = 0; _char < lang.length; _char++ ) {
p1 = abc.indexOf( target[ _char ] );
p2 = abc.indexOf( lang[ _char ] );
if ( p1 > p2 ) {
index++;
continue outer;
} else if ( p1 === p2 ) {
continue inner;
} else {
break outer;
}
}
}
return gadget.langs[ index ];
}
function prepareDraft() {
$.each( gadget.drafts, function ( lang, draft ) {
var targetLang, targetRow, pos, translation;
if ( gadget.langs.length ) {
targetLang = getLangPos( lang );
}
if ( targetLang ) {
targetRow = mw.format( '\\* +$1:', $.escapeRE( targetLang ) );
pos = translations.search( targetRow );
pos = translations.indexOf( '\n', pos ) + 1;
} else {
pos = 0;
}
translation = mw.format( '$1: $2\n', lang, serializeDraft( draft ) );
translations =
translations.slice( 0, pos ) +
'* ' + translation +
translations.slice( pos, translations.length );
gadget.langs.splice( gadget.langs.indexOf( targetLang ) + 1, 0, lang );
} );
pageDraft =
pageContent.slice( 0, startIndex ) +
translations +
pageContent.slice( endIndex, pageContent.length );
}
function resetForms( gui ) {
gadget.activeLang = null;
gui.$langLabel.html( mw.msg( 'transl-select-lang' ) ),
gui.$langSelector.val( '' );
gui.$textInputs.find( 'input' ).val( '' );
gui.$apply.prop( 'disabled', true );
}
function onLoadLang( gui, targetLang, evt ) {
var lang = targetLang || gui.$langSelector.val();
var draft = gadget.drafts[ lang ];
evt && evt.preventDefault();
if ( !lang ) {
return;
}
resetForms( gui );
if (
!draft &&
gadget.langs.indexOf( lang ) !== -1
) {
alert( mw.msg( 'transl-edit-error' ) );
return;
}
gadget.activeLang = lang;
gui.$langLabel.html( mw.msg( 'transl-lang-label', lang ) );
if ( draft ) {
gui.$textInputs.children().each( function () {
var $this = $( this );
var defn = $this.data( 'defn' );
var $inputs = $this.children();
var $text = $inputs.first();
var $tmpl = $inputs.last();
var text = [], tmpl = [];
if ( !draft[ defn ] ) {
return true;
}
$.each( draft[ defn ], function ( i, obj ) {
text.push( obj.base );
tmpl.push( obj.template || '' );
} );
$text.val( text.join( ', ' ) );
$tmpl.val( tmpl.join( ',' ) );
} );
}
refreshPreview( gui, lang );
gui.$apply.prop( 'disabled', false );
}
function onApplyChanges( gui, evt ) {
var preview;
var draft = {};
evt.preventDefault();
gui.$textInputs.children()
.each( function () {
var terms, tmpls, temp;
var $this = $( this );
var $inputs = $this.children();
var text = $inputs.first().val().trim();
var tmpl = $inputs.last().val().trim();
if ( !text ) {
return true;
}
terms = text.split( / *, */ );
tmpls = tmpl
? tmpl.split( / *, */ )
: null;
arr = [];
$.each( terms, function ( j, term ) {
var base, template;
if ( term.indexOf( '[' ) > -1 ) {
base = term;
} else {
base = '[' + '[' + term + ']]';
}
if ( tmpls && tmpls[ j ] ) {
template = '{' + '{' + tmpls[ j ] + '}}';
}
arr.push( {
base: base,
template: template
} );
} );
draft[ $this.data( 'defn' ) ] = arr;
} );
if ( $.isEmpty( draft ) ) {
return;
}
gadget.drafts[ gadget.activeLang ] = draft;
refreshPreview( gui, gadget.activeLang );
gui.$submit.prop( 'disabled', false );
gui.$watch.prop( 'disabled', false );
}
function serializeDraft( obj ) {
return $.map( obj, 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>' );
$.each( gadget.drafts, function ( lang, draft ) {
var $li, $change, $remove;
$li = $( '<li>' )
.append(
$( '<strong>' ).text( mw.format( '$1:', lang ) ),
$( '<code>' ).text( serializeDraft( draft ) ),
$change = $( '<small>' ).text( mw.msg( 'transl-draft-change' ) ),
' ',
$remove = $( '<small>' ).text( mw.msg( 'transl-draft-remove' ) )
)
.appendTo( $ul );
if ( lang === active ) {
$li.addClass( 'transl-active' );
}
$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 ];
gadget.langs.splice( gadget.langs.indexOf( lang ), 1 );
if ( $li.hasClass( 'transl-active' ) ) {
resetForms( gui );
}
$li.remove();
} );
} );
gui.$preview.replaceWith( $ul );
gui.$preview = $ul;
}
function makeSummary() {
var s, arr = [];
var buildString = function ( a ) {
return mw.format( '+$1 na $2',
( a.length > 1 ) ? 'tłumaczenia' : 'tłumaczenie',
a.join( ' || ' )
);
};
$.each( gadget.drafts, function ( lang, data ) {
arr.push( mw.format( '$1: $2', lang, serializeDraft( data ) ) );
} );
arr.sort( function ( a, b ) {
return a.localeCompare( b, 'pl' );
} );
s = buildString( arr );
if ( $.byteLength( s ) > 255 ) {
arr = [];
$.each( gadget.drafts, function ( lang, data ) {
arr.push( lang );
} );
arr.sort( function ( a, b ) {
return a.localeCompare( b, 'pl' );
} );
s = buildString( arr );
}
return s;
}
function onSubmit( gui, evt ) {
evt.preventDefault();
prepareDraft();
gui.$submit
.prop( 'disabled', true )
.attr( 'value', mw.msg( 'transl-submitting' ) );
api.postWithEditToken( {
action: 'edit',
title: mw.config.get( 'wgPageName' ),
text: pageDraft,
tags: 'script',
summary: makeSummary(),
watchlist: gui.$watch.prop( 'checked' ) ? 'watch' : 'nochange',
starttimestamp: starttimestamp,
basetimestamp: basetimestamp
} )
.done( function () {
gui.$submit.attr( 'value', mw.msg( 'transl-reloading' ) );
window.location.reload();
} )
.fail( function () {
alert( mw.msg( 'transl-api-error' ) );
} );
}
function createMenu() {
var gui = {};
gui.$langSelector = $( '<input>' )
.attr( {
type: 'text',
size: 15
} );
gui.$textInputs = $( '<div>' )
.attr( 'id', 'transl-textinputs' );
$.each( gadget.defn, function ( i, defn ) {
$( '<div>' )
.data( 'defn', defn )
.append(
defn,
$( '<input>' )
.attr( {
'type': 'text',
'size': 70
} ),
$( '<input>' )
.attr( {
'type': 'text',
'size': 1
} )
)
.appendTo( gui.$textInputs );
} );
gui.$loadButton = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-load-button' )
} ).on( 'click', $.proxy( onLoadLang, this, gui, null ) );
gui.$apply = $( '<input>' )
.attr( {
'type': 'submit',
'value': mw.msg( 'transl-apply-button' )
} )
.prop( 'disabled', true )
.on( 'click', $.proxy( onApplyChanges, this, gui ) );
gui.$submit = $( '<input>' )
.attr( {
'type': 'submit',
'value': mw.msg( 'transl-submit-button' )
} )
.prop( 'disabled', true )
.on( 'click', $.proxy( onSubmit, this, gui ) );
gui.$watch = $( '<input>' )
.attr( {
type: 'checkbox',
id: 'transl-watch'
} )
.prop( {
disabled: true,
checked: !!mw.user.options.get( 'watchdefault' )
} );
gui.$previewbox = $( '<div>' )
.attr( 'id', 'transl-preview' )
.append(
$( '<strong>' ).text( mw.msg( 'transl-preview-label' ) ),
gui.$preview = $( '<ul>' )
);
gui.$editbox = $( '<div>' )
.attr( 'id', 'transl-editbox' )
.hide()
.append(
$( '<div>' ).append(
gui.$langLabel = $( '<p>' )
.attr( 'id', 'transl-lang-label' )
.html( mw.msg( 'transl-select-lang' ) ),
gui.$langSelector,
gui.$loadButton
),
gui.$textInputs,
$( '<div>' )
.append(
gui.$apply, gui.$submit, '<br>', gui.$watch,
$( '<label>' )
.attr( 'for', 'transl-watch' )
.text( mw.msg( 'transl-watch-article' ) )
),
$( '<hr>' ),
gui.$previewbox
);
$transl
.append( gui.$editbox )
.parent()
.show();
gui.$langSelector.suggestions( {
fetch: function ( input, response ) {
var re = new RegExp( '^' + input );
var arr = $.map( mw.config.get( 'lang2code' ), function ( code, lang ) {
return lang;
} );
response( $.grep( arr, function ( s ) {
return re.test( s );
} ) );
},
highlightInput: true
} );
if ( window.customLang ) {
gadget.activeLang = customLang;
gui.$langSelector.val( gadget.activeLang );
onLoadLang( gui, customLang );
}
}
if (
mw.config.get( 'wgNamespaceNumber' ) === 0 &&
mw.config.get( 'wgAction' ) === 'view'
) {
mw.util.addCSS( css.join( ' ' ) );
mw.messages.set( messages );
api = new mw.Api();
mw.loader.using( 'jquery.spinner' ).done( function () {
mw.hook( 'wikipage.content' ).add( initialize );
} );
}
}( mediaWiki, jQuery ) );