namespace Leaf { export class ReadyBehavior { public isReady = false private readyCallbacks = Leaf.SharedCallbacks.create() counter = 0 debug = false yes() { //if (this.isReady) { // throw new Error("Already ready") //} if (this.counter++ > 0 && this.debug) { console.trace() } this.isReady = true this.events.emit("ready") this.readyCallbacks() } error(err: Error) { this.readyCallbacks(err) } no() { if (!this.isReady) { throw new Error("Not ready") } this.isReady = false this.events.emit("unready") this.readyCallbacks(new Error("Won't ready, ready.no() is specified")) } events = new Leaf.EventEmitter<{ ready unready }>() whenReady(cb: Function) { if (this.isReady) { cb() } else { this.readyCallbacks.push(cb) } } } export class FrameBehavior { interval: number = 1000 setInterval(interval: number) { this.interval = interval return this } private framer: (callback: Callback) => void = (callback: Callback) => { callback() } frame(fn: (callback: Callback) => void) { this.framer = fn return this } isStart = false start() { if (this.isStart) return this.isStart = true this.do() return this } stop() { if (!this.isStart) return this.isStart = false clearTimeout(this.timer) return this } private isFrameActive = false timer = null do() { let begin = Date.now() this.isFrameActive = true let callback = () => { this.isFrameActive = false if (!this.isStart) return let pass = Date.now() - begin let interval = this.interval if (this.timeMode == "include") { interval = Math.max(0, interval - pass) } this.timer = setTimeout(() => { this.do() }, interval) } this.framer(callback) if (this.framer.length == 0) { callback() } } timeMode: string = "between" mode(mode: "include" | "beteen") { this.timeMode = mode return this } } }