r94717 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94716‎ | r94717 | r94718 >
Date:00:52, 17 August 2011
Author:tparscal
Status:deferred
Tags:
Comment:
* Rewrote transactions - they actually work now (whee!)
* Made automatic annotation from neighboring content optional
Modified paths:
  • /trunk/parsers/wikidom/lib/es/es.Block.js (modified) (history)
  • /trunk/parsers/wikidom/lib/es/es.Content.Operation.js (deleted) (history)
  • /trunk/parsers/wikidom/lib/es/es.Content.Transaction.js (modified) (history)
  • /trunk/parsers/wikidom/lib/es/es.Content.js (modified) (history)
  • /trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js (modified) (history)
  • /trunk/parsers/wikidom/lib/es/es.Surface.js (modified) (history)
  • /trunk/parsers/wikidom/tests/transactions/index.html (modified) (history)
  • /trunk/parsers/wikidom/tests/transactions/test.js (modified) (history)

Diff [purge]

Index: trunk/parsers/wikidom/tests/transactions/index.html
@@ -13,8 +13,6 @@
1414 <script src="../../lib/es/es.js"></script>
1515 <script src="../../lib/es/es.EventEmitter.js"></script>
1616 <script src="../../lib/es/es.Content.js"></script>
17 - <script src="../../lib/es/es.Content.Operation.js"></script>
18 - <script src="../../lib/es/es.Content.Selection.js"></script>
1917 <script src="../../lib/es/es.Content.Transaction.js"></script>
2018 <script src="../../lib/es/es.Range.js"></script>
2119 <script src="../../lib/jquery.js"></script>
Index: trunk/parsers/wikidom/tests/transactions/test.js
@@ -40,20 +40,8 @@
4141 /* Tests */
4242
4343 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( es.Content.newFromText( '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), new es.Content.newFromText( 'used to be' )
54 - )
55 - };
56 - var before = content.getData(),
57 - after = [
 44+ var before = content.getContent(),
 45+ after = new es.Content( [
5846 ["T", { "type": "italic" }],
5947 ["h", { "type": "italic" }],
6048 ["i", { "type": "italic" }],
@@ -87,39 +75,28 @@
8876 "p",
8977 "h",
9078 "!"
91 - ];
92 - for ( var method in transactions ) {
93 - var transaction = transactions[method];
94 - deepEqual(
95 - transaction.commit( content ).getData(),
96 - after,
97 - 'Committing transaction built with ' + method
98 - );
99 - deepEqual(
100 - transaction.rollback( content ).getData(),
101 - before,
102 - 'Rolling back transaction built ' + method
103 - );
104 - }
 79+ ] );
 80+
 81+ var tx = new es.Content.Transaction(),
 82+ insertion = es.Content.newFromText( 'used to be' ),
 83+ removal = content.getContent( new es.Range( 5, 7 ) );
 84+
 85+ tx.add( 'retain', 5 );
 86+ tx.add( 'insert', insertion );
 87+ tx.add( 'remove', removal );
 88+ tx.add( 'retain', 18 );
 89+
 90+ var committed = tx.commit( content );
 91+ equal( committed.getText(), after.getText(), 'Committing' );
 92+ deepEqual( committed.getData(), after.getData(), 'Committing' );
 93+ var rolledback = tx.rollback( committed );
 94+ equal( rolledback.getText(), before.getText(), 'Rolling back' );
 95+ deepEqual( rolledback.getData(), before.getData(), 'Rolling back' );
