Santhosh has uploaded a new change for review. https://gerrit.wikimedia.org/r/192786
Change subject: Publish module refactoring for title collision ...................................................................... Publish module refactoring for title collision Better module restructuring for publishing error handling and title validations Bug: T85138 Change-Id: I95b904d9ab2f7ca882c32e91b2441d7cc5e796ab --- M modules/publish/ext.cx.publish.dialog.js M modules/publish/ext.cx.publish.js 2 files changed, 191 insertions(+), 158 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation refs/changes/86/192786/1 diff --git a/modules/publish/ext.cx.publish.dialog.js b/modules/publish/ext.cx.publish.dialog.js index 6860adc..20ff9b7 100644 --- a/modules/publish/ext.cx.publish.dialog.js +++ b/modules/publish/ext.cx.publish.dialog.js @@ -21,22 +21,18 @@ this.$dialog = null; this.$close = null; this.$message = null; + this.$publishButton = null; + this.$keepButton = 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.render( title ); this.position(); this.show(); }; @@ -46,8 +42,7 @@ * @param {string} title The title of the existing article */ CXPublishingDialog.prototype.render = function ( title ) { - var $buttons, $keepButton, $publishAnywayButton, username, namespace, - cxPublishingDialog = this; + var $buttons, username, namespace; username = mw.user.getName(); namespace = mw.config.get( 'wgContentTranslationTargetNamespace' ); @@ -57,49 +52,33 @@ .hide(); this.$close = $( '<div>' ) - .addClass( 'cx-publishing-dialog__close' ) - .on( 'click', function () { - cxPublishingDialog.$dialog.hide(); - } ); + .addClass( 'cx-publishing-dialog__close' ); this.$message = $( '<p>' ) .addClass( 'cx-publishing-dialog__message' ); - $( '.cx-publishing-dialog__message > a' ).prop( 'target', '_blank' ); + this.$dialog.find( '.cx-publishing-dialog__message > a' ).prop( 'target', '_blank' ); $buttons = $( '<div>' ) .addClass( 'cx-publishing-dialog__buttons' ); - $keepButton = $( '<button>' ) + this.$keepButton = $( '<button>' ) .addClass( 'cx-publishing-dialog__buttons-keep mw-ui-button mw-ui-quiet' ); if ( namespace === 'User' ) { - $keepButton.text( mw.msg( 'cx-publishing-dialog-keep-button' ) ); + this.$keepButton.text( mw.msg( 'cx-publishing-dialog-keep-button' ) ); } else { - $keepButton.text( mw.msg( 'cx-publishing-dialog-publish-draft-button' ) ); + this.$keepButton.text( mw.msg( 'cx-publishing-dialog-publish-draft-button' ) ); } - $keepButton.on( 'click', function () { - cxPublishingDialog.$dialog.hide(); - mw.hook( 'mw.cx.publish' ).fire( false ); - } ); - - $publishAnywayButton = $( '<button>' ) + this.$publishButton = $( '<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 ); - } ); + .text( mw.msg( 'cx-publishing-dialog-publish-anyway-button' ) ); this.setMessage( title ); - - $buttons.append( $publishAnywayButton, $keepButton ); - + $buttons.append( this.$publishButton, this.$keepButton ); this.$dialog.append( this.$close, this.$message, $buttons ); - $( 'body' ).append( this.$dialog ); - }; /** @@ -129,10 +108,7 @@ 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; - + dialogTop = $( window ).scrollTop() + buttonPosition.top + this.$trigger.height() + 20; this.$dialog.css( { top: dialogTop, left: dialogLeft, @@ -142,11 +118,28 @@ }; /** - * A listener that adjust the positioning when the page is scrolled - * Necessary because the publishing button moves to the left on window scroll + * Listen for events + * @return {jQuery.Promise} */ CXPublishingDialog.prototype.listen = function () { + var deferred = $.Deferred(), + self = this; + $( window ).on( 'scroll', $.proxy( this.position, this ) ); + this.$keepButton.on( 'click', function () { + deferred.resolve( false ); + self.$dialog.remove(); + } ); + this.$publishButton.on( 'click', function () { + deferred.resolve( true ); + self.$dialog.remove(); + } ); + this.$close.on( 'click', function () { + deferred.reject(); + self.$dialog.remove(); + } ); + + return deferred.promise(); }; /** @@ -161,16 +154,8 @@ */ $.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(); - + var $this = $( this ); + $this.data( 'cxPublishingDialog', new CXPublishingDialog( this ) ); } ); }; } )( jQuery, mediaWiki ); diff --git a/modules/publish/ext.cx.publish.js b/modules/publish/ext.cx.publish.js index c6a6c75..be4918e 100644 --- a/modules/publish/ext.cx.publish.js +++ b/modules/publish/ext.cx.publish.js @@ -16,6 +16,7 @@ */ function CXPublish( $trigger ) { this.$trigger = $trigger; + this.targetTitle = null; } /** @@ -26,28 +27,49 @@ var apiParams, self = this; + this.targetTitle = $( '.cx-column--translation > h2' ).text(); apiParams = $.extend( {}, params, { - action: 'cxpublish' + action: 'cxpublish', + from: mw.cx.sourceLanguage, + to: mw.cx.targetLanguage, + sourcetitle: mw.cx.sourceTitle, + html: self.getContent(), + status: 'published', + sourcerevision: mw.cx.sourceRevision, + categories: this.getCategories(), + progress: JSON.stringify( mw.cx.getProgress() ) } ); - return new mw.Api().postWithToken( 'edit', apiParams, { - // A bigger timeout since publishing after converting html to wikitext - // parsoid is not a fast operation. - timeout: 100 * 1000 // in milliseconds - } ).then( function ( response ) { - if ( response.cxpublish.result === 'success' ) { - return; - } + // Disable the trigger button + this.$trigger.prop( 'disabled', true ).text( mw.msg( 'cx-publish-button-publishing' ) ); - if ( response.cxpublish.edit.captcha ) { - return self.captchaHandler( response.cxpublish.edit.captcha ) - .then( function ( captchaResult ) { - return self.publish( $.extend( params, captchaResult ) ); - } ); - } + this.checkTargetTitle( this.targetTitle ).then( function ( title ) { + apiParams.title = self.targetTitle = title; - // If it's a different error, log it - mw.log( '[CX] Unexpected error while publishing: ', response.cxpublish ); + new mw.Api().postWithToken( 'edit', apiParams, { + // A bigger timeout since publishing after converting html to wikitext + // parsoid is not a fast operation. + timeout: 100 * 1000 // in milliseconds + } ).done( function ( response ) { + if ( response.cxpublish.result === 'success' ) { + self.success(); + return; + } + + if ( response.cxpublish.edit.captcha ) { + return self.captchaHandler( response.cxpublish.edit.captcha ) + .then( function ( captchaResult ) { + return self.publish( $.extend( params, captchaResult ) ); + } ); + } + + // If it's a different error, log it + mw.log( '[CX] Unexpected error while publishing: ', response.cxpublish ); + } ).fail( function ( code, details ) { + self.fail( code, details ); + } ).always( function () { + self.$trigger.prop( 'disabled', true ).text( mw.msg( 'cx-publish-button' ) ); + } ); } ); }; @@ -108,8 +130,9 @@ /** * Checks to see if there is already a published article with the title * @param {string} title The title to check + * @return {jQuery.promise} */ - function checkTargetTitle( title ) { + function getTitle( title ) { var api, $deferred = $.Deferred(); @@ -131,8 +154,59 @@ } /** + * Generate an alternate title in case of title collision + * @param {string} title The title + * @return {string} + */ + function getAlternateTitle( title ) { + var username = mw.user.getName(); + + if ( new mw.Title( title ).getNamespaceId() === 2 ) { + return increaseVersion( title ); + } else { + return 'User:' + username + '/' + title; + } + } + + /** + * Checks to see if there is already a published article with the title + * @param {string} title The title to check + * @return {jQuery.promise} + */ + CXPublish.prototype.checkTargetTitle = function ( title ) { + var deferred = $.Deferred(), + self = this; + + title = mw.cx.SiteMapper.prototype.getTargetTitle( title ); + + getTitle( title ).done( function ( titleExists ) { + var $dialog; + + if ( titleExists ) { + // Show a dialog to decide what to do now + self.$trigger.cxPublishingDialog(); + $dialog = self.$trigger.data( 'cxPublishingDialog' ); + $dialog.listen().done( function ( overwrite ) { + if ( !overwrite ) { + title = getAlternateTitle( title ); + } + + deferred.resolve( title ); + } ).fail( function () { + deferred.reject(); + } ); + } else { + deferred.resolve( title ); + } + } ); + + return deferred.promise(); + }; + + /** * Increase the version number of a title starting with 1. * @param {string} title The title to increase the version on. + * @return {string} */ function increaseVersion( title ) { var match, version; @@ -148,110 +222,79 @@ } /** - * Publish the translation - * @param {boolean} overwrite Flag to overwrite translation - * @param {string} title [optional], Optional title for the translation + * Get categories for the current translation pair + * @return {string} Category titles with '|' delimiter */ - function publish( overwrite, title ) { - var $publishArea, $publishButton, publisher, - translatedContent, targetCategories, targetTitle, - sortedKeys, i, categoryTitles, categories, publishedTitle; + CXPublish.prototype.getCategories = function () { + var i, categories, sortedKeys, categoryTitles, targetCategories; - $publishArea = $( '.cx-header__publish' ); - $publishButton = $publishArea.find( '.cx-header__publish-button' ); - targetTitle = title || $( '.cx-column--translation > h2' ).text(); - translatedContent = prepareTranslationForPublish( + 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( '|' ); + return categories; + }; + + /** + * Get the current translation content + * @return {string} + */ + CXPublish.prototype.getContent = function () { + return this.prepareTranslationForPublish( $( '.cx-column--translation .cx-column__content' ).clone() ); + }; - publishedTitle = mw.cx.SiteMapper.prototype.getTargetTitle( targetTitle ); + /** + * Success handler for publishing + */ + CXPublish.prototype.success = function () { + $( '.cx-column--translation > h2' ) + .text( this.targetTitle ) + .keepAlignment(); + mw.hook( 'mw.cx.success' ) + .fire( mw.message( 'cx-publish-page-success', + $( '<a>' ).attr( { + href: mw.util.getUrl( this.targetTitle ), + target: '_blank' + } ).text( this.targetTitle )[ 0 ].outerHTML + ) ); + mw.hook( 'mw.cx.translation.published' ).fire( + mw.cx.sourceLanguage, + mw.cx.targetLanguage, + this.targetTitle + ); + mw.cx.dirty = false; + }; - checkTargetTitle( publishedTitle ) - .done( function ( titleExists ) { - var username; - - username = mw.user.getName(); - - if ( titleExists === false || overwrite === true ) { - $publishButton - .prop( 'disabled', true ) - .text( mw.msg( 'cx-publish-button-publishing' ) ); - - 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 () { - $( '.cx-column--translation > h2' ) - .text( publishedTitle ) - .keepAlignment(); - 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, - targetTitle - ); - mw.cx.dirty = false; - } ).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 if ( overwrite === false ) { - if ( new mw.Title( publishedTitle ).getNamespaceId() === 2 ) { - publishedTitle = increaseVersion( publishedTitle ); - } else { - publishedTitle = 'User:' + username + '/' + publishedTitle; - } - publish( false, publishedTitle ); - } else { - $publishButton.cxPublishingDialog(); - } - } ); - } + /** + * Failure handler for publishing + */ + CXPublish.prototype.fail = function ( code, details ) { + var trace = { + sourceLanguage: mw.cx.sourceLanguage, + targetLanguage: mw.cx.targetLanguage, + sourceTitle: mw.cx.sourceTitle, + sourceRevision: mw.cx.sourceRevision, + targetTitle: this.targetTitle, + error: details + }; + mw.hook( 'mw.cx.error' ).fire( mw.msg( 'cx-publish-page-error' ) ); + mw.log( '[CX] Error while publishing:', code, trace ); + }; /** * Prepare the translated content for publishing by removing * unwanted parts. * @return {string} processed html */ - function prepareTranslationForPublish( $content ) { + CXPublish.prototype.prepareTranslationForPublish = function ( $content ) { $content.find( '.cx-segment' ).replaceWith( function () { return $( this ).html(); } ); - // TODO: This clean up should be done even before segmentation at server. $content.find( 'link, title' ).remove(); // Remove placeholder sections @@ -266,12 +309,17 @@ } ); return $content.html(); - } + }; // Expose the CXPublish mw.cx.publish = CXPublish; $( function () { - mw.hook( 'mw.cx.publish' ).add( $.proxy( publish, this ) ); + var cxPublish, $publishButton; + + $publishButton = $( '.cx-header__publish .cx-header__publish-button' ); + cxPublish = new mw.cx.publish( $publishButton ); + + mw.hook( 'mw.cx.publish' ).add( $.proxy( cxPublish.publish, cxPublish ) ); } ); }( jQuery, mediaWiki ) ); -- To view, visit https://gerrit.wikimedia.org/r/192786 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I95b904d9ab2f7ca882c32e91b2441d7cc5e796ab 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