Chrome Extension doesn't execute all the way - google-chrome-extension

The idea is simple. Open a window and then call chrome.tabs.executeScript on that new window.
Unfortunately, it doesn't do anything besides open a new window.
function openc(url) {
window.open(url);
chrome.tabs.executeScript(null, {file: "removeContent.js"});
console.log("hi");
}
document.addEventListener('DOMContentLoaded', function () {
openc("http://www.asdf.com/");
});

First of all, make sure that you've got the host permissions to operate on the page.
If you always want to run the script on the specific page, it suffices to use only content scripts, by registration via the manifest file:
"content_scripts": [
{
"matches": ["http://example.com/*"],
"js": ["open-asdf.js"]
},
{
"matches": ["http://www.asdf.com/*"],
"js": ["removeContent.js"]
}
],
If you want to dynamically execute a content script for the new page, you should use the chrome.tabs.create method to open the new tab, and insert the script in the callback. These methods can only be used in the extension's process, so make sure that the code is running on the background/event/popup/options/.. page.
chrome.tabs.create({
url: 'http://www.asdf.com/'
}, function(tab) {
chrome.tabs.executeScript(tab.id, {file: "removeContent.js"}, function() {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
});
});

Related

Firefox WebExtension: Check if MY extension exists

Porting extension from Chrome into FF
Followed this tutorial (which works fine in Chrome): http://www.codingscripts.com/check-whether-user-has-a-chrome-extension-installed/
Sending message from webpage to extension:
In (web)pagescript.js this has:
function IsExist(extensionId,callback){
chrome.runtime.sendMessage(extensionId, { message: "installed" },
function (reply) {
if (reply) {
callback(true);
}else{
callback(false);
}
});
}
IsExist("Your extension id",function(installed){
if(!installed){
alert("Please install extension ");
}
});
Receiving message from webpage in extension:
chrome.runtime.onMessageExternal.addListener(
function(req, sender, callback) {
if (req) {
if (req.message) {
if (req.message == "installed") {
callback(true);
}
}
}
return true;
});
What I'm trying to achieve
A couple of html pages on my website need to redirect back to the homepage when the extension is NOT installed. So those pages need to be able to figure out (on their own) if the extension is installed or not.
Error I'm getting when I open webpage
ReferenceError : chrome is not defined. (I also tried with browser.runtime.onMessageExternal but then it throws "browser" is not defined).
Is there no way to do this similar to what can be done in Chrome ?
Thanks to all the comments this is what I came up with. (I had to go for document_end (altho comments advise document_start) cause I had other things going on in content_script.js
In my add-on's content_script.js
document.body.classList.add("plugininstalledblabla");
In my add-on's manifest.json
"content_scripts":
[
{
"matches": ["*://*/*"],
"all_frames": true,
"js": ["content_script.js"],
"run_at": "document_end"
}
]
in my website's main.js script
$(window).on("load", function() { // !! Window onLoad cause : document_end -> DOM should be loaded here
// Set
$body = $('body');
if(document.body.classList.contains("plugininstalledblabla")){
console.log('addon is installed');
}
});

Does executeScript still work after change window.location.href

when i change the window.location.href,the executeScript didn't work.why is this?
manifest.json is
{
"name": "Page Redder",
"description": "Make the current page red",
"version": "2.0",
"permissions": [
"activeTab","*://*/*"
],
"browser_action": {
"default_title": "Make this page red"
},
"background": {
"scripts": ["jquery-1.11.1.js","background.js"]
},
"manifest_version": 2
}
background.js is
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id,{code:'window.location.href="http://www.google.com"'},function(){
chrome.tabs.executeScript(tab.id, {file:"test.js"}, function() {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
}
});
});
});
test.js is
alert("hello work")
The problem is that the file in the second executeScript is being injected after the code of the first executeScript has been executed, but before the window.location.href call has finished. See for yourself: add a breakpoint on the line calling the second chrome.tabs.executeScript, click your browser action and then wait for the page to load before resuming - the popup will work.
One way to solve this is to add a tabs.onUpdated listener. Then, when you click your browser action store what the tabId was. Inside the tabs.onUpdated listener you can execute test.js if the updated tabId matches the tabId set in your browser action. Quick example:
var activeTabId;
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {code: 'window.location.href="http://www.google.com"'}, function (){
activeTabId = tab.id;
});
});
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(tabId === activeTabId) {
activeTabId = null; //To prevent executing the script multiple times
chrome.tabs.executeScript(tabId, {file:"test.js"});
}
});

