Esanders has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/363644 )

Change subject: Rewrite VE<->CM synchronizer using transaction op walking
......................................................................

Rewrite VE<->CM synchronizer using transaction op walking

Previous hacky method fell apart with multi-line transactions.

Depends-On: I465a3f6a8afcd6536293999eb40c01daeb9d905b
Change-Id: I66946d7e3f425d8dbbdae720756a7978fbe25582
---
M resources/modules/ve-cm/ve.ui.CodeMirrorAction.js
1 file changed, 50 insertions(+), 32 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/CodeMirror 
refs/changes/44/363644/1

diff --git a/resources/modules/ve-cm/ve.ui.CodeMirrorAction.js 
b/resources/modules/ve-cm/ve.ui.CodeMirrorAction.js
index effe1de..14d49d7 100644
--- a/resources/modules/ve-cm/ve.ui.CodeMirrorAction.js
+++ b/resources/modules/ve-cm/ve.ui.CodeMirrorAction.js
@@ -65,11 +65,11 @@
 
                // As the action is regenerated each time, we need to store the 
bound listener
                // in the mirror for later disconnection.
-               surface.mirror.veTransactionListener = 
this.onDocumentTransact.bind( this, surface );
+               surface.mirror.veTransactionListener = 
this.onDocumentPrecommit.bind( this );
 
-               doc.on( 'transact', surface.mirror.veTransactionListener );
+               doc.on( 'precommit', surface.mirror.veTransactionListener );
        } else if ( surface.mirror && enable !== true ) {
-               doc.off( 'transact', surface.mirror.veTransactionListener );
+               doc.off( 'precommit', surface.mirror.veTransactionListener );
 
                surfaceView.$documentNode.removeClass(
                        've-ce-documentNode-codeEditor-webkit-hide 
ve-ce-documentNode-codeEditor-webkit'
@@ -83,37 +83,55 @@
        return true;
 };
 
-ve.ui.CodeMirrorAction.prototype.onDocumentTransact = function ( surface, tx ) 
{
-       var node, textRange, line,
-               doc = surface.getModel().getDocument(),
-               mirror = surface.mirror,
-               modifiedRange = tx.getModifiedRange( doc ),
-               nodes = doc.selectNodes( modifiedRange, 'leaves' );
+/**
+ * Handle precommit events from the document.
+ *
+ * The document is still in it's 'old' state before the transaction
+ * has been applied at this point.
+ *
+ * @param {ve.dm.Transaction} tx [description]
+ */
+ve.ui.CodeMirrorAction.prototype.onDocumentPrecommit = function ( tx ) {
+       var i,
+               offset = 0,
+               replacements = [],
+               linearData = this.surface.getModel().getDocument().data,
+               store = linearData.getStore(),
+               mirror = this.surface.mirror;
 
-       // TODO: Iterate over operations and perform a replaceRange for each 
replace operation
-       if ( nodes.length === 1 && nodes[ 0 ].node instanceof ve.dm.TextNode ) {
-               node = nodes[ 0 ].node.parent;
-               textRange = nodes[ 0 ].nodeRange;
-               line = node.parent.children.indexOf( node );
-               if ( tx.operations.every( function ( op ) {
-                       return op.type === 'retain' || ( op.type === 'replace' 
&& op.remove.length === 0 );
-               } ) ) {
-                       // Single line insert
-                       mirror.replaceRange(
-                               doc.data.getText( true, modifiedRange ),
-                               { line: line, ch: modifiedRange.start - 
textRange.start }
-                       );
-               } else {
-                       // Single line replace
-                       mirror.replaceRange(
-                               doc.data.getText( true, textRange ),
-                               { line: line, ch: 0 },
-                               { line: line, ch: mirror.getLine( line ).length 
}
-                       );
+       /**
+        * Convert a VE offset to a 2D CodeMirror position
+        *
+        * @private
+        * @param {Number} veOffset VE linear model offset
+        * @return {Object} Code mirror position, containing 'line' and 'ch'
+        */
+       function convertOffset( veOffset ) {
+               var cmOffset = linearData.getSourceText( new ve.Range( 0, 
veOffset ) ).length;
+               return mirror.posFromIndex( cmOffset );
+       }
+
+       tx.operations.forEach( function ( op ) {
+               if ( op.type === 'retain' ) {
+                       offset += op.length;
+               } else if ( op.type === 'replace' ) {
+                       replacements.push( {
+                               start: convertOffset( offset ),
+                               // Don't bother recalculating end offset if not 
a removal, replaceRange works with just one arg
+                               end: op.remove.length ? convertOffset( offset + 
op.remove.length ) : undefined,
+                               data: new ve.dm.ElementLinearData( store, 
op.insert ).getSourceText()
+                       } );
+                       offset += op.remove.length;
                }
-       } else {
-               // Fallback - flush whole doc
-               mirror.setValue( surface.getDom() );
+       } );
+
+       // Apply replacements in reverse to avoid having to shift offsets
+       for ( i = replacements.length - 1; i >= 0; i-- ) {
+               mirror.replaceRange(
+                       replacements[ i ].data,
+                       replacements[ i ].start,
+                       replacements[ i ].end
+               );
        }
 };
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I66946d7e3f425d8dbbdae720756a7978fbe25582
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/CodeMirror
Gerrit-Branch: master
Gerrit-Owner: Esanders <esand...@wikimedia.org>

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

Reply via email to