Index: trunk/parsers/wikidom/lib/es/es.Content.js |
— | — | @@ -2,23 +2,6 @@ |
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 | | -
|
23 | 6 | Content.copyObject = function( src ) {
|
24 | 7 | var dst = {};
|
25 | 8 | for ( var key in src ) {
|
— | — | @@ -196,6 +179,26 @@ |
197 | 180 | return out;
|
198 | 181 | };
|
199 | 182 |
|
| 183 | +Content.prototype.coverageOfAnnotation = function( start, end, annotation ) {
|
| 184 | + var coverage = [];
|
| 185 | + for ( var i = start; i < end; i++ ) {
|
| 186 | + if ( typeof this.data[i] !== 'string' && this.indexOfAnnotation( i, annotation ) !== -1 ) {
|
| 187 | + coverage.push( i );
|
| 188 | + }
|
| 189 | + }
|
| 190 | + return coverage;
|
| 191 | +};
|
| 192 | +
|
| 193 | +Content.prototype.indexOfAnnotation = function( offset, annotation ) {
|
| 194 | + var annotatedCharacter = this.data[offset];
|
| 195 | + for ( var i = 1; i < this.data[offset].length; i++ ) {
|
| 196 | + if ( annotatedCharacter[i].type === annotation.type ) {
|
| 197 | + return i;
|
| 198 | + }
|
| 199 | + }
|
| 200 | + return -1;
|
| 201 | +};
|
| 202 | +
|
200 | 203 | /**
|
201 | 204 | * Applies an annotation to a given range.
|
202 | 205 | *
|
— | — | @@ -208,67 +211,42 @@ |
209 | 212 | Content.prototype.annotate = function( annotation, start, end ) {
|
210 | 213 | start = Math.max( start, 0 );
|
211 | 214 | end = Math.min( end, this.data.length );
|
212 | | - for ( var i = start; i < end; i++ ) {
|
213 | | - switch ( annotation.method ) {
|
214 | | - case 'add':
|
215 | | - var duplicate = false;
|
216 | | - if ( typeof this.data[i] === 'string' ) {
|
217 | | - this.data[i] = [this.data[i]];
|
218 | | - } else {
|
219 | | - for ( var j = 1; j < this.data[i].length; j++ ) {
|
220 | | - if ( this.data[i][j].type === annotation.type
|
221 | | - && Content.compareObjects(
|
222 | | - this.data[i][j].data, annotation.data
|
223 | | - )
|
224 | | - ) {
|
225 | | - duplicate = true;
|
226 | | - }
|
227 | | - }
|
| 215 | + method = annotation.method;
|
| 216 | + if ( method === 'toggle' ) {
|
| 217 | + method = this.coverageOfAnnotation( start, end, annotation ).length === end - start
|
| 218 | + ? 'remove' : 'add';
|
| 219 | + }
|
| 220 | + if ( method === 'add' ) {
|
| 221 | + var skip;
|
| 222 | + for ( var i = start; i < end; i++ ) {
|
| 223 | + skip = false;
|
| 224 | + if ( typeof this.data[i] === 'string' ) {
|
| 225 | + // Auto-initialize as annotated character
|
| 226 | + this.data[i] = [this.data[i]];
|
| 227 | + } else {
|
| 228 | + // Detect duplicate annotation
|
| 229 | + skip = this.indexOfAnnotation( i, annotation ) !== -1;
|
| 230 | + }
|
| 231 | + if ( !skip ) {
|
| 232 | + // Apply annotation to character
|
| 233 | + this.data[i].push( annotation );
|
| 234 | + }
|
| 235 | + }
|
| 236 | + } else if ( method === 'remove' ) {
|
| 237 | + for ( var i = start; i < end; i++ ) {
|
| 238 | + if ( typeof this.data[i] !== 'string' ) {
|
| 239 | + if ( annotation.type === 'all' ) {
|
| 240 | + // Remove all annotations by converting the annotated character to a plain
|
| 241 | + // character
|
| 242 | + this.data[i] = this.data[i][0];
|
| 243 | + break;
|
228 | 244 | }
|
229 | | - if ( !duplicate ) {
|
230 | | - this.data[i].push( annotation );
|
| 245 | + // Remove all matching instances of annotation
|
| 246 | + var j;
|
| 247 | + while ( ( j = this.indexOfAnnotation( i, annotation ) ) !== -1 ) {
|
| 248 | + this.data[i].splice( j, 1 );
|
231 | 249 | }
|
232 | | - break;
|
233 | | - case 'remove':
|
234 | | - if ( typeof this.data[i] !== 'string' ) {
|
235 | | - if ( annotation.type === 'all' ) {
|
236 | | - this.data[i] = this.data[i][0];
|
237 | | - } else {
|
238 | | - for ( var j = 1; j < this.data[i].length; j++ ) {
|
239 | | - if ( this.data[i][j].type === annotation.type
|
240 | | - && Content.compareObjects(
|
241 | | - this.data[i][j].data, annotation.data
|
242 | | - )
|
243 | | - ) {
|
244 | | - this.data[i].splice( j, 1 );
|
245 | | - j--;
|
246 | | - }
|
247 | | - }
|
248 | | - }
|
249 | | - }
|
250 | | - break;
|
251 | | - case 'toggle':
|
252 | | - var on = true;
|
253 | | - if ( typeof this.data[i] !== 'string' ) {
|
254 | | - for ( var j = 1; j < this.data[i].length; j++ ) {
|
255 | | - if ( this.data[i][j].type === annotation.type
|
256 | | - && Content.compareObjects(
|
257 | | - this.data[i][j].data, annotation.data
|
258 | | - )
|
259 | | - ) {
|
260 | | - this.data[i].splice( j, 1 );
|
261 | | - j--;
|
262 | | - on = false;
|
263 | | - }
|
264 | | - }
|
265 | | - }
|
266 | | - if ( on ) {
|
267 | | - if ( typeof this.data[i] === 'string' ) {
|
268 | | - this.data[i] = [this.data[i]];
|
269 | | - }
|
270 | | - this.data[i].push( annotation );
|
271 | | - }
|
272 | | - break;
|
| 250 | + }
|
273 | 251 | }
|
274 | 252 | }
|
275 | 253 | };
|
Index: trunk/parsers/wikidom/demos/es/index.html |
— | — | @@ -108,43 +108,43 @@ |
109 | 109 | |
110 | 110 | $( '#es-toolbar-bold' ).click( function() { |
111 | 111 | surface.annotateContent( { |
112 | | - 'method': 'add', |
| 112 | + 'method': 'toggle', |
113 | 113 | 'type': 'bold' |
114 | 114 | } ); |
115 | 115 | } ); |
116 | 116 | $( '#es-toolbar-italic' ).click( function() { |
117 | 117 | surface.annotateContent( { |
118 | | - 'method': 'add', |
| 118 | + 'method': 'toggle', |
119 | 119 | 'type': 'italic' |
120 | 120 | } ); |
121 | 121 | } ); |
122 | 122 | $( '#es-toolbar-small' ).click( function() { |
123 | 123 | surface.annotateContent( { |
124 | | - 'method': 'add', |
| 124 | + 'method': 'toggle', |
125 | 125 | 'type': 'small' |
126 | 126 | } ); |
127 | 127 | } ); |
128 | 128 | $( '#es-toolbar-big' ).click( function() { |
129 | 129 | surface.annotateContent( { |
130 | | - 'method': 'add', |
| 130 | + 'method': 'toggle', |
131 | 131 | 'type': 'big' |
132 | 132 | } ); |
133 | 133 | } ); |
134 | 134 | $( '#es-toolbar-sub' ).click( function() { |
135 | 135 | surface.annotateContent( { |
136 | | - 'method': 'add', |
| 136 | + 'method': 'toggle', |
137 | 137 | 'type': 'sub' |
138 | 138 | } ); |
139 | 139 | } ); |
140 | 140 | $( '#es-toolbar-super' ).click( function() { |
141 | 141 | surface.annotateContent( { |
142 | | - 'method': 'add', |
| 142 | + 'method': 'toggle', |
143 | 143 | 'type': 'super' |
144 | 144 | } ); |
145 | 145 | } ); |
146 | 146 | $( '#es-toolbar-link' ).click( function() { |
147 | 147 | surface.annotateContent( { |
148 | | - 'method': 'add', |
| 148 | + 'method': 'toggle', |
149 | 149 | 'type': 'xlink', |
150 | 150 | 'data': { 'href': '#' } |
151 | 151 | } ); |