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

Change subject: Move getRelativeOffset, getRelativeRange, 
getNearestFocusableNode to model
......................................................................


Move getRelativeOffset, getRelativeRange, getNearestFocusableNode to model

Bonus: Remove ve.dm.Node.getOuterRange get override which was providing
less functionality than ve.Node.

Change-Id: I76f9476c25a64157165fe24fe889d7b9b1020451
---
M src/ce/ve.ce.Document.js
M src/ce/ve.ce.Surface.js
M src/dm/ve.dm.Document.js
M src/dm/ve.dm.Node.js
M tests/ce/ve.ce.Document.test.js
M tests/dm/ve.dm.Document.test.js
6 files changed, 440 insertions(+), 454 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 3392ddc..de968cf 100644
--- a/src/ce/ve.ce.Document.js
+++ b/src/ce/ve.ce.Document.js
@@ -64,90 +64,6 @@
 };
 
 /**
- * Get the nearest word boundary.
- * This method is in CE instead of DM because its behaviour depends on the 
browser (IE/non-IE) and
- * that information is closer to view layer. (CE)
- *
- * @method
- * @param {number} offset Offset to start from
- * @param {number} [direction] Direction to prefer matching offset in, -1 for 
left and 1 for right
- * @returns {number} Nearest word boundary
- */
-ve.ce.Document.prototype.getSiblingWordBoundary = function ( offset, direction 
) {
-       var dataString = new ve.dm.DataString( this.model.getData() );
-       return unicodeJS.wordbreak.moveBreakOffset( direction, dataString, 
offset, true );
-};
-
-/**
- * Get the relative word or character boundary.
- *
- * This method is in CE instead of DM because it uses information about slugs 
about which model
- * does not know at all.
- *
- * @method
- * @param {number} offset Offset to start from
- * @param {number} direction Direction to prefer matching offset in, -1 for 
left and 1 for right
- * @param {string} [unit] Unit [word|character]
- * @returns {number} Relative offset
- */
-ve.ce.Document.prototype.getRelativeOffset = function ( offset, direction, 
unit ) {
-       var relativeContentOffset, relativeStructuralOffset, newOffset, 
adjacentDataOffset, isFocusable,
-               data = this.model.data;
-       if ( unit === 'word' ) { // word
-               // Method getSiblingWordBoundary does not "move/jump" over 
element data. If passed offset is
-               // an element data offset then the same offset is returned - 
and in such case this method
-               // fallback to the other path (character) which does 
"move/jump" over element data.
-               newOffset = this.getSiblingWordBoundary( offset, direction );
-               if ( offset === newOffset ) {
-                       newOffset = this.getRelativeOffset( offset, direction, 
'character' );
-               }
-               return newOffset;
-       } else { // character
-               // Check if we are adjacent to a focusable node
-               adjacentDataOffset = offset + ( direction > 0 ? 0 : -1 );
-               if (
-                       data.isElementData( adjacentDataOffset ) &&
-                       ve.dm.nodeFactory.isNodeFocusable( data.getType( 
adjacentDataOffset ) )
-               ) {
-                       // We are adjacent to a focusableNode, move inside it
-                       return offset + direction;
-               }
-               relativeContentOffset = data.getRelativeContentOffset( offset, 
direction );
-               relativeStructuralOffset = data.getRelativeStructuralOffset( 
offset, direction, true );
-               // Check the structural offset is not in the wrong direction
-               if ( ( relativeStructuralOffset - offset < 0 ? -1 : 1 ) !== 
direction ) {
-                       relativeStructuralOffset = offset;
-               } else {
-                       isFocusable = ( relativeStructuralOffset - offset < 0 ? 
-1 : 1 ) === direction &&
-                               data.isElementData( relativeStructuralOffset + 
direction ) &&
-                               ve.dm.nodeFactory.isNodeFocusable( 
data.getType( relativeStructuralOffset + direction ) );
-               }
-               // Check if we've moved into a slug or a focusableNode
-               if ( isFocusable || this.getSlugAtOffset( 
relativeStructuralOffset ) ) {
-                       if ( isFocusable ) {
-                               relativeStructuralOffset += direction;
-                       }
-                       // Check if the relative content offset is in the 
opposite direction we are trying to go
-                       if (
-                               relativeContentOffset === offset ||
-                               ( relativeContentOffset - offset < 0 ? -1 : 1 ) 
!== direction
-                       ) {
-                               return relativeStructuralOffset;
-                       }
-                       // There's a slug neaby, go into it if it's closer
-                       return direction > 0 ?
-                               Math.min( relativeContentOffset, 
relativeStructuralOffset ) :
-                               Math.max( relativeContentOffset, 
relativeStructuralOffset );
-               } else {
-                       // Don't allow the offset to move in the wrong direction
-                       return direction > 0 ?
-                               Math.max( relativeContentOffset, offset ) :
-                               Math.min( relativeContentOffset, offset );
-               }
-       }
-};
-
-/**
  * Get a DOM node and DOM element offset for a document offset.
  *
  * @method
@@ -219,93 +135,6 @@
                current[1]++;
        }
        throw new Error( 'Offset could not be translated to a DOM element and 
offset: ' + offset );
-};
-
-/**
- * Get the nearest focusable node.
- *
- * @method
- * @param {number} offset Offset to start looking at
- * @param {number} direction Direction to look in, +1 or -1
- * @param {number} limit Stop looking after reaching certain offset
- */
-ve.ce.Document.prototype.getNearestFocusableNode = function ( offset, 
direction, limit ) {
-       // It is never an offset of the node, but just an offset for which 
getNodeFromOffset should
-       // return that node. Usually it would be node offset + 1 or offset of 
node closing tag.
-       var coveredOffset;
-       this.model.data.getRelativeOffset(
-               offset,
-               direction === 1 ? 0 : -1,
-               function ( index, limit ) {
-                       // Our result must be between offset and limit
-                       if ( index >= Math.max( offset, limit ) || index < 
Math.min( offset, limit ) ) {
-                               return true;
-                       }
-                       if (
-                               this.isOpenElementData( index ) &&
-                               ve.dm.nodeFactory.isNodeFocusable( 
this.getType( index ) )
-                       ) {
-                               coveredOffset = index + 1;
-                               return true;
-                       }
-                       if (
-                               this.isCloseElementData( index ) &&
-                               ve.dm.nodeFactory.isNodeFocusable( 
this.getType( index ) )
-                       ) {
-                               coveredOffset = index;
-                               return true;
-                       }
-               },
-               limit
-       );
-       if ( coveredOffset ) {
-               return this.getDocumentNode().getNodeFromOffset( coveredOffset 
);
-       } else {
-               return null;
-       }
-};
-
-/**
- * Get the relative range.
- *
- * @method
- * @param {ve.Range} range Input range
- * @param {number} direction Direction to look in, +1 or -1
- * @param {string} unit Unit [word|character]
- * @param {boolean} expand Expanding range
- * @returns {ve.Range} Relative range
- */
-ve.ce.Document.prototype.getRelativeRange = function ( range, direction, unit, 
expand ) {
-       var contentOrSlugOffset,
-               focusableNode,
-               newOffset,
-               newRange,
-               to = range.to;
-
-       // If you have a non-collapsed range and you move, collapse to the end
-       // in the direction you moved, provided you end up at a content or slug 
offset
-       if ( !range.isCollapsed() && !expand ) {
-               newOffset = direction > 0 ? range.end : range.start;
-               if ( this.model.data.isContentOffset( newOffset ) || 
this.getSlugAtOffset( newOffset ) ) {
-                       return new ve.Range( newOffset );
-               } else {
-                       to = newOffset;
-               }
-       }
-
-       contentOrSlugOffset = this.getRelativeOffset( to, direction, unit );
-
-       focusableNode = this.getNearestFocusableNode( to, direction, 
contentOrSlugOffset );
-       if ( focusableNode ) {
-               newRange = focusableNode.getOuterRange( direction === -1 );
-       } else {
-               newRange = new ve.Range( contentOrSlugOffset );
-       }
-       if ( expand ) {
-               return new ve.Range( range.from, newRange.to );
-       } else {
-               return newRange;
-       }
 };
 
 /**
diff --git a/src/ce/ve.ce.Surface.js b/src/ce/ve.ce.Surface.js
index acc651d..ae6e3b1 100644
--- a/src/ce/ve.ce.Surface.js
+++ b/src/ce/ve.ce.Surface.js
@@ -1876,7 +1876,7 @@
                direction = e.keyCode === OO.ui.Keys.LEFT ? -1 : 1;
        }
 
-       range = this.getDocument().getRelativeRange(
+       range = this.model.getDocument().getRelativeRange(
                selection,
                direction,
                ( e.altKey === true || e.ctrlKey === true ) ? 'word' : 
'character',
@@ -2250,7 +2250,7 @@
        if ( direction && rangeToRemove.isCollapsed() ) {
                // In case when the range is collapsed use the same logic that 
is used for cursor left and
                // right movement in order to figure out range to remove.
-               rangeToRemove = documentView.getRelativeRange(
+               rangeToRemove = documentModel.getRelativeRange(
                        rangeToRemove,
                        direction,
                        ( e.altKey === true || e.ctrlKey === true ) ? 'word' : 
'character',
@@ -2340,7 +2340,7 @@
        }
        // rangeAfterRemove is now guaranteed to be collapsed so make sure that 
it is a content offset
        if ( !documentModel.data.isContentOffset( rangeAfterRemove.start ) ) {
-               rangeAfterRemove = documentView.getRelativeRange(
+               rangeAfterRemove = documentModel.getRelativeRange(
                        rangeAfterRemove,
                        // If direction === 0 (cut), default to backwards 
movement
                        direction || -1
diff --git a/src/dm/ve.dm.Document.js b/src/dm/ve.dm.Document.js
index 4ac7d5f..0217196 100644
--- a/src/dm/ve.dm.Document.js
+++ b/src/dm/ve.dm.Document.js
@@ -590,6 +590,172 @@
 };
 
 /**
+ * Get the nearest word boundary.
+ *
+ * @method
+ * @param {number} offset Offset to start from
+ * @param {number} [direction] Direction to prefer matching offset in, -1 for 
left and 1 for right
+ * @returns {number} Nearest word boundary
+ */
+ve.dm.Document.prototype.getSiblingWordBoundary = function ( offset, direction 
) {
+       var dataString = new ve.dm.DataString( this.getData() );
+       return unicodeJS.wordbreak.moveBreakOffset( direction, dataString, 
offset, true );
+};
+
+/**
+ * Get the relative word or character boundary.
+ *
+ * @method
+ * @param {number} offset Offset to start from
+ * @param {number} direction Direction to prefer matching offset in, -1 for 
left and 1 for right
+ * @param {string} [unit] Unit [word|character]
+ * @returns {number} Relative offset
+ */
+ve.dm.Document.prototype.getRelativeOffset = function ( offset, direction, 
unit ) {
+       var relativeContentOffset, relativeStructuralOffset, newOffset, 
adjacentDataOffset, isFocusable,
+               data = this.data;
+       if ( unit === 'word' ) { // word
+               // Method getSiblingWordBoundary does not "move/jump" over 
element data. If passed offset is
+               // an element data offset then the same offset is returned - 
and in such case this method
+               // fallback to the other path (character) which does 
"move/jump" over element data.
+               newOffset = this.getSiblingWordBoundary( offset, direction );
+               if ( offset === newOffset ) {
+                       newOffset = this.getRelativeOffset( offset, direction, 
'character' );
+               }
+               return newOffset;
+       } else { // character
+               // Check if we are adjacent to a focusable node
+               adjacentDataOffset = offset + ( direction > 0 ? 0 : -1 );
+               if (
+                       data.isElementData( adjacentDataOffset ) &&
+                       ve.dm.nodeFactory.isNodeFocusable( data.getType( 
adjacentDataOffset ) )
+               ) {
+                       // We are adjacent to a focusableNode, move inside it
+                       return offset + direction;
+               }
+               relativeContentOffset = data.getRelativeContentOffset( offset, 
direction );
+               relativeStructuralOffset = data.getRelativeStructuralOffset( 
offset, direction, true );
+               // Check the structural offset is not in the wrong direction
+               if ( ( relativeStructuralOffset - offset < 0 ? -1 : 1 ) !== 
direction ) {
+                       relativeStructuralOffset = offset;
+               } else {
+                       isFocusable = ( relativeStructuralOffset - offset < 0 ? 
-1 : 1 ) === direction &&
+                               data.isElementData( relativeStructuralOffset + 
direction ) &&
+                               ve.dm.nodeFactory.isNodeFocusable( 
data.getType( relativeStructuralOffset + direction ) );
+               }
+               // Check if we've moved into a slug or a focusableNode
+               if ( isFocusable || this.hasSlugAtOffset( 
relativeStructuralOffset ) ) {
+                       if ( isFocusable ) {
+                               relativeStructuralOffset += direction;
+                       }
+                       // Check if the relative content offset is in the 
opposite direction we are trying to go
+                       if (
+                               relativeContentOffset === offset ||
+                               ( relativeContentOffset - offset < 0 ? -1 : 1 ) 
!== direction
+                       ) {
+                               return relativeStructuralOffset;
+                       }
+                       // There's a slug neaby, go into it if it's closer
+                       return direction > 0 ?
+                               Math.min( relativeContentOffset, 
relativeStructuralOffset ) :
+                               Math.max( relativeContentOffset, 
relativeStructuralOffset );
+               } else {
+                       // Don't allow the offset to move in the wrong direction
+                       return direction > 0 ?
+                               Math.max( relativeContentOffset, offset ) :
+                               Math.min( relativeContentOffset, offset );
+               }
+       }
+};
+
+/**
+ * Get the relative range.
+ *
+ * @method
+ * @param {ve.Range} range Input range
+ * @param {number} direction Direction to look in, +1 or -1
+ * @param {string} unit Unit [word|character]
+ * @param {boolean} expand Expanding range
+ * @returns {ve.Range} Relative range
+ */
+ve.dm.Document.prototype.getRelativeRange = function ( range, direction, unit, 
expand ) {
+       var contentOrSlugOffset,
+               focusableNode,
+               newOffset,
+               newRange,
+               to = range.to;
+
+       // If you have a non-collapsed range and you move, collapse to the end
+       // in the direction you moved, provided you end up at a content or slug 
offset
+       if ( !range.isCollapsed() && !expand ) {
+               newOffset = direction > 0 ? range.end : range.start;
+               if ( this.data.isContentOffset( newOffset ) || 
this.hasSlugAtOffset( newOffset ) ) {
+                       return new ve.Range( newOffset );
+               } else {
+                       to = newOffset;
+               }
+       }
+
+       contentOrSlugOffset = this.getRelativeOffset( to, direction, unit );
+
+       focusableNode = this.getNearestFocusableNode( to, direction, 
contentOrSlugOffset );
+       if ( focusableNode ) {
+               newRange = focusableNode.getOuterRange( direction === -1 );
+       } else {
+               newRange = new ve.Range( contentOrSlugOffset );
+       }
+       if ( expand ) {
+               return new ve.Range( range.from, newRange.to );
+       } else {
+               return newRange;
+       }
+};
+
+/**
+ * Get the nearest focusable node.
+ *
+ * @method
+ * @param {number} offset Offset to start looking at
+ * @param {number} direction Direction to look in, +1 or -1
+ * @param {number} limit Stop looking after reaching certain offset
+ */
+ve.dm.Document.prototype.getNearestFocusableNode = function ( offset, 
direction, limit ) {
+       // It is never an offset of the node, but just an offset for which 
getNodeFromOffset should
+       // return that node. Usually it would be node offset + 1 or offset of 
node closing tag.
+       var coveredOffset;
+       this.data.getRelativeOffset(
+               offset,
+               direction === 1 ? 0 : -1,
+               function ( index, limit ) {
+                       // Our result must be between offset and limit
+                       if ( index >= Math.max( offset, limit ) || index < 
Math.min( offset, limit ) ) {
+                               return true;
+                       }
+                       if (
+                               this.isOpenElementData( index ) &&
+                               ve.dm.nodeFactory.isNodeFocusable( 
this.getType( index ) )
+                       ) {
+                               coveredOffset = index + 1;
+                               return true;
+                       }
+                       if (
+                               this.isCloseElementData( index ) &&
+                               ve.dm.nodeFactory.isNodeFocusable( 
this.getType( index ) )
+                       ) {
+                               coveredOffset = index;
+                               return true;
+                       }
+               },
+               limit
+       );
+       if ( coveredOffset ) {
+               return this.getDocumentNode().getNodeFromOffset( coveredOffset 
);
+       } else {
+               return null;
+       }
+};
+
+/**
  * Get a node from an offset.
  *
  * @method
diff --git a/src/dm/ve.dm.Node.js b/src/dm/ve.dm.Node.js
index 24b6604..90b52fb 100644
--- a/src/dm/ve.dm.Node.js
+++ b/src/dm/ve.dm.Node.js
@@ -494,17 +494,6 @@
 };
 
 /**
- * Get the range outside the node.
- *
- * @method
- * @returns {ve.Range} Outer node range
- */
-ve.dm.Node.prototype.getOuterRange = function () {
-       var offset = this.getOffset();
-       return new ve.Range( offset, offset + this.getOuterLength() );
-};
-
-/**
  * Set the inner length of the node.
  *
  * This should only be called after a relevant change to the document data. 
Calling this method will
diff --git a/tests/ce/ve.ce.Document.test.js b/tests/ce/ve.ce.Document.test.js
index a0df564..ef0f43a 100644
--- a/tests/ce/ve.ce.Document.test.js
+++ b/tests/ce/ve.ce.Document.test.js
@@ -9,272 +9,7 @@
 
 /* Tests */
 
