I'm trying to set a keyboard shortcut to active/deactivate my Chrome extension that I'm developing. The Chrome extension just consists of a "content_script" that runs on certain sites. I want it to fully activate/deactivate the extension, like if I were to disable it via Chrome://extensions.
In my search for answers, I saw a lot of suggestions to add "_execute_browser_action" to my manifest.json, but I think this command requires a listener that needs to be set up in background.js (correct me if I'm wrong). I want to avoid a background.js if possible, as I want to keep this extension short and sweet.
Here is my manifest.json:
{
"manifest_version": 2,
"name": "foo",
"description": "foo",
"version": "0.1.0",
"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+8"
}
}
},
"content_scripts": [{
"js": ["./dist/bundle.js"],
"matches": [ ...certain sites... ]
}],
"icons": {
"16": "/icons/logo16.png",
"32": "/icons/logo32.png",
"48": "/icons/logo48.png",
"128": "/icons/logo128.png"
}
}
With this manifest.json, the shortcut shows up in Chrome://extensions/shortcuts, but the shortcut does nothing. When I press the combination, nothing happens. Even when I refresh the page, reload extension, re-bundle, restart Chrome, etc.
How should I go about adding this keyboard shortcut?
Also, I'm using Babel/Webpack, if that helps.
I ended up solving my own issue. Updating here in case it helps anyone else.
It turns out a background.js was exactly what I was looking for. My background script sets a chrome.storage API field, triggered by browserAction, which my content_script then ingests to toggle it on/off. Then the page is refreshed to update the page html. (Inspiration taken from here)
background.js:
var x = true
enableBrowserAction()
function disableBrowserAction() {
chrome.storage.local.set({enabled: false})
}
function enableBrowserAction() {
chrome.storage.local.set({enabled: true})
}
function updateState() {
if (x == false) {
x = true
enableBrowserAction()
} else {
x = false
disableBrowserAction()
}
chrome.tabs.reload()
}
chrome.browserAction.onClicked.addListener(updateState)
manifest.json (with only the necessary fields):
{
"manifest_version": 2,
"browser_action": {},
"commands": {
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+8"
}
}
},
"permissions": [
"storage"
],
"background": {
"scripts": ["background.js"]
},
"content_scripts": [{
"js": ["./dist/bundle.js"],
"matches": [ ...certain sites... ]
}]
}
content_script (entry for bundle.js):
import ServiceHandler from './ServiceHandler.js'
chrome.storage.local.get('enabled', data => {
if (data.enabled) {
const sh = new ServiceHandler()
sh.execute()
}
})
Related
manifest.json
{
"manifest_version": 2,
"name": "Project",
"description": "Chrome Extension for sending messages",
"version": "1.0",
"browser_action": {
"default_icon": "red_dot.png"
},
"permissions": [
"activeTab",
"https://ajax.googleapis.com/",
"storage"
],
"background" : {
"scripts" : ["background.js"]
},
"content_scripts": [
{
"matches":["https://www.website.com/*"],
"js":["keypress.js", "jquery.js", "js_file.js"],
"run_at": "document_end"
}
]
}
background.js
var running = false
chrome.browserAction.onClicked.addListener(function(tab) {
if (running) {
alert('script is running, turning off');
chrome.browserAction.setIcon({path: "red_dot.png"})
running = false
} else {
alert('script is not running, turning on');
chrome.browserAction.setIcon({path: "green_dot.jpg"})
running = true
}
});
When I click on the icon, I get the popup as expected, but the icon itself isn't changing.
I'm getting this error:
Unchecked runtime.lastError: Icon invalid.
but I don't understand why. The code seems valid.
use this api and carefully enter params specifically path
https://developer.chrome.com/extensions/browserAction#method-setIcon
I have a website that updates automatically when I get a message and sends me a push notification. I am trying to create a chrome extension that can detect when I get that push notification and do something when it happens.
This is what I have so far but it doesn't seem to be outputting to console. Is something wrong or do I need to change something about my manifest?
inject.js
self.addEventListener('push', function(event) {
//I want to do a thing here
if (event.data) {
console.log('This push event has data: ', event.data.text());
} else {
console.log('This push event has no data.');
}
});
manifest.json
{
"name": "Push notifcation detector",
"version": "1.0",
"description": "Do a thing!",
"manifest_version": 2,
"permissions": [
],
"content_scripts": [
{
"matches": [
"https://mywebsite.com/*"
],
"js": [
"./js/inject.js"
],
"all_frames": false,
"run_at": "document_end"
}
],
"web_accessible_resources": [
"images/**/*.png"
],
"browser_action": {
"default_icon": {
"16": "./images/icons/icon.png",
"48": "./images/icons/icon.png"
}
},
"icons": {
"16": "./images/icons/icon.png",
"48": "./images/icons/icon.png",
"128": "./images/icons/icon.png"
}
}
Thanks for any help you can give me!
It looks like you need to run some sort of background page to receive the message. For the dropdowns, as far as I know, Chrome creates and drops the pages when you select and de-select, or when the browser is on the configured page. By default, it's not going to work because the page isn't running constantly.
This may help: https://developer.chrome.com/extensions/background_pages
It is possible if method SetBadgeText don't lose counting numbers? What I am struggling is, when I click on a button and counter start to count numbers after that I'm going to check some other pages, sometimes counting starts from zero, the same thing is when I want to close chrome and open it again. How this is possible to save your actual setBadgeText number in memory and start from latest one without losing it?
background.js
var counter = 0;
chrome.runtime.onMessage.addListener(message => {
if(message === 'clicked') {
counter += 1;
chrome.browserAction.setBadgeText({
text: counter.toString()
});
}
});
content-script.js
document.body.addEventListener('click', e => {
if(e.target.matches('[value="Google Search"]')) {
chrome.runtime.sendMessage('clicked')
}
});
manifest.json
{
"manifest_version": 2,
"name": "Counter",
"version": "1.0",
"content_scripts": [
{
"matches": ["https://*/*"],
"run_at": "document_end",
"js": ["content-script.js"]
}
],
"description": "description",
"background": {
"persistent": false,
"scripts": ["background.js"]
},
"browser_action": {
"default_title": "counter"
}
}
Use the storage API: https://developer.chrome.com/apps/storage
The "sync" storage is synced to any Chrome browser you're logged into. The "local" storage is, uh, local.
Here's how you might integrate the storage API into your example:
// background.js
chrome.runtime.onMessage.addListener(message => {
if(message === 'clicked') {
chrome.storage.local.get('counter', ({counter}) => {
counter += 1;
chrome.browserAction.setBadgeText({
text: counter.toString()
});
chrome.storage.local.set('counter', counter)
})
}
});
You will also need to add the "storage" permission to your manifest:
// manifest.json
{
...
"browser_action": {
"default_title": "counter"
},
permissions: [
"storage"
]
}
I have a toggling function, in background.js: every time a user clicks the icon, if the extension was turned off, it is turned on, and if extension was turned on, is now off, and the icon swaps to reveal which of those states it's in. "image1" revealing that it's turned off and "image2" revealing it's turned on. However, the function only updates icon URL once when clicked, despite the fact that it continually fires from "onclicked" event as evidenced by chrome dev console. Any ideas?
Here is what's in background.js:
var off = true;
function updateIcon() {
if (off == true) {
off = false;
chrome.browserAction.setIcon({path:"image1.png"});
console.log(off);
}
else {
off = true;
chrome.browserAction.setIcon({path:"image2.png"});
console.log(off);
}
return;
}
chrome.browserAction.onClicked.addListener(updateIcon);
updateIcon();
And my manifest.json file:
{
"background": {
"scripts": [ "jquery-3.1.1.min.js", "background.js" ]
},
"browser_action": {
"default_icon": "image1.png"
},
"content_scripts": [ {
"css": [ "style.css" ],
"js": [ "jquery-3.1.1.min.js", "content.js"],
"matches": [ "https://www.facebook.com/*", "http://www.facebook.com/*", "http://facebook.com/*", "https://facebook.com/*"],
"all_frames" : true,
"run_at" : "document_start"
} ],
"icons" : {
"64" : "image1.png",
"64" : "image2.png"
},
"description": "Blah blah blah",
"manifest_version": 2,
"name": "Working Title",
"permissions": [ "activeTab", "https://www.facebook.com/*", "http://www.facebook.com/*" ],
"update_url": "https://clients2.google.com/service/update2/crx",
"version": "1.0",
"web_accessible_resources": [ "images/*.png" ]
}
I don't know if there is something wrong with your browser or your computer, but I tested all the code onto different files and it seems to work fine. Unless there is anything clashing with the background.js from the content.js, it isn't the code that's the problem.
Icons were not the proper size of 128 x 128. Working now. Thx!
I am trying to make a Chrome extension to workaround Steam's annoying URL warning page. See this for example: https://steamcommunity.com/linkfilter/?url=http://67.69.104.76:84/marville/photos/planes/comet-162a.jpg
What I have so far works except when clicking a link would launch Chrome, in which case the Steam notice page is displayed.
Here is the page on webrequest: https://developer.chrome.com/extensions/webRequest
Any idea how I might get this to work at launch too?
background.js
chrome.webRequest.onBeforeRequest.addListener(
function (details) {
var url = details.url;
var host = url.substring(43);
return { redirectUrl: host };
},
{
urls: ["*://steamcommunity.com/linkfilter/*"],
types: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"]
},
["blocking"]
);
manifest.json
{
"manifest_version": 2,
"name": "Steam Link Filter Redirect",
"description": "Bypasses Steam link filtering.",
"version": "1.1",
"background": {"scripts":["background.js"]},
"permissions": [
"webRequest",
"*://steamcommunity.com/linkfilter/*",
"webRequestBlocking"
],
"icons": {
"16": "icon16.png",
"19": "icon19.png",
"48": "icon48.png",
"128": "icon128.png"
}
}
The problem is, of course, that your code executes too late, after onBeforeRequest stage is done for the opening page. I don't think you can work around that.
You probably need to add a fallback mechanism. I suggest adding a content script that is injected in the linkfilter page and changes the page URL to the required one, for example:
"content_scripts": [ {
"matches": ["*://steamcommunity.com/linkfilter/*"],
"js": ["redirect.js"]
} ],
redirect.js:
location.replace(
decodeURIComponent( location.href.replace(/^.*?\?url=/, "") )
);
(I've made it more robust than .substring(43))