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

feat: error when element is not found

Ahmad Kholid 3 жил өмнө
parent
commit
cb54d39741

+ 5 - 7
src/background/workflow-engine/blocks-handler/handler-interaction-block.js

@@ -22,13 +22,6 @@ async function interactionHandler(block, prevBlockData) {
     if (block.name === 'link')
       await new Promise((resolve) => setTimeout(resolve, 5000));
 
-    if (data?.isError) {
-      const error = new Error(data.message);
-      error.nextBlockId = nextBlockId;
-
-      throw error;
-    }
-
     if (objectHasKey(block.data, 'dataColumn')) {
       if (!block.data.saveData)
         return {
@@ -58,6 +51,11 @@ async function interactionHandler(block, prevBlockData) {
     };
   } catch (error) {
     error.nextBlockId = nextBlockId;
+    error.data = {
+      name: block.name,
+      selector: block.data.selector,
+    };
+    console.dir(error);
 
     throw error;
   }

+ 16 - 10
src/content/blocks-handler/handler-attribute-value.js

@@ -1,7 +1,7 @@
 import { handleElement } from '../helper';
 
 function attributeValue(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     let result = [];
     const { attributeName, multiple } = block.data;
     const isCheckboxOrRadio = (element) => {
@@ -10,17 +10,23 @@ function attributeValue(block) {
       return ['checkbox', 'radio'].includes(element.getAttribute('type'));
     };
 
-    handleElement(block, (element) => {
-      const value =
-        attributeName === 'checked' && isCheckboxOrRadio(element)
-          ? element.checked
-          : element.getAttribute(attributeName);
+    handleElement(block, {
+      onSelected(element) {
+        const value =
+          attributeName === 'checked' && isCheckboxOrRadio(element)
+            ? element.checked
+            : element.getAttribute(attributeName);
 
-      if (multiple) result.push(value);
-      else result = value;
+        if (multiple) result.push(value);
+        else result = value;
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
+      onSuccess() {
+        resolve(result);
+      },
     });
-
-    resolve(result);
   });
 }
 

+ 20 - 15
src/content/blocks-handler/handler-element-scroll.js

@@ -13,25 +13,30 @@ function elementScroll(block) {
     return currentPos;
   }
 
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     const { data } = block;
     const behavior = data.smooth ? 'smooth' : 'auto';
 
-    handleElement(block, (element) => {
-      if (data.scrollIntoView) {
-        element.scrollIntoView({ behavior, block: 'center' });
-      } else {
-        element.scroll({
-          behavior,
-          top: data.incY ? incScrollPos(element, data) : data.scrollY,
-          left: data.incX ? incScrollPos(element, data, false) : data.scrollX,
-        });
-      }
+    handleElement(block, {
+      onSelected(element) {
+        if (data.scrollIntoView) {
+          element.scrollIntoView({ behavior, block: 'center' });
+        } else {
+          element.scroll({
+            behavior,
+            top: data.incY ? incScrollPos(element, data) : data.scrollY,
+            left: data.incX ? incScrollPos(element, data, false) : data.scrollX,
+          });
+        }
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
+      onSuccess() {
+        window.dispatchEvent(new Event('scroll'));
+        resolve('');
+      },
     });
-
-    window.dispatchEvent(new Event('scroll'));
-
-    resolve('');
   });
 }
 

+ 11 - 3
src/content/blocks-handler/handler-event-click.js

@@ -1,9 +1,17 @@
 import { handleElement } from '../helper';
 
 function eventClick(block) {
-  return new Promise((resolve) => {
-    handleElement(block, (element) => {
-      element.click();
+  return new Promise((resolve, reject) => {
+    handleElement(block, {
+      onSelected(element) {
+        element.click();
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
+      onSuccess() {
+        resolve('');
+      },
     });
 
     resolve('');

+ 8 - 2
src/content/blocks-handler/handler-forms.js

@@ -2,9 +2,15 @@ import { handleElement, markElement } from '../helper';
 import handleFormElement from '@/utils/handle-form-element';
 
 function forms(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     const { data } = block;
-    const elements = handleElement(block, true);
+    const elements = handleElement(block, { returnElement: true });
+
+    if (!elements) {
+      reject(new Error('element-not-found'));
+
+      return;
+    }
 
     if (data.getValue) {
       let result = '';

+ 14 - 8
src/content/blocks-handler/handler-get-text.js

@@ -1,7 +1,7 @@
 import { handleElement } from '../helper';
 
 function getText(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     let regex;
     const { regex: regexData, regexExp, prefixText, suffixText } = block.data;
     const textResult = [];
@@ -10,17 +10,23 @@ function getText(block) {
       regex = new RegExp(regexData, regexExp.join(''));
     }
 
-    handleElement(block, (element) => {
-      let text = element.innerText;
+    handleElement(block, {
+      onSelected(element) {
+        let text = element.innerText;
 
-      if (regex) text = text.match(regex).join(' ');
+        if (regex) text = text.match(regex).join(' ');
 
-      text = (prefixText || '') + text + (suffixText || '');
+        text = (prefixText || '') + text + (suffixText || '');
 
-      textResult.push(text);
+        textResult.push(text);
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
+      onSuccess() {
+        resolve(textResult);
+      },
     });
-
-    resolve(textResult);
   });
 }
 

+ 2 - 2
src/content/blocks-handler/handler-link.js

@@ -1,11 +1,11 @@
 import { markElement } from '../helper';
 
 function link(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     const element = document.querySelector(block.data.selector);
 
     if (!element) {
-      resolve('');
+      reject(new Error('element-not-found'));
       return;
     }
 

+ 9 - 7
src/content/blocks-handler/handler-switch-to.js

@@ -1,10 +1,9 @@
 import { handleElement } from '../helper';
 
 function switchTo(block) {
-  return new Promise((resolve) => {
-    handleElement(
-      block,
-      (element) => {
+  return new Promise((resolve, reject) => {
+    handleElement(block, {
+      onSelected(element) {
         if (element.tagName !== 'IFRAME') {
           resolve('');
           return;
@@ -12,10 +11,13 @@ function switchTo(block) {
 
         resolve({ url: element.src });
       },
-      () => {
+      onSuccess() {
         resolve('');
-      }
-    );
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
+    });
   });
 }
 

+ 11 - 3
src/content/blocks-handler/handler-trigger-event.js

@@ -2,11 +2,19 @@ import { handleElement } from '../helper';
 import simulateEvent from '@/utils/simulate-event';
 
 function triggerEvent(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     const { data } = block;
 
-    handleElement(block, (element) => {
-      simulateEvent(element, data.eventName, data.eventParams);
+    handleElement(block, {
+      onSelected(element) {
+        simulateEvent(element, data.eventName, data.eventParams);
+      },
+      onSuccess() {
+        resolve(data.eventName);
+      },
+      onError() {
+        reject(new Error('element-not-found'));
+      },
     });
 
     resolve(data.eventName);

+ 19 - 8
src/content/helper.js

@@ -8,26 +8,37 @@ export function markElement(el, { id, data }) {
   }
 }
 
-export function handleElement({ data, id }, callback, errCallback) {
+export function handleElement(
+  { data, id },
+  { onSelected, onError, onSuccess, returnElement }
+) {
   if (!data || !data.selector) return null;
 
   try {
     data.blockIdAttr = `block--${id}`;
-    const element = FindElement[data.findBy || 'cssSelector'](data);
 
-    if (typeof callback === 'boolean' && callback) return element;
+    const selectorType = data.findBy || 'cssSelector';
+    const element = FindElement[selectorType](data);
 
-    if (data.multiple && (data.findBy || 'cssSelector') === 'cssSelector') {
+    if (returnElement) return element;
+
+    if (!element) {
+      if (onError) onError();
+
+      return;
+    }
+    console.log(element, onSelected);
+    if (data.multiple && selectorType === 'cssSelector') {
       element.forEach((el) => {
         markElement(el, { id, data });
-        callback(el);
+        onSelected(el);
       });
     } else if (element) {
       markElement(element, { id, data });
-      callback(element);
-    } else if (errCallback) {
-      errCallback();
+      onSelected(element);
     }
+
+    if (onSuccess) onSuccess();
   } catch (error) {
     console.error(error);
   }

+ 6 - 5
src/locales/en/newtab.json

@@ -80,15 +80,16 @@
       "finish": "Finish"
     },
     "messages": {
-      "workflow-disabled": "Workflow is disabled",
-      "stop-timeout": "Workflow is stopped because of timeout",
       "invalid-proxy-host": "Invalid proxy host",
-      "no-iframe-id": "Can't find Frame ID for the iframe element with \"{selector}\" selector",
-      "no-tab": "Can't connect to a tab, use \"New tab\" or \"Active tab\" block before using the \"{name}\" block.",
+      "workflow-disabled": "Workflow is disabled",
       "empty-workflow": "You must select a workflow first",
       "active-tab-removed": "Workflow active tab is removed",
+      "stop-timeout": "Workflow is stopped because of timeout",
       "no-workflow": "Can't find workflow with \"{workflowId}\" ID",
-      "workflow-infinite-loop": "Can't execute the workflow to prevent an infinite loop"
+      "element-not-found": "Can't find an element with \"{selector}\" selector.",
+      "workflow-infinite-loop": "Can't execute the workflow to prevent an infinite loop",
+      "no-iframe-id": "Can't find Frame ID for the iframe element with \"{selector}\" selector",
+      "no-tab": "Can't connect to a tab, use \"New tab\" or \"Active tab\" block before using the \"{name}\" block."
     },
     "description": {
       "text": "{status} on {date} in {duration}",

+ 9 - 3
src/utils/find-element.js

@@ -4,9 +4,15 @@ class FindElement {
       ? `${data.selector.trim()}:not([${data.blockIdAttr}])`
       : data.selector;
 
-    return data.multiple
-      ? document.querySelectorAll(selector)
-      : document.querySelector(selector);
+    if (data.multiple) {
+      const elements = document.querySelectorAll(selector);
+
+      if (elements.length === 0) return null;
+
+      return elements;
+    }
+
+    return document.querySelector(selector);
   }
 
   static xpath(data) {