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

Change subject: Category adaptation and display, add new categories to 
translation
......................................................................


Category adaptation and display, add new categories to translation

* Show category count at top of source and translation columns.
* Listing of categories at end of columns.
* The listing in translation column is editable. Adapted categories
  are automatically added. They can be removed or re-added.
* Allow arbitrary addition of new category to translation.

(Since publishing module rewrite for this OOJS migration part is
not done yet, testing the publishing is not possible. The target
page model will have the new categories. Thats all for now)

Bug: T152586
Bug: T150241
Bug: T134740
Change-Id: Icfc26460a2cb83301c5788614b5cc0e44a5e5ea0
---
M extension.json
A modules/cache/mw.cx.CategoryCache.js
M modules/dm/mw.cx.dm.SourcePage.js
M modules/dm/mw.cx.dm.TargetPage.js
M modules/dm/mw.cx.dm.Translation.js
M modules/mw.cx.MwApiRequestManager.js
A modules/ui/mw.cx.ui.Categories.js
M modules/ui/mw.cx.ui.Columns.js
M modules/ui/mw.cx.ui.SourceColumn.js
M modules/ui/mw.cx.ui.ToolsColumn.js
M modules/ui/mw.cx.ui.TranslationColumn.js
M modules/ui/mw.cx.ui.TranslationView.js
A modules/ui/styles/mw.cx.ui.Categories.less
13 files changed, 363 insertions(+), 65 deletions(-)

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



diff --git a/extension.json b/extension.json
index cf344c2..dbb47c0 100644
--- a/extension.json
+++ b/extension.json
@@ -1293,6 +1293,7 @@
                "mw.cx.cache": {
                        "scripts": [
                                "cache/mw.cx.ApiResponseCache.js",
+                               "cache/mw.cx.CategoryCache.js",
                                "cache/mw.cx.LinkCache.js",
                                "cache/mw.cx.ImageInfoCache.js",
                                "cache/mw.cx.TitlePairCache.js"
@@ -1445,7 +1446,8 @@
                        ],
                        "dependencies": [
                                "mw.cx.ui",
-                               "ext.cx.widgets.spinner"
+                               "ext.cx.widgets.spinner",
+                               "mw.cx.ui.Categories"
                        ]
                },
                "mw.cx.ui.SourceColumn.legacy": {
@@ -1520,6 +1522,20 @@
                                "mw.cx.tools.SearchTool"
                        ]
                },
