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