Index: trunk/parsers/wikidom/lib/es/es.TextFlow.js |
— | — | @@ -3,10 +3,14 @@ |
4 | 4 | * |
5 | 5 | * @extends {EventEmitter} |
6 | 6 | * @param $container {jQuery Selection} Element to render into |
| 7 | + * @param content {Content} Initial content to render |
7 | 8 | * @returns {TextFlow} |
8 | 9 | */ |
9 | 10 | function TextFlow( $container, content ) { |
| 11 | + // Inheritance |
10 | 12 | EventEmitter.call( this ); |
| 13 | + |
| 14 | + // Members |
11 | 15 | this.$ = $container; |
12 | 16 | this.content = content || new Content(); |
13 | 17 | this.boundaries = []; |
— | — | @@ -16,6 +20,7 @@ |
17 | 21 | this.widthCache = {}; |
18 | 22 | this.renderState = {}; |
19 | 23 | |
| 24 | + // Events |
20 | 25 | var flow = this; |
21 | 26 | this.content.on( 'change', function() { |
22 | 27 | flow.scanBoundaries(); |
— | — | @@ -29,8 +34,9 @@ |
30 | 35 | this.content.on( 'annotate', function( args ) { |
31 | 36 | flow.render( args.start ); |
32 | 37 | } ); |
| 38 | + |
| 39 | + // Initialization |
33 | 40 | this.scanBoundaries(); |
34 | | - this.render(); |
35 | 41 | } |
36 | 42 | |
37 | 43 | /** |
— | — | @@ -104,8 +110,8 @@ |
105 | 111 | /** |
106 | 112 | * Gets position coordinates of a given offset. |
107 | 113 | * |
108 | | - * Offsets are boundaries between content. Results are given in left, top and bottom positions, |
109 | | - * which could be used to draw a cursor, highlighting painting, etc. |
| 114 | + * Offsets are boundaries between plain or annotated characters within content. Results are given in |
| 115 | + * left, top and bottom positions, which could be used to draw a cursor, highlighting, etc. |
110 | 116 | * |
111 | 117 | * @param offset {Integer} Offset within content |
112 | 118 | * @return {Object} Object containing left, top and bottom properties, each positions in pixels |
— | — | @@ -179,6 +185,9 @@ |
180 | 186 | return position; |
181 | 187 | }; |
182 | 188 | |
| 189 | +/** |
| 190 | + * Updates the word boundary cache, which is used for word fitting. |
| 191 | + */ |
183 | 192 | TextFlow.prototype.scanBoundaries = function() { |
184 | 193 | /* |
185 | 194 | * Word boundary scan |
— | — | @@ -213,6 +222,13 @@ |
214 | 223 | } |
215 | 224 | }; |
216 | 225 | |
| 226 | +/** |
| 227 | + * Renders a batch of lines and then yields execution before rendering another batch. |
| 228 | + * |
| 229 | + * In cases where a single word is too long to fit on a line, the word will be "virtually" wrapped, |
| 230 | + * causing them to be fragmented. Word fragments are rendered on their own lines, except for their |
| 231 | + * remainder, which is combined with whatever proceeding words can fit on the same line. |
| 232 | + */ |
217 | 233 | TextFlow.prototype.renderIteration = function() { |
218 | 234 | var rs = this.renderState, |
219 | 235 | iteration = 0; |
— | — | @@ -268,25 +284,28 @@ |
269 | 285 | /** |
270 | 286 | * Renders text into a series of HTML elements, each a single line of wrapped text. |
271 | 287 | * |
272 | | - * In cases where a single word is too long to fit on a line, the word will be "virtually" wrapped, |
273 | | - * causing them to be fragmented. Word fragments are rendered on their own lines, except for their |
274 | | - * remainder, which is combined with whatever proceeding words can fit on the same line. |
275 | | - * |
276 | 288 | * The offset parameter can be used to reduce the amount of work involved in re-rendering the same |
277 | 289 | * text, but will be automatically ignored if the text or width of the container has changed. |
278 | 290 | * |
| 291 | + * Rendering happens asynchronously, and yields execution between iterations. Iterative rendering |
| 292 | + * provides the JavaScript engine an ability to process events between rendering batches of lines, |
| 293 | + * allowing rendering to be interrupted and restarted if changes to content are happening before |
| 294 | + * rendering of all lines is complete. |
| 295 | + * |
279 | 296 | * @param offset {Integer} Offset to re-render from, if possible (not yet implemented) |
280 | 297 | */ |
281 | 298 | TextFlow.prototype.render = function( offset ) { |
282 | 299 | var rs = this.renderState; |
283 | 300 | |
284 | | - // Stop iterating from last render |
| 301 | + // Check if rendering is currently underway |
285 | 302 | if ( rs.timeout !== undefined ) { |
| 303 | + // Cancel the active rendering process |
286 | 304 | clearTimeout( rs.timeout ); |
287 | 305 | // Cleanup |
288 | 306 | rs.$ruler.remove(); |
289 | 307 | } |
290 | 308 | |
| 309 | + // Clear caches that were specific to the previous render |
291 | 310 | this.widthCache = {}; |
292 | 311 | |
293 | 312 | /* |
— | — | @@ -299,17 +318,17 @@ |
300 | 319 | rs.$ruler = $( '<div> </div>' ).appendTo( this.$ ); |
301 | 320 | rs.width = rs.$ruler.innerWidth(); |
302 | 321 | |
303 | | - // TODO: Take offset into account |
304 | 322 | // Ignore offset optimization if the width has changed or the text has never been flowed before |
305 | | - //if (this.width !== width) { |
306 | | - // offset = undefined; |
307 | | - //} |
| 323 | + if (this.width !== rs.width) { |
| 324 | + offset = undefined; |
| 325 | + } |
| 326 | + this.width = rs.width; |
308 | 327 | |
309 | | - // TODO: Take offset into account and only work from there |
310 | | - |
| 328 | + // TODO: Only clear lines that are below the line above the offset, or the nearest line above |
| 329 | + // that which is not a fractional line |
311 | 330 | this.lines = []; |
312 | | - // Iterate over each word that will fit in a line, appending them to the DOM as we go |
313 | 331 | |
| 332 | + // Reset the render state |
314 | 333 | rs.wordOffset = 0; |
315 | 334 | rs.lineStart = 0; |
316 | 335 | rs.lineEnd = 0; |
— | — | @@ -320,6 +339,7 @@ |
321 | 340 | rs.ruler = rs.$ruler.addClass('editSurface-ruler')[0]; |
322 | 341 | rs.iterationLimit = 3; |
323 | 342 | |
| 343 | + // Begin rendering |
324 | 344 | this.renderIteration(); |
325 | 345 | }; |
326 | 346 | |