+               "mw.cx.ui.Categories": {
+                       "scripts": [
+                               "ui/mw.cx.ui.Categories.js"
+                       ],
+                       "styles": [
+                               "ui/styles/mw.cx.ui.Categories.less"
+                       ],
+                       "dependencies": [
+                               "mw.cx.ui"
+                       ],
+                       "messages": [
+                               "cx-tools-categories-count-message"
+                       ]
+               },
                "mw.cx.ui.TranslationUnit": {
                        "scripts": [
                                
"ui/translationunits/mw.cx.ui.TranslationUnit.js",
diff --git a/modules/cache/mw.cx.CategoryCache.js 
b/modules/cache/mw.cx.CategoryCache.js
new file mode 100644
index 0000000..50f18e1
--- /dev/null
+++ b/modules/cache/mw.cx.CategoryCache.js
@@ -0,0 +1,51 @@
+/**
+ * ContentTranslation Category request cache
+ *
+ */
+
+'use strict';
+/**
+ * Caches information about title pairs.
+ *
+ * @class
+ * @extends mw.cx.ApiResponseCache
+ * @constructor
+ * @param {Object} config Configuration
+ */
+mw.cx.CategoryCache = function CXCategoryCache( config ) {
+       // Call parent constructor
+       mw.cx.CategoryCache.super.call( this, config );
+       this.language = config.language;
+       this.cacheValues = {};
+};
+
+/* Inheritance */
+
+OO.inheritClass( mw.cx.CategoryCache, mw.cx.ApiResponseCache );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+mw.cx.CategoryCache.static.processPage = function ( page ) {
+       return {
+               categories: $.map( OO.getProp( page, 'categories' ), function( 
item ) {
+                       return item.title;
+               } )
+       };
+};
+
+/**
+ * @inheritdoc
+ */
+mw.cx.CategoryCache.prototype.getRequestPromise = function ( subqueue ) {
+       return this.siteMapper.getApi( this.language ).get( {
+               formatversion: 2,
+               action: 'query',
+               prop: 'categories',
+               clshow: '!hidden',
+               cllimit: 100,
+               titles: subqueue.join( '|' )
+       } );
+};
diff --git a/modules/dm/mw.cx.dm.SourcePage.js 
b/modules/dm/mw.cx.dm.SourcePage.js
index ffbaf7b..ce567d2 100644
--- a/modules/dm/mw.cx.dm.SourcePage.js
+++ b/modules/dm/mw.cx.dm.SourcePage.js
@@ -26,6 +26,7 @@
        this.direction = null;
        this.title = config.sourceTitle;
        this.sourceRevision = config.sourceRevision;
+       this.requestManager = config.requestManager;
        this.sections = [];
        this.categories = [];
 };
@@ -35,15 +36,9 @@
 OO.mixinClass( mw.cx.dm.SourcePage, OO.EventEmitter );
 
 mw.cx.dm.SourcePage.prototype.init = function () {
-       var self = this;
-
        this.direction = $.uls.data.getDir( this.language );
 
-       return this.fetchPage( this.title, this.language, this.sourceRevision 
).then( function () {
-               return self.getCategories().then( function ( categories ) {
-                       self.categories = categories;
-               } );
-       } );
+       return this.fetchPage( this.title, this.language, this.sourceRevision );
 };
 
 /**
@@ -154,19 +149,9 @@
  * @return {jQuery.Promise}
  */
 mw.cx.dm.SourcePage.prototype.getCategories = function () {
-       return this.config.siteMapper.getApi( this.language ).get( {
-               action: 'query',
-               prop: 'categories',
-               clshow: '!hidden',
-               cllimit: 100,
-               indexpageids: true,
-               titles: this.title
-       } ).then( function ( response ) {
-               var pageId;
-
-               if ( response.query ) {
-                       pageId = response.query.pageids[ 0 ];
-                       return response.query.pages[ pageId ].categories || [];
-               }
-       } );
+       return this.requestManager.getCategories( this.language, this.title )
+               .then( function ( categoriesResult ) {
+                       this.categories = categoriesResult.categories;
+                       return this.categories;
+               }.bind( this ) );
 };
diff --git a/modules/dm/mw.cx.dm.TargetPage.js 
b/modules/dm/mw.cx.dm.TargetPage.js
index d48d730..f8e7a28 100644
--- a/modules/dm/mw.cx.dm.TargetPage.js
+++ b/modules/dm/mw.cx.dm.TargetPage.js
@@ -13,10 +13,11 @@
        // Mixin constructor
        OO.EventEmitter.call( this );
        this.config = config;
-       this.language = config.sourceLanguage;
+       this.language = config.targetLanguage;
        this.direction = null;
        this.title = config.sourceTitle;
        this.revisionId = config.revision;
+       this.requestManager = config.requestManager;
        this.section = [];
        this.categories = [];
 };
@@ -32,3 +33,55 @@
 };
 
 mw.cx.dm.TargetPage.prototype.publish = function () {};
