Search code examples
javascriptsafarisafari-extension

Safari Extension - Message


This is my first Safari extension and thus far I like it quiet a bit. I am trying to add an extension bar that interacts with an injected.js page and toggles items on the pages via the jquery .toggle();

I have been able to load jQuery into the page no issue, however when it comes to sending a message from the extension bar to the injected.js I am falling short. I have spent over 8 hours today reviewing the developer pages on Apple. The only thing I have managed to do is

Extension Bar:

<!DOCTYPE html>
<html>
<head>
    <title>Board Tools</title> <!-- Extension Bar -->
    <script type="text/javascript" src="jQuery.min.js"></script>
    <script type="text/javascript">
        const myGlobal = safari.extension.globalPage.contentWindow;

    function ToggleBoard(){ 
        myGlobal.test();    
    }
</script>

</head>
<body>

    <input type="button" id="board" value="Board Toggle" onClick="ToggleBoard();">

</body>
</html>

Global HTML:

<!DOCTYPE HTML>
<html>
<head>
    <title>global page</title>
    <script type="text/javascript">

        function test() {
            alert("1");
            event.target.page.dispatchMessage("test", "test");
            alert("2");
    }

   </script>
</head>
<body> </body>
</html>

Injected.js:

function test(msgEvent) {
    alert(msgEvent.name);
}
// register for message events
safari.self.addEventListener("message", test, false);

I am able to call the ToggleBoard() function from the extension bar. The ToggleBoard() function can call the test() function from the Global HTML. When the test() function is called on the Global HTML page the fist alert fires, the second does not. I have narrowed it down at least that far. I get the way I am trying to send my message is probably wrong, but that is what is says here: https://developer.apple.com/library/archive/documentation/Tools/Conceptual/SafariExtensionGuide/MessagesandProxies/MessagesandProxies.html#//apple_ref/doc/uid/TP40009977-CH14-SW1

Just to see if it was a mistake on my part or something goofy with the development page I copied the exact code on their page and used just the Global HTML and Injected.js and I still did not get the result I was looking for.

Solved: The answer I selected does apply a lot towards the issue I had. It was not the exact answer per-say but it did, along with the comments help me get my code straightened out. In order to get the various extension components to message properly I needed to set the Extension Remote Access to All, and then add URL patterns to the whitelist. My extension only fires on the pages I wanted and I can use messages.


Solution

  • In your test function in the global page, event does not refer to anything, since the function is not an event handler. If you want to target the active tab, use this instead:

    safari.application.activeBrowserWindow.activeTab.page.dispatchMessage('test, 'test');
    

    If, later, you find you want the extension bar or the global page to respond to messages from an injected script, you can add something like this in either place:

    safari.application.addEventListener('message', function (e) {
        if (e.name === 'whatever') {
            e.target.page.dispatchMessage('foo', 'bar');
        }
    }, false);
    

    If you want to send a message from an injected script to the global page or an extension bar, use safari.self.tab.dispatchMessage and have a "message" event handler in place in the global page or extension bar.