jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/371473 )

Change subject: Improve the New Translation dialog
......................................................................


Improve the New Translation dialog

Make New translation dialog show in-place, closable by click outside.
Make selection status clearly differentiable from the search one.

Bug: T111094
Change-Id: I222a29f56786a59f97e03d631b05c37cc9678b15
---
M modules/dashboard/ext.cx.dashboard.js
M modules/dashboard/styles/ext.cx.suggestionlist.less
M modules/source/ext.cx.source.selector.js
M modules/source/styles/ext.cx.source.selector.less
M modules/ui/widgets/mw.cx.ui.PageSelectorWidget.js
M modules/widgets/overlay/ext.cx.overlay.js
M modules/widgets/overlay/ext.cx.overlay.less
7 files changed, 526 insertions(+), 103 deletions(-)

Approvals:
  jenkins-bot: Verified
  Nikerabbit: Checked; Looks good to me, approved



diff --git a/modules/dashboard/ext.cx.dashboard.js 
b/modules/dashboard/ext.cx.dashboard.js
index d3ee47d..817319b 100644
--- a/modules/dashboard/ext.cx.dashboard.js
+++ b/modules/dashboard/ext.cx.dashboard.js
@@ -26,6 +26,7 @@
                this.$filter = null;
                this.$listHeader = null;
                this.$cta = null;
+               this.$sourceSelector = null;
        }
 
        CXDashboard.prototype.init = function () {
@@ -254,9 +255,12 @@
                        this.$filter
                );
 
+               this.$sourceSelector = $( '<div>' )
+                       .addClass( 'cx-sourceselector-embedded' );
+
                return $( '<div>' )
                        .addClass( 'cx-translationlist-container' )
-                       .append( this.$listHeader );
+                       .append( this.$listHeader, this.$sourceSelector );
        };
 
        CXDashboard.prototype.setActiveList = function ( type ) {
@@ -282,7 +286,8 @@
        };
 
        CXDashboard.prototype.listen = function () {
-               var self = this;
+               var self = this,
+                       onVisibleCallback;
 
                this.$filter.click( '.cx-filter', function ( e ) {
                        var $filter = $( e.target );
@@ -307,6 +312,16 @@
                        }
                } );
 
