/** * Creates an es.SurfaceView object. * * @class * @constructor * @param {jQuery} $container DOM Container to render surface into * @param {es.SurfaceModel} model Surface model to view */ es.SurfaceView = function( $container, model ) { // References for use in closures var _this = this, $document = $( document ); es.EventEmitter.call( this ); this.$ = $container.addClass( 'es-surfaceView' ); this.$window = $( window ); this.model = model; this.selection = new es.Range(); // Mac uses different mapping for keyboard shortcuts this.mac = navigator.userAgent.match(/mac/i) ? true : false; this.model.getDocument().on( 'update', function() { _this.emit( 'update' ); } ); this.previousSelection = null; this.emitSelect = function() { if ( _this.previousSelection ) { if ( _this.previousSelection.from !== _this.selection.from || _this.previousSelection.to !== _this.selection.to ) { _this.emit( 'select', _this.selection.clone() ); _this.previousSelection = _this.selection.clone(); } // Mouse movement that doesn't change selection points will terminate here } else { _this.previousSelection = _this.selection.clone(); } }; // Initialize document view this.documentView = new es.DocumentView( this.model.getDocument(), this ); this.$.append( this.documentView.$ ); // Interaction state // There are three different selection modes available for mouse. Selection of: // * 1 - chars // * 2 - words // * 3 - nodes (e.g. paragraph, listitem) // // In case of 2 and 3 selectedRange stores the range of original selection caused by double // or triple mousedowns. this.mouse = { selectingMode: null, selectedRange: null }; this.cursor = { $: $( '
' ).appendTo( this.$ ), interval: null, initialLeft: null, initialBias: false }; this.keyboard = { selecting: false, cursorAnchor: null, keydownTimeout: null, keys: { shift: false } }; // MouseDown and DoubleClick on surface this.$.on( { 'mousedown' : function(e) { return _this.onMouseDown( e ); } } ); // Hidden input this.$input = $( '