Playing around with building a Chrome extension. At the moment I've put together a context menu item. When the context menu item is clicked, it fires itemClicked()
in my background script context_menu.js
:
function itemClicked(info, tab) {
alert("clicked");
}
The alert fires. I can also do stuff like sending ajax requests through itemClicked()
However, I can't append any elements to the page (or DOM manipulation of any sort). Even something as basic as this doesn't work:
var d = document.createElement('div');
d.setAttribute("css", "width: 100px; height: 100px; background-color: red; position: fixed; top: 70px; left: 30px; z-index: 99999999999;");
document.body.appendChild(d);
So I tried to add the same code to a content script:
chrome.contextMenus.onClicked.addListener(function(OnClickData info, tabs.Tab tab) {
//code to append the input here
});
But it still won't work. What am I doing wrong?
How can I get the context menu to append something to the page after clicking?
Thanks so much!
Edit: here is my manifest.json (removed the irrelevant stuff like name/description...etc)
{
"permissions": [
"activeTab",
"tabs",
"cookies",
"contextMenus"
],
"background": {
"scripts": ["context_menu.js"]
},
"browser_action": {
"default_icon": "icon16.png",
"default_css": "popup.css",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["vendor/jquery-1.8.2.min.js", "config.js", "content_script.js"]
}
],
"web_accessible_resources": ["popup.html"]
}
Playing around with building a Chrome extension. At the moment I've put together a context menu item. When the context menu item is clicked, it fires itemClicked()
in my background script context_menu.js
:
function itemClicked(info, tab) {
alert("clicked");
}
The alert fires. I can also do stuff like sending ajax requests through itemClicked()
However, I can't append any elements to the page (or DOM manipulation of any sort). Even something as basic as this doesn't work:
var d = document.createElement('div');
d.setAttribute("css", "width: 100px; height: 100px; background-color: red; position: fixed; top: 70px; left: 30px; z-index: 99999999999;");
document.body.appendChild(d);
So I tried to add the same code to a content script:
chrome.contextMenus.onClicked.addListener(function(OnClickData info, tabs.Tab tab) {
//code to append the input here
});
But it still won't work. What am I doing wrong?
How can I get the context menu to append something to the page after clicking?
Thanks so much!
Edit: here is my manifest.json (removed the irrelevant stuff like name/description...etc)
{
"permissions": [
"activeTab",
"tabs",
"cookies",
"contextMenus"
],
"background": {
"scripts": ["context_menu.js"]
},
"browser_action": {
"default_icon": "icon16.png",
"default_css": "popup.css",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["vendor/jquery-1.8.2.min.js", "config.js", "content_script.js"]
}
],
"web_accessible_resources": ["popup.html"]
}
Share
Improve this question
edited Nov 11, 2013 at 20:58
Michelle
asked Nov 11, 2013 at 20:44
MichelleMichelle
2,7122 gold badges25 silver badges35 bronze badges
4
- Background scripts aren't allowed access to the DOM, so you shouldn't expect that to work. But I'm not seeing why the content script wouldn't accomplish that. Could you post your manifest.json? – Teepeemm Commented Nov 11, 2013 at 20:47
- Instead of having the content script listen for the event, have you tried having the background script inject the necessary code? – Teepeemm Commented Nov 11, 2013 at 21:38
- @Teepeemm that actually works - thanks. Can I inject a content script that won't run unless it is called via executeScript? (from my understanding, content scripts automatically run every time a tab is loaded) – Michelle Commented Nov 11, 2013 at 22:24
- actually the injected content script only worked when I set an alert... It still won't allow for any DOM manipulation :/ – Michelle Commented Nov 11, 2013 at 22:38
1 Answer
Reset to default 20You have probably misunderstood the concept of a background page (and its younger, more resource-friendly and preferred sibling: event page) and that of a content script.
content scripts:
- Are bound to a specific web-page loaded into a tab.
- Live in an isolated world (JS context), but have direct access to the web-pages DOM.
- Can communicate with the background page (see Message Passing).
background pages:
- Are bound to your extension (there is max. 1 background (or event) page for each extension).
- Are always somewhere in the background (event pages "take a nap" from time to time, but you can always wake them up).
- Do not have direct access to any web-page.
- Can communicate with the content scripts (and other views) (see Message Passing).
- Can do cool stuff (because they have access to cool chrome.* APIs).
The chrome.contentMenus API is available only to a background page. Thus, you have to create any context menu and listen for onClicked
events there (in the background page).
Once a context menu has been clicked, you can use Programmatic Injection to inject some code (or a content script) into the active tab's web-page.
Below is the source code of a sample extension that demonstrates this method.
manifest.json:
{
"manifest_version": 2,
"name": "Test Extension",
"version": "0.0",
"background": {
"persistent": false, // <-- let's make it an event page
"scripts": ["background.js"]
},
"permissions": [
"contextMenus",
"activeTab" // <-- here, sufficient for our purpose
]
}
background.js:
/* Create a context-menu */
chrome.contextMenus.create({
id: "myContextMenu", // <-- mandatory with event-pages
title: "Click me",
contexts: ["all"]
});
/* Register a listener for the `onClicked` event */
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if (tab) {
/* Create the code to be injected */
var code = [
'var d = document.createElement("div");',
'd.setAttribute("style", "'
+ 'background-color: red; '
+ 'width: 100px; '
+ 'height: 100px; '
+ 'position: fixed; '
+ 'top: 70px; '
+ 'left: 30px; '
+ 'z-index: 9999; '
+ '");',
'document.body.appendChild(d);'
].join("\n");
/* Inject the code into the current tab */
chrome.tabs.executeScript(tab.id, { code: code });
}
});
(If your injected code is complicated enough, it might be a better idea to inject a .js file. More info on Programmatic Injection.)