Can I determine when to install webextensions firefox addon to a page? - javascript

I wrote a firefox addon use webextensions tech. By default firefox load the addon when the page loaded over. But some pages hava slowly loaded js,like some ads or statistics code, so the addon will not load if I stop the unnecessary page load. Or wait a long time before the addon loaded.
So can I setup the addon loaded time? (example: Before the page loaded)

Check out the run_at option in the content_scripts' manifest options. For example, you may use the following options:
content_scripts": [
{
"js": ["my-script.js"],
"matches": ["https://example.org/"],
"match_about_blank": true,
"run_at": "document_start"
}
]

Related

JavaScript class override for all frames

If an injected JavaScript code modifies Date class
Date = new Proxy(Date, { ...
or
Date.prototype.toString = function() { ...
on the top level of the window/document, would those override changes apply also to all frames and iframes recursively?
If not, is there a way to force it?
No, and there's no way to do it automatically without modifying the source code of the browser.
You'll have to run your code in every frame explicitly by using one of these methods:
Declare a content script that runs in every frame:
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"run_at": "document_start",
"all_frames": true,
"match_about_blank": true
}],
Or add allFrames: true, matchAboutBlank: true to options of chrome.tabs.executeScript.
Or use the nuclear option: chrome.debugger API to attach to the tab and send a CDP command like Page.addScriptToEvaluateOnNewDocument. The downside is that it shows a warning notification on top of every tab.
In cases 1 and 2 the code that overrides the prototypes should be added in page context. Also note that Chrome/Firefox may be unable to run content scripts in certain iframes due to bugs or inherent restrictions, for example iframes with CSP sandbox in Firefox or iframes with src="javascript:..." in Chrome.

Loading libraries for use in a content script

I created a Firefox extension that works, for the most part. I am having a hard time importing jQuery. I have downloaded it locally. I am getting no errors. So, sometimes the extension will work and jQuery will load. Sometimes it won't. Other times I have to reload the page 5 or 6 times to get it to work.
I am not a JavaScript developer and this is my first time attempting an extension. I have Googled and tried a bunch of things with no luck.
Below is my manifest.json
"web_accessible_resources" : ["/jquery-3.2.1.min.js","/jquery.csv.min.js","/ui.js"],
"icons": {
"128": "icon_128px.png",
"48": "icon_48px.png"
},
"browser_action": {
"default_icon": "icon_48px.png"
},
"content_scripts": [
{
"matches": ["https://*****.com/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"permissions":[
"activeTab"
],
"homepage_url": "https://*****.com"
}
content.js
function injectJs(link) {
var scr = document.createElement("script");
scr.type="text/javascript";
scr.src=link;
(document.head || document.body || document.documentElement).appendChild(scr);
}
injectJs(chrome.extension.getURL("/jquery-3.2.1.min.js"));
injectJs(chrome.extension.getURL("/jquery.csv.min.js"));
injectJs(chrome.extension.getURL("/ui.js"));
Normally, you would load jQuery by including it within the js key in your manifest.json content_scripts entry. For example:
"content_scripts": [
{
"matches": ["https://example.com/*"],
"js": ["jquery-3.2.1.min.js", "jquery.csv.min.js", "ui.js", "content.js"]
}
]
Scripts are loaded in the order listed. So, you need to list the libraries which depend on others after the ones they depend upon (e.g. "jquery-3.2.1.min.js" before "jquery.csv.min.js").
What you were doing
The way that you were doing it inserted the scripts into the page context using <script> tags. Such tags are loaded asynchronously. Thus, there was no guarantee that your scripts which depended on jQuery were actually loaded after jQuery. For what you are doing, you don't want to be loading the scripts into the page context, which is separate from the content script context where your content scripts normally run. If you want more information as to how you can do that successfully, you can see my answer to How to sequentially insert scripts into the page context using tags, which has fully functional code to insert multiple dependent libraries into the page context.
Use .tabs.executeScript() to dynamically load scripts when they are not used 100% of the time
However, if you are loading your content script into a large number of pages (e.g. matches being "<all_urls>", *://*/*, etc.), then you should use a manifest.json content_scripts entry to load only the bare minimum needed to show the initial portion of your user interface (i.e. just the static portion seen prior to the user interacting). Only once the user begins interacting with your user interface should you then send a message, using .runtime.sendMessage(), to your background script, received using .runtime.onMessage(), to instruct your background script to inject the rest of the files needed for your complete user interface. You background script would then use .tabs.executeScript() to load the additional scripts you need and, perhaps, tabs.insertCSS() to inject any additional CSS which you may need.
The point of doing the above is to minimize the impact your extension has on the user/browser during the time which the user is not actively using your extension, which is most of the time under most conditions.

Chrome content script not executing on Ember site

I've got a Google Chrome extension which has the following content script syntax in it's manifest.json:
"content_scripts": [
{
"matches": [
"https://example.com/*"
],
"js": ["js/jquery-2.1.1.js", "js/custom.js"],
"run_at": "document_end",
"all_frames": true
}
],
When testing this extension on an Ember site, it runs on initial page load but after changing the page, it does not get injected again.
For non-Ember users, Ember can update the URL and page content without performing an entire page reload which appears to be causing this issue.
Is anyone aware of a work-around for examples like this?
This was fixed by using chrome.WebNavigation.onHistoryStateChanged which fires every time the page updates.

Chrome extension - loading file from localhost to content_scripts

I'm developing Chrome Extension and I need to load a javascript file to content scripts, but that file is being served via webpack-dev-server. So it's approachable only on localhost.
I tried to change my manifest.json:
"content_scripts": [
{
"matches": [
"http://*/*",
"https://*/*"
],
"js": [
"http://localhost:3000/scripts/content_bundle.js"
],
"run_at": "document_end",
"all_frames": false
}
But then I got an error in Chrome Extensions window:
Only local files can be specified in "content_scripts" section.
Solution:
add "permissions": ["http://localhost:3000/scripts/*", "tabs"] to manifest.json
download the script using XMLHttpRequest (there are many examples) in your background script (or better an event page script) when needed
save it in chrome.storage.local or localStorage (so you can load it on every extension start from the storage without redownloading)
inject the script:
add a tabs.onUpdated listener and inject the script using tabs.executeScript
alternatively use declarativeContent API with RequestContentScript action (despite the warning on the doc page it should be actually supported in the Stable channel but of course do some tests first).

Setting the content_script matches at runtime

I'm developing a chrome extension that requires a content_script to add custom controls to a media player. However, I want to allow users to set the domain of the player via an options control panel (for their personal media servers).
It seems like the domain for content scripts has to be set statically in the manifest.json file in the chrome extension. Is there a way to set that programmatically? To achieve something like this:
"content_scripts": [
{
"matches": ["<variable_from_config>"],
"js": ["player.js"],
"run_at": "document_start"
}
]
You can use the new contentScripts.register() API, which does exactly what you want: programmatically registers content scripts.
browser.contentScripts.register({
matches: ['https://your-dynamic-domain.example.com/*'],
js: [{file: 'content.js'}]
});
This API is only available in Firefox but there's a Chrome polyfill you can use.
For that to work, you'll still need permission to the domain you want to register the script on, so you can use optional_permissions in the manifest and chrome.permissions.request to let the user add new domains on demand.
I also wrote some tools to further simplify this for you and for the end user, such as
webext-domain-permission-toggle and webext-dynamic-content-scripts. They will also register your scripts in the next browser launches and allow the user the remove the new permissions and scripts.

Categories

Resources