Catrope has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/165734

Change subject: Followup 2fcc4c0: fix bugs with selection-only polling
......................................................................

Followup 2fcc4c0: fix bugs with selection-only polling

The optimizations in selection-only polling were too aggressive.
When the cursor moved to a different node and the next poll was
a selection-only poll, we would not update this.node because that
code path was skipped for selection-only polls. Changing the
selection by clicking with the mouse will cause both a
selection-only poll (from onDocumentSelectionChange) and
a full poll (from a timeout in onDocumentMouseDown) to occur,
but they can occur in either order, at least in Chrome.
Probably what's going on is that there may or may not be
a timer tick between mousedown and selectionchange, depending
on how fast the user clicks or something.

I think this is related to recent cases I've seen of inserted
characters at the end of a line ending up on the next line.
I would imagine something like this could have caused that:
* User clicks at end of line
* mousedown happens, sets timeout for full poll
* DOM selectionchange event happens, does selectionOnly poll
* Poll emits selectionchange event but does not update this.node
* Timeout fires, full poll happens
* Poll observes that DOM selection hasn't changed, does nothing
* User types 'A', causes full poll
* Poll observes this.node has changed, does not check for content change
* No contentChange emitted, 'A' not added to DM, DM and CE out of sync
* Subsequent polls do nothing because DOM selection didn't change
* User types again
* Poll observes 'B' was added, emits contentChange
* CE sees <p>HelloA|B|</p>, computes insertion offset 7
* DM doesn't have 'A', so "insert B at 7" is <p>Hello</p>|B|
* This is normalized to <p>Hello</p><p>B</p> and committed
* New paragraph is rendered but old paragraph isn't rerendered
* CE DOM now shows <p>HelloAB</p><p>B</p>
* User is confused and goes to Roan's desk

Change-Id: I6333590e46c6c7241b8974afe5e5dfed9d79c877
(cherry picked from commit fdbbad7f29e1159494c0573dd1866a6f2f62d8a1)
---
M src/ce/ve.ce.SurfaceObserver.js
1 file changed, 67 insertions(+), 67 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor 
refs/changes/34/165734/1