10596 } );
10697
107 -/*
10898 test( 'Annotating', 4, function() {
109 - var transactions = {
110 - 'by calling constructor manually': new es.Content.Transaction(
111 - content,
112 - new es.Content.Operation( 'retain', 4 ),
113 - new es.Content.Operation( 'begin', { 'type': 'italic' } ),
114 - new es.Content.Operation( 'retain', 3 ),
115 - new es.Content.Operation( 'end', { 'type': 'italic' } ),
116 - new es.Content.Operation( 'retain', 18 )
117 - ),
118 - 'using es.Content.Transaction.newFromAnnotate': new es.Content.Transaction.newFromAnnotate(
119 - content, new es.Range( 4, 7), 'add', { 'type': 'italic' }
120 - )
121 - };
122 - var before = content.getData(),
123 - after = [
 99+ var before = content.getContent(),
 100+ after = new es.Content( [
124101 ["T", { "type": "italic" }],
125102 ["h", { "type": "italic" }],
126103 ["i", { "type": "italic" }],
@@ -145,19 +122,22 @@
146123 "p",
147124 "h",
148125 "!"
149 - ];
150 - for ( var method in transactions ) {
151 - var transaction = transactions[method];
152 - deepEqual(
153 - transaction.commit( content ).getData(),
154 - after,
155 - 'Committing transaction built with ' + method
156 - );
157 - deepEqual(
158 - transaction.rollback( content ).getData(),
159 - before,
160 - 'Rolling back transaction built ' + method
161 - );
162 - }
 126+ ] );
 127+
 128+ var tx = new es.Content.Transaction(),
 129+ annotation = { 'method': 'add', 'annotation': { 'type': 'italic' } };
 130+
 131+ tx.add( 'retain', 4 );
 132+ tx.add( 'start', annotation );
 133+ tx.add( 'retain', 3 );
 134+ tx.add( 'end', annotation );
 135+ tx.add( 'retain', 18 );
 136+
 137+ var committed = tx.commit( content );
 138+
 139+ equal( committed.getText(), after.getText(), 'Committing' );
 140+ deepEqual( committed.getData(), after.getData(), 'Committing' );
 141+ var rolledback = tx.rollback( committed );
 142+ equal( rolledback.getText(), before.getText(), 'Rolling back' );
 143+ deepEqual( rolledback.getData(), before.getData(), 'Rolling back' );
163144 } );
164 -*/
\ No newline at end of file
Index: trunk/parsers/wikidom/lib/es/es.Content.Operation.js
@@ -1,162 +0,0 @@
2 -/**
3 - * Creates an operation to be applied to a content object.
4 - *
5 - * @class
6 - * @constructor
7 - */
8 -
9 -es.Content.Operation = function( type, content, data ) {
10 - this.type = type;
11 - this.content = content || null;
12 - this.data = data || null;
13 -};
14 -
15 -es.Content.Operation.prototype.getType = function() {
16 - return this.type;
17 -};
18 -
19 -es.Content.Operation.prototype.getContent = function() {
20 - return this.content;
21 -};
22 -
23 -es.Content.Operation.prototype.setContent = function( content ) {
24 - this.content = content;
25 -};
26 -
27 -es.Content.Operation.prototype.hasContent = function() {
28 - return !!this.content;
29 -};
30 -
31 -es.Content.Operation.prototype.getLength = function() {
32 - return 0;
33 -};
34 -
35 -es.Content.Operation.prototype.getAdvance = function() {
36 - return 0
37 -};
38 -
39 -es.Content.Operation.prototype.getData = function() {
40 - return this.data;
41 -};
42 -
43 -es.Content.Operation.prototype.setData = function() {
44 - return this.data;
45 -};
46 -
47 -es.Content.Operation.prototype.commit = function( content, annotations ) {
48 - throw 'es.Content.Operation.commit not implemented in this subclass.';
49 -};
50 -
51 -es.Content.Operation.prototype.rollback = function( content, annotations ) {
52 - throw 'es.Content.Operation.rollback not implemented in this subclass.';
53 -};
54 -
55 -/**
56 - * @class
57 - * @constructor
58 - */
59 -es.Content.Operation.Retain = function( length ) {
60 - es.Content.Operation.call( this, 'remove' );
61 - this.type = 'retain';
62 - this.content = null;
63 - this.length = length;
64 -};
65 -es.extend( es.Content.Operation.Retain, es.Content.Operation );
66 -
67 -es.Content.Operation.Retain.prototype.getLength = function() {
68 - return this.length;
69 -};
70 -
71 -es.Content.Operation.Retain.prototype.getAdvance = function() {
72 - return this.length;
73 -};
74 -
75 -es.Content.Operation.Retain.prototype.commit = function( content, annotations ) {
76 - content.insert( content.getLength(), this.content.getData() );
77 - return this.length;
78 -};
79 -
80 -es.Content.Operation.Retain.prototype.rollback = es.Content.Operation.Retain.prototype.commit;
81 -
82 -/**
83 - * @class
84 - * @constructor
85 - */
86 -es.Content.Operation.Insert = function( content ) {
87 - es.Content.Operation.call( this, 'insert', content );
88 -};
89 -es.extend( es.Content.Operation.Insert, es.Content.Operation );
90 -
91 -es.Content.Operation.Insert.prototype.getLength = function() {
92 - return this.content.getLength();
93 -};
94 -
95 -es.Content.Operation.Insert.prototype.commit = function( content, annotations ) {
96 - content.insert( content.getLength(), this.content.getData() );
97 - return 0;
98 -};
99 -
100 -es.Content.Operation.Insert.prototype.rollback = function( content, annotations ) {
101 - return this.content.getLength();
102 -};
103 -
104 -/**
105 - * @class
106 - * @constructor
107 - */
108 -es.Content.Operation.Remove = function( length ) {
109 - es.Content.Operation.call( this, 'remove' );
110 - this.length = length;
111 -};
112 -es.extend( es.Content.Operation.Remove, es.Content.Operation );
113 -
114 -es.Content.Operation.Remove.prototype.getLength = function() {
115 - return this.length;
116 -};
117 -
118 -es.Content.Operation.Remove.prototype.getAdvance = function() {
119 - return this.length;
120 -};
121 -
122 -es.Content.Operation.Remove.prototype.commit = es.Content.Operation.Insert.prototype.rollback;
123 -es.Content.Operation.Remove.prototype.rollback = es.Content.Operation.Insert.prototype.commit;
124 -
125 -/**
126 - * @class
127 - * @constructor
128 - */
129 -es.Content.Operation.Begin = function( annotation ) {
130 - es.Content.Operation.call( this, 'begin', null, annotation );
131 -};
132 -es.extend( es.Content.Operation.Begin, es.Content.Operation );
133 -
134 -es.Content.Operation.Begin.prototype.commit = function( content, annotations ) {
135 - annotations.push( this.data );
136 - return 0;
137 -};
138 -
139 -es.Content.Operation.Begin.prototype.rollback = function( content, annotations ) {
140 - var index;
141 - for ( var i = 0; i < annotations.length; i++ ) {
142 - if ( es.Content.compareObjects( annotations[i], this.data ) ) {
143 - index = i;
144 - }
145 - }
146 - if ( index === undefined ) {
147 - throw 'Annotation stack error. Annotation is missing.';
148 - }
149 - annotations.splice( index, 1 );
150 - return 0;
151 -};
152 -
153 -/**
154 - * @class
155 - * @constructor
156 - */
157 -es.Content.Operation.End = function( annotation ) {
158 - es.Content.Operation.call( this, 'end', null, annotation );
159 -};
160 -es.extend( es.Content.Operation.End, es.Content.Operation );
161 -
162 -es.Content.Operation.End.prototype.commit = es.Content.Operation.Begin.prototype.rollback;
163 -es.Content.Operation.End.prototype.rollback = es.Content.Operation.Begin.prototype.commit;
Index: trunk/parsers/wikidom/lib/es/es.Content.Transaction.js
@@ -3,125 +3,166 @@
44 *
55 * @class
66 * @constructor
7 - * @param operations {Array} List of operations - can also be the first in a list of variadic
8 - * arguments, each containing a single operation
 7+ * @param content {es.Content} Content to operate on
