This question already has answers here:
Chrome extension - retrieving global variable from webpage
(5 answers)
Hijacking a variable with a userscript for Chrome
(1 answer)
Closed 9 years ago.
I have a Chrome Extension that is trying to find on every browsed URL (and every iframe of every browser URL) if a variable window.my_variable_name exists.
So I wrote this little piece of content script :
function detectVariable(){
if(window.my_variable_name || typeof my_variable_name !== "undefined") return true;
return false;
}
After trying for too long, it seems Content Scripts runs in some sandbox.
Is there a way to access the window element from a Chrome Content Script ?
One thing that is important to know is that Content Scripts share the same DOM as the current page, but they don't share access to variables. The best way of dealing with this case is, from the content script, to inject a script tag into the current DOM that will read the variables in the page.
in manifest.json:
"web_accessible_resources" : ["/js/my_file.js"],
in contentScript.js:
function injectScript(file, node) {
var th = document.getElementsByTagName(node)[0];
var s = document.createElement('script');
s.setAttribute('type', 'text/javascript');
s.setAttribute('src', file);
th.appendChild(s);
}
injectScript( chrome.extension.getURL('/js/my_file.js'), 'body');
in my_file.js:
// Read your variable from here and do stuff with it
console.log(window.my_variable);
Related
This question already has answers here:
How to relink/delink image URLs to point to the full image?
(2 answers)
Closed 7 years ago.
i want to make Greasemonkey script to replace text in html like this:
<img src="http://example.com/image.jpg" data-gifsrc="http://example.com/image.gif">
to
<img src="http://example.com/image.gif">
in website thechive.com
please help me, thanks.
While I cannot find the data-gifsrc attribute on the mentioned website, youi cannot assume the JQuery would be present and available for Greasemonkey.
// attribute name
var attrName='data-gifsrc';
// list all images
var imgs=document.getElementsByTagName("img");
// loop every images
for(var i=0;i<imgs.length;i++) {
// check for attribute
if(imgs[i].attributes[attrName]) {
// set image source
imgs[i].src=imgs[i].attributes[attrName].value;
// remove attribute
imgs[i].attributes.removeNamedItem(attrName);
}
}
This question already has answers here:
Chrome Extension Message passing: response not sent
(3 answers)
Chrome Extension Message Passing [duplicate]
(1 answer)
Closed 8 years ago.
I've got a very odd problem. I have an extension that takes a screenshot of webpages. I created it using this extension as a reference. It works perfectly and the world is happy.
The extension communicates back and forth with a content script and it uses deprecated APIs to do so. In an effort to keep the extension from using outdated code, I went ahead and made the following replacements:
chrome.tabs.sendRequest(...) -> chrome.tabs.sendMessage(...)
chrome.extension.onRequest(...) -> chrome.runtime.onMessage(...)
chrome.extension.sendRequest(...) -> chrome.runtime.sendMessage(...)
Doing that breaks the extension and it no longer works. If I use the deprecated code, it all works fine again.
I did some tracking and discovered that the extension breaks at the following code:
CONTENT SCRIPT
chrome.runtime.sendMessage(sender.id, data, function(captured) {
window.clearTimeout(cleanUpTimeout);
console.log("came back from extension...");
if (captured) {
// Move on to capture next arrangement.
processArrangements(); //function defined elsewhere
} else {
// If there's an error in popup.js, the response value can be
// undefined, so cleanup
cleanUp(); // function defined elsewhere
}
});
EXTENSION
chrome.runtime.onMessage.addListener(function(message, sender, cb){
appendLog("received message from content script. callback is " + cb);
if (message.msg === 'capturePage') {
capturePage(message, sender, cb);
} else {
console.error('Unknown message received from content script: ' + message.msg);
}
});
function capturePage(data, sender, cb) {
... // some code omitted for clarity
chrome.tabs.captureVisibleTab(
null, {format: 'png', quality: 100}, function(dataURI) {
if (dataURI) {
var image = new Image();
image.onload = function() {
screenshot.ctx.drawImage(image, data.x, data.y);
//appendLog("calling callback function. callback is: " + cb);
cb(true); // **callback isn't called on content script**
};
image.src = dataURI;
}
});
}
I've omitted some code for clarity and the missing code is irrelevant. Let me explain what you see up there:
On the extension, inside the capturePage function, the line cb(true) executes. I can confirm it does because I'm able to see the "calling callback function" that comes right before it. However, the callback code on the content script does NOT run. Again, I can confirm this because I don't see the "came back from extension" message.
Here's the bizarre part: if I call cb(true) BEFORE I call chrome.tabs.captureVisibleTab(), the callback code on the content script DOES execute normally. That means chrome.tabs.captureVisibleTab() is interfering with the execution of cb(true) on the content script somehow. Maybe a port is closed when I call captureVisibleTab() - I'm not sure. The fact of the matter is that cb(true) will not execute on the content script after calling captureVisibleTab() but it will execute if I call it before.
On the extension, I tried storing the callback function, cb, in a variable outside capturePage() and then calling another function which would then call cb... but that doesn't work either.
I added the "" permission to my extension thinking maybe that would change things, but no. That changes nothing.
Again, if I replace the 4 lines of code where the deprecated APIs are, my extension works as expected. Thus, the problem is a combination of sendMessage() and captureVisibleTab(). There is no syntax error and I'm not leaving anything out. If I omit the call to captureVisibleTab(), the cb call will execute normally on the content script. What on earth???
How bizarre is that? I don't want to leave those deprecated API calls there. But then again, what could possibly be preventing the call back code to execute on the content script? I'm set on thinking the port is closed/replaced when we call captureVisibleTab(), but I'm not really sure and I've investigating it further.
I came across this online but I'm not sure if it's related to my issue. I also couldn't find anything similar here on stackoverflow and hence I created this question. Can anyone shed some light on this?
Thanks
I have a chrome extension which injects an iframe into every open tab. I have a chrome.runtime.onInstalled listener in my background.js which manually injects the required scripts as follows (Details of the API here : http://developer.chrome.com/extensions/runtime.html#event-onInstalled ) :
background.js
var injectIframeInAllTabs = function(){
console.log("reinject content scripts into all tabs");
var manifest = chrome.app.getDetails();
chrome.windows.getAll({},function(windows){
for( var win in windows ){
chrome.tabs.getAllInWindow(win.id, function reloadTabs(tabs) {
for (var i in tabs) {
var scripts = manifest.content_scripts[0].js;
console.log("content scripts ", scripts);
var k = 0, s = scripts.length;
for( ; k < s; k++ ) {
chrome.tabs.executeScript(tabs[i].id, {
file: scripts[k]
});
}
}
});
}
});
};
This works fine when I first install the extension. I want to do the same when my extension is updated. If I run the same script on update as well, I do not see a new iframe injected. Not only that, if I try to send a message to my content script AFTER the update, none of the messages go through to the content script. I have seen other people also running into the same issue on SO (Chrome: message content-script on runtime.onInstalled). What is the correct way of removing old content scripts and injecting new ones after chrome extension update?
When the extension is updated Chrome automatically cuts off all the "old" content scripts from talking to the background page and they also throw an exception if the old content script does try to communicate with the runtime. This was the missing piece for me. All I did was, in chrome.runtime.onInstalled in bg.js, I call the same method as posted in the question. That injects another iframe that talks to the correct runtime. At some point in time, the old content scripts tries to talk to the runtime which fails. I catch that exception and just wipeout the old content script. Also note that, each iframe gets injected into its own "isolated world" (Isolated world is explained here: http://www.youtube.com/watch?v=laLudeUmXHM) hence newly injected iframe cannot clear out the old lingering iframe.
Hope this helps someone in future!
There is no way to "remove" old content scripts (Apart from reloading the page in question using window.location.reload, which would be bad)
If you want to be more flexible about what code you execute in your content script, use the "code" parameter in the executeScript function, that lets you pass in a raw string with javascript code. If your content script is just one big function (i.e. content_script_function) which lives in background.js
in background.js:
function content_script_function(relevant_background_script_info) {
// this function will be serialized as a string using .toString()
// and will be called in the context of the content script page
// do your content script stuff here...
}
function execute_script_in_content_page(info) {
chrome.tabs.executeScript(tabid,
{code: "(" + content_script_function.toString() + ")(" +
JSON.stringify(info) + ");"});
}
chrome.tabs.onUpdated.addListener(
execute_script_in_content_page.bind( { reason: 'onUpdated',
otherinfo: chrome.app.getDetails() });
chrome.runtime.onInstalled.addListener(
execute_script_in_content_page.bind( { reason: 'onInstalled',
otherinfo: chrome.app.getDetails() });
)
Where relevant_background_script_info contains information about the background page, i.e. which version it is, whether there was an upgrade event, and why the function is being called. The content script page still maintains all its relevant state. This way you have full control over how to handle an "upgrade" event.
I have a google chrome extension that shares some code between it's content script and background process / popup. If it some easy and straightforward way for this code to check if it's executed as content script or not? (message passing behavior differs).
I can include additional "marker" javascript in manifest or call some chrome fnction unavailable from content script and check for exceptions - but these methods looks awkward to be. Maybe it's some easy and clean way to make this check?
To check whether or not your script is running as a content script, check if it is not being executed on a chrome-extension scheme.
if (location.protocol == 'chrome-extension:') {
// Running in the extension's process
// Background-specific code (actually, it could also be a popup/options page)
} else {
// Content script code
}
If you further want to know if you're running in a background page, use chrome.extension.getBackgroundPage()=== window. If it's true, the code is running in the background. If not, you're running in the context of a popup / options page / ...
(If you want to detect if the code is running in the context of an extension, ie not in the context of a regular web page, check if chrome.extension exists.)
Explanation of revised answer
Previously, my answer suggested to check whether background-specific APIs such as chrome.tabs were defined. Since Chrome 27 / Opera 15, this approach comes with an unwanted side-effect: Even if you don't use the method, the following error is logged to the console (at most once per page load per API):
chrome.tabs is not available: You do not have permission to access this API. Ensure that the required permission or manifest property is included in your manifest.json.
This doesn't affect your code (!!chrome.tabs will still be false), but users (developers) may get annoyed, and uninstall your extension.
The function chrome.extension.getBackgroundPage is not defined at all in content scripts, so alone it can be used to detect whether the code is running in a content script:
if (chrome.extension.getBackgroundPage) {
// background page, options page, popup, etc
} else {
// content script
}
There are more robust ways to detect each context separately in a module I wrote
function runningScript() {
// This function will return the currently running script of a Chrome extension
if (location.protocol == 'chrome-extension:') {
if (location.pathname == "/_generated_background_page.html")
return "background";
else
return location.pathname; // Will return "/popup.html" if that is the name of your popup
}
else
return "content";
}
This question already has an answer here:
How to call Greasemonkey's GM_ functions from code that must run in the target page scope?
(1 answer)
Closed 8 years ago.
Can I call function() of my custom Greasemonkey from my page?
For example,
I created a GM script that contains do_this() function.
I want my-web-site.com call the do_this() function.
But I can't.
I know, I can by doing unsafeWindow.do_this() but doing so prevents
me from calling GM_xmlhttpRequest().
Any ideas?
here the example that working, first create element then addEventListener
// ==UserScript==
// #name GM addEventListener Function Test
// #namespace ewwink.com
// #description GM addEventListener Function Test
// #include http://*
// ==/UserScript==
document.body.innerHTML+='<input type="image" id="alertMeID" onclick="do_this()" style="position:fixed;top:0;left:0" src="http://i55.tinypic.com/2nly5wz.gif" />';
document.getElementById('alertMeID').addEventListener('click', do_this, false);
function do_this(){
alert('hello World!, today is: '+new Date())
}
I just had the same Problem. You can find good information here in the wiki. I would suggest to use script injection to insert the needed code into the document. That way it will run like its in the sourcecode of the page. You can't use GM_ functions there either but you can use a combination of script injection (to retrieve a variable for example) and classic greasemonkey scripting with all the GM_ functions (For example you could use the variables you read and POST them with GM_xmlhttpRequest()).
Furthermore, techniques like script injection have several security-related advantages over unsafeWindow.
I hope that helps.
Never used this myself but here is the workaround http://wiki.greasespot.net/0.7.20080121.0%2B_compatibility.
unsafeWindow.someObject.registerCallback(function() {
var value = "bar";
setTimeout(function() {
GM_setValue("foo", value);
}, 0);
});
No, GM_* functions are not accessible from webpage.