r94593 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r94592‎ | r94593 | r94594 >
Date:23:54, 15 August 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Refactoring of operations and transaction code - still need to finish annotation functionality
Modified paths:
  • /trunk/parsers/wikidom/lib/es/es.Content.Operation.js (modified) (history)
  • /trunk/parsers/wikidom/lib/es/es.Content.Transaction.js (modified) (history)
  • /trunk/parsers/wikidom/tests/transactions/test.js (modified) (history)

Diff [purge]

Index: trunk/parsers/wikidom/tests/transactions/test.js
@@ -43,13 +43,13 @@
4444 var transactions = {
4545 'by calling constructor manually': new es.Content.Transaction(
4646 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 )
 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 )
5151 ),
5252 'using es.Content.Transaction.newFromReplace': new es.Content.Transaction.newFromReplace(
53 - content, new es.Range( 5, 7), 'used to be'
 53+ content, new es.Range( 5, 7), new es.Content.newFromText( 'used to be' )
5454 )
5555 };
5656 var before = content.getData(),
@@ -87,7 +87,7 @@
8888 "p",
8989 "h",
9090 "!"
91 - ]
 91+ ];
9292 for ( var method in transactions ) {
9393 var transaction = transactions[method];
9494 deepEqual(
@@ -102,3 +102,62 @@
103103 );
104104 }
105105 } );
 106+
 107+/*
 108+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 = [
 124+ ["T", { "type": "italic" }],
 125+ ["h", { "type": "italic" }],
 126+ ["i", { "type": "italic" }],
 127+ ["s", { "type": "italic" }],
 128+ [" ", { "type": "italic" }],
 129+ ["i", { "type": "italic" }],
 130+ ["s", { "type": "italic" }],
 131+ " ",
 132+ ["a", { "type": "xlink", "data": { "url":"http://www.a.com" } }],
 133+ [" ", { "type": "xlink", "data": { "url":"http://www.a.com" } }],
 134+ ["t", { "type": "xlink", "data": { "url":"http://www.a.com" } }, { "type": "bold" }],
 135+ ["e", { "type": "xlink", "data": { "url":"http://www.a.com" } }, { "type": "bold" }],
 136+ ["s", { "type": "xlink", "data": { "url":"http://www.a.com" } }, { "type": "bold" }],
 137+ ["t", { "type": "xlink", "data": { "url":"http://www.a.com" } }, { "type": "bold" }],
 138+ " ",
 139+ "p",
 140+ "a",
 141+ "r",
 142+ "a",
 143+ "g",
 144+ "r",
 145+ "a",
 146+ "p",
 147+ "h",
 148+ "!"
 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+ }
 163+} );
 164+*/
\ No newline at end of file
Index: trunk/parsers/wikidom/lib/es/es.Content.Transaction.js
@@ -10,29 +10,30 @@
1111 es.Content.Transaction = function( content, operations ) {
1212 this.content = content;
1313 this.operations = [];
 14+ this.length = 0;
1415 if ( arguments.length > 1 ) {
1516 // Support variadic arguments
1617 if ( !$.isArray( operations ) ) {
1718 operations = Array.prototype.slice.call( arguments, 1 );
1819 }
19 - var range = new es.Range();
2020 for ( var i = 0; i < operations.length; i++ ) {
21 - var operation = operations[i];
22 - switch ( operation.getType() ) {
23 - case 'retain':
24 - case 'remove':
25 - range.to = range.from + operation.getLength();
26 - if ( !operation.hasContent() ) {
27 - operation.setContent( content.getContent( range ) );
28 - }
29 - range.from = range.to;
30 - break;
31 - }
32 - this.operations.push( operation );
 21+ this.add( operations[i] );
3322 }
3423 }
3524 };
3625
 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+
3738 /**
3839 * Builds a transaction that removes and or inserts content.
3940 *
@@ -41,84 +42,84 @@
4243 * @param insert {es.Content} Content to insert (optional)
4344 */
4445 es.Content.Transaction.newFromReplace = function( content, range, insert ) {
45 - var operations = [];
 46+ var transaction = new es.Content.Transaction( content );
4647 range.normalize();
4748 if ( content.getLength() ) {
4849 // Delete range
4950 if ( range.start ) {
5051 // Use content up until the range begins
51 - operations.push( new es.Content.Operation( 'retain', range.start ) );
 52+ transaction.add( new es.Content.Operation.Retain( range.start ) );
5253 }
5354 // Skip over the range
5455 if ( range.getLength() ) {
55 - operations.push( new es.Content.Operation( 'remove', range.getLength() ) );
 56+ transaction.add( new es.Content.Operation.Remove( range.getLength() ) );
5657 }
5758 }
5859 if ( insert ) {
5960 // Add content to the output
60 - operations.push( new es.Content.Operation( 'insert', insert ) );
 61+ transaction.add( new es.Content.Operation.Insert( insert ) );
6162 }
6263 // Retain remaining content
6364 if ( range.end < content.getLength() ) {
64 - operations.push(
65 - new es.Content.Operation( 'retain', content.getLength() - range.end )
66 - );
 65+ transaction.add( new es.Content.Operation.Retain( content.getLength() - range.end ) );
6766 }
68 - return new es.Content.Transaction( content, operations );
 67+ return transaction;
6968 };
7069
 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 ) );
 87+ }
 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 ) );
 93+ }
 94+ // Retain remaining content
 95+ if ( range.end < content.getLength() ) {
 96+ transaction.add( new es.Content.Operation.Begin( content.getLength() - range.end ) );
 97+ }
 98+ }
 99+ return transaction;
 100+};
 101+
