import { injectable } from "inversify" ; import { IEvent } from "../api/IEvent" ; import { IEventDispatcher } from "../api/IEventDispatcher" ; import { Event } from "../impl/Event" ; private const enum Keys { eventTarget , eventsMap , captureEventsMap , notifyLevel } private export interface IEventBin { type : string ; listener : Function ; thisObject : any ; priority : number ; target : IEventDispatcher ; useCapture : boolean ; dispatchOnce : boolean ; } let ONCE_EVENT_LIST = [ ] ; see egret . IEventDispatcher version platform includeExample language @ injectable ( ) export class EventDispatcher implements IEventDispatcher { private private _eventDispatcher : any ; param target version platform language public constructor ( target = null ) { this . _eventDispatcher = { 0 : target ? target : this , 1 : { } , 2 : { } , 3 : 0 } ; } inheritDoc version platform public addEventListener ( type , listener , thisObject ? , useCapture ? , priority ? ) { this . _addListener ( type , listener , thisObject , useCapture , priority ) ; } inheritDoc version platform public once ( type , listener , thisObject ? , useCapture ? , priority ? ) { this . _addListener ( type , listener , thisObject , useCapture , priority , true ) ; } inheritDoc version platform public removeEventListener ( type , listener , thisObject ? , useCapture ? ) { let values = this . _eventDispatcher ; let eventMap = this . _getEventMap ( useCapture ) ; let list = eventMap [ type ] ; if ( ! list ) { return ; } if ( values [ Keys . notifyLevel ] !== 0 ) { eventMap [ type ] = list = list . concat ( ) ; } this . _removeEventBin ( list , listener , thisObject ) ; if ( list . length === 0 ) { eventMap [ type ] = null ; } } inheritDoc version platform public hasEventListener ( type ) { let values = this . _eventDispatcher ; return ! ! ( values [ Keys . eventsMap ] [ type ] || values [ Keys . captureEventsMap ] [ type ] ) ; } inheritDoc version platform public willTrigger ( type ) { return this . hasEventListener ( type ) ; } inheritDoc version platform public dispatchEvent ( event ) { event . currentTarget = this . _eventDispatcher [ Keys . eventTarget ] ; event . target = event . currentTarget ; return this . _notifyListener ( event , false ) ; } param type param bubbles param data { any } param cancelable version platform language public dispatchEventWith ( type , bubbles ? , data ? , cancelable ? ) { if ( bubbles || this . hasEventListener ( type ) ) { let event = new Event ( type , bubbles , cancelable , data ) ; let result = this . dispatchEvent ( event ) ; return result ; } return true ; } private param useCapture private _getEventMap ( useCapture ? ) { let values = this . _eventDispatcher ; let eventMap = useCapture ? values [ Keys . captureEventsMap ] : values [ Keys . eventsMap ] ; return eventMap ; } private private _addListener ( type , listener , thisObject ? , useCapture ? , priority ? , dispatchOnce ? ) { let values = this . _eventDispatcher ; let eventMap = this . _getEventMap ( useCapture ) ; let list = eventMap [ type ] ; if ( ! list ) { list = eventMap [ type ] = [ ] ; } else if ( values [ Keys . notifyLevel ] !== 0 ) { eventMap [ type ] = list = list . concat ( ) ; } this . _insertEventBin ( list , type , listener , thisObject , useCapture , priority , dispatchOnce ) ; } private private _insertEventBin ( list , type , listener , thisObject ? , useCapture ? , priority ? , dispatchOnce ? ) { priority = priority || 0 ; let insertIndex = - 1 ; let length = list . length ; for ( let i = 0 ; i < length ; i ++ ) { let bin = list [ i ] ; if ( bin . listener === listener && bin . thisObject === thisObject && bin . target === this ) { return false ; } if ( insertIndex === - 1 && bin . priority < priority ) { insertIndex = i ; } } let eventBin = { type , listener , thisObject , priority , target : this , useCapture , dispatchOnce : ! ! dispatchOnce } ; if ( insertIndex !== - 1 ) { list . splice ( insertIndex , 0 , eventBin ) ; } else { list . push ( eventBin ) ; } return true ; } private private _removeEventBin ( list , listener , thisObject ? ) { let length = list . length ; for ( let i = 0 ; i < length ; i ++ ) { let bin = list [ i ] ; if ( bin . listener === listener && bin . thisObject === thisObject && bin . target === this ) { list . splice ( i , 1 ) ; return true ; } } return false ; } private private _notifyListener ( event , capturePhase ) { let values = this . _eventDispatcher ; let eventMap = this . _getEventMap ( capturePhase ) ; let list = eventMap [ event . type ] ; if ( ! list ) { return true ; } let length = list . length ; if ( length === 0 ) { return true ; } let onceList = ONCE_EVENT_LIST ; values [ Keys . notifyLevel ] ++ ; for ( let i = 0 ; i < length ; i ++ ) { let eventBin = list [ i ] ; eventBin . listener . call ( eventBin . thisObject , event ) ; if ( eventBin . dispatchOnce ) { onceList . push ( eventBin ) ; } if ( event . isPropagationImmediateStopped ) { break ; } } values [ Keys . notifyLevel ] -- ; while ( onceList . length ) { let eventBin = onceList . pop ( ) ; eventBin . target . removeEventListener ( eventBin . type , eventBin . listener , eventBin . thisObject , eventBin . useCapture ) ; } return ! event . isDefaultPrevented ; } }