+
+/**
+ * Get categories for the target article.
+ * @return {string[]} Array of category titles with namespace prefix
+ */
+mw.cx.dm.TargetPage.prototype.getCategories = function () {
+       return this.categories;
+};
+
+/**
+ * Add a category to target article
+ * @param {string} categoryTitle Category title with namespace prefix
+ */
+mw.cx.dm.TargetPage.prototype.addCategory = function ( categoryTitle ) {
+       this.categories.push( categoryTitle );
+};
+
+/**
+ * Remove a category to target article
+ * @param {string} categoryTitle Category title with namespace prefix
+ */
+mw.cx.dm.TargetPage.prototype.removeCategory = function ( categoryTitle ) {
+       var index = this.categories.indexOf( categoryTitle );
+       if ( index > -1 ) {
+               this.categories.splice( index, 1 );
+       }
+};
+
+/**
+ * Adapt and add categories from an array of categories
+ * @param {string} sourceLanguage Source language
+ * @param {string[]} sourceCategories Array of source category titles, with 
namespace prefix
+ * @return {jQuery.Promise}
+ */
+mw.cx.dm.TargetPage.prototype.adaptCategoriesFrom = function ( sourceLanguage, 
sourceCategories ) {
+       var i, category,
+               deferreds = [];
+
+       for ( i = 0; i < sourceCategories.length; i++ ) {
+               category = sourceCategories[ i ];
+               deferreds.push( this.requestManager.getTitlePair( 
sourceLanguage, category )
+                       .then( function ( pairInfo ) {
+                               if ( pairInfo.targetTitle ) {
+                                       this.addCategory( pairInfo.targetTitle 
);
+                               }
+                       }.bind( this ) )
+               );
+       }
+       // Note that requestManager will take care of combining all these 
categories
+       // to a single network request.
+       return $.when.apply( $, deferreds );
+};
diff --git a/modules/dm/mw.cx.dm.Translation.js 
b/modules/dm/mw.cx.dm.Translation.js
index 0267e85..9f199bb 100644
--- a/modules/dm/mw.cx.dm.Translation.js
+++ b/modules/dm/mw.cx.dm.Translation.js
@@ -37,21 +37,26 @@
  * @return {jQuery.Promise}
  */
 mw.cx.dm.Translation.prototype.init = function () {
-       var self = this;
        this.sourcePage = new mw.cx.dm.SourcePage( this.config );
-       return this.sourcePage.init().done( function () {
-               self.onSourcePageReady();
-       } );
+       return this.sourcePage.init().then( function () {
+               return this.onSourcePageReady().then( function() {
+                       this.emit( 'sourcePageReady' );
+               }.bind( this ) );
+       }.bind( this ) );
 };
 
 /**
  * Handler for onSourcePageReady event.
+ * @return {jQuery.Promise}
  */
 mw.cx.dm.Translation.prototype.onSourcePageReady = function () {
        mw.log( '[CX] Translation loaded', this );
        this.setRevisionId( this.sourcePage.revisionId );
        this.prepareTranslationUnits();
        this.targetPage = new mw.cx.dm.TargetPage( this.config );
+       return this.sourcePage.getCategories().then( function( sourceCategories 
) {
+               return this.targetPage.adaptCategoriesFrom( 
this.sourceLanguage, sourceCategories );
+       }.bind( this ) );
 };
 
 /**
diff --git a/modules/mw.cx.MwApiRequestManager.js 
b/modules/mw.cx.MwApiRequestManager.js
index 864a917..3fe41bf 100644
--- a/modules/mw.cx.MwApiRequestManager.js
+++ b/modules/mw.cx.MwApiRequestManager.js
@@ -25,6 +25,7 @@
        this.linkCache = {};
        this.imageCache = {};
        this.titlePairCache = {};
+       this.categoryCache = {};
 };
 
 /**
@@ -56,6 +57,14 @@
        this.titlePairCache[ this.targetLanguage ] = new mw.cx.TitlePairCache( {
                sourceLanguage: this.targetLanguage,
                targetLanguage: this.sourceLanguage,
+               siteMapper: this.siteMapper
+       } );
+       this.categoryCache[ this.sourceLanguage ] = new mw.cx.CategoryCache( {
+               language: this.sourceLanguage,
+               siteMapper: this.siteMapper
+       } );
+       this.categoryCache[ this.targetLanguage ] = new mw.cx.CategoryCache( {
+               language: this.targetLanguage,
                siteMapper: this.siteMapper
        } );
 };
@@ -107,3 +116,17 @@
        }
        return this.titlePairCache[ language ].get( title );
 };
+
+mw.cx.MwApiRequestManager.prototype.getTitlePairs = function ( language, title 
) {
+       if ( !this.titlePairCache[ language ] ) {
+               throw Error( '[CX] TitlePairCache not initialized for ' + 
language );
+       }
+       return this.titlePairCache[ language ].get( title );
+};
+
+mw.cx.MwApiRequestManager.prototype.getCategories = function ( language, title 
) {
+       if ( !this.categoryCache[ language ] ) {
+               throw Error( '[CX] CategoryCache not initialized for ' + 
language );
+       }
+       return this.categoryCache[ language ].get( title );
+};
diff --git a/modules/ui/mw.cx.ui.Categories.js 
b/modules/ui/mw.cx.ui.Categories.js
new file mode 100644
index 0000000..fc96b86
--- /dev/null
+++ b/modules/ui/mw.cx.ui.Categories.js
@@ -0,0 +1,112 @@
+'use strict';
+
+/**
+ * CX Categories UI
+ * @class
+ * @param {Object} [config] Configuration object
+ */
+mw.cx.ui.Categories = function ( config ) {
+       this.categoryCount = null;
+       this.categoryListing = null;
+       this.page = config.page;
+       this.editable = config.editable;
+};
+
+/**
+ * Get the category count labels. To be displayed above source and translation 
contents.
+ * @return {OO.ui.ButtonWidget}
+ */
+mw.cx.ui.Categories.prototype.getCategoryCount = function () {
+       var count;
+
+       count = this.page ? this.page.categories.length : 0;
+       this.categoryCount = new OO.ui.ButtonWidget( {
+               label: mw.msg( 'cx-tools-categories-count-message', count ),
+               icon: 'tag',
+               framed: false
+       } );
+       return this.categoryCount;
+};
+
+/**
+ * Get the category listing To be displayed below source and translation 
contents.
+ * @return {OO.ui.HorizontalLayout}
+ */
+mw.cx.ui.Categories.prototype.getCategoryListing = function () {
+       var i, categories, label, categoryItems = [];
+
+       if ( this.editable ) {
+               return this.getEditableCategoryListing();
+       }
+       categories = this.page ? this.page.categories : [];
+       for ( i = 0; i < categories.length; i++ ) {
+               // mw.Title cannot be used because of
+               // https://phabricator.wikimedia.org/T106644
+               label = categories[ i ].match( /^.+?:(.*)$/ )[ 1 ];
+               categoryItems.push( new OO.ui.ButtonWidget( {
+                       label: label,
+                       icon: 'tag',
+                       framed: true
+               } ) );
+       }
+       if ( !categoryItems.length ) {
+               categoryItems.push( new OO.ui.ButtonWidget( {
+                       label: mw.msg( 'cx-tools-categories-count-message', 0 ),
+                       icon: 'tag',
+                       framed: true
+               } ) );
+       }
+       this.categoryListing = new OO.ui.HorizontalLayout( {
+               items: categoryItems,
+               classes: [ 'cx-category-listing' ]
+       } );
+       return this.categoryListing;
+};
+
+/**
+ * Get the editable category listing for translation column
+ * @return {OO.ui.CapsuleMultiselectWidget}
+ */
+mw.cx.ui.Categories.prototype.getEditableCategoryListing = function () {
+       var i, categories, label, categoryItems = [];
+
+       categories = this.page ? this.page.categories : [];
+       for ( i = 0; i < categories.length; i++ ) {
+               label = categories[ i ].match( /^.+?:(.*)$/ )[ 1 ];
+               categoryItems.push( new OO.ui.MenuOptionWidget( {
+                       data: categories[ i ],
+                       label: label
+               } ) );
+       }
+       this.categoryListing = new OO.ui.CapsuleMultiselectWidget( {
+               // Should we allow Arbitrary categories?
+               allowArbitrary: true,
+               icon: 'tag',
+               menu: {
+                       items: categoryItems
+               },
+               classes: [ 'cx-category-listing' ]
+       } );
+
+       // Add all adapted items
+       this.categoryListing.addItemsFromData( categories );
+
+       return this.categoryListing;
+};
+
+/**
+ * Event handling
+ */
+mw.cx.ui.Categories.prototype.listen = function () {
+       this.categoryCount.on( 'click', function () {
+               // Scroll to categoryListing
+               this.categoryListing.scrollElementIntoView();
+       }.bind( this ) );
+
+       if ( this.editable ) {
+               this.categoryListing.on( 'change', function () {
+                       // The new set of categories. Update the page.
+                       this.page.categories = 
this.categoryListing.getItemsData();
+               }.bind( this ) );
+       }
+};
diff --git a/modules/ui/mw.cx.ui.Columns.js b/modules/ui/mw.cx.ui.Columns.js
index d164962..ecff3cd 100644
--- a/modules/ui/mw.cx.ui.Columns.js
+++ b/modules/ui/mw.cx.ui.Columns.js
@@ -3,13 +3,14 @@
 /**
  *
  * @class
+ * @param {mw.cx.dm.Translation} translation
  * @param {Object} config
  */
