mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-02-23 14:39:32 +08:00
feat(engine): Add debounce option to events.
This commit is contained in:
parent
aa250fc057
commit
003cb0b1ec
@ -18,7 +18,9 @@ import { type } from '@lowdefy/helpers';
|
||||
|
||||
class Events {
|
||||
constructor({ arrayIndices, block, context }) {
|
||||
this.defaultDebounceMs = 300;
|
||||
this.events = {};
|
||||
this.timeouts = {};
|
||||
this.arrayIndices = arrayIndices;
|
||||
this.block = block;
|
||||
this.context = context;
|
||||
@ -35,6 +37,7 @@ class Events {
|
||||
return {
|
||||
actions: (type.isObject(actions) ? actions.try : actions) || [],
|
||||
catchActions: (type.isObject(actions) ? actions.catch : []) || [],
|
||||
debounce: type.isObject(actions) ? actions.debounce : null,
|
||||
history: [],
|
||||
loading: false,
|
||||
};
|
||||
@ -52,37 +55,90 @@ class Events {
|
||||
|
||||
async triggerEvent({ name, event }) {
|
||||
const eventDescription = this.events[name];
|
||||
let result = {
|
||||
blockId: this.block.blockId,
|
||||
event,
|
||||
eventName: name,
|
||||
responses: {},
|
||||
endTimestamp: new Date(),
|
||||
startTimestamp: new Date(),
|
||||
success: true,
|
||||
bounced: false,
|
||||
};
|
||||
// no event
|
||||
if (type.isUndefined(eventDescription)) {
|
||||
return {
|
||||
blockId: this.block.blockId,
|
||||
event,
|
||||
eventName: name,
|
||||
responses: {},
|
||||
endTimestamp: new Date(),
|
||||
startTimestamp: new Date(),
|
||||
success: true,
|
||||
};
|
||||
return result;
|
||||
}
|
||||
eventDescription.loading = true;
|
||||
this.block.update = true;
|
||||
this.context.update();
|
||||
|
||||
const result = await this.context.Actions.callActions({
|
||||
actions: eventDescription.actions,
|
||||
arrayIndices: this.arrayIndices,
|
||||
block: this.block,
|
||||
catchActions: eventDescription.catchActions,
|
||||
event,
|
||||
eventName: name,
|
||||
const actionHandle = async () => {
|
||||
const res = await this.context.Actions.callActions({
|
||||
actions: eventDescription.actions,
|
||||
arrayIndices: this.arrayIndices,
|
||||
block: this.block,
|
||||
catchActions: eventDescription.catchActions,
|
||||
event,
|
||||
eventName: name,
|
||||
});
|
||||
eventDescription.history.unshift(res);
|
||||
this.context.eventLog.unshift(res);
|
||||
eventDescription.loading = false;
|
||||
this.block.update = true;
|
||||
this.context.update();
|
||||
return res;
|
||||
};
|
||||
|
||||
// no debounce
|
||||
if (type.isNone(eventDescription.debounce)) {
|
||||
return await actionHandle();
|
||||
}
|
||||
|
||||
// leading edge: bounce
|
||||
if (this.timeouts[name] && eventDescription.debounce.immediate === true) {
|
||||
result.bounced = true;
|
||||
eventDescription.history.unshift(result);
|
||||
this.context.eventLog.unshift(result);
|
||||
return result;
|
||||
}
|
||||
// leading edge: trigger
|
||||
if (eventDescription.debounce.immediate === true) {
|
||||
this.timeouts[name] = setTimeout(
|
||||
() => {
|
||||
clearTimeout(this.timeouts[name]);
|
||||
this.timeouts[name] = null;
|
||||
},
|
||||
!type.isNone(eventDescription.debounce.ms)
|
||||
? eventDescription.debounce.ms
|
||||
: this.defaultDebounceMs
|
||||
);
|
||||
return actionHandle();
|
||||
}
|
||||
|
||||
// trailing edge
|
||||
if (eventDescription.bouncer) {
|
||||
eventDescription.bouncer();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
const timeout = setTimeout(
|
||||
async () => {
|
||||
const res = await actionHandle();
|
||||
resolve(res);
|
||||
},
|
||||
!type.isNone(eventDescription.debounce.ms)
|
||||
? eventDescription.debounce.ms
|
||||
: this.defaultDebounceMs
|
||||
);
|
||||
|
||||
eventDescription.bouncer = () => {
|
||||
clearTimeout(timeout);
|
||||
result.bounced = true;
|
||||
eventDescription.history.unshift(result);
|
||||
this.context.eventLog.unshift(result);
|
||||
resolve(result);
|
||||
};
|
||||
});
|
||||
|
||||
eventDescription.history.unshift(result);
|
||||
this.context.eventLog.unshift(result);
|
||||
eventDescription.loading = false;
|
||||
this.block.update = true;
|
||||
this.context.update();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,10 +105,11 @@ test('init Events', async () => {
|
||||
const { button } = context.RootBlocks.map;
|
||||
expect(button.Events.events).toEqual({
|
||||
onClick: {
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
catchActions: [],
|
||||
debounce: null,
|
||||
history: [],
|
||||
loading: false,
|
||||
catchActions: [],
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
},
|
||||
});
|
||||
});
|
||||
@ -144,6 +145,7 @@ test('triggerEvent no event defined', async () => {
|
||||
const res = await promise;
|
||||
expect(res).toEqual({
|
||||
blockId: 'button',
|
||||
bounced: false,
|
||||
endTimestamp: { date: 0 },
|
||||
event: undefined,
|
||||
eventName: 'onClick',
|
||||
@ -185,10 +187,11 @@ test('triggerEvent x1', async () => {
|
||||
const promise = button.triggerEvent({ name: 'onClick', event: { x: 1 } });
|
||||
expect(button.Events.events).toEqual({
|
||||
onClick: {
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
catchActions: [],
|
||||
debounce: null,
|
||||
history: [],
|
||||
loading: true,
|
||||
catchActions: [],
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
},
|
||||
});
|
||||
await promise;
|
||||
@ -353,10 +356,11 @@ test('registerEvent then triggerEvent x1', async () => {
|
||||
});
|
||||
expect(button.Events.events).toEqual({
|
||||
onClick: {
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
catchActions: [],
|
||||
debounce: null,
|
||||
history: [],
|
||||
loading: false,
|
||||
catchActions: [],
|
||||
actions: [{ id: 'a', type: 'SetState', params: { a: 'a' } }],
|
||||
},
|
||||
});
|
||||
await button.triggerEvent({ name: 'onClick', event: { x: 1 } });
|
||||
@ -424,6 +428,7 @@ test('triggerEvent skip', async () => {
|
||||
},
|
||||
],
|
||||
"catchActions": Array [],
|
||||
"debounce": null,
|
||||
"history": Array [
|
||||
Object {
|
||||
"blockId": "button",
|
||||
@ -523,6 +528,7 @@ test('triggerEvent skip tests === true', async () => {
|
||||
},
|
||||
],
|
||||
"catchActions": Array [],
|
||||
"debounce": null,
|
||||
"history": Array [
|
||||
Object {
|
||||
"blockId": "button",
|
||||
@ -611,8 +617,8 @@ test('Actions array defaults', async () => {
|
||||
actions: null,
|
||||
});
|
||||
expect(button.Events.events).toEqual({
|
||||
onClick: { actions: [], history: [], loading: false, catchActions: [] },
|
||||
registered: { actions: [], history: [], loading: false, catchActions: [] },
|
||||
onClick: { actions: [], history: [], loading: false, catchActions: [], debounce: null },
|
||||
registered: { actions: [], history: [], loading: false, catchActions: [], debounce: null },
|
||||
});
|
||||
});
|
||||
|
||||
@ -649,7 +655,7 @@ test('Actions try catch array defaults', async () => {
|
||||
});
|
||||
const { button } = context.RootBlocks.map;
|
||||
expect(button.Events.events).toEqual({
|
||||
onClick: { actions: [], history: [], loading: false, catchActions: [] },
|
||||
onClick: { actions: [], history: [], loading: false, catchActions: [], debounce: undefined },
|
||||
});
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user