-QUnit.test( 'getRelativeOffset', function ( assert ) {
-       var documentModel = ve.dm.example.createExampleDocument( 'alienData' ),
-               surface = ve.test.utils.createSurfaceFromDocument( 
documentModel ),
-               documentView = surface.getView().getDocument(),
-               tests = [
-                       {
-                               direction: 1,
-                               unit: 'character',
-                               cases: [
-                                       { input: 0, output: 1 },
-                                       { input: 2, output: 3 },
-                                       { input: 3, output: 4 },
-                                       { input: 4, output: 5 },
-                                       { input: 6, output: 7 },
-                                       { input: 7, output: 9 },
-                                       { input: 10, output: 10 }
-                               ]
-                       },
-                       {
-                               direction: 1,
-                               unit: 'word',
-                               cases: [
-                                       { input: 0, output: 1 },
-                                       { input: 2, output: 3 },
-                                       { input: 3, output: 4 },
-                                       { input: 4, output: 5 },
-                                       { input: 6, output: 7 },
-                                       { input: 7, output: 9 },
-                                       { input: 10, output: 10 }
-                               ]
-                       },
-                       {
-                               direction: -1,
-                               unit: 'character',
-                               cases: [
-                                       { input: 10, output: 9 },
-                                       { input: 8, output: 7 },
-                                       { input: 7, output: 6 },
-                                       { input: 6, output: 5 },
-                                       { input: 4, output: 3 },
-                                       { input: 3, output: 1 },
-                                       { input: 0, output: 0 }
-                               ]
-                       },
-                       {
-                               direction: -1,
-                               unit: 'word',
-                               cases: [
-                                       { input: 10, output: 9 },
-                                       { input: 8, output: 7 },
-                                       { input: 7, output: 6 },
-                                       { input: 6, output: 5 },
-                                       { input: 4, output: 3 },
-                                       { input: 3, output: 1 },
-                                       { input: 0, output: 0 }
-                               ]
-                       }
-               ], i, j, expectCount = 0;
-       for ( i = 0; i < tests.length; i++ ) {
-               for ( j = 0; j < tests[i].cases.length; j++ ) {
-                       assert.strictEqual(
-                               documentView.getRelativeOffset(
-                                       tests[i].cases[j].input,
-                                       tests[i].direction,
-                                       tests[i].unit
-                               ),
-                               tests[i].cases[j].output,
-                               tests[i].cases[j].input + ', ' + 
tests[i].direction + ', ' + tests[i].unit
-                       );
-               }
-               expectCount += tests[i].cases.length;
-       }
-       QUnit.expect( expectCount );
-       surface.destroy();
-} );
-
-QUnit.test( 'getRelativeRange', function ( assert ) {
-       var documentModel, surface, documentView, i, j, expectCount = 0,
-               tests = [
-                       {
-                               data: [
-                                       /* 0 */ { type: 'paragraph' },
-                                       /* 1 */ 'a',
-                                       /* 2 */ { type: 'alienInline' },
-                                       /* 3 */ { type: '/alienInline' },
-                                       /* 4 */ 'b',
-                                       /* 5 */ { type: '/paragraph' }
-                               ],
-                               cases: [
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 1 ),
-                                               expected: new ve.Range( 2 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 2 ),
-                                               expected: new ve.Range( 2, 4 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 2, 4 ),
-                                               expected: new ve.Range( 4 )
-                                       },
-
-                                       {
-                                               direction: 1,
-                                               expand: true,
-                                               given: new ve.Range( 1 ),
-                                               expected: new ve.Range( 1, 2 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               expand: true,
-                                               given: new ve.Range( 1, 2 ),
-                                               expected: new ve.Range( 1, 4 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               expand: true,
-                                               given: new ve.Range( 1, 4 ),
-                                               expected: new ve.Range( 1, 5 )
-                                       }
-                               ]
-                       },
-                       {
-                               data: [
-                                       /* 0 */ { type: 'paragraph' },
-                                       /* 1 */ { type: 'alienInline' },
-                                       /* 2 */ { type: '/alienInline' },
-                                       /* 3 */ { type: 'alienInline' },
-                                       /* 4 */ { type: '/alienInline' },
-                                       /* 5 */ { type: '/paragraph' }
-                               ],
-                               cases: [
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 3 ),
-                                               expected: new ve.Range( 3, 5 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               expand: true,
-                                               given: new ve.Range( 1, 3 ),
-                                               expected: new ve.Range( 1, 5 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               expand: true,
-                                               given: new ve.Range( 1, 5 ),
-                                               expected: new ve.Range( 1, 3 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               expand: true,
-                                               given: new ve.Range( 5, 1 ),
-                                               expected: new ve.Range( 5, 3 )
-                                       }
-                               ]
-                       },
-                       {
-                               data: ve.copy( ve.dm.example.alienData ),
-                               cases: [
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 0 ),
-                                               expected: new ve.Range( 0, 2 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 0, 2 ),
-                                               expected: new ve.Range( 3 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 3 ),
-                                               expected: new ve.Range( 4 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 4 ),
-                                               expected: new ve.Range( 4, 6 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 4, 6),
-                                               expected: new ve.Range( 6 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 6 ),
-                                               expected: new ve.Range( 7 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 7 ),
-                                               expected: new ve.Range( 8, 10 )
-                                       },
-                                       {
-                                               direction: 1,
-                                               given: new ve.Range( 10 ),
-                                               expected: new ve.Range( 10 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 10 ),
-                                               expected: new ve.Range( 10, 8 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 10, 8 ),
-                                               expected: new ve.Range( 7 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 7 ),
-                                               expected: new ve.Range( 6 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 6 ),
-                                               expected: new ve.Range( 6, 4 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 6, 4 ),
-                                               expected: new ve.Range( 4 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 4 ),
-                                               expected: new ve.Range( 3 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 3 ),
-                                               expected: new ve.Range( 2, 0 )
-                                       },
-                                       {
-                                               direction: -1,
-                                               given: new ve.Range( 2, 0 ),
-                                               expected: new ve.Range( 0 )
-                                       }
-                               ]
-                       }
-               ];
-       for ( i = 0; i < tests.length; i++ ) {
-               documentModel = new ve.dm.Document( tests[i].data );
-               surface = ve.test.utils.createSurfaceFromDocument( 
documentModel );
-               documentView = surface.getView().getDocument();
-               for ( j = 0; j < tests[i].cases.length; j++ ) {
-                       expectCount++;
-                       assert.equalRange(
-                               documentView.getRelativeRange(
-                                       tests[i].cases[j].given,
-                                       tests[i].cases[j].direction,
-                                       'character',
-                                       !!tests[i].cases[j].expand
-                               ),
-                               tests[i].cases[j].expected,
-                               'Test document ' + i +
-                               ', range ' + tests[i].cases[j].given.toJSON() +
-                               ', direction ' + tests[i].cases[j].direction
-                       );
-               }
-               surface.destroy();
-       }
-       QUnit.expect( expectCount );
-} );
+// TODO: getNodeFromOffset
+// TODO: getSlugAtOffset
+// TODO: getNodeAndOffset
+// TODO: getDirectionFromRange
diff --git a/tests/dm/ve.dm.Document.test.js b/tests/dm/ve.dm.Document.test.js
index 6506aef..c89bf77 100644
--- a/tests/dm/ve.dm.Document.test.js
+++ b/tests/dm/ve.dm.Document.test.js
@@ -123,6 +123,273 @@
        }
 } );
 
