summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/Translate/resources/js/ext.translate.editor.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/Translate/resources/js/ext.translate.editor.js')
-rw-r--r--www/wiki/extensions/Translate/resources/js/ext.translate.editor.js297
1 files changed, 197 insertions, 100 deletions
diff --git a/www/wiki/extensions/Translate/resources/js/ext.translate.editor.js b/www/wiki/extensions/Translate/resources/js/ext.translate.editor.js
index 47038ec6..b5e3637d 100644
--- a/www/wiki/extensions/Translate/resources/js/ext.translate.editor.js
+++ b/www/wiki/extensions/Translate/resources/js/ext.translate.editor.js
@@ -1,4 +1,6 @@
-( function ( $, mw, autosize ) {
+/* global autosize */
+
+( function () {
'use strict';
/**
@@ -16,9 +18,9 @@
* internally contain the editor's generated UI. So it is going to have the same width
* and inherited properies of the container.
* The container can mark the message item with class 'message'. This is not
- * mandatory, but if found, when editor is opened the message item will be hidden
+ * mandatory, but if found, when the editor is opened, the message item will be hidden
* and the editor will appear as if the message is replaced by the editor.
- * See the UI of Translate messagetable for demo.
+ * See the UI of Translate messagetable for a demo.
*
* @param {HTMLElement} element
* @param {Object} options
@@ -157,8 +159,8 @@
);
this.$messageItem
- .addClass( 'translated' )
- .removeClass( 'untranslated' );
+ .removeClass( 'untranslated translated fuzzy proofread' )
+ .addClass( 'translated' );
this.dirty = false;
@@ -167,6 +169,8 @@
'change',
[ 'translated', this.message.properties.status ]
);
+
+ this.message.properties.status = 'translated';
// TODO: Update any other statsbar for the same group in the page.
}
},
@@ -175,11 +179,13 @@
* Save the translation
*/
save: function () {
- var translation,
+ var translation, editSummary,
translateEditor = this;
- mw.translateHooks.run( 'beforeSubmit', translateEditor.$editor );
+ mw.hook( 'mw.translate.editor.beforeSubmit' ).fire( translateEditor.$editor );
translation = translateEditor.$editor.find( '.editcolumn textarea' ).val();
+ editSummary = translateEditor.$editor.find( '.tux-input-editsummary' ).val() || '';
+
translateEditor.saving = true;
// beforeSave callback
@@ -204,15 +210,33 @@
this.storage.save(
translateEditor.message.title,
- translation
- ).done( function () {
- // Update the translation
- translateEditor.message.translation = translation;
- translateEditor.onSaveSuccess();
+ translation,
+ editSummary
+ ).done( function ( response, xhr ) {
+ var editResp = response.edit;
+ if ( editResp.result === 'Success' ) {
+ translateEditor.message.translation = translation;
+ translateEditor.onSaveSuccess();
+ // Handle errors
+ } else if ( editResp.spamblacklist ) {
+ // @todo Show exactly which blacklisted URL triggered it
+ translateEditor.onSaveFail( mw.msg( 'spamprotectiontext' ) );
+ } else if ( editResp.info &&
+ editResp.info.indexOf( 'Hit AbuseFilter:' ) === 0 &&
+ editResp.warning
+ ) {
+ translateEditor.onSaveFail( editResp.warning );
+ } else {
+ translateEditor.onSaveFail( mw.msg( 'tux-save-unknown-error' ) );
+ mw.log( response, xhr );
+ }
} ).fail( function ( errorCode, response ) {
- translateEditor.onSaveFail( response.error && response.error.info || 'Unknown error' );
+ translateEditor.onSaveFail(
+ response.error && response.error.info || mw.msg( 'tux-save-unknown-error' )
+ );
if ( errorCode === 'assertuserfailed' ) {
- window.alert( mw.msg( 'tux-session-expired' ) );
+ // eslint-disable-next-line no-alert
+ alert( mw.msg( 'tux-session-expired' ) );
}
} );
},
@@ -231,17 +255,26 @@
this.removeWarning( 'fuzzy' );
this.removeWarning( 'validation' );
+ this.$editor.find( '.tux-warning' ).empty();
+ this.$editor.find( '.tux-more-warnings' )
+ .addClass( 'hide' )
+ .empty();
+
$( '.tux-editor-clear-translated' )
.removeClass( 'hide' )
.prop( 'disabled', false );
+ this.$editor.find( '.tux-input-editsummary' )
+ .val( '' )
+ .prop( 'disabled', true );
+
// Save callback
if ( this.options.onSave ) {
this.options.onSave( this.message.translation );
}
mw.translate.dirty = false;
- mw.translateHooks.run( 'afterSubmit', this.$editor );
+ mw.hook( 'mw.translate.editor.afterSubmit' ).fire( this.$editor );
if ( mw.track ) {
mw.track( 'ext.translate.event.translation', this.message );
@@ -279,7 +312,9 @@
// Skip if the message is hidden. For example in a filter result.
if ( $next.length && $next.hasClass( 'hide' ) ) {
this.$editTrigger = $next;
- return this.next();
+ this.next();
+
+ return;
}
// If this is the last message, just hide it
@@ -333,7 +368,20 @@
* @return {jQuery} The new message tools menu element
*/
createMessageTools: function () {
- var $historyItem, $deleteItem, $translationsItem;
+ var $editItem, $historyItem, $deleteItem, $translationsItem, $linkToThisItem;
+
+ $editItem = this.createMessageToolsItem(
+ 'message-tools-edit',
+ {
+ title: this.message.title,
+ action: 'edit'
+ },
+ 'tux-editor-message-tools-show-editor'
+ );
+
+ if ( !mw.translate.canTranslate() ) {
+ $editItem.addClass( 'hide' );
+ }
$historyItem = this.createMessageToolsItem(
'message-tools-history',
@@ -373,9 +421,19 @@
'tux-editor-message-tools-translations'
);
+ $linkToThisItem = this.createMessageToolsItem(
+ 'message-tools-linktothis',
+ {
+ title: 'Special:Translate',
+ showMessage: this.message.key,
+ group: this.message.primaryGroup
+ },
+ 'tux-editor-message-tools-linktothis'
+ );
+
return $( '<ul>' )
.addClass( 'tux-dropdown-menu tux-message-tools-menu hide' )
- .append( $historyItem, $deleteItem, $translationsItem );
+ .append( $editItem, $historyItem, $deleteItem, $translationsItem, $linkToThisItem );
},
prepareEditorColumn: function () {
@@ -392,6 +450,8 @@
$controlButtonBlock,
$editingButtonBlock,
$pasteOriginalButton,
+ $editSummary,
+ $editSummaryBlock,
$discardChangesButton = $( [] ),
$saveButton,
$requestRight,
@@ -402,7 +462,7 @@
$layoutActions,
$infoToggleIcon,
$messageList,
- targetLangAttrib, targetLangDir, targetLangCode,
+ targetLangAttrib, targetLangDir, targetLangCode, prefix,
$messageTools = translateEditor.createMessageTools(),
canTranslate = mw.translate.canTranslate();
@@ -444,7 +504,7 @@
.append( $closeIcon, $infoToggleIcon );
$editorColumn.append( $( '<div>' )
- .addClass( 'row' )
+ .addClass( 'row tux-editor-titletools' )
.append( $messageKeyLabel, $layoutActions )
);
@@ -452,7 +512,7 @@
originalTranslation = this.message.translation;
sourceString = this.message.definition;
$sourceString = $( '<span>' )
- .addClass( 'eleven column sourcemessage' )
+ .addClass( 'twelve columns sourcemessage' )
.attr( {
lang: $messageList.data( 'sourcelangcode' ),
dir: $messageList.data( 'sourcelangdir' )
@@ -483,7 +543,7 @@
$moreWarnings = $warnings.children(),
lastWarningIndex = $moreWarnings.length - 1;
- // If the warning list is not open only one warning is shown
+ // If the warning list is not open, only one warning is shown
if ( $this.hasClass( 'open' ) ) {
$moreWarnings.each( function ( index, element ) {
// The first element must always be shown
@@ -562,7 +622,9 @@
e.stopPropagation();
translateEditor.$editor.find( '.shortcut-activated:visible' ).eq( index ).trigger( 'click' );
// Update numbers and locations after trigger should be completed
- window.setTimeout( function () { translateEditor.showShortcuts(); }, 100 );
+ window.setTimeout( function () {
+ translateEditor.showShortcuts();
+ }, 100 );
}
if ( e.which === 18 && e.type === 'keyup' ) {
@@ -598,7 +660,7 @@
// When there is content in the editor enable the button.
// But do not enable when some saving is not finished yet.
- if ( $.trim( current ) && !translateEditor.saving ) {
+ if ( current.trim() && !translateEditor.saving ) {
$pasteSourceButton.addClass( 'hide' );
$saveButton.prop( 'disabled', false );
} else {
@@ -620,7 +682,7 @@
$editAreaBlock = $( '<div>' )
.addClass( 'row tux-editor-editarea-block' )
.append( $( '<div>' )
- .addClass( 'editarea eleven columns' )
+ .addClass( 'editarea twelve columns' )
.append( $warningsBlock, $textarea )
);
@@ -639,6 +701,36 @@
$pasteOriginalButton.addClass( 'hide' );
} );
+ $editSummary = $( '<input>' )
+ .addClass( 'tux-input-editsummary' )
+ .attr( {
+ maxlength: 255,
+ disabled: true,
+ placeholder: mw.msg( 'tux-editor-editsummary-placeholder' )
+ } )
+ .val( '' );
+
+ // Enable edit summary if there was a change to translation area
+ // or disable if there is no text in translation area
+ $textarea.on( 'textchange', function () {
+ if ( $editSummary.prop( 'disabled' ) ) {
+ $editSummary.prop( 'disabled', false );
+ }
+ if ( $textarea.val().trim() === '' ) {
+ $editSummary.prop( 'disabled', true );
+ }
+ } ).on( 'keydown', function ( e ) {
+ if ( !e.ctrlKey || e.keyCode !== 13 ) {
+ return;
+ }
+
+ if ( !$saveButton.is( ':disabled' ) ) {
+ $saveButton.click();
+ return;
+ }
+ $skipButton.click();
+ } );
+
if ( originalTranslation !== null ) {
$discardChangesButton = $( '<button>' )
.addClass( 'tux-editor-discard-changes-button hide' ) // Initially hidden
@@ -653,6 +745,7 @@
$discardChangesButton.addClass( 'hide' );
// There's nothing new to save...
+ $editSummary.val( '' ).prop( 'disabled', true );
$saveButton.prop( 'disabled', true );
// ...unless there is other action
translateEditor.makeSaveButtonContextSensitive( $saveButton );
@@ -667,17 +760,25 @@
}
$editingButtonBlock = $( '<div>' )
- .addClass( 'ten columns tux-editor-insert-buttons' )
+ .addClass( 'twelve columns tux-editor-insert-buttons' )
.append(
$pasteOriginalButton,
$discardChangesButton
);
+ $editSummaryBlock = $( '<div>' )
+ .addClass( 'row tux-editor-editsummary-block' )
+ .append(
+ $( '<div>' )
+ .addClass( 'twelve columns' )
+ .append( $editSummary )
+ );
+
$requestRight = $( [] );
$saveButton = $( '<button>' )
.prop( 'disabled', true )
- .addClass( 'blue button tux-editor-save-button' )
+ .addClass( 'tux-editor-save-button mw-ui-button mw-ui-progressive' )
.text( mw.msg( 'tux-editor-save-button-label' ) )
.on( 'click', function ( e ) {
translateEditor.save();
@@ -688,21 +789,26 @@
} else {
$editingButtonBlock = $( [] );
+ $editSummaryBlock = $( [] );
+
$requestRight = $( '<span>' )
.addClass( 'tux-editor-request-right' )
- .text( mw.msg( 'translate-edit-nopermission' ) )
- .append( $( '<a>' )
- .text( mw.msg( 'translate-edit-askpermission' ) )
- .addClass( 'tux-editor-ask-permission' )
- .attr( {
- href: mw.util.getUrl(
- mw.config.get( 'wgTranslateUseSandbox' ) ?
- 'Special:TranslationStash' :
- mw.config.get( 'wgTranslatePermissionUrl' )
- )
- } )
- );
-
+ .text( mw.msg( 'translate-edit-nopermission' ) );
+ // Make sure wgTranslatePermissionUrl setting is not 'false'
+ if ( mw.config.get( 'wgTranslatePermissionUrl' ) !== false ) {
+ $requestRight
+ .append( $( '<a>' )
+ .text( mw.msg( 'translate-edit-askpermission' ) )
+ .addClass( 'tux-editor-ask-permission' )
+ .attr( {
+ href: mw.util.getUrl(
+ mw.config.get( 'wgTranslateUseSandbox' ) ?
+ 'Special:TranslationStash' :
+ mw.config.get( 'wgTranslatePermissionUrl' )
+ )
+ } )
+ );
+ }
// Disable the text area if user has no translation rights.
// Use readonly to allow copy-pasting (except for placeholders)
$textarea.prop( 'readonly', true );
@@ -711,7 +817,7 @@
}
$skipButton = $( '<button>' )
- .addClass( 'button tux-editor-skip-button' )
+ .addClass( 'tux-editor-skip-button mw-ui-button mw-ui-quiet' )
.text( mw.msg( 'tux-editor-skip-button-label' ) )
.on( 'click', function ( e ) {
translateEditor.skip();
@@ -726,7 +832,7 @@
// This appears instead of "Skip" on the last message on the page
$cancelButton = $( '<button>' )
- .addClass( 'button tux-editor-cancel-button' )
+ .addClass( 'tux-editor-cancel-button mw-ui-button mw-ui-quiet' )
.text( mw.msg( 'tux-editor-cancel-button-label' ) )
.on( 'click', function ( e ) {
translateEditor.skip();
@@ -741,30 +847,28 @@
$editorColumn.append( $( '<div>' )
.addClass( 'row tux-editor-actions-block' )
- .append( $editingButtonBlock, $controlButtonBlock )
+ .append( $editingButtonBlock )
);
- if ( canTranslate ) {
- // BC for MW <= 1.26
+ $editorColumn.append( $editSummaryBlock );
- ( function () {
- if ( mw.loader.getState( 'jquery.accessKeyLabel' ) ) {
- return mw.loader.using( 'jquery.accessKeyLabel' ).then( function () {
- return $.fn.updateTooltipAccessKeys.getAccessKeyPrefix();
- } );
- }
+ $editorColumn.append( $( '<div>' )
+ .addClass( 'row tux-editor-actions-block' )
+ .append( $controlButtonBlock )
+ );
- return $.Deferred().resolve( mw.util.tooltipAccessKeyPrefix );
- }() ).done( function ( prefix ) {
- $editorColumn.append( $( '<div>' )
- .addClass( 'row shortcutinfo' )
- .text( mw.msg( 'tux-editor-shortcut-info',
- ( prefix + 's' ).toUpperCase(),
- ( prefix + 'd' ).toUpperCase(),
- 'ALT' )
- )
- );
- } );
+ if ( canTranslate ) {
+ prefix = $.fn.updateTooltipAccessKeys.getAccessKeyPrefix();
+ $editorColumn.append( $( '<div>' )
+ .addClass( 'row shortcutinfo' )
+ .text( mw.msg(
+ 'tux-editor-shortcut-info',
+ 'CTRL-ENTER',
+ ( prefix + 'd' ).toUpperCase(),
+ 'ALT',
+ ( prefix + 'b' ).toUpperCase()
+ ) )
+ );
}
return $editorColumn;
@@ -823,21 +927,18 @@
*/
validateTranslation: function () {
var translateEditor = this,
- url,
+ api,
$textarea = translateEditor.$editor.find( '.tux-textarea-translation' );
- // TODO: We need a better API for this
- url = mw.util.getUrl( 'Special:Translate/editpage', {
- suggestions: 'checks',
- page: translateEditor.message.title,
- loadgroup: translateEditor.message.group
- } );
+ api = new mw.Api();
- $.post( url, {
+ api.post( {
+ action: 'translationcheck',
+ title: this.message.title,
translation: $textarea.val()
- }, function ( data ) {
+ } ).done( function ( data ) {
var warningIndex,
- warnings = JSON.parse( data );
+ warnings = data.warnings;
translateEditor.removeWarning( 'validation' );
if ( !warnings || !warnings.length ) {
@@ -876,7 +977,10 @@
},
/**
- * Displays the supplied warning from the bottom up near the translation edit area.
+ * Displays the supplied warning above the translation edit area.
+ * Newer warnings are added to the top while older warnings are
+ * added to the bottom. This also means that older warnings will
+ * not be shown by default unless the user clicks "more warnings" tab.
*
* @param {string} warning used as html for the warning display
* @param {string} type used to group the warnings.eg: validation, diff, error
@@ -887,21 +991,21 @@
$warnings = this.$editor.find( '.tux-warning' ),
$moreWarningsTab = this.$editor.find( '.tux-more-warnings' ),
$newWarning = $( '<div>' )
- .addClass( 'tux-warning-message hide ' + type )
+ .addClass( 'tux-warning-message ' + type )
.html( warning );
+ this.$editor.find( '.tux-warning-message' ).addClass( 'hide' );
+
$warnings
.removeClass( 'hide' )
- .append( $newWarning );
+ .prepend( $newWarning );
warningCount = $warnings.find( '.tux-warning-message' ).length;
- $warnings.find( '.tux-warning-message:first' ).removeClass( 'hide' );
-
if ( warningCount > 1 ) {
$moreWarningsTab
.text( mw.msg( 'tux-warnings-more', warningCount - 1 ) )
- .removeClass( 'hide' );
+ .removeClass( 'hide open' );
} else {
$moreWarningsTab.addClass( 'hide' );
}
@@ -923,7 +1027,7 @@
if ( mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {
$messageDescSaveButton = $( '<button>' )
- .addClass( 'blue button tux-editor-savedoc-button' )
+ .addClass( 'tux-editor-savedoc-button mw-ui-button mw-ui-progressive' )
.prop( 'disabled', true )
.text( mw.msg( 'tux-editor-doc-editor-save' ) )
.on( 'click', function () {
@@ -935,7 +1039,7 @@
} );
$messageDescCancelButton = $( '<button>' )
- .addClass( 'button tux-editor-skipdoc-button' )
+ .addClass( 'tux-editor-skipdoc-button mw-ui-button mw-ui-quiet' )
.text( mw.msg( 'tux-editor-doc-editor-cancel' ) )
.on( 'click', function () {
translateEditor.hideDocumentationEditor();
@@ -973,12 +1077,12 @@
.append( $( '<a>' )
.attr( {
href: mw.translate.getDocumentationEditURL(
- this.message.title.replace( /\/[a-z\-]+$/, '' )
+ this.message.title.replace( /\/[a-z-]+$/, '' )
),
target: '_blank'
} )
.addClass( 'message-desc-edit' )
- .on( 'click', $.proxy( this.showDocumentationEditor, this ) )
+ .on( 'click', this.showDocumentationEditor.bind( this ) )
)
);
@@ -1024,7 +1128,7 @@
return $( '<div>' )
.addClass( 'five columns infocolumn-block' )
.append(
- $( '<span>' ).addClass( 'caret' ),
+ $( '<span>' ).addClass( 'tux-message-editor__caret' ),
$infoColumn
);
},
@@ -1046,6 +1150,7 @@
$( '.tux-editor-save-button, .tux-editor-save-button' ).removeAttr( 'accesskey' );
this.$editor.find( '.tux-editor-save-button' ).attr( 'accesskey', 's' );
this.$editor.find( '.tux-editor-skip-button' ).attr( 'accesskey', 'd' );
+ this.$editor.find( '.tux-input-editsummary' ).attr( 'accesskey', 'b' );
// @todo access key for the cancel button
this.$messageItem.addClass( 'hide' );
@@ -1065,7 +1170,7 @@
$next.data( 'translateeditor' ).init();
}
- mw.translateHooks.run( 'afterEditorShown', this.$editor );
+ mw.hook( 'mw.translate.editor.afterEditorShown' ).fire( this.$editor );
return false;
},
@@ -1108,12 +1213,7 @@
.addClass( 'editor-expand' )
.attr( 'title', mw.msg( 'tux-editor-expand-tooltip' ) );
- this.$editor.find( '.infocolumn-block' )
- .removeClass( 'hide' );
- this.$editor.find( '.editcolumn' )
- .removeClass( 'twelve' )
- .addClass( 'seven' );
-
+ this.$editor.removeClass( 'tux-message-editor--expanded' );
this.expanded = false;
},
@@ -1124,12 +1224,7 @@
.addClass( 'editor-contract' )
.attr( 'title', mw.msg( 'tux-editor-collapse-tooltip' ) );
- this.$editor.find( '.infocolumn-block' )
- .addClass( 'hide' );
- this.$editor.find( '.editcolumn' )
- .removeClass( 'seven' )
- .addClass( 'twelve' );
-
+ this.$editor.addClass( 'tux-message-editor--expanded' );
this.expanded = true;
},
@@ -1147,7 +1242,7 @@
}
// Load the diff styles
- mw.loader.load( 'mediawiki.action.history.diff', undefined, true );
+ mw.loader.load( 'mediawiki.diff.styles' );
$trigger = $( '<span>' )
.addClass( 'show-diff-link' )
@@ -1178,14 +1273,16 @@
/**
* Makes the textare large enough for insertables and positions the insertables.
+ *
+ * @param {jQuery} $textarea Text area.
*/
resizeInsertables: function ( $textarea ) {
var $buttonArea, buttonAreaHeight;
$buttonArea = this.$editor.find( '.tux-editor-insert-buttons' );
buttonAreaHeight = $buttonArea.height();
- $textarea.css( 'padding-bottom', buttonAreaHeight + 10 );
- $buttonArea.css( 'top', -buttonAreaHeight - 5 );
+ $textarea.css( 'padding-bottom', buttonAreaHeight + 5 );
+ $buttonArea.css( 'top', -buttonAreaHeight );
autosize.update( $textarea );
}
};
@@ -1224,4 +1321,4 @@
};
}() );
}
-}( jQuery, mediaWiki, autosize ) );
+}() );