Index: trunk/parsers/wikidom/lib/es/es.js |
— | — | @@ -66,18 +66,21 @@ |
67 | 67 | function Selection( from, to ) { |
68 | 68 | this.from = from; |
69 | 69 | this.to = to; |
| 70 | + this.start = from; |
| 71 | + this.end = to; |
70 | 72 | } |
71 | 73 | |
72 | 74 | /** |
73 | 75 | * Ensures that "from" is before "to". |
74 | 76 | */ |
75 | 77 | Selection.prototype.normalize = function() { |
76 | | - if ( this.from.block.index() > this.to.block.index() |
77 | | - || ( this.from.block.index() === this.to.block.index() |
78 | | - && this.from.offset > this.to.offset ) ) { |
79 | | - var from = sel.from; |
80 | | - this.from = to; |
81 | | - this.to = from; |
| 78 | + if ( this.from.block.getIndex() < this.to.block.getIndex() |
| 79 | + || ( this.from.block === this.to.block && this.from.offset < this.to.offset ) ) { |
| 80 | + this.start = this.from; |
| 81 | + this.end = this.to; |
| 82 | + } else { |
| 83 | + this.start = this.to; |
| 84 | + this.end = this.from; |
82 | 85 | } |
83 | 86 | }; |
84 | 87 | |
Index: trunk/parsers/wikidom/lib/es/es.Surface.js |
— | — | @@ -197,13 +197,14 @@ |
198 | 198 | */ |
199 | 199 | Surface.prototype.drawSelection = function() { |
200 | 200 | if ( this.selection.from && this.selection.to ) { |
| 201 | + this.selection.normalize(); |
201 | 202 | var from = { |
202 | | - 'location': this.selection.from, |
203 | | - 'position': this.selection.from.block.getPosition( this.selection.from.offset ) |
| 203 | + 'location': this.selection.start, |
| 204 | + 'position': this.selection.start.block.getPosition( this.selection.start.offset ) |
204 | 205 | }, |
205 | 206 | to = { |
206 | | - 'location': this.selection.to, |
207 | | - 'position': this.selection.to.block.getPosition( this.selection.to.offset ) |
| 207 | + 'location': this.selection.end, |
| 208 | + 'position': this.selection.end.block.getPosition( this.selection.end.offset ) |
208 | 209 | }; |
209 | 210 | if ( from.location.block === to.location.block ) { |
210 | 211 | var block = from.location.block, |
— | — | @@ -214,12 +215,6 @@ |
215 | 216 | this.$rangeFill.hide(); |
216 | 217 | this.$rangeEnd.hide(); |
217 | 218 | } else if ( from.position.line === to.position.line ) { |
218 | | - // Normalize from/to |
219 | | - if ( from.location.offset > to.location.offset ) { |
220 | | - var temp = to; |
221 | | - to = from; |
222 | | - from = temp; |
223 | | - } |
224 | 219 | // Single line selection |
225 | 220 | this.$rangeStart |
226 | 221 | .css( { |
— | — | @@ -232,12 +227,6 @@ |
233 | 228 | this.$rangeFill.hide(); |
234 | 229 | this.$rangeEnd.hide(); |
235 | 230 | } else { |
236 | | - // Normalize from/to |
237 | | - if ( from.position.line > to.position.line ) { |
238 | | - var temp = to; |
239 | | - to = from; |
240 | | - from = temp; |
241 | | - } |
242 | 231 | // Multiple line selection |
243 | 232 | var blockWidth = block.$.width(); |
244 | 233 | this.$rangeStart |
— | — | @@ -270,12 +259,6 @@ |
271 | 260 | } |
272 | 261 | } |
273 | 262 | } else { |
274 | | - // Normalize from/to |
275 | | - if ( from.location.block.getIndex() > to.location.block.getIndex() ) { |
276 | | - var temp = to; |
277 | | - to = from; |
278 | | - from = temp; |
279 | | - } |
280 | 263 | // Multiple block selection |
281 | 264 | var blockWidth = Math.max( |
282 | 265 | from.location.block.$.width(), |
— | — | @@ -449,3 +432,46 @@ |
450 | 433 | this.document.updateBlocks(); |
451 | 434 | } |
452 | 435 | }; |
| 436 | + |
| 437 | +/** |
| 438 | + * Applies an annotation to a given selection. |
| 439 | + * |
| 440 | + * If a selection argument is not provided, the current selection will be annotated. |
| 441 | + * |
| 442 | + * @param annotation {Object} Annotation to apply |
| 443 | + * @param selection {Selection} Range to apply annotation to |
| 444 | + */ |
| 445 | +Surface.prototype.annotateContent= function( annotation, selection ) { |
| 446 | + if ( selection === undefined ) { |
| 447 | + selection = this.selection; |
| 448 | + } |
| 449 | + if ( selection.from && selection.to ) { |
| 450 | + selection.normalize(); |
| 451 | + var from = selection.start, |
| 452 | + to = selection.end; |
| 453 | + if ( from.block === to.block ) { |
| 454 | + // Single block annotation |
| 455 | + from.block.annotateContent( annotation, from.offset, to.offset ); |
| 456 | + from.block.renderContent(); |
| 457 | + } else { |
| 458 | + // Multiple block annotation |
| 459 | + for ( var i = from.block.getIndex(), end = to.block.getIndex(); i <= end; i++ ) { |
| 460 | + var block = this.document.blocks[i]; |
| 461 | + if ( block === from.block ) { |
| 462 | + // From offset to length |
| 463 | + block.annotateContent( annotation, from.offset, block.getLength() ); |
| 464 | + block.renderContent(); |
| 465 | + } else if ( block === to.block ) { |
| 466 | + // From 0 to offset |
| 467 | + block.annotateContent( annotation, 0, to.offset ); |
| 468 | + block.renderContent(); |
| 469 | + } else { |
| 470 | + // Full coverage |
| 471 | + block.annotateContent( annotation, 0, block.getLength() ); |
| 472 | + block.renderContent(); |
| 473 | + } |
| 474 | + } |
| 475 | + } |
| 476 | + } |
| 477 | + this.drawSelection(); |
| 478 | +}; |
Index: trunk/parsers/wikidom/lib/es/es.Block.js |
— | — | @@ -70,23 +70,12 @@ |
71 | 71 | |
72 | 72 | /** |
73 | 73 | * Renders content into a container. |
74 | | - * |
75 | | - * @param $container {jQuery Selection} Container to render into |
76 | 74 | */ |
77 | | -Block.prototype.renderContent = function( $container ) { |
| 75 | +Block.prototype.renderContent = function() { |
78 | 76 | throw 'Block.renderContent not implemented in this subclass.'; |
79 | 77 | }; |
80 | 78 | |
81 | 79 | /** |
82 | | - * Updates the rendered content in a container. |
83 | | - * |
84 | | - * @param $container {jQuery Selection} Container to update content in |
85 | | - */ |
86 | | -Block.prototype.updateContent = function( $container ) { |
87 | | - throw 'Block.updateContent not implemented in this subclass.'; |
88 | | -}; |
89 | | - |
90 | | -/** |
91 | 80 | * Gets the offset of a position. |
92 | 81 | * |
93 | 82 | * @param position {Integer} Offset to translate |
— | — | @@ -103,3 +92,16 @@ |
104 | 93 | Block.prototype.getPosition = function( offset ) { |
105 | 94 | throw 'Block.getPosition not implemented in this subclass.'; |
106 | 95 | }; |
| 96 | + |
| 97 | +/** |
| 98 | + * Applies an annotation to a given range. |
| 99 | + * |
| 100 | + * If a range arguments are not provided, all content will be annotated. |
| 101 | + * |
| 102 | + * @param annotation {Object} Annotation to apply |
| 103 | + * @param start {Integer} Offset to begin annotating from |
| 104 | + * @param end {Integer} Offset to stop annotating to |
| 105 | + */ |
| 106 | +Block.prototype.annotateContent = function( annotation, start, end ) { |
| 107 | + throw 'Block.annotateContent not implemented in this subclass.'; |
| 108 | +}; |
Index: trunk/parsers/wikidom/lib/es/es.Content.js |
— | — | @@ -2,6 +2,23 @@ |
3 | 3 | this.data = content || [];
|
4 | 4 | };
|
5 | 5 |
|
| 6 | +Content.compareObjects = function( a, b ) {
|
| 7 | + for ( var key in a ) {
|
| 8 | + if ( typeof a[key] !== typeof b[key] ) {
|
| 9 | + return false
|
| 10 | + } else if ( typeof a[key] === 'string' || typeof a[key] === 'number' ) {
|
| 11 | + if ( a[key] !== b[key] ) {
|
| 12 | + return false;
|
| 13 | + }
|
| 14 | + } else if ( $.isPlainObject( a[key] ) ) {
|
| 15 | + if ( !Content.compareObjects( a[key], b[key] ) ) {
|
| 16 | + return false;
|
| 17 | + }
|
| 18 | + }
|
| 19 | + }
|
| 20 | + return true;
|
| 21 | +};
|
| 22 | +
|
6 | 23 | Content.copyObject = function( src ) {
|
7 | 24 | var dst = {};
|
8 | 25 | for ( var key in src ) {
|
— | — | @@ -163,6 +180,70 @@ |
164 | 181 | return out;
|
165 | 182 | };
|
166 | 183 |
|
| 184 | +/**
|
| 185 | + * Applies an annotation to a given range.
|
| 186 | + *
|
| 187 | + * If a range arguments are not provided, all content will be annotated.
|
| 188 | + *
|
| 189 | + * @param annotation {Object} Annotation to apply
|
| 190 | + * @param start {Integer} Offset to begin annotating from
|
| 191 | + * @param end {Integer} Offset to stop annotating to
|
| 192 | + */
|
| 193 | +Content.prototype.annotate = function( annotation, start, end ) {
|
| 194 | + start = Math.max( start, 0 );
|
| 195 | + end = Math.min( end, this.data.length );
|
| 196 | + for ( var i = start; i < end; i++ ) {
|
| 197 | + switch ( annotation.method ) {
|
| 198 | + case 'add':
|
| 199 | + if ( typeof this.data[i] === 'string' ) {
|
| 200 | + this.data[i] = [this.data[i]];
|
| 201 | + }
|
| 202 | + this.data[i].push( annotation );
|
| 203 | + break;
|
| 204 | + case 'remove':
|
| 205 | + if ( typeof this.data[i] !== 'string' ) {
|
| 206 | + if ( annotation.type === 'all' ) {
|
| 207 | + this.data[i] = this.data[i][0];
|
| 208 | + } else {
|
| 209 | + for ( var j = 1; j < this.data[i].length; j++ ) {
|
| 210 | + if ( this.data[i][j].type === annotation.type
|
| 211 | + && Content.compareObjects(
|
| 212 | + this.data[i][j].data, annotation.data
|
| 213 | + )
|
| 214 | + ) {
|
| 215 | + this.data[i].splice( j, 1 );
|
| 216 | + j--;
|
| 217 | + }
|
| 218 | + }
|
| 219 | + }
|
| 220 | + }
|
| 221 | + break;
|
| 222 | + case 'toggle':
|
| 223 | + var on = true;
|
| 224 | + if ( typeof this.data[i] !== 'string' ) {
|
| 225 | + for ( var j = 1; j < this.data[i].length; j++ ) {
|
| 226 | + if ( this.data[i][j].type === annotation.type
|
| 227 | + && Content.compareObjects(
|
| 228 | + this.data[i][j].data, annotation.data
|
| 229 | + )
|
| 230 | + ) {
|
| 231 | + this.data[i].splice( j, 1 );
|
| 232 | + j--;
|
| 233 | + on = false;
|
| 234 | + }
|
| 235 | + }
|
| 236 | + }
|
| 237 | + if ( on ) {
|
| 238 | + if ( typeof this.data[i] === 'string' ) {
|
| 239 | + this.data[i] = [this.data[i]];
|
| 240 | + }
|
| 241 | + this.data[i].push( annotation );
|
| 242 | + }
|
| 243 | + break;
|
| 244 | + }
|
| 245 | + }
|
| 246 | +};
|
| 247 | +
|
167 | 248 | Content.htmlCharacters = {
|
168 | 249 | '&': '&',
|
169 | 250 | '<': '<',
|
Index: trunk/parsers/wikidom/lib/es/es.ParagraphBlock.js |
— | — | @@ -85,4 +85,17 @@ |
86 | 86 | return this.flow.getPosition( offset ); |
87 | 87 | }; |
88 | 88 | |
| 89 | +/** |
| 90 | + * Applies an annotation to a given range. |
| 91 | + * |
| 92 | + * If a range arguments are not provided, all content will be annotated. |
| 93 | + * |
| 94 | + * @param annotation {Object} Annotation to apply |
| 95 | + * @param start {Integer} Offset to begin annotating from |
| 96 | + * @param end {Integer} Offset to stop annotating to |
| 97 | + */ |
| 98 | +Block.prototype.annotateContent = function( annotation, start, end ) { |
| 99 | + this.content.annotate( annotation, start, end ); |
| 100 | +}; |
| 101 | + |
89 | 102 | extend( ParagraphBlock, Block ); |
Index: trunk/parsers/wikidom/demos/es/index.html |
— | — | @@ -40,6 +40,7 @@ |
41 | 41 | <div class="es-toolbarTool" id="es-toolbar-bold"><img src="images/bold.png"></div> |
42 | 42 | <div class="es-toolbarTool" id="es-toolbar-italic"><img src="images/italic.png"></div> |
43 | 43 | <div class="es-toolbarTool" id="es-toolbar-link"><img src="images/link.png"></div> |
| 44 | + <div class="es-toolbarTool" id="es-toolbar-clear"><img src="images/clear.png"></div> |
44 | 45 | <div style="clear:both"></div> |
45 | 46 | </div> |
46 | 47 | <div id="es-editor"></div> |
— | — | @@ -89,6 +90,32 @@ |
90 | 91 | ]); |
91 | 92 | var surface = new Surface( $('#es-editor'), doc ); |
92 | 93 | |
| 94 | + $( '#es-toolbar-bold' ).click( function() { |
| 95 | + surface.annotateContent( { |
| 96 | + 'method': 'toggle', |
| 97 | + 'type': 'bold' |
| 98 | + } ); |
| 99 | + } ); |
| 100 | + $( '#es-toolbar-italic' ).click( function() { |
| 101 | + surface.annotateContent( { |
| 102 | + 'method': 'toggle', |
| 103 | + 'type': 'italic' |
| 104 | + } ); |
| 105 | + } ); |
| 106 | + $( '#es-toolbar-link' ).click( function() { |
| 107 | + surface.annotateContent( { |
| 108 | + 'method': 'toggle', |
| 109 | + 'type': 'xlink', |
| 110 | + 'data': { 'href': '#' } |
| 111 | + } ); |
| 112 | + } ); |
| 113 | + $( '#es-toolbar-clear' ).click( function() { |
| 114 | + surface.annotateContent( { |
| 115 | + 'method': 'remove', |
| 116 | + 'type': 'all' |
| 117 | + } ); |
| 118 | + } ); |
| 119 | + |
93 | 120 | $(window).resize( function() { |
94 | 121 | surface.render(); |
95 | 122 | } ); |