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