2
0
mirror of https://github.com/frappe/books.git synced 2024-11-08 23:00:56 +00:00

added submit feature and other cleanups

This commit is contained in:
Rushabh Mehta 2018-02-27 21:59:14 +05:30
parent 415389bca0
commit b8d7294465
24 changed files with 281 additions and 162 deletions

View File

@ -36,7 +36,7 @@ module.exports = class Database extends Observable {
let indexes = [];
for (let field of meta.getValidFields({ withChildren: false })) {
if (this.type_map[field.fieldtype]) {
if (this.typeMap[field.fieldtype]) {
this.updateColumnDefinition(field, columns, indexes);
}
}
@ -53,7 +53,7 @@ module.exports = class Database extends Observable {
}
updateColumnDefinition(field, columns, indexes) {
// return `${df.fieldname} ${this.type_map[df.fieldtype]} ${ ? "PRIMARY KEY" : ""} ${df.required && !df.default ? "NOT NULL" : ""} ${df.default ? `DEFAULT ${df.default}` : ""}`
// return `${df.fieldname} ${this.typeMap[df.fieldtype]} ${ ? "PRIMARY KEY" : ""} ${df.required && !df.default ? "NOT NULL" : ""} ${df.default ? `DEFAULT ${df.default}` : ""}`
}
async alterTable(doctype) {
@ -74,7 +74,7 @@ module.exports = class Database extends Observable {
let meta = frappe.getMeta(doctype);
let newColumns = [];
for (let field of meta.getValidFields({ withChildren: false })) {
if (!tableColumns.includes(field.fieldname) && this.type_map[field.fieldtype]) {
if (!tableColumns.includes(field.fieldname) && this.typeMap[field.fieldtype]) {
newColumns.push(field);
}
}
@ -399,7 +399,7 @@ module.exports = class Database extends Observable {
}
initTypeMap() {
this.type_map = {
this.typeMap = {
'Currency': 'real'
, 'Int': 'integer'
, 'Float': 'real'

View File

@ -119,7 +119,7 @@ module.exports = class HTTPClient extends Observable {
}
initTypeMap() {
this.type_map = {
this.typeMap = {
'Currency': true
, 'Int': true
, 'Float': true

View File

@ -11,7 +11,7 @@ module.exports = class mysqlDatabase extends Database{
this.username = username;
this.password = password;
this.host = host;
this.init_type_map();
this.init_typeMap();
}
connect(db_name) {
@ -53,7 +53,7 @@ module.exports = class mysqlDatabase extends Database{
updateColumnDefinition(df, columns, indexes) {
columns.push(`${df.fieldname} ${this.type_map[df.fieldtype]} ${df.reqd && !df.default ? "not null" : ""} ${df.default ? `default '${df.default}'` : ""}`);
columns.push(`${df.fieldname} ${this.typeMap[df.fieldtype]} ${df.reqd && !df.default ? "not null" : ""} ${df.default ? `default '${df.default}'` : ""}`);
}
async getTableColumns(doctype) {
@ -176,8 +176,8 @@ module.exports = class mysqlDatabase extends Database{
}
init_type_map() {
this.type_map = {
init_typeMap() {
this.typeMap = {
'Currency': 'real'
, 'Int': 'INT'
, 'Float': 'decimal(18,6)'

View File

@ -66,7 +66,7 @@ module.exports = class sqliteDatabase extends Database {
}
getColumnDefinition(field) {
let def = `${field.fieldname} ${this.type_map[field.fieldtype]}`;
let def = `${field.fieldname} ${this.typeMap[field.fieldtype]}`;
if (field.fieldname==='name') {
def += ' PRIMARY KEY NOT NULL';
}
@ -205,7 +205,7 @@ module.exports = class sqliteDatabase extends Database {
}
initTypeMap() {
this.type_map = {
this.typeMap = {
'Currency': 'real'
, 'Int': 'integer'
, 'Float': 'real'

View File

@ -27,11 +27,11 @@ module.exports = class FormModal extends Modal {
doctype: this.doctype,
parent: this.getBody(),
container: this,
actions: ['submit']
actions: ['save']
});
this.form.on('submit', async () => {
await this.trigger('submit');
this.form.on('save', async () => {
await this.trigger('save');
this.hide();
});
}

View File

@ -13,7 +13,7 @@ module.exports = class FormPage extends Page {
doctype: doctype,
parent: this.body,
container: this,
actions: ['submit', 'delete', 'duplicate', 'settings', 'print']
actions: ['save', 'delete', 'duplicate', 'settings', 'print']
});
this.on('show', async (params) => {
@ -21,11 +21,11 @@ module.exports = class FormPage extends Page {
});
// if name is different after saving, change the route
this.form.on('submit', async (params) => {
this.form.on('save', async (params) => {
let route = frappe.router.get_route();
if (this.form.doc.name && !(route && route[2] === this.form.doc.name)) {
await frappe.router.setRoute('edit', this.form.doc.doctype, this.form.doc.name);
this.form.showAlert('Added', 'success');
frappe.ui.showAlert({message: 'Added', color: 'green'});
}
});

View File

@ -36,6 +36,7 @@ module.exports = class PrintPage extends Page {
try {
this.body.innerHTML = `<div class="print-page">${nunjucks.renderString(this.printFormat.template, context)}</div>`;
this.setTitle(doc.name);
if (doc.submitted) this.addTitleBadge('✓', 'Submitted');
} catch (e) {
this.renderError('Template Error', e);
throw e;

View File

@ -3,6 +3,7 @@
@import "node_modules/flatpickr/dist/flatpickr";
@import "node_modules/flatpickr/dist/themes/airbnb";
@import "node_modules/codemirror/lib/codemirror";
@import "node_modules/frappe-datatable/dist/frappe-datatable";
$spacer-1: 0.25rem;
$spacer-2: 0.5rem;
@ -36,8 +37,8 @@ html {
.page-head {
padding: $spacer-2 $spacer-3;
background-color: $gray-800;
color: $gray-100;
background-color: $gray-100;
border-bottom: 1px solid $gray-300;
.page-title {
display: inline-block;
@ -56,7 +57,7 @@ html {
}
.form-body {
padding: $spacer-3;
padding: $spacer-4;
.form-control.font-weight-bold {
background-color: lightyellow;
@ -100,6 +101,15 @@ html {
padding: $spacer-2 $spacer-3;
}
.bottom-right-float {
position: fixed;
margin-bottom: 0px;
bottom: $spacer-3;
right: $spacer-3;
max-width: 200px;
padding: $spacer-2 $spacer-3;
}
.desk-menu {
background-color: $gray-200;

View File

@ -41,6 +41,12 @@ module.exports = {
make_dropdown(label, parent, btn_class = 'btn-secondary') {
return new Dropdown({parent: parent, label:label, btn_class:btn_class});
}
},
showAlert({message, color='yellow', timeout=4}) {
let alert = this.add('div', 'alert alert-warning bottom-right-float', document.body);
alert.innerHTML = `<span class='indicator ${color}'>${message}</span>`;
frappe.sleep(timeout).then(() => alert.remove());
return alert;
}
}

View File

@ -37,6 +37,7 @@ class BaseControl {
} else {
this.setDocValue();
}
this.setDisabled();
}
renderTemplate() {
@ -86,10 +87,12 @@ class BaseControl {
}
isDisabled() {
return this.disabled || this.formula || (this.doc && this.doc.submitted);
}
setDisabled() {
if (this.disabled) {
this.input.disabled = true;
}
this.input.disabled = this.isDisabled();
}
getInputParent() {

View File

@ -22,6 +22,13 @@ class DateControl extends BaseControl {
});
}
setDisabled() {
this.input.disabled = this.isDisabled();
if (this.flatpickr && this.flatpickr.altInput) {
this.flatpickr.altInput.disabled = this.isDisabled();
}
}
setInputValue(value) {
super.setInputValue(value);
this.flatpickr.setDate(value);

View File

@ -39,7 +39,7 @@ class LinkControl extends BaseControl {
formModal.form.doc.set('name', this.input.value);
}
formModal.once('submit', async () => {
formModal.once('save', async () => {
await this.updateDocValue(formModal.form.doc.name);
});
}

View File

@ -55,11 +55,21 @@ class TableControl extends BaseControl {
setInputValue(value) {
this.datatable.refresh(this.getTableData(value));
}
setDisabled() {
this.refreshToolbar();
}
getToolbar() {
return this.wrapper.querySelector('.table-toolbar');
}
refreshToolbar() {
this.wrapper.querySelector('.table-toolbar').classList.toggle('hide', this.disabled ? true : false);
const toolbar = this.wrapper.querySelector('.table-toolbar');
if (toolbar) {
toolbar.classList.toggle('hide', this.isDisabled() ? true : false);
}
}
getTableData(value) {
@ -68,6 +78,9 @@ class TableControl extends BaseControl {
getTableInput(colIndex, rowIndex, value, parent) {
let field = this.datatable.getColumn(colIndex).field;
if (field.disabled || field.forumla || this.isDisabled()) {
return false;
}
if (field.fieldtype==='Text') {
// text in modal
@ -92,6 +105,7 @@ class TableControl extends BaseControl {
return control.setInputValue(control.doc[column.id]);
},
setValue: async (value, rowIndex, column) => {
this.doc._dirty = true;
control.handleChange();
},
getValue: () => {
@ -127,7 +141,7 @@ class TableControl extends BaseControl {
id: field.fieldname,
field: field,
content: field.label,
editable: (this.disabled || field.disabled) ? false : true,
editable: true,
sortable: false,
resizable: true,
dropdown: false,

View File

@ -43,10 +43,12 @@ module.exports = class BaseForm extends Observable {
}
makeToolbar() {
if (this.actions.includes('submit')) {
this.container.addButton(frappe._("Save"), 'primary', async (event) => {
await this.submit();
})
if (this.actions.includes('save')) {
this.makeSaveButton();
if (this.meta.isSubmittable) {
this.makeSubmitButton();
}
}
if (this.meta.print && this.actions.includes('print')) {
@ -67,7 +69,6 @@ module.exports = class BaseForm extends Observable {
let menu = this.container.getDropdown(frappe._('Menu'));
menu.addItem(frappe._('Duplicate'), async () => {
let newDoc = await frappe.getDuplicate(this.doc);
console.log(newDoc);
await frappe.router.setRoute('edit', newDoc.doctype, newDoc.name);
newDoc.set('name', '');
});
@ -82,13 +83,38 @@ module.exports = class BaseForm extends Observable {
}
makeSaveButton() {
this.saveButton = this.container.addButton(frappe._("Save"), 'primary', async (event) => {
await this.save();
});
this.on('change', () => {
const show = this.doc._dirty && !this.doc.submitted;
this.saveButton.classList.toggle('hide', !show);
});
}
makeSubmitButton() {
this.submitButton = this.container.addButton(frappe._("Submit"), 'primary', async (event) => {
await this.submit();
});
this.on('change', () => {
const show = this.meta.isSubmittable && !this.doc._dirty && !this.doc.submitted;
this.submitButton.classList.toggle('hide', !show);
});
}
bindKeyboard() {
keyboard.bindKey(this.form, 'ctrl+s', (e) => {
if (document.activeElement) {
document.activeElement.blur();
}
e.preventDefault();
this.submit();
if (this.doc._notInserted || this.doc._dirty) {
this.save();
} else {
if (this.meta.isSubmittable && !this.doc.submitted) this.submit();
}
});
}
@ -101,6 +127,7 @@ module.exports = class BaseForm extends Observable {
await this.doc.set('name', '');
}
this.setTitle();
frappe._curFrm = this;
}
setTitle() {
@ -113,6 +140,7 @@ module.exports = class BaseForm extends Observable {
} else {
this.container.setTitle(this.doc.name);
}
if (this.doc.submitted) this.container.addTitleBadge('✓', frappe._('Submitted'));
}
async bindEvents(doc) {
@ -120,17 +148,16 @@ module.exports = class BaseForm extends Observable {
// stop listening to the old doc
this.doc.off(this.docListener);
}
this.clearAlert();
this.doc = doc;
for (let control of this.controlList) {
control.bind(this.doc);
}
this.setupChangeListener();
this.setupDocListener();
this.trigger('use', {doc:doc});
}
setupChangeListener() {
setupDocListener() {
// refresh value in control
this.docListener = (params) => {
if (params.fieldname) {
@ -143,10 +170,12 @@ module.exports = class BaseForm extends Observable {
// multiple values changed
this.refresh();
}
this.trigger('change');
this.form.classList.remove('was-validated');
};
this.doc.on('change', this.docListener);
this.trigger('change');
}
checkValidity() {
@ -165,7 +194,18 @@ module.exports = class BaseForm extends Observable {
return validity;
}
refresh() {
for(let control of this.controlList) {
control.refresh();
}
}
async submit() {
this.doc.submitted = 1;
await this.save();
}
async save() {
if (!this.checkValidity()) {
this.form.classList.add('was-validated');
return;
@ -176,44 +216,23 @@ module.exports = class BaseForm extends Observable {
} else {
await this.doc.update();
}
this.showAlert('Saved', 'success');
frappe.ui.showAlert({message: frappe._('Saved'), color: 'green'});
this.refresh();
this.trigger('change');
} catch (e) {
this.showAlert('Failed', 'danger');
frappe.ui.showAlert({message: frappe._('Failed'), color: 'red'});
return;
}
await this.trigger('submit');
await this.trigger('save');
}
async delete() {
try {
await this.doc.delete();
this.showAlert('Deleted', 'success');
frappe.ui.showAlert({message: frappe._('Deleted'), color: 'green'});
this.trigger('delete');
} catch (e) {
this.showAlert(e, 'danger');
frappe.ui.showAlert({message: e, color: 'red'});
}
}
refresh() {
for(let control of this.controlList) {
control.refresh();
}
}
showAlert(message, type, clear_after = 5) {
this.clearAlert();
this.alert = frappe.ui.add('div', `alert alert-${type}`, this.body);
this.alert.textContent = message;
setTimeout(() => {
this.clearAlert();
}, clear_after * 1000);
}
clearAlert() {
if (this.alert) {
frappe.ui.remove(this.alert);
this.alert = null;
}
}
}

View File

@ -58,9 +58,11 @@ module.exports = class BaseList {
}
async getData() {
let fields = this.getFields();
this.updateStandardFields(fields);
return await frappe.db.getAll({
doctype: this.doctype,
fields: this.getFields(),
fields: fields,
filters: this.getFilters(),
start: this.start,
limit: this.pageLength + 1
@ -68,7 +70,13 @@ module.exports = class BaseList {
}
getFields() {
return ['name'];
return [];
}
updateStandardFields(fields) {
if (!fields.includes('name')) fields.push('name');
if (!fields.includes('modified')) fields.push('modified');
if (this.meta.isSubmittable && !fields.includes('submitted')) fields.push('submitted');
}
async append() {

View File

@ -35,6 +35,11 @@ module.exports = class Page extends Observable {
}
}
addTitleBadge(message, title='', style='secondary') {
this.titleElement.innerHTML += ` <span class='badge badge-${style}' title='${title}'>
${message}</span>`;
}
hide() {
this.parent.activePage = null;
this.wrapper.classList.add('hide');

View File

@ -12,6 +12,7 @@ class ValidationError extends BaseError {
module.exports = {
ValidationError: ValidationError,
ValueError: class ValueError extends ValidationError { },
Conflict: class Conflict extends ValidationError { },
NotFound: class NotFound extends BaseError {
constructor(...params) { super(404, ...params); }
},

View File

@ -104,7 +104,7 @@ module.exports = {
async getDuplicate(doc) {
const newDoc = await this.getNewDoc(doc.doctype);
for (let field of this.getMeta(doc.doctype).getValidFields()) {
if (field.fieldname === 'name') continue;
if (['name', 'submitted'].includes(field.fieldname)) continue;
if (field.fieldtype === 'Table') {
newDoc[field.fieldname] = (doc[field.fieldname] || []).map(d => {
let newd = Object.assign({}, d);

View File

@ -128,16 +128,17 @@ module.exports = class BaseDocument extends Observable {
}
setStandardValues() {
let now = new Date();
if (this.docstatus === null || this.docstatus === undefined) {
this.docstatus = 0;
// set standard values on server-side only
if (frappe.isServer) {
let now = new Date();
if (!this.submitted) this.submitted = 0;
if (!this.owner) {
this.owner = frappe.session.user;
this.creation = now;
}
this.modifieldBy = frappe.session.user;
this.modified = now;
}
if (!this.owner) {
this.owner = frappe.session.user;
this.creation = now;
}
this.modifieldBy = frappe.session.user;
this.modified = now;
}
async load() {
@ -178,6 +179,30 @@ module.exports = class BaseDocument extends Observable {
}
}
async compareWithCurrentDoc() {
if (frappe.isServer && !this._notInserted) {
let currentDoc = await frappe.db.get(this.doctype, this.name);
// check for conflict
if (currentDoc && this.modified != currentDoc.modified) {
throw new frappe.errors.Conflict(frappe._('Document {0} {1} has been modified after loading', [this.doctype, this.name]));
}
if (this.submitted && !this.meta.isSubmittable) {
throw new frappe.errors.ValidationError(frappe._('Document type {1} is not submittable', [this.doctype]));
}
// set submit action flag
if (this.submitted && !currentDoc.submitted) {
this.submitAction = true;
}
if (currentDoc.submitted && !this.submitted) {
this.unSubmitAction = true;
}
}
}
async applyFormula() {
if (!this.meta.hasFormula()) {
return false;
@ -219,20 +244,25 @@ module.exports = class BaseDocument extends Observable {
async insert() {
await this.commit();
await this.trigger('before_insert');
await this.trigger('beforeInsert');
this.syncValues(await frappe.db.insert(this.doctype, this.getValidDict()));
await this.trigger('after_insert');
await this.trigger('after_save');
await this.trigger('afterInsert');
await this.trigger('afterSave');
return this;
}
async update() {
await this.compareWithCurrentDoc();
await this.commit();
await this.trigger('before_update');
await this.trigger('beforeUpdate');
if (this.submitAction) this.trigger('beforeSubmit');
if (this.unSubmitAction) this.trigger('beforeUnSubmit');
this.syncValues(await frappe.db.update(this.doctype, this.getValidDict()));
await this.trigger('after_update');
await this.trigger('after_save');
await this.trigger('afterUpdate');
await this.trigger('afterSave');
if (this.submitAction) this.trigger('afterSubmit');
if (this.unSubmitAction) this.trigger('afterUnSubmit');
return this;
}
@ -243,6 +273,8 @@ module.exports = class BaseDocument extends Observable {
await this.trigger('after_delete');
}
// trigger methods on the class if they match
// with the trigger name
async trigger(event, params) {
if (this[event]) {
await this[event](params);

View File

@ -15,12 +15,12 @@ module.exports = {
let next = await series.next()
return prefix + next;
},
common_fields: [
commonFields: [
{
fieldname: 'name', fieldtype: 'Data', required: 1
}
],
parent_fields: [
parentFields: [
{
fieldname: 'owner', fieldtype: 'Data', required: 1
},
@ -35,12 +35,9 @@ module.exports = {
},
{
fieldname: 'keywords', fieldtype: 'Text'
},
{
fieldname: 'docstatus', fieldtype: 'Int', required: 1, default: 0
}
],
child_fields: [
childFields: [
{
fieldname: 'idx', fieldtype: 'Int', required: 1
},

View File

@ -69,36 +69,40 @@ module.exports = class BaseMeta extends BaseDocument {
}
getValidFields({ withChildren = true } = {}) {
if (!this._valid_fields) {
if (!this._validFields) {
this._valid_fields = [];
this._valid_fields_withChildren = [];
this._validFields = [];
this._validFieldsWithChildren = [];
const _add = (field) => {
this._valid_fields.push(field);
this._valid_fields_withChildren.push(field);
this._validFields.push(field);
this._validFieldsWithChildren.push(field);
}
const doctype_fields = this.fields.map((field) => field.fieldname);
// standard fields
for (let field of model.common_fields) {
if (frappe.db.type_map[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
for (let field of model.commonFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
if (this.isSubmittable) {
_add({fieldtype:'Check', fieldname: 'submitted', label: frappe._('Submitted')})
}
if (this.isChild) {
// child fields
for (let field of model.child_fields) {
if (frappe.db.type_map[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
for (let field of model.childFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
} else {
// parent fields
for (let field of model.parent_fields) {
if (frappe.db.type_map[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
for (let field of model.parentFields) {
if (frappe.db.typeMap[field.fieldtype] && !doctype_fields.includes(field.fieldname)) {
_add(field);
}
}
@ -106,7 +110,7 @@ module.exports = class BaseMeta extends BaseDocument {
// doctype fields
for (let field of this.fields) {
let include = frappe.db.type_map[field.fieldtype];
let include = frappe.db.typeMap[field.fieldtype];
if (include) {
_add(field);
@ -114,15 +118,15 @@ module.exports = class BaseMeta extends BaseDocument {
// include tables if (withChildren = True)
if (!include && field.fieldtype === 'Table') {
this._valid_fields_withChildren.push(field);
this._validFieldsWithChildren.push(field);
}
}
}
if (withChildren) {
return this._valid_fields_withChildren;
return this._validFieldsWithChildren;
} else {
return this._valid_fields;
return this._validFields;
}
}
@ -162,12 +166,13 @@ module.exports = class BaseMeta extends BaseDocument {
setDefaultIndicators() {
if (!this.indicators) {
this.indicators = {
key: 'docstatus',
colors: {
0: 'gray',
1: 'blue',
2: 'red'
if (this.isSubmittable) {
this.indicators = {
key: 'submitted',
colors: {
0: 'gray',
1: 'blue'
}
}
}
}
@ -177,9 +182,13 @@ module.exports = class BaseMeta extends BaseDocument {
if (frappe.isDirty(this.name, doc.name)) {
return 'orange';
} else {
let value = doc[this.indicators.key];
if (value) {
return this.indicators.colors[value] || 'gray';
if (this.indicators) {
let value = doc[this.indicators.key];
if (value) {
return this.indicators.colors[value] || 'gray';
} else {
return 'gray';
}
} else {
return 'gray';
}

View File

@ -43,6 +43,7 @@ module.exports = {
// listen
frappe.app = app;
frappe.server = server;
frappe.isServer = true;
server.listen(frappe.config.port);
},

View File

@ -15,10 +15,10 @@ module.exports = {
_(text, args) {
// should return translated text
return this.string_replace(text, args);
return this.stringReplace(text, args);
},
string_replace(str, args) {
stringReplace(str, args) {
if (!Array.isArray(args)) {
args = [args];
}

View File

@ -1,38 +1,32 @@
module.exports = class Observable {
constructor() {
this._isHot = {};
this._eventQueue = {};
this._observable = {
isHot: {},
eventQueue: {},
listeners: {},
onceListeners: {}
}
}
on(event, listener) {
this._addListener('_listeners', event, listener);
if (this._socketClient) {
this._socketClient.on(event, listener);
this._addListener('listeners', event, listener);
if (this._observable.socketClient) {
this._observable.socketClient.on(event, listener);
}
}
// remove listener
off(event, listener) {
for (let type of ['_listeners', '_onceListeners']) {
let index = this[type] && this[type][event] && this[type][event].indexOf(listener);
for (let type of ['listeners', 'onceListeners']) {
let index = this._observable[type][event] && this._observable[type][event].indexOf(listener);
if (index) {
this[type][event].splice(index, 1);
this._observable[type][event].splice(index, 1);
}
}
}
once(event, listener) {
this._addListener('_onceListeners', event, listener);
}
bindSocketClient(socket) {
// also send events with sockets
this._socketClient = socket;
}
bindSocketServer(socket) {
// also send events with sockets
this._socketServer = socket;
this._addListener('onceListeners', event, listener);
}
async trigger(event, params, throttle=false) {
@ -45,38 +39,58 @@ module.exports = class Observable {
}
async _executeTriggers(event, params) {
await this._triggerEvent('_listeners', event, params);
await this._triggerEvent('_onceListeners', event, params);
let response = await this._triggerEvent('listeners', event, params);
if (response === false) return false;
if (this._socketServer) {
this._socketServer.emit(event, params);
response = await this._triggerEvent('onceListeners', event, params);
if (response === false) return false;
// emit via socket
if (this._observable.socketServer) {
this._observable.socketServer.emit(event, params);
}
// clear once-listeners
if (this._onceListeners && this._onceListeners[event]) {
delete this._onceListeners[event];
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._isHot[event]) {
if (this._observable.isHot[event]) {
// hot, add to queue
if (!this._eventQueue[event]) this._eventQueue[event] = [];
this._eventQueue[event].push(params);
if (!this._observable.eventQueue[event]) this._observable.eventQueue[event] = [];
this._observable.eventQueue[event].push(params);
// aleady hot, quit
return true;
}
this._isHot[event] = true;
this._observable.isHot[event] = true;
// cool-off
setTimeout(() => {
this._isHot[event] = false;
this._observable.isHot[event] = false;
// flush queue
if (this._eventQueue[event]) {
let _queuedParams = this._eventQueue[event];
this._eventQueue[event] = null;
if (this._observable.eventQueue[event]) {
let _queuedParams = this._observable.eventQueue[event];
this._observable.eventQueue[event] = null;
this._executeTriggers(event, _queuedParams);
}
}, throttle);
@ -84,26 +98,18 @@ module.exports = class Observable {
return false;
}
_addListener(name, event, listener) {
if (!this[name]) {
this[name] = {};
_addListener(type, event, listener) {
if (!this._observable[type][event]) {
this._observable[type][event] = [];
}
if (!this[name][event]) {
this[name][event] = [];
}
this[name][event].push(listener);
this._observable[type][event].push(listener);
}
async _triggerEvent(name, event, params) {
if (this[name] && this[name][event]) {
for (let listener of this[name][event]) {
async _triggerEvent(type, event, params) {
if (this._observable[type][event]) {
for (let listener of this._observable[type][event]) {
await listener(params);
}
}
}
clearListeners() {
this._listeners = {};
this._onceListeners = {};
}
}