diff options
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.js | 297 |
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 ) ); +}() ); |