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

Change subject: Section editor enhancements, refactoring
......................................................................


Section editor enhancements, refactoring

* Create a class for the UX of section editor CXSectionEditor
* Refactor the MediumEditor binding to an editor enhancement
* If the user clear the translation in a section, present the placeholder
* Define custom event mw.cx.translation.clear for the above mentioned case
* Refactor the placeholder construction code for the above purpose
* For Figures, make the figcaption alone editable, prevent return key press
  in figcaption.
* Avoid previews on mouse over of links

Change-Id: I960c8530055a3fc69cdcf3a30090a1179e4a5709
---
M modules/editor/ext.cx.editor.js
M modules/translation/ext.cx.translation.js
2 files changed, 128 insertions(+), 30 deletions(-)

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



diff --git a/modules/editor/ext.cx.editor.js b/modules/editor/ext.cx.editor.js
index 189e882..36b484e 100644
--- a/modules/editor/ext.cx.editor.js
+++ b/modules/editor/ext.cx.editor.js
@@ -9,20 +9,102 @@
  * @license GPL-2.0+
  */
 /* global MediumEditor: true */
-( function ( $ ) {
+( function ( $, mw ) {
        'use strict';
 
-       var editorOptions = {
-               cleanPastedHTML: true,
-               buttons: [ 'bold', 'italic', 'header1', 'header2', 
'unorderedlist', 'orderedlist', 'indent', 'outdent' ],
-               firstHeader: 'h2',
-               secondHeader: 'h3'
+       var delay = ( function () {
+               var timer = 0;
+
+               return function ( callback, milliseconds ) {
+                       clearTimeout( timer );
+                       timer = setTimeout( callback, milliseconds );
+               };
+       }() );
+
+       /**
+        * CXSectionEditor - Editor for each sections in the translation
+        *
+        * @class
+        */
+       function CXSectionEditor( element ) {
+               this.$element = $( element );
+               this.$editableElement = this.$element;
+               this.init();
+               this.listen();
+       }
+
+       /**
+        * Initialize the editor
+        */
+       CXSectionEditor.prototype.init = function () {
+               if ( this.$element.get( 0 ).tagName === 'FIGURE' ) {
+                       // Inside figure allow editing of caption alone
+                       this.$editableElement = this.$element.find( 
'figcaption' );
+               }
+               // Make the element editable
+               this.$editableElement.attr( 'contenteditable', true );
+               // Initialize a WYSIWYG editor
+               this.wysiwygEditor();
+       };
+
+       /**
+        * Listen for changes in the section
+        */
+       CXSectionEditor.prototype.listen = function () {
+               var cxEditor = this;
+
+               this.$editableElement.on( 'input', function () {
+                       // Delay the emptiness check till user pause typing.
+                       // If this check was done every input, the 
responsiveness
+                       // will get affected.
+                       delay( function () {
+                               if ( cxEditor.$editableElement.text().trim() 
=== '' ) {
+                                       // Emit 'mw.cx.translation.clear' event
+                                       mw.hook( 'mw.cx.translation.clear' 
).fire(
+                                               cxEditor.$element.data( 
'source' )
+                                       );
+                               }
+                       }, 300 );
+               } );
+       };
+
+       /**
+        * Enhance the basic content editable with a WYSIWYG editor
+        * MediumEditor is used here. But any such simple editor
+        * can work here.
+        */
+       CXSectionEditor.prototype.wysiwygEditor = function () {
+               var editorOptions;
+
+               editorOptions = {
+                       cleanPastedHTML: true,
+                       buttons: [ 'bold', 'italic', 'header1', 'header2',
+                               'unorderedlist', 'orderedlist', 'indent', 
'outdent' ],
+                       firstHeader: 'h2',
+                       secondHeader: 'h3',
+                       disableDoubleReturn: true
+               };
+               // Avoid previews on mouse over of links
+               MediumEditor.prototype.editorAnchorObserver = function () {};
+
+               if ( this.$editableElement.get( 0 ).tagName === 'FIGURECAPTION' 
) {
+                       // Prevent pressing return on caption to avoid
+                       // creation of <p> nodes
+                       editorOptions.disableReturn = true;
+               }
+
+               /*jshint -W031 */
+               new MediumEditor( this.$editableElement, editorOptions );
        };
 
        $.fn.cxEditor = function () {
-               /*jshint -W031 */
-               new MediumEditor( this, editorOptions );
-               return this;
+               return this.each( function () {
+                       var $this = $( this ),
+                               data = $this.data( 'cxSectionEditor' );
+                       if ( !data ) {
+                               $this.data( 'cxSectionEditor', ( data = new 
CXSectionEditor( this ) ) );
+                       }
+               } );
        };
 
-}( jQuery ) );
+}( jQuery, mediaWiki ) );
diff --git a/modules/translation/ext.cx.translation.js 
b/modules/translation/ext.cx.translation.js
index afb9a3c..d0517a3 100644
--- a/modules/translation/ext.cx.translation.js
+++ b/modules/translation/ext.cx.translation.js
@@ -90,6 +90,14 @@
                                cxTranslation.addPlaceholders();
                        }, 2000 );
                } );
