Divec has uploaded a new change for review.

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

Change subject: Single function to apply DOM selections
......................................................................

Single function to apply DOM selections

Also fix reversed selection bug in onCopy

Bug: T104517
Change-Id: I33c8073592341d5b775e2839be0221662705a6df
---
M src/ce/ve.ce.Surface.js
M tests/ce/ve.ce.Surface.test.js
2 files changed, 223 insertions(+), 155 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor 
refs/changes/21/222221/1

diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index c710a02..3a2664f 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -1588,7 +1588,7 @@
  * @param {jQuery.Event} e Copy event
  */
 ve.ce.Surface.prototype.onCopy = function ( e ) {
-       var originalRange,
+       var originalSelection,
                clipboardIndex, clipboardItem,
                scrollTop, unsafeSelector, range, slice,
                selection = this.getModel().getSelection(),
@@ -1668,10 +1668,16 @@
 
                // If direct clipboard editing is not allowed, we must use the 
pasteTarget to
                // select the data we want to go in the clipboard
+               if ( this.getModel().getSelection() instanceof 
ve.dm.LinearSelection ) {
+                       // We have a selection in the document; preserve it so 
it can restored
+                       originalSelection = {
+                               anchorNode: this.nativeSelection.anchorNode,
+                               anchorOffset: this.nativeSelection.anchorOffset,
+                               focusNode: this.nativeSelection.focusNode,
+                               focusOffset: this.nativeSelection.focusOffset,
+                               isCollapsed: this.nativeSelection.isCollapsed
+                       };
 
-               // If we have a range in the document, preserve it so it can 
restored
-               originalRange = this.getNativeRange();
-               if ( originalRange ) {
                        // Save scroll position before changing focus to 
"offscreen" paste target
                        scrollTop = this.$window.scrollTop();
 
@@ -1684,11 +1690,10 @@
 
                        setTimeout( function () {
                                // If the range was in $highlights (right-click 
copy), don't restore it
-                               if ( !OO.ui.contains( view.$highlights[0], 
originalRange.startContainer, true ) ) {
+                               if ( !OO.ui.contains( view.$highlights[0], 
originalSelection.focusNode, true ) ) {
                                        // Change focus back
                                        view.$documentNode[0].focus();
-                                       view.nativeSelection.removeAllRanges();
-                                       view.nativeSelection.addRange( 
originalRange.cloneRange() );
+                                       view.showRangeSelection( 
originalSelection );
                                        // Restore scroll position
                                        view.$window.scrollTop( scrollTop );
                                }
@@ -3768,7 +3773,7 @@
 };
 
 /**
- * Show selection
+ * Show DM selection
  *
  * @method
  * @param {ve.dm.Selection} selection Selection to show
@@ -3788,80 +3793,141 @@
                return;
        }
 
-       var endRange, oldRange, $node,
-               range = selection.getRange(),
-               rangeSelection = this.getRangeSelection( range ),
-               nativeRange = this.getElementDocument().createRange();
+       this.showRangeSelection( this.getRangeSelection( selection.getRange() ) 
);
+};
 
-       nativeRange.setStart( rangeSelection.start.node, 
rangeSelection.start.offset );
-       if ( rangeSelection.end ) {
-               nativeRange.setEnd( rangeSelection.end.node, 
rangeSelection.end.offset );
+/**
+ * Show native-selection-like object
+ *
+ * @param {Object} rangeSelection A native-selection-like object
+ * @param {Node} rangeSelection.anchorNode Anchor node to show
+ * @param {number} rangeSelection.anchorOffset Anchor offset to show
+ * @param {Node} rangeSelection.focusNode Focus node to show
+ * @param {number} rangeSelection.focusOffset Focus offset to show
+ * @param {boolean} rangeSelection.isCollapsed Are focus and anchor equal?
+ * @param {boolean} [rangeSelection.isBackwards] Is focus before anchor? 
(Calculated if ommitted)
+ */
+ve.ce.Surface.prototype.showRangeSelection = function ( rangeSelection ) {
+       var range = document.createRange(),
+               sel = this.nativeSelection,
+               newSel = rangeSelection,
+               isBackwards = newSel.isBackwards;
+
+       /** Test whether the selection would change.
+        * TODO: this gives false positives, because an apparent change can be 
normalized away
+        * by the browser e.g. "abc|<i>def" -> "abc<i>|def" in Chromium.
+        */
+       function isChanged() {
+               return sel.rangeCount === 0 ||
+                       newSel.anchorNode !== sel.anchorNode ||
+                       newSel.anchorOffset !== sel.anchorOffset ||
+                       newSel.focusNode !== sel.focusNode ||
+                       newSel.focusOffset !== sel.focusOffset;
        }
-       if ( rangeSelection.end && rangeSelection.isBackwards && 
this.nativeSelection.extend ) {
-               endRange = nativeRange.cloneRange();
-               endRange.collapse( false );
-               this.nativeSelection.removeAllRanges();
-               this.nativeSelection.addRange( endRange );
-               try {
-                       this.nativeSelection.extend( 
nativeRange.startContainer, nativeRange.startOffset );
-               } catch ( e ) {
-                       // Firefox sometimes fails when nodes are different,
-                       // see 
https://bugzilla.mozilla.org/show_bug.cgi?id=921444
-                       this.nativeSelection.addRange( nativeRange );
-               }
-       } else if ( !(
-               this.nativeSelection.rangeCount > 0 &&
-               ( oldRange = this.nativeSelection.getRangeAt( 0 ) ) &&
-               oldRange.startContainer === nativeRange.startContainer &&
-               oldRange.startOffset === nativeRange.startOffset &&
-               oldRange.endContainer === nativeRange.endContainer &&
-               oldRange.endOffset === nativeRange.endOffset
-       ) ) {
-               // Genuine selection change: apply it.
-               // TODO: this is slightly too zealous, because a cursor 
position at a node edge
-               // can have more than one (container,offset) representation
-               this.nativeSelection.removeAllRanges();
-               this.nativeSelection.addRange( nativeRange );
-       } else {
-               // Not a selection change: don't needlessly reapply the same 
selection.
+
+       if ( !isChanged() ) {
                return;
        }
 
+       if ( isBackwards === undefined ) {
+               isBackwards = !newSel.isCollapsed && ve.compareDocumentOrder(
+                       newSel.focusNode,
+                       newSel.focusOffset,
+                       newSel.anchorNode,
+                       newSel.anchorOffset
+               ) < 0;
+       }
+
+       if ( isBackwards ) {
+               if ( sel.extend ) {
+                       range.setStart( newSel.anchorNode, newSel.anchorOffset 
);
+                       sel.removeAllRanges();
+                       sel.addRange( range );
+                       try {
+                               sel.extend( newSel.focusNode, 
newSel.focusOffset );
+                               return;
+                       } catch ( e ) {
+                               // Firefox sometimes fails when nodes are 
different
+                               // see 
https://bugzilla.mozilla.org/show_bug.cgi?id=921444
+                       }
+               }
+               // Fallback: Apply the corresponding forward selection
+               newSel = this.flipRangeSelection( newSel );
+               if ( !isChanged() ) {
+                       return;
+               }
+       }
+
+       // Forward selection
+       range.setStart( newSel.anchorNode, newSel.anchorOffset );
+       if ( !newSel.isCollapsed ) {
+               range.setEnd( newSel.focusNode, newSel.focusOffset );
+       }
+       sel.removeAllRanges();
+       sel.addRange( range );
+
        // Setting a range doesn't give focus in all browsers so make sure this 
happens
        // Also set focus after range to prevent scrolling to top
-       if ( !OO.ui.contains( this.getElementDocument().activeElement, 
rangeSelection.start.node, true ) ) {
-               $( rangeSelection.start.node ).closest( 
'[contenteditable=true]' ).focus();
+       if ( !OO.ui.contains( this.getElementDocument().activeElement, 
newSel.focusNode, true ) ) {
+               $( newSel.focusNode ).closest( '[contenteditable=true]' 
).focus();
        } else {
-               $node = $( rangeSelection.start.node ).closest( '*' );
                // Scroll the node into view
-               OO.ui.Element.static.scrollIntoView( $node.get( 0 ) );
+               OO.ui.Element.static.scrollIntoView(
+                       $( newSel.focusNode ).closest( '*' ).get( 0 )
+               );
        }
 };
 
 /**
- * Get selection for a range.
+ * Get anchor and focus positions for a range.
  *
  * @method
  * @param {ve.Range} range Range to get selection for
- * @returns {Object} Object containing start and end node/offset selections, 
and an isBackwards flag.
+ * @returns {Object} The selection
+ * @returns.anchorNode {Node} The anchor node
+ * @returns.anchorOffset {number} The anchor offset
+ * @returns.focusNode {Node} The focus node
+ * @returns.focusOffset {number} The focus offset
+ * @returns.isCollapsed {boolean} True if the focus and anchor are in the same 
place
+ * @returns.isBackwards {boolean} True if the focus is before the anchor
  */
 ve.ce.Surface.prototype.getRangeSelection = function ( range ) {
-       range = new ve.Range(
-               this.getNearestCorrectOffset( range.from, -1 ),
-               this.getNearestCorrectOffset( range.to, 1 )
-       );
+       var anchor, focus;
 
-       if ( !range.isCollapsed() ) {
-               return {
-                       start: this.documentView.getNodeAndOffset( range.start 
),
-                       end: this.documentView.getNodeAndOffset( range.end ),
-                       isBackwards: range.isBackwards()
-               };
-       } else {
-               return {
-                       start: this.documentView.getNodeAndOffset( range.start )
-               };
+       // Anchor/focus at the nearest correct position in the direction that 
grows the selection
+       anchor = this.documentView.getNodeAndOffset(
+               this.getNearestCorrectOffset( range.from, range.isBackwards() ? 
1 : -1 )
+       );
+       focus = this.documentView.getNodeAndOffset(
+               this.getNearestCorrectOffset( range.to, range.isBackwards() ? 
-1 : 1 )
+       );
+       return {
+               anchorNode: anchor.node,
+               anchorOffset: anchor.offset,
+               focusNode: focus.node,
+               focusOffset: focus.offset,
+               isCollapsed: range.isCollapsed() && ( anchor.node === 
focus.node && anchor.offset === focus.offset ),
+               isBackwards: range.isBackwards()
+       };
+};
+
+/**
+ * Flips the selection if uncollapsed; otherwise returns it unchanged
+ *
+ * @param {Object} rangeSelection native-selection-like object
+ * @returns {Object} The selection with the anchor/focus swapped
+ */
+ve.ce.Surface.prototype.flipRangeSelection = function ( rangeSelection ) {
+       if ( rangeSelection.isCollapsed ) {
+               return rangeSelection;
        }
+       return {
+               anchorNode: rangeSelection.focusNode,
+               anchorOffset: rangeSelection.focusOffset,
+               focusNode: rangeSelection.anchorNode,
+               focusOffset: rangeSelection.focusOffset,
+               isCollapsed: false
+       };
 };
 
 /**
@@ -3900,10 +3966,12 @@
 
        nativeRange = document.createRange();
        rangeSelection = this.getRangeSelection( range );
-
-       nativeRange.setStart( rangeSelection.start.node, 
rangeSelection.start.offset );
-       if ( rangeSelection.end ) {
-               nativeRange.setEnd( rangeSelection.end.node, 
rangeSelection.end.offset );
+       if ( rangeSelection.isBackwards ) {
+               rangeSelection = this.flipRangeSelection( rangeSelection );
+       }
+       nativeRange.setStart( rangeSelection.anchorNode, 
rangeSelection.anchorOffset );
+       if ( !rangeSelection.isCollapsed ) {
+               nativeRange.setEnd( rangeSelection.focusNode, 
rangeSelection.focusOffset );
        }
        return nativeRange;
 };
diff --git a/tests/ce/ve.ce.Surface.test.js b/tests/ce/ve.ce.Surface.test.js
index 366912f..9d3b2c1 100644
--- a/tests/ce/ve.ce.Surface.test.js
+++ b/tests/ce/ve.ce.Surface.test.js
@@ -1409,7 +1409,7 @@
 } );
 
 QUnit.test( 'getRangeSelection', function ( assert ) {
-       var i, j, l, view, selection, expectedNode, internlListNode, node, msg,
+       var i, j, l, view, selection, expectedNode, internalListNode, node, msg,
                expect = 0,
                cases = [
                        {
@@ -1425,102 +1425,102 @@
                                        '2<b>n</b>d' +
                                '</p>',
                                expected: [
-                                       { startNode: 'Foo', startOffset: 0 },
-                                       { startNode: 'Foo', startOffset: 0 },
-                                       { startNode: 'Foo', startOffset: 1 },
-                                       { startNode: 'Foo', startOffset: 2 },
-                                       { startNode: 'Foo', startOffset: 3 },
+                                       { anchorNode: 'Foo', anchorOffset: 0 },
+                                       { anchorNode: 'Foo', anchorOffset: 0 },
+                                       { anchorNode: 'Foo', anchorOffset: 1 },
+                                       { anchorNode: 'Foo', anchorOffset: 2 },
+                                       { anchorNode: 'Foo', anchorOffset: 3 },
                                        null, // Focusable
-                                       { startNode: 'Whee', startOffset: 0 },
-                                       { startNode: 'Whee', startOffset: 1 },
-                                       { startNode: 'Whee', startOffset: 2 },
-                                       { startNode: 'Whee', startOffset: 3 },
-                                       { startNode: 'Whee', startOffset: 4 },
-                                       { startNode: 'Whee', startOffset: 4, 
endNode: '2', endOffset: 0 },
-                                       { startNode: '2', startOffset: 0 },
-                                       { startNode: '2', startOffset: 1 },
-                                       { startNode: 'n', startOffset: 1 },
-                                       { startNode: 'd', startOffset: 1 }
+                                       { anchorNode: 'Whee', anchorOffset: 0 },
+                                       { anchorNode: 'Whee', anchorOffset: 1 },
+                                       { anchorNode: 'Whee', anchorOffset: 2 },
+                                       { anchorNode: 'Whee', anchorOffset: 3 },
+                                       { anchorNode: 'Whee', anchorOffset: 4 },
+                                       { anchorNode: 'Whee', anchorOffset: 4, 
focusNode: '2', focusOffset: 0 },
+                                       { anchorNode: '2', anchorOffset: 0 },
+                                       { anchorNode: '2', anchorOffset: 1 },
+                                       { anchorNode: 'n', anchorOffset: 1 },
+                                       { anchorNode: 'd', anchorOffset: 1 }
                                ]
                        },
                        {
                                msg: 'Simple example doc',
                                html: ve.dm.example.html,
                                expected: [
-                                       { startNode: 'a', startOffset: 0 },
-                                       { startNode: 'a', startOffset: 0 },
-                                       { startNode: 'a', startOffset: 1 },
-                                       { startNode: 'b', startOffset: 1 },
-                                       { startNode: 'c', startOffset: 1 },
-                                       { startNode: 'c', startOffset: 1, 
endNode: 'd', endOffset: 0 },
-                                       { startNode: 'c', startOffset: 1, 
endNode: 'd', endOffset: 0 },
-                                       { startNode: 'c', startOffset: 1, 
endNode: 'd', endOffset: 0 },
-                                       { startNode: 'c', startOffset: 1, 
endNode: 'd', endOffset: 0 },
-                                       { startNode: 'c', startOffset: 1, 
endNode: 'd', endOffset: 0 },
+                                       { anchorNode: 'a', anchorOffset: 0 },
+                                       { anchorNode: 'a', anchorOffset: 0 },
+                                       { anchorNode: 'a', anchorOffset: 1 },
+                                       { anchorNode: 'b', anchorOffset: 1 },
+                                       { anchorNode: 'c', anchorOffset: 1 },
+                                       { anchorNode: 'c', anchorOffset: 1, 
focusNode: 'd', focusOffset: 0 },
+                                       { anchorNode: 'c', anchorOffset: 1, 
focusNode: 'd', focusOffset: 0 },
+                                       { anchorNode: 'c', anchorOffset: 1, 
focusNode: 'd', focusOffset: 0 },
+                                       { anchorNode: 'c', anchorOffset: 1, 
focusNode: 'd', focusOffset: 0 },
+                                       { anchorNode: 'c', anchorOffset: 1, 
focusNode: 'd', focusOffset: 0 },
                                        // 10
-                                       { startNode: 'd', startOffset: 0 },
-                                       { startNode: 'd', startOffset: 1 },
-                                       { startNode: 'd', startOffset: 1, 
endNode: 'e', endOffset: 0 },
-                                       { startNode: 'd', startOffset: 1, 
endNode: 'e', endOffset: 0 },
-                                       { startNode: 'd', startOffset: 1, 
endNode: 'e', endOffset: 0 },
-                                       { startNode: 'e', startOffset: 0 },
-                                       { startNode: 'e', startOffset: 1 },
-                                       { startNode: 'e', startOffset: 1, 
endNode: 'f', endOffset: 0 },
-                                       { startNode: 'e', startOffset: 1, 
endNode: 'f', endOffset: 0 },
-                                       { startNode: 'e', startOffset: 1, 
endNode: 'f', endOffset: 0 },
+                                       { anchorNode: 'd', anchorOffset: 0 },
+                                       { anchorNode: 'd', anchorOffset: 1 },
+                                       { anchorNode: 'd', anchorOffset: 1, 
focusNode: 'e', focusOffset: 0 },
+                                       { anchorNode: 'd', anchorOffset: 1, 
focusNode: 'e', focusOffset: 0 },
+                                       { anchorNode: 'd', anchorOffset: 1, 
focusNode: 'e', focusOffset: 0 },
+                                       { anchorNode: 'e', anchorOffset: 0 },
+                                       { anchorNode: 'e', anchorOffset: 1 },
+                                       { anchorNode: 'e', anchorOffset: 1, 
focusNode: 'f', focusOffset: 0 },
+                                       { anchorNode: 'e', anchorOffset: 1, 
focusNode: 'f', focusOffset: 0 },
+                                       { anchorNode: 'e', anchorOffset: 1, 
focusNode: 'f', focusOffset: 0 },
                                        // 20
-                                       { startNode: 'f', startOffset: 0 },
-                                       { startNode: 'f', startOffset: 1 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'f', startOffset: 1, 
endNode: 'g', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'f', anchorOffset: 1, 
focusNode: 'g', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 0 },
                                        // 30
-                                       { startNode: 'g', startOffset: 1 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'g', startOffset: 1, 
endNode: 'h', endOffset: 0 },
-                                       { startNode: 'h', startOffset: 0 },
-                                       { startNode: 'h', startOffset: 1 },
+                                       { anchorNode: 'g', anchorOffset: 1 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'g', anchorOffset: 1, 
focusNode: 'h', focusOffset: 0 },
+                                       { anchorNode: 'h', anchorOffset: 0 },
+                                       { anchorNode: 'h', anchorOffset: 1 },
                                        // 40
                                        null, // Focusable
-                                       { startNode: 'i', startOffset: 0 },
-                                       { startNode: 'i', startOffset: 1 },
-                                       { startNode: 'i', startOffset: 1, 
endNode: 'j', endOffset: 0 },
-                                       { startNode: 'i', startOffset: 1, 
endNode: 'j', endOffset: 0 },
-                                       { startNode: 'i', startOffset: 1, 
endNode: 'j', endOffset: 0 },
-                                       { startNode: 'j', startOffset: 0 },
-                                       { startNode: 'j', startOffset: 1 },
-                                       { startNode: 'j', startOffset: 1, 
endNode: 'k', endOffset: 0 },
-                                       { startNode: 'j', startOffset: 1, 
endNode: 'k', endOffset: 0 },
+                                       { anchorNode: 'i', anchorOffset: 0 },
+                                       { anchorNode: 'i', anchorOffset: 1 },
+                                       { anchorNode: 'i', anchorOffset: 1, 
focusNode: 'j', focusOffset: 0 },
+                                       { anchorNode: 'i', anchorOffset: 1, 
focusNode: 'j', focusOffset: 0 },
+                                       { anchorNode: 'i', anchorOffset: 1, 
focusNode: 'j', focusOffset: 0 },
+                                       { anchorNode: 'j', anchorOffset: 0 },
+                                       { anchorNode: 'j', anchorOffset: 1 },
+                                       { anchorNode: 'j', anchorOffset: 1, 
focusNode: 'k', focusOffset: 0 },
+                                       { anchorNode: 'j', anchorOffset: 1, 
focusNode: 'k', focusOffset: 0 },
                                        // 50
-                                       { startNode: 'j', startOffset: 1, 
endNode: 'k', endOffset: 0 },
-                                       { startNode: 'k', startOffset: 0 },
-                                       { startNode: 'k', startOffset: 1 },
-                                       { startNode: 'k', startOffset: 1, 
endNode: 'l', endOffset: 0 },
-                                       { startNode: 'k', startOffset: 1, 
endNode: 'l', endOffset: 0 },
-                                       { startNode: 'k', startOffset: 1, 
endNode: 'l', endOffset: 0 },
-                                       { startNode: 'l', startOffset: 0 },
-                                       { startNode: 'l', startOffset: 1 },
-                                       { startNode: 'l', startOffset: 1, 
endNode: 'm', endOffset: 0 },
-                                       { startNode: 'm', startOffset: 0 },
+                                       { anchorNode: 'j', anchorOffset: 1, 
focusNode: 'k', focusOffset: 0 },
+                                       { anchorNode: 'k', anchorOffset: 0 },
+                                       { anchorNode: 'k', anchorOffset: 1 },
+                                       { anchorNode: 'k', anchorOffset: 1, 
focusNode: 'l', focusOffset: 0 },
+                                       { anchorNode: 'k', anchorOffset: 1, 
focusNode: 'l', focusOffset: 0 },
+                                       { anchorNode: 'k', anchorOffset: 1, 
focusNode: 'l', focusOffset: 0 },
+                                       { anchorNode: 'l', anchorOffset: 0 },
+                                       { anchorNode: 'l', anchorOffset: 1 },
+                                       { anchorNode: 'l', anchorOffset: 1, 
focusNode: 'm', focusOffset: 0 },
+                                       { anchorNode: 'm', anchorOffset: 0 },
                                        // 60
-                                       { startNode: 'm', startOffset: 1 }
+                                       { anchorNode: 'm', anchorOffset: 1 }
                                ]
                        }
                ];
 
        for ( i = 0; i < cases.length; i++ ) {
                for ( j = 0; j < cases[i].expected.length; j++ ) {
-                       expect += cases[i].expected[j] ? ( 
cases[i].expected[j].endNode ? 4 : 2 ) : 1;
+                       expect += cases[i].expected[j] ? ( 
cases[i].expected[j].focusNode === undefined ? 2 : 4 ) : 1;
                }
        }
 
@@ -1528,25 +1528,25 @@
 
        for ( i = 0; i < cases.length; i++ ) {
                view = ve.test.utils.createSurfaceViewFromHtml( cases[i].html );
-               internlListNode = 
view.getModel().getDocument().getInternalList().getListNode();
-               for ( j = 0, l = internlListNode.getOuterRange().start; j < l; 
j++ ) {
+               internalListNode = 
view.getModel().getDocument().getInternalList().getListNode();
+               for ( j = 0, l = internalListNode.getOuterRange().start; j < l; 
j++ ) {
                        msg = ' at ' + j + ' in ' + cases[i].msg;
                        node = 
view.getDocument().getDocumentNode().getNodeFromOffset( j );
                        if ( node.isFocusable() ) {
                                assert.strictEqual( null, cases[i].expected[j], 
'Focusable node at ' + j );
                        } else {
                                selection = view.getRangeSelection( new 
ve.Range( j ) );
-                               if ( selection.end ) {
-                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].startNode )[0].childNodes[0];
-                                       assert.equalDomElement( 
selection.start.node, expectedNode, 'Start node ' + msg );
-                                       assert.strictEqual( 
selection.start.offset, cases[i].expected[j].startOffset, 'Start offfset ' + 
msg );
-                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].endNode )[0].childNodes[0];
-                                       assert.equalDomElement( 
selection.end.node, expectedNode, 'End node ' + msg );
-                                       assert.strictEqual( 
selection.end.offset, cases[i].expected[j].endOffset, 'End offfset ' + msg );
+                               if ( selection.isCollapsed ) {
+                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].anchorNode )[0].childNodes[0];
+                                       assert.equalDomElement( 
selection.anchorNode, expectedNode, 'Node ' + msg );
+                                       assert.strictEqual( 
selection.anchorOffset, cases[i].expected[j].anchorOffset, 'Offset ' + msg );
                                } else {
-                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].startNode )[0].childNodes[0];
-                                       assert.equalDomElement( 
selection.start.node, expectedNode, 'Node ' + msg );
-                                       assert.strictEqual( 
selection.start.offset, cases[i].expected[j].startOffset, 'Offset ' + msg );
+                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].anchorNode )[0].childNodes[0];
+                                       assert.equalDomElement( 
selection.anchorNode, expectedNode, 'Anchor node ' + msg );
+                                       assert.strictEqual( 
selection.anchorOffset, cases[i].expected[j].anchorOffset, 'Anchor offset ' + 
msg );
+                                       expectedNode = $( '<div>' ).html( 
cases[i].expected[j].focusNode )[0].childNodes[0];
+                                       assert.equalDomElement( 
selection.focusNode, expectedNode, 'End node ' + msg );
+                                       assert.strictEqual( 
selection.focusOffset, cases[i].expected[j].focusOffset, 'Focus offset ' + msg 
);
                                }
                        }
                }

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I33c8073592341d5b775e2839be0221662705a6df
Gerrit-PatchSet: 1
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Divec <[email protected]>

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

Reply via email to