Parcourir la source

feat: add handle dialog block

Ahmad Kholid il y a 3 ans
Parent
commit
c291242cd9

+ 38 - 0
src/background/workflow-engine/blocks-handler/handler-handle-dialog.js

@@ -0,0 +1,38 @@
+import { getBlockConnection, sendDebugCommand } from '../helper';
+
+function handleDialog({ data, outputs }) {
+  const nextBlockId = getBlockConnection({ outputs });
+
+  return new Promise((resolve, reject) => {
+    if (!this.workflow.settings.debugMode) {
+      const error = new Error('not-debug-mode');
+      error.nextBlockId = nextBlockId;
+
+      reject(error);
+      return;
+    }
+
+    this.dialogParams = {
+      accept: data.accept,
+      promptText: data.promptText,
+    };
+
+    const methodName = 'Page.javascriptDialogOpening';
+    if (!this.eventListeners[methodName]) {
+      this.on(methodName, () => {
+        sendDebugCommand(
+          this.activeTab.id,
+          'Page.handleJavaScriptDialog',
+          this.dialogParams
+        );
+      });
+    }
+
+    resolve({
+      data: '',
+      nextBlockId,
+    });
+  });
+}
+
+export default handleDialog;

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

@@ -71,6 +71,13 @@ class WorkflowEngine {
       globalData: parseJSON(globalData, globalData),
     };
 
+    this.onDebugEvent = ({ tabId }, method, params) => {
+      if (tabId !== this.activeTab.id) return;
+
+      (this.eventListeners[method] || []).forEach((listener) => {
+        listener(params);
+      });
+    };
     this.onWorkflowStopped = (id) => {
       if (this.id !== id || this.isDestroyed) return;
       this.stop();
@@ -127,6 +134,10 @@ class WorkflowEngine {
       return;
     }
 
+    if (this.workflow.settings.debugMode) {
+      chrome.debugger.onEvent.addListener(this.onDebugEvent);
+    }
+
     const triggerBlock = Object.values(blocks).find(
       ({ name }) => name === 'trigger'
     );
@@ -249,10 +260,13 @@ class WorkflowEngine {
     try {
       if (this.isDestroyed) return;
       if (this.isUsingProxy) chrome.proxy.settings.clear({});
-      if (this.workflow.settings.debugMode && this.activeTab.id) {
-        await sleep(1000);
+      if (this.workflow.settings.debugMode) {
+        chrome.debugger.onEvent.removeListener(this.onDebugEvent);
 
-        chrome.debugger.detach({ tabId: this.activeTab.id });
+        if (this.activeTab.id) {
+          await sleep(1000);
+          chrome.debugger.detach({ tabId: this.activeTab.id });
+        }
       }
 
       const endedTimestamp = Date.now();

+ 3 - 1
src/background/workflow-engine/helper.js

@@ -9,7 +9,9 @@ export function attachDebugger(tabId, prevTab) {
     if (prevTab && tabId !== prevTab)
       chrome.debugger.detach({ tabId: prevTab });
 
-    chrome.debugger.attach({ tabId }, '1.3', resolve);
+    chrome.debugger.attach({ tabId }, '1.3', () => {
+      chrome.debugger.sendCommand({ tabId }, 'Page.enable', resolve);
+    });
   });
 }
 

+ 44 - 0
src/components/newtab/workflow/edit/EditHandleDialog.vue

@@ -0,0 +1,44 @@
+<template>
+  <div>
+    <ui-textarea
+      :model-value="data.description"
+      class="w-full"
+      :placeholder="t('common.description')"
+      @change="updateData({ description: $event })"
+    />
+    <ui-checkbox
+      :model-value="data.accept"
+      block
+      class="mt-4"
+      @change="updateData({ accept: $event })"
+    >
+      {{ t('workflow.blocks.handle-dialog.accept') }}
+    </ui-checkbox>
+    <ui-input
+      v-if="data.accept"
+      :model-value="data.promptText"
+      :label="t('workflow.blocks.handle-dialog.promptText.label')"
+      :title="t('workflow.blocks.handle-dialog.promptText.description')"
+      placeholder="Text"
+      class="w-full mt-1"
+      @change="updateData({ promptText: $event })"
+    />
+  </div>
+</template>
+<script setup>
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+  data: {
+    type: Object,
+    default: () => ({}),
+  },
+});
+const emit = defineEmits(['update:data']);
+
+const { t } = useI18n();
+
+function updateData(value) {
+  emit('update:data', { ...props.data, ...value });
+}
+</script>

+ 18 - 1
src/content/handle-selector.js

@@ -36,8 +36,23 @@ export function waitForSelector({
   });
 }
 
+function scrollIfNeeded(debugMode, element) {
+  if (!debugMode) return;
+
+  const { top, left, bottom, right } = element.getBoundingClientRect();
+  const isInViewport =
+    top >= 0 &&
+    left >= 0 &&
+    bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
+    right <= (window.innerWidth || document.documentElement.clientWidth);
+
+  if (!isInViewport) {
+    element.scrollIntoView();
+  }
+}
+
 export default async function (
-  { data, id, frameSelector },
+  { data, id, frameSelector, debugMode },
   { onSelected, onError, onSuccess, returnElement }
 ) {
   if (!data || !data.selector) {
@@ -94,11 +109,13 @@ export default async function (
       await Promise.allSettled(
         Array.from(element).map((el) => {
           markElement(el, { id, data });
+          scrollIfNeeded(debugMode, el);
           return onSelected(el);
         })
       );
     } else if (element) {
       markElement(element, { id, data });
+      scrollIfNeeded(debugMode, element);
       await onSelected(element);
     }
 

+ 2 - 0
src/lib/v-remixicon.js

@@ -4,6 +4,7 @@ import {
   riH2,
   riLinkM,
   riTwitterLine,
+  riChat3Line,
   riDiscordLine,
   riEarthLine,
   riClipboardLine,
@@ -106,6 +107,7 @@ export const icons = {
   riH2,
   riLinkM,
   riTwitterLine,
+  riChat3Line,
   riDiscordLine,
   riEarthLine,
   riClipboardLine,

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

@@ -41,6 +41,15 @@
           "timeout": "Selector timeout (ms)"
         }
       },
+      "handle-dialog": {
+        "name": "Handle dialog",
+        "description": "Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).",
+        "accept": "Accept dialog",
+        "promptText": {
+          "label": "Prompt text",
+          "description": "The text to enter into the dialog prompt before accepting"
+        }
+      },
       "insert-data": {
         "name": "Insert data",
         "description": "Insert data into table or variable"

+ 19 - 0
src/utils/shared.js

@@ -746,6 +746,25 @@ export const tasks = {
       multiple: false,
     },
   },
+  'handle-dialog': {
+    name: 'Handle dialog',
+    description:
+      'Accepts or dismisses a JavaScript initiated dialog (alert, confirm, prompt, or onbeforeunload).',
+    icon: 'riChat3Line',
+    component: 'BlockBasic',
+    editComponent: 'EditHandleDialog',
+    category: 'browser',
+    inputs: 1,
+    outputs: 1,
+    allowedInputs: true,
+    maxConnection: 1,
+    refDataKeys: ['promptText'],
+    data: {
+      description: '',
+      accept: true,
+      promptText: '',
+    },
+  },
 };
 
 export const categories = {

+ 20 - 0
test.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <title>Dialog</title>
+</head>
+<body>
+  <script type="text/javascript">
+    setTimeout(() => {
+      alert('anu');
+    }, 2000);
+  </script>
+  <style type="text/css">
+    html {
+      background-color: black;
+    }
+  </style>
+</body>
+</html>