+               // Tanslation for a section was cleared. Either the translator
+               // deleted the content, or translator used the clear translation
+               // tool. Present the placeholder for the section to user.
+               mw.hook( 'mw.cx.translation.clear' ).add( function ( sourceId ) 
{
+                       var targetSectionId, $placeholder = getPlaceholder( 
sourceId );
+                       targetSectionId = jquerySelectorForId( sourceId, 'cx' );
+                       $( targetSectionId ).replaceWith( $placeholder );
+               } );
        };
 
        /**
@@ -107,7 +115,6 @@
                        .clone()
                        .attr( {
                                'id': 'cx' + sourceId,
-                               'contenteditable': true,
                                'data-source': sourceId
                        } )
                );
@@ -268,25 +275,7 @@
                        template = false;
                        $sourceSection = $( $sourceSections[ i ] );
                        sourceSectionId = $sourceSection.attr( 'id' );
-                       $placeholder = $( '<div>' )
-                               .addClass( 'placeholder' )
-                               .hover( sectionMouseEnterHandler, 
sectionMouseLeaveHandler )
-                               .on( 'click', sectionClick )
-                               .attr( {
-                                       'id': 'cx' + sourceSectionId,
-                                       'data-source': sourceSectionId,
-                               } ).css( {
-                                       // Copy a bunch of position related 
attribute values
-                                       'min-height': 
$sourceSection.outerHeight(),
-                                       'width': $sourceSection.width(),
-                                       'margin-top': $sourceSection.css( 
'margin-top' ),
-                                       'margin-bottom': $sourceSection.css( 
'margin-bottom' ),
-                                       'display': $sourceSection.css( 
'display' ),
-                                       'float': $sourceSection.css( 'float' ),
-                                       'clear': $sourceSection.css( 'clear' ),
-                                       'position': $sourceSection.css( 
'position' )
-                               } );
-
+                       $placeholder = getPlaceholder( sourceSectionId );
                        // Bind events to the placeholder sections
                        $sourceSection.click( sourceSectionClickHandler )
                                .hover( sourceSectionMouseEnterHandler, 
sourceSectionMouseLeaveHandler );
@@ -297,6 +286,33 @@
        };
 
        /**
+        * Get a placeholder div for the given source section
+        * @param {string} sourceSectionId
+        * @return {jQuery} The placeholder jQuery object
+        */
+       function getPlaceholder( sourceSectionId ) {
+               var $sourceSection = $( '#' + sourceSectionId );
+               return $( '<div>' )
+                       .addClass( 'placeholder' )
+                       .hover( sectionMouseEnterHandler, 
sectionMouseLeaveHandler )
+                       .on( 'click', sectionClick )
+                       .attr( {
+                               'id': 'cx' + sourceSectionId,
+                               'data-source': sourceSectionId,
+                       } ).css( {
+                               // Copy a bunch of position related attribute 
values
+                               'min-height': $sourceSection.outerHeight(),
+                               'width': $sourceSection.width(),
+                               'margin-top': $sourceSection.css( 'margin-top' 
),
+                               'margin-bottom': $sourceSection.css( 
'margin-bottom' ),
+                               'display': $sourceSection.css( 'display' ),
+                               'float': $sourceSection.css( 'float' ),
+                               'clear': $sourceSection.css( 'clear' ),
+                               'position': $sourceSection.css( 'position' )
+                       } );
+       }
+
+       /**
         * Keep the height of the source and translation sections equal
         * so that they will appear top aligned.
         */

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

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

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

Reply via email to