Safari Web Extension - Injecting Script Only When Extension Button Is Clicked

Safari Web Extension - injecting script only when extension button is clicked

Oh that's so weird. I got it so late that, I have to include background script key in manifest.json besides 'content_script' key.

"background" : {
"scripts" : [
"bundle.js"
]
},
"content_scripts": [{
"js": [ "init.bundled.js" ],
"matches": [ "<all_urls>" ]
}]

I already have chrome.browserAction.onClicked... method written inside bundle.js which is being called everytime I press extension button from Safari toolbar.

Whew.

Safari Extension: How do you inject content scripts only after a toolbar button is clicked?

You can use the following four methods to conditionally inject content into pages:

safari.extension.addContentScript
safari.extension.addContentScriptFromURL
safari.extension.addContentStyleSheet
safari.extension.addContentStyleSheetFromURL

Documentation here.

However, note that these methods will not inject content into any already existing tabs at the time you call them. Therefore, they may not be suitable for your use case. You could use one of these methods and then reload the tab, but you may not want that because of the jarring user experience.

Instead, you may need to use a technique like this: Have a very lightweight content script that gets injected into every page, whose only job is to listen for messages from the extension's global page and, when instructed, to create the appropriate <script> and <style> or <link> elements for the content you want to inject. Then, when your toolbar button is clicked, have the global page pass the appropriate message to the content script, perhaps including the URLs of the desired content.

A drawback of this approach is that the injected scripts (the ones you add by creating <script> tags) will not be able to communicate directly with the global page or with other parts of the extension. If you need them to communicate, they will need to do so using window.postMessage or some other technique.

Here's a minimal example. Assume your extension has a toolbar item that issues the command "inject-content".

In the global page:

safari.application.addEventListener('command', function (evt) {
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage(evt.command);
}, false);

In the always-injected content script:

safari.self.addEventListener('message', function (evt) {
if (evt.name == 'inject-content') {
var myScriptTag = document.createElement('script');
myScriptTag.src = safari.extension.baseURI + 'my_script.js';
document.body.appendChild(myScriptTag);
}
}, false);

How is injected content by a Safari extension supposed to work?

Sounds like maybe you didn't select your injected script under the Injected Extension Content heading of the Extension Builder. If you did, then try restarting Safari and reloading the extension.

Injected Javascript from Safari App Extension stops working once I make any modification

Figured this out: we have to clean the build every time the script is modified. Then the extension debug run works again. Cleaning also works if we modified the info.plist and get code signing errors in debug runs.

Inject dynamic script to each tab onLoad in Safari Extension

See addContentScript() and addContentScriptFromURL().

How to write safari extension that gets the url being clicked on when opening context menu?

event.target is a SafariExtensionContextMenuItem, not the page element you are expecting. To get access to the page contents, you will need to use an injected script:

global.js

safari.application.addEventListener('command', handleCommand, false);

function handleCommand(event) {
if(event.command === 'geturl') {
var link = event.userInfo;
if (link) {
safari.application.openBrowserWindow().activeTab.url = link;
}
}
}

injected.js

document.addEventListener('contextmenu', handleContextMenu, false);

function handleContextMenu(event) {
var target = event.target;
while(target != null && target.nodeType == Node.ELEMENT_NODE && target.nodeName.toLowerCase() != "a") {
target = target.parentNode;
}
safari.self.tab.setContextMenuEventUserInfo(event, target.href);
}

Safari Extension - Message

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.



Related Topics



Leave a reply



Submit