Browse Source

feat: add `automaFetch` function in javascript block

Ahmad Kholid 2 years ago
parent
commit
b2042bb6af

+ 8 - 4
src/background/index.js

@@ -43,14 +43,18 @@ if (browser.notifications && browser.notifications.onClicked) {
 
 const message = new MessageListener('background');
 
+message.on('fetch', ({ type, resource }) => {
+  return fetch(resource.url, resource).then((response) => {
+    if (!response.ok) throw new Error(response.statusText);
+
+    return response[type]();
+  });
+});
 message.on('fetch:text', (url) => {
   return fetch(url).then((response) => response.text());
 });
-message.on('open:dashboard', async (url) => {
-  await BackgroundUtils.openDashboard(url);
 
-  return Promise.resolve(true);
-});
+message.on('open:dashboard', (url) => BackgroundUtils.openDashboard(url));
 message.on('set:active-tab', (tabId) => {
   return browser.tabs.update(tabId, { active: true });
 });

+ 5 - 1
src/components/newtab/workflow/edit/EditJavascriptCode.vue

@@ -57,7 +57,7 @@
         Run before page loaded
       </ui-checkbox>
     </template>
-    <ui-modal v-model="state.showCodeModal" content-class="max-w-3xl">
+    <ui-modal v-model="state.showCodeModal" content-class="max-w-4xl">
       <template #header>
         <ui-tabs v-model="state.activeTab" class="border-none">
           <ui-tab value="code">
@@ -185,6 +185,10 @@ const availableFuncs = [
     name: 'automaSetVariable(name, value)',
     id: 'automasetvariable-name-value',
   },
+  {
+    name: 'automaFetch(type, resource)',
+    id: 'automasetvariable-type-resource',
+  },
   { name: 'automaResetTimeout()', id: 'automaresettimeout' },
 ];
 const autocompleteList = Object.values(automaFuncsSnippets).slice(0, 4);

+ 19 - 1
src/content/index.js

@@ -1,7 +1,8 @@
 import browser from 'webextension-polyfill';
+import { nanoid } from 'nanoid';
 import findSelector from '@/lib/findSelector';
 import { toCamelCase } from '@/utils/helper';
-import { nanoid } from 'nanoid';
+import { sendMessage } from '@/utils/message';
 import automa from '@business';
 import handleSelector from './handleSelector';
 import blocksHandler from './blocksHandler';
@@ -243,6 +244,23 @@ function messageListener({ data, source }) {
   });
 })();
 
+window.addEventListener('__automa-fetch__', (event) => {
+  const { id, resource, type } = event.detail;
+  const sendResponse = (payload) => {
+    window.dispatchEvent(
+      new CustomEvent(`__autom-fetch-response-${id}__`, { detail: payload })
+    );
+  };
+
+  sendMessage('fetch', { type, resource }, 'background')
+    .then((result) => {
+      sendResponse({ isError: false, result });
+    })
+    .catch((error) => {
+      sendResponse({ isError: true, result: error.message });
+    });
+});
+
 window.addEventListener('DOMContentLoaded', async () => {
   const link = window.location.pathname;
   const isAutomaWorkflow = /.+\.automa\.json$/.test(link);

+ 32 - 0
src/newtab/utils/javascriptBlockUtil.js

@@ -1,3 +1,35 @@
+export function automaFetchClient(id, { type, resource }) {
+  return new Promise((resolve, reject) => {
+    const validType = ['text', 'json', 'base64'];
+    if (!type || !validType.includes(type)) {
+      reject(new Error('The "type" must be "text" or "json"'));
+      return;
+    }
+
+    const eventName = `__autom-fetch-response-${id}__`;
+    const eventListener = ({ detail }) => {
+      window.removeEventListener(eventName, eventListener, { once: true });
+
+      if (detail.isError) {
+        reject(new Error(detail.result));
+      } else {
+        resolve(detail.result);
+      }
+    };
+
+    window.addEventListener(eventName, eventListener, { once: true });
+    window.dispatchEvent(
+      new CustomEvent(`__automa-fetch__`, {
+        detail: {
+          id,
+          type,
+          resource,
+        },
+      })
+    );
+  });
+}
+
 export function jsContentHandler($blockData, $preloadScripts, $automaScript) {
   return new Promise((resolve, reject) => {
     try {

+ 12 - 6
src/newtab/workflowEngine/blocksHandler/handlerJavascriptCode.js

@@ -1,14 +1,15 @@
 import { customAlphabet } from 'nanoid/non-secure';
 import browser from 'webextension-polyfill';
 import cloneDeep from 'lodash.clonedeep';
-import { jsContentHandler } from '@/newtab/utils/javascriptBlockUtil';
+import {
+  jsContentHandler,
+  automaFetchClient,
+} from '@/newtab/utils/javascriptBlockUtil';
 import { messageSandbox, automaRefDataStr, waitTabLoaded } from '../helper';
 
 const nanoid = customAlphabet('1234567890abcdef', 5);
 
-function getAutomaScript(refData, everyNewTab) {
-  const varName = `automa${nanoid()}`;
-
+function getAutomaScript(varName, refData, everyNewTab) {
   let str = `
 const ${varName} = ${JSON.stringify(refData)};
 ${automaRefDataStr(varName)}
@@ -20,6 +21,9 @@ function automaNextBlock(data, insert = true) {
 }
 function automaResetTimeout() {
  document.body.dispatchEvent(new CustomEvent('__automa-reset-timeout__'));
+}
+function automaFetch(type, resource) {
+  return (${automaFetchClient.toString()})('${varName}', { type, resource });
 }
   `;
 
@@ -96,10 +100,11 @@ export async function javascriptCode({ outputs, data, ...block }, { refData }) {
     return acc;
   }, []);
 
+  const instanceId = `automa${nanoid()}`;
   const automaScript =
     data.everyNewTab || data.context === 'background'
       ? ''
-      : getAutomaScript(payload.refData, data.everyNewTab);
+      : getAutomaScript(instanceId, payload.refData, data.everyNewTab);
 
   if (data.context !== 'background') {
     await waitTabLoaded({
@@ -110,12 +115,13 @@ export async function javascriptCode({ outputs, data, ...block }, { refData }) {
 
   const result = await (data.context === 'background'
     ? messageSandbox('javascriptBlock', {
+        instanceId,
         preloadScripts,
         refData: payload.refData,
         blockData: cloneDeep(payload.data),
       })
     : executeInWebpage(
-        [payload, preloadScripts, automaScript],
+        [payload, preloadScripts, automaScript, instanceId],
         {
           tabId: this.activeTab.id,
           frameIds: [this.activeTab.frameId || 0],

+ 14 - 0
src/utils/codeEditorAutocomplete.js

@@ -112,6 +112,20 @@ export const automaFuncsSnippets = {
       return container;
     },
   },
+  automaFetch: {
+    label: 'automaFetch',
+    type: 'function',
+    apply: snippet("automaFetch('${json}', { url: '${}' })"),
+    info: () => {
+      const container = document.createElement('div');
+
+      container.innerHTML = `
+        <code>automaFetch(<i>type</i>, <i>resource</i>)</code>
+      `;
+
+      return container;
+    },
+  },
   automaRefData: {
     label: 'automaRefData',
     type: 'function',