diff --git a/src/ce/ve.ce.SurfaceObserver.js b/src/ce/ve.ce.SurfaceObserver.js
index b786540..073f6de 100644
--- a/src/ce/ve.ce.SurfaceObserver.js
+++ b/src/ce/ve.ce.SurfaceObserver.js
@@ -188,7 +188,7 @@
  */
 ve.ce.SurfaceObserver.prototype.pollOnceInternal = function ( emitChanges, 
selectionOnly ) {
        var $nodeOrSlug, node, text, hash, range, domRange, $slugWrapper,
-               domRangeChange = false,
+               anchorNodeChange = false,
                slugChange = false,
                observer = this;
 
@@ -201,82 +201,82 @@
        domRange = ve.ce.DomRange.newFromDocument( this.domDocument );
 
        if ( !domRange.equals( this.domRange ) ) {
+               if ( !this.domRange || this.domRange.anchorNode !== 
domRange.anchorNode ) {
+                       anchorNodeChange = true;
+               }
                range = domRange.getRange();
                this.domRange = domRange;
-               domRangeChange = true;
        }
 
-       if ( !selectionOnly ) {
-               if ( domRangeChange ) {
-                       node = null;
-                       $nodeOrSlug = $( domRange.anchorNode ).closest( 
'.ve-ce-branchNode, .ve-ce-branchNode-slug' );
-                       if ( $nodeOrSlug.length ) {
-                               if ( $nodeOrSlug.hasClass( 
've-ce-branchNode-slug' ) ) {
-                                       $slugWrapper = $nodeOrSlug.closest( 
'.ve-ce-branchNode-blockSlugWrapper' );
-                               } else {
-                                       node = $nodeOrSlug.data( 'view' );
-                                       // Check this node belongs to our 
document
-                                       if ( node && node.root !== 
this.documentView.getDocumentNode() ) {
-                                               node = null;
-                                               range = null;
-                                       }
+       if ( anchorNodeChange ) {
+               node = null;
+               $nodeOrSlug = $( domRange.anchorNode ).closest( 
'.ve-ce-branchNode, .ve-ce-branchNode-slug' );
+               if ( $nodeOrSlug.length ) {
+                       if ( $nodeOrSlug.hasClass( 've-ce-branchNode-slug' ) ) {
+                               $slugWrapper = $nodeOrSlug.closest( 
'.ve-ce-branchNode-blockSlugWrapper' );
+                       } else {
+                               node = $nodeOrSlug.data( 'view' );
+                               // Check this node belongs to our document
+                               if ( node && node.root !== 
this.documentView.getDocumentNode() ) {
+                                       node = null;
+                                       range = null;
                                }
-                       }
-
-                       if ( this.$slugWrapper && !this.$slugWrapper.is( 
$slugWrapper ) ) {
-                               this.$slugWrapper
-                                       .addClass( 
've-ce-branchNode-blockSlugWrapper-unfocused' )
-                                       .removeClass( 
've-ce-branchNode-blockSlugWrapper-focused' );
-                               this.$slugWrapper = null;
-                               slugChange = true;
-                       }
-
-                       if ( $slugWrapper && !$slugWrapper.is( 
this.$slugWrapper) ) {
-                               this.$slugWrapper = $slugWrapper
-                                       .addClass( 
've-ce-branchNode-blockSlugWrapper-focused' )
-                                       .removeClass( 
've-ce-branchNode-blockSlugWrapper-unfocused' );
-                               slugChange = true;
-                       }
-
-                       if ( slugChange ) {
-                               // Emit 'position' on the surface view after 
the animation completes
-                               this.setTimeout( function () {
-                                       if ( observer.surface ) {
-                                               observer.surface.emit( 
'position' );
-                                       }
-                               }, 200 );
                        }
                }
 
-               if ( this.node !== node ) {
-                       if ( node === null ) {
-                               this.text = null;
-                               this.hash = null;
-                               this.node = null;
-                       } else {
-                               this.text = ve.ce.getDomText( node.$element[0] 
);
-                               this.hash = ve.ce.getDomHash( node.$element[0] 
);
-                               this.node = node;
-                       }
-               } else if ( node !== null ) {
-                       text = ve.ce.getDomText( node.$element[0] );
-                       hash = ve.ce.getDomHash( node.$element[0] );
-                       if ( this.text !== text || this.hash !== hash ) {
-                               if ( emitChanges ) {
-                                       this.emit(
-                                               'contentChange',
-                                               node,
-                                               {
-                                                       text: this.text,
-                                                       hash: this.hash,
-                                                       range: this.range
-                                               },
-                                               { text: text, hash: hash, 
range: range }
-                                       );
+               if ( this.$slugWrapper && !this.$slugWrapper.is( $slugWrapper ) 
) {
+                       this.$slugWrapper
+                               .addClass( 
've-ce-branchNode-blockSlugWrapper-unfocused' )
+                               .removeClass( 
've-ce-branchNode-blockSlugWrapper-focused' );
+                       this.$slugWrapper = null;
+                       slugChange = true;
+               }
+
+               if ( $slugWrapper && !$slugWrapper.is( this.$slugWrapper ) ) {
+                       this.$slugWrapper = $slugWrapper
+                               .addClass( 
've-ce-branchNode-blockSlugWrapper-focused' )
+                               .removeClass( 
've-ce-branchNode-blockSlugWrapper-unfocused' );
+                       slugChange = true;
+               }
+
+               if ( slugChange ) {
+                       // Emit 'position' on the surface view after the 
animation completes
+                       this.setTimeout( function () {
+                               if ( observer.surface ) {
+                                       observer.surface.emit( 'position' );
                                }
-                               this.text = text;
-                               this.hash = hash;
+                       }, 200 );
+               }
+       }
+
+       if ( this.node !== node ) {
+               if ( node === null ) {
+                       this.text = null;
+                       this.hash = null;
+                       this.node = null;
+               } else {
+                       this.text = ve.ce.getDomText( node.$element[0] );
+                       this.hash = ve.ce.getDomHash( node.$element[0] );
+                       this.node = node;
+               }
+       } else if ( !selectionOnly && node !== null ) {
+               text = ve.ce.getDomText( node.$element[0] );
+               hash = ve.ce.getDomHash( node.$element[0] );
+               if ( this.text !== text || this.hash !== hash ) {
+                       if ( emitChanges ) {
+                               this.emit(
+                                       'contentChange',
+                                       node,
+                                       {
+                                               text: this.text,
+                                               hash: this.hash,
+                                               range: this.range
+                                       },
+                                       { text: text, hash: hash, range: range }
+                               );
                        }
+                       this.text = text;
+                       this.hash = hash;
                }
        }
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I6333590e46c6c7241b8974afe5e5dfed9d79c877
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: wmf/1.25wmf2
Gerrit-Owner: Catrope <[email protected]>

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

Reply via email to