Esanders has uploaded a new change for review.

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

Change subject: Restrict get relative offset to movements of +/-1
......................................................................

Restrict get relative offset to movements of +/-1

Moving in steps of greater than one is never done, and
would break the handlesOwnChildren detection.

Change-Id: Ic34563d6fed4f7c0aa348cc82c20a72f9f7531fb
---
M modules/ve/dm/lineardata/ve.dm.ElementLinearData.js
M modules/ve/test/dm/lineardata/ve.dm.ElementLinearData.test.js
2 files changed, 69 insertions(+), 152 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/VisualEditor/VisualEditor 
refs/changes/46/144046/1

diff --git a/modules/ve/dm/lineardata/ve.dm.ElementLinearData.js 
b/modules/ve/dm/lineardata/ve.dm.ElementLinearData.js
index 9a5b4b9..d10d874 100644
--- a/modules/ve/dm/lineardata/ve.dm.ElementLinearData.js
+++ b/modules/ve/dm/lineardata/ve.dm.ElementLinearData.js
@@ -475,47 +475,45 @@
  * - If {offset} is not already valid, one step will be used to move it to a 
valid one.
  * - If {offset} is already valid and cannot be moved in the direction of 
{distance} and still be
  *   valid, it will be left where it is
- * - If {distance} is zero the result will either be {offset} if it's already 
valid or the
+ * - If {initialDirection} is zero the result will either be {offset} if it's 
already valid or the
  *   nearest valid offset to the right if possible and to the left otherwise.
- * - If {offset} is after the last valid offset and {distance} is >= 1, or if 
{offset} if
- *   before the first valid offset and {distance} <= 1 than the result will be 
the nearest
+ * - If {offset} is after the last valid offset and {initialDirection} is 1, 
or if {offset} is
+ *   before the first valid offset and {initialDirection} is -1 then the 
result will be the nearest
  *   valid offset in the opposite direction.
  * - If the data does not contain a single valid offset the result will be -1
  *
  * @method
  * @param {number} offset Offset to start from
- * @param {number} distance Number of valid offsets to move
+ * @param {number} initialDirection Initial direction so search in, -1/0/+1
  * @param {Function} callback Function to call to check if an offset is valid 
which will be
  * given initial argument of offset
  * @param {Mixed...} [args] Additional arguments to pass to the callback
  * @returns {number} Relative valid offset or -1 if there are no valid offsets 
in data
  */
