jenkins-bot has submitted this change and it was merged.

Change subject: Kill rangy (almost)
......................................................................


Kill rangy (almost)

Replace simple range getting and setting with native Selection/Range
api that is supported by Chrome/FF & IE10+.

Bonus: Fix documentation in ve.ce.DomRange, and variable names
in various places.

Rename getSelection to getRangeSelection to avoid confusion with
native method.

Fixme: Some tests in ve.ce.TestRunner were pretending to pass because
of a typo (startNode instead of startContainer). Have been logically
commented out with an if(false) but should be fixed in later.

Change-Id: If6f5f59f96b0787b0a4545d430dae3ef0b8deb4d
---
M src/ce/ve.ce.Document.js
M src/ce/ve.ce.DomRange.js
M src/ce/ve.ce.Surface.js
M src/ce/ve.ce.SurfaceObserver.js
M src/ui/ve.ui.Surface.js
M tests/ce/ve.ce.Surface.test.js
M tests/ce/ve.ce.TestRunner.js
7 files changed, 139 insertions(+), 137 deletions(-)

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



diff --git a/src/ce/ve.ce.Document.js b/src/ce/ve.ce.Document.js
index c50cafd..8ea5658 100644
--- a/src/ce/ve.ce.Document.js
+++ b/src/ce/ve.ce.Document.js
@@ -150,8 +150,6 @@
 /**
  * Get a DOM node and DOM element offset for a document offset.
  *
- * The results of this function are meant to be used with rangy.
- *
  * @method
  * @param {number} offset Linear model offset
  * @returns {Object} Object containing a node and offset property where node 
is an HTML element and
diff --git a/src/ce/ve.ce.DomRange.js b/src/ce/ve.ce.DomRange.js
index 4f1d6d2..2647e4e 100644
--- a/src/ce/ve.ce.DomRange.js
+++ b/src/ce/ve.ce.DomRange.js
@@ -6,7 +6,7 @@
  */
 
 /**
- * DomRange.
+ * DOM range
  *
  * @class
  * @constructor
@@ -24,7 +24,14 @@
 
 /* Static Methods */
 
