Index: trunk/extensions/VisualEditor/modules/es/views/es.SurfaceView.js |
— | — | @@ -7,7 +7,9 @@ |
8 | 8 | * @param {es.SurfaceModel} model Surface model to view |
9 | 9 | */ |
10 | 10 | es.SurfaceView = function( $container, model ) { |
11 | | - var _this = this; |
| 11 | + // References for use in closures |
| 12 | + var _this = this, |
| 13 | + $document = $( document ); |
12 | 14 | |
13 | 15 | es.EventEmitter.call( this ); |
14 | 16 | |
— | — | @@ -15,12 +17,15 @@ |
16 | 18 | this.$window = $( window ); |
17 | 19 | this.model = model; |
18 | 20 | this.selection = new es.Range(); |
19 | | - this.previousSelection = null; |
| 21 | + |
| 22 | + // Mac uses different mapping for keyboard shortcuts |
20 | 23 | this.mac = navigator.userAgent.match(/mac/i) ? true : false; |
21 | 24 | |
22 | 25 | this.model.getDocument().on( 'update', function() { |
23 | 26 | _this.emit( 'update' ); |
24 | 27 | } ); |
| 28 | + |
| 29 | + this.previousSelection = null; |
25 | 30 | this.emitSelect = function() { |
26 | 31 | if ( _this.previousSelection ) { |
27 | 32 | if ( |
— | — | @@ -53,65 +58,55 @@ |
54 | 59 | selectingMode: null, |
55 | 60 | selectedRange: null |
56 | 61 | }; |
57 | | - |
| 62 | + |
58 | 63 | this.cursor = { |
59 | 64 | $: $( '<div class="es-surfaceView-cursor"></div>' ).appendTo( this.$ ), |
60 | 65 | interval: null, |
61 | 66 | initialLeft: null, |
62 | 67 | initialBias: false |
63 | 68 | }; |
| 69 | + |
64 | 70 | this.keyboard = { |
65 | 71 | selecting: false, |
66 | 72 | cursorAnchor: null, |
67 | 73 | keydownTimeout: null, |
68 | | - keys: { |
69 | | - shift: false, |
70 | | - //control: false, |
71 | | - //command: false, |
72 | | - //alt: false |
73 | | - } |
| 74 | + keys: { shift: false } |
74 | 75 | }; |
75 | 76 | |
76 | | - // References for use in closures |
77 | | - var surfaceView = this, |
78 | | - $document = $( document ); |
79 | | - |
80 | 77 | // MouseDown and DoubleClick on surface |
81 | 78 | this.$.on( { |
82 | 79 | 'mousedown' : function(e) { |
83 | | - return surfaceView.onMouseDown( e ); |
| 80 | + return _this.onMouseDown( e ); |
84 | 81 | } |
85 | 82 | } ); |
86 | | - |
| 83 | + |
87 | 84 | // Hidden input |
88 | 85 | this.$input = $( '<textarea class="es-surfaceView-textarea" />' ) |
89 | 86 | .prependTo( this.$ ) |
90 | 87 | .on( { |
91 | 88 | 'focus' : function() { |
92 | | - //console.log("focus"); |
93 | 89 | $document.off( '.es-surfaceView' ); |
94 | 90 | $document.on({ |
95 | 91 | 'mousemove.es-surfaceView': function(e) { |
96 | | - return surfaceView.onMouseMove( e ); |
| 92 | + return _this.onMouseMove( e ); |
97 | 93 | }, |
98 | 94 | 'mouseup.es-surfaceView': function(e) { |
99 | | - return surfaceView.onMouseUp( e ); |
| 95 | + return _this.onMouseUp( e ); |
100 | 96 | }, |
101 | 97 | 'keydown.es-surfaceView': function( e ) { |
102 | | - return surfaceView.onKeyDown( e ); |
| 98 | + return _this.onKeyDown( e ); |
103 | 99 | }, |
104 | 100 | 'keyup.es-surfaceView': function( e ) { |
105 | | - return surfaceView.onKeyUp( e ); |
| 101 | + return _this.onKeyUp( e ); |
106 | 102 | } |
107 | 103 | }); |
108 | 104 | }, |
109 | 105 | 'blur': function( e ) { |
110 | | - //console.log("blur"); |
111 | 106 | $document.off( '.es-surfaceView' ); |
112 | | - surfaceView.hideCursor(); |
| 107 | + _this.hideCursor(); |
113 | 108 | } |
114 | 109 | } ).focus(); |
115 | | - |
| 110 | + |
116 | 111 | // First render |
117 | 112 | this.documentView.renderContent(); |
118 | 113 | |
— | — | @@ -122,18 +117,20 @@ |
123 | 118 | }; |
124 | 119 | |
125 | 120 | // Re-render when resizing horizontally |
| 121 | + // TODO: Instead of re-rendering on every single 'resize' event wait till user is done with |
| 122 | + // resizing - can be implemented with setTimeout |
126 | 123 | this.$window.resize( function() { |
127 | | - surfaceView.hideCursor(); |
128 | | - surfaceView.dimensions.height = surfaceView.$window.height(); |
129 | | - var width = surfaceView.$.width(); |
130 | | - if ( surfaceView.dimensions.width !== width ) { |
131 | | - surfaceView.dimensions.width = width; |
132 | | - surfaceView.documentView.renderContent(); |
| 124 | + _this.hideCursor(); |
| 125 | + _this.dimensions.height = _this.$window.height(); |
| 126 | + var width = _this.$.width(); |
| 127 | + if ( _this.dimensions.width !== width ) { |
| 128 | + _this.dimensions.width = width; |
| 129 | + _this.documentView.renderContent(); |
133 | 130 | } |
134 | 131 | } ); |
135 | | - |
| 132 | + |
136 | 133 | this.$window.scroll( function() { |
137 | | - surfaceView.dimensions.scrollTop = surfaceView.$window.scrollTop(); |
| 134 | + _this.dimensions.scrollTop = _this.$window.scrollTop(); |
138 | 135 | } ); |
139 | 136 | }; |
140 | 137 | |
— | — | @@ -144,8 +141,6 @@ |
145 | 142 | |
146 | 143 | var offset = this.documentView.getOffsetFromEvent( e ); |
147 | 144 | |
148 | | - //console.log('onMouseDown; offset: ' + offset); |
149 | | - |
150 | 145 | if ( e.originalEvent.detail === 1 ) { // single click |
151 | 146 | this.mouse.selectingMode = 1; // used in mouseMove handler |
152 | 147 | |
— | — | @@ -245,23 +240,13 @@ |
246 | 241 | }; |
247 | 242 | |
248 | 243 | es.SurfaceView.prototype.onKeyDown = function( e ) { |
249 | | - var tx; |
| 244 | + this.selection.normalize(); |
| 245 | + |
250 | 246 | switch ( e.keyCode ) { |
251 | 247 | case 16: // Shift |
252 | 248 | this.keyboard.keys.shift = true; |
253 | 249 | this.keyboard.selecting = true; |
254 | 250 | break; |
255 | | - case 17: // Control |
256 | | - //this.keyboard.keys.control = true; |
257 | | - break; |
258 | | - case 18: // Alt |
259 | | - //this.keyboard.keys.alt = true; |
260 | | - break; |
261 | | - case 91: // Left Command in WebKit |
262 | | - case 93: // Right Command in WebKit |
263 | | - case 224: // Command in FireFox |
264 | | - //this.keyboard.keys.command = true; |
265 | | - break; |
266 | 251 | case 36: // Home |
267 | 252 | this.moveCursor( 'left', 'line' ); |
268 | 253 | break; |
— | — | @@ -333,76 +318,10 @@ |
334 | 319 | } |
335 | 320 | break; |
336 | 321 | case 8: // Backspace |
337 | | - this.selection.normalize(); |
338 | | - |
339 | | - var range; |
340 | | - |
341 | | - if ( this.selection.from === this.selection.to ) { |
342 | | - range = new es.Range( |
343 | | - this.documentView.getModel().getRelativeContentOffset( this.selection.from, -1 ), |
344 | | - this.selection.from |
345 | | - ); |
346 | | - } else { |
347 | | - this.documentView.clearSelection(); |
348 | | - range = this.selection; |
349 | | - } |
350 | | - |
351 | | - var tx = this.documentView.model.prepareRemoval( range ); |
352 | | - this.documentView.model.commit ( tx ); |
353 | | - this.selection.from = this.selection.to = range.start; |
354 | | - this.showCursor(); |
355 | 322 | break; |
356 | 323 | case 46: // Delete |
357 | | - this.selection.normalize(); |
358 | | - |
359 | | - var range; |
360 | | - |
361 | | - if ( this.selection.from === this.selection.to ) { |
362 | | - range = new es.Range( |
363 | | - this.documentView.getModel().getRelativeContentOffset( this.selection.from, 1 ), |
364 | | - this.selection.from |
365 | | - ); |
366 | | - } else { |
367 | | - this.documentView.clearSelection(); |
368 | | - range = this.selection; |
369 | | - } |
370 | | - |
371 | | - var tx = this.documentView.model.prepareRemoval( range ); |
372 | | - this.documentView.model.commit ( tx ); |
373 | | - this.selection.from = this.selection.to = range.start; |
374 | | - this.showCursor(); |
375 | 324 | break; |
376 | 325 | case 13: // Enter |
377 | | - if ( this.selection.from === this.selection.to ) { |
378 | | - var node = this.documentView.getNodeFromOffset( this.selection.to, false ).model, |
379 | | - nodeType, |
380 | | - stack = []; |
381 | | - |
382 | | - while ( node ) { |
383 | | - nodeType = node.getElementType(); |
384 | | - stack.splice( |
385 | | - stack.length / 2, |
386 | | - 0, |
387 | | - { 'type': '/' + nodeType }, |
388 | | - { 'type': nodeType, 'attributes': es.copyObject( node.element.attributes ) } |
389 | | - ); |
390 | | - node = node.getParent(); |
391 | | - if ( es.DocumentView.splitRules[ nodeType ].self === true ) { |
392 | | - nodeType = node.getElementType(); |
393 | | - if ( es.DocumentView.splitRules[ nodeType ].children === true) { |
394 | | - break; |
395 | | - } |
396 | | - } |
397 | | - } |
398 | | - |
399 | | - var tx = this.documentView.model.prepareInsertion( this.selection.to, stack ); |
400 | | - this.documentView.model.commit( tx ); |
401 | | - |
402 | | - this.selection.from = this.selection.to = this.documentView.getModel().getRelativeContentOffset( this.selection.to, 1 ); |
403 | | - this.showCursor(); |
404 | | - e.preventDefault(); |
405 | | - return false; |
406 | | - } |
407 | 326 | break; |
408 | 327 | default: // Insert content (maybe) |
409 | 328 | if ( this.keyboard.keydownTimeout ) { |
— | — | @@ -417,17 +336,6 @@ |
418 | 337 | return true; |
419 | 338 | }; |
420 | 339 | |
421 | | -es.SurfaceView.prototype.insertFromInput = function() { |
422 | | - var val = this.$input.val(); |
423 | | - this.$input.val( '' ); |
424 | | - if ( val.length > 0 ) { |
425 | | - var transaction = this.documentView.model.prepareInsertion( this.selection.to, val.split('') ); |
426 | | - this.documentView.model.commit ( transaction ); |
427 | | - this.selection.from = this.selection.to += val.length; |
428 | | - this.showCursor(); |
429 | | - } |
430 | | -}; |
431 | | - |
432 | 340 | es.SurfaceView.prototype.onKeyUp = function( e ) { |
433 | 341 | switch ( e.keyCode ) { |
434 | 342 | case 16: // Shift |
— | — | @@ -436,36 +344,34 @@ |
437 | 345 | this.keyboard.selecting = false; |
438 | 346 | } |
439 | 347 | break; |
440 | | - case 17: // Control |
441 | | - //this.keyboard.keys.control = false; |
442 | | - break; |
443 | | - case 18: // Alt |
444 | | - //this.keyboard.keys.alt = false; |
445 | | - break; |
446 | | - case 91: // Left Command in WebKit |
447 | | - case 93: // Right Command in WebKit |
448 | | - case 224: // Command in FireFox |
449 | | - //this.keyboard.keys.command = false; |
450 | | - break; |
451 | 348 | default: |
452 | 349 | break; |
453 | 350 | } |
454 | 351 | return true; |
455 | 352 | }; |
456 | 353 | |
| 354 | +es.SurfaceView.prototype.insertFromInput = function() { |
| 355 | + var val = this.$input.val(); |
| 356 | + this.$input.val( '' ); |
| 357 | + if ( val.length > 0 ) { |
| 358 | + var transaction = this.documentView.model.prepareInsertion( this.selection.to, val.split('') ); |
| 359 | + this.documentView.model.commit ( transaction ); |
| 360 | + this.selection.from = this.selection.to += val.length; |
| 361 | + this.showCursor(); |
| 362 | + } |
| 363 | +}; |
| 364 | + |
| 365 | + |
| 366 | + |
457 | 367 | /** |
458 | 368 | * @param {String} direction up | down | left | right |
459 | 369 | * @param {String} unit char | word | line | node | page |
460 | 370 | */ |
461 | 371 | es.SurfaceView.prototype.moveCursor = function( direction, unit ) { |
462 | | - //console.log('moveCursor; direction: ' + direction + ', unit: ' + unit); |
463 | | - |
464 | 372 | if ( direction !== 'up' && direction !== 'down' ) { |
465 | 373 | this.cursor.initialLeft = null; |
466 | 374 | } |
467 | 375 | |
468 | | - this.selection.normalize(); |
469 | | - |
470 | 376 | var to; |
471 | 377 | |
472 | 378 | switch ( direction ) { |