jenkins-bot has submitted this change and it was merged.
Change subject: (bug 45423) Create SurfaceFragment.isolate method
......................................................................
(bug 45423) Create SurfaceFragment.isolate method
This method will take a selection of siblings and ensure they
are the only chlidren in their first parent which can be placed anywhere
(for example the first parent of a tableCell which can be placed anywhere
is a table, and for a listItem is a list).
The method ensures no redundant empty tags are created, so if
the selection encompasses all siblings then no action is taken.
Also in this commit are two test cases run against ve.dm.example.isolationData.
Change-Id: I783bd5ecd9d43d61f9b2685985409b4d746cbe94
---
M modules/ve/dm/ve.dm.SurfaceFragment.js
M modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
2 files changed, 131 insertions(+), 1 deletion(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/modules/ve/dm/ve.dm.SurfaceFragment.js
b/modules/ve/dm/ve.dm.SurfaceFragment.js
index fd9e095..c208099 100644
--- a/modules/ve/dm/ve.dm.SurfaceFragment.js
+++ b/modules/ve/dm/ve.dm.SurfaceFragment.js
@@ -690,3 +690,88 @@
// TODO: Implement
return this;
};
+
+/**
+ * Isolates the nodes in a fragment.
+ *
+ * The node selection is expanded to siblings and then these are isolated such
that they are the
+ * sole children of a parent element which can be placed anywhere.
+ *
+ * @method
+ * @returns {ve.dm.SurfaceFragment} This fragment
+ */
+ve.dm.SurfaceFragment.prototype.isolate = function () {
+ // Handle null fragment
+ if ( !this.surface ) {
+ return this;
+ }
+ var nodes, startSplitNode, endSplitNode, tx,
+ startOffset, endOffset,
+ startSplitRequired = false,
+ endSplitRequired = false,
+ startSplitNodes = [],
+ endSplitNodes = [],
+ fragment = this;
+
+ function createSplits( splitNodes, insertBefore ) {
+ var i, length,
+ startOffsetChange = 0, endOffsetChange = 0, data = [];
+ for ( i = 0, length = splitNodes.length; i < length; i++ ) {
+ data.unshift( { 'type': '/' + splitNodes[i].type } );
+ data.push( splitNodes[i].getClonedElement() );
+
+ if ( insertBefore ) {
+ startOffsetChange += 2;
+ endOffsetChange += 2;
+ }
+ }
+
+ tx = ve.dm.Transaction.newFromInsertion( fragment.document,
insertBefore ? startOffset : endOffset, data );
+ fragment.surface.change( tx, !fragment.noAutoSelect &&
tx.translateRange( fragment.range ) );
+
+ startOffset += startOffsetChange;
+ endOffset += endOffsetChange;
+ }
+
+ nodes = this.document.selectNodes( this.range, 'siblings' );
+
+ // Find start split point, if required
+ startSplitNode = nodes[0].node;
+ startOffset = startSplitNode.getOuterRange().start;
+ while ( startSplitNode.constructor.static.parentNodeTypes !== null ) {
+ if ( startSplitNode.parent.indexOf( startSplitNode ) > 0 ) {
+ startSplitRequired = true;
+ }
+ startSplitNode = startSplitNode.parent;
+ if ( startSplitRequired ) {
+ startSplitNodes.unshift(startSplitNode);
+ } else {
+ startOffset = startSplitNode.getOuterRange().start;
+ }
+ }
+
+ // Find end split point, if required
+ endSplitNode = nodes[nodes.length - 1].node;
+ endOffset = endSplitNode.getOuterRange().end;
+ while ( endSplitNode.constructor.static.parentNodeTypes !== null ) {
+ if ( endSplitNode.parent.indexOf( endSplitNode ) <
endSplitNode.parent.getChildren().length - 1 ) {
+ endSplitRequired = true;
+ }
+ endSplitNode = endSplitNode.parent;
+ if ( endSplitRequired ) {
+ endSplitNodes.unshift(endSplitNode);
+ } else {
+ endOffset = endSplitNode.getOuterRange().end;
+ }
+ }
+
+ if ( startSplitRequired ) {
+ createSplits( startSplitNodes, true );
+ }
+
+ if ( endSplitRequired ) {
+ createSplits( endSplitNodes, false );
+ }
+
+ return this;
+};
diff --git a/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
b/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
index a685386..88c2a5b 100644
--- a/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
+++ b/modules/ve/test/dm/ve.dm.SurfaceFragment.test.js
@@ -7,7 +7,7 @@
QUnit.module( 've.dm.SurfaceFragment' );
-// Tests
+/* Tests */
QUnit.test( 'constructor', 8, function ( assert ) {
var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.data ) ),
@@ -225,3 +225,48 @@
'wrapping nodes can add multiple levels of wrapping to a single
element'
);
} );
+
+function runIsolateTest( assert, range, expected, label ) {
+ var doc = new ve.dm.Document( ve.copyArray( ve.dm.example.isolationData
) ),
+ surface = new ve.dm.Surface( doc ),
+ fragment = new ve.dm.SurfaceFragment( surface, range ),
+ data;
+
+ data = ve.copyArray( doc.getFullData() );
+ fragment.isolate();
+ expected( data );
+
+ assert.deepEqual( doc.getFullData(), data, label );
+}
+
+QUnit.test( 'isolate', 2, function ( assert ) {
+ var rebuilt = { 'changed': { 'rebuilt': 1 } },
+ created = { 'changed': { 'created': 1 } },
+ createdAndRebuilt = { 'changed': { 'created': 1, 'rebuilt': 1 }
};
+
+ runIsolateTest( assert, new ve.Range( 11, 21 ), function( data ) {
+ data[0].internal = rebuilt;
+ data.splice( 11, 0, { 'type': '/list' }, { 'type': 'list',
'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt });
+ data.splice( 23, 0, { 'type': '/list' }, { 'type': 'list',
'attributes': { 'style': 'bullet' }, 'internal': createdAndRebuilt });
+ }, 'isolating list item "Item 2"');
+
+ runIsolateTest( assert, new ve.Range( 88, 108 ), function( data ) {
+ data[75].internal = rebuilt;
+ data[76].internal = rebuilt;
+ data[77].internal = rebuilt;
+ data.splice( 88, 0,
+ { 'type': '/tableRow' },
+ { 'type': '/tableSection' },
+ { 'type': '/table' },
+ { 'type': 'table', 'internal': createdAndRebuilt },
+ { 'type': 'tableSection', 'attributes': { 'style':
'body' }, 'internal': createdAndRebuilt },
+ { 'type': 'tableRow', 'internal': created }
+ );
+ data.splice( 115, 0,
+ { 'type': '/tableSection' },
+ { 'type': '/table' },
+ { 'type': 'table', 'internal': createdAndRebuilt },
+ { 'type': 'tableSection', 'attributes': { 'style':
'body' }, 'internal': createdAndRebuilt }
+ );
+ }, 'isolating table cells "Cell 2" & "Cell 3"');
+} );
--
To view, visit https://gerrit.wikimedia.org/r/50199
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I783bd5ecd9d43d61f9b2685985409b4d746cbe94
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits