Browse Source

feat(background): add updated tab handler

Ahmad Kholid 3 years ago
parent
commit
9f68dc85de

+ 31 - 23
src/background/blocks-handler.js

@@ -16,33 +16,39 @@ export function trigger(block) {
 }
 
 export function openWebsite(block) {
-  return new Promise((resolve) => {
+  return new Promise((resolve, reject) => {
     browser.tabs
       .create({
         active: true,
         url: block.data.url,
       })
       .then((tab) => {
-        const tabListener = (tabId, changeInfo) => {
-          if (changeInfo.status === 'complete' && tabId === tab.id) {
-            browser.tabs.onUpdated.removeListener(tabListener);
-
-            browser.tabs
-              .executeScript(tabId, {
+        this._listener({
+          name: 'tab-updated',
+          id: tab.id,
+          once: true,
+          callback: async (tabId, changeInfo, deleteListener) => {
+            if (changeInfo.status !== 'complete') return;
+            console.log(changeInfo.status !== 'complete', 'clll');
+            try {
+              await browser.tabs.executeScript(tabId, {
                 file: './contentScript.bundle.js',
-              })
-              .then(() => {
-                this._connectTab(tabId);
-
-                resolve({
-                  nextBlockId: getBlockConnection(block),
-                  data: block.data.url,
-                });
               });
-          }
-        };
 
-        browser.tabs.onUpdated.addListener(tabListener);
+              this.tabId = tabId;
+              this._connectTab(tabId);
+
+              deleteListener();
+
+              resolve({
+                nextBlockId: getBlockConnection(block),
+                data: block.data.url,
+              });
+            } catch (error) {
+              console.error(error);
+            }
+          },
+        });
       })
       .catch((error) => {
         console.error(error, 'nnnaa');
@@ -56,16 +62,18 @@ export function interactionHandler(block) {
     if (!this._connectedTab) return;
 
     this._connectedTab.postMessage(block);
-    this._listenTabMessage(
-      block.name,
-      (data) => {
+    this._listener({
+      name: 'tab-message',
+      id: block.name,
+      once: true,
+      callback: (data) => {
+        this.data.push(data);
         resolve({
           data,
           nextBlockId: getBlockConnection(block),
         });
       },
-      { once: true }
-    );
+    });
   });
 }
 

+ 55 - 16
src/background/workflow-engine.js

@@ -4,7 +4,7 @@ import { toCamelCase } from '@/utils/helper';
 import { tasks } from '@/utils/shared';
 import * as blocksHandler from './blocks-handler';
 
-function tabMessageListenerHandler({ type, data }) {
+function tabMessageHandler({ type, data }) {
   const listener = this.tabMessageListeners[type];
 
   if (listener) {
@@ -13,15 +13,45 @@ function tabMessageListenerHandler({ type, data }) {
     if (listener.once) delete this.tabMessageListeners[type];
   }
 }
-function tabRemovedListener(tabId) {
+function tabRemovedHandler(tabId) {
   if (tabId !== this.tabId) return;
 
-  this.connectedTab?.onMessage.removeListener(this.tabMessageListenerHandler);
+  this.connectedTab?.onMessage.removeListener(this.tabMessageHandler);
   this.connectedTab?.disconnect();
 
   delete this.connectedTab;
   delete this.tabId;
 }
+function tabUpdatedHandler(tabId, changeInfo) {
+  const listener = this.tabUpdatedListeners[tabId];
+
+  if (listener) {
+    listener.callback(tabId, changeInfo, () => {
+      delete this.tabUpdatedListeners[tabId];
+    });
+  } else {
+    if (changeInfo.status !== 'complete') return;
+
+    if (this.tabId === tabId) {
+      this.isPaused = true;
+
+      browser.tabs
+        .executeScript(tabId, {
+          file: './contentScript.bundle.js',
+        })
+        .then(() => {
+          console.log(this.currentBlock);
+          if (this._connectedTab) this._connectTab(this.tabId);
+
+          this.isPaused = false;
+        })
+        .catch((error) => {
+          console.error(error);
+          this.isPaused = false;
+        });
+    }
+  }
+}
 
 class WorkflowEngine {
   constructor(workflow) {
@@ -32,10 +62,13 @@ class WorkflowEngine {
     this.isDestroyed = false;
     this.isPaused = false;
     this.logs = [];
+    this.currentBlock = null;
 
     this.tabMessageListeners = {};
-    this.tabRemovedListener = tabRemovedListener.bind(this);
-    this.tabMessageListenerHandler = tabMessageListenerHandler.bind(this);
+    this.tabUpdatedListeners = {};
+    this.tabMessageHandler = tabMessageHandler.bind(this);
+    this.tabUpdatedHandler = tabUpdatedHandler.bind(this);
+    this.tabRemovedHandler = tabRemovedHandler.bind(this);
   }
 
   init() {
@@ -54,8 +87,9 @@ class WorkflowEngine {
       console.error('A trigger block is required');
       return;
     }
-    /* to do: pause if website is loading and inject content-script */
-    browser.tabs.onRemoved.addListener(this.tabRemovedListener);
+
+    browser.tabs.onUpdated.addListener(this.tabUpdatedHandler);
+    browser.tabs.onRemoved.addListener(this.tabRemovedHandler);
 
     this.blocks = blocks;
     this.blocksArr = blocksArr;
@@ -65,7 +99,7 @@ class WorkflowEngine {
 
   destroy() {
     // save log
-    browser.tabs.onRemoved.removeListener(this.tabRemovedListener);
+    browser.tabs.onRemoved.removeListener(this.tabRemovedHandler);
 
     this.isDestroyed = true;
   }
@@ -86,6 +120,9 @@ class WorkflowEngine {
       return;
     }
     console.log(`${block.name}:`, block);
+
+    this.currentBlock = block;
+
     const isInteraction = tasks[block.name].category === 'interaction';
     const handlerName = isInteraction
       ? 'interactionHandler'
@@ -99,7 +136,7 @@ class WorkflowEngine {
           if (result.nextBlockId) {
             this._blockHandler(this.blocks[result.nextBlockId], result.data);
           } else {
-            console.log('Done');
+            console.log('Done', this);
           }
         })
         .catch((error) => {
@@ -116,14 +153,12 @@ class WorkflowEngine {
     });
 
     if (this.connectedTab) {
-      this.connectedTab.onMessage.removeListener(
-        this.tabMessageListenerHandler
-      );
+      this.connectedTab.onMessage.removeListener(this.tabMessageHandler);
       this.connectedTab.disconnect();
     }
 
     console.log('===Message Listener===');
-    connectedTab.onMessage.addListener(this.tabMessageListenerHandler);
+    connectedTab.onMessage.addListener(this.tabMessageHandler);
 
     this.connectedTab = connectedTab;
     this.tabId = tabId;
@@ -131,11 +166,15 @@ class WorkflowEngine {
     return connectedTab;
   }
 
-  _listenTabMessage(name, callback, options = { once: false }) {
-    this.tabMessageListeners[name] = { callback, ...options };
+  _listener({ id, name, callback, once = true }) {
+    const listenerNames = {
+      'tab-updated': 'tabUpdatedListeners',
+      'tab-message': 'tabMessageListeners',
+    };
+    this[listenerNames[name]][id] = { callback, once };
 
     return () => {
-      delete this.tabMessageListeners[name];
+      delete this.tabMessageListeners[id];
     };
   }
 

+ 20 - 12
src/content/index.js

@@ -2,16 +2,24 @@ import browser from 'webextension-polyfill';
 import { toCamelCase } from '@/utils/helper';
 import * as blocksHandler from './blocks-handler';
 
-browser.runtime.onConnect.addListener((port) => {
-  port.onMessage.addListener((data) => {
-    const handler = blocksHandler[toCamelCase(data.name)];
-    console.log(`${data.name}(${toCamelCase(data.name)}):`, data);
-    if (handler) {
-      handler(data).then((result) => {
-        port.postMessage({ type: data.name, data: result });
-      });
-    } else {
-      console.error(`"${data.name}" doesn't have a handler`);
-    }
+console.log('===Content Script===');
+
+function onConnectListener() {
+  browser.runtime.onConnect.addListener((port) => {
+    console.log('Connect');
+    port.onMessage.addListener((data) => {
+      const handler = blocksHandler[toCamelCase(data.name)];
+      console.log(`${data.name}(${toCamelCase(data.name)}):`, data);
+      if (handler) {
+        handler(data).then((result) => {
+          port.postMessage({ type: data.name, data: result });
+        });
+      } else {
+        console.error(`"${data.name}" doesn't have a handler`);
+      }
+    });
   });
-});
+}
+
+if (document.readyState === 'complete') onConnectListener();
+else window.addEventListener('load', onConnectListener);

+ 0 - 2
src/utils/handle-form-element.js

@@ -41,13 +41,11 @@ export default function (element, data, callback) {
   const textFields = ['INPUT', 'TEXTAREA'];
 
   if (data.type === 'text-field' && textFields.includes(element.tagName)) {
-    console.log('inputtt');
     inputText({ data, element, callback });
     return;
   }
 
   if (data.type === 'checkbox' || data.type === 'radio') {
-    console.log('checkbox|radio', data.selected);
     element.checked = data.selected;
     formEvent(element, { type: data.type, value: data.selected });
     callback();

+ 2 - 0
src/utils/shared.js

@@ -1,3 +1,5 @@
+/* link, tab loaded, and close tab block? */
+
 export const tasks = {
   trigger: {
     name: 'Trigger',