import isEqual from '../util/isEqual' ; import Editor , { EditorChangeEvent } from '../Editor' ; import { getSelection , setSelection } from '../rendering/selection' ; import { getLineNodeStart } from '../rendering/rendering' ; import { DecorationsModule } from './decorations' ; export function selection ( editor ) { let rootDocument ; let rootWindow ; let paused = false ; function onSelectionChange ( ) { if ( ! editor . enabled ) return ; const selection = getSelection ( editor ) ; if ( ! selection && paused ) return ; if ( paused ) paused = false ; if ( selection && selection [ 0 ] === selection [ 1 ] && editor . doc . selection && editor . doc . selection [ 0 ] === selection [ 0 ] && editor . doc . selection [ 1 ] === selection [ 0 ] + 1 ) { const line = editor . doc . getLineAt ( selection [ 0 ] ) ; const type = editor . typeset . lines . findByAttributes ( line . attributes , true ) ; if ( type . frozen ) { selection [ 0 ] -- ; selection [ 1 ] -- ; } } const { doc } = editor ; if ( ! isEqual ( doc . selection , selection ) ) { if ( selection && selection [ 0 ] === selection [ 1 ] && selection [ 0 ] >= doc . length ) { return ; } editor . select ( selection ) ; } } function renderSelection ( ) { if ( paused || ! editor . enabled ) return ; setSelection ( editor , editor . doc . selection ) ; } function onDecorate ( ) { const { doc , typeset : { lines } } = editor ; const decorator = ( editor . modules . decorations as DecorationsModule ) . getDecorator ( 'selection' ) ; decorator . clear ( ) ; const selection = doc . selection ; if ( selection ) { doc . getLinesAt ( selection ) . forEach ( line => { if ( lines . findByAttributes ( line . attributes , true ) . frozen ) { const focused = isEqual ( selection , doc . getLineRange ( line ) ) ; decorator . decorateLine ( doc . getLineRange ( line ) [ 0 ] , { class : 'selected' + ( focused ? ' focus' : '' ) } ) ; } } ) ; } decorator . apply ( ) ; } function onMouseDown ( event ) { let node = event . target as Node ; while ( node . parentNode && node . parentNode !== editor . root ) node = node . parentNode ; const start = getLineNodeStart ( editor . root , node ) ; const line = start != null && editor . doc . getLineAt ( start ) ; const type = line && editor . typeset . lines . findByAttributes ( line . attributes ) ; if ( start != null && line && type && type . frozen ) { event . preventDefault ( ) ; editor . select ( [ start , start + line . length ] ) ; } } function onChange ( event ) { const selection = event . doc ?. selection || editor . doc . selection ; setSelection ( editor , selection ) ; } function onWindowFocus ( ) { editor . root . classList . toggle ( 'window-inactive' , ! rootDocument . hasFocus ( ) ) ; } function pause ( ) { paused = true ; const { selection } = editor . doc ; const { decorations } = editor . modules as { decorations : DecorationsModule ; } ; if ( selection && selection [ 0 ] !== selection [ 1 ] && decorations ) { const decorator = decorations . getDecorator ( 'pausedSelection' ) ; decorator . decorateText ( selection , { class : 'selected' } ) . apply ( ) ; } } function resume ( ) { paused = false ; const { decorations } = editor . modules as { decorations : DecorationsModule ; } ; if ( decorations ) { decorations . removeDecorations ( 'pausedSelection' ) ; } setTimeout ( renderSelection ) ; } return { pause , resume , renderSelection , init ( ) { rootDocument = editor . root . ownerDocument ; rootWindow = rootDocument . defaultView as Window ; rootDocument . addEventListener ( 'selectionchange' , onSelectionChange ) ; rootWindow . addEventListener ( 'focus' , onWindowFocus ) ; rootWindow . addEventListener ( 'blur' , onWindowFocus ) ; editor . root . addEventListener ( 'mousedown' , onMouseDown ) ; editor . on ( 'change' , onChange ) ; editor . on ( 'decorate' , onDecorate ) ; } , destroy ( ) { rootDocument . removeEventListener ( 'selectionchange' , onSelectionChange ) ; rootWindow . removeEventListener ( 'focus' , onWindowFocus ) ; rootWindow . removeEventListener ( 'blur' , onWindowFocus ) ; editor . root . removeEventListener ( 'mousedown' , onMouseDown ) ; editor . off ( 'change' , onChange ) ; editor . off ( 'decorate' , onDecorate ) ; paused = false ; rootDocument = null as any ; rootWindow = null as any ; } } ; } ;