-mw.cx.ui.Columns = function ( config ) {
+mw.cx.ui.Columns = function ( translation, config ) {
        // Configuration initialization
        this.config = config || {};
-       this.sourceColumn = new mw.cx.ui.SourceColumn( this.config );
-       this.translationColumn = new mw.cx.ui.TranslationColumn( this.config );
+       this.sourceColumn = new mw.cx.ui.SourceColumn( translation, this.config 
);
+       this.translationColumn = new mw.cx.ui.TranslationColumn( translation, 
this.config );
        this.ToolsColumn = new mw.cx.ui.ToolsColumn( this.config );
 
        // Parent constructor
diff --git a/modules/ui/mw.cx.ui.SourceColumn.js 
b/modules/ui/mw.cx.ui.SourceColumn.js
index f4c2f25..46e5117 100644
--- a/modules/ui/mw.cx.ui.SourceColumn.js
+++ b/modules/ui/mw.cx.ui.SourceColumn.js
@@ -4,9 +4,10 @@
  * Source article container
  *
  * @class
+ * @param {mw.cx.dm.Translation} translation
  * @param {Object} [config] Configuration object
  */
-mw.cx.ui.SourceColumn = function ( config ) {
+mw.cx.ui.SourceColumn = function ( translation, config ) {
        // Configuration initialization
        this.config = $.extend( {}, config, {
                continuous: true,
@@ -17,9 +18,13 @@
        // Parent constructor
        mw.cx.ui.SourceColumn.parent.call( this, this.config );
        this.siteMapper = config.siteMapper;
+       this.translation = translation;
        this.loading = true;
        this.$loadingIndicator = null;
        this.init();
+       this.translation.connect( this, {
+               sourcePageReady: 'onSourcePageReady'
+       } );
 };
 
 /* Setup */
@@ -33,8 +38,8 @@
 };
 
 mw.cx.ui.SourceColumn.prototype.render = function () {
-       var sourceLanguageDir,
-               $languageLabel, $articleLink, userLanguage, $subHeading;
+       var sourceLanguageDir, $languageLabel, $articleLink,
+               userLanguage, $subHeading;
 
        sourceLanguageDir = $.uls.data.getDir( this.config.sourceLanguage );
        this.$element.prop( {
@@ -78,8 +83,28 @@
 
        this.$content = $( '<div>' )
                .addClass( 'cx-column__content' );
-       this.$element.append( this.$title, $subHeading, this.$content );
+
+       this.$element.append(
+               this.$title,
+               $subHeading,
+               this.$content
+       );
        this.showLoadingIndicator();
+};
+
+mw.cx.ui.SourceColumn.prototype.onSourcePageReady = function() {
+       this.showCategories();
+};
+
+mw.cx.ui.SourceColumn.prototype.showCategories = function() {
+       var categoryUI = new mw.cx.ui.Categories( {
+               page: this.translation.sourcePage
+       } );
+       this.loading = false;
+       this.$loadingIndicator.remove();
+       this.$content.before( categoryUI.getCategoryCount().$element );
+       this.$content.after( categoryUI.getCategoryListing().$element );
+       categoryUI.listen();
 };
 
 /**
@@ -87,10 +112,6 @@
  * @param {integer} position
  */
 mw.cx.ui.SourceColumn.prototype.add = function ( $translationUnit, position ) {
-       if ( this.loading ) {
-               this.loading = false;
-               this.$loadingIndicator.remove();
-       }
        this.insertAt( position, $translationUnit );
 };
 
diff --git a/modules/ui/mw.cx.ui.ToolsColumn.js 
b/modules/ui/mw.cx.ui.ToolsColumn.js
index 8e2299b..89095be 100644
--- a/modules/ui/mw.cx.ui.ToolsColumn.js
+++ b/modules/ui/mw.cx.ui.ToolsColumn.js
@@ -36,7 +36,8 @@
 mw.cx.ui.ToolsColumn.prototype.init = function () {
        mw.loader.using( 'mw.cx.tools', function () {
                mw.log( '[CX] Initializing translation tool system' );
-       } );
+               this.showInstructions();
+       }.bind( this ) );
        this.listen();
 };
 
@@ -45,6 +46,17 @@
 };
 
 /**
+ * Show the instructions card when translation is loaded.
+ */
+mw.cx.ui.ToolsColumn.prototype.showInstructions = function () {
+       var instructions = mw.cx.tools.translationToolFactory.create(
+               'instructions', null, this, this.config
+       );
+
+       this.showTool( instructions );
+};
+
+/**
  * Show the tools associated with the translationUnit.
  *
  * @param {mw.cx.ui.TranslationUnit} translationUnit
diff --git a/modules/ui/mw.cx.ui.TranslationColumn.js 
b/modules/ui/mw.cx.ui.TranslationColumn.js
index 88131ef..cee34b6 100644
--- a/modules/ui/mw.cx.ui.TranslationColumn.js
+++ b/modules/ui/mw.cx.ui.TranslationColumn.js
@@ -4,9 +4,10 @@
  * Translation column
  *
  * @class
+ * @param {mw.cx.dm.Translation} translation
  * @param {Object} [config] Configuration object
  */
-mw.cx.ui.TranslationColumn = function ( config ) {
+mw.cx.ui.TranslationColumn = function ( translation, config ) {
        // Configuration initialization
        this.config = $.extend( {}, config, {
                continuous: true,
@@ -17,7 +18,11 @@
        // Parent constructor
        mw.cx.ui.TranslationColumn.parent.call( this, this.config );
        this.siteMapper = config.siteMapper;
+       this.translation = translation;
        this.init();
+       this.translation.connect( this, {
+               sourcePageReady: 'onSourcePageReady'
+       } );
 };
 /* Setup */
 
@@ -90,6 +95,20 @@
        mw.hook( 'mw.cx.translation.ready' ).fire();
 };
 
+mw.cx.ui.TranslationColumn.prototype.onSourcePageReady = function() {
+       this.showCategories();
+};
+
+mw.cx.ui.TranslationColumn.prototype.showCategories = function () {
+       var categoryUI = new mw.cx.ui.Categories( {
+               page: this.translation.targetPage,
+               editable: true
+       } );
+       this.$content.before( categoryUI.getCategoryCount().$element );
+       this.$content.after( categoryUI.getCategoryListing().$element );
+       categoryUI.listen();
+};
+
 /**
  * @param {jQuery} $translationUnit
  * @param {integer} position
diff --git a/modules/ui/mw.cx.ui.TranslationView.js 
b/modules/ui/mw.cx.ui.TranslationView.js
index 5a7d8a3..2e6377f 100644
--- a/modules/ui/mw.cx.ui.TranslationView.js
+++ b/modules/ui/mw.cx.ui.TranslationView.js
@@ -7,13 +7,10 @@
  */
 
 mw.cx.ui.TranslationView = function ( config ) {
-       this.header = new mw.cx.ui.Header( config );
-       this.columns = new mw.cx.ui.Columns( config );
        // Configuration initialization
        this.config = $.extend( {}, config, {
                continuous: true,
                expanded: false,
-               items: [ this.header, this.columns ],
                classes: [ 'cx-widget' ],
                scrollable: false,
                padded: false
@@ -21,9 +18,6 @@
        // Parent constructor
        mw.cx.ui.TranslationView.parent.call( this, this.config );
        this.publishButton = null;
-       this.connect( this, {
-               change: 'onChange'
-       } );
        this.init();
 };
 
@@ -33,8 +27,6 @@
 OO.mixinClass( mw.cx.ui.TranslationUnit, OO.EventEmitter );
 
 mw.cx.ui.TranslationView.prototype.init = function () {
-       var self = this;
-
        if ( mw.user.isAnon() ) {
                mw.hook( 'mw.cx.error.anonuser' ).fire();
                return;
@@ -52,12 +44,19 @@
                mw.hook( 'mw.cx.cta.accept' ).fire( this.config.campaign, 
this.config.sourceLanguage, this.config.targetLanguage );
        }
 
-       this.translation = new mw.cx.dm.Translation( this.config );
-       this.translation.init().then( function () {
-               self.loadTranslation();
-               self.showInstructions();
-       } );
+       this.header = new mw.cx.ui.Header( this.config );
        this.preparePublishButton();
+
+       this.translation = new mw.cx.dm.Translation( this.config );
+       this.columns = new mw.cx.ui.Columns( this.translation, this.config );
+       this.addItems( [ this.header, this.columns ] );
+
+       this.translation.init().then( function () {
+               this.loadTranslation();
+       }.bind( this ) );
+       this.connect( this, {
+               change: 'onChange'
+       } );
 };
 
 /**
@@ -88,17 +87,6 @@
 mw.cx.ui.TranslationView.prototype.preparePublishButton = function () {
        this.setupPublishButton();
        this.attachPublishButton();
-};
-
-/**
- * Show the instructions card when translation is loaded.
- */
-mw.cx.ui.TranslationView.prototype.showInstructions = function () {
-       var instructions = mw.cx.tools.translationToolFactory.create(
-               'instructions', null, this,     this.config
-       );
-
-       this.columns.ToolsColumn.showTool( instructions );
 };
 
 mw.cx.ui.TranslationView.prototype.setupPublishButton = function () {
diff --git a/modules/ui/styles/mw.cx.ui.Categories.less 
b/modules/ui/styles/mw.cx.ui.Categories.less
new file mode 100644
index 0000000..23ed046
--- /dev/null
+++ b/modules/ui/styles/mw.cx.ui.Categories.less
@@ -0,0 +1,12 @@
+@import '../../widgets/common/ext.cx.common.less';
+
+.cx-category-listing {
+       .mw-ui-item;
+       .mw-ui-one-whole;
+       margin: 10px 0;
+       padding: 0;
+       border: 1px solid @gray;
+       .oo-ui-buttonElement {
+               margin: 5px;
+       }
+}

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Icfc26460a2cb83301c5788614b5cc0e44a5e5ea0
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com>
Gerrit-Reviewer: Nikerabbit <niklas.laxst...@gmail.com>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to