2
0
mirror of https://github.com/frappe/books.git synced 2024-12-24 11:55:46 +00:00
books/frappe/utils/observable.js

129 lines
3.5 KiB
JavaScript
Raw Normal View History

2018-01-31 10:13:33 +00:00
module.exports = class Observable {
constructor() {
this._observable = {
isHot: {},
eventQueue: {},
listeners: {},
onceListeners: {}
}
}
2018-03-27 13:55:26 +00:00
// getter, setter stubs, so Observable can be used as a simple Document
get(key) {
return this[key];
}
set(key, value) {
this[key] = value;
2019-01-12 12:10:52 +00:00
this.trigger('change', {
doc: this,
fieldname: key
});
2018-03-27 13:55:26 +00:00
}
2018-02-13 11:54:57 +00:00
on(event, listener) {
this._addListener('listeners', event, listener);
if (this._observable.socketClient) {
this._observable.socketClient.on(event, listener);
2018-02-19 16:41:10 +00:00
}
2018-01-31 12:56:21 +00:00
}
2018-01-31 10:13:33 +00:00
// remove listener
off(event, listener) {
for (let type of ['listeners', 'onceListeners']) {
let index = this._observable[type][event] && this._observable[type][event].indexOf(listener);
if (index) {
this._observable[type][event].splice(index, 1);
}
}
}
2018-02-13 11:54:57 +00:00
once(event, listener) {
this._addListener('onceListeners', event, listener);
2018-02-19 16:41:10 +00:00
}
2019-01-12 12:10:52 +00:00
async trigger(event, params, throttle = false) {
2018-02-23 16:17:55 +00:00
if (throttle) {
if (this._throttled(event, params, throttle)) return;
params = [params]
}
2018-02-23 16:17:55 +00:00
await this._executeTriggers(event, params);
}
2018-02-23 16:17:55 +00:00
async _executeTriggers(event, params) {
let response = await this._triggerEvent('listeners', event, params);
if (response === false) return false;
response = await this._triggerEvent('onceListeners', event, params);
if (response === false) return false;
2018-02-13 11:54:57 +00:00
// emit via socket
if (this._observable.socketServer) {
this._observable.socketServer.emit(event, params);
2018-02-19 16:41:10 +00:00
}
2018-02-13 11:54:57 +00:00
// clear once-listeners
if (this._observable.onceListeners && this._observable.onceListeners[event]) {
delete this._observable.onceListeners[event];
}
}
clearListeners() {
this._observable.listeners = {};
this._observable.onceListeners = {};
}
bindSocketClient(socket) {
// also send events with sockets
this._observable.socketClient = socket;
}
bindSocketServer(socket) {
// also send events with sockets
this._observable.socketServer = socket;
}
_throttled(event, params, throttle) {
if (this._observable.isHot[event]) {
2018-02-23 16:17:55 +00:00
// hot, add to queue
if (!this._observable.eventQueue[event]) this._observable.eventQueue[event] = [];
this._observable.eventQueue[event].push(params);
2018-02-23 16:17:55 +00:00
// aleady hot, quit
return true;
}
this._observable.isHot[event] = true;
2018-02-23 16:17:55 +00:00
// cool-off
setTimeout(() => {
this._observable.isHot[event] = false;
2018-02-23 16:17:55 +00:00
// flush queue
if (this._observable.eventQueue[event]) {
let _queuedParams = this._observable.eventQueue[event];
this._observable.eventQueue[event] = null;
2018-02-23 16:17:55 +00:00
this._executeTriggers(event, _queuedParams);
}
2018-02-23 16:17:55 +00:00
}, throttle);
return false;
}
_addListener(type, event, listener) {
if (!this._observable[type][event]) {
this._observable[type][event] = [];
}
this._observable[type][event].push(listener);
}
async _triggerEvent(type, event, params) {
if (this._observable[type][event]) {
for (let listener of this._observable[type][event]) {
2018-02-13 11:54:57 +00:00
await listener(params);
2018-01-31 10:13:33 +00:00
}
}
}
}