Chrome extension development: Call a method in popup from background_html - javascript

I have a popup named mf_popup.html and my background page is named mf_background.html.
As I start the browser my background page fires (as is my understanding, I am new to Chrome development), and I would like to call a function in my mf_popup.html page from my background page.
For example:
Start chrome
background page fires
background page calls some function in popup page (which initiates some stuff)
How do I do the above?

if you place the needed code in both html-files in mf_javascript.js and includes the script in both with this line:
<script type="text/javascript" src="mf_javascript.js">

mf_popup.html
//sendRequest([any type] request, [function] responseCallback)
chrome.extension.sendRequest({
function: "foo",
params: [myParam1, myParam2],
function(response) {
alert("foo returns:"+response.result+");
}
});
mf_background.html
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if(request.function == "foo")
var bar = foo(request.params[0], request.params[1]);
sendResponse({result: bar});
}
);
You also could just use sendRequest("foo") if you don't want send any params and/or use an callback function.

Related

chrome.tabs.create not working

Because my content script cannot use all the chrome API tools, I am sending a message from my content script to my background script. When received, the background script is supposed to open a new tab containing an html file I had made.
This is sending the message from the content script...
chrome.runtime.sendMessage({permission: true}, function(response) {
console.log(response.access);
});
This is the code to receive the message in my background script...
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.permission == true) {
chrome.tabs.create({'url': chrome.extension.getURL('./src/permission.html')}, function(tab) {
sendResponse({access: "yes"});
});
}
});
The message is received, I have already tested that. But when I add the following code...
chrome.tabs.create({'url': chrome.extension.getURL('./src/permission.html')}, function(tab) {
...etc
I get an error saying response not received. Meaning something must have broke inside my chrome.tabs.create. Why is it breaking?
The permission.html path is relative to the background script.
What I want is for a new tab to be created when the message is received.
I'm not sure if this has any affect, but the content scripts and the background scripts communicate asyncronously so for you to use the sendResponse callback, you'll need to return true; at the end of your onMessage anonymous function.
Chrome onMessage return true
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.permission == true) {
chrome.tabs.create({'url': chrome.extension.getURL('./src/permission.html')}, function(tab) {
sendResponse({access: "yes"});
});
}
return true; //to tell the content script to look out for sendResponse
});
Again, I'm not sure if this will solve your problem, but regardless, your response using sendResponse will not work without returning true at the end of the listener
Also, BTW, chome.extension.getURL() does not need a dot-slash so chrome.extension.getURL('src/permission.html') should be enough.
Have you tried just running
chrome.tabs.create({'url': chrome.extension.getURL('src/permission.html')});
(with or without the dot-slash) to see if the tab opens up?

How to update the DOM using chrome.runtime.onMessageExternal function callback

