Browse Source

feat: persist selector when looping through elements

Ahmad Kholid 3 years ago
parent
commit
072e341fa4

+ 8 - 0
src/background/workflowEngine/blocksHandler/handlerLoopBreakpoint.js

@@ -23,6 +23,14 @@ function loopBreakpoint(block, { prevBlockData }) {
         nextBlockId: currentLoop.blockId,
       });
     } else {
+      if (currentLoop.type === 'elements') {
+        const loopElsIndex = this.loopEls.findIndex(
+          ({ blockId }) => blockId === currentLoop.blockId
+        );
+
+        if (loopElsIndex !== -1) this.loopEls.splice(loopElsIndex, 1);
+      }
+
       delete this.loopList[block.data.loopId];
       delete this.engine.referenceData.loopData[block.data.loopId];
 

+ 15 - 3
src/background/workflowEngine/blocksHandler/handlerLoopData.js

@@ -35,16 +35,28 @@ async function loopData({ data, id, outputs }, { refData }) {
           return parseJSON(variableVal, variableVal);
         },
         elements: async () => {
-          const elements = await this._sendMessageToTab({
+          const max = +data.maxLoop || 0;
+          const findBy = isXPath(data.elementSelector)
+            ? 'xpath'
+            : 'cssSelector';
+          const { elements, url, loopId } = await this._sendMessageToTab({
             id,
             name: 'loop-data',
             data: {
+              max,
+              findBy,
               multiple: true,
-              max: +data.maxLoop || 0,
               selector: data.elementSelector,
-              findBy: isXPath(data.elementSelector) ? 'xpath' : 'cssSelector',
             },
           });
+          this.loopEls.push({
+            url,
+            max,
+            loopId,
+            findBy,
+            blockId: id,
+            selector: data.elementSelector,
+          });
 
           return elements;
         },

+ 2 - 0
src/background/workflowEngine/worker.js

@@ -10,6 +10,7 @@ class Worker {
     this.engine = engine;
     this.settings = engine.workflow.settings;
 
+    this.loopEls = [];
     this.loopList = {};
     this.repeatedTasks = {};
     this.preloadScripts = [];
@@ -318,6 +319,7 @@ class Worker {
         isBlock: true,
         debugMode,
         executedBlockOnWeb,
+        loopEls: this.loopEls,
         activeTabId: this.activeTab.id,
         frameSelector: this.frameSelector,
         ...payload,

+ 2 - 2
src/components/newtab/shared/SharedLogsTable.vue

@@ -33,9 +33,9 @@
               countDuration(item.state.startedTimestamp, Date.now())
             }}</span>
           </td>
-          <td title="Executing block">
+          <td title="Executing block" class="text-overflow">
             <ui-spinner color="text-accent" size="20" />
-            <span class="align-middle inline-block ml-3">
+            <span class="align-middle inline-block ml-3 text-overflow">
               {{ t(`workflow.blocks.${item.state.currentBlock[0].name}.name`) }}
             </span>
           </td>

+ 36 - 10
src/content/blocksHandler/handlerLoopData.js

@@ -1,19 +1,11 @@
 import { nanoid } from 'nanoid';
 import handleSelector from '../handleSelector';
 
-export default async function loopElements(block) {
-  const elements = await handleSelector(block);
+function generateLoopSelectors(elements, { max, attrId, frameSelector }) {
   const selectors = [];
-  const attrId = nanoid(5);
-
-  let frameSelector = '';
-
-  if (block.data.$frameSelector) {
-    frameSelector = `${block.data.$frameSelector} |> `;
-  }
 
   elements.forEach((el, index) => {
-    if (block.data.max > 0 && selectors.length - 1 > block.data.max) return;
+    if (max > 0 && selectors.length - 1 > max) return;
 
     const attrName = 'automa-loop';
     const attrValue = `${attrId}--${index}`;
@@ -24,3 +16,37 @@ export default async function loopElements(block) {
 
   return selectors;
 }
+
+export default async function loopElements(block) {
+  const elements = await handleSelector(block);
+  if (!elements) throw new Error('element-not-found');
+
+  let frameSelector = '';
+  if (block.data.$frameSelector) {
+    frameSelector = `${block.data.$frameSelector} |> `;
+  }
+
+  if (block.onlyGenerate) {
+    generateLoopSelectors(elements, {
+      ...block.data,
+      frameSelector,
+      attrId: block.data.loopId,
+    });
+
+    return {};
+  }
+
+  const attrId = nanoid(5);
+  const selectors = generateLoopSelectors(elements, {
+    ...block.data,
+    frameSelector,
+    attrId,
+  });
+  const { origin, pathname } = window.location;
+
+  return {
+    loopId: attrId,
+    elements: selectors,
+    url: origin + pathname,
+  };
+}

+ 30 - 1
src/content/index.js

@@ -150,7 +150,36 @@ function messageListener({ data, source }) {
   browser.runtime.onMessage.addListener((data) => {
     return new Promise((resolve, reject) => {
       if (data.isBlock) {
-        executeBlock(data).then(resolve).catch(reject);
+        executeBlock(data)
+          .then(resolve)
+          .catch((error) => {
+            const elNotFound = error.message === 'element-not-found';
+            const selectLoopItem = data.data?.selector?.includes('automa-loop');
+            if (elNotFound && selectLoopItem) {
+              const findLoopEl = data.loopEls.find(({ url }) =>
+                window.location.href.includes(url)
+              );
+
+              const blockData = { ...data.data, ...findLoopEl, multiple: true };
+              const loopBlock = {
+                ...data,
+                onlyGenerate: true,
+                data: blockData,
+              };
+
+              blocksHandler
+                .loopData(loopBlock)
+                .then(() => {
+                  executeBlock(data).then(resolve).catch(reject);
+                })
+                .catch((blockError) => {
+                  reject(blockError);
+                });
+              return;
+            }
+
+            reject(error);
+          });
       } else {
         switch (data.type) {
           case 'condition-builder':