Index: trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js |
— | — | @@ -37,8 +37,8 @@ |
38 | 38 | /** |
39 | 39 | * Deletes content in a block within a range. |
40 | 40 | * |
41 | | - * @param offset {Integer} Offset to start removing content from |
42 | | - * @param length {Integer} Offset to start removing content to |
| 41 | + * @param start {Integer} Offset to start removing content from |
| 42 | + * @param end {Integer} Offset to start removing content to |
43 | 43 | */ |
44 | 44 | es.ParagraphBlock.prototype.deleteContent = function( start, end ) { |
45 | 45 | // Normalize start/end |
— | — | @@ -51,6 +51,27 @@ |
52 | 52 | }; |
53 | 53 | |
54 | 54 | /** |
| 55 | + * Gets content within a range. |
| 56 | + * |
| 57 | + * @param start {Integer} Offset to get content from |
| 58 | + * @param end {Integer} Offset to get content to |
| 59 | + */ |
| 60 | +es.Block.prototype.getContent = function( start, end ) { |
| 61 | + return this.content.slice( start, end ); |
| 62 | +}; |
| 63 | + |
| 64 | +/** |
| 65 | + * Gets content as plain text within a range. |
| 66 | + * |
| 67 | + * @param start {Integer} Offset to start get text from |
| 68 | + * @param end {Integer} Offset to start get text to |
| 69 | + * @param render {Boolean} If annotations should have any influence on output |
| 70 | + */ |
| 71 | +es.Block.prototype.getText = function( start, end, render ) { |
| 72 | + return this.content.getText( start, end, render ); |
| 73 | +}; |
| 74 | + |
| 75 | +/** |
55 | 76 | * Renders content into a container. |
56 | 77 | * |
57 | 78 | * @param $container {jQuery Selection} Container to render into |
Index: trunk/parsers/wikidom/lib/es/es.Surface.js |
— | — | @@ -66,6 +66,15 @@ |
67 | 67 | 'blur': function( e ) { |
68 | 68 | $document.unbind('.editSurface'); |
69 | 69 | surface.cursor.hide(); |
| 70 | + }, |
| 71 | + 'cut': function( e ) { |
| 72 | + return surface.onCut( e ); |
| 73 | + }, |
| 74 | + 'copy': function( e ) { |
| 75 | + return surface.onCopy( e ); |
| 76 | + }, |
| 77 | + 'paste': function( e ) { |
| 78 | + return surface.onPaste( e ); |
70 | 79 | } |
71 | 80 | } ); |
72 | 81 | |
— | — | @@ -121,10 +130,16 @@ |
122 | 131 | } |
123 | 132 | this.drawSelection(); |
124 | 133 | } |
125 | | - break; |
| 134 | + break; |
126 | 135 | case 17: // Control |
127 | 136 | this.ctrlDown = true; |
128 | 137 | break; |
| 138 | + case 18: // Alt |
| 139 | + this.altDown = true; |
| 140 | + break; |
| 141 | + case 91: // Command |
| 142 | + this.commandDown = true; |
| 143 | + break; |
129 | 144 | case 37: // Left arrow |
130 | 145 | this.initialHorizontalCursorPosition = null; |
131 | 146 | this.moveCursorLeft(); |
— | — | @@ -171,6 +186,9 @@ |
172 | 187 | this.handleDelete(); |
173 | 188 | break; |
174 | 189 | default: |
| 190 | + if ( this.ctrlDown || this.altDown || this.commandDown ) { |
| 191 | + break; |
| 192 | + } |
175 | 193 | this.initialHorizontalCursorPosition = null; |
176 | 194 | this.cursor.hide(); |
177 | 195 | if ( this.keyboard.keydownTimeout ) { |
— | — | @@ -178,28 +196,49 @@ |
179 | 197 | } |
180 | 198 | var surface = this; |
181 | 199 | this.keyboard.keydownTimeout = setTimeout( function () { |
182 | | - var val = surface.$input.val(); |
183 | | - surface.$input.val( '' ); |
184 | | - if ( val.length > 0 ) { |
185 | | - if ( surface.selection.from && surface.selection.to ) { |
186 | | - var deleteSelection = surface.selection; |
187 | | - deleteSelection.normalize(); |
188 | | - surface.location = surface.selection.start; |
189 | | - surface.deleteContent( deleteSelection ); |
190 | | - } |
191 | | - var insertLocation = surface.location; |
192 | | - surface.selection = new es.Selection(); |
193 | | - surface.location = new es.Location( |
194 | | - surface.location.block, surface.location.offset + val.length |
195 | | - ); |
196 | | - surface.insertContent( insertLocation, val.split('') ); |
197 | | - } |
| 200 | + surface.insertFromInput(); |
198 | 201 | }, 10 ); |
199 | 202 | break; |
200 | 203 | } |
201 | 204 | return true; |
202 | 205 | }; |
203 | 206 | |
| 207 | +es.Surface.prototype.insertFromInput = function() { |
| 208 | + var val = this.$input.val(); |
| 209 | + this.$input.val( '' ); |
| 210 | + if ( val.length > 0 ) { |
| 211 | + if ( this.selection.from && this.selection.to ) { |
| 212 | + var deleteSelection = this.selection; |
| 213 | + deleteSelection.normalize(); |
| 214 | + this.location = this.selection.start; |
| 215 | + this.deleteContent( deleteSelection ); |
| 216 | + } |
| 217 | + var insertLocation = this.location; |
| 218 | + this.selection = new es.Selection(); |
| 219 | + this.location = new es.Location( |
| 220 | + this.location.block, this.location.offset + val.length |
| 221 | + ); |
| 222 | + this.insertContent( insertLocation, val.split('') ); |
| 223 | + } |
| 224 | +}; |
| 225 | + |
| 226 | +es.Surface.prototype.onCut = function( e ) { |
| 227 | + // TODO: Keep a Content object copy of the selection |
| 228 | +}; |
| 229 | + |
| 230 | +es.Surface.prototype.onCopy = function( e ) { |
| 231 | + // TODO: Keep a Content object copy of the selection |
| 232 | +}; |
| 233 | + |
| 234 | +es.Surface.prototype.onPaste = function( e ) { |
| 235 | + // TODO: If clipboard data is same as previous copy, use the Content object version |
| 236 | + var surface = this; |
| 237 | + // Catch content just AFTER paste |
| 238 | + setTimeout( function() { |
| 239 | + surface.insertFromInput(); |
| 240 | + }, 0 ); |
| 241 | +}; |
| 242 | + |
204 | 243 | es.Surface.prototype.onKeyUp = function( e ) { |
205 | 244 | switch ( e.keyCode ) { |
206 | 245 | case 16: // Shift |
— | — | @@ -211,6 +250,12 @@ |
212 | 251 | case 17: // Control |
213 | 252 | this.ctrlDown = false; |
214 | 253 | break; |
| 254 | + case 18: // Alt |
| 255 | + this.altDown = false; |
| 256 | + break; |
| 257 | + case 91: // Command |
| 258 | + this.commandDown = false; |
| 259 | + break; |
215 | 260 | default: |
216 | 261 | var surface = this; |
217 | 262 | setTimeout( function() { |
— | — | @@ -307,7 +352,7 @@ |
308 | 353 | } |
309 | 354 | this.initialHorizontalCursorPosition = null; |
310 | 355 | if ( !this.$input.is(':focus') ) { |
311 | | - this.$input.focus(); |
| 356 | + this.$input.focus().select(); |
312 | 357 | } |
313 | 358 | return false; |
314 | 359 | }; |
— | — | @@ -335,8 +380,9 @@ |
336 | 381 | * @return {Boolean} If selection is visibly painted |
337 | 382 | */ |
338 | 383 | es.Surface.prototype.drawSelection = function() { |
339 | | - var blockWidth; |
340 | | - |
| 384 | + var blockWidth, |
| 385 | + text = ''; |
| 386 | + |
341 | 387 | if ( this.selection.from && this.selection.to ) { |
342 | 388 | this.selection.normalize(); |
343 | 389 | var from = { |
— | — | @@ -399,12 +445,13 @@ |
400 | 446 | this.$rangeFill.hide(); |
401 | 447 | } |
402 | 448 | } |
| 449 | + text += from.location.block.getText( from.location.offset, to.location.offset ); |
403 | 450 | } else { |
404 | 451 | // Multiple block selection |
405 | 452 | blockWidth = Math.max( |
406 | | - from.location.block.$.width(), |
407 | | - to.location.block.$.width() |
408 | | - ); |
| 453 | + from.location.block.$.width(), |
| 454 | + to.location.block.$.width() |
| 455 | + ); |
409 | 456 | var fromBlockOffset = from.location.block.$.offset(), |
410 | 457 | toBlockOffset = to.location.block.$.offset(), |
411 | 458 | blockLeft = Math.min( fromBlockOffset.left, toBlockOffset.left ); |
— | — | @@ -433,10 +480,13 @@ |
434 | 481 | - ( fromBlockOffset.top + from.position.bottom ) |
435 | 482 | } ) |
436 | 483 | .show(); |
| 484 | + // TODO: Get text from multiple-block selection |
437 | 485 | } |
| 486 | + this.$input.val( text ).select(); |
438 | 487 | this.$ranges.show(); |
439 | 488 | return true; |
440 | 489 | } |
| 490 | + this.$input.val( text ).select(); |
441 | 491 | this.$ranges.hide(); |
442 | 492 | return false; |
443 | 493 | }; |
Index: trunk/parsers/wikidom/lib/es/es.Block.js |
— | — | @@ -77,14 +77,35 @@ |
78 | 78 | /** |
79 | 79 | * Deletes content in a block within a range. |
80 | 80 | * |
81 | | - * @param offset {Integer} Position to start removing content from |
82 | | - * @param length {Integer} Length of content to remove |
| 81 | + * @param offset {Integer} Offset to start removing content from |
| 82 | + * @param length {Integer} Offset to start removing content to |
83 | 83 | */ |
84 | | -es.Block.prototype.deleteContent = function( offset, length ) { |
| 84 | +es.Block.prototype.deleteContent = function( start, end ) { |
85 | 85 | throw 'Block.deleteContent not implemented in this subclass.'; |
86 | 86 | }; |
87 | 87 | |
88 | 88 | /** |
| 89 | + * Gets content within a range. |
| 90 | + * |
| 91 | + * @param start {Integer} Offset to get content from |
| 92 | + * @param end {Integer} Offset to get content to |
| 93 | + */ |
| 94 | +es.Block.prototype.getContent = function( start, end ) { |
| 95 | + throw 'Block.getContent not implemented in this subclass.'; |
| 96 | +}; |
| 97 | + |
| 98 | +/** |
| 99 | + * Gets content as plain text within a range. |
| 100 | + * |
| 101 | + * @param start {Integer} Offset to start get text from |
| 102 | + * @param end {Integer} Offset to start get text to |
| 103 | + * @param render {Boolean} If annotations should have any influence on output |
| 104 | + */ |
| 105 | +es.Block.prototype.getText = function( start, end, render ) { |
| 106 | + throw 'Block.getText not implemented in this subclass.'; |
| 107 | +}; |
| 108 | + |
| 109 | +/** |
89 | 110 | * Renders content into a container. |
90 | 111 | */ |
91 | 112 | es.Block.prototype.renderContent = function() { |
Index: trunk/parsers/wikidom/lib/es/es.Content.js |
— | — | @@ -262,11 +262,15 @@ |
263 | 263 | * |
264 | 264 | * Range arguments (start and end) are clamped if out of range. |
265 | 265 | * |
| 266 | + * TODO: Implement render option, which will allow annotations to influence output, such as an |
| 267 | + * image outputing it's URL |
| 268 | + * |
266 | 269 | * @param start {Integer} Optional beginning of range, if omitted range will begin at 0 |
267 | 270 | * @param end {Integer} Optional end of range, if omitted range will end a this.data.length |
| 271 | + * @param render {Boolean} If annotations should have any influence on output |
268 | 272 | * @return {String} Plain text within given range |
269 | 273 | */ |
270 | | -es.Content.prototype.substring = function( start, end ) { |
| 274 | +es.Content.prototype.getText = function( start, end, render ) { |
271 | 275 | // Wrap values |
272 | 276 | start = Math.max( 0, start || 0 ); |
273 | 277 | if ( end === undefined ) { |
Index: trunk/parsers/wikidom/lib/es/es.TextFlow.js |
— | — | @@ -201,7 +201,7 @@ |
202 | 202 | * "boundaries" array. Slices of the "words" array can be joined, producing the escaped HTML of |
203 | 203 | * the words. |
204 | 204 | */ |
205 | | - var text = this.content.substring(); |
| 205 | + var text = this.content.getText(); |
206 | 206 | // Purge "boundaries" and "words" arrays |
207 | 207 | this.boundaries = [0]; |
208 | 208 | // Reset RegExp object's state |
— | — | @@ -381,7 +381,7 @@ |
382 | 382 | $line[0].innerHTML = this.content.render( start, end ); |
383 | 383 | // Collect line information |
384 | 384 | rs.lines.push({ |
385 | | - 'text': this.content.substring( start, end ), |
| 385 | + 'text': this.content.getText( start, end ), |
386 | 386 | 'start': start, |
387 | 387 | 'end': end, |
388 | 388 | 'width': $line.outerWidth(), |