-ve.ce.DomRange.newFromDomSelection = function ( selection ) {
+/**
+ * Create a new DOM range from a document's native selection
+ *
+ * @param {HTMLDocument} doc Document to get selection from
+ * @return {ve.ce.DomRange} DOM range
+ */
+ve.ce.DomRange.newFromDocument = function ( doc ) {
+       var selection = doc.getSelection();
        return new ve.ce.DomRange(
                selection.focusNode, selection.focusOffset, 
selection.anchorNode, selection.anchorOffset
        );
@@ -32,7 +39,11 @@
 
 /* Methods */
 
-/** */
+/**
+ * Check if a DOM range is equal to another DOM range
+ * @param {ve.ce.DomRange} other DOM range to compare to
+ * @return {boolean} The other DOM range is equal to this one
+ */
 ve.ce.DomRange.prototype.equals = function ( other ) {
        return other &&
                this.focusNode === other.focusNode &&
@@ -42,6 +53,8 @@
 };
 
 /**
+ * Get a linear model ve.Range for the DOM range
+ *
  * @returns {ve.Range}
  */
 ve.ce.DomRange.prototype.getRange = function () {
diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index c8f1618..cc933e4 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -35,6 +35,8 @@
        this.selectionTimeout = null;
        this.$window = this.$( this.getElementWindow() );
        this.$document = this.$( this.getElementDocument() );
+       // Window.getSelection returns a live singleton representing the 
document's selection
+       this.nativeSelection = this.getElementWindow().getSelection();
        this.eventSequencer = new ve.EventSequencer( [
                'keydown', 'keypress', 'keyup',
                'compositionstart', 'compositionend'
@@ -277,7 +279,7 @@
  * @returns {Object|null} Start and end selection rectangles
  */
 ve.ce.Surface.prototype.getSelectionInlineClientRects = function () {
-       var inlineRects, surfaceRect, sel, boundingRect, rtl, x, collapsedRect;
+       var inlineRects, surfaceRect, boundingRect, rtl, x, collapsedRect;
        if ( this.focusedNode ) {
                inlineRects = this.focusedNode.getInlineRects();
                surfaceRect = this.getSurface().getBoundingClientRect();
@@ -291,10 +293,8 @@
                };
        }
 
-       sel = this.getElementDocument().getSelection();
-
        // We can't do anything if there's no selection
-       if ( sel.rangeCount === 0 ) {
+       if ( this.nativeSelection.rangeCount === 0 ) {
                return null;
        }
 
@@ -302,14 +302,14 @@
        // * in Firefox on page load when the address bar is still focused
        // * in empty paragraphs
        try {
-               return ve.getStartAndEndRects( sel.getRangeAt( 0 
).getClientRects() );
+               return ve.getStartAndEndRects( this.nativeSelection.getRangeAt( 
0 ).getClientRects() );
        } catch ( e ) {
                // When possible, pretend the cursor is the left/right border 
of the node
                // (depending on directionality) as a fallback.
-               if ( sel.focusNode && sel.focusNode.nodeType === 
Node.ELEMENT_NODE ) {
+               if ( this.nativeSelection.focusNode && 
this.nativeSelection.focusNode.nodeType === Node.ELEMENT_NODE ) {
                        // We would use getBoundingClientRect(), but in iOS7 
that's relative to the
                        // document rather than to the viewport
-                       boundingRect = sel.focusNode.getClientRects()[0];
+                       boundingRect = 
this.nativeSelection.focusNode.getClientRects()[0];
                        if ( !boundingRect ) {
                                // FF can return null when focusNode is 
invisible
                                return null;
@@ -344,7 +344,7 @@
  * @returns {Object|null} Selection rectangle, with keys top, bottom, left, 
right, width, height
  */
 ve.ce.Surface.prototype.getSelectionBoundingClientRect = function () {
-       var inlineRects, boundingRect, surfaceRect, sel;
+       var inlineRects, boundingRect, surfaceRect;
 
        if ( this.focusedNode ) {
                boundingRect = this.focusedNode.getBoundingRect();
@@ -356,15 +356,13 @@
                return ve.translateRect( boundingRect, surfaceRect.left, 
surfaceRect.top );
        }
 
-       sel = this.getElementDocument().getSelection();
-
        // We can't do anything if there's no selection
-       if ( sel.rangeCount === 0 ) {
+       if ( this.nativeSelection.rangeCount === 0 ) {
                return null;
        }
 
        try {
-               inlineRects = sel.getRangeAt( 0 ).getClientRects();
+               inlineRects = this.nativeSelection.getRangeAt( 0 
).getClientRects();
                // Try the zeroth inline rect first as Chrome sometimes returns 
a rectangle
                // full of zeros for getBoundingClientRect when the cursor is 
collapsed.
                // We could test for this failure and fall back to inline[0], 
except for the
@@ -374,7 +372,7 @@
                if ( inlineRects.length === 1 ) {
                        return inlineRects[0];
                }
-               return sel.getRangeAt( 0 ).getBoundingClientRect();
+               return this.nativeSelection.getRangeAt( 0 
).getBoundingClientRect();
        } catch ( e ) {
                return null;
        }
@@ -522,17 +520,14 @@
 ve.ce.Surface.prototype.onFocusChange = function () {
        var hasFocus = false;
 
-       // rangy.getSelection can throw an exception in FF
-       try {
-               hasFocus = ve.contains(
-                       [
-                               this.documentView.getDocumentNode().$element[0],
-                               this.$pasteTarget[0]
-                       ],
-                       rangy.getSelection( this.getElementDocument() 
).anchorNode,
-                       true
-               );
-       } catch ( ex ) {}
+       hasFocus = ve.contains(
+               [
+                       this.documentView.getDocumentNode().$element[0],
+                       this.$pasteTarget[0]
+               ],
+               this.nativeSelection.anchorNode,
+               true
+       );
 
        if ( hasFocus && !this.isFocused() ) {
                this.onDocumentFocus();
@@ -950,7 +945,7 @@
  * @param {jQuery.Event} e Copy event
  */
 ve.ce.Surface.prototype.onCopy = function ( e ) {
-       var rangyRange, sel, originalRange,
+       var nativeRange, originalRange,
                clipboardIndex, clipboardItem, pasteData,
                scrollTop, unsafeSelector,
                view = this,
@@ -1022,27 +1017,25 @@
                );
                // If direct clipboard editing is not allowed, we must use the 
pasteTarget to
                // select the data we want to go in the clipboard
-               rangyRange = rangy.createRange( this.getElementDocument() );
-               rangyRange.setStart( this.$pasteTarget[0], 0 );
-               rangyRange.setEnd( this.$pasteTarget[0], 
this.$pasteTarget[0].childNodes.length );
+               nativeRange = this.getElementDocument().createRange();
+               nativeRange.setStart( this.$pasteTarget[0], 0 );
+               nativeRange.setEnd( this.$pasteTarget[0], 
this.$pasteTarget[0].childNodes.length );
 
                // Save scroll position before changing focus to "offscreen" 
paste target
                scrollTop = this.$window.scrollTop();
 
-               sel = rangy.getSelection( this.getElementDocument() );
-               originalRange = sel.getRangeAt( 0 ).cloneRange();
-               sel.removeAllRanges();
+               originalRange = this.nativeSelection.getRangeAt( 0 
).cloneRange();
+               this.nativeSelection.removeAllRanges();
                this.$pasteTarget[0].focus();
-               sel.addRange( rangyRange, false );
+               this.nativeSelection.addRange( nativeRange );
                // Restore scroll position after changing focus
                this.$window.scrollTop( scrollTop );
 
                setTimeout( function () {
                        // Change focus back
-                       sel = rangy.getSelection( view.getElementDocument() );
-                       sel.removeAllRanges();
+                       view.nativeSelection.removeAllRanges();
                        view.documentView.getDocumentNode().$element[0].focus();
-                       sel.addRange( originalRange );
+                       view.nativeSelection.addRange( originalRange );
                        // Restore scroll position
                        view.$window.scrollTop( scrollTop );
                } );
@@ -1077,7 +1070,7 @@
  * @param {jQuery.Event} e Paste event
  */
 ve.ce.Surface.prototype.beforePaste = function ( e ) {
-       var tx, node, range, contextElement, rangyRange, sel,
+       var tx, node, range, contextElement, nativeRange,
                context, leftText, rightText, textNode, textStart, textEnd,
                selection = this.model.getSelection(),
                clipboardData = e.originalEvent.clipboardData,
@@ -1093,7 +1086,7 @@
        this.surfaceObserver.stopTimerLoop();
 
        // Pasting into a range? Remove first.
-       if ( !rangy.getSelection( this.$document[0] ).isCollapsed ) {
+       if ( !this.nativeSelection.isCollapsed ) {
                tx = ve.dm.Transaction.newFromRemoval( doc, selection );
                selection = tx.translateRange( selection );
                this.model.change( tx, selection );
@@ -1150,15 +1143,14 @@
                // so do it up here.
                this.$pasteTarget[0].focus();
 
-               rangyRange = rangy.createRange( this.getElementDocument() );
+               nativeRange = this.getElementDocument().createRange();
                // Assume that the DM node only generated one child
                textNode = this.$pasteTarget.children().contents()[0];
                // Place the cursor between the placeholder characters
-               rangyRange.setStart( textNode, textStart );
-               rangyRange.setEnd( textNode, textEnd );
-               sel = rangy.getSelection( this.getElementDocument() );
-               sel.removeAllRanges();
-               sel.addRange( rangyRange, false );
+               nativeRange.setStart( textNode, textStart );
+               nativeRange.setEnd( textNode, textEnd );
+               this.nativeSelection.removeAllRanges();
+               this.nativeSelection.addRange( nativeRange );
 
                this.beforePasteData.context = context;
                this.beforePasteData.leftText = leftText;
@@ -1189,7 +1181,7 @@
                selection = this.model.getSelection();
 
        // If the selection doesn't collapse after paste then nothing was 
inserted
-       if ( !rangy.getSelection( this.getElementDocument() ).isCollapsed ) {
+       if ( !this.nativeSelection.isCollapsed ) {
                return;
        }
 
@@ -1440,7 +1432,7 @@
  * @param {ve.Range|null} selection
  */
 ve.ce.Surface.prototype.onModelSelect = function ( selection ) {
-       var start, end, rangySel, rangyRange,
+       var start, end, nativeRange,
                next = null,
                previous = this.focusedNode;
 
@@ -1476,17 +1468,16 @@
                        next.setFocused( true );
                        this.focusedNode = next;
 
-                       rangySel = rangy.getSelection( 
this.getElementDocument() );
                        // As FF won't fire a copy event with nothing selected, 
make
                        // a dummy selection of one space in the pasteTarget.
                        // onCopy will ignore this native selection and use the 
DM selection
                        this.$pasteTarget.text( ' ' );
-                       rangyRange = rangy.createRange( 
this.getElementDocument() );
-                       rangyRange.setStart( this.$pasteTarget[0], 0 );
-                       rangyRange.setEnd( this.$pasteTarget[0], 1 );
-                       rangySel.removeAllRanges();
+                       nativeRange = this.getElementDocument().createRange();
+                       nativeRange.setStart( this.$pasteTarget[0], 0 );
+                       nativeRange.setEnd( this.$pasteTarget[0], 1 );
+                       this.nativeSelection.removeAllRanges();
                        this.$pasteTarget[0].focus();
-                       rangySel.addRange( rangyRange, false );
+                       this.nativeSelection.addRange( nativeRange );
                        // Since the selection is no longer in the 
documentNode, clear the SurfaceObserver's
                        // selection state. Otherwise, if the user places the 
selection back into the documentNode
                        // in exactly the same place where it was before, the 
observer won't consider that a change.
@@ -1820,7 +1811,8 @@
  * @param {jQuery.Event} e Up or down key down event
  */
 ve.ce.Surface.prototype.handleUpOrDownArrowKey = function ( e ) {
-       var selection, rangySelection, rangyRange, slug, $cursorHolder,
+       var selection, nativeRange, slug, $cursorHolder,
+               rangySelection = rangy.getSelection( this.getElementDocument() 
),
                direction = e.keyCode === OO.ui.Keys.DOWN ? 1 : -1;
 
        // TODO: onDocumentKeyDown did this already
@@ -1829,7 +1821,6 @@
        this.surfaceObserver.pollOnce();
 
        selection = this.model.getSelection();
-       rangySelection = rangy.getSelection( this.$document[0] );
 
        if ( this.focusedNode ) {
                $cursorHolder = this.$( '<span 
class="ve-ce-surface-cursorHolder"> </span>' ).hide();
@@ -1839,34 +1830,35 @@
                        $cursorHolder.insertAfter( 
this.focusedNode.$element.last() );
                }
        } else if ( !selection.isCollapsed() && selection.isBackwards() && 
!rangySelection.isBackwards() ) {
-               // Perform programatic handling for a selection that is 
expanded and backwards accordig to
+               // TODO: Implement our own isBackwards for native selections so 
we can kill rangy here
+               // Perform programatic handling for a selection that is 
expanded and backwards according to
                // model data but not according to browser data.
                slug = this.documentView.getSlugAtOffset( selection.to );
                if ( !slug ) {
                        $cursorHolder = this.$( '<span 
class="ve-ce-surface-cursorHolder"> </span>' ).hide();
-                       rangySelection.anchorNode.splitText( 
rangySelection.anchorOffset );
-                       rangySelection.anchorNode.parentNode.insertBefore(
+                       this.nativeSelection.anchorNode.splitText( 
this.nativeSelection.anchorOffset );
+                       this.nativeSelection.anchorNode.parentNode.insertBefore(
                                $cursorHolder[0],
-                               rangySelection.anchorNode.nextSibling
+                               this.nativeSelection.anchorNode.nextSibling
                        );
                }
        }
        if ( $cursorHolder || slug ) {
-               rangyRange = rangy.createRange( this.$document[0] );
-               rangyRange.selectNode( $cursorHolder ? $cursorHolder[0] : slug 
);
-               rangySelection.setSingleRange( rangyRange );
+               nativeRange = this.getElementDocument().createRange();
+               nativeRange.selectNode( $cursorHolder ? $cursorHolder[0] : slug 
);
+               this.nativeSelection.removeAllRanges();
+               this.nativeSelection.addRange( nativeRange );
        }
        setTimeout( ve.bind( function () {
-               var view, range;
+               var node, range;
                if ( $cursorHolder ) {
                        $cursorHolder.remove();
                        this.surfaceObserver.clear();
                }
-               rangySelection = rangy.getSelection( this.$document[0] );
                // Chrome bug lets you cursor into a multi-line 
contentEditable=false with up/down...
-               view = $( rangySelection.anchorNode ).closest( 
'.ve-ce-leafNode,.ve-ce-branchNode' ).data( 'view' );
-               if ( view.isFocusable() ) {
-                       range = direction === 1 ? view.getOuterRange() : 
view.getOuterRange().flip();
+               node = $( this.nativeSelection.anchorNode ).closest( 
'.ve-ce-leafNode,.ve-ce-branchNode' ).data( 'view' );
+               if ( node.isFocusable() ) {
+                       range = direction === 1 ? node.getOuterRange() : 
node.getOuterRange().flip();
                } else {
                        this.surfaceObserver.pollOnce();
                        range = new ve.Range( this.model.getSelection().to );
@@ -2270,19 +2262,26 @@
  * @param {ve.Range} range Range to show selection on
  */
 ve.ce.Surface.prototype.showSelection = function ( range ) {
-       var documentElement = this.documentView.getDocumentNode().$element[0],
-               selection = this.getSelection( range ),
-               rangySel = rangy.getSelection( this.$document[0] ),
-               rangyRange = rangy.createRange( this.$document[0] );
+       var endRange,
+               documentElement = 
this.documentView.getDocumentNode().$element[0],
+               rangeSelection = this.getRangeSelection( range ),
+               nativeRange = this.getElementDocument().createRange();
 
-       if ( selection.end ) {
-               rangyRange.setStart( selection.start.node, 
selection.start.offset );
-               rangyRange.setEnd( selection.end.node, selection.end.offset );
-               rangySel.removeAllRanges();
-               rangySel.addRange( rangyRange, selection.isBackwards );
+       this.nativeSelection.removeAllRanges();
+       if ( rangeSelection.end ) {
+               nativeRange.setStart( rangeSelection.start.node, 
rangeSelection.start.offset );
+               nativeRange.setEnd( rangeSelection.end.node, 
rangeSelection.end.offset );
+               if ( rangeSelection.isBackwards && this.nativeSelection.extend 
) {
+                       endRange = nativeRange.cloneRange();
+                       endRange.collapse( false );
+                       this.nativeSelection.addRange( endRange );
+                       this.nativeSelection.extend( 
nativeRange.startContainer, nativeRange.startOffset );
+               } else {
+                       this.nativeSelection.addRange( nativeRange );
+               }
        } else {
-               rangyRange.setStart( selection.start.node, 
selection.start.offset );
-               rangySel.setSingleRange( rangyRange );
+               nativeRange.setStart( rangeSelection.start.node, 
rangeSelection.start.offset );
+               this.nativeSelection.addRange( nativeRange );
        }
        // 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
@@ -2298,7 +2297,7 @@
  * @param {ve.Range} range Range to get selection for
  * @returns {Object} Object containing start and end node/offset selections, 
and an isBackwards flag.
  */
-ve.ce.Surface.prototype.getSelection = function ( range ) {
+ve.ce.Surface.prototype.getRangeSelection = function ( range ) {
        range = new ve.Range(
                this.getNearestCorrectOffset( range.from, -1 ),
                this.getNearestCorrectOffset( range.to, 1 )
@@ -2430,7 +2429,7 @@
        }
        // At the beginning of a node, take from the right
        if (
-               rangy.getSelection( this.$document[0] ).anchorOffset === 0 &&
+               this.nativeSelection.anchorOffset === 0 &&
                rightAnnotations &&
                !rightAnnotations.compareTo( insertionAnnotations )
        ) {
diff --git a/src/ce/ve.ce.SurfaceObserver.js b/src/ce/ve.ce.SurfaceObserver.js
index 8e5bb7a..fc8df6b 100644
--- a/src/ce/ve.ce.SurfaceObserver.js
+++ b/src/ce/ve.ce.SurfaceObserver.js
@@ -1,5 +1,3 @@
-/*global rangy */
-
 /*!
  * VisualEditor ContentEditable Surface class.
  *
@@ -72,7 +70,7 @@
  * @param {ve.Range} range Initial range to use
  */
 ve.ce.SurfaceObserver.prototype.clear = function ( range ) {
-       this.rangyRange = null;
+       this.domRange = null;
        this.range = range || null;
        this.node = null;
        this.text = null;
@@ -176,7 +174,7 @@
  * @fires selectionChange
  */
 ve.ce.SurfaceObserver.prototype.pollOnceInternal = function ( emitChanges ) {
-       var $nodeOrSlug, node, text, hash, range, rangyRange, $slugWrapper, 
observer = this;
+       var $nodeOrSlug, node, text, hash, range, domRange, $slugWrapper, 
observer = this;
 
        if ( !this.domDocument ) {
                return;
@@ -184,14 +182,14 @@
 
        range = this.range;
        node = this.node;
-       rangyRange = ve.ce.DomRange.newFromDomSelection( rangy.getSelection( 
this.domDocument ) );
+       domRange = ve.ce.DomRange.newFromDocument( this.domDocument );
 
-       if ( !rangyRange.equals( this.rangyRange ) ) {
-               this.rangyRange = rangyRange;
+       if ( !domRange.equals( this.domRange ) ) {
+               this.domRange = domRange;
                node = null;
-               $nodeOrSlug = $( rangyRange.anchorNode ).closest( 
'.ve-ce-branchNode, .ve-ce-branchNode-slug' );
+               $nodeOrSlug = $( domRange.anchorNode ).closest( 
'.ve-ce-branchNode, .ve-ce-branchNode-slug' );
                if ( $nodeOrSlug.length ) {
-                       range = rangyRange.getRange();
+                       range = domRange.getRange();
                        if ( $nodeOrSlug.hasClass( 've-ce-branchNode-slug' ) ) {
                                $slugWrapper = $nodeOrSlug.closest( 
'.ve-ce-branchNode-blockSlugWrapper' );
                        } else {
diff --git a/src/ui/ve.ui.Surface.js b/src/ui/ve.ui.Surface.js
index 8a01a29..d0d05d8 100644
--- a/src/ui/ve.ui.Surface.js
+++ b/src/ui/ve.ui.Surface.js
@@ -4,7 +4,6 @@
  * @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
  * @license The MIT License (MIT); see LICENSE.txt
  */
-/*global rangy */
 
 /**
  * A surface is a top-level object which contains both a surface model and a 
surface view.
@@ -408,7 +407,7 @@
 };
 
 ve.ui.Surface.prototype.initFilibuster = function () {
-       var uiSurface = this;
+       var surface = this;
        this.filibuster = new ve.Filibuster()
                .wrapClass( ve.EventSequencer )
                .wrapNamespace( ve.dm, 've.dm' )
@@ -419,30 +418,30 @@
                        ve.ui.Surface.prototype.stopFilibuster
                ] )
                .setObserver( 'dm doc', function () {
-                       return JSON.stringify( 
uiSurface.model.documentModel.data.data );
+                       return JSON.stringify( 
surface.model.documentModel.data.data );
                } )
                .setObserver( 'dm range', function () {
-                       var selection = uiSurface.model.selection;
+                       var selection = surface.model.selection;
                        if ( !selection ) {
                                return null;
                        }
                        return [ selection.from, selection.to ].join( ',' );
                } )
                .setObserver( 'DOM doc', function () {
-                       return uiSurface.view.$element.html();
+                       return surface.view.$element.html();
                } )
                .setObserver( 'DOM selection', function () {
-                       var range, sel;
-                       sel = rangy.getSelection( 
uiSurface.view.getElementDocument() );
-                       if ( sel.rangeCount === 0 ) {
+                       var nativeRange,
+                               nativeSelection = surface.view.nativeSelection;
+                       if ( nativeSelection.rangeCount === 0 ) {
                                return null;
                        }
-                       range = sel.getRangeAt( 0 );
+                       nativeRange = nativeSelection.getRangeAt( 0 );
                        return JSON.stringify( {
-                               startContainer: range.startContainer.outerHTML,
-                               startOffset: range.startOffset,
-                               endContainer: range.endContainer.outerHTML,
-                               endOffset: range.endOffset
+                               startContainer: 
nativeRange.startContainer.outerHTML,
+                               startOffset: nativeRange.startOffset,
+                               endContainer: 
nativeRange.endContainer.outerHTML,
+                               endOffset: nativeRange.endOffset
                        } );
                } );
 };
diff --git a/tests/ce/ve.ce.Surface.test.js b/tests/ce/ve.ce.Surface.test.js
index dd9a6a7..5748cb3 100644
--- a/tests/ce/ve.ce.Surface.test.js
+++ b/tests/ce/ve.ce.Surface.test.js
@@ -934,7 +934,7 @@
        }
 } );
 
-QUnit.test( 'getSelection', function ( assert ) {
+QUnit.test( 'getRangeSelection', function ( assert ) {
        var i, j, l, surface, selection, expectedNode, internlListNode, node, 
msg,
                expect = 0,
                cases = [
@@ -1061,7 +1061,7 @@
                        if ( node.isFocusable() ) {
                                assert.equal( null, cases[i].expected[j], 
'Focusable node at ' + j );
                        } else {
-                               selection = surface.getView().getSelection( new 
ve.Range( j ) );
+                               selection = 
surface.getView().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 );
diff --git a/tests/ce/ve.ce.TestRunner.js b/tests/ce/ve.ce.TestRunner.js
index 95ecd42..bb988ca 100644
--- a/tests/ce/ve.ce.TestRunner.js
+++ b/tests/ce/ve.ce.TestRunner.js
@@ -4,7 +4,6 @@
  * @copyright 2011-2014 VisualEditor Team and others; see AUTHORS.txt
  * @license The MIT License (MIT); see LICENSE.txt
  */
-/*global rangy */
 
 /**
  * Text offset from start or end of string
@@ -112,19 +111,20 @@
  *
  * @class
  * @constructor
- * @param {ve.ui.Surface} uiSurface The UI Surface
+ * @param {ve.ui.Surface} surface The UI Surface
  */
-ve.ce.TestRunner = function VeCeTestRunner( uiSurface ) {
+ve.ce.TestRunner = function VeCeTestRunner( surface ) {
        var testRunner,
                callId = 0;
-       this.uiSurface = uiSurface;
-       this.view = uiSurface.view;
-       this.model = uiSurface.model;
-       this.doc = uiSurface.getElementDocument();
+       this.surface = surface;
+       this.view = surface.view;
+       this.model = surface.model;
+       this.doc = surface.getElementDocument();
+       this.nativeSelection = surface.getElementWindow().getSelection();
        this.postponedCalls = {};
 
        // Turn off SurfaceObserver setTimeouts
-       uiSurface.view.surfaceObserver.frequency = null;
+       surface.view.surfaceObserver.frequency = null;
 
        // Take control of eventSequencer 'setTimeouts'
        testRunner = this;
@@ -146,7 +146,7 @@
  * @returns {Node} The paragraph node
  */
 
-ve.ce.TestRunner.prototype.getP = function () {
+ve.ce.TestRunner.prototype.getParagraph = function () {
        var p = this.view.$element.find( '.ve-ce-documentNode > p' )[0];
        if ( p === undefined ) {
                if ( this.view.$element.find( '.ve-ce-documentNode' )[0] === 
undefined ) {
@@ -196,22 +196,18 @@
  */
 ve.ce.TestRunner.prototype.changeText = function ( text ) {
        var extra,
-               range = null,
-               sel = rangy.getSelection( this.doc ),
-               ranges = sel.getAllRanges();
+               nativeRange = this.nativeSelection.getRangeAt( 0 );
 
-       if ( ranges.length > 0 ) {
-               range = ranges[0];
-       }
        // TODO: Enable multi-paragraph testing. For now, assuming one 
paragraph.
-       if ( range && range.startNode && text.startsWith( 
this.startNode.textContent ) ) {
+       // FIXME: renaming startNode to startContainer revealed failing tests
+       if ( false && nativeRange && nativeRange.startContainer && 
text.indexOf( nativeRange.startContainer.textContent ) === 0 ) {
                // We're just appending
-               extra = range.startNode.textContent.substring( 
range.startNode.textContent.length );
-               // This is fine IF startNode is a TextNode
-               range.startNode.textContent += extra;
+               extra = nativeRange.startContainer.textContent.substring( 
nativeRange.startContainer.textContent.length );
+               // This is fine IF startContainer is a TextNode
+               nativeRange.startContainer.textContent += extra;
        } else {
                // Wipe out the node
-               this.getP().textContent = text;
+               this.getParagraph().textContent = text;
        }
        this.lastText = text;
 };
@@ -228,7 +224,7 @@
  * @returns {number} return.endOffset The endoffset within the node
  */
 ve.ce.TestRunner.prototype.changeSel = function ( start, end ) {
-       var foundStart, foundEnd, rangyRange, sel;
+       var foundStart, foundEnd, nativeRange;
        if ( typeof start === 'number' ) {
                start = new ve.ce.TestOffset( 'forward', start );
        }
@@ -236,8 +232,8 @@
                end = new ve.ce.TestOffset( 'forward', end );
        }
 
-       foundStart = start.resolve( this.getP() );
-       foundEnd = start.resolve( this.getP() );
+       foundStart = start.resolve( this.getParagraph() );
+       foundEnd = start.resolve( this.getParagraph() );
        if ( !foundStart.node ) {
                throw new Error( 'Bad start offset: ' + start.offset );
        }
@@ -245,13 +241,12 @@
                throw new Error( 'Bad end offset: ', end.offset );
        }
 
-       rangyRange = rangy.createRange( this.doc );
-       rangyRange.setStart( foundStart.node, foundStart.offset );
-       rangyRange.setEnd( foundEnd.node, foundEnd.offset );
-       sel = rangy.getSelection( this.doc );
-       sel.removeAllRanges();
-       this.getP().focus();
-       sel.addRange( rangyRange, false );
+       nativeRange = this.doc.createRange();
+       nativeRange.setStart( foundStart.node, foundStart.offset );
+       nativeRange.setEnd( foundEnd.node, foundEnd.offset );
+       this.nativeSelection.removeAllRanges();
+       this.getParagraph().focus();
+       this.nativeSelection.addRange( nativeRange, false );
        this.lastSel = [start, end];
 
        return {

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

Gerrit-MessageType: merged
Gerrit-Change-Id: If6f5f59f96b0787b0a4545d430dae3ef0b8deb4d
Gerrit-PatchSet: 5
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

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

Reply via email to