Wikisłownikarz:Peter Bowman/add-translations.js
Wygląd
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)
- 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 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; text-align: center; clear: both; }',
'#transl-editbox > div { vertical-align: middle; margin: 5px; display: inline-block; }',
'#transl-textinputs { max-height: 200px; overflow-y: auto; width: 410px; }',
'#transl-textinputs > div { margin: 5px 0; }',
'#transl-textinputs > div input:first-of-type { margin: 0 5px; }',
'.transl-def-label { cursor: help; }',
'#transl-edit-buttons { text-align: left !important; }',
'#transl-edit-buttons input[type="button"] { display: block; }',
'#transl-preview { width: 100%; }',
'#transl-preview > div { width: 0; float: left; }',
'#transl-preview > div small { cursor: pointer; }',
'#transl-preview > ul { text-align: left; margin-right: 1em; }',
'#transl-preview > ul small { cursor: pointer; }',
'#transl-preview > ul small.disabled { cursor: auto; opacity: 0.5; }',
'#transl-preview > ul code { margin: 0 0.5em; }',
'.transl-active { background-color: #F0F0F0; }',
'#transl-keyboard { position: fixed; left: 0; bottom: 0; background-color: #fafafa; height: 250px; width: 350px; border-color: black; border-style: solid solid none none; border-width: 1px 1px medium medium; z-index: 100; padding: 5px; }',
'#transl-keyboard > div { margin-top: 5px; overflow-y: auto; height: 225px; }',
'#transl-special-chars span { border: 1px solid #ddd; cursor: pointer; display: block; float: left; color: black; font-family: monospace, "Courier New"; font-size: 1.25em; height: 1em; margin-left: 5px; margin-top: 5px; padding: 5px 8px; text-decoration: none; }',
'#transl-special-chars span:hover { background-color: white; border-color: #a8d7f9; text-decoration: none; }'
];
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-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-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-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=add-translations.js%20%28b%C5%82%C4%85d%29&nosummary=" target="_blank">zgłoś błąd</a>)'
};
function initialize( $content ) {
var $transl, $defs, $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
.attr( 'id', 'transl-field' )
.children( '#transl' )
.css( 'display', 'inline' );
$buttonHolder = $( '<div>' )
.attr( 'id', 'transl-buttons' )
.appendTo( $transl );
if ( window.customLang && typeof hideTranslations === 'function' ) {
hideTranslations( customLang );
}
extractDefinitions( $defs );
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 );
makeRequest( function () {
$spinner.remove();
$content.find( '#transl-editbox' ).show();
} );
}
$content.find( '#transl-editbox' ).toggle();
} );
$transl.parent().show();
}
function makeRequest( callback ) {
$.when(
api.get( {
prop: 'revisions',
rvprop: [ 'timestamp', 'content' ],
titles: mw.config.get( 'wgPageName' ),
indexpageids: true,
curtimestamp: true
} ),
mw.loader.using( [
'mediawiki.api.edit',
'mediawiki.cookie',
'mediawiki.language.specialCharacters',
'jquery.suggestions',
'jquery.mwExtension',
'jquery.byteLength',
'jquery.tipsy',
'jquery.textSelection',
'ext.gadget.langdata'
] )
)
.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 extractDefinitions( $defs ) {
$defs.each( function () {
var m, text = $( this ).children( 'dfn' ).text();
if ( !text ) {
text = $( this ).text();
}
m = text.match( /^(\(.+?\)) (.+)/ );
if ( m && m[ 1 ] ) {
gadget.defn.push( {
num: m[ 1 ],
text: m[ 2 ].replace( /\[\d+\]/g, '' )
} );
} 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( $.inArray( targetLang, gadget.langs ) + 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 );
gui.$textInputs.find( 'input' ).prop( 'disabled', true );
if ( $.isEmpty( gadget.drafts ) ) {
gui.$watch.prop( 'disabled', true );
gui.$submit.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 &&
$.inArray( lang, gadget.langs ) !== -1
) {
alert( mw.msg( 'transl-edit-error' ) );
return;
}
gadget.activeLang = lang;
gui.$langLabel.html( lang in mw.config.get( 'lang2code' )
? mw.msg( 'transl-lang-label-iso', lang, mw.config.get( 'lang2code' )[ lang ] )
: mw.msg( 'transl-lang-label', lang )
);
gui.$textInputs.find( 'input' ).prop( 'disabled', false );
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( stripBrackets( obj.base ) );
tmpl.push( stripBrackets( obj.template || '' ) );
} );
$text.val( text.join( ', ' ) );
if ( tmpl.join( '' ) !== '' ) {
$tmpl.val( tmpl.join( ',' ) );
}
} );
}
refreshPreview( gui, lang );
gui.$apply.prop( 'disabled', false );
}
function stripBrackets( s ) {
return s.replace( /^[\[\{]{2}([^\|\[\]\{\}]+?)[\]\}]{2}$/, '$1' );
}
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( 'input' );
var text = $.trim( $inputs.first().val() );
var 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 ( 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.$watch.prop( 'disabled', false );
gui.$submit.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.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 ) {
resetForms( gui );
}
} );
} );
gui.$preview.replaceWith( $ul );
gui.$preview = $ul;
}
function makeSummary() {
var s, arr = [];
var buildString = function ( a, delimiter ) {
return mw.format( '+tłumaczenie na $1',
a.join( delimiter )
);
};
$.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',
notminor: true,
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' ) );
} );
}
// [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 createMenu() {
var gui = {}, $activeTextInput = $( [] ), charActions = {};
gui.$langSelector = $( '<input>' )
.attr( {
type: 'text',
size: 15
} );
gui.$textInputs = $( '<div>' )
.attr( 'id', 'transl-textinputs' );
$.each( gadget.defn, function ( i, defn ) {
var $num;
$( '<div>' )
.data( 'defn', defn.num )
.append(
$num = $( '<span>' )
.addClass( 'transl-def-label' )
.attr( 'title', defn.text )
.text( defn.num ),
$( '<input>' )
.attr( {
'type': 'text',
'size': 50
} ),
$( '<input>' )
.attr( {
'type': 'text',
'size': 1
} )
)
.appendTo( gui.$textInputs );
$num.tipsy( {
gravity: 'e'
} );
} );
gui.$loadButton = $( '<input>' )
.attr( {
type: 'button',
value: mw.msg( 'transl-load-button' )
} )
.on( 'click', $.proxy( onLoadLang, this, gui, null ) );
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' )
} )
.on( 'click', $.proxy( onSubmit, this, gui ) );
gui.$watch = $( '<input>' )
.attr( {
type: 'checkbox',
id: 'transl-watch'
} )
.prop( 'checked', !!mw.user.options.get( 'watchdefault' ) );
gui.$specialCharsButton = $( '<small>' )
.html( mw.msg( 'transl-keyboard' ) )
.on( 'click', function () {
gui.$keyboard.show();
} );
gui.$previewbox = $( '<div>' )
.attr( 'id', 'transl-preview' )
.append(
$( '<div>' ).append(
gui.$specialCharsButton,
' ',
$( '<small>' ).html( mw.msg( 'transl-report-error' ) )
),
$( '<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.language.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();
var action = charActions[ label ];
var 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,
gui.$loadButton
),
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' ) )
),
$( '<hr>' ),
gui.$previewbox
)
.appendTo( '#transl-field' );
gui.$editbox.on( 'focus', 'input[type="text"]', function () {
$activeTextInput = $( this );
} );
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
} )
.on( 'keypress', function ( evt ) {
if ( evt.keyCode === 13 ) { // Enter
onLoadLang( gui, null );
}
} );
resetForms( gui );
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.loader.using( [
'mediawiki.user',
'mediawiki.util',
'mediawiki.api',
'jquery.spinner',
'ext.gadget.section-links'
] )
.done( function () {
var currentRevId = mw.config.get( 'wgCurRevisionId' ).toString();
if (
mw.util.getParamValue( 'printable' ) ||
(
mw.util.getParamValue( 'oldid' ) &&
mw.util.getParamValue( 'oldid' ) !== currentRevId
)
) {
return;
}
mw.util.addCSS( css.join( ' ' ) );
mw.messages.set( messages );
api = new mw.Api();
mw.hook( mw.user.options.get( 'gadget-hide-empty-fields' )
? 'hideEmptyFields.ready'
: 'sectionLinks.ready'
).add( initialize );
} );
}
}( mediaWiki, jQuery ) );