2018-12-30 23:41:44 +01:00
import Debug from '../conf/Debug' ;
2018-12-31 03:34:26 +01:00
import PlayerData from './video-data/PlayerData' ;
2021-02-08 23:04:54 +01:00
import ExtensionMode from '../../common/enums/ExtensionMode.enum' ;
2021-02-20 00:09:17 +01:00
import Logger from './Logger' ;
import PageInfo from './video-data/PageInfo' ;
import Settings from './Settings' ;
import VideoData from './video-data/VideoData' ;
2022-05-06 00:23:15 +02:00
import EventBus from './EventBus' ;
2018-11-14 23:32:37 +01:00
2020-04-13 15:20:29 +02:00
if ( process . env . CHANNEL !== 'stable' ) {
2020-12-03 01:05:39 +01:00
console . info ( "Loading ActionHandler" ) ;
2020-04-13 15:20:29 +02:00
}
2018-11-14 23:32:37 +01:00
class ActionHandler {
2021-02-20 00:09:17 +01:00
logger : Logger ;
settings : Settings ;
2022-05-06 00:23:15 +02:00
eventBus : EventBus ;
2021-02-20 00:09:17 +01:00
inputs : string [ ] = [ 'input' , 'select' , 'button' , 'textarea' ] ;
2021-03-06 02:53:58 +01:00
keyboardLocalDisabled : boolean = false ;
2021-02-20 00:09:17 +01:00
mouseMoveActions : any [ ] = [ ] ;
2022-05-06 00:23:15 +02:00
commands : any [ ] = [ ] ;
2018-11-14 23:32:37 +01:00
2022-05-06 00:23:15 +02:00
2022-07-31 00:14:40 +02:00
constructor ( eventBus : EventBus , settings , logger ) {
2022-05-06 00:23:15 +02:00
this . logger = logger ;
this . settings = settings ;
this . eventBus = eventBus ;
this . init ( ) ;
2018-11-14 23:32:37 +01:00
}
init() {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'debug' , "[ActionHandler::init] starting init" ) ;
2018-11-18 18:44:44 +01:00
2022-05-06 00:23:15 +02:00
// build the action list — but only from actions that have shortcuts assigned
for ( const key in this . settings . active . commands ) {
for ( const command of this . settings . active . commands [ key ] ) {
if ( command . shortcut ) {
this . commands . push ( command ) ;
2018-12-31 03:34:26 +01:00
}
2018-11-14 23:32:37 +01:00
}
}
2022-05-06 00:23:15 +02:00
2021-11-25 20:00:32 +01:00
// events should be handled in handleEvent function. We need to do things this
2021-02-09 00:54:04 +01:00
// way, otherwise we can't remove event listener
2020-10-21 23:52:16 +02:00
// https://stackoverflow.com/a/19507086
2019-07-18 21:25:58 +02:00
2022-05-06 00:23:15 +02:00
document . addEventListener ( 'keyup' , this ) ;
2018-11-14 23:32:37 +01:00
}
2020-10-21 23:52:16 +02:00
handleEvent ( event ) {
switch ( event . type ) {
2021-11-25 20:00:32 +01:00
case 'keyup' :
2020-10-21 23:52:16 +02:00
this . handleKeyup ( event ) ;
break ;
case 'mousemove' :
this . handleMouseMove ( event ) ;
break ;
}
}
destroy() {
document . removeEventListener ( 'keyup' , this ) ;
}
2018-12-02 23:51:34 +01:00
registerHandleMouse ( videoData ) {
2020-02-03 22:13:03 +01:00
this . logger . log ( 'info' , [ 'actionHandler' , 'mousemove' ] , "[ActionHandler::registerHandleMouse] registering handle mouse for videodata:" , videoData . id )
2019-07-18 21:25:58 +02:00
2018-12-02 23:51:34 +01:00
var ths = this ;
if ( videoData . player && videoData . player . element ) {
videoData . player . element . addEventListener ( 'mousemove' , ( event ) = > ths . handleMouseMove ( event , videoData ) ) ;
}
}
2019-08-25 01:52:04 +02:00
unregisterHandleMouse ( videoData ) {
var ths = this ;
if ( videoData . player && videoData . player . element ) {
videoData . player . element . removeEventListener ( 'mousemove' , ( event ) = > ths . handleMouseMove ( event , videoData ) ) ;
}
}
2018-12-02 23:51:34 +01:00
2019-06-02 23:54:32 +02:00
setKeyboardLocal ( state ) {
if ( state === ExtensionMode . Enabled ) {
this . keyboardLocalDisabled = false ;
} else if ( state === ExtensionMode . Disabled ) {
this . keyboardLocalDisabled = true ;
}
// don't do shit on invalid value of state
}
2019-10-27 23:37:13 +01:00
preventAction ( event ) {
2018-11-14 23:32:37 +01:00
var activeElement = document . activeElement ;
2020-01-30 01:06:02 +01:00
if ( this . logger . canLog ( 'keyboard' ) ) {
2019-07-18 21:25:58 +02:00
this . logger . pause ( ) ; // temp disable to avoid recursing;
2020-01-30 01:06:02 +01:00
const preventAction = this . preventAction ( event ) ;
2019-10-27 23:37:13 +01:00
this . logger . resume ( ) ; // undisable
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'keyboard' , "[ActionHandler::preventAction] Testing whether we're in a textbox or something. Detailed rundown of conditions:\n" +
2018-11-15 00:18:41 +01:00
"\nis tag one of defined inputs? (yes->prevent):" , this . inputs . indexOf ( activeElement . tagName . toLocaleLowerCase ( ) ) !== - 1 ,
2018-11-14 23:32:37 +01:00
"\nis role = textbox? (yes -> prevent):" , activeElement . getAttribute ( "role" ) === "textbox" ,
"\nis type === 'text'? (yes -> prevent):" , activeElement . getAttribute ( "type" ) === "text" ,
2019-10-27 23:37:13 +01:00
"\nevent.target.isContentEditable? (yes -> prevent):" , event . target . isContentEditable ,
2019-06-02 23:54:32 +02:00
"\nis keyboard local disabled? (yes -> prevent):" , this . keyboardLocalDisabled ,
"\nis keyboard enabled in settings? (no -> prevent)" , this . settings . keyboardShortcutsEnabled ( window . location . hostname ) ,
2019-10-27 23:37:13 +01:00
"\nwill the action be prevented? (yes -> prevent)" , preventAction ,
2018-11-14 23:32:37 +01:00
"\n-----------------{ extra debug info }-------------------" ,
"\ntag name? (lowercase):" , activeElement . tagName , activeElement . tagName . toLocaleLowerCase ( ) ,
"\nrole:" , activeElement . getAttribute ( 'role' ) ,
"\ntype:" , activeElement . getAttribute ( 'type' ) ,
2019-10-27 23:37:13 +01:00
"\ninsta-fail inputs:" , this . inputs ,
"\nevent:" , event ,
"\nevent.target:" , event . target
2018-11-14 23:32:37 +01:00
) ;
}
2019-06-02 23:54:32 +02:00
if ( this . keyboardLocalDisabled ) {
return true ;
}
if ( ! this . settings . keyboardShortcutsEnabled ( window . location . hostname ) ) {
return true ;
}
2018-11-14 23:32:37 +01:00
if ( this . inputs . indexOf ( activeElement . tagName . toLocaleLowerCase ( ) ) !== - 1 ) {
return true ;
2021-11-25 20:00:32 +01:00
}
2018-11-14 23:32:37 +01:00
if ( activeElement . getAttribute ( "role" ) === "textbox" ) {
return true ;
}
2019-10-27 23:37:13 +01:00
if ( event . target . isContentEditable ) {
return true ;
}
2018-11-14 23:32:37 +01:00
if ( activeElement . getAttribute ( "type" ) === "text" ) {
return true ;
}
return false ;
}
2022-05-06 00:23:15 +02:00
ghettoLocalizeKeyboardEvent ( event : KeyboardEvent ) {
const realKey = event . key . toLocaleUpperCase ( ) ;
const isLatin = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890' . indexOf ( realKey ) !== - 1 ;
if ( ! isLatin ) {
return event ;
}
const nativeKey = event . code . substring ( 3 ) ;
if ( nativeKey !== realKey ) {
return {
. . . event ,
code : ` Key ${ realKey } `
} ;
}
return event ;
}
2019-10-22 01:33:56 +02:00
isLatin ( key ) {
2022-05-06 00:23:15 +02:00
return 'abcdefghijklmnopqrstuvwxyz1234567890' . indexOf ( key . toLocaleLowerCase ( ) ) !== - 1 ;
2019-10-22 01:33:56 +02:00
}
isActionMatchStandard ( shortcut , event ) {
2018-11-14 23:32:37 +01:00
return shortcut . key === event . key &&
shortcut . ctrlKey === event . ctrlKey &&
shortcut . metaKey === event . metaKey &&
shortcut . altKey === event . altKey &&
shortcut . shiftKey === event . shiftKey
}
2019-10-23 19:34:58 +02:00
isActionMatchKeyCode ( shortcut , event ) {
return shortcut . code === event . code &&
2019-10-22 01:33:56 +02:00
shortcut . ctrlKey === event . ctrlKey &&
shortcut . metaKey === event . metaKey &&
shortcut . altKey === event . altKey &&
shortcut . shiftKey === event . shiftKey
}
isActionMatch ( shortcut , event , isLatin = true ) {
2019-10-23 19:34:58 +02:00
// ASCII and symbols fall back to key code matching, because we don't know for sure that
2019-10-22 01:33:56 +02:00
// regular matching by key is going to work
2021-11-25 20:00:32 +01:00
return isLatin ?
this . isActionMatchStandard ( shortcut , event ) :
2019-10-23 19:34:58 +02:00
this . isActionMatchStandard ( shortcut , event ) || this . isActionMatchKeyCode ( shortcut , event ) ;
2019-10-22 01:33:56 +02:00
}
2018-11-14 23:32:37 +01:00
2018-12-02 23:51:34 +01:00
2018-11-14 23:32:37 +01:00
handleKeyup ( event ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'keyboard' , "%c[ActionHandler::handleKeyup] we pressed a key: " , "color: #ff0" , event . key , " | keyup: " , event . keyup , "event:" , event ) ;
2018-11-14 23:32:37 +01:00
2021-08-24 02:13:05 +02:00
try {
if ( this . preventAction ( event ) ) {
this . logger . log ( 'info' , 'keyboard' , "[ActionHandler::handleKeyup] we are in a text box or something. Doing nothing." ) ;
return ;
}
2018-11-14 23:32:37 +01:00
2022-05-06 00:23:15 +02:00
this . logger . log ( 'info' , 'keyboard' , "%c[ActionHandler::handleKeyup] Trying to find and execute action for event. Actions/event: " , "color: #ff0" , this . commands , event ) ;
2018-11-15 00:18:41 +01:00
2022-05-06 00:23:15 +02:00
const isLatin = this . isLatin ( event . key ) ;
2018-11-15 00:18:41 +01:00
2022-05-06 00:23:15 +02:00
for ( const command of this . commands ) {
if ( this . isActionMatch ( command . shortcut , event , isLatin ) ) {
this . eventBus . sendGlobal ( command . action , command . arguments ) ;
}
2021-08-24 02:13:05 +02:00
}
} catch ( e ) {
2022-05-06 00:23:15 +02:00
this . logger . log ( 'info' , 'debug' , '[ActionHandler::handleKeyup] Failed to handle keyup!' , e ) ;
2021-08-24 02:13:05 +02:00
}
2018-11-14 23:32:37 +01:00
}
2022-05-06 00:23:15 +02:00
2021-02-20 00:09:17 +01:00
handleMouseMove ( event , videoData? : VideoData ) {
2019-07-18 21:25:58 +02:00
this . logger . log ( 'info' , 'keyboard' , "[ActionHandler::handleMouseMove] mouse move is being handled.\nevent:" , event , "\nvideo data:" , videoData ) ;
2022-05-06 00:23:15 +02:00
console . info ( 'mousemove must be migrated!' ) ;
// videoData?.panHandler(event);
// this.execAction(this.mouseMoveActions, event, videoData)
2018-12-02 23:51:34 +01:00
}
2018-12-30 23:41:44 +01:00
}
2020-04-13 15:20:29 +02:00
if ( process . env . CHANNEL !== 'stable' ) {
2020-12-03 01:05:39 +01:00
console . info ( "ActionHandler loaded" ) ;
2020-04-13 15:20:29 +02:00
}
2018-12-30 23:41:44 +01:00
export default ActionHandler ;