diff --git a/src/content/blocksHandler/handlerForms.js b/src/content/blocksHandler/handlerForms.js index 96a62e62..4b649524 100644 --- a/src/content/blocksHandler/handlerForms.js +++ b/src/content/blocksHandler/handlerForms.js @@ -1,6 +1,7 @@ -import { sendMessage } from '@/utils/message'; import handleFormElement from '@/utils/handleFormElement'; +import { sendMessage } from '@/utils/message'; import handleSelector, { markElement } from '../handleSelector'; +import synchronizedLock from '../synchronizedLock'; async function forms(block) { const { data } = block; @@ -24,38 +25,43 @@ async function forms(block) { async function typeText(element) { if (block.debugMode && data.type === 'text-field') { + // get lock + await synchronizedLock.getLock(); element.focus?.(); - if (data.clearValue) { - const backspaceCommands = new Array(element.value?.length ?? 0).fill({ - type: 'rawKeyDown', - unmodifiedText: 'Delete', - text: 'Delete', - windowsVirtualKeyCode: 46, - }); + try { + if (data.clearValue) { + const backspaceCommands = new Array(element.value?.length ?? 0).fill({ + type: 'rawKeyDown', + unmodifiedText: 'Delete', + text: 'Delete', + windowsVirtualKeyCode: 46, + }); + + await sendMessage( + 'debugger:type', + { commands: backspaceCommands, tabId: block.activeTabId, delay: 0 }, + 'background' + ); + } + const commands = data.value.split('').map((char) => ({ + type: 'keyDown', + text: char === '\n' ? '\r' : char, + })); + const typeDelay = +block.data.delay; await sendMessage( 'debugger:type', - { commands: backspaceCommands, tabId: block.activeTabId, delay: 0 }, + { + commands, + tabId: block.activeTabId, + delay: Number.isNaN(typeDelay) ? 0 : typeDelay, + }, 'background' ); + } finally { + synchronizedLock.releaseLock(); } - - const commands = data.value.split('').map((char) => ({ - type: 'keyDown', - text: char === '\n' ? '\r' : char, - })); - const typeDelay = +block.data.delay; - await sendMessage( - 'debugger:type', - { - commands, - tabId: block.activeTabId, - delay: Number.isNaN(typeDelay) ? 0 : typeDelay, - }, - 'background' - ); - return; } diff --git a/src/content/index.js b/src/content/index.js index 3086bb76..0076f2f8 100644 --- a/src/content/index.js +++ b/src/content/index.js @@ -240,19 +240,9 @@ async function messageListener({ data, source }) { automa('content'); - let locked = false; - const queue = []; - browser.runtime.onMessage.addListener(async (data) => { const asyncExecuteBlock = async (block) => { - if (locked) { - return new Promise((resolve, reject) => { - queue.push([block, resolve, reject]); - }); - } - try { - locked = true; const res = await executeBlock(block); return res; } catch (error) { @@ -275,20 +265,11 @@ async function messageListener({ data, source }) { await blocksHandler().loopData(loopBlock); return executeBlock(block); - } finally { - locked = false; } }; if (data.isBlock) { const res = await asyncExecuteBlock(data); - while (queue.length) { - const [block, resolve, reject] = queue.shift(); - requestAnimationFrame(() => { - asyncExecuteBlock(block).then(resolve).catch(reject); - }); - } - return res; } diff --git a/src/content/synchronizedLock.js b/src/content/synchronizedLock.js new file mode 100644 index 00000000..e1b93cdd --- /dev/null +++ b/src/content/synchronizedLock.js @@ -0,0 +1,34 @@ +class SynchronizedLock { + constructor() { + this.lock = false; + this.queue = []; + } + + async getLock(timeout = 10000) { + while (this.lock) { + await new Promise((resolve) => { + this.queue.push(resolve); + setTimeout(() => { + const index = this.queue.indexOf(resolve); + if (index !== -1) { + this.queue.splice(index, 1); + console.warn('SynchronizedLock timeout'); + resolve(); + } + }, timeout); + }); + } + + this.lock = true; + } + + releaseLock() { + this.lock = false; + const resolve = this.queue.shift(); + if (resolve) resolve(); + } +} + +const synchronizedLock = new SynchronizedLock(); + +export default synchronizedLock; diff --git a/src/workflowEngine/WorkflowEngine.js b/src/workflowEngine/WorkflowEngine.js index e606111e..a91da958 100644 --- a/src/workflowEngine/WorkflowEngine.js +++ b/src/workflowEngine/WorkflowEngine.js @@ -481,6 +481,12 @@ class WorkflowEngine { const { table, variables } = this.referenceData; const tableId = this.workflow.connectedTable; + // Merge all table and variables from all workflows + Object.values(this.referenceData.workflow).forEach((data) => { + Object.assign(table, data.table); + Object.assign(variables, data.variables); + }); + await dbStorage.transaction( 'rw', dbStorage.tablesItems, diff --git a/src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js b/src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js index 00662b20..9e249e43 100644 --- a/src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js +++ b/src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js @@ -2,6 +2,7 @@ import browser from 'webextension-polyfill'; import { isWhitespace, parseJSON } from '@/utils/helper'; import decryptFlow, { getWorkflowPass } from '@/utils/decryptFlow'; import convertWorkflowData from '@/utils/convertWorkflowData'; +import { nanoid } from 'nanoid'; import WorkflowEngine from '../WorkflowEngine'; function workflowListener(workflow, options) { @@ -115,14 +116,14 @@ async function executeWorkflow({ id: blockId, data }, { refData }) { this.childWorkflowId = engine.id; }, onDestroyed: (engine) => { - if (data.executeId) { - const { variables, table } = engine.referenceData; - - this.engine.referenceData.workflow[data.executeId] = { - table, - variables, - }; - } + const { variables, table } = engine.referenceData; + + this.engine.referenceData.workflow[ + data.executeId || `${engine.id}-${nanoid(8)}` + ] = { + table, + variables, + }; }, }, states: this.engine.states,