chrome extension - getting the last url instead of current

I'm getting the last visited url instead of the current one. (when i go to site.com and after that to site2.com, the url I get is 'site.com' and after I refresh site2.com I'm getting the right one.
Based on the answers here:
Google Chrome Extension get page information
Display current URL in a chrome extension
I've come up with this code:
manifest.json
{
"manifest_version": 2,
"browser_action": {
"default_popup": "action.html"
},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["content.js"],
"run_at": "document_end"
}
],
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs",
"unlimitedStorage",
]
}
content.js
chrome.extension.sendRequest({method: "getUrl"}, function(response) {
console.log(response.data);
});
background.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if(request.method == "getUrl") {
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
currentUrl = tabs[0].url;
});
sendResponse({data: currentUrl});
}
else
sendResponse({}); // snub them.
});
I've also tried to put this code below directly in content.js and I'm getting an error and in background.js and the url is set to chrome://extensions/.
chrome.tabs.query({ currentWindow: true, active: true }, function (tabs) {
currentUrl = tabs[0].url;
});
what is the right way to do this ?
First of all:
chrome.extension.sendRequest/onRequest are deprecated. Please, use chrome.runtime.sendMessage/onMessage instead.
Also, whenever possible, prefer event pages over background pages. Most of the time it takes next to nothing to convert a background page to an event page, but can save consideably on resources.
The problem:
chrome.tabs.query is asynchronous. It means that, when called, it initializes the request and then completes its execution so the next part of your script gets executed. Once the request has completed, the registered callback function is executed. So, this is what happens in your case:
You visit http://www.site1.com.
chrome.tabs.query({...}, callback) gets executed (notice the callback has not been executed yet).
sendResponse({data: currentUrl}) gets executed (note that at this point currentUrl is not defined).
chrome.tabs.query's request completes and the callback function is executed, setting currentUrl = "http://www.site1.com" (but only after it is too late).
You visit http://www.site2.com.
chrome.tabs.query({...}, callback) gets executed (notice the callback has not been executed yet).
sendResponse({data: currentUrl}) gets executed (note that at this point currentUrl still equals http://www.site1.com from step 4).
chrome.tabs.query's request completes and the callback function is executed, setting currentUrl = "http://www.site2.com" (again only after it is too late).
The solutions:
(A)
Move the logic inside the callback.
(Note: Whenever the callback (i.e. sendResponse) is going be called asynchronously, it is necessary for the onMessage listener to return true.)
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request.method && (request.method == "getURL")) {
if (sendResponse) {
chrome.tabs.query({
currentWindow: true,
active: true
}, function(tabs) {
if (tabs.length > 0) {
sendResponse({ data: tabs[0].url });
}
});
/* Since 'sendResponse' is to going be called
* asynchronously, it is necessary to return 'true' */
return true;
}
} else {
// Do not talk to strangers !!!
}
});
(B)
Even simpler in your case, the sender parameter of the onMessage listener, contains the field tab which contains the URL info. E.g.:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if(request.method && (request.method == "getURL") && sendResponse) {
sendResponse({ data: sender.tab.url });
}
});
(C)
If you only need the URL in the context of the content script, why don't you use location.href from within the content script ?

Translating JavaScript bookmark into Chrome browser action extension

I want to create a Chrome extension with a browser action onClicked which provides the same functionality as the following bookmark:
javascript:(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='http://page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
However, I struggle to correctly translate the javascript code of the bookmark into the logic of a Chrome extension. I thought the best to is to to put the exact code of the bookmark into a separate script create_feed_url.js and execute it in background.js. My background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
// Run the bookmark code
chrome.tabs.executeScript(null, {file: "create_feed_url.js"});
// Open a new tab for a valid url resulting from create_feed_url.js
var feed_url = "http://page2rss.com/page?url=" + tab.url;
chrome.tabs.create({"url": feed_url});
Yet the code in create_feed_url.js somewhat runs not sucessfully. There is no feed URL generated, resulting in a non existing value for feed_url.
My questions:
Could you please help me to find out why I cannot just put the code of the bookmark into create_feed_url.js and run it?
Is this approach of executeScript recommendable in my case or is there a better way translating a bookmark into an extension?
I solved it with a workaround calling the URL that generates the new feed in a new tab before closing it and finally jumping to the tab with the final RSS feed URL. This solution does not require create_feed_url.js but relies completely on background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
// Original bookmark JS code
//(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='http://page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
var create_feed_url = "http://page2rss.com/api/page?url=" + encodeURIComponent(tab.url); //+ "&callback=page2rss_bookmark_urlr"
var feed_url = "http://page2rss.com/page?url=" + tab.url;
chrome.tabs.create({"url": create_feed_url, active: false}, function(tab) {
chrome.browserAction.setBadgeText({text: 'wait'});
setTimeout(function() {
chrome.tabs.remove(tab.id, function(tab) {
chrome.browserAction.setBadgeText({text: ''});
});
}, 5000);
});
setTimeout(function() {
chrome.tabs.create({"url": feed_url, active: true}, function(tab) {
chrome.tabs.onUpdated.addListener(function( tabId , info ) {
if ( info.status == "complete" ) {
chrome.browserAction.setBadgeText({text: 'done', tabId: tabId});
}
});
}); }
, 1000);
});
Based on Rob's comment above of using a content script approach I tried to implement it. However, clicking on the browser icon does not trigger the content script create_feed_url.js through content_script.js. I tried to debug the code but neither the Developer Tools nor the inspect element tool show any error.
background.js:
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {file: "content_script.js"});
});
content_script.js:
var s = document.createElement('script');
s.src = chrome.extension.getURL("create_feed_url.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
create_feed_url.js:
(function(){if(!window.page2rss_bookmark_urlr)window.page2rss_bookmark_urlr=function(ur){if(ur.error)alert(ur.error);if(ur.page&&ur.page.page)location.href=ur.page.page};var r=document.getElementById('urlFormRequest');if(r)r.parentNode.removeChild(r);r=document.createElement('script');r.id='urlFormRequest';r.type='text/javascript';r.src='//page2rss.com/api/page?url='+encodeURIComponent(location.href)+'&callback=page2rss_bookmark_urlr';document.body.appendChild(r);})();
manifest.json:
{
"permissions": [
"tabs", "http://*/*", "https://*/*"
],
"background" : {
"scripts": ["background.js"],
"persistent": false
},
"web_accessible_resources": ["create_feed_url.js"],
"browser_action" :
{
"default_icon" : "rss-19.png",
"default_title" : "Create RSS feed for this page"
},
"manifest_version": 2
}

chrome extension not working for secure sites https

I've written a chrome extension, but it doesn't seem to work for https sites. Its currently a background page that injects script into the page. It runs jquery and some libraries too. The only way I've found out so far to do this is to run a background page, and use chrome.tabs.executescript. If anyone knows a better way then that would help too.
I've added permissions to http and https sites, so i thought that would be sufficient. Please can someone help, thanks.
Manifest:
{
"name": "My First Extension",
"version": "1.0",
"description": "The first extension that I made.",
"background_page": "popup.html",
"permissions": ["tabs", "http://*/*", "https://*/*"]
}
popup.html
<script type="text/javascript">
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab)
{
if(changeInfo.status == "loading")
{
chrome.tabs.insertCSS(null, { file: "jquery-ui-1.8.10.custom.css" }, null);
chrome.tabs.executeScript(null, { file: "jquery.min.js" }, null);
chrome.tabs.executeScript(null, { file: "jquery-ui-1.8.10.custom.min.js" }, null);
chrome.tabs.executeScript(null, { file: "jquery.hotkeys-0.7.9.min.js" }, null);
chrome.tabs.executeScript(null, { file: "custom.js" }, null);
}
})
</script>
the file custom.js is where i do my coding.
thanks
Try adding "conent_scripts" to manifest.json:
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"css": ["empty.css"]
}]
You have to specify 'css' or 'file'. In my add-on, scripts are loaded dynamically, so I just use a dummy css file.
See also: http://code.google.com/chrome/extensions/content_scripts.html
Maybe there is a problem with dependencies. All calls to executeScript are asynchronous. So you can not assume that jquery is injected when you start injecting jquery hotkeys. You should better use something like this:
var runScripts = function(tabId, scripts, cb) {
var current = scripts.shift();
if (current) {
chrome.tabs.executeScript(tabId, {file: current}, function(a) {
console.log("Finished running script:", current);
runScripts(tabId, scripts, cb);
});
} else {
cb();
}
};
chrome.tabs.insertCSS(null, {file: "jquery-ui-1.8.10.custom.css"}, function () {
runScripts( null, ["jquery.min.js", "jquery-ui-1.8.10.custom.min.js", "jquery.hotkeys-0.7.9.min.js", "custom.js"], function() {});
});

Resources