+               onVisibleCallback = function () {
+                       if ( $( 'html' ).prop( 'dir' ) === 'rtl' ) {
+                               this.left = this.$element.offset().left + 
this.$element.parent().width() - this.$menu.width();
+                       } else {
+                               this.left = this.$element.offset().left;
+                       }
+
+                       this.$menu.css( this.position() );
+               };
+
                $.each( this.lists, function ( name, list ) {
                        var setFilter = self.setFilter.bind( self );
 
@@ -314,10 +329,7 @@
                                onSelect: function ( language ) {
                                        setFilter( 'sourceLanguage', language );
                                },
-                               onVisible: function () {
-                                       this.left = 
list.languageFilter.$sourceLanguageFilter.offset().left;
-                                       this.$menu.css( 'left', this.left );
-                               },
+                               onVisible: onVisibleCallback,
                                menuWidth: 'medium',
                                left: 
list.languageFilter.$sourceLanguageFilter.offset().left,
                                quickList: function () {
@@ -330,10 +342,7 @@
                                onSelect: function ( language ) {
                                        setFilter( 'targetLanguage', language );
                                },
-                               onVisible: function () {
-                                       this.left = 
list.languageFilter.$targetLanguageFilter.offset().left;
-                                       this.$menu.css( 'left', this.left );
-                               },
+                               onVisible: onVisibleCallback,
                                menuWidth: 'medium',
                                left: 
list.languageFilter.$targetLanguageFilter.offset().left,
                                quickList: function () {
@@ -344,8 +353,14 @@
                } );
 
                this.initSourceSelector();
+               this.$newTranslationButton.on( 'click', function ( e ) {
+                       self.$listHeader.hide();
+                       e.stopPropagation();
+
+                       $( window ).scrollTop( 0 );
+               } );
                // Scroll handler
-               $( window ).scroll( $.throttle( 250, $.proxy( this.scroll, this 
) ) );
+               $( window ).scroll( $.throttle( 250, this.scroll.bind( this ) ) 
);
        };
 
        CXDashboard.prototype.setFilter = function ( type, value ) {
@@ -364,7 +379,7 @@
                sourceSelectorOptions.sourceLanguage = query.from;
                sourceSelectorOptions.targetLanguage = query.to;
                sourceSelectorOptions.sourceTitle = query.page;
-               sourceSelectorOptions.targetTitle = query.targettitle;
+               sourceSelectorOptions.container = this.$sourceSelector;
                this.$newTranslationButton.cxSourceSelector( 
sourceSelectorOptions );
 
                if ( query.campaign ) {
diff --git a/modules/dashboard/styles/ext.cx.suggestionlist.less 
b/modules/dashboard/styles/ext.cx.suggestionlist.less
index 08b295e..df6c68d 100644
--- a/modules/dashboard/styles/ext.cx.suggestionlist.less
+++ b/modules/dashboard/styles/ext.cx.suggestionlist.less
@@ -63,10 +63,9 @@
 
 .cx-suggestionlist__refresh {
        color: @colorProgressive;
-       margin-bottom: 48px;
+       margin: -10px 0 48px 0;
        border-width: 1px 0;
        border-radius: 0 0 @borderRadius @borderRadius;
-       margin-top: -10px;
        padding: 20px;
        font-weight: bold;
 
diff --git a/modules/source/ext.cx.source.selector.js 
b/modules/source/ext.cx.source.selector.js
index 2dad54e..752800f 100644
--- a/modules/source/ext.cx.source.selector.js
+++ b/modules/source/ext.cx.source.selector.js
@@ -23,16 +23,30 @@
                this.options = $.extend( {}, options );
                this.siteMapper = siteMapper;
 
+               // Boolean property indicating if CXSourceSelector is used as
+               // modal dialog or embedded
+               this.embedded = !!options.container && options.container 
instanceof jQuery;
+
                this.sourceLanguages = [];
                this.targetLanguages = [];
                this.sourceLanguage = null;
                this.targetLanguage = null;
-               this.$dialog = null;
+               // this.$container is used for both types of CXSourceSelector - 
embedded and modal dialog
+               // Embedded version - $container field gets DOM container 
passed through options parameter
+               // Dialog version - $container fields gets created in 
renderAsDialog method of this class
+               this.$container = this.embedded ? options.container : null;
+               this.$selectedItem = null;
+               this.$selectedItemImage = null;
+               this.$selectedItemInfo = null;
+               this.$languageFilter = null;
                this.$sourceLanguage = null;
                this.$targetLanguage = null;
+               this.$discardItem = null;
+               this.$sourceInputs = null;
                this.$messageBar = null;
                this.$targetTitleInput = null;
                this.overlay = null;
+               this.$translateFromButton = null;
                this.validator = new mw.cx.ContentTranslationValidator( 
this.siteMapper );
                this.init();
        }
@@ -73,6 +87,19 @@
        }
 
        /**
+        * Calculate position for ULS, depending on directionality
+        */
+       function calculateUlsPosition() {
+               if ( $( 'html' ).prop( 'dir' ) === 'rtl' ) {
+                       this.left = this.$element.offset().left + 
this.$element.parent().width() - this.$menu.width();
+               } else {
+                       this.left = this.$element.offset().left;
+               }
+
+               this.$menu.css( this.position() );
+       }
+
+       /**
         * Initialize the plugin.
         */
        CXSourceSelector.prototype.init = function () {
@@ -103,7 +130,8 @@
                        this.sourcePageSelector.setValue( 
this.options.sourceTitle );
                }
 
-               if ( this.options.targetTitle ) {
+               // !this.embedded is extra check, second one may be sufficient
+               if ( !this.embedded && this.options.targetTitle ) {
                        this.$targetTitleInput.val( this.options.targetTitle );
                }
 
@@ -212,7 +240,7 @@
                        .text( $.uls.data.getAutonym( this.sourceLanguage ) );
                mw.storage.set( 'cxSourceLanguage', this.sourceLanguage );
                this.sourcePageSelector.setLanguage( this.sourceLanguage );
-               this.fillTargetLanguages();
+               this.fillTargetLanguages( this.targetLanguages );
        };
 
        /**
@@ -240,17 +268,21 @@
                        lang: this.targetLanguage,
                        dir: $.uls.data.getDir( this.targetLanguage )
                };
-               this.$targetTitleInput.prop( langProps );
+               if ( !this.embedded ) {
+                       this.$targetTitleInput.prop( langProps );
+               }
                this.$targetLanguage.prop( langProps )
                        .text( $.uls.data.getAutonym( this.targetLanguage ) );
+               this.sourcePageSelector.setTargetLanguage( language );
                mw.storage.set( 'cxTargetLanguage', this.targetLanguage );
        };
 
        /**
         * Fill the target language dropdown with target languages that have
         * language tools compatible with the source language.
+        * @param {array} targetLanguages
         */
-       CXSourceSelector.prototype.fillTargetLanguages = function () {
+       CXSourceSelector.prototype.fillTargetLanguages = function ( 
targetLanguages ) {
                var targetLanguageCodes, sourceLanguage,
                        cxSourceSelector = this,
                        targetUlsClass = 'cx-sourceselector-uls-target';
@@ -262,7 +294,7 @@
 
                // Don't let the target be the same as source
                sourceLanguage = this.getSourceLanguage();
-               targetLanguageCodes = $.grep( this.targetLanguages, function ( 
language ) {
+               targetLanguageCodes = $.grep( targetLanguages, function ( 
language ) {
                        return language !== sourceLanguage;
                } );
 
@@ -277,15 +309,7 @@
                        onReady: function () {
                                this.$menu.addClass( targetUlsClass );
                        },
-                       onVisible: function () {
-                               if ( $( 'html' ).prop( 'dir' ) === 'rtl' ) {
-                                       this.left = this.$element.offset().left 
+ this.$element.parent().width() - this.$menu.width();
-                               } else {
-                                       this.left = this.$element.offset().left;
-                               }
-
-                               this.$menu.css( this.position() );
-                       },
+                       onVisible: calculateUlsPosition,
                        quickList: function () {
                                return mw.uls.getFrequentLanguageList().filter( 
function ( n ) {
                                        return targetLanguageCodes.indexOf( n ) 
!== -1;
@@ -299,8 +323,8 @@
         */
        CXSourceSelector.prototype.listen = function () {
                var self = this;
-               // Open or close the dialog when clicking the link.
-               // The dialog will be unitialized until the first click.
+               // Open or close the (embedded) dialog when clicking the link.
+               // The (embedded) dialog will be unitialized until the first 
click.
                this.$trigger.click( $.proxy( this.show, this ) );
 
                this.sourcePageSelector.on( 'change', function () {
@@ -309,15 +333,19 @@
                        self.$messageBar.hide();
                } );
 
-               // Target title input (check)
-               this.$targetTitleInput.on( 'input blur',
-                       $.debounce( 600, false, $.proxy( this.check, this ) )
-               );
+               if ( !this.embedded ) {
+                       // Target title input (check)
+                       this.$targetTitleInput.on( 'input blur',
+                               $.debounce( 600, false, $.proxy( this.check, 
this ) )
+                       );
+               } else {
+                       this.$discardItem.click( this.discardSelectedItem.bind( 
this ) );
+               }
 
                // Keypress (start translation on enter key)
-               this.$dialog.on(
+               this.$container.on(
                        'keypress',
-                       '.cx-sourceselector-dialog-title',
+                       '.cx-sourceselector-page-title',
                        $.proxy( this.enterKeyHandler, this )
                );
        };
@@ -366,7 +394,7 @@
                var sourceLanguage = this.getSourceLanguage(),
                        targetLanguage = this.getTargetLanguage(),
                        sourceTitle = this.sourcePageSelector.getQueryValue(),
-                       targetTitle = this.$targetTitleInput.val().trim(),
+                       targetTitle = this.embedded ? '' : 
this.$targetTitleInput.val().trim(),
                        selector = this;
 
                this.$messageBar.hide();
@@ -518,7 +546,7 @@
         * @param {mw.Message|text} message the message to show
         */
        CXSourceSelector.prototype.showMessage = function ( message ) {
-               var $messageText = $( 
'.cx-sourceselector-dialog__messagebar-text' );
+               var $messageText = $( '.cx-sourceselector-messagebar-text' );
 
                if ( message instanceof mw.Message ) {
                        $messageText.html( message.parse() );
@@ -536,17 +564,15 @@
         * Show the CXSourceSelector.
         */
        CXSourceSelector.prototype.show = function () {
-               var $container = this.options.container;
-
-               if ( $container && $container instanceof jQuery ) {
-                       this.showAsEmbedded( $container );
+               if ( this.embedded ) {
+                       this.showAsEmbedded();
                } else {
                        this.showAsDialog();
                }
 
                // If there is something in the source field, it is probably 
auto-filled,
                // so go immediately to the target to save time
-               if ( this.options.sourceTitle ) {
+               if ( !this.embedded && this.options.sourceTitle ) {
                        this.$targetTitleInput.focus();
                } else {
                        this.sourcePageSelector.focus();
@@ -565,17 +591,17 @@
                if ( this.options.top ) {
                        top = this.options.top;
                } else {
-                       top = ( $( window ).height() - this.$dialog.height() ) 
/ 2;
+                       top = ( $( window ).height() - this.$container.height() 
) / 2;
                        top = top + $( document ).scrollTop();
                }
 
                if ( this.options.left ) {
                        left = this.options.left;
                } else {
-                       left = ( $( window ).width() - this.$dialog.width() ) / 
2;
+                       left = ( $( window ).width() - this.$container.width() 
) / 2;
                }
 
-               this.$dialog.css( {
+               this.$container.css( {
                        top: top,
                        left: left
                } );
@@ -585,18 +611,24 @@
                }
 
                this.overlay.show();
-               this.$dialog.show();
+               this.$container.show();
        };
 
        /**
-        * Embeds source selector dialog inside the element
-        * specified by $container.
+        * Shows the embedded version of source selector dialog
         *
         * @param {jQuery} $container the container in which to embed the 
selector
         */
-       CXSourceSelector.prototype.showAsEmbedded = function ( $container ) {
-               $container.append( this.$dialog );
-               this.$dialog.show();
+       CXSourceSelector.prototype.showAsEmbedded = function () {
+               var overlayOptions = {};
+
+               if ( !this.overlay ) {
+                       overlayOptions.closeOnClick = 
this.closeOnClickOutside.bind( this );
+                       this.overlay = new mw.cx.widgets.Overlay( 'body', 
overlayOptions );
+               }
+
+               this.overlay.show();
+               this.$container.slideDown();
        };
 
        /**
@@ -609,17 +641,25 @@
                this.$translateFromButton.prop( 'disabled', true );
                this.$messageBar.hide();
 
-               if ( !this.options.container ) {
-                       this.overlay.hide();
-                       this.$dialog.hide();
-               }
+               // Only dialog version of CXSourceSelector has cancel button
+               this.overlay.hide();
+               this.hide();
+       };
+
+       /*
+       * Embedded version of CXSourceSelector supports closing by clicking 
anywhere outside of element
+       */
+       CXSourceSelector.prototype.closeOnClickOutside = function () {
+               this.overlay.hide();
+               this.$container.toggle();
+               $( '.translation-filter' ).slideDown();
        };
 
        /**
         * Hide the entry point dialog.
         */
        CXSourceSelector.prototype.hide = function () {
-               this.$dialog.hide();
+               this.$container.hide();
        };
 
        /**
@@ -634,7 +674,7 @@
                sourceLanguage = this.getSourceLanguage();
                targetLanguage = this.getTargetLanguage();
                originalSourceTitle = this.sourcePageSelector.getQueryValue();
-               targetTitle = this.$targetTitleInput.val().trim();
+               targetTitle = this.embedded ? '' : 
this.$targetTitleInput.val().trim();
 
                this.validator.isTitleExistInLanguage(
                        sourceLanguage,
@@ -699,21 +739,76 @@
                this.setTargetLanguage( targetLanguage );
        };
 
-       /**
-        * Render the CXSourceSelector dialog.
-        */
+       CXSourceSelector.prototype.setSelectedItem = function ( item ) {
+               var itemImage;
+
+               this.sourcePageSelector.setValue( item.getData() );
+
+               this.$sourceInputs.hide(); // Hide input field
+               this.$selectedItem.show(); // Show selected item view
+
+               itemImage = item.$icon.css( 'background-image' );
+               if ( itemImage !== 'none' ) {
+                       this.$selectedItemImage.css( {
+                               'background-color': 'transparent',
+                               'background-image': itemImage
+                       } );
+               }
+
+               this.$selectedItemInfo.append(
+                       $( '<a>' ).prop( {
+                               href: item.$label.prop( 'href' ),
+                               title: item.$label.prop( 'title' ),
+                               target: '_blank',
+                               text: item.$label.text()
+                       } )
+               );
+               this.$container
+                       .toggleClass( 'cx-sourceselector-embedded--selected' );
+
+               this.$languageFilter.insertBefore( this.$discardItem );
+       };
+
+       CXSourceSelector.prototype.discardSelectedItem = function () {
+               this.$sourceInputs.show(); // Show input field
+               this.$selectedItem.hide(); // Hide selected item view
+
+               this.sourcePageSelector.setValue( '' );
+               this.$messageBar.hide();
+
+               // Discard selected item image and info
+               this.$selectedItemInfo.empty();
+               this.$selectedItemImage.removeAttr( 'style' );
+
+               this.$container
+                       .toggleClass( 'cx-sourceselector-embedded--selected' );
+
+               this.$sourceInputs.append( this.$languageFilter );
+       };
+
        CXSourceSelector.prototype.render = function () {
+               if ( this.embedded ) {
+                       this.renderAsEmbedded();
+               } else {
+                       this.renderAsDialog();
+               }
+       };
+
+       /**
+        * Render the CXSourceSelector as dialog.
+        */
+       CXSourceSelector.prototype.renderAsDialog = function () {
                var $heading,
                        $sourceLanguageLabel, $sourceLanguageLabelContainer, 
$sourceLanguageContainer,
                        $targetLanguageLabel, $targetLanguageLabelContainer, 
$targetLanguageContainer,
                        $targetTitleInputContainer,
-                       $sourceInputs, $targetInputs,
+                       $targetInputs,
                        $messageText,
                        translateButtonLabel,
                        $actions, $license,
                        cxSourceSelector = this;
 
-               this.$dialog = $( '<div>' )
+               this.$container = $( '<div>' )
                        .addClass( 'cx-sourceselector-dialog' )
                        .hide();
 
@@ -740,15 +835,7 @@
                        onReady: function () {
                                this.$menu.addClass( 
'cx-sourceselector-uls-source' );
                        },
-                       onVisible: function () {
-                               if ( $( 'html' ).prop( 'dir' ) === 'rtl' ) {
-                                       this.left = this.$element.offset().left 
+ this.$element.parent().width() - this.$menu.width();
-                               } else {
-                                       this.left = this.$element.offset().left;
-                               }
-
-                               this.$menu.css( this.position() );
-                       },
+                       onVisible: calculateUlsPosition,
                        quickList: function () {
                                return mw.uls.getFrequentLanguageList().filter( 
function ( n ) {
                                        return 
cxSourceSelector.sourceLanguages.indexOf( n ) !== -1;
@@ -775,12 +862,11 @@
                        .append( this.$targetLanguage );
 
                this.sourcePageSelector = new mw.cx.ui.PageSelectorWidget( {
-                       classes: [ 'cx-sourceselector-dialog-title' ],
+                       classes: [ 'cx-sourceselector-page-title' ],
                        language: this.getSourceLanguage(),
                        siteMapper: this.siteMapper,
                        value: this.options.sourceTitle,
                        validateTitle: true,
-                       icon: 'search',
                        placeholder: mw.msg( 
'cx-sourceselector-dialog-source-title-placeholder' )
                } );
 
@@ -791,10 +877,10 @@
                        } );
 
                $targetTitleInputContainer = $( '<div>' )
-                       .addClass( 'cx-sourceselector-dialog-title' )
+                       .addClass( 'cx-sourceselector-page-title' )
                        .append( this.$targetTitleInput );
 
-               $sourceInputs = $( '<div>' )
+               this.$sourceInputs = $( '<div>' )
                        .addClass( 'cx-sourceselector-dialog__source-inputs' )
                        .append(
                                $sourceLanguageLabelContainer,
@@ -811,9 +897,9 @@
                        );
 
                this.$messageBar = $( '<div>' )
-                       .addClass( 'cx-sourceselector-dialog__messagebar' );
+                       .addClass( 'cx-sourceselector-messagebar' );
                $messageText = $( '<span>' )
-                       .addClass( 'cx-sourceselector-dialog__messagebar-text' 
);
+                       .addClass( 'cx-sourceselector-messagebar-text' );
                this.$messageBar
                        .append( $messageText )
                        .hide();
@@ -821,7 +907,7 @@
                this.$cancelButton = $( '<button>' )
                        .addClass( 'mw-ui-button mw-ui-quiet 
cx-sourceselector-dialog__button-cancel' )
                        .text( mw.msg( 'cx-sourceselector-dialog-button-cancel' 
) )
-                       .click( $.proxy( this.cancel, this ) );
+                       .click( this.cancel.bind( this ) );
 
                translateButtonLabel = mw.msg( 
'cx-sourceselector-dialog-button-start-translation' );
                this.$translateFromButton = $( '<button>' )
@@ -831,7 +917,7 @@
                        .click( $.proxy( this.startPageInCX, this ) );
 
                $license = $( '<div>' )
-                       .addClass( 'cx-sourceselector-dialog__license' )
+                       .addClass( 'cx-sourceselector__license' )
                        .html( mw.message( 'cx-license-agreement', 
translateButtonLabel ).parse() );
 
                $actions = $( '<div>' )
@@ -839,15 +925,130 @@
 
                $actions.append( this.$cancelButton, this.$translateFromButton 
);
 
-               this.$dialog.append( $heading,
-                       $sourceInputs,
+               this.$container.append( $heading,
+                       this.$sourceInputs,
                        $targetInputs,
                        this.$messageBar,
                        $license,
                        $actions
                );
 
-               $( 'body' ).append( this.$dialog );
+               $( 'body' ).append( this.$container );
+       };
+
+       CXSourceSelector.prototype.renderAsEmbedded = function () {
+               var $sourceLanguageContainer,
+                       $targetLanguageContainer,
+                       $messageText,
+                       translateButtonLabel,
+                       $actions, $license,
+                       cxSourceSelector = this;
+
+               this.$container.hide(); // Starts as hidden, shown on button 
click
+
+               this.$selectedItem = $( '<div>' )
+                       .addClass( 'cx-sourceselector-embedded-selected-item' )
+                       .hide();
+
+               this.$sourceLanguage = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded__language-button' );
+
+               this.$sourceLanguage.uls( {
+                       languages: getAutonyms( this.sourceLanguages ),
+                       menuWidth: getUlsMenuWidth( this.sourceLanguages.length 
),
+                       onSelect: function ( language ) {
+                               cxSourceSelector.sourceLanguageChangeHandler( 
language );
+                               mw.uls.addPreviousLanguage( language );
+                       },
+                       onReady: function () {
+                               this.$menu.addClass( 
'cx-sourceselector-uls-source' );
+                       },
+                       onVisible: calculateUlsPosition,
+                       quickList: function () {
+                               return mw.uls.getFrequentLanguageList().filter( 
function ( n ) {
+                                       return 
cxSourceSelector.sourceLanguages.indexOf( n ) !== -1;
+                               } );
+                       }
+               } );
+
+               $sourceLanguageContainer = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded__source-language' )
+                       .append( this.$sourceLanguage );
+
+               this.$targetLanguage = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded__language-button' );
+
+               $targetLanguageContainer = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded__target-language' )
+                       .append( this.$targetLanguage );
+
+               this.$languageFilter = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded__language-filter' )
+                       .append(
+                               $sourceLanguageContainer,
+                               $( '<div>' ).addClass( 
'translation-language-arrow' ),
+                               $targetLanguageContainer
+                       );
+               this.sourcePageSelector = new mw.cx.ui.PageSelectorWidget( {
+                       classes: [ 'cx-sourceselector-page-title' ],
+                       language: this.getSourceLanguage(),
+                       siteMapper: this.siteMapper,
+                       value: this.options.sourceTitle,
+                       validateTitle: true,
+                       placeholder: mw.msg( 
'cx-sourceselector-dialog-source-title-placeholder' )
+               } );
+               this.sourcePageSelector.onLookupMenuItemChoose = 
this.setSelectedItem.bind( this );
+
+               this.$sourceInputs = $( '<div>' )
+                       .addClass( 'cx-sourceselector-embedded__source-inputs' )
+                       .append(
+                               this.sourcePageSelector.$element,
+                               this.$languageFilter
+                       );
+               this.$selectedItemImage = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded-selected-item__image' );
+
+               this.$selectedItemInfo = $( '<div>' )
+                       .addClass( 
'cx-sourceselector-embedded-selected-item__info' );
+
+               this.$discardItem = $( '<div>' )
+                       .addClass( 'cx-sourceselector-embedded-discard' );
+
+               this.$selectedItem.append(
+                       this.$selectedItemImage,
+                       this.$selectedItemInfo,
+                       this.$discardItem
+               );
+
+               this.$messageBar = $( '<div>' )
+                       .addClass( 'cx-sourceselector-messagebar' );
+               $messageText = $( '<span>' )
+                       .addClass( 'cx-sourceselector-messagebar-text' );
+               this.$messageBar
+                       .append( $messageText )
+                       .hide();
+
+               translateButtonLabel = mw.msg( 
'cx-sourceselector-dialog-button-start-translation' );
+               this.$translateFromButton = $( '<button>' )
+                       .addClass( 'mw-ui-button mw-ui-progressive 
cx-sourceselector-dialog__button-translate' )
+                       .text( translateButtonLabel )
+                       .prop( 'disabled', true )
+                       .click( this.startPageInCX.bind( this ) );
+
+               $license = $( '<div>' )
+                       .addClass( 'cx-sourceselector__license' )
+                       .html( mw.message( 'cx-license-agreement', 
translateButtonLabel ).parse() );
+
+               $actions = $( '<div>' )
+                       .addClass( 'cx-sourceselector-embedded__actions' )
+                       .append( this.$translateFromButton );
+
+               this.$container.append( this.$sourceInputs,
+                       this.$selectedItem,
+                       this.$messageBar,
+                       $license,
+                       $actions
+               );
        };
 
        mw.cx.CXSourceSelector = CXSourceSelector;
diff --git a/modules/source/styles/ext.cx.source.selector.less 
b/modules/source/styles/ext.cx.source.selector.less
index 468035f..cbef4c5 100644
--- a/modules/source/styles/ext.cx.source.selector.less
+++ b/modules/source/styles/ext.cx.source.selector.less
@@ -4,31 +4,226 @@
 .cx-sourceselector-dialog {
        .mw-ui-item;
 
+       background-color: #fff;
        color: @gray-darker;
        position: absolute;
+       z-index: 400; // 300 is the z-index of overlay
        min-width: 650px;
        max-width: 700px;
-       background: #fff;
        border: 1px solid #ddd;
        border-bottom-width: 3px;
        border-radius: @borderRadius;
        padding: 0;
        box-shadow: 0 5px 10px rgba( 0, 0, 0, 0.2 );
-       z-index: 1001;
+
+       .cx-sourceselector-dialog__heading {
+               @vertical-margin: 10px;
+               @horizontal-margin: 15px;
+
+               .mw-ui-item;
+               .mw-ui-one-whole;
+
+               padding: @vertical-margin @horizontal-margin;
+               font-size: 1.6em;
+               line-height: 1.5em;
+               border-bottom: 1px solid #eee;
+               font-weight: normal;
+       }
 }
 
-.cx-sourceselector-dialog__heading {
-       @vertical-margin: 10px;
-       @horizontal-margin: 15px;
-
+.cx-sourceselector-embedded {
        .mw-ui-item;
-       .mw-ui-one-whole;
 
-       padding: @vertical-margin @horizontal-margin;
-       font-size: 1.6em;
-       line-height: 1.5em;
-       border-bottom: 1px solid #eee;
-       font-weight: normal;
+       background-color: @white;
+       color: @gray-darker;
+       position: relative;
+       z-index: 400; // 300 is the z-index of overlay
+       margin-bottom: 2em;
+       border-radius: @borderRadius;
+       padding: 0;
+
+       &.cx-sourceselector-embedded--selected {
+               .cx-sourceselector-embedded__target-language,
+               .translation-language-arrow,
+               .cx-sourceselector-embedded-discard,
+               .cx-sourceselector-embedded__actions {
+                       display: block;
+               }
+       }
+
+       .cx-sourceselector-embedded-selected-item {
+               @item-height: 6.25em;
+               @image-size: 5.25em;
+
+               .mw-ui-one-whole;
+               .flex-display( box );
+               .flex-display;
+               -ms-flex-align: center; // Support IE10
+               -webkit-box-align: center; // Support 2011 syntax
+               -webkit-align-items: center; // Vendor specific
+               align-items: center; // Modern syntax
+               min-height: @item-height;
+
+               &__image {
+                       background-color: @colorGray15;
+                       
.background-image-svg('../../dashboard/images/page_lightgray.svg', 
'../../dashboard/images/page_lightgray.png');
+                       background-repeat: no-repeat;
+                       background-size: @image-size;
+                       background-position: center center;
+                       display: block;
+                       height: @image-size;
+                       width: @image-size;
+                       border: 0;
+                       margin: 0.5em;
+               }
+
+               &__info {
+                       color: @colorGray1;
+
+                       .flex-display( box );
+                       .flex-display;
+                       flex-direction: column;
+                       // Support 2009/2012 syntax that does not support 
space-around
+                       -webkit-box-pack: justify; // iOS 6-, Safari 3.1-6
+                       -moz-box-pack: justify; // Firefox 21-
+                       -ms-flex-pack: distribute; // Support IE10
+                       justify-content: space-around;
+
+                       max-width: 60%;
+                       min-height: @item-height;
+                       padding-left: 0.7em;
+
+                       font-size: 1.2em;
+                       font-weight: bold;
+
+                       // Needs to be overridden for specificity
+                       > a {
+                               color: @colorGray1;
+                       }
+               }
+
+               .cx-sourceselector-embedded-discard {
+                       .background-image-svg('../../tools/images/clear.svg', 
'../../tools/images/clear.png');
+                       background-position: center center;
+                       background-repeat: no-repeat;
+                       background-size: 16px;
+                       opacity: 0.8;
+
+                       float: right;
+                       width: 30px;
+                       height: 30px;
+                       padding: 0 8px;
+                       cursor: pointer;
+
+                       &:hover {
+                               opacity: 1;
+                       }
+               }
+       }
+
+       .cx-sourceselector-embedded__source-inputs {
+               .flex-display( box );
+               .flex-display;
+
+               height: 40px;
+               border-bottom: 1px solid #eee;
+               padding: 10px;
+       }
+
+       .cx-sourceselector-embedded__actions {
+               display: none;
+       }
+
+       .cx-sourceselector-embedded__language-filter {
+               background: @colorGray15;
+               width: auto;
+               max-width: 25%;
+               border: 1px solid #9d9d9d;
+               border-radius: @borderRadius;
+               padding: 0;
+               font-weight: bold;
+
+               .flex-display( box ); // Support 2009 syntax
+               .flex-display();
+               margin-left: auto;
+
+               .cx-sourceselector-embedded__source-language,
+               .cx-sourceselector-embedded__target-language {
+                       float: left;
+                       position: relative;
+                       box-sizing: border-box;
+                       font-size: 18px;
+                       cursor: pointer;
+
+                       -webkit-box-flex: 1; // iOS 6-, Safari 3.1-6
+                       -moz-box-flex: 1; // Firefox 21-
+                       width: auto; // Fallback for flex-basis
+                       -ms-flex: 0 1 auto; // IE 10
+                       -webkit-flex: 0 1 auto; // Safari 6.2 - 8
+                       flex: 0 1 auto;
+                       overflow: hidden;
+               }
+
+               .cx-sourceselector-embedded__language-button {
+                       max-height: 34px;
+                       padding: 8px;
+                       line-height: 1;
+
+                       overflow: hidden;
+                       text-overflow: ellipsis;
+                       white-space: nowrap;
+               }
+       }
+
+       .cx-sourceselector-embedded__source-language {
+               padding-right: 8px;
+               margin-right: -8px;
+       }
+
+       .cx-sourceselector-embedded__target-language {
+               display: none;
+
+               padding-left: 8px;
+               margin-left: -8px;
+       }
+
+       .translation-language-arrow {
+               display: none;
+
+               float: left;
+               position: relative;
+               width: 0;
+               height: 34px;
+               margin-right: 16px;
+       }
+
+       .translation-language-arrow:after,
+       .translation-language-arrow:before {
+               content: ' ';
+               position: absolute;
+               top: 50%;
+               left: 100%;
+               width: 0;
+               height: 0;
+               border: solid transparent;
+               pointer-events: none;
+       }
+
+       .translation-language-arrow:after {
+               margin-top: -17px;
+               border-color: rgba( 255, 255, 255, 0 );
+               border-left-color: @colorGray15;
+               border-width: 17px;
+               border-left-width: 12px;
+       }
+
+       .translation-language-arrow:before {
+               margin-top: -18px;
+               border-color: rgba( 157, 157, 157, 0 );
+               border-left-color: #9d9d9d;
+               border-width: 18px;
+               border-left-width: 13px;
+       }
 }
 
 .cx-sourceselector-uls-target,
@@ -54,14 +249,14 @@
        font-size: large;
 }
 
-.cx-sourceselector-dialog__messagebar {
-       .mw-ui-item;
+.cx-sourceselector-messagebar {
        .mw-ui-one-whole;
        padding: 10px;
        background-color: #f7d358;
 }
 
-.cx-sourceselector-dialog__actions {
+.cx-sourceselector-dialog__actions,
+.cx-sourceselector-embedded__actions {
        .mw-ui-one-whole;
        padding: 10px 15px 15px 15px;
        text-align: right;
@@ -72,8 +267,7 @@
        }
 }
 
-.cx-sourceselector-dialog__license {
-       .mw-ui-item;
+.cx-sourceselector__license {
        .mw-ui-one-whole;
 
        padding: 10px;
@@ -114,7 +308,7 @@
        }
 }
 
-.cx-sourceselector-dialog-title {
+.cx-sourceselector-page-title {
        .mw-ui-item;
        .mw-ui-seven-twelfths;
 
diff --git a/modules/ui/widgets/mw.cx.ui.PageSelectorWidget.js 
b/modules/ui/widgets/mw.cx.ui.PageSelectorWidget.js
index 73d6033..6a7390c 100644
--- a/modules/ui/widgets/mw.cx.ui.PageSelectorWidget.js
+++ b/modules/ui/widgets/mw.cx.ui.PageSelectorWidget.js
@@ -55,6 +55,10 @@
        this.requestCache = {};
 };
 
+mw.cx.ui.PageSelectorWidget.prototype.setTargetLanguage = function ( language 
) {
+       this.targetLanguage = language;
+};
+
 /**
  * @inheritdoc
  */
diff --git a/modules/widgets/overlay/ext.cx.overlay.js 
b/modules/widgets/overlay/ext.cx.overlay.js
index 6376146..ee852d4 100644
--- a/modules/widgets/overlay/ext.cx.overlay.js
+++ b/modules/widgets/overlay/ext.cx.overlay.js
@@ -32,10 +32,16 @@
                if ( this.options.showLoading ) {
                        this.$overlay.append( mw.cx.widgets.spinner() );
                }
+
+               if ( this.options.closeOnClick ) {
+                       this.$overlay
+                               .addClass( 'cx-overlay--clickable' )
+                               .click( this.options.closeOnClick );
+               }
+
                this.$container
                        .css( 'position', 'relative' )
                        .append( this.$overlay );
-               this.show();
        };
 
        CXOverlay.prototype.show = function () {
diff --git a/modules/widgets/overlay/ext.cx.overlay.less 
b/modules/widgets/overlay/ext.cx.overlay.less
index a90628b..ed3be14 100644
--- a/modules/widgets/overlay/ext.cx.overlay.less
+++ b/modules/widgets/overlay/ext.cx.overlay.less
@@ -7,6 +7,10 @@
        width: 100%;
        height: 100%;
        opacity: 0.5;
+
+       &--clickable {
+               background-color: transparent;
+       }
 }
 
 body.cx-noscroll {

-- 
To view, visit https://gerrit.wikimedia.org/r/371473
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I222a29f56786a59f97e03d631b05c37cc9678b15
Gerrit-PatchSet: 9
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Petar.petkovic <[email protected]>
Gerrit-Reviewer: Nikerabbit <[email protected]>
Gerrit-Reviewer: Petar.petkovic <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to