jenkins-bot has submitted this change and it was merged.
Change subject: Fix translateRange bug that expands selections
......................................................................
Fix translateRange bug that expands selections
Change-Id: Ib93e88afe8a4be61fa3306db87d6f51f6f495198
---
M src/dm/selections/ve.dm.LinearSelection.js
M src/dm/selections/ve.dm.NullSelection.js
M src/dm/selections/ve.dm.TableSelection.js
M src/dm/ve.dm.Selection.js
M src/dm/ve.dm.Surface.js
M src/dm/ve.dm.Transaction.js
M tests/dm/ve.dm.Document.test.js
M tests/dm/ve.dm.Surface.test.js
8 files changed, 145 insertions(+), 9 deletions(-)
Approvals:
Esanders: Looks good to me, approved
jenkins-bot: Verified
diff --git a/src/dm/selections/ve.dm.LinearSelection.js
b/src/dm/selections/ve.dm.LinearSelection.js
index 2d795b2..79e3e87 100644
--- a/src/dm/selections/ve.dm.LinearSelection.js
+++ b/src/dm/selections/ve.dm.LinearSelection.js
@@ -106,6 +106,13 @@
/**
* @inheritdoc
*/
+ve.dm.LinearSelection.prototype.translateByTransactionWithAuthor = function (
tx, author ) {
+ return new this.constructor( this.getDocument(),
tx.translateRangeWithAuthor( this.getRange(), author ) );
+};
+
+/**
+ * @inheritdoc
+ */
ve.dm.LinearSelection.prototype.getRanges = function () {
return [ this.range ];
};
@@ -130,9 +137,12 @@
* @inheritdoc
*/
ve.dm.LinearSelection.prototype.equals = function ( other ) {
- return other instanceof ve.dm.LinearSelection &&
+ return this === other || (
+ !!other &&
+ other.constructor === this.constructor &&
this.getDocument() === other.getDocument() &&
- this.getRange().equals( other.getRange() );
+ this.getRange().equals( other.getRange() )
+ );
};
/* Registration */
diff --git a/src/dm/selections/ve.dm.NullSelection.js
b/src/dm/selections/ve.dm.NullSelection.js
index a099620..9a23ecc 100644
--- a/src/dm/selections/ve.dm.NullSelection.js
+++ b/src/dm/selections/ve.dm.NullSelection.js
@@ -74,6 +74,8 @@
ve.dm.NullSelection.prototype.translateByTransaction =
ve.dm.NullSelection.prototype.clone;
+ve.dm.NullSelection.prototype.translateByTransactionWithAuthor =
ve.dm.NullSelection.prototype.clone;
+
/**
* @inheritdoc
*/
@@ -92,8 +94,11 @@
* @inheritdoc
*/
ve.dm.NullSelection.prototype.equals = function ( other ) {
- return other instanceof ve.dm.NullSelection &&
- this.getDocument() === other.getDocument();
+ return this === other || (
+ !!other &&
+ other.constructor === this.constructor &&
+ this.getDocument() === other.getDocument()
+ );
};
/**
diff --git a/src/dm/selections/ve.dm.TableSelection.js
b/src/dm/selections/ve.dm.TableSelection.js
index def74f1..f4f39ee 100644
--- a/src/dm/selections/ve.dm.TableSelection.js
+++ b/src/dm/selections/ve.dm.TableSelection.js
@@ -112,7 +112,14 @@
* @inheritdoc
*/
ve.dm.TableSelection.prototype.clone = function () {
- return new this.constructor( this.getDocument(), this.tableRange,
this.fromCol, this.fromRow, this.toCol, this.toRow );
+ return new this.constructor(
+ this.getDocument(),
+ this.tableRange,
+ this.fromCol,
+ this.fromRow,
+ this.toCol,
+ this.toRow
+ );
};
/**
@@ -303,6 +310,21 @@
};
/**
+ * @inheritdoc
+ */
+ve.dm.TableSelection.prototype.translateByTransactionWithAuthor = function (
tx, author ) {
+ var newRange = tx.translateRangeWithAuthor( this.tableRange, author );
+
+ if ( newRange.isCollapsed() ) {
+ return new ve.dm.NullSelection( this.getDocument() );
+ }
+ return new this.constructor(
+ this.getDocument(), newRange,
+ this.fromCol, this.fromRow, this.toCol, this.toRow
+ );
+};
+
+/**
* Check if the selection spans a single cell
*
* @return {boolean} The selection spans a single cell
@@ -464,13 +486,16 @@
* @inheritdoc
*/
ve.dm.TableSelection.prototype.equals = function ( other ) {
- return other instanceof ve.dm.TableSelection &&
+ return this === other || (
+ !!other &&
+ other.constructor === this.constructor &&
this.getDocument() === other.getDocument() &&
this.tableRange.equals( other.tableRange ) &&
this.fromCol === other.fromCol &&
this.fromRow === other.fromRow &&
this.toCol === other.toCol &&
- this.toRow === other.toRow;
+ this.toRow === other.toRow
+ );
};
/**
diff --git a/src/dm/ve.dm.Selection.js b/src/dm/ve.dm.Selection.js
index dc80892..e2bf78b 100644
--- a/src/dm/ve.dm.Selection.js
+++ b/src/dm/ve.dm.Selection.js
@@ -57,6 +57,11 @@
/* Methods */
/**
+ * Test for selection equality
+ */
+ve.dm.Selection.prototype.equals = null;
+
+/**
* Get a JSON serialization of this selection
*
* @abstract
@@ -140,6 +145,17 @@
ve.dm.Selection.prototype.translateByTransaction = null;
/**
+ * Apply translations from a transaction, with bias depending on author ID
comparison
+ *
+ * @abstract
+ * @method
+ * @param {ve.dm.Transaction} tx Transaction
+ * @param {number} author The selection's author ID
+ * @return {ve.dm.Selection} A new translated selection
+ */
+ve.dm.Selection.prototype.translateByTransactionWithAuthor = null;
+
+/**
* Apply translations from a set of transactions
*
* @param {ve.dm.Transaction[]} txs Transactions
diff --git a/src/dm/ve.dm.Surface.js b/src/dm/ve.dm.Surface.js
index 7e6ac5f..70ef113 100644
--- a/src/dm/ve.dm.Surface.js
+++ b/src/dm/ve.dm.Surface.js
@@ -931,7 +931,7 @@
* @fires documentUpdate
*/
ve.dm.Surface.prototype.onDocumentTransact = function ( tx ) {
- this.setSelection( this.getSelection().translateByTransaction( tx ) );
+ this.setSelection(
this.getSelection().translateByTransactionWithAuthor( tx, null ) );
this.emit( 'documentUpdate', tx );
};
diff --git a/src/dm/ve.dm.Transaction.js b/src/dm/ve.dm.Transaction.js
index 11cb1a0..0c5b42b 100644
--- a/src/dm/ve.dm.Transaction.js
+++ b/src/dm/ve.dm.Transaction.js
@@ -1109,7 +1109,7 @@
};
/**
- * Translate a range based on a transaction.
+ * Translate a range based on the transaction, with grow/shrink preference at
changes
*
* This is useful when you want to anticipate what a selection will be after a
transaction is
* processed.
@@ -1128,6 +1128,23 @@
};
/**
+ * Translate a range based on the transaction, with bias depending on author
ID comparison
+ *
+ * Biases backward if !author || !this.author || author <= this.author
+ *
+ * @see #translateOffset
+ * @param {ve.Range} range Range in the linear model before the transaction
has been processed
+ * @param {number} [author] Author ID of the range
+ * @return {ve.Range} Translated range, as it will be after processing
transaction
+ */
+ve.dm.Transaction.prototype.translateRangeWithAuthor = function ( range,
author ) {
+ var backward = !this.author || !author || author <= this.author,
+ start = this.translateOffset( range.start, backward ),
+ end = this.translateOffset( range.end, backward );
+ return range.isBackwards() ? new ve.Range( end, start ) : new ve.Range(
start, end );
+};
+
+/**
* Get the range that covers modifications made by this transaction.
*
* In the case of insertions, the range covers content the user intended to
insert.
diff --git a/tests/dm/ve.dm.Document.test.js b/tests/dm/ve.dm.Document.test.js
index e487425..c40e1ce 100644
--- a/tests/dm/ve.dm.Document.test.js
+++ b/tests/dm/ve.dm.Document.test.js
@@ -944,3 +944,54 @@
}
}
} );
+
+QUnit.test( 'Selection equality', function ( assert ) {
+ var selections, i, iLen, j, jLen, iSel, jSel, doc;
+ doc = new ve.dm.Document( [
+ { type: 'paragraph' }, 'h', 'i', { type: '/paragraph' },
+ { type: 'table' },
+ { type: 'tableSection' },
+ { type: 'tableRow' },
+ { type: 'tableCell', attributes: { colspan: 2, rowspan: 2 } },
+ { type: '/tableCell' },
+ { type: 'tableCell', attributes: {} },
+ { type: '/tableCell' },
+ { type: '/tableRow' },
+ { type: 'tableRow' },
+ { type: 'tableCell', attributes: {} },
+ { type: '/tableCell' },
+ { type: '/tableRow' },
+ { type: 'tableRow' },
+ { type: 'tableCell', attributes: {} },
+ { type: '/tableCell' },
+ { type: 'tableCell', attributes: {} },
+ { type: '/tableCell' },
+ { type: 'tableCell', attributes: {} },
+ { type: '/tableCell' },
+ { type: '/tableRow' },
+ { type: '/tableSection' },
+ { type: '/table' }
+ ] );
+ selections = [
+ new ve.dm.LinearSelection( doc, new ve.Range( 1, 1 ) ),
+ new ve.dm.LinearSelection( doc, new ve.Range( 1, 3 ) ),
+ new ve.dm.LinearSelection( doc, new ve.Range( 3, 1 ) ),
+ new ve.dm.TableSelection( doc, new ve.Range( 4, 25 ), 0, 1, 2,
2, true ),
+ new ve.dm.NullSelection( doc ),
+ undefined,
+ null,
+ 'foo'
+ ];
+ QUnit.expect( selections.length * ( selections.length - 3 ) );
+ for ( i = 0, iLen = selections.length; i < iLen; i++ ) {
+ iSel = selections[ i ];
+ if ( !( iSel instanceof ve.dm.Selection ) ) {
+ continue;
+ }
+ iSel = iSel.clone();
+ for ( j = 0, jLen = selections.length; j < jLen; j++ ) {
+ jSel = selections[ j ];
+ assert.strictEqual( iSel.equals( jSel ), i === j,
'Selections ' + i + ' and ' + j );
+ }
+ }
+} );
diff --git a/tests/dm/ve.dm.Surface.test.js b/tests/dm/ve.dm.Surface.test.js
index 48cd63f..5a4ad57 100644
--- a/tests/dm/ve.dm.Surface.test.js
+++ b/tests/dm/ve.dm.Surface.test.js
@@ -95,6 +95,18 @@
} );
+QUnit.test( 'range translation', 2, function ( assert ) {
+ var sel, range,
+ surface = new ve.dm.SurfaceStub( null, new ve.Range( 3 ) ),
+ doc = surface.getDocument(),
+ tx = ve.dm.Transaction.newFromInsertion( doc, 3, [ 'x' ] );
+ surface.change( tx );
+ sel = surface.getSelection();
+ assert.ok( sel instanceof ve.dm.LinearSelection, 'Selection is linear'
);
+ range = sel.getRange();
+ assert.deepEqual( { from: range.from, to: range.to }, { from: 3, to: 3
}, 'Cursor is unmoved' );
+} );
+
QUnit.test( 'staging', 37, function ( assert ) {
var tx1, tx2,
surface = new ve.dm.SurfaceStub( null, new ve.Range( 1, 3 ) ),
--
To view, visit https://gerrit.wikimedia.org/r/317330
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ib93e88afe8a4be61fa3306db87d6f51f6f495198
Gerrit-PatchSet: 10
Gerrit-Project: VisualEditor/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Divec <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Divec <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits