I have created a Chrome extension that, as part of it's operation, opens a new tab with a specified url.
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "open_new_tab" ) {
chrome.tabs.create({"url": request.url});
}
}
);
(Full code available on GitHub)
This works fine on tabs with webpages, but I cannot get it to work on empty tabs, for example: chrome://apps/ To clarify, if I have a tab open and it is on stackoverflow.com, then when I click on my extension button it opens a new tab loading a generated url. When I am on a new tab, or a tab where the url begins with chrome:// then the extension does not work.
What permissions do I need to include to allow the extension to open in ANY tab? Including new tabs and any chrome:// tab?
Manifest.json:
{
"manifest_version": 2,
"name": "MyMiniCity Checker",
"short_name": "MyMiniCity Checker",
"description": "Checks what your city needs most and redirects the browser accordingly.",
"version": "0.2",
"author":"Richard Parnaby-King",
"homepage_url": "https://github.com/richard-parnaby-king/MyMiniCity-Checker/",
"icons": {
"128": "icon-big.png"
},
"options_page": "options/options.html",
"browser_action": {
"default_icon": "icon.png"
},
"permissions": ["tabs","storage","http://*.myminicity.com/","http://*/*", "https://*/*"],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [ {
"matches": [ "http://*/*", "https://*/*"],
"js": [ "jquery-1.11.3.min.js" ]
}]
}
Background.js:
//When user clicks on button, run script
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, { file: "jquery-1.11.3.min.js" }, function() {
chrome.tabs.executeScript(null, { file: "contentscript.js" });
});
});
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "open_new_tab" ) {
chrome.tabs.create({"url": request.url});
}
}
);
It appears as though the background.js file is not being executed. I suspect this to be a permissions. What permissions do I need in order to run this extension in every tab?
Well, this message is supposed to come from a content script you're trying to inject into the current tab.
The widest permission you can request is "<all_urls>", however, there are still URLs that are excluded from access.
You can only normally access http:, https:, file: and ftp: schemes.
file: scheme requires the user to manually approve the access in chrome://extensions/:
Chrome Web Store URLs are specifically blacklisted from access for security reasons. There is no override.
chrome:// URLs (also called WebUI) are excluded for security reasons. There is a manual override in the flags: chrome://flags/#extensions-on-chrome-urls, but you can never expect it to be there.
There is an exception to the above, chrome://favicon/ URLs are accessible if you declare the exact permission.
All in all, even with the widest permissions you cannot be sure you have access. Check for chrome.runtime.lastError in the callback of executeScript and fail gracefully.
As I was wanting this to run on EVERY page it meant I could not have the code in the content script. I moved all the code into the background script:
chrome.browserAction.onClicked.addListener(function(tab) {
//...
chrome.tabs.create({"url": newTabUrl});
//...
});
So when I click on my button the above code is called, using the enclosed jquery script.
Related
This is the first time I read about writing Firefox extensions.
What I need is obviously only viable via WebExtensions and both a background and a contentscript. I actually only want to write all open tabs as links in a new tab and then File->Save it. Another alternative Idea was to put it into a JSON Object and save that through a dialog, then I probably could even spare the contentscript but I haven't found anything in the API to download a JSON Object via asking the user to download it via Download Dialog.
Whatever. I think I need to communicate with the content-script then.
I tried to run the following example, but it is not working. When I load the manifest file and open the debugger for extensions, it doesn't log anything and nothing has happened except that the variables myPort and portFromCS seem to be declared without any value.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#connection-based_messaging
// manifest.json
{
"manifest_version": 2,
"name": "Save Open Tabs",
"version": "1.0",
"description": "Save my tabs",
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
// content.js
let myPort=browser.runtime.connect({name:"port-from-cs"});
myPort.postMessage({greeting: "hello from content script"});
myPort.onMessage.addListener((m) => {
console.log("In content script, received message from background script: ");
console.log(m.greeting);
});
// background.js
let portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.postMessage({greeting: "hi there content script!"});
portFromCS.onMessage.addListener((m) => {
portFromCS.postMessage({greeting: "In background script, received message from content script:" + m.greeting});
});
}
browser.runtime.onConnect.addListener(connected);
Why doesn't the example work? Maybe wrong URL matching in the manifest file?
I am trying to make a chrome extension that blocks users from accessing sites by redirecting them to the extension's custom HTML block page. The user can then choose to click "Unblock" to exclude the current tab from being checked by the filter.
The extension works as expected. For example, if you try to access https://www.youtube.com/ while "youtube.com" is in the blocked list, it will redirect you to "blocked.html".
However, it seems that the extension only works on the CURRENT TAB that you are working with. If you try to shift click a hyperlink (Which opens the link in a new tab) which leads to https://www.youtube.com, it will redirect to "blocked.html", but Chrome would block the redirect and give you this screen:
Even if you now focus on the tab and press refresh, "blocked.html" still does not load.
I believe this may be because I am missing permissions in my manifest file, however, I looked at the docs for the permissions page and I could not find any relevant permissions I could add.
Thanks in advance.
Note: Interestingly, the yellow error message shown above only appears on pages that have been blocked by chrome. The message is this: "crbug/1173575, non-JS module files deprecated."
Also, if you try to refresh the page, the line number that the message appears becomes higher. (I refreshed a few times and right now it is at VM712:7146). Not sure if this message is related to the error.
manifest.json
"manifest_version": 2,
"background": {
"service_worker": "background.js"
},
"options_page": "options.html",
"permissions": [
"storage",
"activeTab",
"tabs",
"webRequest",
"webRequestBlocking",
"<all_urls>"
],
"page_action": {
"default_popup": "popup.html"
}
blocked.js (Shortened)
// Unblock button redirect
let unblockButton = document.getElementById("unblockButton");
updateOriginalUrl();
chrome.runtime.onMessage.addListener(function update(message) {
updateOriginalUrl();
chrome.runtime.onMessage.removeListener(update);
})
function updateOriginalUrl() {
chrome.storage.sync.get("originalUrl", (result) => {
console.log("Unblock button URL set to: " + result.originalUrl);
unblockButton.addEventListener("click", () => {
location.href = result.originalUrl;
chrome.runtime.sendMessage("exclude")
})
});
}
background.js
chrome.webRequest.onBeforeRequest.addListener((details) => {
console.log("New request detected")
console.log("Request URL: " + details.url);
if(enabled && !excludedTabs.includes(details.tabId)) {
for(let blockedUrl of blockedList) {
if(details.url.includes(blockedUrl)) {
console.log("Match detected, redirecting");
chrome.storage.sync.set( {"originalUrl": details.url}, () => {
chrome.runtime.sendMessage("updateOriginalUrl");
});
return {
redirectUrl: chrome.runtime.getURL("blocked.html")
};
}
}
}
}, {
urls: ["<all_urls>"],
types: ["main_frame"]
}, ["blocking"]);
Thanks #wOxxOm:
Either add blocked.html to web_accessible_resources in manifest.json or switch to using declarativeNetRequest API.
This worked.
I am learning to make chrome extensions. I ran into a problem where context scripts that I want to run, even just alert("test");, are unable to when onload is not activated. This also occurs when you press the back arrow to visit the last visited page. I notice that the url changed, but nothing activates. How do I detect this? If the answer is with service workers, a detailed explanation would be greatly appreciated.
maifest version 2.0
Try using chrome.tabs.onUpdated.addListener((id, change, tab)=>{}). This should run every time the URL changes! Here is a minimalistic example of some code that injects js to a site when the URL changes.
background.js:
// inject code on change
chrome.tabs.onUpdated.addListener((id, change, tab) => {
// inject js file called 'inject.js'
chrome.tabs.executeScript(id, {
file: 'inject.js'
});
});
mainfest version 3.0
You can do it by using chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {}). However, this will actually trigger multiple times when a page URL is changed So you need to add a check for the URL in the changeInfo variable, so it only triggers once!
manifest.json:
{
"name": "URL change detector",
"description": "detect a URL change in a tab, and inject a script to the page!",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"scripting",
"tabs"
],
"host_permissions": [
"http://*/*",
"https://*/*"
],
"background": {
"service_worker": "background.js"
}
}
background.js:
// function that injects code to a specific tab
function injectScript(tabId) {
chrome.scripting.executeScript(
{
target: {tabId: tabId},
files: ['inject.js'],
}
);
}
// adds a listener to tab change
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// check for a URL in the changeInfo parameter (url is only added when it is changed)
if (changeInfo.url) {
// calls the inject function
injectScript(tabId);
}
});
inject.js:
// you can write the code here that you want to inject
alert('Hello world!');
I am trying to create a Chrome extension that, when clicked, opens a new incognito window and performs some DOM action on it. These are the files I'm using:
manifest.json
{
"manifest_version": 2,
"name": "SampleExtension",
"description": "",
"version": "1.0",
"incognito": "spanning",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://www.google.com"],
"js": ["myscript.js"]
}
],
"permissions": [
"tabs",
"activeTab",
"http://www.google.com"
]
}
popup.js
chrome.windows.create({
"url": "http://www.google.com",
"focused": true,
"incognito": true
});
chrome.tabs.executeScript(null, {
"file": "myscript.js",
"run_at": "document_end",
"all_frames": true
});
myscript.js
document.querySelector('a[target]').click();
The extension opens the new window, but my content script doesn't seem to be executing. Any thoughts?
Edit: Added "incognito": "spanning" to the manifest. Still doesn't work, however.
First of all, I understand that you have enabled to run in Incognito Mode. Extensions are disabled by default and, hence, it would not run otherwise.
Secondly, your match pattern needs to end with a slash:
"matches": ["http://www.google.com/"],
Thirdly, Google will redirect you to its https version, hence I would improve the match pattern like this:
"matches": ["*://www.google.com/"],
Still, it didn't work for me as I was redirected to my local Google domain. Hence, I had to do add more:
"matches": [
"*://www.google.com/*",
"*://www.google.com.sg/*"
],
Also, I added the final wildcard, because Google was adding some ?urlParams that I had to match too. And this made it work. Note that I tried with other pages like "*://www.stackoverflow.com/*", and it was easier than Google :)
In case your Google page was just a test, I'd advise to use some less redirected pages to test with.
A final note: I do not think it's possible to use the wildcard for the domain (I tried). However, you can request all the main domains, or request all_pages and then add the logic for Google only on my_script.js to decide whether to execute the action or not. (However, this last piece is not ideal).
Edit post comments:
It seems your function fails because the element is not loaded yet. An easy way to solve this is by doing an interval which checks whether the element is on the page. When it finds it, clicks it and removes the interval.
// Function which clicks element if existing and clears interval after doing it.
var clickLink = function() {
if (document.querySelectorAll('a[target]').length > 0) {
clearInterval(waitAndClick); // stop interval
document.querySelector('a[target]').click(); // click element.
}
}
// Run click function every second, until it clicks it.
var waitAndClick = setInterval(clickLink, 1000);
I am a psychology student and I read papers very often. The university libraries provide the access to the databases but I need to use library search engine and log in every time. Quite annoying. I found a way to avoid jumping around the pages.
Here is the method:
I add "ezp.lib.unimelb.edu.au" to the end of the target database address after I found a paper in Google Scholar, then it will redirect to the library login page.
For example, the paper's address is:
http://www.sciencedirect.com/science/article/pii/S0006899315008550
I modified it as:
http://www.sciencedirect.com.ezp.lib.unimelb.edu.au/science/article/pii/S000689315008550
I want to create a Chrome Extension to finish this job on click (too lazy). I tried for hours but it does not work.
Here is what I have done:
I have three files in a folder:
First file: manifest.json
{
"manifest_version": 2,
"name": "Damn! Take me to the library!",
"description": "This extension automatically adds the 'ezp.lib.unimelb.edu.au' to the browser's address, allowing you to visit the databases bought by the library quickly",
"version": "1.0",
"browser_action": {
"default_icon": "unimelb.png",
"default_title": "Damn! Take me to the library!"
},
"background":{
"scripts":["popup.js"]
},
"permissions": [
"activeTab",
"tabs"
]
}
Second file: popup.js
function getCurrentTabUrlthenChangeIt(callback) {
var queryInfo = {
active: true,
currentWindow: true
};
chrome.tabs.query(queryInfo, function(tabs) {
var tab = tabs[0];
var url = tab.url;
callback(url);
var newurl = url.replace('/',"ezp.lib.unimelb.edu.au/");
window.location.replace(newurl);
});
}
Third file: unimelb.png
When I load this folder into Chrome, it does not work.
It's the first time I use JS, anyone has any suggestions?
Thanks!
You can do this even without clicking. You can use the content script for this URL pattern so that your script gets injected to this page. Then you can send a message to the background script using chrome.runtime.sendMessage() and your listener will create a link you want here and then just reload the tab using chrome.tabs.update() with the new URL.
manifest.json
{
"name": "My extension",
...
"content_scripts": [{
"matches": ["http://www.sciencedirect.com/science/article/pii/*"],
"js": ["content-script.js"]
}],
...
}
content-script.js
chrome.runtime.sendMessage({loadURL: true});
background.js
chrome.runtime.onMessage.addListener(function(message, sender, response) {
if (message.loadURL) {
var newurl = sender.tab.url.replace("/", "ezp.lib.unimelb.edu.au/");
chrome.tabs.update(sender.tab.id, {url: newURL})
}
);
This is my first answer to the StackOverflow Community, I hope it helps.
Instead of making an extension, it would be a lot easier to make a bookmarklet which can be used in any browser...
Right click on the bookmark bar
Choose "Add page..."
Under "Name", enter whatever you want "Journal redirect" or whatever
Under "URL", copy and paste the following code (no spaces)
javascript:(function(){location.href=location.href.replace('sciencedirect.com/','sciencedirect.com/ezp.lib.unimelb.edu.au/');})();
Now when you're on the page, click that bookmark and it'll redirect you.
Update: Try this code in the URL for other domains
javascript:(function(){var%20l=location;l.href=l.origin+l.href.replace(l.origin,'ezp.lib.unimelb.edu.au/');})();
manifest.json
{
"manifest_version": 2,
"name": "Damn! Take me to the library!",
"description": "This extension automatically adds the 'ezp.lib.unimelb.edu.au' to the browser's address, allowing you to visit the databases bought by the library quickly",
"version": "1.0",
"browser_action": {
"default_icon": "unimelb.png",
"default_title": "Damn! Take me to the library!"
},
"background":{
"scripts":["background.js"]
},
"permissions": [
"activeTab",
"tabs"
]
}
background.js
//Wait for click
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {
"file": "popup.js"
}, function(){
"popup.js";
console.log("Script Executed ...");
});
})
popup.js
// Change the url to library when on click
var l=location;l.href=l.origin+l.href.replace(l.origin, '.ezp.lib.unimelb.edu.au');
They work well.
It's so cool to finish the first chrome extension. Thank for the help from Mottie.
Anyone looking to edit the url based on some pattern can use the chrome extension Edit Url by Regex
For example for the scenario in this post, while using the extension, you can provide the regex as http.*/science/ and the value as http://www.sciencedirect.com.ezp.lib.unimelb.edu.au/science/
and click submit. The url will get updated as expected.