Index: trunk/parsers/wikidom/tests/transactions/test.js |
— | — | @@ -39,18 +39,30 @@ |
40 | 40 | |
41 | 41 | /* Tests */ |
42 | 42 | |
43 | | -test( 'Insert and delete', 2, function() { |
44 | | - var Op = es.Content.Operation, |
45 | | - Tx = es.Content.Transaction; |
46 | | - |
47 | | - var tx = new Tx( |
48 | | - content, |
49 | | - new Op( 'retain', 5 ), |
50 | | - new Op( 'insert', 'used to be' ), |
51 | | - new Op( 'delete', 2 ), |
52 | | - new Op( 'retain', 18 ) |
53 | | - ); |
54 | | - |
55 | | - equal( tx.commit( content ).getText(), 'This used to be a test paragraph!', 'Committing' ); |
56 | | - equal( tx.rollback( content ).getText(), 'This is a test paragraph!', 'Rolling back' ); |
| 43 | +test( 'Insert, retain and remove', 4, function() { |
| 44 | + var transactions = { |
| 45 | + 'by calling constructor manually': new es.Content.Transaction( |
| 46 | + content, |
| 47 | + new es.Content.Operation( 'retain', 5 ), |
| 48 | + new es.Content.Operation( 'insert', 'used to be' ), |
| 49 | + new es.Content.Operation( 'remove', 2 ), |
| 50 | + new es.Content.Operation( 'retain', 18 ) |
| 51 | + ), |
| 52 | + 'using es.Content.Transaction.newFromReplace': new es.Content.Transaction.newFromReplace( |
| 53 | + content, new es.Range( 5, 7), 'used to be' |
| 54 | + ) |
| 55 | + }; |
| 56 | + for ( var method in transactions ) { |
| 57 | + var transaction = transactions[method]; |
| 58 | + equal( |
| 59 | + transaction.commit( content ).getText(), |
| 60 | + 'This used to be a test paragraph!', |
| 61 | + 'Committing transaction built with ' + method |
| 62 | + ); |
| 63 | + equal( |
| 64 | + transaction.rollback( content ).getText(), |
| 65 | + 'This is a test paragraph!', |
| 66 | + 'Rolling back transaction built ' + method |
| 67 | + ); |
| 68 | + } |
57 | 69 | } ); |
Index: trunk/parsers/wikidom/lib/es/es.Content.Transaction.js |
— | — | @@ -3,19 +3,24 @@ |
4 | 4 | * |
5 | 5 | * @class |
6 | 6 | * @constructor |
7 | | - * @param operations {Array} List of operations |
| 7 | + * @param operations {Array} List of operations - can also be the first in a list of variadic |
| 8 | + * arguments, each containing a single operation |
8 | 9 | * @property operations {Array} List of operations |
9 | 10 | */ |
10 | 11 | es.Content.Transaction = function( content, operations ) { |
11 | 12 | this.content = content; |
12 | 13 | this.operations = []; |
13 | 14 | if ( arguments.length > 1 ) { |
| 15 | + // Support variadic arguments |
| 16 | + if ( !$.isArray( operations ) ) { |
| 17 | + operations = Array.prototype.slice.call( arguments, 1 ); |
| 18 | + } |
14 | 19 | var range = new es.Range(); |
15 | | - for ( var i = 1; i < arguments.length; i++ ) { |
16 | | - var operation = arguments[i]; |
| 20 | + for ( var i = 0; i < operations.length; i++ ) { |
| 21 | + var operation = operations[i]; |
17 | 22 | switch ( operation.getType() ) { |
18 | 23 | case 'retain': |
19 | | - case 'delete': |
| 24 | + case 'remove': |
20 | 25 | range.to = range.from + operation.getLength(); |
21 | 26 | if ( !operation.hasContent() ) { |
22 | 27 | operation.setContent( content.getContent( range ) ); |
— | — | @@ -28,8 +33,38 @@ |
29 | 34 | } |
30 | 35 | }; |
31 | 36 | |
32 | | -es.Content.Transaction.prototype.add = function( operation ) { |
33 | | - this.operations.push( operation ); |
| 37 | +/** |
| 38 | + * Builds a transaction that removes and or inserts content. |
| 39 | + * |
| 40 | + * @param content {es.Content} Content to operate on |
| 41 | + * @param range {es.Range} Range of content to remove, or zero length range when inserting only |
| 42 | + * @param insert {es.Content} Content to insert (optional) |
| 43 | + */ |
| 44 | +es.Content.Transaction.newFromReplace = function( content, range, insert ) { |
| 45 | + var operations = []; |
| 46 | + range.normalize(); |
| 47 | + if ( content.getLength() ) { |
| 48 | + // Delete range |
| 49 | + if ( range.start ) { |
| 50 | + // Use content up until the range begins |
| 51 | + operations.push( new es.Content.Operation( 'retain', range.start ) ); |
| 52 | + } |
| 53 | + // Skip over the range |
| 54 | + if ( range.getLength() ) { |
| 55 | + operations.push( new es.Content.Operation( 'remove', range.getLength() ) ); |
| 56 | + } |
| 57 | + } |
| 58 | + if ( insert ) { |
| 59 | + // Add content to the output |
| 60 | + operations.push( new es.Content.Operation( 'insert', insert ) ); |
| 61 | + } |
| 62 | + // Retain remaining content |
| 63 | + if ( range.end < content.getLength() ) { |
| 64 | + operations.push( |
| 65 | + new es.Content.Operation( 'retain', content.getLength() - range.end ) |
| 66 | + ); |
| 67 | + } |
| 68 | + return new es.Content.Transaction( content, operations ); |
34 | 69 | }; |
35 | 70 | |
36 | 71 | es.Content.Transaction.prototype.commit = function() { |
— | — | @@ -50,7 +85,7 @@ |
51 | 86 | case 'insert': |
52 | 87 | to.insert( to.getLength(), operation.getContent().getData() ); |
53 | 88 | break; |
54 | | - case 'delete': |
| 89 | + case 'remove': |
55 | 90 | range.to = range.from + operation.getLength(); |
56 | 91 | // Automatically add content to operation |
57 | 92 | if ( !operation.hasContent() ) { |
— | — | @@ -74,7 +109,7 @@ |
75 | 110 | to.insert( to.getLength(), operation.getContent().getData() ); |
76 | 111 | range.from = range.to; |
77 | 112 | break; |
78 | | - case 'delete': |
| 113 | + case 'remove': |
79 | 114 | to.insert( to.getLength(), operation.getContent().getData() ); |
80 | 115 | break; |
81 | 116 | case 'insert': |
Index: trunk/parsers/wikidom/lib/es/es.Content.Operation.js |
— | — | @@ -26,7 +26,7 @@ |
27 | 27 | this.length = this.content.getLength(); |
28 | 28 | break; |
29 | 29 | } |
30 | | - this.data = data || {}; |
| 30 | + this.data = data || null; |
31 | 31 | }; |
32 | 32 | |
33 | 33 | es.Content.Operation.prototype.getType = function() { |