98 * @property operations {Array} List of operations
109 */
11 -es.Content.Transaction = function( content, operations ) {
12 - this.content = content;
 10+es.Content.Transaction = function() {
1311 this.operations = [];
14 - this.length = 0;
15 - if ( arguments.length > 1 ) {
16 - // Support variadic arguments
17 - if ( !$.isArray( operations ) ) {
18 - operations = Array.prototype.slice.call( arguments, 1 );
19 - }
20 - for ( var i = 0; i < operations.length; i++ ) {
21 - this.add( operations[i] );
22 - }
23 - }
 12+ this.cursor = 0;
2413 };
2514
26 -es.Content.Transaction.prototype.add = function( operation ) {
27 - // Auto-add content to operations which affect a range but don't have content (yet)
28 - var range = new es.Range( this.length, this.length + operation.getLength() );
29 - if ( operation.getLength() && !operation.hasContent() ) {
30 - if ( !operation.hasContent() ) {
31 - operation.setContent( content.getContent( range ) );
32 - }
33 - }
34 - this.length += operation.getAdvance();
35 - this.operations.push( operation );
36 -};
37 -
3815 /**
39 - * Builds a transaction that removes and or inserts content.
40 - *
41 - * @param content {es.Content} Content to operate on
42 - * @param range {es.Range} Range of content to remove, or zero length range when inserting only
43 - * @param insert {es.Content} Content to insert (optional)
 16+ * List of operation implementations.
4417 */
45 -es.Content.Transaction.newFromReplace = function( content, range, insert ) {
46 - var transaction = new es.Content.Transaction( content );
47 - range.normalize();
48 - if ( content.getLength() ) {
49 - // Delete range
50 - if ( range.start ) {
51 - // Use content up until the range begins
52 - transaction.add( new es.Content.Operation.Retain( range.start ) );
 18+es.Content.Transaction.operations = ( function() {
 19+ function annotate( con, add, rem ) {
 20+ // Ensure that modifications to annotated characters do not affect other uses of the same
 21+ // content by isolating it - performing a deep-slice
 22+ con.isolate();
 23+ for ( var i = 0; i < add.length; i++ ) {
 24+ con.annotate( 'add', add[i] );
5325 }
54 - // Skip over the range
55 - if ( range.getLength() ) {
56 - transaction.add( new es.Content.Operation.Remove( range.getLength() ) );
 26+ for ( var i = 0; i < rem.length; i++ ) {
 27+ con.annotate( 'remove', rem[i] );
5728 }
5829 }
59 - if ( insert ) {
60 - // Add content to the output
61 - transaction.add( new es.Content.Operation.Insert( insert ) );
 30+ function retain( val, cur, src, dst, add, rem ) {
 31+ var con = src.getContent( new es.Range( cur, cur + val ) );
 32+ if ( add.length || rem.length ) {
 33+ annotate( con, add, rem );
 34+ }
 35+ dst.insert( dst.getLength(), con.getData() );
 36+ return val;
6237 }
63 - // Retain remaining content
64 - if ( range.end < content.getLength() ) {
65 - transaction.add( new es.Content.Operation.Retain( content.getLength() - range.end ) );
 38+ function insert( val, cur, src, dst, add, rem ) {
 39+ var con = val.getContent();
 40+ if ( add.length || rem.length ) {
 41+ annotate( con, add, rem );
 42+ }
 43+ dst.insert( dst.getLength(), con.getData() );
 44+ return 0;
6645 }
67 - return transaction;
68 -};
69 -
70 -/**
71 - * Builds a transaction that applies annotations
72 - *
73 - * TODO: Support method argument
74 - *
75 - * @param content {es.Content} Content to operate on
76 - * @param range {es.Range} Range of content to annotate, content will be retained
77 - * @param method {String} Mode of application; "add", "remove", or "toggle"
78 - * @param annotation {Object} Annotation to apply
79 - */
80 -es.Content.Transaction.newFromAnnotate = function( content, range, method, annotation ) {
81 - var transaction = new es.Content.Transaction();
82 - range.normalize();
83 - if ( content.getLength() ) {
84 - if ( range.start ) {
85 - // Use content up until the range begins
86 - transaction.add( new es.Content.Operation.Retain( range.start ) );
 46+ function start( val, cur, src, dst, add, rem ) {
 47+ if ( val.method === 'add' ) {
 48+ add.push( val.annotation );
 49+ } else if ( val.method === 'remove' ) {
 50+ rem.push( val.annotation );
 51+ } else {
 52+ throw 'Annotation method error. Unsupported annotation method: ' + val.method;
8753 }
88 - if ( range.getLength() ) {
89 - // Apply annotation to range
90 - transaction.add( new es.Content.Operation.Begin( annotation ) );
91 - transaction.add( new es.Content.Operation.Retain( range.getLength() ) );
92 - transaction.add( new es.Content.Operation.End( annotation ) );
 54+ return 0;
 55+ }
 56+ function end( val, cur, src, dst, add, rem ) {
 57+ var stack;
 58+ if ( val.method === 'add' ) {
 59+ stack = add;
 60+ } else if ( val.method === 'remove' ) {
 61+ stack = rem;
 62+ } else {
 63+ throw 'Annotation method error. Unsupported annotation method: ' + val.method;
9364 }
94 - // Retain remaining content
95 - if ( range.end < content.getLength() ) {
96 - transaction.add( new es.Content.Operation.Begin( content.getLength() - range.end ) );
 65+ var index;
 66+ for ( var i = 0; i < stack.length; i++ ) {
 67+ // TODO: Compare data too: es.Content.compareObjects( stack[i], val.annotation )
 68+ if ( stack[i].type === val.annotation.type ) {
 69+ index = i;
 70+ break;
 71+ }
9772 }
 73+ if ( index === undefined ) {
 74+ throw 'Annotation stack error. Annotation is missing.';
 75+ }
 76+ stack.splice( index, 1 );
 77+ return 0;
9878 }
99 - return transaction;
 79+ function measure( val ) {
 80+ return val.getLength();
 81+ }
 82+ function pass( val ) {
 83+ return val;
 84+ }
 85+ function zero( val ) {
 86+ return 0;
 87+ }
 88+ return {
 89+ 'retain': {
 90+ 'commit': retain,
 91+ 'rollback': retain,
 92+ 'advance': pass
 93+ },
 94+ 'insert': {
 95+ 'commit': insert,
 96+ 'rollback': measure,
 97+ 'advance': zero
 98+ },
 99+ 'remove': {
 100+ 'commit': measure,
 101+ 'rollback': insert,
 102+ 'advance': measure
 103+ },
 104+ 'start': {
 105+ 'commit': start,
 106+ 'rollback': function( val, cur, src, dst, add, rem ) {
 107+ return start( val, cur, src, dst, rem, add );
 108+ },
 109+ 'advance': zero
 110+ },
 111+ 'end': {
 112+ 'commit': end,
 113+ 'rollback': function( val, cur, src, dst, add, rem ) {
 114+ return end( val, cur, src, dst, rem, add );
 115+ },
 116+ 'advance': zero
 117+ }
 118+ };
 119+} )();
 120+
 121+es.Content.Transaction.prototype.getCursor = function() {
 122+ return this.cursor;
100123 };
101124
102 -es.Content.Transaction.prototype.commit = function() {
103 - var offset = 0,
104 - content = new es.Content(),
105 - annotations = [];
106 - for ( var i = 0; i < this.operations.length; i++ ) {
107 - var length = this.operations[i].commit( content, annotations );
108 - // TODO: Apply annotations in stack
109 - offset += length;
 125+es.Content.Transaction.prototype.reset = function() {
 126+ this.operations = [];
 127+ this.cursor = 0;
 128+};
 129+
 130+es.Content.Transaction.prototype.add = function( type, val ) {
 131+ if ( !( type in es.Content.Transaction.operations ) ) {
 132+ throw 'Unknown operation error. Operation type is not supported: ' + type;
110133 }
111 - return content;
 134+ var model = es.Content.Transaction.operations[type];
 135+ this.operations.push( {
 136+ 'type': type,
 137+ 'val': val,
 138+ 'model': model
 139+ } );
 140+ this.cursor += model.advance( val );
112141 };
113142
114 -es.Content.Transaction.prototype.rollback = function() {
115 - var offset = 0,
116 - content = new es.Content(),
117 - annotations = [];
 143+es.Content.Transaction.prototype.commit = function( src ) {
 144+ var cur = 0,
 145+ dst = new es.Content(),
 146+ add = [],
 147+ rem = [],
 148+ adv;
118149 for ( var i = 0; i < this.operations.length; i++ ) {
119 - var length = this.operations[i].rollback( content, annotations );
120 - // TODO: Apply annotations in stack
121 - offset += length;
 150+ var op = this.operations[i];
 151+ adv = op.model.commit( op.val, cur, src, dst, add, rem );
 152+ cur += adv;
122153 }
123 - return content;
 154+ return dst;
124155 };
125156
126 -es.Content.Transaction.prototype.optimize = function() {
127 - // reduce consecutive operations of the same type to single operations if possible
 157+es.Content.Transaction.prototype.rollback = function( src ) {
 158+ var cur = 0,
 159+ dst = new es.Content(),
 160+ add = [],
 161+ rem = [],
 162+ adv;
 163+ for ( var i = 0; i < this.operations.length; i++ ) {
 164+ var op = this.operations[i];
 165+ adv = op.model.rollback( op.val, cur, src, dst, add, rem );
 166+ cur += adv;
 167+ }
 168+ return dst;
128169 };
Index: trunk/parsers/wikidom/lib/es/es.Content.js
@@ -380,9 +380,8 @@
381381 es.Content.prototype.getContent = function( range ) {
382382 if ( !range ) {
383383 range = new es.Range( 0, this.data.length );
384 - } else {
385 - range.normalize();
386384 }
 385+ range.normalize();
387386 return new es.Content( this.data.slice( range.start, range.end ) );
388387 };
389388
@@ -396,13 +395,32 @@
397396 es.Content.prototype.getData = function( range ) {
398397 if ( !range ) {
399398 range = new es.Range( 0, this.data.length );
400 - } else {
401 - range.normalize();
402399 }
 400+ range.normalize();
403401 return this.data.slice( range.start, range.end );
404402 };
405403
406404 /**
 405+ * Breaks cross references, which occur when content is copied around.
 406+ *
 407+ * Because content data is an array of characters, or arrays containing a character and any
 408+ * number of references to annotation objects, slicing the array still leaves annotated characters
 409+ * as references to shared memory. This should be used only when annotations are going to be
 410+ * changed because it is rather expensive.
 411+ *
 412+ * @method
 413+ */
 414+es.Content.prototype.isolate = function() {
 415+ var i = 0,
 416+ length = this.data.length;
 417+ while ( i < length ) {
 418+ // The slice method works for array or string character type
 419+ this.data[i] = this.data[i].slice( 0 );
 420+ i++;
 421+ }
 422+};
 423+
 424+/**
407425 * Inserts content data at a specific position.
408426 *
409427 * Inserted content will inherit annotations from neighboring content.
@@ -413,17 +431,19 @@
414432 * @emits "insert" with offset and content data properties
415433 * @emits "change" with type:"insert" data property
416434 */
417 -es.Content.prototype.insert = function( offset, content ) {
418 - // TODO: Prefer to not take annotations from a neighbor that's a space character
419 - var neighbor = this.data[Math.max( offset - 1, 0 )];
420 - if ( $.isArray( neighbor ) ) {
421 - var annotations = neighbor.slice( 1 );
422 - var i;
423 - for ( i = 0; i < content.length; i++ ) {
424 - if ( typeof content[i] === 'string' ) {
425 - content[i] = [content[i]];
 435+es.Content.prototype.insert = function( offset, content, autoAnnotate ) {
 436+ if ( autoAnnotate ) {
 437+ // TODO: Prefer to not take annotations from a neighbor that's a space character
 438+ var neighbor = this.data[Math.max( offset - 1, 0 )];
 439+ if ( $.isArray( neighbor ) ) {
 440+ var annotations = neighbor.slice( 1 );
 441+ var i;
 442+ for ( i = 0; i < content.length; i++ ) {
 443+ if ( typeof content[i] === 'string' ) {
 444+ content[i] = [content[i]];
 445+ }
 446+ content[i] = content[i].concat( annotations );
426447 }
427 - content[i] = content[i].concat( annotations );
428448 }
429449 }
430450 Array.prototype.splice.apply( this.data, [offset, 0].concat( content ) );
@@ -554,7 +574,7 @@
555575 if ( this.data[i] === '\n' ) {
556576 continue;
557577 }
558 - // Auto-initialize as annotated character
 578+ // Auto-convert to annotated character format
559579 this.data[i] = [this.data[i]];
560580 } else {
561581 // Detect duplicate annotation
@@ -581,6 +601,10 @@
582602 while ( ( j = this.indexOfAnnotation( i, annotation ) ) !== -1 ) {
583603 this.data[i].splice( j, 1 );
584604 }
 605+ // Auto-convert to plain character format
 606+ if ( this.data[i].length === 1 ) {
 607+ this.data[i] = this.data[i][0];
 608+ }
585609 }
586610 }
587611 }
Index: trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js
@@ -57,9 +57,10 @@
5858 * @method
5959 * @param offset {Integer} Position to insert content at
6060 * @param content {Object} Content to insert
 61+ * @param autoAnnotate {Boolean} Content to insert
6162 */
62 -es.ParagraphBlock.prototype.insertContent = function( offset, content ) {
63 - this.content.insert( offset, content );
 63+es.ParagraphBlock.prototype.insertContent = function( offset, content, autoAnnotate ) {
 64+ this.content.insert( offset, content, autoAnnotate );
6465 };
6566
6667 /**
Index: trunk/parsers/wikidom/lib/es/es.Surface.js
@@ -693,7 +693,7 @@
694694 if ( typeof location.block === 'undefined' || typeof location.offset === 'undefined' ) {
695695 throw 'Invalid selection error. Properties for from and to locations expected.';
696696 }
697 - this.location.block.insertContent( location.offset, content );
 697+ this.location.block.insertContent( location.offset, content, true );
698698 };
699699
700700 es.Surface.prototype.deleteContent = function( selection ) {
Index: trunk/parsers/wikidom/lib/es/es.Block.js
@@ -108,8 +108,9 @@
109109 * @method
110110 * @param offset {Integer} Position to insert content at
111111 * @param content {Object} Content to insert
 112+ * @param autoAnnotate {Boolean} Content to insert
112113 */
113 -es.Block.prototype.insertContent = function( offset, content ) {
 114+es.Block.prototype.insertContent = function( offset, content, autoAnnotate ) {
114115 throw 'Block.insertContent not implemented in this subclass.';
115116 };
116117

Status & tagging log