import { IObserverHandle } from "./observer" ; import { root } from "./platform" ; export type RquestAnimationFrame = ( callback : FrameRequestCallback ) => number | undefined ; export type CancelAnimationFrame = ( handle : number ) => void | undefined ; let requestAnimationFrame ; ( function ( ) { if ( root . requestAnimationFrame ) { requestAnimationFrame = root . requestAnimationFrame ; } else { let lastTime = 0 ; requestAnimationFrame = function ( callback ) : number { const currTime = new Date ( ) . getTime ( ) ; const timeToCall = Math . max ( 0 , 16 - ( currTime - lastTime ) ) ; const id = setTimeout ( ( ) => callback ( currTime + timeToCall ) , timeToCall ) ; lastTime = currTime + timeToCall ; return id ; } ; } } ) ( ) ; export class Message { get canConflate ( ) : boolean { return false ; } conflate ( other ) { return false ; } void ( ) { return false ; } } type MessageConstructor < T extends Message > = new ( ... args ) => T ; export type Callback < T extends Message > = ( messages : T [ ] ) => void ; export { IObserverHandle } ; type ObserverAdapter < T extends Message = Message > = { id : number ; type ? : MessageConstructor < T > ; callback : Callback < T > ; } ; export class Dispatch < T extends Message = Message > { private _observerID : number = 0 ; private _observers : ObserverAdapter [ ] = [ ] ; private _messageBuffer : T [ ] = [ ] ; constructor ( ) { } private observers ( ) { return this . _observers ; } private messages ( ) { const retVal = [ ] ; this . _messageBuffer . forEach ( msg => { if ( ! retVal . some ( msg2 => msg2 . canConflate && msg2 . conflate ( msg ) ) ) { retVal . push ( msg ) ; } } ) ; return retVal ; } private dispatchAll ( ) { this . dispatch ( this . messages ( ) ) ; this . flush ( ) ; } private dispatch ( messages ) { if ( messages . length === 0 ) return ; this . observers ( ) . forEach ( o => { const msgs = messages . filter ( m => ! m . void ( ) && ( o . type === undefined || m instanceof o . type ) ) ; if ( msgs . length ) { o . callback ( msgs ) ; } } ) ; } hasObserver ( ) { return this . _observers . length > 0 ; } flush ( ) { this . _messageBuffer = [ ] ; } send ( msg ) { this . dispatch ( [ msg ] ) ; } post ( msg ) { this . _messageBuffer . push ( msg ) ; requestAnimationFrame ( ( ) => this . dispatchAll ( ) ) ; } attach ( callback , type ? ) { const context = this ; const id = ++ this . _observerID ; this . _observers . push ( { id , type , callback } ) ; return { release ( ) { context . _observers = context . _observers . filter ( o => o . id !== id ) ; } , unwatch ( ) { this . release ( ) ; } } ; } }