+QUnit.test( 'getRelativeOffset', function ( assert ) {
+       var i, j,
+               expectCount = 0,
+               documentModel = ve.dm.example.createExampleDocument( 
'alienData' ),
+               tests = [
+                       {
+                               direction: 1,
+                               unit: 'character',
+                               cases: [
+                                       { input: 0, output: 1 },
+                                       { input: 2, output: 3 },
+                                       { input: 3, output: 4 },
+                                       { input: 4, output: 5 },
+                                       { input: 6, output: 7 },
+                                       { input: 7, output: 9 },
+                                       { input: 10, output: 10 }
+                               ]
+                       },
+                       {
+                               direction: 1,
+                               unit: 'word',
+                               cases: [
+                                       { input: 0, output: 1 },
+                                       { input: 2, output: 3 },
+                                       { input: 3, output: 4 },
+                                       { input: 4, output: 5 },
+                                       { input: 6, output: 7 },
+                                       { input: 7, output: 9 },
+                                       { input: 10, output: 10 }
+                               ]
+                       },
+                       {
+                               direction: -1,
+                               unit: 'character',
+                               cases: [
+                                       { input: 10, output: 9 },
+                                       { input: 8, output: 7 },
+                                       { input: 7, output: 6 },
+                                       { input: 6, output: 5 },
+                                       { input: 4, output: 3 },
+                                       { input: 3, output: 1 },
+                                       { input: 0, output: 0 }
+                               ]
+                       },
+                       {
+                               direction: -1,
+                               unit: 'word',
+                               cases: [
+                                       { input: 10, output: 9 },
+                                       { input: 8, output: 7 },
+                                       { input: 7, output: 6 },
+                                       { input: 6, output: 5 },
+                                       { input: 4, output: 3 },
+                                       { input: 3, output: 1 },
+                                       { input: 0, output: 0 }
+                               ]
+                       }
+               ];
+       for ( i = 0; i < tests.length; i++ ) {
+               for ( j = 0; j < tests[i].cases.length; j++ ) {
+                       assert.strictEqual(
+                               documentModel.getRelativeOffset(
+                                       tests[i].cases[j].input,
+                                       tests[i].direction,
+                                       tests[i].unit
+                               ),
+                               tests[i].cases[j].output,
+                               tests[i].cases[j].input + ', ' + 
tests[i].direction + ', ' + tests[i].unit
+                       );
+               }
+               expectCount += tests[i].cases.length;
+       }
+       QUnit.expect( expectCount );
+} );
+
+QUnit.test( 'getRelativeRange', function ( assert ) {
+       var documentModel, i, j,
+               expectCount = 0,
+               tests = [
+                       {
+                               data: [
+                                       /* 0 */ { type: 'paragraph' },
+                                       /* 1 */ 'a',
+                                       /* 2 */ { type: 'alienInline' },
+                                       /* 3 */ { type: '/alienInline' },
+                                       /* 4 */ 'b',
+                                       /* 5 */ { type: '/paragraph' }
+                               ],
+                               cases: [
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 1 ),
+                                               expected: new ve.Range( 2 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 2 ),
+                                               expected: new ve.Range( 2, 4 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 2, 4 ),
+                                               expected: new ve.Range( 4 )
+                                       },
+
+                                       {
+                                               direction: 1,
+                                               expand: true,
+                                               given: new ve.Range( 1 ),
+                                               expected: new ve.Range( 1, 2 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               expand: true,
+                                               given: new ve.Range( 1, 2 ),
+                                               expected: new ve.Range( 1, 4 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               expand: true,
+                                               given: new ve.Range( 1, 4 ),
+                                               expected: new ve.Range( 1, 5 )
+                                       }
+                               ]
+                       },
+                       {
+                               data: [
+                                       /* 0 */ { type: 'paragraph' },
+                                       /* 1 */ { type: 'alienInline' },
+                                       /* 2 */ { type: '/alienInline' },
+                                       /* 3 */ { type: 'alienInline' },
+                                       /* 4 */ { type: '/alienInline' },
+                                       /* 5 */ { type: '/paragraph' }
+                               ],
+                               cases: [
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 3 ),
+                                               expected: new ve.Range( 3, 5 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               expand: true,
+                                               given: new ve.Range( 1, 3 ),
+                                               expected: new ve.Range( 1, 5 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               expand: true,
+                                               given: new ve.Range( 1, 5 ),
+                                               expected: new ve.Range( 1, 3 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               expand: true,
+                                               given: new ve.Range( 5, 1 ),
+                                               expected: new ve.Range( 5, 3 )
+                                       }
+                               ]
+                       },
+                       {
+                               data: ve.copy( ve.dm.example.alienData ),
+                               cases: [
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 0 ),
+                                               expected: new ve.Range( 0, 2 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 0, 2 ),
+                                               expected: new ve.Range( 3 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 3 ),
+                                               expected: new ve.Range( 4 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 4 ),
+                                               expected: new ve.Range( 4, 6 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 4, 6),
+                                               expected: new ve.Range( 6 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 6 ),
+                                               expected: new ve.Range( 7 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 7 ),
+                                               expected: new ve.Range( 8, 10 )
+                                       },
+                                       {
+                                               direction: 1,
+                                               given: new ve.Range( 10 ),
+                                               expected: new ve.Range( 10 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 10 ),
+                                               expected: new ve.Range( 10, 8 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 10, 8 ),
+                                               expected: new ve.Range( 7 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 7 ),
+                                               expected: new ve.Range( 6 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 6 ),
+                                               expected: new ve.Range( 6, 4 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 6, 4 ),
+                                               expected: new ve.Range( 4 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 4 ),
+                                               expected: new ve.Range( 3 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 3 ),
+                                               expected: new ve.Range( 2, 0 )
+                                       },
+                                       {
+                                               direction: -1,
+                                               given: new ve.Range( 2, 0 ),
+                                               expected: new ve.Range( 0 )
+                                       }
+                               ]
+                       }
+               ];
+       for ( i = 0; i < tests.length; i++ ) {
+               documentModel = new ve.dm.Document( tests[i].data );
+               for ( j = 0; j < tests[i].cases.length; j++ ) {
+                       expectCount++;
+                       assert.equalRange(
+                               documentModel.getRelativeRange(
+                                       tests[i].cases[j].given,
+                                       tests[i].cases[j].direction,
+                                       'character',
+                                       !!tests[i].cases[j].expand
+                               ),
+                               tests[i].cases[j].expected,
+                               'Test document ' + i +
+                               ', range ' + tests[i].cases[j].given.toJSON() +
+                               ', direction ' + tests[i].cases[j].direction
+                       );
+               }
+       }
+       QUnit.expect( expectCount );
+} );
+
 QUnit.test( 'getNodeFromOffset', function ( assert ) {
        var i, j, node,
                doc = ve.dm.example.createExampleDocument(),

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

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

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

Reply via email to