71102 es.Content.Transaction.prototype.commit = function() {
72 - var range = new es.Range(),
73 - to = new es.Content();
 103+ var offset = 0,
 104+ content = new es.Content(),
 105+ annotations = [];
74106 for ( var i = 0; i < this.operations.length; i++ ) {
75 - var operation = this.operations[i];
76 - switch (operation.getType()) {
77 - case 'retain':
78 - range.to = range.from + operation.getLength();
79 - // Automatically add content to operation
80 - if ( !operation.hasContent() ) {
81 - operation.setContent( this.content.getContent( range ) );
82 - }
83 - to.insert( to.getLength(), operation.getContent().getData() );
84 - range.from = range.to;
85 - break;
86 - case 'insert':
87 - to.insert( to.getLength(), operation.getContent().getData() );
88 - break;
89 - case 'remove':
90 - range.to = range.from + operation.getLength();
91 - // Automatically add content to operation
92 - if ( !operation.hasContent() ) {
93 - operation.setContent( this.content.getContent( range ) );
94 - }
95 - range.from = range.to;
96 - break;
97 - }
 107+ var length = this.operations[i].commit( content, annotations );
 108+ // TODO: Apply annotations in stack
 109+ offset += length;
98110 }
99 - return to;
 111+ return content;
100112 };
101113
102114 es.Content.Transaction.prototype.rollback = function() {
103 - var range = new es.Range(),
104 - to = new es.Content();
 115+ var offset = 0,
 116+ content = new es.Content(),
 117+ annotations = [];
105118 for ( var i = 0; i < this.operations.length; i++ ) {
106 - var operation = this.operations[i];
107 - switch (operation.getType()) {
108 - case 'retain':
109 - range.to = range.from + operation.getLength();
110 - to.insert( to.getLength(), operation.getContent().getData() );
111 - range.from = range.to;
112 - break;
113 - case 'remove':
114 - to.insert( to.getLength(), operation.getContent().getData() );
115 - break;
116 - case 'insert':
117 - range.to = range.from + operation.getLength();
118 - range.from = range.to;
119 - break;
120 - }
 119+ var length = this.operations[i].rollback( content, annotations );
 120+ // TODO: Apply annotations in stack
 121+ offset += length;
121122 }
122 - return to;
 123+ return content;
123124 };
124125
125126 es.Content.Transaction.prototype.optimize = function() {
Index: trunk/parsers/wikidom/lib/es/es.Content.Operation.js
@@ -3,29 +3,11 @@
44 *
55 * @class
66 * @constructor
7 - * @param type {String} Type of operation, e.g. insert, delete, annotate
8 - * @param content {Mixed} Either {Integer} length, {String} text or {es.Content} content
9 - * @param data {Object} Data of operation, e.g. range
10 - * @property type {String} Type of operation
11 - * @property content {es.Content} Content of operation
12 - * @property data {Object} Data of operation
137 */
 8+
149 es.Content.Operation = function( type, content, data ) {
1510 this.type = type;
16 - switch ( typeof content ) {
17 - case 'number':
18 - this.content = null;
19 - this.length = content;
20 - break;
21 - case 'string':
22 - this.content = es.Content.newFromText( content );
23 - this.length = this.content.getLength();
24 - break;
25 - case 'object':
26 - this.content = content;
27 - this.length = this.content.getLength();
28 - break;
29 - }
 11+ this.content = content || null;
3012 this.data = data || null;
3113 };
3214
@@ -46,9 +28,135 @@
4729 };
4830
4931 es.Content.Operation.prototype.getLength = function() {
50 - return this.content ? this.content.getLength() : this.length;
 32+ return 0;
5133 };
5234
 35+es.Content.Operation.prototype.getAdvance = function() {
 36+ return 0
 37+};
 38+
5339 es.Content.Operation.prototype.getData = function() {
5440 return this.data;
5541 };
 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;

Status & tagging log