https://www.mediawiki.org/wiki/Special:Code/MediaWiki/113425
Revision: 113425
Author: catrope
Date: 2012-03-08 23:21:26 +0000 (Thu, 08 Mar 2012)
Log Message:
-----------
Implement prepareWrap and add tests for it
Modified Paths:
--------------
trunk/extensions/VisualEditor/modules/ve/dm/nodes/ve.dm.DocumentNode.js
trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentNode.test.js
trunk/extensions/VisualEditor/tests/ve/ve.dm.TransactionProcessor.test.js
Modified:
trunk/extensions/VisualEditor/modules/ve/dm/nodes/ve.dm.DocumentNode.js
===================================================================
--- trunk/extensions/VisualEditor/modules/ve/dm/nodes/ve.dm.DocumentNode.js
2012-03-08 23:21:24 UTC (rev 113424)
+++ trunk/extensions/VisualEditor/modules/ve/dm/nodes/ve.dm.DocumentNode.js
2012-03-08 23:21:26 UTC (rev 113425)
@@ -1145,6 +1145,87 @@
*
*/
ve.dm.DocumentNode.prototype.prepareWrap = function( range, unwrapOuter,
wrapOuter, unwrapEach, wrapEach ) {
+ // Function to generate arrays of closing elements in reverse order
+ function closingArray( openings ) {
+ var closings = [], i, len = openings.length;
+ for ( i = 0; i < len; i++ ) {
+ closings[closings.length] = { 'type': '/' +
openings[len - i - 1].type };
+ }
+ return closings;
+ }
+
+ // TODO sanity checks:
+ // * range.start > unwrapOuter.length
+ // * unwraps actually match
+ // * result is valid
+
+ var tx = new ve.dm.Transaction();
+ range.normalize();
+ if ( range.start > unwrapOuter.length ) {
+ // Retain up to the first thing we're unwrapping
+ // The outer unwrapping takes place *outside*
+ // the range, so compensate for that
+ tx.pushRetain ( range.start - unwrapOuter.length );
+ }
+
+ // Replace the opening elements for the outer unwrap&wrap
+ if ( wrapOuter.length > 0 || unwrapOuter.length > 0 ) {
+ tx.pushReplace( unwrapOuter, wrapOuter );
+ }
+
+ if ( wrapEach.length > 0 && unwrapEach.length > 0 ) {
+ var closingUnwrapEach = closingArray( unwrapEach ),
+ closingWrapEach = closingArray( wrapEach ),
+ depth = 0,
+ startOffset,
+ i;
+ // Visit each top-level child and wrap/unwrap it
+ // TODO figure out if we should use the tree/node functions here
+ // rather than iterating over offsets, it may or may not be
faster
+ for ( i = range.start; i < range.end; i++ ) {
+ if ( this.data[offset].type === undefined ) {
+ // This is a content offset, skip
+ } else {
+ // This is a structural offset
+ if ( this.data[offset].type.charAt( 0 ) != '/'
) {
+ // This is an opening element
+ if ( depth == 0 ) {
+ // We are at the start of a
top-level element
+ // Replace the opening elements
+ tx.pushReplace( unwrapEach,
wrapEach );
+ // Store this offset for later
+ startOffset = i;
+ }
+ depth++;
+ } else {
+ // This is a closing element
+ depth--;
+ if ( depth == 0 ) {
+ // We are at the end of a
top-level element
+ // Retain the contents of what
we're wrapping
+ tx.pushRetain( i - startOffset
+ 1 - unwrapEach.length*2 );
+ // Replace the closing elements
+ tx.pushReplace(
closingUnwrapEach, closingWrapEach );
+ }
+ }
+ }
+ }
+ } else {
+ // There is no wrapEach/unwrapEach to be done, just retain
+ // up to the end of the range
+ tx.pushRetain( range.end - range.start );
+ }
+
+ if ( wrapOuter.length > 0 || unwrapOuter.length > 0 ) {
+ tx.pushReplace( closingArray( unwrapOuter ), closingArray(
wrapOuter ) );
+ }
+
+ // Retain up to the end of the document
+ if ( range.end < this.data.length ) {
+ tx.pushRetain( this.data.length - range.end -
unwrapOuter.length );
+ }
+
+ return tx;
};
Modified: trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentNode.test.js
===================================================================
--- trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentNode.test.js
2012-03-08 23:21:24 UTC (rev 113424)
+++ trunk/extensions/VisualEditor/tests/ve/ve.dm.DocumentNode.test.js
2012-03-08 23:21:26 UTC (rev 113425)
@@ -800,3 +800,19 @@
'prepareInsertion throws exception for malformed input'
);
} );
+
+test( 've.dm.DocumentNode.prepareWrap', 1, function() {
+ var documentModel = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
+
+ // Test 1
+ deepEqual(
+ documentModel.prepareWrap( new ve.Range( 1, 4 ), [ { 'type':
'paragraph' } ], [ { 'type': 'heading', 'level': 2 } ], [], []
).getOperations(),
+ [
+ { 'type': 'replace', 'remove': [ { 'type': 'paragraph'
} ], 'replacement': [ { 'type': 'heading', 'level': 2 } ] },
+ { 'type': 'retain', 'length': 3 },
+ { 'type': 'replace', 'remove': [ { 'type': '/paragraph'
} ], 'replacement': [ { 'type': '/heading' } ] },
+ { 'type': 'retain', 'length': 29 }
+ ],
+ 'prepareWrap changes a paragraph to a heading'
+ );
+} );
\ No newline at end of file
Modified:
trunk/extensions/VisualEditor/tests/ve/ve.dm.TransactionProcessor.test.js
===================================================================
--- trunk/extensions/VisualEditor/tests/ve/ve.dm.TransactionProcessor.test.js
2012-03-08 23:21:24 UTC (rev 113424)
+++ trunk/extensions/VisualEditor/tests/ve/ve.dm.TransactionProcessor.test.js
2012-03-08 23:21:26 UTC (rev 113425)
@@ -1,6 +1,6 @@
module( 've/dm' );
-test( 've.dm.TransactionProcessor', 33, function() {
+test( 've.dm.TransactionProcessor', 35, function() {
var documentModel = ve.dm.DocumentNode.newFromPlainObject( veTest.obj );
// FIXME: These tests shouldn't use prepareFoo() because those functions
@@ -404,4 +404,34 @@
],
'rollback restores content'
);
+
+ var paragraphToHeading = documentModel.prepareWrap( new ve.Range( 1, 4
), [ { 'type': 'paragraph' } ], [ { 'type': 'heading', 'level': 2 } ], [], [] );
+
+ // Test 33
+ ve.dm.TransactionProcessor.commit( documentModel, paragraphToHeading );
+ deepEqual(
+ documentModel.getData( new ve.Range( 0, 5 ) ),
+ [
+ { 'type': 'heading', 'level': 2 },
+ 'a',
+ ['b', { 'type': 'textStyle/bold', 'hash':
'{"type":"textStyle/bold"}' }],
+ ['c', { 'type': 'textStyle/italic', 'hash':
'{"type":"textStyle/italic"}' }],
+ { 'type': '/heading' }
+ ],
+ 'changing paragraph to heading'
+ );
+
+ // Test 34
+ ve.dm.TransactionProcessor.rollback( documentModel, paragraphToHeading
);
+ deepEqual(
+ documentModel.getData( new ve.Range( 0, 5 ) ),
+ [
+ { 'type': 'paragraph' },
+ 'a',
+ ['b', { 'type': 'textStyle/bold', 'hash':
'{"type":"textStyle/bold"}' }],
+ ['c', { 'type': 'textStyle/italic', 'hash':
'{"type":"textStyle/italic"}' }],
+ { 'type': '/paragraph' }
+ ],
+ 'rollback puts paragraph back'
+ );
} );
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs