Nikerabbit has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/345513 )

Change subject: Some refactoring in the initialization code
......................................................................

Some refactoring in the initialization code

I was debugging a JS error that was happening on draft restoration.
I found the initialization code a bit hard to follow, so I refactored
it into clear chain.

This patch also contains some cleanups to constructor parameters,
documentation etc. which make it harder to review.

Change-Id: Ie68d3b46b6cd0eae22282288ab0158bb2f5d8bef
---
M extension.json
M modules/dm/mw.cx.dm.SourcePage.js
M modules/dm/mw.cx.dm.Translation.js
M modules/mw.cx.MwApiRequestManager.js
M modules/mw.cx.Translation.js
M modules/mw.cx.init.Translation.js
M modules/mw.cx.init.js
M modules/tests/dm/mw.cx.dm.LinkTranslationUnit.test.js
M modules/ui/mw.cx.ui.Columns.js
M modules/ui/mw.cx.ui.SourceColumn.js
M modules/ui/mw.cx.ui.TranslationView.js
11 files changed, 333 insertions(+), 267 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation 
refs/changes/13/345513/1

diff --git a/extension.json b/extension.json
index 6adc640..d64de02 100644
--- a/extension.json
+++ b/extension.json
@@ -1239,6 +1239,10 @@
                                "mw.cx.dm"
                        ]
                },
