Question

I have a safari extension popover that needs to communicate with its global page. From a content-script I am using

safari.self.tab.dispatchMessage(name,data); 

to accomplish that. From a popover I didn't find a way to do that. I know that I can access methods in the global page directly

safari.extension.globalPage.contentWindow

but my goal was to reuse code fragments that are already used in content-scripts. I do the same for the chrome version of the plugin.

Is there code for a little clever proxy that emulates

safari.self.tab.dispatchMessage(name,data); 

from the popover?

Was it helpful?

Solution

To be honest it's probably just easier to have different code in your popover and injected scripts. If you really want, you could do something like this:

function dispatchMessage(name, message) {
    if (safari.self.tab) {
        safari.self.tab.dispatchMessage(name, message);
    } else if (safari.extension.globalPage.contentWindow) {
        safari.extension.globalPage.contentWindow.handleMessage({name: name, message: message});
    }
}

Then just use dispatchMessage('foo', 'bar') in both your popover and injected scripts. It's a bit hacky though, because the message event object normally has more information on it than just the name and message, and you have to ensure that your handleMessage function is actually the same function that is assigned as the message event listener in the global page.

OTHER TIPS

A simplistic way to accomplish reusing your message-based content script code in your popover is by wrapping the safari.self.tab.dispatchMessage calls in an abstraction function that I'll describe below...

But first, you need to make sure to have a single named handler function in your global page that handles all messages, like this:

function handleMessage(evt) {
    switch (evt.name) {
        case 'Message1':
            // do something with evt.message
        break;
        case 'Message2':
            // do something else with evt.message
        break;
    }
}

safari.application.addEventListener('message', handleMessage, false);

If you have separate handlers for each different message, or if you're using an anonymous function, this approach will not work.

Now, the wrapper function that goes in your popover and content scripts is very simple:

function tellGlobalPage(msgName, msgData) {
    if (safari.self instanceof SafariExtensionPopover) {
        // this script is running in a popover
        var fakeMsgEvt = { name: msgName, message: msgData };
        safari.extension.globalPage.contentWindow.handleMessage(fakeMsgEvt);
    } else {
        // this script is a content script
        safari.self.tab.dispatchMessage(msgName, msgData);
    }
}

And then instead of safari.self.tab.dispatchMessage(name, data), you use tellGlobalPage(name, data).

Please note that this simplistic approach doesn't deal with roundtrip messaging, where the popover or content script sends a message to the global page, and the global page replies with another message. There are other approaches that can handle that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top