jenkins-bot has submitted this change and it was merged.

Change subject: Publishing: Add publishing options dialog
......................................................................


Publishing: Add publishing options dialog

* Adds dialog and logic for when title to be published already exists
* Presents two options: Keep both versions and Publish anyway
* Keep both options adds a version number and saves that
* Publish anyway overrides the existing translation

Bug: T76464
Change-Id: I35b7a041cd9b2e2fefd8e9e271619a37e9a63e35
---
M Resources.php
M i18n/en.json
M i18n/qqq.json
A modules/publish/ext.cx.publish.dialog.js
M modules/publish/ext.cx.publish.js
A modules/publish/images/clear.png
A modules/publish/images/clear.svg
A modules/publish/styles/ext.cx.publish.dialog.less
8 files changed, 358 insertions(+), 54 deletions(-)

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



diff --git a/Resources.php b/Resources.php
index 61078d4..9b317d6 100644
--- a/Resources.php
+++ b/Resources.php
@@ -466,6 +466,7 @@
                'json',
                'mediawiki.api.edit',
                'mediawiki.cookie',
+               'ext.cx.publish.dialog',
        ),
        'messages' => array(
                'cx-publish-page-success',
@@ -475,6 +476,23 @@
        ),
 ) + $resourcePaths;
 
+$wgResourceModules['ext.cx.publish.dialog'] = array(
+       'scripts' => array(
+               'publish/ext.cx.publish.dialog.js',
+       ),
+       'styles' => array(
+               'publish/styles/ext.cx.publish.dialog.less',
+       ),
+       'dependencies' => array(
+               'ext.cx.model',
+       ),
+       'messages' => array(
+               'cx-publishing-dialog-message',
+               'cx-publishing-dialog-keep-button',
+               'cx-publishing-dialog-publish-anyway-button',
+       ),
+) + $resourcePaths;
+
 $wgResourceModules['ext.cx.eventlogging'] = array(
        'scripts' => 'eventlogging/ext.cx.eventlogging.js',
        'dependencies' => array(
diff --git a/i18n/en.json b/i18n/en.json
index e66d5e2..e257b51 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -122,5 +122,8 @@
        "cx-save-draft-tooltip": "Translation drafts are saved automatically",
        "cx-contributions": "New contribution",
        "cx-contributions-translation": "Translation",
-       "cx-contributions-media": "Upload media file"
+       "cx-contributions-media": "Upload media file",
+       "cx-publishing-dialog-message": "The page $1 already exists. The 
current content will be replaced by your translation. Do you want to publish 
anyway?",
+       "cx-publishing-dialog-keep-button": "Keep both versions",
+       "cx-publishing-dialog-publish-anyway-button": "Publish anyway"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 17b2cb5..1b651b0 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -125,5 +125,8 @@
        "cx-save-draft-tooltip": "Tooltip text shown for the save status 
indicator text in the header of [[Special:ContentTranslation]].\n\nParameters: 
\n* $1 - the number of minutes ago the translation was saved.",
        "cx-contributions": "Text of a button which opens a dropdown",
        "cx-contributions-translation": "Dropdown 
item\n{{Identical|Translation}}",
-       "cx-contributions-media": "Dropdown item"
+       "cx-contributions-media": "Dropdown item",
+       "cx-publishing-dialog-message": "Message that shows in the publishing 
options dialog when there is an existing page with the same title already 
published.\n\nParameters:\n* $1 - The link to the existing page with just the 
title as text.",
+       "cx-publishing-dialog-keep-button": "Button label for publishing 
options dialog. Clicking button preserves both the existing translation and the 
new translation.",
+       "cx-publishing-dialog-publish-anyway-button": "Button label for 
publishing options dialog. Clicking button overwrites the existing translation 
with the new translation."
 }
diff --git a/modules/publish/ext.cx.publish.dialog.js 
b/modules/publish/ext.cx.publish.dialog.js
new file mode 100644
index 0000000..d8e2a3f
--- /dev/null
+++ b/modules/publish/ext.cx.publish.dialog.js
@@ -0,0 +1,186 @@
+/**
+ * ContentTranslation Tools
+ * A tool that allows editors to translate pages from one language
+ * to another with the help of machine translation and other translation tools
+ *
+ * @file
+ * @ingroup Extensions
+ * @copyright See AUTHORS.txt
+ * @license GPL-2.0+
+ */
+( function ( $, mw ) {
+       'use strict';
+
+       /**
+        * Handles show the publishing options dialog.
+        *
+        * @class
+        */
+       function CXPublishingDialog( trigger ) {
+               this.$trigger = $( trigger );
+               this.$dialog = null;
+               this.$close = null;
+               this.$message = null;
+               this.init();
+       }
+
+       /**
+        * Initializes the publishing dialog instance.
+        * @param {string} title The title of the existing article
+        */
+       CXPublishingDialog.prototype.init = function () {
+               var title = $( '.cx-column--translation > h2' ).text();
+
+               if ( this.$dialog ) {
+                       this.setMessage( title );
+               } else {
+                       this.render( title );
+               }
+               this.listen();
+               this.position();
+               this.show();
+       };
+
+       /**
+        * Increase the version number of a title starting with 1
+        * @param {string} title The title to increase the version on
+        */
+       function increaseVersion( title ) {
+               var match, version;
+
+               match = title.match( /^.*\((\d)\)$/ );
+               if ( match ) {
+                       version = parseInt( match[ 1 ] ) + 1;
+                       return title.replace( /\(\d+\)$/, '(' + version + ')' );
+               } else {
+                       return title + ' (1)';
+               }
+
+       }
+
+       /**
+        * Renders the publishing options dialog.
+        * @param {string} title The title of the existing article
+        */
+       CXPublishingDialog.prototype.render = function ( title ) {
+               var $buttons, $keepButton, $publishAnywayButton,
+                       cxPublishingDialog = this;
+
+               this.$dialog = $( '<div>' )
+                       .addClass( 'cx-publishing-dialog' )
+                       .hide();
+
+               this.$close = $( '<div>' )
+                       .addClass( 'cx-publishing-dialog__close' )
+                       .on( 'click', function () {
+                               cxPublishingDialog.$dialog.hide();
+                       } );
+
+               this.$message = $( '<p>' )
+                       .addClass( 'cx-publishing-dialog__message' );
+
+               $( '.cx-publishing-dialog__message > a' ).prop( 'target', 
'_blank' );
+
+               $buttons = $( '<div>' )
+                       .addClass( 'cx-publishing-dialog__buttons' );
+
+               $keepButton = $( '<button>' )
+                       .addClass( 'cx-publishing-dialog__buttons-keep 
mw-ui-button mw-ui-quiet' )
+                       .text( mw.msg( 'cx-publishing-dialog-keep-button' ) )
+                       .on( 'click', function () {
+                               var text = $( '.cx-column--translation > h2' 
).text();
+                               $( '.cx-column--translation > h2' ).text( 
increaseVersion( text ) );
+                               cxPublishingDialog.$dialog.hide();
+                               mw.hook( 'mw.cx.publish' ).fire();
+                       } );
+
+               $publishAnywayButton = $( '<button>' )
+                       .addClass( 'cx-publishing-dialog__buttons-publishanyway 
mw-ui-button mw-ui-progressive' )
+                       .text( mw.msg( 
'cx-publishing-dialog-publish-anyway-button' ) )
+                       .on( 'click', function () {
+                               cxPublishingDialog.$dialog.hide();
+                               mw.hook( 'mw.cx.publish' ).fire( true );
+                       } );
+
+               this.setMessage( title );
+
+               $buttons.append( $publishAnywayButton, $keepButton );
+
+               this.$dialog.append( this.$close, this.$message, $buttons );
+
+               $( 'body' ).append( this.$dialog );
+
+       };
+
+       /**
+        * Sets the message for the publishing options dialog
+        * @param {string} title The title of the article to link in the message
+        */
+       CXPublishingDialog.prototype.setMessage = function ( title ) {
+               var publishedTitle, link;
+
+               publishedTitle = 'User:' + mw.user.getName() + '/' + title;
+
+               link = $( '<a>' ).attr( {
+                       href: mw.util.getUrl( publishedTitle ),
+                       target: '_blank'
+               } ).text( title )[ 0 ].outerHTML;
+
+               this.$message.html( mw.msg( 'cx-publishing-dialog-message', 
link ) );
+
+       };
+
+       /**
+        * Positions the dialog relative to the publish button.
+        */
+       CXPublishingDialog.prototype.position = function () {
+               var buttonPosition, buttonCenter, dialogLeft, dialogTop;
+
+               buttonPosition = this.$trigger.position();
+               buttonCenter = buttonPosition.left + ( 
this.$trigger.outerWidth() / 2 );
+               dialogLeft = buttonCenter - ( this.$dialog.outerWidth() / 2 );
+               dialogTop = $( window ).scrollTop() +
+                       buttonPosition.top +
+                       this.$trigger.height() + 20;
+
+               this.$dialog.css( {
+                       'top': dialogTop,
+                       'left': dialogLeft,
+                       'z-index': 100
+               } );
+
+       };
+
+       /**
+        * A listener that adjust the positioning when the page is scrolled
+        * Necessary because the publishing button moves to the left on window 
scroll
+        */
+       CXPublishingDialog.prototype.listen = function () {
+               $( window ).on( 'scroll', $.proxy( this.position, this ) );
+       };
+
+       /**
+        * Shows the dialog
+        */
+       CXPublishingDialog.prototype.show = function () {
+               this.$dialog.show();
+       };
+
+       /**
+        * CXPublishingDialog Plugin
+        */
+       $.fn.cxPublishingDialog = function () {
+               return this.each( function () {
+                       /*jshint validthis:true */
+                       var $this = $( this ),
+                               data = $this.data( 'cxPublishingDialog' );
+
+                       if ( !data ) {
+                               $this.data( 'cxPublishingDialog', ( data = new 
CXPublishingDialog( this ) ) );
+                       }
+
+                       data.init();
+
+               } );
+       };
+} )( jQuery, mediaWiki );
diff --git a/modules/publish/ext.cx.publish.js 
b/modules/publish/ext.cx.publish.js
index 00ca9c7..9a332e4 100644
--- a/modules/publish/ext.cx.publish.js
+++ b/modules/publish/ext.cx.publish.js
@@ -103,12 +103,37 @@
        };
 
        /**
+        * Checks to see if there is already a published article with the title
+        * @param {string} title The title to check
+        */
+       function checkTargetTitle( title ) {
+               var api,
+                       $deferred = $.Deferred();
+
+               api = new mw.Api();
+
+               api.get( {
+                       titles: title
+               }, {
+                       dataType: 'jsonp'
+               } ).done( function ( response ) {
+                       if ( response.query.pages[ -1 ] ) {
+                               $deferred.resolve( false );
+                       } else {
+                               $deferred.resolve( true );
+                       }
+               } );
+
+               return $deferred.promise();
+       }
+
+       /**
         * Publish the translation
         */
-       function publish() {
+       function publish( publishAnyway ) {
                var $publishArea, $publishButton, publisher, translatedTitle,
-                       translatedContent, targetTitle, targetCategories, 
$draftButton,
-                       sortedKeys, i, categoryTitles, categories;
+                       translatedContent, targetCategories, $draftButton, 
targetTitle,
+                       sortedKeys, i, categoryTitles, categories, 
publishedTitle;
 
                $publishArea = $( '.cx-header__publish' );
                $publishButton = $publishArea.find( 
'.cx-header__publish-button' );
@@ -118,57 +143,65 @@
                        $( '.cx-column--translation .cx-column__content' 
).clone()
                );
 
-               $publishButton
-                       .prop( 'disabled', true )
-                       .text( mw.msg( 'cx-publish-button-publishing' ) );
+               publishedTitle = 'User:' + mw.user.getName() + '/' + 
targetTitle;
 
-               targetCategories = mw.cx.categoryTool.categories.target;
-               sortedKeys = Object.keys( targetCategories ).sort();
-               categoryTitles = [];
-               for ( i = 0; i < sortedKeys.length; i++ ) {
-                       categoryTitles.push( targetCategories[ sortedKeys[ i ] 
] );
-               }
-               categories = categoryTitles.join( '|' );
+               checkTargetTitle( publishedTitle )
+                       .done( function ( titleExists ) {
+                               if ( titleExists === false || publishAnyway === 
true ) {
+                                       $publishButton
+                                               .prop( 'disabled', true )
+                                               .text( mw.msg( 
'cx-publish-button-publishing' ) );
 
-               publisher = new CXPublish( $publishArea );
-               publisher.publish( {
-                       from: mw.cx.sourceLanguage,
-                       to: mw.cx.targetLanguage,
-                       sourcetitle: mw.cx.sourceTitle,
-                       title: targetTitle,
-                       html: translatedContent,
-                       status: 'published',
-                       sourcerevision: mw.cx.sourceRevision,
-                       categories: categories,
-                       progress: JSON.stringify( mw.cx.getProgress() )
-               } ).done( function () {
-                       var publishedTitle = 'User:' + mw.user.getName() + '/' 
+ targetTitle;
-                       mw.hook( 'mw.cx.success' ).fire( mw.message( 
'cx-publish-page-success',
-                               $( '<a>' ).attr( {
-                                       href: mw.util.getUrl( publishedTitle ),
-                                       target: '_blank'
-                               } ).text( publishedTitle )[ 0 ].outerHTML
-                       ) );
-                       mw.hook( 'mw.cx.translation.published' ).fire(
-                               mw.cx.sourceLanguage,
-                               mw.cx.targetLanguage
-                       );
-               } ).fail( function ( code, details ) {
-                       var trace = {
-                               sourceLanguage: mw.cx.sourceLanguage,
-                               targetLanguage: mw.cx.targetLanguage,
-                               sourceTitle: mw.cx.sourceTitle,
-                               sourceRevision: mw.cx.sourceRevision,
-                               targetTitle: targetTitle,
-                               error: details
-                       };
-                       mw.hook( 'mw.cx.error' ).fire( mw.msg( 
'cx-publish-page-error' ) );
-                       mw.log( '[CX] Error while publishing:', code, trace );
-               } ).always( function () {
-                       $publishButton
-                               .prop( 'disabled', true )
-                               .text( mw.msg( 'cx-publish-button' ) );
-               } );
+                                       targetCategories = 
mw.cx.categoryTool.categories.target;
+                                       sortedKeys = Object.keys( 
targetCategories ).sort();
+                                       categoryTitles = [];
+                                       for ( i = 0; i < sortedKeys.length; i++ 
) {
+                                               categoryTitles.push( 
targetCategories[ sortedKeys[ i ] ] );
+                                       }
+                                       categories = categoryTitles.join( '|' );
+
+                                       publisher = new CXPublish( $publishArea 
);
+                                       publisher.publish( {
+                                               from: mw.cx.sourceLanguage,
+                                               to: mw.cx.targetLanguage,
+                                               sourcetitle: mw.cx.sourceTitle,
+                                               title: targetTitle,
+                                               html: translatedContent,
+                                               status: 'published',
+                                               sourcerevision: 
mw.cx.sourceRevision,
+                                               categories: categories,
+                                               progress: JSON.stringify( 
mw.cx.getProgress() )
+                                       } ).done( function () {
+                                               mw.hook( 'mw.cx.success' 
).fire( mw.message( 'cx-publish-page-success',
+                                                       $( '<a>' ).attr( {
+                                                               href: 
mw.util.getUrl( publishedTitle ),
+                                                               target: '_blank'
+                                                       } ).text( 
publishedTitle )[ 0 ].outerHTML
+                                               ) );
+                                               mw.hook( 
'mw.cx.translation.published' ).fire(
+                                                       mw.cx.sourceLanguage,
+                                                       mw.cx.targetLanguage
+                                               );
+                                       } ).fail( function ( code, details ) {
+                                               var trace = {
+                                                       sourceLanguage: 
mw.cx.sourceLanguage,
+                                                       targetLanguage: 
mw.cx.targetLanguage,
+                                                       sourceTitle: 
mw.cx.sourceTitle,
+                                                       sourceRevision: 
mw.cx.sourceRevision,
+                                                       targetTitle: 
targetTitle,
+                                                       error: details
+                                               };
+                                               mw.hook( 'mw.cx.error' ).fire( 
mw.msg( 'cx-publish-page-error' ) );
+                                               mw.log( '[CX] Error while 
publishing:', code, trace );
+                                       } ).always( function () {
+                                               $publishButton
+                                                       .prop( 'disabled', true 
)
+                                                       .text( mw.msg( 
'cx-publish-button' ) );
+                                       } );
+                               } else {
+                                       $publishButton.cxPublishingDialog();
+                               }
+                       } );
 
                initGuidedTour( translatedTitle );
        }
diff --git a/modules/publish/images/clear.png b/modules/publish/images/clear.png
new file mode 100644
index 0000000..f900e7d
--- /dev/null
+++ b/modules/publish/images/clear.png
Binary files differ
diff --git a/modules/publish/images/clear.svg b/modules/publish/images/clear.svg
new file mode 100755
index 0000000..8cb15e3
--- /dev/null
+++ b/modules/publish/images/clear.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg"; 
width="12.52" height="12.52"><path fill="#555" d="M0 1.194l1.194-1.194 11.326 
11.326-1.194 1.194zM11.326 0l1.194 1.194-11.326 11.326-1.194-1.194z"/></svg>
\ No newline at end of file
diff --git a/modules/publish/styles/ext.cx.publish.dialog.less 
b/modules/publish/styles/ext.cx.publish.dialog.less
new file mode 100644
index 0000000..b0b7423
--- /dev/null
+++ b/modules/publish/styles/ext.cx.publish.dialog.less
@@ -0,0 +1,60 @@
+@import "../../base/styles/grid/agora-grid";
+@import "mediawiki.mixins";
+
+.cx-publishing-dialog {
+       .mw-ui-item;
+       color: #333;
+       position: absolute;
+       width: 400px;
+       background: white;
+       border: 1px solid #ccc;
+       border-bottom-width: 3px;
+       border-radius: 3px;
+       padding: 5px;
+       padding-bottom: 10px;
+       box-shadow: 0 5px 10px rgba(0,0,0,0.2);
+
+       .cx-publishing-dialog__close {
+               float: right;
+               .background-image-svg('../images/clear.svg', 
'../images/clear.png');
+               background-repeat: no-repeat;
+               background-color: #FFFFFF;
+               background-position: 10px center;
+               background-size: 15px;
+               width: 30px;
+               height: 30px;
+               cursor: pointer;
+       }
+
+       .cx-publishing-dialog__message {
+               font-size: medium;
+               margin: 0;
+               margin-right: 30px;
+               margin-bottom: 10px;
+               padding: 5px;
+
+               a {
+                       text-decoration: none;
+               }
+       }
+
+       .cx-publishing-dialog__buttons {
+               clear: both;
+
+               button {
+                       float: right;
+                       margin-right: 5px;
+               }
+       }
+}
+
+.cx-publishing-dialog::before {
+       content: "";
+       width: 0px;
+       height: 0px;
+       border: 0.8em solid transparent;
+       position: absolute;
+       left: 45%;
+       top: -20px;
+       border-bottom: 10px solid white;
+}

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I35b7a041cd9b2e2fefd8e9e271619a37e9a63e35
Gerrit-PatchSet: 24
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Jsahleen <[email protected]>
Gerrit-Reviewer: Amire80 <[email protected]>
Gerrit-Reviewer: Jsahleen <[email protected]>
Gerrit-Reviewer: Nikerabbit <[email protected]>
Gerrit-Reviewer: Pginer <[email protected]>
Gerrit-Reviewer: Santhosh <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to