From 11a3b6886b859ed35b3c9bca3b20ee8ea2e7fece Mon Sep 17 00:00:00 2001 From: Catrope Date: Fri, 4 May 2012 11:07:55 -0700 Subject: [PATCH] Implement basic replace processor * Implement basic TransactionProcessor.replace(), only does content replacements * Add ve.dm.Document.containsElementData() * Fix bug in attribute() * Write basic tests for attribute() and replace() Change-Id: Ie9c22aec3f2631be5b0bd66790408ad283565491 --- modules/ve2/dm/ve.dm.Document.js | 18 ++++++++ modules/ve2/dm/ve.dm.TransactionProcessor.js | 25 +++++++++- .../ve2/dm/ve.dm.TransactionProcessor.test.js | 46 +++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/modules/ve2/dm/ve.dm.Document.js b/modules/ve2/dm/ve.dm.Document.js index 22391a7f00..c3f56aebd5 100644 --- a/modules/ve2/dm/ve.dm.Document.js +++ b/modules/ve2/dm/ve.dm.Document.js @@ -65,6 +65,24 @@ ve.dm.Document.prototype.rebuildNodes = function( parent, index, numNodes, offse return nodes; }; +/* Static methods */ +/** + * Checks if elements are present within data. + * + * @static + * @method + * @param {Array} data Data to look for elements within + * @returns {Boolean} If elements exist in data + */ +ve.dm.Document.containsElementData = function( data ) { + for ( var i = 0, length = data.length; i < length; i++ ) { + if ( data[i].type !== undefined ) { + return true; + } + } + return false; +}; + /* Inheritance */ ve.extendClass( ve.dm.Document, ve.dm.DocumentFragment ); diff --git a/modules/ve2/dm/ve.dm.TransactionProcessor.js b/modules/ve2/dm/ve.dm.TransactionProcessor.js index 2c3d151019..a7a72f1b5c 100644 --- a/modules/ve2/dm/ve.dm.TransactionProcessor.js +++ b/modules/ve2/dm/ve.dm.TransactionProcessor.js @@ -169,7 +169,7 @@ ve.dm.TransactionProcessor.prototype.annotate = function( op ) { * to: new attribute value, or undefined to unset */ ve.dm.TransactionProcessor.prototype.attribute = function( op ) { - var element = this.model.data[this.cursor]; + var element = this.document.data[this.cursor]; if ( element.type === undefined ) { throw 'Invalid element error. Can not set attributes on non-element data.'; } @@ -207,5 +207,26 @@ ve.dm.TransactionProcessor.prototype.attribute = function( op ) { * replacement: Linear model data fragment to insert */ ve.dm.TransactionProcessor.prototype.replace = function( op ) { - // TODO + var remove = this.reversed ? op.replacement : op.remove, + replacement = this.reversed ? op.remove : op.replacement, + removeHasStructure = ve.dm.Document.containsElementData( remove ), + replacementHasStructure = ve.dm.Document.containsElementData( replacement ), + node; + // Figure out if this is a structural replacement or a content replacement + if ( !removeHasStructure && !replacementHasStructure ) { + // Content replacement + // Update the linear model + ve.batchSplice( this.document.data, this.cursor, remove.length, replacement ); + this.applyAnnotations( this.cursor + replacement.length ); + + // Get the node containing the replaced content + node = this.document.getNodeFromOffset( this.cursor ); + // Queue a resize for this node + //this.synchronizer.pushResize( node, replacement.length - remove.length ); + // Advance the cursor + this.cursor += replacement.length; + } else { + // Structural replacement + // TODO implement + } }; diff --git a/tests/ve2/dm/ve.dm.TransactionProcessor.test.js b/tests/ve2/dm/ve.dm.TransactionProcessor.test.js index f252f27e1f..e4ba54464c 100644 --- a/tests/ve2/dm/ve.dm.TransactionProcessor.test.js +++ b/tests/ve2/dm/ve.dm.TransactionProcessor.test.js @@ -51,3 +51,49 @@ test( 'annotate', function() { deepEqual( doc.getData(), ve.dm.example.data, 'Complex annotation transaction rolls back correctly' ); } ); + +test( 'attribute', function() { + var doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) ); + var tx = new ve.dm.Transaction(); + var expectedData = ve.dm.example.data.slice( 0 ); + tx.pushReplaceElementAttribute( 'level', 1, 2 ); + tx.pushRetain( 11 ); + tx.pushReplaceElementAttribute( 'styles', ['bullet'], ['number'] ); + expectedData[0].attributes.level = 2; + expectedData[11].attributes.styles = ['number']; + + ve.dm.TransactionProcessor.commit( doc, tx ); + deepEqual( doc.getData(), expectedData, + 'Attribute transaction replaces attributes correctly' ); + ve.dm.TransactionProcessor.rollback( doc, tx ); + deepEqual( doc.getData(), ve.dm.example.data, + 'Attribute transaction rolls back correctly' ); + + // TODO test attribute addition/removal + + doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) ); + tx = new ve.dm.Transaction(); + tx.pushRetain( 1 ); + tx.pushReplaceElementAttribute( 'foo', 23, 42 ); + raises( + function() { ve.dm.TransactionProcessor.commit( doc, tx ); }, + /^Invalid element error. Can not set attributes on non-element data.$/, + 'Trying to replace attributes on content results in an exception' + ); +} ); + +test( 'replace', function() { + var doc = new ve.dm.Document( ve.dm.example.data.slice( 0 ) ); + var tx = new ve.dm.Transaction(); + var expectedData = ve.dm.example.data.slice( 0 ); + tx.pushRetain( 1 ); + tx.pushReplace( [ 'a' ], [ 'F', 'O', 'O' ] ); + expectedData.splice( 1, 1, 'F', 'O', 'O' ); + + ve.dm.TransactionProcessor.commit( doc, tx ); + deepEqual( doc.getData(), expectedData, + 'Replace transaction replaces content correctly' ); + ve.dm.TransactionProcessor.rollback( doc, tx ); + deepEqual( doc.getData(), ve.dm.example.data, + 'Replace transaction rolls back correctly' ); +} ); \ No newline at end of file