UNPKG

board-game

Version:

an online board game engine

171 lines (169 loc) 5.58 kB
/** * Created by wm123 on 2017/5/23. */ class Queue { constructor() { this.queue = []; this.timer = false; } exec() { if (this.queue.length) { clearTimeout(this.timer); this.timer = process.nextTick(() => { this.queue.shift().call(); this.exec(); }); } } execute(executor) { this.queue.push(executor); this.exec(); } } class Listener { constructor(dispatcher) { this.dispatcher = dispatcher; this.listeners = []; this.callbacks = []; this.queue = new Queue(); } add(listener, id) { let index = this.listeners.findIndex(fun => fun === listener || typeof fun.id !== 'undefined' && fun.id === id); if (index >= 0) this.listeners.splice(index, 1); listener.id = id; this.listeners.push(listener); } remove(listener) { let index = this.listeners.findIndex(fun => fun === listener || typeof fun.id !== 'undefined' && fun.id === listener); if (index >= 0) this.listeners.splice(index, 1); } removeAll() { this.listeners = []; } dispatch(callback) { this.callbacks.push(callback); if (this.callbacks.length === 1) { this.queue.execute(() => { this.dispatcher.dispatching = true; this.listeners.forEach(cb => cb && cb.call(this.dispatcher, this.dispatcher)); this.callbacks.forEach(cb => cb.call()); this.callbacks = []; this.dispatcher.dispatching = false; }); } } get size() { return this.listeners.length; } } class ListenerMap { constructor() { this.listeners = new WeakMap(); } add(dispatcher, listener, id) { this.get(dispatcher).add(listener, id); } remove(dispatcher, listener) { this.get(dispatcher).remove(listener); } removeAll(dispatcher) { this.get(dispatcher).removeAll(); } get(dispatcher) { if (this.listeners.has(dispatcher)) { return this.listeners.get(dispatcher); } else { let listener = new Listener(dispatcher); this.listeners.set(dispatcher, listener); return listener; } } dispatch(dispatcher, callback) { this.get(dispatcher).dispatch(callback); } size(dispatcher) { return this.get(dispatcher).size; } } class Dispatcher { constructor() { this.listeners = new ListenerMap(); this.dispatching = false; let dispatcher = new Proxy(this, { set(target, property, value, receiver) { Reflect.set(target, property, value, receiver); if (!property.startsWith('~') && property !== 'dispatching') { if (!dispatcher.dispatching) dispatcher.dispatch(); } return true; }, get(target, property, receiver) { let value = Reflect.get(target, property, receiver); if (!['on', 'off', 'clear', 'dispatch', 'constructor', 'dispatching'].includes(property) && !(property in { }) && (value instanceof Function || typeof value === 'function')) { return function() { let result = value.apply(this, arguments); if (!dispatcher.dispatching) dispatcher.dispatch(); return result; }; } else { return value; } }, deleteProperty(target, property) { if (Reflect.get(target, property, dispatcher) instanceof Dispatcher) Reflect.get(target, property, dispatcher).off(dispatcher); Reflect.deleteProperty(target, property); if (!property.startsWith('~')) { Reflect.set(target, '~' + property, true); if (!dispatcher.dispatching) dispatcher.dispatch(); } return true; } }); //dispatcher.dispatch(); return dispatcher; } on(listener, id, append = false) { this.listeners.add(this, listener, id); if(!append) this.dispatch(); } off(listener) { this.listeners.remove(this, listener); } clear() { this.listeners.removeAll(this); } refresh() { //do nothing } dispatch() { this.listeners.dispatch(this, () => { for (let name in this) { if (this.hasOwnProperty(name)) { if (name.startsWith('~')) { delete this[name]; } } } }); } dispose() { this.clear(); } get data() { let result = { }; for (let name in this) { if (this.hasOwnProperty(name)) { if (name !== 'data' && name !== 'listeners') { let value = this[name]; if (value instanceof Dispatcher) { result[name] = value.data; } else { result[name] = value; } } } } return result; } } module.exports = Dispatcher;