Santhosh has uploaded a new change for review. https://gerrit.wikimedia.org/r/294702
Change subject: WIP: Simplified MT card ...................................................................... WIP: Simplified MT card Bug: T130594 Change-Id: I38a8147d164dc3b78ae6b43bd2baf8770a4944a4 --- M extension.json M i18n/en.json M i18n/qqq.json M modules/tools/ext.cx.tools.mt.js M modules/tools/styles/ext.cx.tools.mt.less 5 files changed, 212 insertions(+), 436 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation refs/changes/02/294702/1 diff --git a/extension.json b/extension.json index 990a3e6..1d7c872 100644 --- a/extension.json +++ b/extension.json @@ -633,6 +633,7 @@ "cx-tools-mt-provider-title", "cx-tools-mt-not-available", "cx-tools-mt-dont-use", + "cx-tools-mt-set-default", "cx-tools-mt-new-provider", "cx-tools-mt-new-providers-available" ], diff --git a/i18n/en.json b/i18n/en.json index 8f9cd99..368e17e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -78,6 +78,7 @@ "cx-tools-mt-provider-title": "Use $1", "cx-tools-mt-not-available": "Not available for $1", "cx-tools-mt-dont-use": "Don't use machine translation", + "cx-tools-mt-set-default": "Keep as default", "cx-tools-categories-count-message": "{{PLURAL:$1|$1 category|$1 categories|0=No categories}}", "cx-stats-title": "Content Translation statistics", "cx-tools-reference-title": "Reference", diff --git a/i18n/qqq.json b/i18n/qqq.json index 410b242..dd9ceb0 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -81,6 +81,7 @@ "cx-tools-mt-use-source": "A button in the machine translation tool card on Special:ContentTranslation. Clicking the button pastes the source text to the translation column.", "cx-tools-mt-clear-translation": "A button in the machine translation tool card on Special:ContentTranslation. Clicking the button removes the machine translation that was added to the paragraph.", "cx-tools-mt-restore": "A button in the machine translation tool card on Special:ContentTranslation. It appears if the translation was cleared using the button {{msg-mw|cx-tools-mt-clear-translation}}, and clicking it restores the machine translation.\n{{Identical|Restore}}", + "cx-tools-mt-set-default": "A button in the machine translation tool card on Special:ContentTranslation. Clicking the button saves the current machine translation option.", "cx-tools-mt-provider-title": "An item in a menu in the machine translation tool card on Special:ContentTranslation. The menu lists different available machine translation providers for this language.\n* $1 is the name of the provider, such as Apertium, Microsoft Translator, Google Translate, etc.\n{{Identical|Use}}", "cx-tools-mt-not-available": "An item in a menu in the machine translation tool card on Special:ContentTranslation. It's shown when there is no machine translation provider for that language. $1 is the name of the target language.", "cx-tools-mt-dont-use": "An item in a menu in the machine translation tool card on Special:ContentTranslation. Other items in same menu will use the message {{msg-mw|cx-tools-mt-from-provider}}. Selecting this item disables machine translation. It may be the default for some languages.", diff --git a/modules/tools/ext.cx.tools.mt.js b/modules/tools/ext.cx.tools.mt.js index d5117d4..bf686bc 100644 --- a/modules/tools/ext.cx.tools.mt.js +++ b/modules/tools/ext.cx.tools.mt.js @@ -16,18 +16,52 @@ jwt: undefined, promise: undefined }, - cache = {}, // MT requests cache + mtProvidersReuqestCache = {}, + mtRequestCache = {}, // MT requests cache providerIdPrefix = 'cx-provider-', - disableMT = 'disable-mt', noMT = 'no-mt', - sourceMT = 'source-mt', - translationOptions = [ disableMT, noMT, sourceMT ]; + sourceMT = 'source-mt'; + + function MachineTranslation( $section, options ) { + this.$section = $section; + this.siteMapper = options.siteMapper; + this.sourceLanguage = options.sourceLanguage; + this.targetLanguage = options.targetLanguage; + this.providers = null; + this.provider = null; + } + + MachineTranslation.prototype.init = function () { + var self = this; + + if ( this.providers ) { + // Selected provider can be changed by other instances of this class. + // So refresh it. + this.provider = this.getPreferredProvider(); + return $.Deferred().resolve(); + } + // This is for backwards compatibility with old drafts. For example + // we have lots of drafts stored with language code "no". + this.sourceLanguage = this.siteMapper.getLanguageCodeForWikiDomain( this.sourceLanguage ); + this.targetLanguage = this.siteMapper.getLanguageCodeForWikiDomain( this.targetLanguage ); + this.translationOptions = [ noMT, sourceMT ]; + if ( !this.$section || !this.$section.length || !this.$section.data( 'source' ) ) { + return $.Deferred().reject(); + } + + this.$sourceSection = mw.cx.getSourceSection( this.$section.data( 'source' ) ); + return this.getProviders().then( function ( providers ) { + self.providers = providers; + self.provider = self.getPreferredProvider(); + } ); + }; + /** * Fetch token for authentication with cxserver. * * @return {jQuery.Promise} */ - function getCXServerToken() { + MachineTranslation.prototype.getCXServerToken = function () { var now = Math.floor( Date.now() / 1000 ); // If request in progress, wait for it @@ -52,8 +86,7 @@ .always( function () { cxserverToken.promise = undefined; } ) - .then( - function ( response ) { + .then( function ( response ) { cxserverToken.jwt = response.jwt; cxserverToken.expires = response.exp; @@ -67,216 +100,27 @@ ); return cxserverToken.promise; - } + }; - /** - * Get the registry of machine translation providers - * for a language pair from the CX server. - * - * @param {string} from Source language - * @param {string} to Target language - * @return {jQuery.Promise} - */ - function getProviders( from, to ) { - var fetchProvidersUrl, - translationPreference; + MachineTranslation.prototype.doMT = function () { + var sourceId, self = this; - if ( MTControlCard.provider ) { - return $.Deferred().resolve(); - } + sourceId = this.$sourceSection.prop( 'id' ); - // This is for backwards compatibility with old drafts. For example - // we have lots of drafts stored with language code "no". - from = mw.cx.siteMapper.getLanguageCodeForWikiDomain( from ); - to = mw.cx.siteMapper.getLanguageCodeForWikiDomain( to ); - - // TODO: Refactor - fetchProvidersUrl = mw.cx.siteMapper.getCXServerUrl( '/list/mt/$from/$to', { - $from: from, - $to: to - } ); - - return $.get( fetchProvidersUrl ) - .done( function ( response ) { - MTControlCard.providers = response.mt || []; - translationPreference = mw.storage.get( getMTProviderStorageKey() ); - if ( MTControlCard.providers.indexOf( translationPreference ) < 0 && - translationOptions.indexOf( translationPreference ) < 0 ) { - // Stored MT preference is not available now. - translationPreference = null; - } - - if ( $.isEmptyObject( MTControlCard.providers ) ) { - MTControlCard.provider = translationPreference || noMT; - // For languages with different directionality, - // provide disable MT as default option. It gives - // an empty editor to translator. - if ( $.uls.data.getDir( mw.cx.sourceLanguage ) !== - $.uls.data.getDir( mw.cx.targetLanguage ) - ) { - MTControlCard.provider = translationPreference || disableMT; - } - } else { - // There are MT providers. If there is a saved mt provider preference - // select that from the providers. Otherwise select the first one. - MTControlCard.provider = translationPreference || MTControlCard.providers[ 0 ]; - } - } ) - .fail( function ( response ) { - mw.log( - 'Error getting translation providers from ' + fetchProvidersUrl + ' . ' + - response.statusText + ' (' + response.status + '). ' + - response.responseText - ); - } ); - } - - /** - * Get the localStorage key for the MT preference - * - * @return {string} The storage key. - */ - function getMTProviderStorageKey() { - return [ - 'cxMTProvider', mw.cx.sourceLanguage, mw.cx.targetLanguage - ].join( '-' ); - } - - /** - * Do machine translation. - * - * @param {string} sourceLang Source language - * @param {string} targetLang Target language - * @param {string} sourceHtml Content - * @return {jQuery.Promise} - */ - function doMT( sourceLang, targetLang, sourceHtml ) { - // TODO: Refactor - var mtURL = mw.cx.siteMapper.getCXServerUrl( '/mt/$from/$to/$provider', { - // This is for backwards compatibility with old drafts. For example - // we have lots of drafts stored with language code "no". - $from: mw.cx.siteMapper.getLanguageCodeForWikiDomain( sourceLang ), - $to: mw.cx.siteMapper.getLanguageCodeForWikiDomain( targetLang ), - $provider: MTControlCard.provider - } ); - - return getCXServerToken().then( function ( token ) { - return $.ajax( { - type: 'post', - url: mtURL, - data: { - html: sourceHtml - }, - headers: { - Authorization: token - } - } ).then( null, function () { - return $.Deferred().reject( 'service-failure', arguments ).promise(); - } ); - } ); - } - - function markMTLoading( $section ) { - $section.empty().append( mw.cx.widgets.spinner() ); - } - - /** - * Clean up the section by removing data-parsoid and data-mw attributes - * - * @param {jQuery} $section - * @return {string} - */ - function getSimplifiedHTMLForMT( $section ) { - var $wrapper = $( '<div>' ).append( $section.clone() ); - - $wrapper.find( '*' ).removeAttr( 'data-parsoid data-mw' ); - - return $wrapper.html(); - } - - /** - * Translate the given source section - * - * @param {jQuery} $section Source section to translate - * @param {boolean} prefetch Whether the translation of next secton to be prefetched - * @return {jQuery.Promise} - */ - function translateSection( $section, prefetch ) { - var sectionId, sourceContent, sectionTranslationRequest, - $nextSection, - provider = MTControlCard.provider; - - if ( !provider ) { - // Provider information not ready. Fetch it and call this method again. - return getProviders( mw.cx.sourceLanguage, mw.cx.targetLanguage ).then( function () { - translateSection( $section ); - } ); - } - - if ( provider === disableMT ) { - return $.Deferred().reject( 'mt-user-disabled' ).promise(); - } - - if ( provider === noMT ) { - return $.Deferred().reject( 'mt-not-available' ).promise(); - } - - if ( provider === sourceMT ) { - return $.Deferred().reject( 'mt-not-available' ).promise(); - } - - if ( $section.data( 'editable' ) === false ) { - return $.Deferred().reject( 'non-editable' ).promise(); - } - - sectionId = $section.prop( 'id' ); - sourceContent = getSimplifiedHTMLForMT( $section ); - sectionTranslationRequest = cache[ sectionId ] && cache[ sectionId ][ provider ]; - - if ( !sectionTranslationRequest ) { - sectionTranslationRequest = - doMT( mw.cx.sourceLanguage, mw.cx.targetLanguage, sourceContent ); - // Put that in cache. - cache[ sectionId ] = cache[ sectionId ] || {}; - cache[ sectionId ][ provider ] = sectionTranslationRequest; - } - - if ( prefetch ) { - $nextSection = $section.next(); - - if ( $nextSection.length ) { - translateSection( $nextSection ); - } - } - - return sectionTranslationRequest; - } - - /** - * A plugin that performs machine translation on a section element. - * - * @return {jQuery} - */ - $.fn.machineTranslate = function () { - var $sourceSection = $( this ), - prefetch = true, - sourceId = $sourceSection.prop( 'id' ), - $section = mw.cx.getTranslationSection( sourceId ); - - markMTLoading( $section ); - translateSection( $sourceSection, prefetch ) + // markMTLoading( $section ); + this.translateSection( this.$sourceSection, prefetch ) .done( function ( translation ) { if ( translation ) { // Translation is sent as json string // Automatically parsed by jQuery into object // Html is inside contents field - $section.replaceWith( $( translation.contents ) + self.$section.replaceWith( $( translation.contents ) .children() .attr( { id: 'cx' + sourceId, 'data-source': sourceId, 'data-cx-state': 'mt', - 'data-cx-mt-provider': MTControlCard.provider + 'data-cx-mt-provider': self.provider } ) ); } @@ -286,23 +130,84 @@ } ) .always( function () { // $section was replaced. Get the updated instance. - $section = mw.cx.getTranslationSection( sourceId ); - mw.hook( 'mw.cx.translation.postMT' ).fire( $section ); + self.$section = mw.cx.getTranslationSection( sourceId ); + mw.hook( 'mw.cx.translation.postMT' ).fire( self.$section ); } ); + }; - return this; + /** + * Get the registry of machine translation providers + * for a language pair from the CX server. + * + * @return {jQuery.Promise} + */ + MachineTranslation.prototype.getProviders = function () { + var fetchProvidersUrl, cacheKey; + + cacheKey = this.sourceLanguage + '-' + this.targetLanguage; + if ( mtProvidersReuqestCache[ cacheKey ] ) { + return mtProvidersReuqestCache[ cacheKey ]; + } + + fetchProvidersUrl = this.siteMapper.getCXServerUrl( '/list/mt/$from/$to', { + $from: this.sourceLanguage, + $to: this.targetLanguage + } ); + + mtProvidersReuqestCache[ cacheKey ] = $.get( fetchProvidersUrl ) + .then( function ( response ) { + return response.mt || []; + } ); + return mtProvidersReuqestCache[ cacheKey ]; + }; + + /** + * Get the localStorage key for the MT preference + * + * @return {string} The storage key. + */ + MachineTranslation.prototype.getMTProviderStorageKey = function () { + return [ 'cxMTProvider', this.sourceLanguage, this.targetLanguage + ].join( '-' ); + }; + + MachineTranslation.prototype.setDefaultProvider = function ( provider ) { + this.provider = provider; + mw.storage.set( this.getMTProviderStorageKey(), this.provider ); + }; + + MachineTranslation.prototype.getPreferredProvider = function () { + var storedMTPreference; + + storedMTPreference = mw.storage.get( this.getMTProviderStorageKey() ); + if ( this.providers.indexOf( storedMTPreference ) >= 0 || + this.translationOptions.indexOf( storedMTPreference ) >= 0 ) { + // Stored MT preference is available. + return storedMTPreference; + } + + if ( $.isEmptyObject( this.providers ) ) { + // For languages with different directionality, provide noMT + // as default option. It gives an empty editor to translator. + if ( $.uls.data.getDir( this.sourceLanguage ) !== + $.uls.data.getDir( this.targetLanguage ) + ) { + return noMT; + } else { + return sourceMT; + } + } else { + // There are MT providers. Select the first one. + return this.providers[ 0 ]; + } }; function MTControlCard() { this.$section = null; this.$card = null; + this.currentProvider = null; this.$translations = null; this.$providersMenu = null; - this.actions = { - $restore: null, - $clear: null, - $source: null - }; } MTControlCard.prototype.getCard = function () { @@ -322,72 +227,30 @@ this.$providerSelectorTrigger = $( '<div>' ) .addClass( 'card__trigger' ); - this.actions.$restore = $( '<div>' ) - .addClass( 'card__control-button cx-restore-translation' ) - .text( mw.msg( 'cx-tools-mt-restore' ) ); - - this.actions.$source = $( '<div>' ) - .addClass( 'card__control-button cx-use-source' ) - .text( mw.msg( 'cx-tools-mt-use-source' ) ); - - this.actions.$clear = $( '<div>' ) - .addClass( 'card__control-button cx-clear-translation' ) - .text( mw.msg( 'cx-tools-mt-clear-translation' ) ); + this.$keepDefault = $( '<div>' ) + .addClass( 'card__control-button cx-mt-set-default' ) + .text( mw.msg( 'cx-tools-mt-set-default' ) ) + .hide(); $controlButtonsBlock = $( '<div>' ) .addClass( 'card__button-block' ) - .append( // Object.values would be nice here - this.actions.$restore, - this.actions.$source, - this.actions.$clear - ); + .append( this.$keepDefault ); this.$card.append( $titleRow, this.$providerSelectorTrigger, $controlButtonsBlock ); - - this.buildProvidersMenu(); - + this.$providersMenu = $( [] ); this.listen(); return this.$card; }; - /** - * Update the section with text from source, - * not applying machine translation. - */ - MTControlCard.prototype.useSource = function () { - var sourceId = this.$section.data( 'source' ); - // Use the source without machine translation - mw.hook( 'mw.cx.translation.add' ).fire( sourceId, 'source' ); - }; - - /** - * Update the section with text from source, - * apply machine translation, - * and hide the restore button. - */ - MTControlCard.prototype.restoreTranslation = function () { - var sourceId = this.$section.data( 'source' ); - // Use the source without machine translation - mw.hook( 'mw.cx.translation.add' ).fire( sourceId, 'restore' ); - this.stop(); - }; - - /** - * Clear the translation text. - */ - MTControlCard.prototype.clearTranslation = function () { - var sourceId = this.$section.data( 'source' ); - - mw.hook( 'mw.cx.translation.add' ).fire( sourceId, 'clear' ); - }; - MTControlCard.prototype.selectProvider = function ( providerId ) { var $providerItem = $( '#' + providerIdPrefix + providerId ); + + this.currentProvider = providerId; // Hide the menu this.$providersMenu.hide(); @@ -395,49 +258,17 @@ // Mark the selected item this.$providersMenu.find( 'li' ).removeClass( 'selected' ); $providerItem.addClass( 'selected' ); - - // Set the global engine - if ( MTControlCard.provider !== providerId ) { - MTControlCard.provider = providerId; - // Apply this choice to the current section. - if ( providerId === sourceMT ) { - this.useSource(); - } else if ( providerId === disableMT ) { - this.clearTranslation(); - } else { - // Must be an MT engine. Restore. - this.restoreTranslation(); - } - - // Save the current provider - mw.storage.set( getMTProviderStorageKey(), providerId ); - + if ( providerId !== this.mt.provider ) { + this.$keepDefault.show(); + } else { + this.$keepDefault.hide(); } // Set the main label this.$providerSelectorTrigger.text( this.getProviderTitle( providerId ) ); }; - /* - * Toggle the section highlight. - */ - MTControlCard.prototype.toggleSectionHighlight = function () { - this.$section.toggleClass( 'cx-highlight' ); - }; - MTControlCard.prototype.listen = function () { var self = this; - - this.actions.$source - .on( 'click', $.proxy( this.useSource, this ) ) - .on( 'mouseenter mouseleave', $.proxy( this.toggleSectionHighlight, this ) ); - - this.actions.$clear - .on( 'click', $.proxy( this.clearTranslation, this ) ) - .on( 'mouseenter mouseleave', $.proxy( this.toggleSectionHighlight, this ) ); - - this.actions.$restore - .on( 'click', $.proxy( this.restoreTranslation, this ) ) - .on( 'mouseenter mouseleave', $.proxy( this.toggleSectionHighlight, this ) ); this.$providerSelectorTrigger .on( 'click', function ( e ) { @@ -445,75 +276,40 @@ e.stopPropagation(); } ); - this.$providersMenu.find( '.card__providers-menu-item' ) - .on( 'click', function () { - self.selectProvider( $( this ).data( 'provider' ) ); - // Restore the selection - mw.cx.selection.restore( 'translation' ); - } ) - .on( 'mouseenter mouseleave', $.proxy( this.toggleSectionHighlight, this ) ); - // Hide the dropdown on clicking outside of it $( 'html' ).on( 'click', function ( e ) { if ( !e.isDefaultPrevented() ) { self.$providersMenu.hide(); } } ); + this.$keepDefault.on( 'click', function () { + self.mt.setDefaultProvider( self.currentProvider ); + self.$keepDefault.hide(); + } ); }; - MTControlCard.prototype.buildProvidersMenu = function () { - var provider, items = [], - nonDefaultMT, translationPreference, newProvider = false; - - translationPreference = mw.storage.get( getMTProviderStorageKey() ); - - if ( - // If there are more than one provider - MTControlCard.providers && MTControlCard.providers.length > 1 && - // If there is no stored preference or preference is not a MT engine - ( translationPreference === null || - translationOptions.indexOf( translationPreference ) >= 0 ) - ) { - nonDefaultMT = true; - // There are more MT options or non default MT available. Announce. - this.$card.find( '.card__title-row' ) - .addClass( 'card--new' ) - .append( $( '<div>' ) - .text( mw.msg( 'cx-tools-mt-new-providers-available' ) ) - .addClass( 'card__new-providers' ) - ); - } + MTControlCard.prototype.buildProvidersMenu = function ( providers ) { + var i, self = this, + newProvider = false; this.$providersMenu = $( '<ul>' ) .addClass( 'card__providers-menu' ) .hide(); - if ( MTControlCard.providers ) { - items = MTControlCard.providers.slice( 0 ); // Copy values. - } - if ( items.indexOf( sourceMT ) < 0 ) { - items.push( sourceMT ); - } - if ( items.indexOf( disableMT ) < 0 ) { - items.push( disableMT ); - } // Add available machine translation engines to the menu - for ( provider in items ) { - if ( !items.hasOwnProperty( provider ) ) { - continue; - } - - if ( nonDefaultMT && translationOptions.indexOf( items[ provider ] ) < 0 ) { - newProvider = true; - } else { - newProvider = false; - } + for ( i = 0; i < providers.length; i++ ) { this.$providersMenu.append( - this.getProviderItem( items[ provider ], newProvider ) + this.getProviderMenuItem( providers[ i ], newProvider ) ); } this.$providerSelectorTrigger.after( this.$providersMenu ); + this.$providersMenu.find( '.card__providers-menu-item' ) + .on( 'click', function () { + self.selectProvider( $( this ).data( 'provider' ) ); + // Restore the selection + // mw.cx.selection.restore( 'translation' ); + } ); }; /** @@ -522,20 +318,17 @@ * @param {string} id Provider id. * @return {string} */ - MTControlCard.prototype.getProviderTitle = function ( id ) { + MTControlCard.prototype.getProviderTitle = function ( providerId ) { var providerLabels = { Yandex: 'Yandex.Translate' }; - if ( id === disableMT ) { + if ( providerId === noMT ) { return mw.msg( 'cx-tools-mt-dont-use' ); - } else if ( id === noMT ) { - return mw.msg( 'cx-tools-mt-not-available', $.uls.data.getAutonym( mw.cx.targetLanguage ) ); - } else if ( id === sourceMT ) { - // FIXME: message reuse + } else if ( providerId === sourceMT ) { return mw.msg( 'cx-tools-mt-use-source' ); } else { - return mw.msg( 'cx-tools-mt-provider-title', providerLabels[ id ] || id ); + return mw.msg( 'cx-tools-mt-provider-title', providerLabels[ providerId ] || providerId ); } }; @@ -545,15 +338,13 @@ * @param {string} providerId Provider id. * @return {jQuery} */ - MTControlCard.prototype.getProviderItem = function ( providerId, newProvider ) { - var $label, $new = $( [] ); + MTControlCard.prototype.getProviderMenuItem = function ( providerId, newProvider ) { + var $label, + $new = $( [] ); + $label = $( '<span>' ) - .text( this.getProviderTitle( providerId ) ) - .addClass( 'card__providers-menu-item' ) - .attr( { - id: providerIdPrefix + providerId, - 'data-provider': providerId - } ); + .text( this.getProviderTitle( providerId ) ); + if ( newProvider ) { $new = $( '<span>' ) .text( mw.msg( 'cx-tools-mt-new-provider' ) ) @@ -561,46 +352,34 @@ } return $( '<li>' ) + .addClass( 'card__providers-menu-item' ) + .attr( { + id: providerIdPrefix + providerId, + 'data-provider': providerId + } ) .append( $label, $new ); }; MTControlCard.prototype.start = function ( $section ) { - var state, - provider = MTControlCard.provider; + var self = this, + options; this.$section = $section; - this.selectProvider( provider ); - - // Hide or disable action buttons depending on the state. - // Disabling is achieved by changing style. Actions are - // only disabled if they were already executed and no changes - // have been done after that. Hence there is no need to actually - // prevent doing them again. - state = $section.data( 'cx-state' ); - - if ( - state === 'mt' || - provider === disableMT || - provider === sourceMT || - provider === noMT - ) { - this.actions.$restore.hide(); - } else { - this.actions.$restore.show(); + this.mt = this.$section.data( 'cxmt' ); + if ( !this.mt ) { + options = { + siteMapper: mw.cx.siteMapper, + sourceLanguage: mw.cx.sourceLanguage, + targetLanguage: mw.cx.targetLanguage + }; + this.mt = new MachineTranslation( this.$section, options ); + this.$section.data( 'cxmt', this.mt ); } - - if ( state === 'empty' ) { - this.actions.$clear.addClass( 'card__control-button--disabled' ); - } else { - this.actions.$clear.removeClass( 'card__control-button--disabled' ); - } - - if ( state === 'source' ) { - this.actions.$source.addClass( 'card__control-button--disabled' ); - } else { - this.actions.$source.removeClass( 'card__control-button--disabled' ); - } - + this.mt.init().then( function () { + var menuItems = self.mt.providers.concat( self.mt.translationOptions ); + self.buildProvidersMenu( menuItems ); + self.selectProvider( self.mt.provider ); + } ); this.$card.show(); this.onShow(); }; @@ -625,7 +404,8 @@ $( function () { mw.hook( 'mw.cx.source.ready' ).add( $.proxy( function () { - translateSection( $( '.cx-column__content' ).find( mw.cx.getSectionSelector() ).first(), true ); + // Initiate the request for first section. + // translateSection( $( '.cx-column__content' ).find( mw.cx.getSectionSelector() ).first(), true ); }, this ) ); } ); }( jQuery, mediaWiki ) ); diff --git a/modules/tools/styles/ext.cx.tools.mt.less b/modules/tools/styles/ext.cx.tools.mt.less index 0d79ed2..db7829d 100644 --- a/modules/tools/styles/ext.cx.tools.mt.less +++ b/modules/tools/styles/ext.cx.tools.mt.less @@ -19,20 +19,18 @@ .card__trigger { .mw-ui-item; .mw-ui-two-thirds; - padding-left: 10px; - padding-bottom: 10px; + padding: 5px 10px 10px; cursor: pointer; color: #555; - &:after { - width: 0; - height: 0; - content: ""; + .background-image-svg( '../images/dropdown.svg', '../images/dropdown.png'); + content: ''; display: inline-block; - border-style: solid; - border-width: 5px 5px 0 5px; - border-color: #555 transparent transparent transparent; - margin-left: 10px; + width: 20px; + height: 12px; + right: -5px; + position: relative; + bottom: 50%; } } @@ -41,34 +39,34 @@ .mw-ui-one-half; list-style: none; position: absolute; - margin-top: 30px; - background-color: white; + margin: 30px 10px; + background-color: #fff; border: 1px solid #aaa; + border-radius: 2px; + box-shadow: 0 1px 0 #C9C9C9; padding: 0; z-index: 1; - >li { + > li { cursor: pointer; - padding: 5px; + padding: 10px 20px; &.selected { - .background-image-svg('../images/tick.svg', '../images/tick.png'); + .background-image-svg( '../images/tick.svg', '../images/tick.png'); background-repeat: no-repeat; background-position: right 4px center; } - &:hover { background-color: #6698FF; color: #FFF; } } - :after, :before { bottom: 100%; left: 25%; border: solid transparent; - content: " "; + content: ' '; height: 0; width: 0; position: absolute; @@ -76,14 +74,14 @@ } :after { - border-color: rgba(255, 255, 255, 0); - border-bottom-color: #FFF; + border-color: rgba( 255, 255, 255, 0 ); + border-bottom-color: #fff; border-width: 10px; margin-left: -10px; } :before { - border-color: rgba(238, 238, 238, 0); + border-color: rgba( 238, 238, 238, 0 ); border-bottom-color: #aaa; border-width: 11px; margin-left: -11px; @@ -101,15 +99,13 @@ .mw-ui-one-whole; line-height: 1.5em; color: @gray; - padding: 0; + border-top: 1px solid #dddddd; .card__control-button { .mw-ui-one-half; color: @gray-dark; cursor: pointer; - padding: 10px 10px 10px 25px; /* grid override */ - border-top: 1px solid #dddddd; - border-left: 1px solid #dddddd; + padding: 10px 20px; background-repeat: no-repeat; background-position: left 4px center; @@ -119,25 +115,22 @@ } } - .cx-use-source { - .background-image-svg('../images/pasting.svg', '../images/pasting.png'); - } - - .cx-clear-translation { - .background-image-svg('../images/clear.svg', '../images/clear.png'); + .cx-mt-set-default { + .background-image-svg( '../images/tick.svg', '../images/tick.png' ); + background-repeat: no-repeat; + background-position: left 4px center; } .cx-restore-translation { - .background-image-svg('../images/arched-arrow-ltr.svg', '../images/arched-arrow-ltr.png'); - border: none; + .background-image-svg( '../images/arched-arrow-ltr.svg', '../images/arched-arrow-ltr.png'); + border: 0; float: none; } } - - .card__title-row.card--new::before { - content: ""; - width: 0px; - height: 0px; + .card__title-row.card--new:before { + content: ''; + width: 0; + height: 0; float: right; border-top: 30px solid #00af89; border-left: 30px solid transparent; @@ -147,7 +140,7 @@ } .card__title-row.card--new > .card__new-providers { - padding: 0 5px 5px 5px; + padding: 0 5px 5px; color: #00af89; font-size: 1em; } -- To view, visit https://gerrit.wikimedia.org/r/294702 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I38a8147d164dc3b78ae6b43bd2baf8770a4944a4 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/ContentTranslation Gerrit-Branch: master Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits