jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/371550 )

Change subject: Placeholder styling and fixes
......................................................................


Placeholder styling and fixes

Change-Id: I8f3063c75111562f2e77c9a716b13b15c6694402
---
M extension.json
M modules/ui/mw.cx.ui.TranslationView.js
M modules/ui/styles/mw.cx.ui.TargetColumn.less
A modules/ve-cx/ce/styles/ve.ce.CXPlaceholderNode.css
M modules/ve-cx/ce/ve.ce.CXPlaceholderNode.js
A modules/ve-cx/ui/ve.ui.CXTranslation.js
6 files changed, 194 insertions(+), 14 deletions(-)

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



diff --git a/extension.json b/extension.json
index e11087a..e1dc515 100644
--- a/extension.json
+++ b/extension.json
@@ -1305,6 +1305,7 @@
                                "ve-cx/ui/ve.ui.CXTargetSurface.js"
                        ],
                        "styles": [
+                               "ve-cx/ce/styles/ve.ce.CXPlaceholderNode.css",
                                "ve-cx/ui/styles/ve.ui.CXSurface.css"
                        ],
                        "messages": [
diff --git a/modules/ui/mw.cx.ui.TranslationView.js 
b/modules/ui/mw.cx.ui.TranslationView.js
index 1c5e352..59e04c0 100644
--- a/modules/ui/mw.cx.ui.TranslationView.js
+++ b/modules/ui/mw.cx.ui.TranslationView.js
@@ -56,6 +56,7 @@
                this.alignSectionPairs.bind( this ),
                500
        );
+       $( this.getElementWindow() ).on( 'resize', 
this.throttleAlignSectionPairs );
        this.targetColumn.connect( this, {
                titleChange: 'onTargetTitleChange'
        } );
@@ -85,12 +86,15 @@
        if ( !sourceNode || !targetNode ) {
                return;
        }
+       sourceNode.style.marginTop = '';
+       targetNode.style.marginTop = '';
+       targetNode.style.height = '';
        offsetTop = Math.max(
                sourceOffsetTop + sourceNode.offsetTop,
                targetOffsetTop + targetNode.offsetTop
        );
-       sourceNode.style.paddingTop = ( offsetTop - sourceOffsetTop - 
sourceNode.offsetTop ) + 'px';
-       targetNode.style.paddingTop = ( offsetTop - targetOffsetTop - 
targetNode.offsetTop ) + 'px';
+       sourceNode.style.marginTop = ( offsetTop - sourceOffsetTop - 
sourceNode.offsetTop ) + 'px';
+       targetNode.style.marginTop = ( offsetTop - targetOffsetTop - 
targetNode.offsetTop ) + 'px';
        if ( isSubclass( $.data( targetNode, 'view' ), ve.ce.CXPlaceholderNode 
) ) {
                if ( sourceNode.offsetHeight > targetNode.offsetHeight ) {
                        targetNode.style.height = sourceNode.offsetHeight + 
'px';
@@ -125,6 +129,13 @@
        this.header.$toolbar.prepend( this.publishSettings.$element, 
this.publishButton.$element );
 };
 
+mw.cx.ui.TranslationView.prototype.unbindHandlers = function () {
+       // Parent method
+       mw.cx.ui.TranslationView.super.prototype.unbindHandlers.call( this );
+
+       $( this.getElementWindow() ).off( 'resize', 
this.throttleAlignSectionPairs );
+};
+
 mw.cx.ui.TranslationView.prototype.onSurfaceMouseOver = function ( ev ) {
        var fromSegmentId = $( ev.relatedTarget ).closest( '.cx-segment' 
).data( 'segmentid' ),
                toSegmentId = $( ev.toElement ).closest( '.cx-segment' ).data( 
'segmentid' );
diff --git a/modules/ui/styles/mw.cx.ui.TargetColumn.less 
b/modules/ui/styles/mw.cx.ui.TargetColumn.less
index c3ba4d2..a94b3c0 100644
--- a/modules/ui/styles/mw.cx.ui.TargetColumn.less
+++ b/modules/ui/styles/mw.cx.ui.TargetColumn.less
@@ -2,10 +2,6 @@
 @import '../../widgets/common/ext.cx.highlight.less';
 
 .cx-column--translation {
-       [contenteditable] {
-               outline: 0;
-       }
-
        .cx-column-target-title {
                padding: 0;
                padding-top: 0.5em;
diff --git a/modules/ve-cx/ce/styles/ve.ce.CXPlaceholderNode.css 
b/modules/ve-cx/ce/styles/ve.ce.CXPlaceholderNode.css
new file mode 100644
index 0000000..5a0ebfd
--- /dev/null
+++ b/modules/ve-cx/ce/styles/ve.ce.CXPlaceholderNode.css
@@ -0,0 +1,27 @@
+/* Copied from ve-ce-branchNode-blockSlug */
+.ve-ce-cxPlaceholderNode {
+       opacity: 0;
+       cursor: pointer;
+       -webkit-transition: opacity 200ms ease-out;
+       -moz-transition: opacity 200ms ease-out;
+       transition: opacity 200ms ease-out;
+
+       outline: 1px dashed #ccc;
+       /* rgba( #f1f7fb, 0.75 ) */
+       background-color: rgba( 241, 247, 251, 0.75 );
+}
+
+.ve-ce-cxPlaceholderNode:hover,
+.ve-ce-cxPlaceholderNode.ve-ce-focusableNode-focused {
+       opacity: 1;
+}
+
+.ve-ce-cxPlaceholderNode > .oo-ui-buttonWidget {
+       margin-left: 0.25em;
+       opacity: 0.5;
+       display: block;
+}
+
+.ve-ce-cxPlaceholderNode > .oo-ui-buttonWidget > .oo-ui-buttonElement-button {
+       display: block;
+}
diff --git a/modules/ve-cx/ce/ve.ce.CXPlaceholderNode.js 
b/modules/ve-cx/ce/ve.ce.CXPlaceholderNode.js
index 44f863a..88de981 100644
--- a/modules/ve-cx/ce/ve.ce.CXPlaceholderNode.js
+++ b/modules/ve-cx/ce/ve.ce.CXPlaceholderNode.js
@@ -5,16 +5,24 @@
  * @extends ve.ce.LeafNode
  * @mixins ve.ce.FocusableNode
  * @constructor
- * @param {ve.dm.CXPlaceholderNode} model
  */
-ve.ce.CXPlaceholderNode = function VeCeCXPlaceholderNode( model ) {
+ve.ce.CXPlaceholderNode = function VeCeCXPlaceholderNode() {
+       var button;
+
        // Parent constructor
        ve.ce.CXPlaceholderNode.super.apply( this, arguments );
        ve.ce.FocusableNode.call( this );
-       this.$element.addClass( 've-ce-cxPlaceholderNode' );
-       this.$element.append(
-               $( '<p>' ).text( 'Placeholder ' + model.element.attributes.cxid 
)
-       );
+
+       button = new ve.ui.NoFocusButtonWidget( {
+               label: ve.msg( 'cx-translation-add-translation' ),
+               icon: 'add',
+               framed: false
+       } );
+       button.on( 'click', this.onFocusableMouseDown.bind( this ) );
+
+       this.$element
+               .addClass( 've-ce-cxPlaceholderNode' )
+               .append( button.$element );
        this.active = false;
 };
 
@@ -31,14 +39,21 @@
 
 /* Methods */
 
-ve.ce.CXPlaceholderNode.prototype.onFocusableMouseDown = function () {
-       if ( this.active ) {
+ve.ce.CXPlaceholderNode.prototype.onFocusableMouseDown = function ( e ) {
+       if ( this.active || ( e && e.which !== OO.ui.MouseButtons.LEFT ) ) {
                return;
        }
+       this.executeCommand();
+};
+
+ve.ce.CXPlaceholderNode.prototype.executeCommand = function () {
        this.active = true;
        this.getDocument().emit( 'activatePlaceholder', this );
 };
 
+ve.ce.CXPlaceholderNode.prototype.createHighlights = function () {
+};
+
 /* Registration */
 
 ve.ce.nodeFactory.register( ve.ce.CXPlaceholderNode );
diff --git a/modules/ve-cx/ui/ve.ui.CXTranslation.js 
b/modules/ve-cx/ui/ve.ui.CXTranslation.js
new file mode 100644
index 0000000..987d222
--- /dev/null
+++ b/modules/ve-cx/ui/ve.ui.CXTranslation.js
@@ -0,0 +1,130 @@
+/**
+ * @class
+ *
+ * @constructor
+ * @param {HTMLNode} $sourceCol The column for displaying the source document
+ * @param {HTMLNode} $targetCol The column for displaying the target surface
+ */
+ve.ui.CXTranslation = function VeUiCXTranslation( $sourceCol, $targetCol ) {
+       this.$sourceCol = $sourceCol;
+       this.$targetCol = $targetCol;
+       this.throttleAlignSectionPairs = OO.ui.throttle(
+               this.alignSectionPairs.bind( this ),
+               500
+       );
+};
+
+/* Inheritance */
+
+OO.initClass( ve.ui.CXTranslation );
+
+/* Static methods */
+
+ve.ui.CXTranslation.static.isSegmentNode = function ( node ) {
+       return node.tagName.toLowerCase() === 'span' && 
node.classList.contains( 'cx-segment' );
+};
+
+ve.ui.CXTranslation.static.alignSectionPair = function ( sectionId ) {
+       var offsetTop,
+               sourceNode = document.getElementById( sectionId ),
+               targetNode = document.getElementById( 'cx' + sectionId );
+
+       if ( !sourceNode || !targetNode ) {
+               return;
+       }
+       sourceNode.style.marginTop = '';
+       targetNode.style.marginTop = '';
+
+       offsetTop = Math.max( sourceNode.offsetTop, targetNode.offsetTop );
+       sourceNode.style.marginTop = ( offsetTop - sourceNode.offsetTop ) + 
'px';
+       targetNode.style.marginTop = ( offsetTop - targetNode.offsetTop ) + 
'px';
+};
+
+/* Methods */
+
+ve.ui.CXTranslation.prototype.alignSectionPairs = function () {
+       var alignSectionPair = this.constructor.static.alignSectionPair;
+
+       this.$sourceCol[ 0 ].childNodes.forEach( function ( node ) {
+               if ( node.id ) {
+                       alignSectionPair( node.id );
+               }
+       } );
+};
+
+ve.ui.CXTranslation.prototype.setSourceAndBuildTarget = function ( sourceHtml, 
targetHtml, config ) {
+       function restructure( doc ) {
+               var root, i, len, node, sectionNode;
+               // rewrite IDs
+               $( doc ).find( '[id]' ).each( function ( i, node ) {
+                       node.setAttribute( 'id', 'cx' + node.getAttribute( 'id' 
) );
+               } );
+               root = doc.body.firstChild;
+               for ( i = 0, len = root.childNodes.length; i < len; i++ ) {
+                       node = root.childNodes[ i ];
+                       if (
+                               node.nodeType !== Node.ELEMENT_NODE ||
+                               node.tagName.toLowerCase() === 'meta'
+                       ) {
+                               continue;
+                       }
+                       if ( node.getAttribute( 'typeof' ) === 
'mw:Transclusion' ) {
+                               // TODO: handle more systematically
+                               continue;
+                       }
+                       sectionNode = doc.createElement( 'section' );
+                       root.replaceChild( sectionNode, node );
+                       sectionNode.appendChild( node );
+               }
+               return doc;
+       }
+       this.$sourceCol.empty().html( sourceHtml );
+       this.targetSurface = new ve.ui.CXSurface(
+               ve.dm.converter.getModelFromDom(
+                       restructure( ve.createDocumentFromHtml( targetHtml ) ),
+                       {
+                               lang: $.i18n().locale,
+                               dir: $( 'body' ).css( 'direction' )
+                       }
+               ),
+               $.extend( { mode: 'visual' }, config )
+       );
+       this.targetSurface.model.documentModel.connect( this, {
+               transact: 'throttleAlignSectionPairs'
+       } );
+       this.$targetCol.append( this.targetSurface.$element );
+       this.setupHover();
+       return this.targetSurface;
+};
+
+ve.ui.CXTranslation.prototype.setupHover = function () {
+       var cxTranslation = this,
+               isSegmentNode = this.constructor.static.isSegmentNode;
+       this.targetSurface.getView().$element.on( 'mouseover', function ( ev ) {
+               var segmentId;
+               if ( !isSegmentNode( ev.target ) ) {
+                       return;
+               }
+               segmentId = ev.target.dataset.segmentid;
+               ev.target.classList.add( 'cx-highlight' );
+               cxTranslation.getSourceSentenceSegment( segmentId 
).classList.add( 'cx-highlight' );
+               cxTranslation.throttleAlignSectionPairs();
+       } );
+       this.targetSurface.getView().$element.on( 'mouseout', function ( ev ) {
+               var segmentId;
+               if ( !isSegmentNode( ev.target ) ) {
+                       return;
+               }
+               segmentId = ev.target.dataset.segmentid;
+               ev.target.classList.remove( 'cx-highlight' );
+               cxTranslation.getSourceSentenceSegment( segmentId 
).classList.remove( 'cx-highlight' );
+               cxTranslation.throttleAlignSectionPairs();
+       } );
+};
+
+ve.ui.CXTranslation.prototype.getSourceSentenceSegment = function ( segmentId 
) {
+       if ( typeof segmentId !== 'string' || !segmentId.match( /^[0-9]+$/ ) ) {
+               throw new Error( 'Invalid segment Id: ' + segmentId );
+       }
+       return this.$sourceCol.find( '.cx-segment[data-segmentid=' + segmentId 
+ ']' )[ 0 ];
+};

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I8f3063c75111562f2e77c9a716b13b15c6694402
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Esanders <esand...@wikimedia.org>
Gerrit-Reviewer: Catrope <r...@wikimedia.org>
Gerrit-Reviewer: Jforrester <jforres...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to