1
0
Эх сурвалжийг харах

feat: add preload script in javascript block

Ahmad Kholid 3 жил өмнө
parent
commit
6077c29965

+ 4 - 0
src/background/index.js

@@ -110,6 +110,10 @@ chrome.runtime.onInstalled.addListener((details) => {
 
 const message = new MessageListener('background');
 
+message.on('fetch:text', (url) => {
+  return fetch(url).then((response) => response.text());
+});
+
 message.on('get:sender', (_, sender) => {
   return sender;
 });

+ 1 - 1
src/components/block/BlockConditions.vue

@@ -112,7 +112,7 @@ const conditions = {
 
 function getTitle(index) {
   const type = conditions[block.data.conditions[index]?.type] || 'equals';
-  console.log(type, block.data.conditions);
+
   return t(`workflow.blocks.conditions.${type}`);
 }
 function addComparison() {

+ 92 - 37
src/components/newtab/workflow/edit/EditJavascriptCode.vue

@@ -16,47 +16,85 @@
       @change="updateData({ timeout: +$event })"
     />
     <prism-editor
-      v-if="!showCodeModal"
+      v-if="!state.showCodeModal"
       :model-value="data.code"
       :highlight="highlighter('javascript')"
       readonly
       class="p-4 max-h-80"
-      @click="showCodeModal = true"
+      @click="state.showCodeModal = true"
     />
-    <ui-modal
-      v-model="showCodeModal"
-      :title="t('workflow.blocks.javascript-code.modal')"
-      content-class="max-w-3xl"
-    >
-      <prism-editor
-        v-model="code"
-        class="py-4"
-        :highlight="highlighter('javascript')"
-        line-numbers
-        style="height: calc(100vh - 12rem)"
-      />
-      <p class="mt-1">
-        {{ t('workflow.blocks.javascript-code.availabeFuns') }}
-      </p>
-      <p class="space-x-1">
-        <a
-          v-for="func in availableFuncs"
-          :key="func.id"
-          :href="`https://github.com/Kholid060/automa/wiki/Blocks#${func.id}`"
-          target="_blank"
-          rel="noopener"
-          class="inline-block"
-        >
-          <code>
-            {{ func.name }}
-          </code>
-        </a>
-      </p>
+    <ui-modal v-model="state.showCodeModal" content-class="max-w-3xl">
+      <template #header>
+        <ui-tabs v-model="state.activeTab" class="border-none">
+          <ui-tab value="code">
+            {{ t('workflow.blocks.javascript-code.modal.tabs.code') }}
+          </ui-tab>
+          <ui-tab value="preloadScript">
+            {{ t('workflow.blocks.javascript-code.modal.tabs.preloadScript') }}
+          </ui-tab>
+        </ui-tabs>
+      </template>
+      <ui-tab-panels
+        v-model="state.activeTab"
+        class="overflow-auto"
+        style="height: calc(100vh - 9rem)"
+      >
+        <ui-tab-panel value="code" class="h-full">
+          <prism-editor
+            v-model="state.code"
+            :highlight="highlighter('javascript')"
+            line-numbers
+            class="py-4 overflow-auto"
+            style="height: 87%"
+          />
+          <p class="mt-1">
+            {{ t('workflow.blocks.javascript-code.availabeFuncs') }}
+          </p>
+          <p class="space-x-1">
+            <a
+              v-for="func in availableFuncs"
+              :key="func.id"
+              :href="`https://github.com/Kholid060/automa/wiki/Blocks#${func.id}`"
+              target="_blank"
+              rel="noopener"
+              class="inline-block"
+            >
+              <code>
+                {{ func.name }}
+              </code>
+            </a>
+          </p>
+        </ui-tab-panel>
+        <ui-tab-panel value="preloadScript">
+          <div
+            v-for="(script, index) in state.preloadScripts"
+            :key="index"
+            class="flex items-center mt-4"
+          >
+            <v-remixicon
+              name="riDeleteBin7Line"
+              class="mr-2 cursor-pointer"
+              @click="state.preloadScripts.splice(index, 1)"
+            />
+            <ui-input
+              v-model="state.preloadScripts[index].src"
+              placeholder="http://example.com/script.js"
+              class="flex-1 mr-4"
+            />
+            <ui-checkbox v-model="state.preloadScripts[index].removeAfterExec">
+              {{ t('workflow.blocks.javascript-code.removeAfterExec') }}
+            </ui-checkbox>
+          </div>
+          <ui-button variant="accent" class="w-20 mt-4" @click="addScript">
+            {{ t('common.add') }}
+          </ui-button>
+        </ui-tab-panel>
+      </ui-tab-panels>
     </ui-modal>
   </div>
 </template>
 <script setup>
-import { ref, watch } from 'vue';
+import { watch, reactive } from 'vue';
 import { PrismEditor } from 'vue-prism-editor';
 import { useI18n } from 'vue-i18n';
 import { highlighter } from '@/lib/prism';
@@ -77,16 +115,33 @@ const availableFuncs = [
   { name: 'automaResetTimeout', id: 'automaresettimeout' },
 ];
 
-const code = ref(props.data.code);
-const showCodeModal = ref(false);
+const state = reactive({
+  activeTab: 'code',
+  code: `${props.data.code}`,
+  preloadScripts: [...(props.data.preloadScripts || [])],
+  showCodeModal: false,
+});
 
 function updateData(value) {
   emit('update:data', { ...props.data, ...value });
 }
+function addScript() {
+  state.preloadScripts.push({ src: '', removeAfterExec: true });
+}
 
-watch(code, (value) => {
-  updateData({ code: value });
-});
+watch(
+  () => state.code,
+  (value) => {
+    updateData({ code: value });
+  }
+);
+watch(
+  () => state.preloadScripts,
+  (value) => {
+    updateData({ preloadScripts: value });
+  },
+  { deep: true }
+);
 </script>
 <style scoped>
 code {

+ 62 - 20
src/content/blocks-handler.js

@@ -2,6 +2,7 @@
 import simulateEvent from '@/utils/simulate-event';
 import handleFormElement from '@/utils/handle-form-element';
 import { generateJSON } from '@/utils/data-exporter';
+import { sendMessage } from '@/utils/message';
 
 function markElement(el, { id, data }) {
   if (data.markEl) {
@@ -142,32 +143,73 @@ function automaRefData(keyword, path = '') {
       return;
     }
 
-    const script = document.createElement('script');
-    let timeout;
+    const promisePreloadScripts =
+      block.data?.preloadScripts.map(async (item) => {
+        try {
+          const { protocol, pathname } = new URL(item.src);
+          const isValidUrl = /https?/.test(protocol) && /\.js$/.test(pathname);
+
+          if (!isValidUrl) return null;
+
+          const script = await sendMessage(
+            'fetch:text',
+            item.src,
+            'background'
+          );
+          const scriptEl = document.createElement('script');
+
+          scriptEl.type = 'text/javascript';
+          scriptEl.innerHTML = script;
+
+          return {
+            ...item,
+            script: scriptEl,
+          };
+        } catch (error) {
+          return null;
+        }
+      }, []) || [];
 
-    script.setAttribute(scriptAttr, '');
-    script.id = 'automa-custom-js';
-    script.innerHTML = `(() => {\n${automaScript} ${block.data.code}\n})()`;
+    Promise.allSettled(promisePreloadScripts).then((result) => {
+      const preloadScripts = result.reduce((acc, { status, value }) => {
+        if (status !== 'fulfilled' || !value) return acc;
 
-    const cleanUp = (data = '') => {
-      script.remove();
-      sessionStorage.removeItem(`automa--${block.id}`);
-      resolve(data);
-    };
+        acc.push(value);
+        document.body.appendChild(value.script);
 
-    window.addEventListener('__automa-next-block__', ({ detail }) => {
-      clearTimeout(timeout);
-      cleanUp(detail || {});
-    });
-    window.addEventListener('__automa-reset-timeout__', () => {
-      clearTimeout(timeout);
+        return acc;
+      }, []);
 
-      timeout = setTimeout(cleanUp, block.data.timeout);
-    });
+      const script = document.createElement('script');
+      let timeout;
+
+      script.setAttribute(scriptAttr, '');
+      script.id = 'automa-custom-js';
+      script.innerHTML = `(() => {\n${automaScript} ${block.data.code}\n})()`;
+
+      const cleanUp = (data = '') => {
+        script.remove();
+        preloadScripts.forEach((item) => {
+          if (item.removeAfterExec) item.script.remove();
+        });
+        sessionStorage.removeItem(`automa--${block.id}`);
+        resolve(data);
+      };
+
+      window.addEventListener('__automa-next-block__', ({ detail }) => {
+        clearTimeout(timeout);
+        cleanUp(detail || {});
+      });
+      window.addEventListener('__automa-reset-timeout__', () => {
+        clearTimeout(timeout);
 
-    document.body.appendChild(script);
+        timeout = setTimeout(cleanUp, block.data.timeout);
+      });
 
-    timeout = setTimeout(cleanUp, block.data.timeout);
+      document.body.appendChild(script);
+
+      timeout = setTimeout(cleanUp, block.data.timeout);
+    });
   });
 }
 

+ 8 - 2
src/locales/en/blocks.json

@@ -180,8 +180,14 @@
       "javascript-code": {
         "name": "JavaScript code",
         "description": "Execute your javascript code in the web page",
-        "modal": "JavaScript code",
-        "availabeFuns": "Available functions:",
+        "availabeFuncs": "Available functions:",
+        "removeAfterExec": "Remove after block executed",
+        "modal": {
+          "tabs": {
+            "code": "JavaScript code",
+            "preloadScript": "Preload script"
+          }
+        },
         "timeout": {
           "placeholder": "Timeout",
           "title": "Javascript code execution timeout"

+ 7 - 2
src/locales/zh/blocks.json

@@ -174,8 +174,13 @@
       "javascript-code": {
         "name": "JavaScript 代码",
         "description": "在网页中执行你的 javascript 代码",
-        "modal": "JavaScript 代码",
-        "availabeFuns": "可用的函数:",
+        "modal": {
+          "tabs": {
+            "code": "JavaScript 代码",
+            "preloadScript": "Preload script"
+          }
+        },
+        "availabeFuncs": "可用的函数:",
         "timeout": {
           "placeholder": "超时",
           "title": "Javascript代码执行超时"

+ 1 - 0
src/utils/shared.js

@@ -334,6 +334,7 @@ export const tasks = {
       description: '',
       timeout: 10000,
       code: 'console.log("Hello world!")',
+      preloadScripts: [],
     },
   },
   'trigger-event': {