r103992 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r103991‎ | r103992 | r103993 >
Date:00:36, 23 November 2011
Author:tparscal
Status:deferred
Tags:
Comment:
Routed selection through the SurfaceModel
Modified paths:
  • /trunk/extensions/VisualEditor/modules/es/models/es.SurfaceModel.js (modified) (history)
  • /trunk/extensions/VisualEditor/modules/es/views/es.SurfaceView.js (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/modules/es/models/es.SurfaceModel.js
@@ -13,6 +13,7 @@
1414 // Properties
1515 this.doc = doc;
1616 this.selection = new es.Range();
 17+ this.previousSelection = null;
1718 this.states = [[]];
1819 this.initializeState( this.states.length - 1 );
1920
@@ -67,15 +68,25 @@
6869 if ( !combine && this.shouldPushState( selection ) ) {
6970 this.pushState();
7071 }
71 - var lastAction = this.states[this.states.length - 1];
72 - if ( lastAction instanceof es.Range ) {
73 - this.currentStateDistance += Math.abs(
74 - selection.from - this.states[this.states.length - 1].from
75 - );
 72+ // Filter out calls to select if they do not change the selection values
 73+ this.selection = selection;
 74+ if (
 75+ !combine ||
 76+ !this.previousSelection || (
 77+ this.previousSelection.from !== this.selection.from ||
 78+ this.previousSelection.to !== this.selection.to
 79+ )
 80+ ) {
 81+ var lastAction = this.states[this.states.length - 1];
 82+ if ( lastAction instanceof es.Range ) {
 83+ this.currentStateDistance += Math.abs(
 84+ selection.from - this.states[this.states.length - 1].from
 85+ );
 86+ }
 87+ this.currentState.push( selection );
 88+ this.emit( 'select', this.selection.clone() );
7689 }
77 - this.selection = selection;
78 - this.currentState.push( selection );
79 - this.emit( 'select', selection );
 90+ this.previousSelection = this.selection.clone();
8091 };
8192
8293 /**
@@ -199,11 +210,25 @@
200211 }
201212 }
202213 // Push a new state to the stack
 214+ this.optimizeState( this.states.length - 1 );
203215 this.states.push( [] );
204216 this.initializeState( this.states.length - 1 );
205217 this.emit( 'pushState' );
206218 };
207219
 220+es.SurfaceModel.prototype.optimizeState = function( stateIndex ) {
 221+ var skipSelects = false,
 222+ newState = [];
 223+ for ( var i = this.states[stateIndex].length - 1; i >= 0; i-- ) {
 224+ var action = this.states[stateIndex][i];
 225+ if ( !( action instanceof es.Range && skipSelects ) ) {
 226+ newState.push( action );
 227+ skipSelects = true;
 228+ }
 229+ }
 230+ this.states[stateIndex] = newState;
 231+};
 232+
208233 /* Inheritance */
209234
210235 es.extendClass( es.SurfaceModel, es.EventEmitter );
Index: trunk/extensions/VisualEditor/modules/es/views/es.SurfaceView.js
@@ -7,86 +7,86 @@
88 * @param {es.SurfaceModel} model Surface model to view
99 */
1010 es.SurfaceView = function( $container, model ) {
11 - // References for use in closures
12 - var _this = this,
13 - $document = $( document );
14 -
 11+ // Inheritance
1512 es.EventEmitter.call( this );
1613
17 - this.$ = $container.addClass( 'es-surfaceView' );
18 - this.$window = $( window );
 14+ // References for use in closures
 15+ var _this = this,
 16+ $document = $( document ),
 17+ $window = $( window );
 18+
 19+ // Properties
1920 this.model = model;
20 - this.selection = new es.Range();
21 -
22 - // Mac uses different mapping for keyboard shortcuts
23 - this.mac = navigator.userAgent.match(/mac/i) ? true : false;
24 -
25 - this.model.getDocument().on( 'update', function() {
26 - _this.emit( 'update' );
27 - } );
28 -
29 - this.previousSelection = null;
30 - this.emitSelect = function() {
31 - if ( _this.previousSelection ) {
32 - if (
33 - _this.previousSelection.from !== _this.selection.from ||
34 - _this.previousSelection.to !== _this.selection.to
35 - ) {
36 - _this.emit( 'select', _this.selection.clone() );
37 - _this.previousSelection = _this.selection.clone();
38 - }
39 - // Mouse movement that doesn't change selection points will terminate here
40 - } else {
41 - _this.previousSelection = _this.selection.clone();
42 - }
43 - };
44 -
45 - // Initialize document view
 21+ this.currentSelection = new es.Range();
4622 this.documentView = new es.DocumentView( this.model.getDocument(), this );
47 - this.$.append( this.documentView.$ );
 23+ this.$ = $container
 24+ .addClass( 'es-surfaceView' )
 25+ .append( this.documentView.$ );
 26+ this.$input = $( '<textarea class="es-surfaceView-textarea" />' )
 27+ .prependTo( this.$ );
 28+ this.$cursor = $( '<div class="es-surfaceView-cursor"></div>' )
 29+ .appendTo( this.$ );
4830
49 - // Interaction state
 31+ // Interaction states
5032
51 - // There are three different selection modes available for mouse. Selection of:
52 - // * 1 - chars
53 - // * 2 - words
54 - // * 3 - nodes (e.g. paragraph, listitem)
55 - //
56 - // In case of 2 and 3 selectedRange stores the range of original selection caused by double
57 - // or triple mousedowns.
 33+ /*
 34+ * There are three different selection modes available for mouse. Selection of:
 35+ * 1 - chars
 36+ * 2 - words
 37+ * 3 - nodes (e.g. paragraph, listitem)
 38+ *
 39+ * In case of 2 and 3 selectedRange stores the range of original selection caused by double
 40+ * or triple mousedowns.
 41+ */
5842 this.mouse = {
5943 selectingMode: null,
6044 selectedRange: null
6145 };
62 -
6346 this.cursor = {
64 - $: $( '<div class="es-surfaceView-cursor"></div>' ).appendTo( this.$ ),
6547 interval: null,
6648 initialLeft: null,
6749 initialBias: false
6850 };
69 -
7051 this.keyboard = {
7152 selecting: false,
7253 cursorAnchor: null,
7354 keydownTimeout: null,
7455 keys: { shift: false }
7556 };
 57+ this.dimensions = {
 58+ width: this.$.width(),
 59+ height: $window.height(),
 60+ scrollTop: $window.scrollTop(),
 61+ // XXX: This is a dirty hack!
 62+ toolbarTop: $( '#es-toolbar' ).offset().top,
 63+ toolbarHeight: $( '#es-toolbar' ).height()
 64+ };
7665
77 - // MouseDown and DoubleClick on surface
78 - this.$.on( {
79 - 'mousedown' : function(e) {
80 - return _this.onMouseDown( e );
 66+ // Events
 67+
 68+ this.model.on( 'select', function( selection ) {
 69+ // Keep a copy of the current selection on hand
 70+ _this.currentSelection = selection.clone();
 71+ // Respond to selection changes
 72+ if ( selection.from !== selection.to ) {
 73+ _this.hideCursor();
 74+ } else {
 75+ _this.showCursor();
8176 }
 77+ _this.documentView.drawSelection( selection );
8278 } );
83 -
84 - // Hidden input
85 - this.$input = $( '<textarea class="es-surfaceView-textarea" />' )
86 - .prependTo( this.$ )
87 - .on( {
88 - 'focus' : function() {
 79+ this.model.getDocument().on( 'update', function() {
 80+ _this.emit( 'update' );
 81+ } );
 82+ this.$.mousedown( function(e) {
 83+ return _this.onMouseDown( e );
 84+ } );
 85+ this.$input.on( {
 86+ 'focus': function() {
 87+ // Make sure we aren't double-binding
8988 $document.off( '.es-surfaceView' );
90 - $document.on({
 89+ // Bind mouse and key events to the document to ensure we don't miss anything
 90+ $document.on( {
9191 'mousemove.es-surfaceView': function(e) {
9292 return _this.onMouseMove( e );
9393 },
@@ -99,40 +99,29 @@
100100 'keyup.es-surfaceView': function( e ) {
101101 return _this.onKeyUp( e );
102102 }
103 - });
 103+ } );
104104 },
105105 'blur': function( e ) {
 106+ // Release our event handlers when not focused
106107 $document.off( '.es-surfaceView' );
107108 _this.hideCursor();
108109 }
109 - } ).focus();
110 -
111 - // First render
112 - this.documentView.renderContent();
113 -
114 - this.dimensions = {
115 - width: this.$.width(),
116 - height: this.$window.height(),
117 - scrollTop: this.$window.scrollTop(),
118 - toolbarTop: $( '#es-toolbar' ).offset().top,
119 - toolbarHeight: $( '#es-toolbar' ).height()
120 - };
121 -
122 - // Re-render when resizing horizontally
123 - // TODO: Instead of re-rendering on every single 'resize' event wait till user is done with
124 - // resizing - can be implemented with setTimeout
125 - this.$window.resize( function() {
 110+ } );
 111+ $window.resize( function() {
 112+ // Re-render when resizing horizontally
 113+ // TODO: Instead of re-rendering on every single 'resize' event wait till user is done with
 114+ // resizing - can be implemented with setTimeout
126115 _this.hideCursor();
127 - _this.dimensions.height = _this.$window.height();
 116+ _this.dimensions.height = $window.height();
128117 var width = _this.$.width();
129118 if ( _this.dimensions.width !== width ) {
130119 _this.dimensions.width = width;
131120 _this.documentView.renderContent();
132121 }
133122 } );
134 -
135 - this.$window.scroll( function() {
136 - _this.dimensions.scrollTop = _this.$window.scrollTop();
 123+ $window.scroll( function() {
 124+ // FIXME: Is this code in the right place?
 125+ _this.dimensions.scrollTop = $window.scrollTop();
137126 if ( _this.dimensions.scrollTop >= _this.dimensions.toolbarTop ) {
138127 $( '#es-toolbar' ).addClass( 'float' );
139128 $( '#es-panes' ).css( 'padding-top', _this.dimensions.toolbarHeight );
@@ -141,147 +130,155 @@
142131 $( '#es-panes' ).css( 'padding-top', 0 );
143132 }
144133 } );
 134+
 135+ // Configuration
 136+ this.mac = navigator.userAgent.match(/mac/i) ? true : false; // (yes it's evil, for keys only!)
 137+
 138+ // Initialization
 139+ this.$input.focus();
 140+ this.documentView.renderContent();
145141 };
146142
147143 /* Methods */
148144
149145 es.SurfaceView.prototype.onMouseDown = function( e ) {
150 - if ( e.button === 0 ) { // left mouse button
 146+ // Only for left mouse button
 147+ if ( e.button === 0 ) {
 148+ var selection = this.currentSelection.clone(),
 149+ offset = this.documentView.getOffsetFromEvent( e );
151150
152 - this.selection.normalize();
 151+ // Single click
 152+ if ( e.originalEvent.detail === 1 ) {
 153+ // @see {es.SurfaceView.prototype.onMouseMove}
 154+ this.mouse.selectingMode = 1;
153155
154 - var offset = this.documentView.getOffsetFromEvent( e );
155 -
156 - if ( e.originalEvent.detail === 1 ) { // single click
157 - this.mouse.selectingMode = 1; // used in mouseMove handler
158 -
159 - if ( this.keyboard.keys.shift && offset !== this.selection.from ) {
160 - // extend current or create new selection
161 - this.selection.to = offset;
 156+ if ( this.keyboard.keys.shift && offset !== selection.from ) {
 157+ // Extend current or create new selection
 158+ selection.to = offset;
162159 } else {
163 - if ( this.selection.to !== this.selection.from ) {
164 - // clear the selection if there was any
 160+ if ( selection.to !== selection.from ) {
 161+ // Clear the selection if there was any
165162 this.documentView.clearSelection();
166163 }
167 - this.selection.from = this.selection.to = offset;
 164+ selection.from = selection.to = offset;
168165
169166 var position = es.Position.newFromEventPagePosition( e ),
170167 nodeView = this.documentView.getNodeFromOffset( offset, false );
171168 this.cursor.initialBias = position.left > nodeView.contentView.$.offset().left;
172169 }
173170
174 - } else if ( e.originalEvent.detail === 2 ) { // double click
175 - this.mouse.selectingMode = 2; // used in mouseMove handler
 171+ }
 172+ // Double click
 173+ else if ( e.originalEvent.detail === 2 ) {
 174+ // @see {es.SurfaceView.prototype.onMouseMove}
 175+ this.mouse.selectingMode = 2;
176176
177177 var wordRange = this.model.getDocument().getWordBoundaries( offset );
178178 if( wordRange ) {
179 - this.selection = wordRange;
180 - this.mouse.selectedRange = this.selection.clone();
 179+ selection = wordRange;
 180+ this.mouse.selectedRange = selection.clone();
181181 }
182182
183 - } else if ( e.originalEvent.detail >= 3 ) { // triple click
184 - this.mouse.selectingMode = 3; // used in mouseMove handler
 183+ }
 184+ // Triple click
 185+ else if ( e.originalEvent.detail >= 3 ) {
 186+ // @see {es.SurfaceView.prototype.onMouseMove}
 187+ this.mouse.selectingMode = 3;
185188
186189 var node = this.documentView.getNodeFromOffset( offset ),
187190 nodeOffset = this.documentView.getOffsetFromNode( node, false );
188191
189 - this.selection.from = this.model.getDocument().getRelativeContentOffset(
190 - nodeOffset,
191 - 1
 192+ selection.from = this.model.getDocument().getRelativeContentOffset( nodeOffset, 1 );
 193+ selection.to = this.model.getDocument().getRelativeContentOffset(
 194+ nodeOffset + node.getElementLength(), -1
192195 );
193 - this.selection.to = this.model.getDocument().getRelativeContentOffset(
194 - nodeOffset + node.getElementLength(),
195 - -1
196 - );
197 - this.mouse.selectedRange = this.selection.clone();
 196+ this.mouse.selectedRange = selection.clone();
198197 }
199198
200 - if ( this.selection.from === this.selection.to ) {
201 - this.showCursor();
202 - } else {
203 - this.hideCursor();
204 - this.documentView.drawSelection( this.selection );
205 - }
 199+ // Reset the initial left position
 200+ this.cursor.initialLeft = null;
 201+ // Apply new selection
 202+ this.model.select( selection );
206203 }
207 -
 204+ // If the inut isn't already focused, focus it and select it's contents
208205 if ( !this.$input.is( ':focus' ) ) {
209206 this.$input.focus().select();
210207 }
211 - this.cursor.initialLeft = null;
212 - this.emitSelect();
213208 return false;
214209 };
215210
216211 es.SurfaceView.prototype.onMouseMove = function( e ) {
217 - if ( e.button === 0 && this.mouse.selectingMode ) { // left mouse button and in selecting mode
 212+ // Only with the left mouse button while in selecting mode
 213+ if ( e.button === 0 && this.mouse.selectingMode ) {
 214+ var selection = this.currentSelection.clone(),
 215+ offset = this.documentView.getOffsetFromEvent( e );
218216
219 - var offset = this.documentView.getOffsetFromEvent( e );
220 -
221 - if ( this.mouse.selectingMode === 1 ) { // selection of chars
222 - this.selection.to = offset;
223 - } else if ( this.mouse.selectingMode === 2 ) { // selection of words
 217+ // Character selection
 218+ if ( this.mouse.selectingMode === 1 ) {
 219+ selection.to = offset;
 220+ }
 221+ // Word selection
 222+ else if ( this.mouse.selectingMode === 2 ) {
224223 var wordRange = this.model.getDocument().getWordBoundaries( offset );
225224 if ( wordRange ) {
226225 if ( wordRange.to <= this.mouse.selectedRange.from ) {
227 - this.selection.from = wordRange.from;
228 - this.selection.to = this.mouse.selectedRange.to;
 226+ selection.from = wordRange.from;
 227+ selection.to = this.mouse.selectedRange.to;
229228 } else {
230 - this.selection.from = this.mouse.selectedRange.from;
231 - this.selection.to = wordRange.to;
 229+ selection.from = this.mouse.selectedRange.from;
 230+ selection.to = wordRange.to;
232231 }
233232 }
234 - } else if ( this.mouse.selectingMode === 3 ) {
 233+ }
 234+ // Node selection
 235+ else if ( this.mouse.selectingMode === 3 ) {
 236+ // @see {es.SurfaceView.prototype.onMouseMove}
 237+ this.mouse.selectingMode = 3;
235238
236 - this.mouse.selectingMode = 3; // used in mouseMove handler
237 -
238239 var nodeRange = this.documentView.getRangeFromNode(
239240 this.documentView.getNodeFromOffset( offset )
240241 );
241242 if ( nodeRange.to <= this.mouse.selectedRange.from ) {
242 - this.selection.from = this.model.getDocument().getRelativeContentOffset(
243 - nodeRange.from,
244 - 1
 243+ selection.from = this.model.getDocument().getRelativeContentOffset(
 244+ nodeRange.from, 1
245245 );
246 - this.selection.to = this.mouse.selectedRange.to;
 246+ selection.to = this.mouse.selectedRange.to;
247247 } else {
248 - this.selection.from = this.mouse.selectedRange.from;
249 - this.selection.to = this.model.getDocument().getRelativeContentOffset(
250 - nodeRange.to,
251 - -1
 248+ selection.from = this.mouse.selectedRange.from;
 249+ selection.to = this.model.getDocument().getRelativeContentOffset(
 250+ nodeRange.to, -1
252251 );
253252 }
254253 }
255 -
256 - this.emitSelect();
257 -
258 - this.documentView.drawSelection( this.selection );
259 - if ( this.selection.from !== this.selection.to ) {
260 - this.hideCursor();
261 - }
 254+ // Apply new selection
 255+ this.model.select( selection, true );
262256 }
263257 };
264258
265259 es.SurfaceView.prototype.onMouseUp = function( e ) {
266260 if ( e.button === 0 ) { // left mouse button
267261 this.mouse.selectingMode = this.mouse.selectedRange = null;
 262+ this.model.select( this.currentSelection );
268263 }
269264 };
270265
271266 es.SurfaceView.prototype.onKeyDown = function( e ) {
272 - this.selection.normalize();
273 -
274267 switch ( e.keyCode ) {
275 - case 16: // Shift
 268+ // Shift
 269+ case 16:
276270 this.keyboard.keys.shift = true;
277271 this.keyboard.selecting = true;
278272 break;
279 - case 36: // Home
 273+ // Home
 274+ case 36:
280275 this.moveCursor( 'left', 'line' );
281276 break;
282 - case 35: // End
 277+ // End
 278+ case 35:
283279 this.moveCursor( 'right', 'line' );
284280 break;
285 - case 37: // Left arrow
 281+ // Left arrow
 282+ case 37:
286283 if ( !this.mac ) {
287284 if ( e.ctrlKey ) {
288285 this.moveCursor( 'left', 'word' );
@@ -298,7 +295,8 @@
299296 }
300297 }
301298 break;
302 - case 38: // Up arrow
 299+ // Up arrow
 300+ case 38:
303301 if ( !this.mac ) {
304302 if ( e.ctrlKey ) {
305303 this.moveCursor( 'up', 'unit' );
@@ -313,7 +311,8 @@
314312 }
315313 }
316314 break;
317 - case 39: // Right arrow
 315+ // Right arrow
 316+ case 39:
318317 if ( !this.mac ) {
319318 if ( e.ctrlKey ) {
320319 this.moveCursor( 'right', 'word' );
@@ -330,7 +329,8 @@
331330 }
332331 }
333332 break;
334 - case 40: // Down arrow
 333+ // Down arrow
 334+ case 40:
335335 if ( !this.mac ) {
336336 if ( e.ctrlKey ) {
337337 this.moveCursor( 'down', 'unit' );
@@ -345,34 +345,31 @@
346346 }
347347 }
348348 break;
349 - case 8: // Backspace
 349+ // Backspace
 350+ case 8:
350351 this.handleDelete( true );
351352 break;
352 - case 46: // Delete
 353+ // Delete
 354+ case 46:
353355 this.handleDelete();
354356 break;
355 - case 13: // Enter
 357+ // Enter
 358+ case 13:
356359 this.handleEnter();
357360 e.preventDefault();
358361 break;
359 - /*
360 - case 90: // z (undo/redo)
 362+ // Z (undo/redo)
 363+ case 90:
361364 if ( e.metaKey || e.ctrlKey ) {
362365 if ( this.keyboard.keys.shift ) {
363 - this.history.redo();
 366+ this.model.redo();
364367 } else {
365 - this.history.undo();
 368+ this.model.undo();
366369 }
367 - var selection = this.history.getCurrentStateSelection();
368 - if ( selection ) {
369 - this.selection = selection.clone();
370 - this.showCursor();
371 - }
372370 break;
373371 }
374 - // Fall through to default so the z key still otherwise works
375 - */
376 - default: // Insert content (maybe)
 372+ // Insert content (maybe)
 373+ default:
377374 if ( this.keyboard.keydownTimeout ) {
378375 clearTimeout( this.keyboard.keydownTimeout );
379376 }
@@ -400,24 +397,25 @@
401398 };
402399
403400 es.SurfaceView.prototype.handleDelete = function( backspace ) {
404 - var sourceOffset,
 401+ var selection = this.currentSelection.clone(),
 402+ sourceOffset,
405403 targetOffset,
406404 sourceSplitableNode,
407405 targetSplitableNode,
408406 tx;
409 - if ( this.selection.from === this.selection.to ) {
 407+ if ( selection.from === selection.to ) {
410408 if ( backspace ) {
411 - sourceOffset = this.selection.to;
 409+ sourceOffset = selection.to;
412410 targetOffset = this.model.getDocument().getRelativeContentOffset(
413411 sourceOffset,
414412 -1
415413 );
416414 } else {
417415 sourceOffset = this.model.getDocument().getRelativeContentOffset(
418 - this.selection.to,
 416+ selection.to,
419417 1
420418 );
421 - targetOffset = this.selection.to;
 419+ targetOffset = selection.to;
422420 }
423421
424422 var sourceNode = this.documentView.getNodeFromOffset( sourceOffset, false ),
@@ -428,8 +426,8 @@
429427 targetSplitableNode = es.DocumentViewNode.getSplitableNode( targetNode );
430428 }
431429
432 - this.selection.from = this.selection.to = targetOffset;
433 - this.showCursor();
 430+ selection.from = selection.to = targetOffset;
 431+ this.model.select( selection );
434432
435433 if ( sourceNode === targetNode ||
436434 ( typeof sourceSplitableNode !== 'undefined' &&
@@ -460,32 +458,33 @@
461459 }
462460 } else {
463461 // selection removal
464 - tx = this.model.getDocument().prepareRemoval( this.selection );
 462+ tx = this.model.getDocument().prepareRemoval( selection );
465463 this.model.transact( tx );
466464 this.documentView.clearSelection();
467 - this.selection.from = this.selection.to = this.selection.start;
468 - this.showCursor();
 465+ selection.from = selection.to = selection.start;
 466+ this.model.select( selection );
469467 }
470468 };
471469
472470 es.SurfaceView.prototype.handleEnter = function() {
473 - if ( this.selection.from !== this.selection.to ) {
 471+ var selection = this.currentSelection.clone(),
 472+ tx;
 473+ if ( selection.from !== selection.to ) {
474474 this.handleDelete();
475475 }
476 - var node = this.documentView.getNodeFromOffset( this.selection.to, false ),
 476+ var node = this.documentView.getNodeFromOffset( selection.to, false ),
477477 nodeOffset = this.documentView.getOffsetFromNode( node, false );
478478
479479 if (
480 - nodeOffset + node.getContentLength() + 1 === this.selection.to &&
 480+ nodeOffset + node.getContentLength() + 1 === selection.to &&
481481 node === es.DocumentViewNode.getSplitableNode( node )
482482 ) {
483 - var tx = this.documentView.model.prepareInsertion(
 483+ tx = this.documentView.model.prepareInsertion(
484484 nodeOffset + node.getElementLength(),
485485 [ { 'type': 'paragraph' }, { 'type': '/paragraph' } ]
486486 );
487487 this.model.transact( tx );
488 - this.selection.from = this.selection.to = nodeOffset + node.getElementLength() + 1;
489 - this.showCursor();
 488+ selection.from = selection.to = nodeOffset + node.getElementLength() + 1;
490489 } else {
491490 var stack = [],
492491 splitable = false;
@@ -509,31 +508,32 @@
510509 );
511510 splitable = es.DocumentView.splitRules[ elementType ].self;
512511 } );
513 - var tx = this.documentView.model.prepareInsertion( this.selection.to, stack );
 512+ tx = this.documentView.model.prepareInsertion( selection.to, stack );
514513 this.model.transact( tx );
515 - this.selection.from = this.selection.to =
516 - this.model.getDocument().getRelativeContentOffset( this.selection.to, 1 );
517 - this.showCursor();
 514+ selection.from = selection.to =
 515+ this.model.getDocument().getRelativeContentOffset( selection.to, 1 );
518516 }
 517+ this.model.select( selection );
519518 };
520519
521520 es.SurfaceView.prototype.insertFromInput = function() {
522 - var val = this.$input.val();
 521+ var selection = this.currentSelection.clone(),
 522+ val = this.$input.val();
523523 this.$input.val( '' );
524524 if ( val.length > 0 ) {
525525 var tx;
526 - if ( this.selection.from != this.selection.to ) {
527 - tx = this.model.getDocument().prepareRemoval( this.selection );
 526+ if ( selection.from != selection.to ) {
 527+ tx = this.model.getDocument().prepareRemoval( selection );
528528 this.model.transact( tx );
529529 this.documentView.clearSelection();
530 - this.selection.from = this.selection.to =
531 - Math.min( this.selection.from, this.selection.to );
 530+ selection.from = selection.to =
 531+ Math.min( selection.from, selection.to );
532532 }
533 - tx = this.model.getDocument().prepareInsertion( this.selection.from, val.split('') );
 533+ tx = this.model.getDocument().prepareInsertion( selection.from, val.split('') );
534534 this.model.transact( tx );
535 - this.selection.from += val.length;
536 - this.selection.to += val.length;
537 - this.showCursor();
 535+ selection.from += val.length;
 536+ selection.to += val.length;
 537+ this.model.select( selection );
538538 }
539539 };
540540
@@ -545,20 +545,19 @@
546546 if ( direction !== 'up' && direction !== 'down' ) {
547547 this.cursor.initialLeft = null;
548548 }
549 -
550 - var to,
 549+ var selection = this.currentSelection.clone(),
 550+ to,
551551 offset;
552 -
553552 switch ( direction ) {
554553 case 'left':
555554 case 'right':
556555 switch ( unit ) {
557556 case 'char':
558557 case 'word':
559 - if ( this.keyboard.keys.shift || this.selection.from === this.selection.to ) {
560 - offset = this.selection.to;
 558+ if ( this.keyboard.keys.shift || selection.from === selection.to ) {
 559+ offset = selection.to;
561560 } else {
562 - offset = direction === 'left' ? this.selection.start : this.selection.end;
 561+ offset = direction === 'left' ? selection.start : selection.end;
563562 }
564563 to = this.model.getDocument().getRelativeContentOffset(
565564 offset,
@@ -576,9 +575,9 @@
577576 case 'line':
578577 offset = this.cursor.initialBias ?
579578 this.model.getDocument().getRelativeContentOffset(
580 - this.selection.to,
 579+ selection.to,
581580 -1) :
582 - this.selection.to;
 581+ selection.to;
583582 var range = this.documentView.getRenderedLineRangeFromOffset( offset );
584583 to = direction === 'left' ? range.start : range.end;
585584 break;
@@ -598,7 +597,7 @@
599598 return false;
600599 }
601600 },
602 - this.documentView.getNodeFromOffset( this.selection.to, false ).getModel(),
 601+ this.documentView.getNodeFromOffset( selection.to, false ).getModel(),
603602 direction === 'up' ? true : false
604603 );
605604 to = this.model.getDocument().getOffsetFromNode( toNode, false ) + 1;
@@ -610,7 +609,7 @@
611610 * reach the next/previous line
612611 */
613612 var position = this.documentView.getRenderedPositionFromOffset(
614 - this.selection.to,
 613+ selection.to,
615614 this.cursor.initialBias
616615 );
617616
@@ -623,7 +622,7 @@
624623 top = this.$.position().top;
625624
626625 this.cursor.initialBias = position.left > this.documentView.getNodeFromOffset(
627 - this.selection.to, false
 626+ selection.to, false
628627 ).contentView.$.offset().left;
629628
630629 do {
@@ -652,18 +651,15 @@
653652 this.cursor.initialBias = direction === 'right' && unit === 'line' ? true : false;
654653 }
655654
656 - if ( this.keyboard.keys.shift && this.selection.from !== to) {
657 - this.selection.to = to;
658 - this.documentView.drawSelection( this.selection );
659 - this.hideCursor();
 655+ if ( this.keyboard.keys.shift && selection.from !== to) {
 656+ selection.to = to;
660657 } else {
661 - if ( this.selection.from !== this.selection.to ) {
 658+ if ( selection.from !== selection.to ) {
662659 this.documentView.clearSelection();
663660 }
664 - this.selection.from = this.selection.to = to;
665 - this.showCursor();
 661+ selection.from = selection.to = to;
666662 }
667 - this.emitSelect();
 663+ this.model.select( selection );
668664 };
669665
670666 /**
@@ -673,10 +669,12 @@
674670 * @param offset {Integer} Position to show the cursor at
675671 */
676672 es.SurfaceView.prototype.showCursor = function() {
677 - var position = this.documentView.getRenderedPositionFromOffset(
678 - this.selection.to, this.cursor.initialBias
679 - );
680 - this.cursor.$.css( {
 673+ var $window = $( window ),
 674+ position = this.documentView.getRenderedPositionFromOffset(
 675+ this.currentSelection.to, this.cursor.initialBias
 676+ );
 677+
 678+ this.$cursor.css( {
681679 'left': position.left,
682680 'top': position.top,
683681 'height': position.bottom - position.top
@@ -690,9 +688,9 @@
691689 var inputTop = this.$input.offset().top,
692690 inputBottom = inputTop + position.bottom - position.top;
693691 if ( inputTop - this.dimensions.toolbarHeight < this.dimensions.scrollTop ) {
694 - this.$window.scrollTop( inputTop - this.dimensions.toolbarHeight );
 692+ $window.scrollTop( inputTop - this.dimensions.toolbarHeight );
695693 } else if ( inputBottom > ( this.dimensions.scrollTop + this.dimensions.height ) ) {
696 - this.$window.scrollTop( inputBottom - this.dimensions.height );
 694+ $window.scrollTop( inputBottom - this.dimensions.height );
697695 }
698696
699697 // cursor blinking
@@ -702,7 +700,7 @@
703701
704702 var _this = this;
705703 this.cursor.interval = setInterval( function( surface ) {
706 - _this.cursor.$.css( 'display', function( index, value ) {
 704+ _this.$cursor.css( 'display', function( index, value ) {
707705 return value === 'block' ? 'none' : 'block';
708706 } );
709707 }, 500 );
@@ -717,7 +715,7 @@
718716 if( this.cursor.interval ) {
719717 clearInterval( this.cursor.interval );
720718 }
721 - this.cursor.$.hide();
 719+ this.$cursor.hide();
722720 };
723721
724722 /* Inheritance */

Status & tagging log