Santhosh has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/232019

Change subject: [WIP] Dashboard: Show translation suggestions
......................................................................

[WIP] Dashboard: Show translation suggestions

Change-Id: I503310492a7bac3f4072042bb1e64b9e2ed4891b
---
M extension.json
M modules/dashboard/ext.cx.dashboard.js
A modules/dashboard/ext.cx.suggestionlist.js
A modules/dashboard/styles/ext.cx.suggestionlist.less
4 files changed, 348 insertions(+), 5 deletions(-)


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

diff --git a/extension.json b/extension.json
index c1604cf..eabfd35 100644
--- a/extension.json
+++ b/extension.json
@@ -197,6 +197,7 @@
                                "ext.cx.sitemapper",
                                "ext.cx.source.selector",
                                "ext.cx.translationlist",
+                               "ext.cx.suggestionlist",
                                "mediawiki.Uri",
                                "mediawiki.ui.button"
                        ],
@@ -768,6 +769,18 @@
                                "cx-translationlist-empty-desc"
                        ]
                },
+               "ext.cx.suggestionlist": {
+                       "scripts": [
+                               "dashboard/ext.cx.suggestionlist.js"
+                       ],
+                       "styles": [
+                               "dashboard/styles/ext.cx.suggestionlist.less"
+                       ],
+                       "dependencies": [
+                               "ext.cx.util",
+                               "jquery.uls.data"
+                       ]
+               },
                "ext.cx.translation.conflict": {
                        "scripts": [
                                "translation/ext.cx.translation.conflict.js"
diff --git a/modules/dashboard/ext.cx.dashboard.js 
b/modules/dashboard/ext.cx.dashboard.js
index ac36202..91b2d67 100644
--- a/modules/dashboard/ext.cx.dashboard.js
+++ b/modules/dashboard/ext.cx.dashboard.js
@@ -39,6 +39,27 @@
        };
 
        /**
+        * Get all the translation suggestion lists of given user.
+        *
+        * @return {jQuery.Promise}
+        */
+       CXDashboard.prototype.getSuggestionLists = function () {
+               var storedSourceLanguage, storedTargetLanguage, api = new 
mw.Api();
+               if ( window.localStorage ) {
+                       storedTargetLanguage = localStorage.getItem( 
'cxTargetLanguage' );
+                       storedSourceLanguage = localStorage.getItem( 
'cxSourceLanguage' );
+               }
+
+               return api.get( {
+                       action: 'query',
+                       list: 'contenttranslationlist',
+                       from: storedSourceLanguage || 'en', // FIXME do 
something smart here
+                       to: storedTargetLanguage || mw.config.get( 
'wgContentLanguage' ),
+                       format: 'json'
+               } );
+       };
+
+       /**
         * Get all the translations of given user.
         *
         * @return {jQuery.Promise}
@@ -64,7 +85,11 @@
                                response.query.contenttranslation.translations
                        );
                } );
-               // TODO: Get suggestions
+               this.getSuggestionLists().done( function ( response ) {
+                       self.renderTranslationSuggestions(
+                               
response.query.contenttranslationlist.lists.missingfeaturedarticles
+                       );
+               } );
        };
 
        /**
@@ -84,6 +109,15 @@
                        );
                }
        };
+
+       /**
+        * Populates various UI components with data in the given translation 
suggestions.
+        */
+       CXDashboard.prototype.renderTranslationSuggestions = function ( 
suggestions ) {
+               this.suggestionList = new mw.cx.CXSuggestionList( 
this.$translationListContainer, suggestions, this.siteMapper );
+               this.suggestionList.init();
+       };
+
        /**
         * Populates various UI components with data in the given translations.
         */
@@ -213,11 +247,14 @@
                        .addClass( 'cx-statusfilter' )
                        .append(
                                $( '<span>' )
-                               .addClass( 'cx-status cx-status--draft 
cx-status--selected mw-ui-input' )
-                               .text( mw.msg( 
'cx-translation-filter-draft-translations' ) ),
+                                       .addClass( 'cx-status 
cx-status--suggestions mw-ui-input' )
+                                       .text( 'Suggestions' ),
                                $( '<span>' )
-                               .addClass( 'cx-status cx-status--published 
mw-ui-input' )
-                               .text( mw.msg( 
'cx-translation-filter-published-translations' ) )
+                                       .addClass( 'cx-status cx-status--draft 
cx-status--selected mw-ui-input' )
+                                       .text( mw.msg( 
'cx-translation-filter-draft-translations' ) ),
+                               $( '<span>' )
+                                       .addClass( 'cx-status 
cx-status--published mw-ui-input' )
+                                       .text( mw.msg( 
'cx-translation-filter-published-translations' ) )
                        );
 
                this.$sourceLanguageFilter = createSelect(
diff --git a/modules/dashboard/ext.cx.suggestionlist.js 
b/modules/dashboard/ext.cx.suggestionlist.js
new file mode 100644
index 0000000..b7f83eb
--- /dev/null
+++ b/modules/dashboard/ext.cx.suggestionlist.js
@@ -0,0 +1,291 @@
+/**
+ * ContentTranslation extension - Translation listing in dashboard.
+ *
+ * @file
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $, mw ) {
+       'use strict';
+
+       /**
+        * CXTranslationList
+        *
+        * @class
+        */
+       function CXSuggestionList( $container, translations, siteMapper ) {
+               this.$container = $container;
+               this.siteMapper = siteMapper;
+               this.translations = translations;
+               this.$sourceLanguageFilter = null;
+               this.$targetLanguageFilter = null;
+               this.$header = null;
+               this.$confirmationDialog = null;
+               this.$overlay = null;
+
+               this.listen();
+       }
+
+       CXSuggestionList.prototype.init = function () {
+               this.listTranslations();
+       };
+
+       /**
+        * Get the thumbnail image of the given link.
+        * @param {string} id translation id
+        * @param {string} language
+        * @param {string} title Title
+        * @return {jQuery.Promise}
+        */
+       CXSuggestionList.prototype.getLinkImage = function ( language, title ) {
+               return this.siteMapper.getApi( language ).get( {
+                       action: 'query',
+                       titles: title,
+                       prop: 'pageimages',
+                       piprop: 'thumbnail',
+                       pithumbsize: 150,
+                       redirects: true,
+                       format: 'json'
+               }, {
+                       dataType: 'jsonp',
+                       // This prevents warnings about the unrecognized 
parameter "_"
+                       cache: true
+               } );
+       };
+
+       /**
+        * Show a title image of the translation based on source title.
+        * @param {Object} translation
+        */
+       CXSuggestionList.prototype.showTitleImage = function ( translation, 
type ) {
+               this.getLinkImage( translation.sourceLanguage, 
translation.sourceTitle )
+                       .done( function ( response ) {
+                               var pageId, page, imgSrc;
+
+                               pageId = Object.keys( response.query.pages )[ 0 
];
+                               page = response.query.pages[ pageId ];
+                               if ( page.thumbnail ) {
+                                       imgSrc = page.thumbnail.source;
+                                       $( '#' + type + translation.id ).find( 
'.image' ).attr( 'src', imgSrc );
+                               }
+                       } );
+       };
+
+       /**
+        * List all translations.
+        */
+       CXSuggestionList.prototype.listTranslations = function () {
+               var i, translation, progress, $translation,
+                       $lastUpdated, $imageBlock, $image, $progressbar,
+                       sourceDir, targetDir,
+                       translationLinkUrl, $translationLink,
+                       $sourceLanguage, $targetLanguage, $languageContainer, 
$status,
+                       $actionsTrigger, $deleteTranslation, $menu, 
$menuContainer,
+                       $titleLanguageBlock,
+                       $translations = [];
+
+               for ( i = 0; i < this.translations.length; i++ ) {
+                       translation = this.translations[ i ];
+
+                       try {
+                               progress = JSON.parse( translation.progress );
+                       } catch ( e ) {
+                               progress = {};
+                       }
+
+                       $translation = $( '<div>' )
+                               .addClass( 'cx-tlitem' )
+                               .attr( 'id', 'translation' + translation.id );
+                       $lastUpdated = $( '<div>' )
+                               .addClass( 'last-updated' )
+                               .text( moment( translation.lastUpdateTimeStamp, 
'YYYYMMDDHHmmss Z' ).fromNow() );
+                       $imageBlock = $( '<div>' )
+                               .addClass( 'cx-tlitem__image' );
+                       $image = $( '<img>' )
+                               .addClass( 'image' );
+                       $progressbar = $( '<div>' )
+                               .addClass( 'progressbar' )
+                               .cxProgressBar( {
+                                       weights: progress
+                               } );
+                       $imageBlock.append( $image );
+                       this.showTitleImage( translation, 'translation' );
+
+                       sourceDir = $.uls.data.getDir( 
translation.sourceLanguage );
+                       targetDir = $.uls.data.getDir( 
translation.targetLanguage );
+
+                       if ( translation.status === 'draft' ) {
+                               translationLinkUrl = new mw.Uri( 
mw.cx.siteMapper.getCXUrl(
+                                       translation.sourceTitle,
+                                       translation.targetTitle,
+                                       translation.sourceLanguage,
+                                       translation.targetLanguage
+                               ) ).extend( {
+                                       draft: translation.status === 'draft' ? 
translation.id : undefined
+                               } ).toString();
+                       }
+
+                       if ( translation.status === 'published' ) {
+                               translationLinkUrl = translation.targetURL;
+                       }
+
+                       $translationLink = $( '<a>' )
+                               .addClass( 'translation-link' )
+                               .prop( 'href', translationLinkUrl )
+                               // It must be a separate element to ensure
+                               // separation from the target title
+                               .append( $( '<span>' )
+                                       .text( translation.sourceTitle )
+                                       .addClass( 'source-title' )
+                                       .prop( {
+                                               lang: 
translation.sourceLanguage,
+                                               dir: sourceDir
+                                       } )
+                               );
+
+                       // If the translated title is different from the source 
title,
+                       // show it near the source title
+                       if ( translation.sourceTitle !== 
translation.targetTitle ) {
+                               $translationLink.append(
+                                       $( '<span>' ).html( '&#160;' ), // nbsp 
to ensure separation between words
+                                       $( '<span>' )
+                                       .prop( {
+                                               lang: 
translation.targetLanguage,
+                                               dir: targetDir
+                                       } )
+                                       .addClass( 'target-title' )
+                                       .text( translation.targetTitle )
+                               );
+                       }
+
+                       $sourceLanguage = $( '<div>' )
+                               .prop( {
+                                       lang: translation.sourceLanguage,
+                                       dir: sourceDir
+                               } )
+                               .addClass( 'cx-tlitem__languages__language 
cx-tlitem__languages__language--source' )
+                               .text( $.uls.data.getAutonym( 
translation.sourceLanguage ) );
+
+                       $targetLanguage = $( '<div>' )
+                               .prop( {
+                                       lang: translation.targetLanguage,
+                                       dir: targetDir
+                               } )
+                               .addClass( 'cx-tlitem__languages__language 
cx-tlitem__languages__language--target' )
+                               .text( $.uls.data.getAutonym( 
translation.targetLanguage ) );
+
+                       $languageContainer = $( '<div>' )
+                               .addClass( 'cx-tlitem__languages' )
+                               .append( $sourceLanguage, $targetLanguage );
+
+                       $status = $( '<div>' )
+                               .addClass( 'status status-' + 
translation.status )
+                               .text( mw.msg( 'cx-translation-status-' + 
translation.status ) );
+
+                       // If the translation is draft, allow deleting it
+                       if ( translation.status === 'draft' ) {
+                               $actionsTrigger = $( '<div>' )
+                                       .addClass( 
'cx-tlitem__actions__trigger' )
+                                       .text( '…' );
+                               $deleteTranslation = $( '<li>' )
+                                       .addClass( 'cx-discard-translation' )
+                                       .text( mw.msg( 'cx-discard-translation' 
) )
+                                       .data( 'translation', translation );
+                               $menu = $( '<ul>' )
+                                       .append( $deleteTranslation );
+                               $menuContainer = $( '<div>' )
+                                       .addClass( 'cx-tlitem__actions' )
+                                       .append( $actionsTrigger, $menu );
+                       } else {
+                               $menuContainer = $();
+                       }
+
+                       $titleLanguageBlock = $( '<div>' )
+                               .addClass( 'cx-tlitem__details' )
+                               .append( $translationLink, $progressbar, 
$lastUpdated, $languageContainer );
+
+                       $translation.append(
+                               $menuContainer,
+                               $imageBlock,
+                               $titleLanguageBlock
+                       );
+
+                       $translations.push( $translation );
+
+                       // Store reference to the DOM node
+                       translation.$element = $translation;
+               }
+
+               if ( $translations.length ) {
+                       this.$container.append( $( '<div>' )
+                               .addClass( 'cx-translationlist' )
+                               .append( $translations )
+                       );
+               } else {
+                       this.$container.append( $( '<div>' )
+                               .addClass( 'cx-translationlist-empty' )
+                               .append(
+                                       $( '<div>' )
+                                       .addClass( 
'cx-translationlist-empty__img' ),
+                                       $( '<div>' )
+                                       .addClass( 
'cx-translationlist-empty__title' )
+                                       .text( mw.msg( 
'cx-translationlist-empty-title' ) ),
+                                       $( '<div>' )
+                                       .addClass( 
'cx-translationlist-empty__desc' )
+                                       .text( mw.msg( 
'cx-translationlist-empty-desc' ) )
+                               ) );
+               }
+       };
+
+       CXSuggestionList.prototype.listen = function () {
+               var translationList = this;
+
+               this.$container.on( 'click', '.cx-discard-translation', 
function ( e ) {
+                       var translation;
+
+                       e.stopPropagation();
+
+                       translation = $( e.target ).data( 'translation' );
+
+                       translationList.showDiscardConfirmation( translation 
).done( function () {
+                               translationList.discardTranslation( translation 
).done( function ( response ) {
+                                       if ( response.cxdelete.result !== 
'success' ) {
+                                               return;
+                                       }
+
+                                       
translationList.markTranslationAsDeleted( translation );
+                                       mw.hook( 'mw.cx.translation.deleted' 
).fire(
+                                               translation.sourceLanguage,
+                                               translation.targetLanguage,
+                                               translation.sourceTitle,
+                                               translation.targetTitle
+                                       );
+                               } );
+                       } );
+               } );
+
+               this.$container.on( 'click', '.cx-tlitem', function () {
+                       if ( $( this ).hasClass( 'cx-translation-deleted' ) ) {
+                               return;
+                       }
+
+                       location.href = $( this ).find( '.translation-link' 
).attr( 'href' );
+               } );
+
+               $( window ).scroll( $.throttle( 250, $.proxy( this.scroll, this 
) ) );
+       };
+
+       CXSuggestionList.prototype.scroll = function () {
+               var scrollTop = $( window ).scrollTop(),
+                       offsetTop = this.$container.offset().top;
+
+               if ( scrollTop > offsetTop ) {
+                       this.$container.addClass( 'sticky' );
+               } else if ( scrollTop <= offsetTop ) {
+                       this.$container.removeClass( 'sticky' );
+               }
+       };
+
+       mw.cx.CXSuggestionList = CXSuggestionList;
+}( jQuery, mediaWiki ) );
diff --git a/modules/dashboard/styles/ext.cx.suggestionlist.less 
b/modules/dashboard/styles/ext.cx.suggestionlist.less
new file mode 100644
index 0000000..f05d003
--- /dev/null
+++ b/modules/dashboard/styles/ext.cx.suggestionlist.less
@@ -0,0 +1,2 @@
+@import "../../widgets/common/ext.cx.common";
+@import "mediawiki.mixins";

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I503310492a7bac3f4072042bb1e64b9e2ed4891b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com>

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

Reply via email to