import { elt , on } from '../utils/dom' ; import Workspace from './workspace' ; import LineCache from './line-cache' ; import { createView } from './view' ; import { View , ViewOptions } from './view' ; import ViewProxy from './view-proxy' ; import { CoreMethod } from './types/core' ; import { posIsClose , Point , clamp } from '../utils/misc' ; declare var ResizeObserver ; type ResizeObserverEntry = any ; export default class ViewController { public wrapper : HTMLElement ; public lineCache : LineCache ; private view : View ; private hasFocus : boolean ; param { HTMLElement } place param { ViewProxy } proxy param { [ type ] } opts constructor ( workspace , private proxy , opts ) { this . wrapper = workspace . wrapper . appendChild ( elt ( 'div' , null , 'xi-view' , 'height: 100%; width: 100%' ) ) ; this . wrapper . style . border = '1px solid #000' ; this . wrapper . style . overflow = 'hidden' ; this . wrapper . tabIndex = 0 ; this . hasFocus = false ; on ( this . wrapper , 'blur' , ( ) => this . hasFocus = false , false ) ; on ( this . wrapper , 'focus' , ( ) => this . hasFocus = true , false ) ; this . lineCache = new LineCache ( ) ; this . view = createView ( this , opts ) ; const ro = new ResizeObserver ( ( entries ) => { for ( const entry of entries ) { if ( entry . target == this . wrapper ) { const { width , height } = entry . contentRect ; this . view . resize ( width , height ) ; this . updateViewport ( ) ; } } } ) ; ro . observe ( this . wrapper ) ; const { width , height } = this . wrapper . getBoundingClientRect ( ) ; this . view . resize ( width , height ) ; this . proxy . on ( 'update' , this . update . bind ( this ) ) ; this . proxy . on ( 'scroll_to' , this . scrollTo . bind ( this ) ) ; this . updateViewport ( ) ; } /**
     * Public API
     */ param { CoreMethod } method public doMethod ( method ) { this . edit ( method ) ; } param { String } chars public insert ( chars ) { this . edit ( CoreMethod . INSERT , { chars } ) ; } private clicks : { last : number ; count : number ; point : Point ; } = { last : Date . now ( ) , count : 1 , point : { x : 0 , y : 0 } } ; param { Object } event return { Array } public doClick ( event ) { if ( ! this . isFocused ( ) ) { this . focus ( ) ; } event . preventDefault ( ) ; const now = Date . now ( ) ; const { left , top } = this . wrapper . getBoundingClientRect ( ) ; const point = { x : event . clientX - left , y : event . clientY - top , } ; if ( now - this . clicks . last > 300 ) { this . clicks = { last : Date . now ( ) , count : 1 , point : point , } ; } else { const wasClose = posIsClose ( point , this . clicks . point ) ; if ( wasClose ) { const { count } = this . clicks ; this . clicks . last = now ; this . clicks . count = count == 3 ? 1 : count + 1 ; this . clicks . point = point ; } } const mod = event . shiftKey ? 2 : 0 ; const [ line , char ] = this . view . posFromCoords ( point . x , point . y , false ) ; this . click ( line , char , mod , this . clicks . count ) ; return [ line , char ] ; } /**
     * doDrag
     */ public doDrag ( event ) { const { left , top , width , height } = this . wrapper . getBoundingClientRect ( ) ; const point = { x : clamp ( event . clientX - left , 0 , width ) , y : clamp ( event . clientY - top , 0 , height ) , } ; const mod = event . shiftKey ? 2 : 0 ; const [ line , char ] = this . view . posFromCoords ( point . x , point . y , false ) ; this . drag ( line , char , mod ) ; } /**
     * Trigger a render of the view.
     */ public render ( ) { this . view . render ( ) ; } /**
     * Remove focus from the view.
     */ public blur ( ) { this . wrapper . blur ( ) ; } /**
     * Give focus to the view.
     */ public focus ( ) { this . wrapper . focus ( ) ; } return { Boolean } public isFocused ( ) { return this . hasFocus ; } return { [ type ] } public getWrapperElement ( ) { return this . wrapper ; } /**
     * Determine how many lines should render, and send this info to xi-core so it
     * knows how much information to give us.
     */ public updateViewport ( ) { const { lineStart , lineEnd } = this . view . getViewport ( ) ; this . edit ( CoreMethod . SCROLL , [ lineStart , lineEnd ] ) ; } param { Number } line param { Number } char param { Number } mod param { Number } count private click ( line , char , mod , count ) { this . edit ( CoreMethod . CLICK , [ line , char , mod , count ] ) ; } param { Number } line param { Number } char param { Number } mod private drag ( line , char , mod ) { this . edit ( CoreMethod . DRAG , [ line , char , mod ] ) ; } param { CoreMethod } method param { Object } params private edit ( method , params = { } ) { this . proxy . send ( CoreMethod . EDIT , { method , params } ) ; } param { Object } params private update ( params ) { this . lineCache . applyUpdate ( params . update ) ; this . render ( ) ; } param { Object } params private scrollTo ( params ) { this . view . scrollTo ( params . line , params . col ) ; } }