r99057 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r99056‎ | r99057 | r99058 >
Date:22:30, 5 October 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Added hashing to annotation objects, making them faster to compare when performing annotation operations.
Modified paths:
  • /trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js (modified) (history)
  • /trunk/parsers/wikidom/tests/hype/es.DocumentModel.test.js (modified) (history)

Diff [purge]

Index: trunk/parsers/wikidom/tests/hype/es.DocumentModel.test.js
@@ -111,6 +111,7 @@
112112 *
113113 * {Array} Annotated character
114114 * {String} Character
 115+ * {String} Hash
115116 * {Object}... List of annotation object references
116117 *
117118 * {Object} Opening or closing structural element
@@ -124,9 +125,9 @@
125126 // 1 - Plain content
126127 'a',
127128 // 2 - Annotated content
128 - ['b', { 'type': 'bold' }],
 129+ ['b', { 'type': 'bold', 'hash': '#bold' }],
129130 // 3 - Annotated content
130 - ['c', { 'type': 'italic' }],
 131+ ['c', { 'type': 'italic', 'hash': '#italic' }],
131132 // 4 - End of paragraph
132133 { 'type': '/paragraph' },
133134 // 5 - Beginning of table
Index: trunk/parsers/wikidom/lib/hype/models/es.DocumentModel.js
@@ -76,7 +76,7 @@
7777 function retain( op ) {
7878 annotate.call( this, this.cursor + op.length );
7979 this.cursor += op.length;
80 - };
 80+ }
8181
8282 function insert( op ) {
8383 // Splice content into document in 1024 element chunks, as to not overflow max allowed
@@ -90,18 +90,18 @@
9191 }
9292 annotate.call( this, this.cursor + op.data.length );
9393 this.cursor += op.data.length;
94 - };
 94+ }
9595
9696 function remove( op ) {
9797 this.data.splice( this.cursor, op.data.length );
98 - };
 98+ }
9999
100100 function indexOfAnnotation( character, annotation ) {
101101 if ( $.isArray( character ) ) {
102102 // Find the index of a comparable annotation (checking for same value, not reference)
103103 var index;
104 - for ( var i = 0; i < target.length; i++ ) {
105 - if ( es.compareObjects( target[i], op.annotation ) ) {
 104+ for ( var i = 0; i < character.length; i++ ) {
 105+ if ( character[i].hash === op.annotation.hash ) {
106106 return index;
107107 }
108108 }
@@ -136,7 +136,7 @@
137137 } else {
138138 throw 'Invalid method error. Can not operate attributes this way: ' + method;
139139 }
140 - };
 140+ }
141141
142142 function annotate( to ) {
143143 // Handle annotations
@@ -150,6 +150,8 @@
151151 this.data[j] = [this.data[j], annotation];
152152 }
153153 }
 154+ // Rebuild annotation hash
 155+ annotation.hash = es.DocumentModel.getAnnotationHash( annotation );
154156 }
155157 }
156158 if ( this.clear.length ) {
@@ -161,6 +163,8 @@
162164 this.data[j].splice( index, 1 );
163165 }
164166 }
 167+ // Rebuild annotation hash
 168+ annotation.hash = es.DocumentModel.getAnnotationHash( annotation );
165169 }
166170 }
167171 }
@@ -177,15 +181,8 @@
178182 if ( op.bias === 'start' ) {
179183 target.push( op.annotation );
180184 } else if ( op.bias === 'end' ) {
181 - // Find the index of a comparable annotation (checking for same value, not reference)
182 - var index;
183 - for ( var i = 0; i < target.length; i++ ) {
184 - if ( es.compareObjects( target[i], op.annotation ) ) {
185 - index = i;
186 - break;
187 - }
188 - }
189 - if ( index === undefined ) {
 185+ var index = indexOfAnnotation( target[i], op.annotation );
 186+ if ( index === -1 ) {
190187 throw 'Annotation stack error. Annotation is missing.';
191188 }
192189 target.splice( index, 1 );
@@ -252,6 +249,29 @@
253250 };
254251
255252 /**
 253+ * Generates a hash of an annotation object based on it's name and data.
 254+ *
 255+ * TODO: Add support for deep hashing of array and object properties of annotation data.
 256+ *
 257+ * @static
 258+ * @method
 259+ * @param {Object} annotation Annotation object to generate hash for
 260+ * @returns {String} Hash of annotation
 261+ */
 262+es.DocumentModel.getAnnotationHash = function( annotation ) {
 263+ var hash = '#' + annotation.type;
 264+ if ( annotation.data ) {
 265+ var keys = [];
 266+ for ( var key in annotation.data ) {
 267+ keys.push( key + ':' + annotation.data );
 268+ }
 269+ keys.sort();
 270+ hash += '|' + keys.join( '|' );
 271+ }
 272+ return hash;
 273+};
 274+
 275+/**
256276 * Creates an es.ContentModel object from a plain content object.
257277 *
258278 * A plain content object contains plain text and a series of annotations to be applied to ranges of
@@ -288,12 +308,15 @@
289309 var data = obj.text.split('');
290310 // Render annotations
291311 if ( $.isArray( obj.annotations ) ) {
292 - $.each( obj.annotations, function( i, src ) {
 312+ for ( var i = 0, length = obj.annotations.length; i < length; i++ ) {
 313+ var src = obj.annotations[i];
293314 // Build simplified annotation object
294315 var dst = { 'type': src.type };
295316 if ( 'data' in src ) {
296317 dst.data = es.copyObject( src.data );
297318 }
 319+ // Add a hash to the annotation for faster comparison
 320+ dst.hash = es.DocumentModel.getAnnotationHash( dst );
298321 // Apply annotation to range
299322 if ( src.start < 0 ) {
300323 // TODO: The start can not be lower than 0! Throw error?
@@ -305,13 +328,13 @@
306329 // Clamp end value
307330 src.end = data.length;
308331 }
309 - for ( var i = src.start; i < src.end; i++ ) {
 332+ for ( var j = src.start; j < src.end; j++ ) {
310333 // Auto-convert to array
311 - typeof data[i] === 'string' && ( data[i] = [data[i]] );
 334+ typeof data[j] === 'string' && ( data[j] = [data[j]] );
312335 // Append
313 - data[i].push( dst );
 336+ data[j].push( dst );
314337 }
315 - } );
 338+ }
316339 }
317340 return data;
318341 }
@@ -488,7 +511,31 @@
489512 * @returns {es.Transaction}
490513 */
491514 es.DocumentModel.prototype.prepareInsertion = function( offset, data ) {
492 - //
 515+ /*
 516+ * There are 2 basic types of locations the insertion point can be:
 517+ * Structural locations
 518+ * |<p>a</p><p>b</p> - Beginning of the document
 519+ * <p>a</p>|<p>b</p> - Between elements (like in a document or list)
 520+ * <p>a</p><p>b</p>| - End of the document
 521+ * Content locations
 522+ * <p>|a</p><p>b</p> - Inside an element (like in a paragraph or listItem)
 523+ *
 524+ * if ( Incoming data contains structural elements ) {
 525+ * if ( Insertion point is a structural location ) {
 526+ * if ( Incoming data is not a complete structural element ) {
 527+ * Incoming data must be balanced
 528+ * }
 529+ * } else {
 530+ * Closing and opening elements for insertion point must be added to incoming data
 531+ * }
 532+ * } else {
 533+ * if ( Insertion point is a structural location ) {
 534+ * Incoming data must be balanced
 535+ * } else {
 536+ * Content being inserted into content is OK, do nothing
 537+ * }
 538+ * }
 539+ */
493540 };
494541
495542 /**

Status & tagging log