+               "mw.cx.dm.WikiPage": {
+                       "scripts": "dm/mw.cx.dm.WikiPage.js",
+                       "dependencies": "mw.cx.dm"
+               },
                "mw.cx.dm.TranslationUnits": {
                        "dependencies": [
                                "mw.cx.dm.TranslationUnit",
@@ -1346,8 +1350,9 @@
                        ],
                        "dependencies": [
                                "ext.cx.model",
-                               "mw.cx.ui",
+                               "ext.cx.sitemapper",
                                "mw.cx.MwApiRequestManager",
+                               "mw.cx.dm.WikiPage",
                                "mw.cx.init.Translation"
                        ],
                        "targets": [
@@ -1357,6 +1362,13 @@
                "mw.cx.init.Translation": {
                        "scripts": [
                                "mw.cx.init.Translation.js"
+                       ],
+                       "messages": [
+                               "cx-draft-restore-failed",
+                               "cx-draft-restored",
+                               "cx-draft-restoring",
+                               "cx-error-page-not-found",
+                               "cx-error-server-connection"
                        ],
                        "dependencies": [
                                "mw.cx.dm.Translation",
@@ -1386,14 +1398,10 @@
                                "cx-save-draft-save-success",
                                "cx-save-draft-saving",
                                "cx-save-draft-tooltip",
-                               "cx-draft-restoring",
-                               "cx-draft-restored",
-                               "cx-draft-restore-failed",
                                "cx-page-old-revision-loaded"
                        ],
                        "dependencies": [
                                "easy-deflate.deflate",
-                               "ext.cx.model",
                                "mediawiki.api",
                                "mediawiki.api.edit",
                                "mediawiki.user",
@@ -1522,8 +1530,6 @@
                                "ui/styles/mw.cx.ui.Infobar.less"
                        ],
                        "messages": [
-                               "cx-error-server-connection",
-                               "cx-error-page-not-found",
                                "cx-header-new-translation",
                                "cx-header-all-translations",
                                "cx-special-login-error",
diff --git a/modules/dm/mw.cx.dm.SourcePage.js 
b/modules/dm/mw.cx.dm.SourcePage.js
index 1e90bed..0cdd9b4 100644
--- a/modules/dm/mw.cx.dm.SourcePage.js
+++ b/modules/dm/mw.cx.dm.SourcePage.js
@@ -3,7 +3,6 @@
 /**
  * CX Source page
  *
- * @abstract
  * @mixins OO.EventEmitter
  *
  * @constructor
@@ -14,9 +13,7 @@
  * @cfg {string} sourceLanguage Source language code
  * @cfg {string} targetLanguage Target language code
  * @cfg {string} [sourceRevision] Source revision id
- * @cfg {string} [campaign] Campaign identifier
  * @cfg {Object} requestManager The MediaWiki api request manager instance
- * @cfg {string[]} removableSections Sections that can be removed from source 
page
  */
 mw.cx.dm.SourcePage = function SourcePage( config ) {
        // Mixin constructor
diff --git a/modules/dm/mw.cx.dm.Translation.js 
b/modules/dm/mw.cx.dm.Translation.js
index 723d71b..9893a15 100644
--- a/modules/dm/mw.cx.dm.Translation.js
+++ b/modules/dm/mw.cx.dm.Translation.js
@@ -57,7 +57,8 @@
                        model,
                        this.config,
                        this,
-                       translatableSections[ i ] );
+                       translatableSections[ i ]
+               );
        }
 };
 
diff --git a/modules/mw.cx.MwApiRequestManager.js 
b/modules/mw.cx.MwApiRequestManager.js
index 5a8a3d0..4939be5 100644
--- a/modules/mw.cx.MwApiRequestManager.js
+++ b/modules/mw.cx.MwApiRequestManager.js
@@ -16,12 +16,14 @@
 
 /**
  * @class
- * @param {Object} config Configuration
+ * @param {string} sourceLanguage Language code
+ * @param {string} targetLanguage Language code
+ * @param {mw.cx.SiteMapper} siteMapper
  */
-mw.cx.MwApiRequestManager = function MwApiRequestManager( config ) {
-       this.sourceLanguage = config.sourceLanguage;
-       this.targetLanguage = config.targetLanguage;
-       this.siteMapper = config.siteMapper;
+mw.cx.MwApiRequestManager = function MwApiRequestManager( sourceLanguage, 
targetLanguage, siteMapper ) {
+       this.sourceLanguage = sourceLanguage;
+       this.targetLanguage = targetLanguage;
+       this.siteMapper = siteMapper;
        this.linkCache = {};
        this.imageCache = {};
        this.titlePairCache = {};
diff --git a/modules/mw.cx.Translation.js b/modules/mw.cx.Translation.js
index c9ccab5..7af20cb 100644
--- a/modules/mw.cx.Translation.js
+++ b/modules/mw.cx.Translation.js
@@ -228,30 +228,6 @@
        return records;
 };
 
-mw.cx.Translation.prototype.getSavedTranslation = function () {
-       return this.find().then( function( translation ) {
-               if ( !translation ) {
-                       return $.Deferred().reject( false ).resolve();
-               }
-
-               // Do not allow two users to start a draft at the same time. 
The API only
-               // returns a translation with different translatorName if this 
is the case.
-               if ( translation.translatorName !== mw.user.getName() ) {
-                       this.view.showConflictWarning( translation );
-                       return $.Deferred().reject( false ).resolve();
-               }
-
-               if ( translation.status === 'deleted' ) {
-                       // Deleted translation
-                       return $.Deferred().reject( false ).resolve();
-               }
-                       // Fetch the translation content
-               return this.fetch( translation.id ).then( function( 
fetchedTranslation ) {
-                       return fetchedTranslation;
-               } );
-       }.bind( this ) );
-};
-
 /**
  * Restore the translation from database to translation view to continue.
  * @param {Object} savedTranslation
@@ -259,7 +235,6 @@
 mw.cx.Translation.prototype.restore = function ( savedTranslation ) {
        var i, translationUnits, sectionId, savedTranslationUnits, 
savedTranslationUnit, translationContent;
 
-       this.emit( 'restorestart' );
        translationUnits = this.translation.getTranslationUnits();
        savedTranslationUnits = savedTranslation.translationUnits;
        for ( i = 0; i < translationUnits.length; i++ ) {
@@ -276,73 +251,4 @@
                translationUnits[ i ].setTargetDocument( 
translationContent.content );
        }
        // TODO: Find out orphan translation units and handle them.
-       this.view.setStatusMessage( mw.msg( 'cx-draft-restored' ) );
-};
-
-/**
- * Fetch the translation from database to translation view to continue.
- * @param {string} translationId Translation id
- * @return {jQuery.Promise}
- */
-mw.cx.Translation.prototype.fetch = function ( translationId ) {
-       var api = new mw.Api();
-
-       this.emit( 'fetchstart' );
-       this.view.setStatusMessage( mw.msg( 'cx-draft-restoring' ) );
-       return api.get( {
-               action: 'query',
-               list: 'contenttranslation',
-               translationid: translationId
-       } ).then(
-               // Success handler
-               this.onFetchSuccess.bind( this ),
-               // Failure handler
-               this.onFetchFail.bind( this )
-       );
-};
-
-mw.cx.Translation.prototype.onFetchSuccess = function ( response ) {
-       var fetchedTranslation;
-       fetchedTranslation = response.query.contenttranslation.translation;
-       this.emit( 'fetchsuccess' );
-       return fetchedTranslation;
-};
-
-mw.cx.Translation.prototype.onFetchFail = function ( errorCode, details ) {
-       if ( details.exception instanceof Error ) {
-               details.exception = details.exception.toString();
-       }
-       details.errorCode = errorCode;
-       this.emit( 'fetcherror', this.translation, details );
-       this.view.setStatusMessage( mw.msg( 'cx-draft-restore-failed' ) );
-};
-
-/**
- * Find if there is a draft existing for the current title and language pair.
- *
- * @return {jQuery.Promise}
- */
-mw.cx.Translation.prototype.find = function () {
-       var api = new mw.Api();
-
-       return api.get( {
-               action: 'query',
-               list: 'contenttranslation',
-               sourcetitle: this.sourceTitle,
-               from: this.sourceLanguage,
-               to: this.targetLanguage
-       } ).then( function ( response ) {
-               return response.query && 
response.query.contenttranslation.translation;
-       } );
-};
-
-mw.cx.Translation.prototype.showOldRevisionWarning = function () {
-       var diffUrl;
-
-       diffUrl = this.siteMapper.getPageUrl( this.sourceLanguage, 
this.sourceTitle, {
-               type: 'revision',
-               diff: 'cur',
-               oldid: this.translation.sourceRevisionId
-       } );
-       this.view.showMessage( 'warning', mw.message( 
'cx-page-old-revision-loaded', diffUrl ) );
 };
diff --git a/modules/mw.cx.init.Translation.js 
b/modules/mw.cx.init.Translation.js
index a5e404a..4d7bb71 100644
--- a/modules/mw.cx.init.Translation.js
+++ b/modules/mw.cx.init.Translation.js
@@ -1,155 +1,308 @@
 mw.cx.init = {};
 
 /**
- * Translation Initialization
- * @param {object} config Translation configuration
+ * This class loads translation documents (source and target) and sets up the 
main views and models.
+ *
+ * @class
+ *
+ * @constructor
+ * @param {mw.cx.dm.WikiPage} sourceWikiPage
+ * @param {mw.cx.dm.WikiPage} targetWikiPage
+ * @param {Object} services Standard services
  */
-mw.cx.init.Translation = function MWCXInitTranslation( config ) {
-       this.config = config;
-       this.siteMapper = config.siteMapper;
-       this.sourceTitle = config.sourceTitle;
-       this.targetTitle = config.targetTitle;
-       this.sourceLanguage = config.sourceLanguage;
-       this.targetLanguage = config.targetLanguage;
-       this.sourceRevision = config.sourceRevision;
+mw.cx.init.Translation = function MwCXInitTranslation( sourceWikiPage, 
targetWikiPage, services ) {
+       this.sourceWikiPage = sourceWikiPage;
+       this.targetWikiPage = targetWikiPage;
+       this.services = services;
+
+       // BC with other code
+       this.config = services;
+       this.config.sourceTitle = sourceWikiPage.getTitle();
+       this.config.sourceLanguage = sourceWikiPage.getLanguage();
+       this.config.sourceRevision = sourceWikiPage.getRevision();
+       this.config.targetTitle = targetWikiPage.getTitle();
+       this.config.targetLanguage = targetWikiPage.getLanguage();
+
+       // @var {mw.cx.ui.TranslationView}
        this.translationView = null;
+       // @var {mw.cx.dm.Translation}
        this.translationModel = null;
+       // @var {mw.cx.Translation}
        this.translation = null;
+       // @var {mw.cx.dm.SourcePage}
+       this.sourcePage = null;
+       // @var {mw.cx.dm.TargetPage}
+       this.targetPage = null;
 };
 
 /**
- * Initialize translation feature
- * @return {jQuery.Promise}
+ * Load all data necessary to start a translation.
  */
 mw.cx.init.Translation.prototype.init = function () {
        this.translationView = new mw.cx.ui.TranslationView( this.config );
        // Paint the initial UI.
        this.attachToDOM( this.translationView );
 
-       return this.fetchCXConfiguration( this.sourceLanguage, 
this.targetLanguage ).then( function( response ) {
-               $.extend( this.config, response.configuration );
-               return this.initTranslation();
-       }.bind( this ) );
-};
-
-/**
- * Initialize the data models, fetch source page and present it to user.
- * @return {jQuery.Promise}
- */
-mw.cx.init.Translation.prototype.initTranslation = function () {
-       this.sourcePage = new mw.cx.dm.SourcePage( this.config );
-       this.targetPage = new mw.cx.dm.TargetPage( this.config );
-       this.translationModel = new mw.cx.dm.Translation( this.config );
-       this.translationModel.setSourcePage( this.sourcePage );
-       this.translationModel.setTargetPage( this.targetPage );
-
-       this.translation = new mw.cx.Translation( this.translationModel, 
this.translationView, this.config );
-       // Fetch the source page from cxserver. The content is segmented.
-       return this.fetchSourcePageContent(
-               this.sourceTitle, this.sourceLanguage, this.sourceRevision
-       ).then( function( segmentedSourcePage ) {
-               this.loadTranslation( segmentedSourcePage );
-               return this.fetchAndAdaptCategories();
-       }.bind( this ) );
-};
-
-/**
- * Load the translation from the fetched source page and present to translator
- * @param {object} segmentedSourcePage
- */
-mw.cx.init.Translation.prototype.loadTranslation = function ( 
segmentedSourcePage ) {
-       this.sourcePage.setSections( $.parseHTML( 
segmentedSourcePage.segmentedContent ) );
-       this.sourcePage.setSourceRevision( segmentedSourcePage.revision );
-       this.config.sourceRevision = segmentedSourcePage.revision;
-       this.translationModel.setSourceRevisionId( 
this.sourcePage.getSourceRevision() );
-       this.translationModel.prepareTranslationUnits();
-
-       // Get the saved translation and set the properties in translation model
-       this.translation.getSavedTranslation().then( function( savedTranslation 
) {
-               this.translationModel.setTargetURL( savedTranslation.targetURL 
);
-               this.translationModel.setStatus( savedTranslation.status );
-               this.translationModel.setTargetRevisionId( 
savedTranslation.targetRevisionId );
-               this.translationModel.setProgress( JSON.parse( 
savedTranslation.progress ) );
-               this.translationModel.setId( savedTranslation.id );
-               this.translationModel.setTargetTitle( 
savedTranslation.targetTitle );
-               // Restore each translation storage units against the source 
sections.
-               this.translation.restore( savedTranslation );
-       }.bind( this ) ).always( function() {
-               this.translationView.setTranslation( this.translationModel );
-               this.translationView.loadTranslation();
-       }.bind( this ) );
-};
-
-/**
- * Fetch and adapt the categories for target language
- * @return {jQuery.Promise}
- */
-mw.cx.init.Translation.prototype.fetchAndAdaptCategories = function () {
-       return this.sourcePage.getCategories().then( function( sourceCategories 
) {
-               return this.targetPage.adaptCategoriesFrom( 
this.sourceLanguage, sourceCategories )
-                       .then( function() {
-                               this.translationView.showCategories();
+       // Deferred.done is used to stop errors from bubbling to other error 
handlers.
+       // Can be rewritten when we have proper promises.
+       this.fetchConfiguration(
+               this.sourceWikiPage.getLanguage(),
+               this.targetWikiPage.getLanguage()
+       ).then(
+               this.fetchConfigurationSuccess.bind( this ),
+               this.fetchConfigurationError.bind( this )
+       ).done( function () {
+               this.fetchSourcePageContent( this.sourceWikiPage, 
this.services.siteMapper ).then(
+                       this.fetchSourcePageContentSuccess.bind( this ),
+                       this.fetchSourcePageContentError.bind( this )
+               ).done( function () {
+                       this.fetchDraftInformation(
+                               this.sourceWikiPage,
+                               this.targetWikiPage
+                       ).then(
+                               this.fetchDraftInformationSuccess.bind( this ),
+                               this.fetchDraftInformationError.bind( this )
+                       ).done( function ( draftId ) {
+                               this.fetchDraft( draftId ).then(
+                                       this.fetchDraftSuccess.bind( this ),
+                                       this.fetchDraftError.bind( this )
+                               ).done( this.enableTranslation.bind( this ) );
                        }.bind( this ) );
+               }.bind( this ) );
        }.bind( this ) );
 };
 
 /**
- * Attach the translation view to DOM
- * @param {mw.cx.ui.TranslationView} cxview
- */
-mw.cx.init.Translation.prototype.attachToDOM = function ( cxview ) {
-       $( 'body' ).append( cxview.$element );
-};
-
-/**
- * Fetch the page with given title and language.
- * Response contains
+ * Attach the translation view to DOM.
  *
- * @param {string} title Title of the page to be fetched
- * @param {string} language Language of the page requested. This will be used 
to
- *     identify the host wiki.
- * @param {string} revision Source page revision id.
- * @return {jQuery.Promise}
+ * @private
+ * @param {mw.cx.ui.TranslationView} view
  */
-mw.cx.init.Translation.prototype.fetchSourcePageContent = function ( title, 
language, revision ) {
-       var fetchParams, apiURL, fetchPageUrl;
-
-       fetchParams = {
-               $language: this.siteMapper.getWikiDomainCode( language ),
-               // Manual normalisation to avoid redirects on spaces but not to 
break namespaces
-               $title: title.replace( / /g, '_' )
-       };
-       apiURL = '/page/$language/$title';
-
-       // If revision is requested, load that revision of page.
-       if ( revision ) {
-               fetchParams.$revision = revision;
-               apiURL += '/$revision';
-       }
-
-       fetchPageUrl = this.config.siteMapper.getCXServerUrl( apiURL, 
fetchParams );
-
-       return $.get( fetchPageUrl ).fail( function ( xhr ) {
-               if ( xhr.status === 404 ) {
-                       mw.hook( 'mw.cx.error' ).fire(
-                               mw.msg( 'cx-error-page-not-found', title, 
$.uls.data.getAutonym( language ) )
-                       );
-               } else {
-                       mw.hook( 'mw.cx.error' ).fire( mw.msg( 
'cx-error-server-connection' ) );
-               }
-       } );
+mw.cx.init.Translation.prototype.attachToDOM = function ( view ) {
+       $( 'body' ).append( view.$element );
 };
 
 /**
- * Fetch CX Language pair configuration
+ * Fetch language pair configuration from ContentTranslation extension API.
+ *
+ * @private
  * @param {string} sourceLanguage Source language
  * @param {string} targetLanguage Target language
- * @return {jQuery.Promise}
+ * @return {jQuery.Promise} Configuration settings as returned by the API.
  */
-mw.cx.init.Translation.prototype.fetchCXConfiguration = function ( 
sourceLanguage, targetLanguage ) {
+mw.cx.init.Translation.prototype.fetchConfiguration = function ( 
sourceLanguage, targetLanguage ) {
        return new mw.Api().get( {
                action: 'cxconfiguration',
                from: sourceLanguage,
                to: targetLanguage
        } );
 };
+
+mw.cx.init.Translation.prototype.fetchConfigurationSuccess = function ( 
response ) {
+       $.extend( this.config, response.configuration );
+};
+
+mw.cx.init.Translation.prototype.fetchConfigurationError = function () {
+       // XXX
+       mw.hook( 'mw.cx.error' ).fire( 'Unable to fetch configuration for this 
language pair.' );
+};
+
+/**
+ * Fetch the source page content from cxserver.
+ *
+ * @private
+ * @param {mw.cx.dm.WikiPage} wikiPage
+ * @param {ext.cx.SiteMapper} siteMapper
+ * @return {jQuery.Promise}
+ */
+mw.cx.init.Translation.prototype.fetchSourcePageContent = function ( wikiPage, 
siteMapper ) {
+       var fetchParams, apiURL, fetchPageUrl;
+
+       fetchParams = {
+               $language: siteMapper.getWikiDomainCode( wikiPage.getLanguage() 
),
+               // Manual normalisation to avoid redirects on spaces but not to 
break namespaces
+               $title: wikiPage.getTitle().replace( / /g, '_' )
+       };
+
+       apiURL = '/page/$language/$title';
+
+       // If revision is requested, load that revision of page.
+       if ( wikiPage.getRevision() ) {
+               fetchParams.$revision = wikiPage.getRevision();
+               apiURL += '/$revision';
+       }
+
+       fetchPageUrl = siteMapper.getCXServerUrl( apiURL, fetchParams );
+
+       return $.get( fetchPageUrl );
+};
+
+mw.cx.init.Translation.prototype.fetchSourcePageContentSuccess = function ( 
content ) {
+       // Update with revision information
+       this.sourceWikiPage = new mw.cx.dm.WikiPage(
+               this.sourceWikiPage.getTitle(),
+               this.sourceWikiPage.getLanguage(),
+               content.revision
+       );
+       // BC
+       this.config.sourceRevision = content.revision;
+
+       this.sourcePage = new mw.cx.dm.SourcePage( this.config );
+       this.sourcePage.setSections( $.parseHTML( content.segmentedContent ) );
+
+       this.targetPage = new mw.cx.dm.TargetPage( this.config );
+
+       this.translationModel = new mw.cx.dm.Translation( this.config );
+       this.translationModel.setSourcePage( this.sourcePage );
+       this.translationModel.setTargetPage( this.targetPage );
+       this.translationModel.setSourceRevisionId( 
this.sourcePage.getSourceRevision() );
+       this.translationModel.prepareTranslationUnits();
+
+       this.translation = new mw.cx.Translation( this.translationModel, 
this.translationView, this.config );
+};
+
+mw.cx.init.Translation.prototype.fetchSourcePageContentError = function ( xhr 
) {
+       if ( xhr.status === 404 ) {
+               mw.hook( 'mw.cx.error' ).fire(
+                       mw.msg(
+                               'cx-error-page-not-found',
+                               this.sourceWikiPage.getTitle(),
+                               $.uls.data.getAutonym( 
this.sourceWikiPage.getLanguage() )
+                       )
+               );
+       } else {
+               mw.hook( 'mw.cx.error' ).fire( mw.msg( 
'cx-error-server-connection' ) );
+       }
+};
+
+/**
+ * Find if there is a draft existing for the current title and language pair.
+ *
+ * @private
+ * @param {mw.cx.dm.WikiPage} sourceWikiPage
+ * @param {mw.cx.dm.WikiPage} targetWikiPage
+ * @return {jQuery.Promise} Information about an existing draft (if any) as 
returned by the API.
+ */
+mw.cx.init.Translation.prototype.fetchDraftInformation = function ( 
sourceWikiPage, targetWikiPage ) {
+       return new mw.Api().get( {
+               action: 'query',
+               list: 'contenttranslation',
+               sourcetitle: sourceWikiPage.getTitle(),
+               from: sourceWikiPage.getLanguage(),
+               to: targetWikiPage.getLanguage()
+       } ).then( function ( response ) {
+               return response.query && 
response.query.contenttranslation.translation;
+       } );
+};
+
+/**
+ * Check whether an existing draft can be used.
+ *
+ * @private
+ * @param {Object} draft
+ * @return {jQuery.Promise} Draft id or null.
+ */
+mw.cx.init.Translation.prototype.fetchDraftInformationSuccess = function ( 
draft ) {
+       if ( !draft ) {
+               // No draft exists
+               return $.Deferred().resolve( null ).promise();
+       }
+
+       // Do not allow two users to start a draft at the same time. The API 
only
+       // returns a translation with different translatorName if this is the 
case.
+       if ( draft.translatorName !== mw.user.getName() ) {
+               this.translationView.showConflictWarning( draft );
+               // Stop further processing!
+               return $.Deferred().reject().promise();
+       }
+
+       // Don't restore deleted drafts
+       if ( draft.status !== 'deleted' ) {
+               return $.Deferred().resolve( draft.id ).promise();
+       }
+
+       return $.Deferred().resolve( null ).promise();
+};
+
+mw.cx.init.Translation.prototype.fetchDraftInformationError = function () {
+       // XXX
+       mw.hook( 'mw.cx.error' ).fire( 'Unable to fetch draft information.' );
+       mw.log( '[CX]', arguments );
+};
+
+/**
+ * Fetch the translation from database (if any exists)
+ *
+ * @private
+ * @param {string|null} draftId Id for saved draft
+ * @return {jQuery.Promise}
+ */
+mw.cx.init.Translation.prototype.fetchDraft = function ( draftId ) {
+       // In case there is no draft, skip loading it
+       if ( draftId === null ) {
+               return $.Deferred().resolve().promise();
+       }
+
+       this.translationView.setStatusMessage( mw.msg( 'cx-draft-restoring' ) );
+
+       return new mw.Api().get( {
+               action: 'query',
+               list: 'contenttranslation',
+               translationid: draftId
+       } ).then( function ( response ) {
+               return response.query.contenttranslation.translation;
+       } );
+};
+
+mw.cx.init.Translation.prototype.fetchDraftSuccess = function ( draft ) {
+       // In case there is no draft (see fetchDraft), there is nothing for us 
to do
+       if ( !draft ) {
+               return;
+       }
+
+       this.translationModel.setTargetURL( draft.targetURL );
+       this.translationModel.setStatus( draft.status );
+       this.translationModel.setTargetRevisionId( draft.targetRevisionId );
+       this.translationModel.setProgress( JSON.parse( draft.progress ) );
+       this.translationModel.setId( draft.id );
+       this.translationModel.setTargetTitle( draft.targetTitle );
+
+       // Restore each translation storage units against the source sections.
+       this.translation.restore( draft );
+       this.translationView.setStatusMessage( mw.msg( 'cx-draft-restored' ) );
+};
+
+mw.cx.init.Translation.prototype.fetchDraftError = function ( errorCode, 
details ) {
+       if ( details.exception instanceof Error ) {
+               details.exception = details.exception.toString();
+       }
+       details.errorCode = errorCode;
+       this.translationView.setStatusMessage( mw.msg( 
'cx-draft-restore-failed' ) );
+
+};
+
+/**
+ * Enables translation and starts post-load processes.
+ *
+ * @private
+ */
+mw.cx.init.Translation.prototype.enableTranslation = function () {
+       this.translationView.setTranslation( this.translationModel );
+       this.translationView.loadTranslation();
+       this.fetchAndAdaptCategories();
+};
+
+/**
+ * Fetch and adapt the categories.
+ * @return {jQuery.Promise}
+ */
+mw.cx.init.Translation.prototype.fetchAndAdaptCategories = function () {
+       return this.sourcePage.getCategories().then( function( sourceCategories 
) {
+               return this.targetPage.adaptCategoriesFrom(
+                       this.sourceWikiPage.getLanguage(),
+                       sourceCategories
+               ).then( function() {
+                       this.translationView.showCategories();
+               }.bind( this ) );
+       }.bind( this ) );
+};
diff --git a/modules/mw.cx.init.js b/modules/mw.cx.init.js
index 7be8a71..86e3338 100644
--- a/modules/mw.cx.init.js
+++ b/modules/mw.cx.init.js
@@ -6,40 +6,42 @@
        'use strict';
 
        function initCX() {
-               var translation, query, requestManager, config;
+               var query, services = {}, sourceWikiPage, targetWikiPage, 
translation;
+
+               query = new mw.Uri().query;
+               if (
+                       !query.page || !query.from || !query.to ||
+                       ( mw.Title.newFromText( query.page ) === null )
+               ) {
+                       location.href = mw.util.getUrl( 
'Special:ContentTranslation' );
+                       return;
+               }
 
                // Set the global siteMapper for code which we cannot inject it
+               // All these configuration in mw.cx is just for supporting 
legacy code.
+               // New code should get them from config injected to classes.
                mw.cx.siteMapper = new mw.cx.SiteMapper( mw.config.get( 
'wgContentTranslationSiteTemplates' ) );
-               query = new mw.Uri().query;
                mw.cx.sourceTitle = query.page;
                mw.cx.targetLanguage = query.to;
                mw.cx.sourceLanguage = query.from;
                mw.cx.sourceRevision = query.revision;
                mw.cx.targetTitle = query.targettitle || query.page;
-               // All these configuration in mw.cx is just for supporting 
legacy code.
-               // New code should get them from config injected to classes.
 
-               // Make them available in config.
-               config = {
-                       siteMapper: mw.cx.siteMapper,
-                       sourceTitle: mw.cx.sourceTitle,
-                       targetTitle: mw.cx.targetTitle,
-                       targetLanguage: mw.cx.targetLanguage,
-                       sourceLanguage: mw.cx.sourceLanguage,
-                       sourceRevision: mw.cx.sourceRevision,
-                       campaign: query.campaign
+               // Global services that every class can expect to have
+               services = {
+                       siteMapper: mw.cx.siteMapper
                };
-               requestManager = new mw.cx.MwApiRequestManager( config );
-               requestManager.init();
-               config.requestManager = requestManager;
 
-               if ( !config.sourceTitle || !config.sourceLanguage || 
!config.targetLanguage ||
-                       ( mw.Title.newFromText( config.sourceTitle ) === null )
-               ) {
-                       location.href = mw.util.getUrl( 
'Special:ContentTranslation' );
-               } else {
-                       translation = new mw.cx.init.Translation( config );
-                       translation.init();
+               services.requestManager = new mw.cx.MwApiRequestManager( 
query.from, query.to, services.siteMapper );
+               services.requestManager.init();
+
+               sourceWikiPage = new mw.cx.dm.WikiPage( query.page, query.from, 
query.revision );
+               targetWikiPage = new mw.cx.dm.WikiPage( query.targettitle || 
query.page, query.to );
+               translation = new mw.cx.init.Translation( sourceWikiPage, 
targetWikiPage, services );
+               translation.init();
+
+               if ( query.campaign ) {
+                       mw.hook( 'mw.cx.cta.accept' ).fire( query.campaign, 
query.from, query.page, query.to );
                }
        }
 
diff --git a/modules/tests/dm/mw.cx.dm.LinkTranslationUnit.test.js 
b/modules/tests/dm/mw.cx.dm.LinkTranslationUnit.test.js
index 067c8b6..e944ab8 100644
--- a/modules/tests/dm/mw.cx.dm.LinkTranslationUnit.test.js
+++ b/modules/tests/dm/mw.cx.dm.LinkTranslationUnit.test.js
@@ -1,12 +1,8 @@
 QUnit.module( 'mw.cx.dm.LinkTranslationUnit', QUnit.newMwEnvironment( {
        setup: function () {
-               var sitemapper;
-
-               sitemapper = new mw.cx.SiteMapper(
+               this.siteMapper = new mw.cx.SiteMapper(
                        mw.config.get( 'wgContentTranslationSiteTemplates' )
                );
-               this.config = {};
-               this.config.siteMapper = sitemapper;
        }
 } ) );
 
@@ -50,10 +46,12 @@
                sourceLinkDoc.title = tests[ i ].title;
                sourceLinkDoc.href = tests[ i ].title;
 
-               config = $.extend( {}, this.config, {
+               // BC
+               config = {
                        sourceLanguage: tests[ i ].sourceLanguage,
-                       targetLanguage: tests[ i ].targetLanguage
-               } );
+                       targetLanguage: tests[ i ].targetLanguage,
+                       siteMapper: this.siteMapper
+               };
 
                // Set the response in cache so that network requests wont be 
initiated.
                mockResponse = {};
@@ -63,7 +61,11 @@
                        missing: false
                };
 
-               requestManager = new mw.cx.MwApiRequestManager( config );
+               requestManager = new mw.cx.MwApiRequestManager(
+                       tests[ i ].sourceLanguage,
+                       tests[ i ].targetLanguage,
+                       this.siteMapper
+               );
                requestManager.init();
                requestManager.titlePairCache[ tests[ i ].sourceLanguage ].set( 
mockResponse );
                config.requestManager = requestManager;
diff --git a/modules/ui/mw.cx.ui.Columns.js b/modules/ui/mw.cx.ui.Columns.js
index b453faa..506fe12 100644
--- a/modules/ui/mw.cx.ui.Columns.js
+++ b/modules/ui/mw.cx.ui.Columns.js
@@ -6,7 +6,7 @@
  * @param {mw.cx.dm.Translation} translation
  * @param {Object} config
  */
-mw.cx.ui.Columns = function ( translation, config ) {
+mw.cx.ui.Columns = function MwCxUiColumns( translation, config ) {
        // Configuration initialization
        this.config = config || {};
        this.sourceColumn = new mw.cx.ui.SourceColumn( translation, this.config 
);
diff --git a/modules/ui/mw.cx.ui.SourceColumn.js 
b/modules/ui/mw.cx.ui.SourceColumn.js
index 494a42b..b2f6fa8 100644
--- a/modules/ui/mw.cx.ui.SourceColumn.js
+++ b/modules/ui/mw.cx.ui.SourceColumn.js
@@ -32,6 +32,7 @@
        this.render();
        // Try to load Cite styles. Silently ignored if not installed.
        mw.loader.load( 'ext.cite.style' );
+       mw.hook( 'mw.cx.error' ).add( $.proxy( this.removeLoadingIndicator, 
this ) );
 };
 
 mw.cx.ui.SourceColumn.prototype.render = function () {
diff --git a/modules/ui/mw.cx.ui.TranslationView.js 
b/modules/ui/mw.cx.ui.TranslationView.js
index 6047a45..051e4f6 100644
--- a/modules/ui/mw.cx.ui.TranslationView.js
+++ b/modules/ui/mw.cx.ui.TranslationView.js
@@ -32,12 +32,8 @@
 mw.cx.ui.TranslationView.prototype.init = function () {
        if ( mw.user.isAnon() ) {
                mw.hook( 'mw.cx.error.anonuser' ).fire();
-               return;
        }
 
-       if ( this.config.campaign ) {
-               mw.hook( 'mw.cx.cta.accept' ).fire( this.config.campaign, 
this.config.sourceLanguage, this.config.targetLanguage );
-       }
        this.render();
 };
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie68d3b46b6cd0eae22282288ab0158bb2f5d8bef
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Nikerabbit <[email protected]>

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

Reply via email to