I'm working on a Chrome app that received an address from an extension and is supposed to open that URL in the app window, using the webview tag and Chrome runtime API message sending.
I'm trying to get the chrome.window.create callback function to update the index.html page the was created.
It's not working as I planned though.
Here is the code:
chrome.runtime.onMessageExternal.addListener(
function (request, sender, sendResponse) {
chrome.app.window.create(
'index.html',
{PARAMETERS},
function () {
//get
var thisWindow = document.querySelector("webview");
thisWindow.setAttribute("src", request.url);
}
);
}
The index.html file is just a webview tag and some styling.
This opens an empty window once the message is received. However, it opens the page when I send again while the app is open, meaning that the callback probably tried to access the index.html file before it was created?
Thanks for reading!
The window.create callback function is called prior to the execution of the created windows onload event (see here). So presumably the DOM is not yet available at this stage. What you can do is, bind your modifications to the created windows onload event, thus ensuring the DOM is available.
chrome.app.window.create(
'index.html',
{
PARAMETERS
},
function (createdWindow) {
var contentWindow = createdWindow.contentWindow;
contentWindow.onload = function() {
var thisWindow = contentWindow.document.querySelector("webview");
thisWindow.setAttribute("src", request.url);
}
}
);

Passing message from one listener to another

I'm developing an extension for Chrome, and here's the workflow I'm trying to achieve:
popup sends message -> content script 1 listens -> content script 1 sends message -> content script 2 listens -> content script 2 performs action
In concept it's fine and dandy; what I've done is set up 2 listeners: one in each content script:
Popup:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
console.log('popup send request');
chrome.tabs.sendMessage(tabs[0].id, obj);
});
Content script 1:
chrome.runtime.onMessage.addListener((function (request, sender) {
this.log('wg got request', 'request', request, 'sender', sender);
if (request.action == 'options-updated') {
this.updateOptions(request, (function() {
var obj = {action: 'refresh', WG: window.WG};
this.log('wg forwarded request');
chrome.runtime.sendMessage(obj); // attempting to forward another request
return true;
}).bind(this));
}
return true;
}).bind(window.WG));
Content script 2:
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log('content script got request', 'request', request, 'sender', sender);
if (request.WG) {
request.WG.log('message', request.action);
if (request.action == 'refresh') {
WGRefresh(request.WG, request.options);
}
}
return true;
});
Problem is, content script 2 only receives the first message. So the output I'm getting is:
popup send request
content script got request (first, to ignore)
wg got request (same, first, don't ignore here)
wg forward request
And then nothing. The content script should have fired it again, and in the request I always send "action", which I check for in the listener, but for the logs I don't differentiate (it should ALWAYS log, so this means the request never gets there).
I've tried returning true in all the listeners, according to the documentation it will keep the chain running and not stop after the first hit, but even so it's not working. What am I doing wrong?!
There are 2 sendMessage functions in Chrome API.
chrome.runtime.sendMessage sends a message to all open extension pages (i.e. background, popup, etc.)
chrome.tabs.sendMessage sends a message to all content scripts from the extension in a given tab
So the call to chrome.runtime.sendMessage() in your first content script can't reach any other content script.
What's more, you can't call chrome.tabs directly from a content script.
To do what you want, you need to set up a background script that will act like a proxy between CS1 and CS2. Technically, you could use the popup, but it's unreliable, as the popup may be closed and then nobody would be listening. The background page (or better yet, an event page) is designed specifically for that purpose.
So the scheme becomes: popup -(tabs.sendMessage)-> CS1 -(runtime.sendMessage)-> background -(tabs.sendMessage)-> CS2
Do note that background page will need to know the tab ID to send the message to. If it's the same tab for some reason, e.g. you're trying to message across frames, you can use the sender parameter in the callback.
See Messaging docs for more details.

embed _generated_background_page to options page

I made Chrome extension which working fine, but need to be modified this way:
console.log of background.js should be monitored in real time by user constantly, while options page opened, as an element of this page. At the worst case, it may be duplicate of log, but generated in background.js.
How can I access and display this data, where background script process external data once a second?
You can't embed the background page in another page.
To do what you are looking to do, you can override console.log to do extra stuff:
// background.js
(function() {
if(window.console && console.log) {
var old = console.log;
console.log = function() {
// Do extra stuff here
chrome.runtime.sendMessage({
type: "backgroundLogEvent",
content: arguments
});
// Call normal console.log
old.apply(this, arguments);
}
}
})();
And in the options page, you can receive those messages:
// options.js
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.type == "backgroundLogEvent") {
// Do something with message.arguments
// I.e. log them here:
message.arguments.unshift('From background:');
console.log.apply(console, message.arguments);
}
});
This will transmit all console.log messages from background in realtime.
Exercise for the reader: implement a buffer that shows a short history before opening the options page.

Chrome extensions: best method for communicating between background page and a web site page script

What I want to do is to run go() function in image.js file. I've googled around and I understand that is not possible to run inline scripts.
What is the best method to call the JavaScript I want? Events? Messages? Requests? Any other way?
Here is my code so far:
background.js
chrome.browserAction.onClicked.addListener(function(tab) {
var viewTabUrl = chrome.extension.getURL('image.html');
var newURL = "image.html";
chrome.tabs.create({
url : newURL
});
var tabs = chrome.tabs.query({}, function(tabs) {
for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i];
if (tab.url == viewTabUrl) {
//here i want to call go() function from image.js
}
}
});
});
image.html
<html>
<body>
<script src="js/image.js"></script>
</body>
</html>
image.js
function go(){
alert('working!');
}
There are various ways to achieve this. Based on what exactly you are trying to achieve (which is not clear by your question), one way might be better than the other.
An easy way, would be to inject a content script and communicate with it through Message Passing, but it is not possible to inject content scripts into a page with the chrome-extension:// scheme (despite what the docs say - there is an open issue for correcting the docs).
So, here is one possibility: Use window.postMessage
E.g.:
In background.js:
var viewTabURL = chrome.extension.getURL("image.html");
var win = window.open(viewTabURL); // <-- you need to open the tab like this
// in order to be able to use `postMessage()`
function requestToInvokeGo() {
win.postMessage("Go", viewTabURL);
}
image.js:
window.addEventListener("message", function(evt) {
if (location.href.indexOf(evt.origin) !== -1) {
/* OK, I know this guy */
if (evt.data === "Go") {
/* Master says: "Go" */
alert("Went !");
}
}
});
In general, the easiest method to communicate between the background page and extension views is via direct access to the respective window objects. That way you can invoke functions or access defined properties in the other page.
Obtaining the window object of the background page from another extension page is straightforward: use chrome.extension.getBackgroundPage(), or chrome.runtime.getBackgroundPage(callback) if it's an event page.
To obtain the window object of an extension page from the background page you have at least three options:
Loop through the results of chrome.extension.getViews({type:'tab'}) to find the page you want.
Open the page in the first place using window.open, which directly returns the window object.
Make code in the extension page call a function in the background page to register itself, passing its window object as a parameter. See for instance this answer.
Once you have a reference to the window object of your page, you can call its functions directly: win.go()
As a side note, in your case you are opening an extension view, and then immediately want to invoke a function in it without passing any information from the background page. The easiest way to achieve that would be to simply make the view run the function when it loads. You just need to add the following line to the end of your image.js script:
go();
Note also that the code in your example will probably fail to find your tab, because chrome.tabs.create is asynchronous and will return before your tab is created.

Categories

Resources