Thursday, October 29, 2026

How to call a function two time in chrome extension - also click on search and view in function snippets

 menifest.json

{

  "manifest_version": 3,

  "name": "Run Snippet from Right Click",

  "version": "1.0",

  "permissions": [

    "contextMenus",

    "activeTab",

    "scripting","storage"

  ],

  "background": {

    "service_worker": "background.js"

  }

}

bakground.js

// 1. Create the right-click menu item when the extension installs
chrome.runtime.onInstalled.addListener(() => {
  chrome.contextMenus.create({
    id: "runSearchAndViewAutomation",
    title: "Run Search & View Automation",
    contexts: ["all"]
  });
});

// 2. Initial Trigger: User right-clicks and hits the menu item
chrome.contextMenus.onClicked.addListener(async (info, tab) => {
  if (info.menuItemId === "runSearchAndViewAutomation") {
    console.log("Context menu clicked. Starting CALL_ONE...");
    
    // Set state to CALL_TWO *before* the refresh happens
    await chrome.storage.local.set({ extension_step: 'CALL_TWO' });

    // Inject and execute Phase 1
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      func: automatedSearchAndView,
      args: ['CALL_ONE'] 
    });
  }
});

// 3. AUTOMATION ENGINE: Listens for the page refresh to complete
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  // Wait until the page has fully loaded after the refresh
  if (changeInfo.status === 'complete') {
    
    // Check if CALL_ONE left a footprint telling us to run CALL_TWO
    const data = await chrome.storage.local.get('extension_step');
    
    if (data.extension_step === 'CALL_TWO') {
      console.log("Page refresh detected! Automatically triggering CALL_TWO...");
      
      // Clear storage instantly so it doesn't get trapped in an endless loop
      await chrome.storage.local.remove('extension_step');

      // Automatically inject and run Phase 2
      chrome.scripting.executeScript({
        target: { tabId: tabId },
        func: automatedSearchAndView,
        args: ['CALL_TWO']
      });
    }
  }
});

// 4. Core UI runner injected directly onto the webpage
async function automatedSearchAndView(phase) {
    const SEARCH_BUTTON_SELECTOR = '#edit-submit-registration-title';
    const TARGET_ANCHOR_SELECTOR = 'a.view-link';

    const waitForElement = (selector, timeout = 7000) => {
        return new Promise((resolve, reject) => {
            const startTime = Date.now();
            const interval = setInterval(() => {
                const element = document.querySelector(selector);
                if (element) {
                    clearInterval(interval);
                    resolve(element);
                } else if (Date.now() - startTime > timeout) {
                    clearInterval(interval);
                    reject(new Error(`Timeout: "${selector}" not found.`));
                }
            }, 100);
        });
    };

    if (phase === 'CALL_ONE') {
        console.log("Executing CALL_ONE: Clicking search button...");
        const searchButton = document.querySelector(SEARCH_BUTTON_SELECTOR);
        if (!searchButton) {
            console.error("Search button missing from webpage.");
            return;
        }
        searchButton.click();
    } 
    
    else if (phase === 'CALL_TWO') {
        console.log("Executing CALL_TWO: Polling for anchor link...");
        try {
            const viewAnchor = await waitForElement(TARGET_ANCHOR_SELECTOR);
            if (viewAnchor.href && viewAnchor.href !== '#' && !viewAnchor.href.startsWith('javascript:')) {
                window.location.href = viewAnchor.href;
            } else {
                viewAnchor.click();
            }
        } catch (error) {
            console.error(error.message);
        }
    }
}

No comments:

Post a Comment