-ve.dm.ElementLinearData.prototype.getRelativeOffset = function ( offset, 
distance, callback ) {
+ve.dm.ElementLinearData.prototype.getRelativeOffset = function ( offset, 
initialDirection, callback ) {
        var i, direction,
                dataOffset, isOpen,
                args = Array.prototype.slice.call( arguments, 3 ),
                start = offset,
-               steps = 0,
                turnedAround = false,
                handlesOwnChildrenDepth = 0;
-       // If offset is already a structural offset and distance is zero than 
no further work is needed,
-       // otherwise distance should be 1 so that we can get out of the invalid 
starting offset
-       if ( distance === 0 ) {
+       // If offset is already a structural offset and initialDirection is 
zero than no further work is needed,
+       // otherwise initialDirection should be 1 so that we can get out of the 
invalid starting offset
+       if ( initialDirection === 0 ) {
                if ( callback.apply( this, [offset].concat( args ) ) ) {
                        return offset;
                } else {
-                       distance = 1;
+                       initialDirection = 1;
                }
        }
        // Initial values
-       direction = (
-               offset <= 0 ? 1 : (
-                       offset >= this.getLength() ? -1 : (
-                               distance > 0 ? 1 : -1
-                       )
-               )
-       );
-       distance = Math.abs( distance );
+       if ( offset <= 0 ) {
+               direction = 1;
+       } else if ( offset >= this.getLength() ) {
+               direction = -1;
+       } else {
+               direction = initialDirection;
+       }
        i = start + direction;
        offset = -1;
        // Iteration
@@ -539,17 +537,11 @@
                }
                if ( callback.apply( this, [i].concat( args ) ) ) {
                        if ( !handlesOwnChildrenDepth ) {
-                               steps++;
-                               offset = i;
-                               if ( distance === steps ) {
-                                       return offset;
-                               }
+                               return i;
                        }
                } else if (
                        // Don't keep turning around over and over
                        !turnedAround &&
-                       // Only turn around if not a single step could be taken
-                       steps === 0 &&
                        // Only turn around if we're about to reach the edge
                        ( ( direction < 0 && i === 0 ) || ( direction > 0 && i 
=== this.getLength() ) )
                ) {
@@ -561,7 +553,6 @@
                        // Start over going in the opposite direction
                        direction *= -1;
                        i = start;
-                       distance = 1;
                        turnedAround = true;
                        handlesOwnChildrenDepth = 0;
                }
@@ -571,18 +562,18 @@
 };
 
 /**
- * Get a content offset at a distance from an offset.
+ * Get a content offset in a direction from an offset.
  *
  * This method is a wrapper around {getRelativeOffset}, using 
{isContentOffset} as
  * the offset validation callback.
  *
  * @method
  * @param {number} offset Offset to start from
- * @param {number} distance Number of content offsets to move
+ * @param {number} direction Direction to move, -1/0/1
  * @returns {number} Relative content offset or -1 if there are no valid 
offsets in data
  */
-ve.dm.ElementLinearData.prototype.getRelativeContentOffset = function ( 
offset, distance ) {
-       return this.getRelativeOffset( offset, distance, 
this.constructor.prototype.isContentOffset );
+ve.dm.ElementLinearData.prototype.getRelativeContentOffset = function ( 
offset, direction ) {
+       return this.getRelativeOffset( offset, direction, 
this.constructor.prototype.isContentOffset );
 };
 
 /**
@@ -613,24 +604,24 @@
 };
 
 /**
- * Get a structural offset at a distance from an offset.
+ * Get a structural offset in a direction from an offset.
  *
  * This method is a wrapper around {getRelativeOffset}, using 
{this.isStructuralOffset} as
  * the offset validation callback.
  *
  * @method
  * @param {number} offset Offset to start from
- * @param {number} distance Number of structural offsets to move
+ * @param {number} direction Direction to move, -1/0/1
  * @param {boolean} [unrestricted] Only consider offsets where any kind of 
element can be inserted
  * @returns {number} Relative structural offset
  */
-ve.dm.ElementLinearData.prototype.getRelativeStructuralOffset = function ( 
offset, distance, unrestricted ) {
+ve.dm.ElementLinearData.prototype.getRelativeStructuralOffset = function ( 
offset, direction, unrestricted ) {
        // Optimization: start and end are always unrestricted structural 
offsets
-       if ( distance === 0 && ( offset === 0 || offset === this.getLength() ) 
) {
+       if ( direction === 0 && ( offset === 0 || offset === this.getLength() ) 
) {
                return offset;
        }
        return this.getRelativeOffset(
-               offset, distance, 
this.constructor.prototype.isStructuralOffset, unrestricted
+               offset, direction, 
this.constructor.prototype.isStructuralOffset, unrestricted
        );
 };
 
diff --git a/modules/ve/test/dm/lineardata/ve.dm.ElementLinearData.test.js 
b/modules/ve/test/dm/lineardata/ve.dm.ElementLinearData.test.js
index beaa859..cd1899e 100644
--- a/modules/ve/test/dm/lineardata/ve.dm.ElementLinearData.test.js
+++ b/modules/ve/test/dm/lineardata/ve.dm.ElementLinearData.test.js
@@ -737,7 +737,7 @@
                {
                        'msg': 'document without any valid offsets returns -1',
                        'offset': 0,
-                       'distance': 1,
+                       'direction': 1,
                        'data': [],
                        'callback': function () {
                                return false;
@@ -745,14 +745,14 @@
                        'expected': -1
                },
                {
-                       'msg': 'document with all valid offsets returns offset 
+ distance',
+                       'msg': 'document with all valid offsets returns offset',
                        'offset': 0,
-                       'distance': 2,
+                       'direction': 1,
                        'data': ['a', 'b'],
                        'callback': function () {
                                return true;
                        },
-                       'expected': 2
+                       'expected': 1
                }
        ];
        QUnit.expect( cases.length );
@@ -761,7 +761,7 @@
                assert.strictEqual(
                        data.getRelativeOffset(
                                cases[i].offset,
-                               cases[i].distance,
+                               cases[i].direction,
                                cases[i].callback
                        ),
                        cases[i].expected,
@@ -776,119 +776,83 @@
                annDoc = ve.dm.example.createExampleDocument( 'annotationData' 
),
                cases = [
                        {
-                               'msg': 'invalid starting offset with zero 
distance gets corrected',
+                               'msg': 'invalid starting offset with zero 
direction gets corrected',
                                'offset': 0,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 1
                        },
                        {
-                               'msg': 'invalid starting offset with zero 
distance gets corrected',
+                               'msg': 'invalid starting offset with zero 
direction gets corrected',
                                'offset': 61,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 60
                        },
                        {
-                               'msg': 'valid offset with zero distance returns 
same offset',
+                               'msg': 'valid offset with zero direction 
returns same offset',
                                'offset': 2,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 2
                        },
                        {
                                'msg': 'invalid starting offset gets corrected',
                                'offset': 0,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 1
                        },
                        {
                                'msg': 'invalid starting offset gets corrected',
                                'offset': 61,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 60
                        },
                        {
                                'msg': 'stop at left edge if already valid',
                                'offset': 1,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 1
                        },
                        {
                                'msg': 'stop at right edge if already valid',
                                'offset': 60,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 60
                        },
                        {
-                               'msg': 'first content offset is farthest left',
-                               'offset': 2,
-                               'distance': -2,
-                               'expected': 1
-                       },
-                       {
-                               'msg': 'last content offset is farthest right',
-                               'offset': 59,
-                               'distance': 2,
-                               'expected': 60
-                       },
-                       {
-                               'msg': '1 right within text',
+                               'msg': 'right within text',
                                'offset': 1,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 2
                        },
                        {
-                               'msg': '2 right within text',
-                               'offset': 1,
-                               'distance': 2,
-                               'expected': 3
-                       },
-                       {
-                               'msg': '1 left within text',
+                               'msg': 'left within text',
                                'offset': 2,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 1
                        },
                        {
-                               'msg': '2 left within text',
-                               'offset': 3,
-                               'distance': -2,
-                               'expected': 1
-                       },
-                       {
-                               'msg': '1 right over elements',
+                               'msg': 'right over elements',
                                'offset': 4,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 10
                        },
                        {
-                               'msg': '2 right over elements',
-                               'offset': 4,
-                               'distance': 2,
-                               'expected': 11
-                       },
-                       {
-                               'msg': '1 left over elements',
+                               'msg': 'left over elements',
                                'offset': 10,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 4
-                       },
-                       {
-                               'msg': '2 left over elements',
-                               'offset': 10,
-                               'distance': -2,
-                               'expected': 3
                        },
                        {
                                'msg': 'Skips over nested handlesOwnChildren 
nodes',
                                'doc': annDoc,
                                'offset': 10,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 24
                        },
                        {
                                'msg': 'Skips over nested handlesOwnChildren 
nodes (reverse)',
                                'doc': annDoc,
                                'offset': 23,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 9
                        }
                ];
@@ -896,7 +860,7 @@
        for ( i = 0; i < cases.length; i++ ) {
                doc = cases[i].doc || simpleDoc;
                assert.strictEqual(
-                       doc.data.getRelativeContentOffset( cases[i].offset, 
cases[i].distance ),
+                       doc.data.getRelativeContentOffset( cases[i].offset, 
cases[i].direction ),
                        cases[i].expected,
                        cases[i].msg
                );
@@ -964,105 +928,67 @@
                doc = ve.dm.example.createExampleDocument(),
                cases = [
                        {
-                               'msg': 'invalid starting offset with zero 
distance gets corrected',
+                               'msg': 'invalid starting offset with zero 
direction gets corrected',
                                'offset': 1,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 5
                        },
                        {
-                               'msg': 'invalid starting offset with zero 
distance gets corrected',
+                               'msg': 'invalid starting offset with zero 
direction gets corrected',
                                'offset': 60,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 61
                        },
                        {
-                               'msg': 'valid offset with zero distance returns 
same offset',
+                               'msg': 'valid offset with zero direction 
returns same offset',
                                'offset': 0,
-                               'distance': 0,
+                               'direction': 0,
                                'expected': 0
                        },
                        {
                                'msg': 'invalid starting offset gets corrected',
                                'offset': 2,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 0
                        },
                        {
                                'msg': 'invalid starting offset gets corrected',
                                'offset': 59,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 61
                        },
                        {
-                               'msg': 'first structural offset is farthest 
left',
-                               'offset': 5,
-                               'distance': -2,
-                               'expected': 0
-                       },
-                       {
-                               'msg': 'last structural offset is farthest 
right',
-                               'offset': 62,
-                               'distance': 2,
-                               'expected': 63
-                       },
-                       {
-                               'msg': '1 right',
+                               'msg': 'right',
                                'offset': 0,
-                               'distance': 1,
+                               'direction': 1,
                                'expected': 5
                        },
                        {
-                               'msg': '1 right, unrestricted',
+                               'msg': 'right, unrestricted',
                                'offset': 5,
-                               'distance': 1,
+                               'direction': 1,
                                'unrestricted': true,
                                'expected': 9
                        },
                        {
-                               'msg': '2 right',
-                               'offset': 0,
-                               'distance': 2,
-                               'expected': 6
-                       },
-                       {
-                               'msg': '2 right, unrestricted',
-                               'offset': 0,
-                               'distance': 2,
-                               'unrestricted': true,
-                               'expected': 9
-                       },
-                       {
-                               'msg': '1 left',
+                               'msg': 'left',
                                'offset': 61,
-                               'distance': -1,
+                               'direction': -1,
                                'expected': 58
                        },
                        {
-                               'msg': '1 left, unrestricted',
+                               'msg': 'left, unrestricted',
                                'offset': 9,
-                               'distance': -1,
+                               'direction': -1,
                                'unrestricted': true,
                                'expected': 5
-                       },
-                       {
-                               'msg': '2 left',
-                               'offset': 61,
-                               'distance': -2,
-                               'expected': 55
-                       },
-                       {
-                               'msg': '2 left, unrestricted',
-                               'offset': 9,
-                               'distance': -2,
-                               'unrestricted': true,
-                               'expected': 0
                        }
                ];
        QUnit.expect( cases.length );
        for ( i = 0; i < cases.length; i++ ) {
                assert.strictEqual(
                        doc.data.getRelativeStructuralOffset(
-                               cases[i].offset, cases[i].distance, 
cases[i].unrestricted
+                               cases[i].offset, cases[i].direction, 
cases[i].unrestricted
                        ),
                        cases[i].expected,
                        cases[i].msg

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

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

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

Reply via email to