Browse Source

feat: add "execute every new tab" option on javascript block

Ahmad Kholid 3 years ago
parent
commit
2827e8854b

+ 2 - 2
package.json

@@ -23,8 +23,8 @@
   },
   "dependencies": {
     "@codemirror/basic-setup": "^0.19.1",
-    "@codemirror/lang-javascript": "0.19.1",
-    "@codemirror/lang-json": "^0.19.1",
+    "@codemirror/lang-javascript": "^0.19.7",
+    "@codemirror/lang-json": "^0.19.2",
     "@codemirror/theme-one-dark": "^0.19.1",
     "@medv/finder": "^2.1.0",
     "@tiptap/extension-character-count": "^2.0.0-beta.24",

+ 7 - 0
src/background/workflow-engine/blocks-handler/handler-active-tab.js

@@ -40,6 +40,13 @@ async function activeTab(block) {
     };
     this.windowId = tab.windowId;
 
+    if (this.preloadScripts.length > 0) {
+      const preloadScripts = this.preloadScripts.map((script) =>
+        this._sendMessageToTab(script)
+      );
+      await Promise.allSettled(preloadScripts);
+    }
+
     return data;
   } catch (error) {
     console.error(error);

+ 2 - 29
src/background/workflow-engine/blocks-handler/handler-interaction-block.js

@@ -24,24 +24,13 @@ async function checkAccess(blockName) {
   return true;
 }
 
-async function interactionHandler(block, { refData }) {
+async function interactionHandler(block) {
   await checkAccess(block.name);
 
-  const { executedBlockOnWeb, debugMode } = this.workflow.settings;
-
   const nextBlockId = getBlockConnection(block);
-  const messagePayload = {
-    ...block,
-    debugMode,
-    executedBlockOnWeb,
-    activeTabId: this.activeTab.id,
-    frameSelector: this.frameSelector,
-  };
-
-  if (block.name === 'javascript-code') messagePayload.refData = refData;
 
   try {
-    const data = await this._sendMessageToTab(messagePayload, {
+    const data = await this._sendMessageToTab(block, {
       frameId: this.activeTab.frameId || 0,
     });
 
@@ -78,22 +67,6 @@ async function interactionHandler(block, { refData }) {
       this.referenceData.variables[block.data.variableName] = data;
     }
 
-    if (block.name === 'javascript-code') {
-      if (data?.variables) {
-        Object.keys(data.variables).forEach((varName) => {
-          this.referenceData.variables[varName] = data.variables[varName];
-        });
-      }
-
-      if (data?.columns.insert) {
-        const params = Array.isArray(data.columns.data)
-          ? data.columns.data
-          : [data.columns.data];
-
-        this.addDataToColumn(params);
-      }
-    }
-
     return {
       data,
       nextBlockId,

+ 50 - 0
src/background/workflow-engine/blocks-handler/handler-javascript-code.js

@@ -0,0 +1,50 @@
+import { getBlockConnection } from '../helper';
+
+export async function javascriptCode({ outputs, data, ...block }, { refData }) {
+  const nextBlockId = getBlockConnection({ outputs });
+
+  try {
+    if (data.everyNewTab) {
+      const isScriptExist = this.preloadScripts.find(
+        ({ id }) => id === block.id
+      );
+
+      if (!isScriptExist) {
+        this.preloadScripts.push({ ...block, data });
+      }
+    }
+    if (!this.activeTab.id) {
+      if (!data.everyNewTab) {
+        throw new Error('no-tab');
+      } else {
+        return { data: '', nextBlockId };
+      }
+    }
+
+    const result = await this._sendMessageToTab({ ...block, data, refData });
+    console.log(result);
+    if (result?.variables) {
+      Object.keys(result.variables).forEach((varName) => {
+        this.referenceData.variables[varName] = result.variables[varName];
+      });
+    }
+    if (result?.columns.insert) {
+      const params = Array.isArray(result.columns.data)
+        ? result.columns.data
+        : [result.columns.data];
+
+      this.addDataToColumn(params);
+    }
+
+    return {
+      nextBlockId,
+      data: result?.columns.data || {},
+    };
+  } catch (error) {
+    error.nextBlockId = nextBlockId;
+
+    throw error;
+  }
+}
+
+export default javascriptCode;

+ 8 - 1
src/background/workflow-engine/blocks-handler/handler-new-tab.js

@@ -1,10 +1,10 @@
 import browser from 'webextension-polyfill';
+import { isWhitespace, sleep } from '@/utils/helper';
 import {
   getBlockConnection,
   attachDebugger,
   sendDebugCommand,
 } from '../helper';
-import { isWhitespace, sleep } from '@/utils/helper';
 
 async function newTab(block) {
   if (this.windowId) {
@@ -84,6 +84,13 @@ async function newTab(block) {
       chrome.debugger.detach({ tabId: tab.id });
     }
 
+    if (this.preloadScripts.length > 0) {
+      const preloadScripts = this.preloadScripts.map((script) =>
+        this._sendMessageToTab(script)
+      );
+      await Promise.allSettled(preloadScripts);
+    }
+
     return {
       data: url,
       nextBlockId,

+ 7 - 0
src/background/workflow-engine/blocks-handler/handler-switch-tab.js

@@ -41,6 +41,13 @@ export default async function ({ data, outputs }) {
   this.activeTab.url = tab.url;
   this.windowId = tab.windowId;
 
+  if (this.preloadScripts.length > 0) {
+    const preloadScripts = this.preloadScripts.map((script) =>
+      this._sendMessageToTab(script)
+    );
+    await Promise.allSettled(preloadScripts);
+  }
+
   return {
     nextBlockId,
     data: tab.url,

+ 17 - 4
src/background/workflow-engine/engine.js

@@ -1,7 +1,6 @@
 import browser from 'webextension-polyfill';
 import { nanoid } from 'nanoid';
 import { tasks } from '@/utils/shared';
-import { convertData, waitTabLoaded } from './helper';
 import {
   toCamelCase,
   sleep,
@@ -10,6 +9,7 @@ import {
   objectHasKey,
 } from '@/utils/helper';
 import referenceData from '@/utils/reference-data';
+import { convertData, waitTabLoaded } from './helper';
 import executeContentScript from './execute-content-script';
 
 class WorkflowEngine {
@@ -40,6 +40,7 @@ class WorkflowEngine {
     this.history = [];
     this.columnsId = {};
     this.eventListeners = {};
+    this.preloadScripts = [];
     this.columns = { column: { index: 0, name: 'column', type: 'any' } };
 
     let variables = {};
@@ -483,12 +484,24 @@ class WorkflowEngine {
       }
 
       await waitTabLoaded(this.activeTab.id);
-      await executeContentScript(this.activeTab.id, options.frameId || 0);
+      await executeContentScript(
+        this.activeTab.id,
+        this.activeTab.frameId || 0
+      );
 
+      const { executedBlockOnWeb, debugMode } = this.workflow.settings;
+      const messagePayload = {
+        isBlock: true,
+        debugMode,
+        executedBlockOnWeb,
+        activeTabId: this.activeTab.id,
+        frameSelector: this.frameSelector,
+        ...payload,
+      };
       const data = await browser.tabs.sendMessage(
         this.activeTab.id,
-        { isBlock: true, ...payload },
-        options
+        messagePayload,
+        { ...options, frameId: this.activeTab.frameId }
       );
 
       return data;

+ 33 - 20
src/components/newtab/workflow/edit/EditJavascriptCode.vue

@@ -8,6 +8,7 @@
       @change="updateData({ description: $event })"
     />
     <ui-input
+      v-if="!data.everyNewTab"
       :model-value="data.timeout"
       :label="t('workflow.blocks.javascript-code.timeout.placeholder')"
       :title="t('workflow.blocks.javascript-code.timeout.title')"
@@ -24,6 +25,13 @@
       @click="state.showCodeModal = true"
       v-text="data.code"
     />
+    <ui-checkbox
+      :model-value="data.everyNewTab"
+      class="mt-2"
+      @change="updateData({ everyNewTab: $event })"
+    >
+      {{ t('workflow.blocks.javascript-code.everyNewTab') }}
+    </ui-checkbox>
     <ui-modal v-model="state.showCodeModal" content-class="max-w-3xl">
       <template #header>
         <ui-tabs v-model="state.activeTab" class="border-none">
@@ -44,28 +52,30 @@
           <shared-codemirror
             v-model="state.code"
             :extensions="codemirrorExts"
+            :style="{ height: data.everyNewTab ? '100%' : '87%' }"
             class="overflow-auto"
-            style="height: 87%"
           />
-          <p class="mt-1 text-sm">
-            {{ t('workflow.blocks.javascript-code.availabeFuncs') }}
-          </p>
-          <p
-            class="space-x-1 whitespace-nowrap overflow-x-auto overflow-y-hidden pb-1 scroll"
-          >
-            <a
-              v-for="func in availableFuncs"
-              :key="func.id"
-              :href="`https://docs.automa.site/blocks/javascript-code.html#${func.id}`"
-              target="_blank"
-              rel="noopener"
-              class="inline-block"
+          <template v-if="!data.everyNewTab">
+            <p class="mt-1 text-sm">
+              {{ t('workflow.blocks.javascript-code.availabeFuncs') }}
+            </p>
+            <p
+              class="space-x-1 whitespace-nowrap overflow-x-auto overflow-y-hidden pb-1 scroll"
             >
-              <code>
-                {{ func.name }}
-              </code>
-            </a>
-          </p>
+              <a
+                v-for="func in availableFuncs"
+                :key="func.id"
+                :href="`https://docs.automa.site/blocks/javascript-code.html#${func.id}`"
+                target="_blank"
+                rel="noopener"
+                class="inline-block"
+              >
+                <code>
+                  {{ func.name }}
+                </code>
+              </a>
+            </p>
+          </template>
         </ui-tab-panel>
         <ui-tab-panel value="preloadScript">
           <div
@@ -83,7 +93,10 @@
               placeholder="http://example.com/script.js"
               class="flex-1 mr-4"
             />
-            <ui-checkbox v-model="state.preloadScripts[index].removeAfterExec">
+            <ui-checkbox
+              v-if="!data.everyNewTab"
+              v-model="state.preloadScripts[index].removeAfterExec"
+            >
               {{ t('workflow.blocks.javascript-code.removeAfterExec') }}
             </ui-checkbox>
           </div>

+ 40 - 26
src/content/blocks-handler/handler-javascript-code.js

@@ -1,7 +1,7 @@
 import { sendMessage } from '@/utils/message';
 
-function getAutomaScript(blockId) {
-  return `
+function getAutomaScript(blockId, everyNewTab) {
+  const str = `
 function automaSetVariable(name, value) {
   const data = JSON.parse(sessionStorage.getItem('automa--${blockId}')) || null;
 
@@ -43,11 +43,19 @@ function automaRefData(keyword, path = '') {
   return findData(data[keyword], path);
 }
   `;
+
+  if (everyNewTab) return '';
+
+  return str;
 }
 
 function javascriptCode(block) {
-  sessionStorage.setItem(`automa--${block.id}`, JSON.stringify(block.refData));
-  const automaScript = getAutomaScript(block.id);
+  if (!block.data.everyNewTab)
+    sessionStorage.setItem(
+      `automa--${block.id}`,
+      JSON.stringify(block.refData)
+    );
+  const automaScript = getAutomaScript(block.id, block.data.everyNewTab);
 
   return new Promise((resolve, reject) => {
     let documentCtx = document;
@@ -65,10 +73,12 @@ function javascriptCode(block) {
       documentCtx = iframeCtx;
     }
 
-    const isScriptExists = documentCtx.getElementById('automa-custom-js');
     const scriptAttr = `block--${block.id}`;
+    const isScriptExists = documentCtx.querySelector(
+      `.automa-custom-js[${scriptAttr}]`
+    );
 
-    if (isScriptExists && isScriptExists.hasAttribute(scriptAttr)) {
+    if (isScriptExists) {
       resolve('');
       return;
     }
@@ -111,37 +121,41 @@ function javascriptCode(block) {
       }, []);
 
       const script = document.createElement('script');
-      let timeout;
 
       script.setAttribute(scriptAttr, '');
-      script.id = 'automa-custom-js';
+      script.classList.add('automa-custom-js');
       script.innerHTML = `(() => {\n${automaScript} ${block.data.code}\n})()`;
 
-      const cleanUp = (columns = '') => {
-        const storageKey = `automa--${block.id}`;
-        const storageRefData = JSON.parse(sessionStorage.getItem(storageKey));
+      if (!block.data.everyNewTab) {
+        let timeout;
+        const cleanUp = (columns = '') => {
+          const storageKey = `automa--${block.id}`;
+          const storageRefData = JSON.parse(sessionStorage.getItem(storageKey));
 
-        script.remove();
-        preloadScripts.forEach((item) => {
-          if (item.removeAfterExec) item.script.remove();
-        });
+          script.remove();
+          preloadScripts.forEach((item) => {
+            if (item.removeAfterExec) item.script.remove();
+          });
+
+          resolve({ columns, variables: storageRefData?.variables });
+        };
 
-        resolve({ columns, variables: storageRefData?.variables });
-      };
+        window.addEventListener('__automa-next-block__', ({ detail }) => {
+          clearTimeout(timeout);
+          cleanUp(detail || {});
+        });
+        window.addEventListener('__automa-reset-timeout__', () => {
+          clearTimeout(timeout);
 
-      window.addEventListener('__automa-next-block__', ({ detail }) => {
-        clearTimeout(timeout);
-        cleanUp(detail || {});
-      });
-      window.addEventListener('__automa-reset-timeout__', () => {
-        clearTimeout(timeout);
+          timeout = setTimeout(cleanUp, block.data.timeout);
+        });
 
         timeout = setTimeout(cleanUp, block.data.timeout);
-      });
+      } else {
+        resolve();
+      }
 
       documentCtx.body.appendChild(script);
-
-      timeout = setTimeout(cleanUp, block.data.timeout);
     });
   });
 }

+ 1 - 0
src/locales/en/blocks.json

@@ -360,6 +360,7 @@
         "description": "Execute your javascript code in the web page",
         "availabeFuncs": "Available functions:",
         "removeAfterExec": "Remove after block executed",
+        "everyNewTab": "Execute every new tab",
         "modal": {
           "tabs": {
             "code": "JavaScript code",

+ 1 - 0
src/utils/shared.js

@@ -479,6 +479,7 @@ export const tasks = {
       timeout: 20000,
       code: 'console.log("Hello world!");\nautomaNextBlock()',
       preloadScripts: [],
+      everyNewTab: false,
     },
   },
   'trigger-event': {

File diff suppressed because it is too large
+ 393 - 422
yarn.lock


Some files were not shown because too many files changed in this diff