I'm creating a Chrome extension that uses key bindings (i.e. will use javascript keydown and keyup event handlers) via a content script. I've hit upon a snag while trying to get this to work with GMail, though.
The the handler function in the following code (content script) seems to trigger only when I chat with someone via GChat:
$(window).bind('keydown', function(e){console.log('yay!');});
Unfortunately, it doesn't seem to activate anywhere else, including when I am trying to send an email. I looked into the GMail webpage source, and it turns out all of the content actually displayed resides in an iFrame with id canvas_frame, so I tried this:
$('#canvas_frame').content().live('keydown', function(e){console.log('yay!');});
and this:
$('#canvas_frame').content().find('body').live('keydown', function(e){
console.log('yay!');
});
Unfortunately, that didn't work either.
My manifest.json looks like this:
{
"name": "extension",
"version": "1.0",
"description": "description",
"background_page": "background.html",
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"css": [],
"js": [
"main.js"
]
}
],
"all_frames": true,
"permissions": [
"http://*/*", "https://*/*"
]
}
I was wondering if anyone had a clue about what was going on, what's the right way to do this with GMail, and if $('#canvas_frame').content().live(...) is the right way to go about it.
Thanks!
Your all_frames parameter is misplaced in manifest, it should be:
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"all_frames": true,
"js": ["main.js"]
}
],
I would approach this problem by injecting content scripts into iframes themselves and doing all key bindings there. Identify URLs of those iframes and inject individual content scripts into each of them. For example:
"content_scripts": [
{
"matches": ["http://gmail.com/*"],
"all_frames": false,
"js": ["main.js"]
},
{
"matches": ["http://gmail.com/iframe1.html"],
"all_frames": true,
"js": ["iframe1.js"]
},
{
"matches": ["http://gmail.com/iframe2.html"],
"all_frames": true,
"js": ["iframe2.js"]
}
],
Related
I have an extension I've developed for Chrome (and Firefox, down the road), but can't get it to work when downloaded from the App Store. I think the problem is the permissions.
It's simple: the extension looks for particular text on a page (say: "dog") and highlights it. Just a simple HTML swap.
The .crx file includes the manifest and the javascript which does the replacement (and works locally). This is packaged with the icon and another version of the manifest (unless I'm doing something wrong here?) and submitted to the store. I tried various permissions (like "activetab") but it didn't work.
The three files are:
manifest.json (sits outside .crx)
{
"name": "[name]",
"version": "[version]",
"description": "[description]",
"manifest_version": 2,
"icons": {
"128": "icon_128.png"
},
"permissions": ["activeTab"],
"content_scripts":
[
{
"matches": ["<all_urls>"],
"all_frames": true,
"js": ["script.js"],
"run_at": "document_end"
}
]
}
manifest.json (sits inside the .crx)
{
"name": "[name]",
"version": "[version]",
"description": "[description]",
"manifest_version": 2,
"author": "[author]",
"permissions": ["activeTab"],
"content_scripts":
[
{
"matches": ["<all_urls>"],
"all_frames": true,
"js": ["script.js"],
"run_at": "document_end"
}
]
}
script.js (sits inside the .crx)
Runs the actual search and replace. Runs without issue locally.
What am I doing wrong? Pulling out my hair.
So this is currently hardcoded in manifest.json
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": [],
"js": ["content-script.js"]
}
],
my question is - is there a way to dynamically launch a content script for a webpage? I am actually waiting for user input in my Chrome extension, to determine which page to use a content script for.
you can create and written regexp as per your requirement
"content_scripts": [
{
"matches": ["regex 1" ,"regexp 2",...."regexp N"],
"css": [],
"js": ["content-script.js"]
}
],
Why don't you just get the current page URL (location.href) and then decide whether you want to run your content script or not?
I think this would be easiest way to do it.
For a test case, I want to try to output the URL for the current tab.
My manifest.json
{
"manifest_version": 2,
"name": "Chrome Extension",
"description": "MyExtension",
"icons": {
"16": "img/favicon.png",
"48": "img/48.png"
},
"version": "0.1",
"background": {
"scripts": ["js/content.js"],
"persistent": false
},
"permissions": [
"tabs", "https://*/*", "http://*/*"
],
"browser_action": {
"default_icon": "img/default_icon.png",
"default_title": "Get URL"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"all_frames": true,
"css": ["css/style.css"]
}],
"short_name": "GetURL"
}
And the code in my content.js
document.addEventListener('DOMContentLoaded', () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
alert(tabs[0].url)
});
});
The problem is that the URL is displayed only for the first current tab, but not for another tab that became active. I tried to changed currentWindow to lastFocusedWindow and to windowId but it did not solve the problem. Tell me what I'm doing wrong?
Make sure to read the extension architecture overview. You don't need a background/event page which is an entirely separate page inside the extension with its own DOM (document and window) not related to the webpage in any way.
You need a content script that runs alongside the webpage and can access its DOM directly.
manifest.json:
"content_scripts": [{
"matches": ["<all_urls>"],
"all_frames": true,
"js": ["js/content.js"],
"css": ["css/style.css"]
}],
content.js:
console.log(location.href);
Here you can write normal JavaScript DOM code and access the webpage.
There's no need for DOMContentLoaded wrapper because the content script is injected by default at document_idle which occurs after document_end event. If you need to run the code at document_end exactly, not later, you can specify it explicitly in manifest.json:
"content_scripts": [{
"matches": ["<all_urls>"],
"all_frames": true,
"run_at": "document_end",
"js": ["js/content.js"],
"css": ["css/style.css"]
}],
P.S. alert is a counter-productive way of displaying information because it blocks the browser UI.
I am working with a chrome extension . I want to inject js script in all tab. I am using this manifest.json :
{
"name": "ABC",
"version": "0.0.1",
"manifest_version": 2,
"background": {
"scripts": [
"src/background/background.min.js"
],
"persistent": true
},
"browser_action": {
"default_icon": "icons/128.png",
"default_title": "ABC",
"default_popup": "src/browser_action/index.html"
},
"permissions": [
"tabs",
"http://*/*",
"https://*/*",
"<all_urls>"
],
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["./src/inject/inject.min.js"],
"css": ["./css/inject.min.css"],
"all_frames": true
}]
}
And my inject.js is like this :
(function() {
console.log("Hello");
});
I am getting all log from all tab except the tab of the chrome setting (eg : chrome://extensions/:id , chrome://history etc).
Am I missing something in manifest.json or chrome disables the feature of injection in settings page ?
Thanks in advance.
Indeed, you can't inject code into chrome:// pages. They contain control elements / code that can modify the browser in ways that an extension is not allowed to.
Chrome resolves this by simply not allowing permissions to be set for chrome:// URLs, and <all_urls> does not include it.
However, you could use Override Pages to replace some of them (well, History page at least) completely.
I did test my google chrome extension with below code in content_scripts:
function test()
{
alert("test");
}
document.addEventListener("DOMContentLoaded", test, false);
Manifest:
{
"name": "Test",
"version": "1.0",
"manifest_version": 2,
"permissions": ["contextMenus", "tabs", "http://*/*", "https://*/*"],
"content_scripts": [{
"all_frames": true,
"js": [ "jquery-1.8.1.min.js","test.js"],
"matches": [ "http://*/*" ],
"run_at": "document_start"
}]
}
It's okay with all webpages such as facebook or microsoft..... after page loaded, a alertbox will popup, except "Google.com" => I accessed into Google.com but there is NO alertbox. I wonder why almost pages are okay except Google.com? So, I need which DOM event to catch after Google.com loaded?
Thank you
Google is always in https, your script is not injected to any https websites since you target only http websites (in your manifest you have: "matches": [ "http://*/*" ],).
Change your manifest to "matches": [ "http://*/*", "https://*/*" ], or "matches": [ "<all_urls>" ],.