import { ConnectorRegistry } from './ConnectorRegistry' ; import { EventHandlerUpdates , CraftEventListener , EventHandlerConnectors , CraftDOMEvent , Connector , ConnectorsUsage , } from './interfaces' ; import { isEventBlockedByDescendant } from './isEventBlockedByDescendant' ; export abstract class EventHandlers < O extends Record < string , any > = { } > { options : O ; private registry : ConnectorRegistry = new ConnectorRegistry ( ) ; private subscribers : Set < ( msg : EventHandlerUpdates ) => void > = new Set ( ) ; onEnable ? ( ) ; onDisable ? ( ) ; constructor ( options ? ) { this . options = options ; } listen ( cb ) { this . subscribers . add ( cb ) ; return ( ) => this . subscribers . delete ( cb ) ; } disable ( ) { if ( this . onDisable ) { this . onDisable ( ) ; } this . registry . disable ( ) ; this . subscribers . forEach ( ( listener ) => { listener ( EventHandlerUpdates . HandlerDisabled ) ; } ) ; } enable ( ) { if ( this . onEnable ) { this . onEnable ( ) ; } this . registry . enable ( ) ; this . subscribers . forEach ( ( listener ) => { listener ( EventHandlerUpdates . HandlerEnabled ) ; } ) ; } cleanup ( ) { this . disable ( ) ; this . subscribers . clear ( ) ; this . registry . clear ( ) ; } addCraftEventListener < K extends keyof HTMLElementEventMap > ( el , eventName , listener , options ? ) { const bindedListener = ( e ) => { if ( ! isEventBlockedByDescendant ( e , eventName , el ) ) { e . craft . stopPropagation = ( ) => { if ( ! e . craft . blockedEvents [ eventName ] ) { e . craft . blockedEvents [ eventName ] = [ ] ; } e . craft . blockedEvents [ eventName ] . push ( el ) ; } ; listener ( e ) ; } } ; el . addEventListener ( eventName , bindedListener , options ) ; return ( ) => el . removeEventListener ( eventName , bindedListener , options ) ; } abstract handlers ( ) ; /**
     * Creates a record of chainable connectors and tracks their usages
     */ createConnectorsUsage ( ) { const handlers = this . handlers ( ) ; const activeConnectorIds = new Set ( ) ; const connectors = Object . entries ( handlers ) . reduce < Record < string , Connector > > ( ( accum , [ name , handler ] ) => ( { ... accum , [ name ] : ( el , required , options ) => { const connector = this . registry . register ( el , { required , name , options , connector : handler , } ) ; activeConnectorIds . add ( connector . id ) ; return el ; } , } ) , { } ) as any ; return { connectors , cleanup : ( ) => { activeConnectorIds . forEach ( ( connectorId ) => this . registry . remove ( connectorId ) ) ; } , } ; } derive < C extends EventHandlers > ( type , opts ) { return new type ( this , opts ) ; } protected createProxyHandlers < H extends EventHandlers > ( instance , cb ) { const connectorsToCleanup = [ ] ; const handlers = instance . handlers ( ) ; const proxiedHandlers = new Proxy ( handlers , { get : ( target , key , receiver ) => { if ( key in handlers === false ) { return Reflect . get ( target , key , receiver ) ; } return ( el , ... args ) => { const cleanup = handlers [ key ] ( el , ... args ) ; if ( ! cleanup ) { return ; } connectorsToCleanup . push ( cleanup ) ; } ; } , } ) ; cb ( proxiedHandlers as any ) ; return ( ) => { connectorsToCleanup . forEach ( ( cleanup ) => { cleanup ( ) ; } ) ; } ; } reflect ( cb ) { return this . createProxyHandlers ( this , cb ) ; } }