javascriptgoogle-sheetsgoogle-chrome-extensiongoogle-sheets-api

Send event from Google Spreadsheet to a Chrome extension


I previously had a Google Spreadsheet where I was able to send an event with parameters to my Google Chrome extension. It was a bit of a hack but the cell in my spreadsheet had something like this -

=HYPERLINK(CONCATENATE("#gid=12345678&player=", ENCODEURL(C3), "&team=", D3), "chrome")

Clicking on this link would edit the URL of the current tab, and in my Chrome ext I had something like this in my background.js file -

chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
  if (tab.url.match(/google.com\/spreadsheets/g)) {
    console.log(tab.url);
  }
}

This method worked fine for a couple years, but recently Google must've started blocking URL manipulation from within spreadsheets and this broke the message passing hack I had in place. I tried using a content script to place an event listener on the =HYPERLINK() output in the spreadsheet, but Google Spreadsheet outputs the entire DOM onto a canvas so I'm unable to drill down and find the hyperlink element.

Does anyone know of a better workaround for my use case?


Solution

  • The hyperlink container will not be loaded until you hover/click on the relevant cell, it is also removed/added when you switch between sheets.

    So, using a MutationObserver & the Navigation API should work:

    function main(){
        function hyperlinkCallback(e){
            const data = Object.fromEntries(new URLSearchParams(e.currentTarget.hash));
            console.log(data);
        }
    
        const container = document.querySelector('div[id$="static-overlay-container"]');
        const config = {attributes: false, childList: true, subtree: true };
    
        new MutationObserver((mutations, observer) => {
            const hyperlink = container.querySelector('a#docs-linkbubble-link-text');
            if (!hyperlink) return;
    
            observer.disconnect();
            hyperlink.addEventListener('click', hyperlinkCallback);
    
        }).observe(container, config);
    
    }
    
    window.addEventListener('load', () => {
        main();
        window.navigation.addEventListener('navigatesuccess', main);
    })