I created long-lived connection between popup and content pages. It works successfully. But I want to send message to content when user click the button.
contentscript.js
console.log("content script loaded!");
var port = chrome.runtime.connect({name: "content-script"});
port.onMessage.addListener(function(message){
if(message.key=="color"){
document.body.style.backgroundColor='lightgrey';
}
else if(message.key=="color2"){
document.body.style.backgroundColor='blue';
}
});
popup.js
document.addEventListener('DOMContentLoaded', function() {
var checkPageButton = document.getElementById('btnStart');
checkPageButton.addEventListener('click', function() {
GetImages("");
}, false);
}, false);
function GetImages(pageURL){
if(activePort!=null){
activePort.postMessage({key:"color2"});
}
}
var activePort=null;
chrome.runtime.onConnect.addListener(function (port) {
console.assert(port.name == "content-script");
activePort=port;
port.onMessage.addListener(function(message) {
if(message.key=="download"){
port.postMessage({key:"download", text: "OK"});
}
else if(message.key="load"){
port.postMessage({key:"color"});
console.log(message.text);
}
})
});
In the GetImages() function I try to
port.postMessage({key:"color2"});
naturally it can't find the "port". So I create the activePort variable and try to post message with it. But It didn't work properly.
I changed the codes below and it works correctly. Now I opened the port in popup.js and I can send message with button click.
newpopup.js
function GetImages(pageURL){
port.postMessage({text:"ok"});
}
var port;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
port = chrome.tabs.connect(tabs[0].id,{name: "knockknock"});
});
newcontentscript.js
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "knockknock");
port.onMessage.addListener(function(msg) {
console.log(msg);
});
});
Related
I'm writing an extension that has a button with different functions.
So I'm trying to figure out how to retrieve number of tabs that are open and
in my content.js I want to execute different thing when clicking the button depending on how many tabs that are open.
Been trying different approaches with chrome.tabs.query in background.js and sending it back but having troubles since it's asynchronous.
content.js
if (tabcount < 2) {
$(function () {
$("#Back").on('click', function (e) {
e.preventDefault();
window.history.back();
});
});
console.log("one tab");
}
if (tabcount > 1) {
$(function () {
$("#Back").on('click', function (e) {
e.preventDefault();
window.location.href = 'exit';
});
});
console.log("more tabs");
}
Edit: added message code
Background message code
function sendMessageToTab(tabId, message) {
return new Promise((resolve) => {
chrome.tabs.sendMessage(tabId, message, resolve)
})
}
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.query({ windowType: 'normal' }, function (tabs) {
const msg = tabs.length;
sendMessageToTab(tabs[0].id, msg)
});
} return true;
});
content recieve
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request > 1) {console.log('more than 1 tab open'); }
});
I have been researching asynchronous function calls and how to set variables to values from them and have had a lot of trouble with it. I want to create a port to message with my file content.js on the extension.
To do this I need to receive the tab of the window that I have open, and use its attribute id in the chrome.tabs.connect() function.
This implementation fails to reach any console.log() calls but I don't understand asynchronous programming well enough to understand. Can anyone help with this? My problem is that the two files aren't communicating, so the port isn't opening.
<script language = "Javascript">
function foo(callback){
var port = chrome.tabs.connect(chrome.tabs.query({ currentWindow: true, active: true }, function(tabs) {
//sets curTab to current tab
console.log(tabs[0]);
var curTab;
setTimeout(function(tabs) {
curTab = tabs[0];
console.log(curTab);
}, 5000);
}),{name: "mode"})
//both files are preset to this so no need to message
var mode = "on";
document.getElementById("stop").onclick = function(){
if(mode === "off")
mode = "on";
else
mode = "off";
setMode();
console.log("clikityclik");
};
console.log(mode);
function setMode(){
/*sends message to port*/
if(port)
port.postMessage({newMode: mode});
else{
console.log("error: port not created");
}
}
}
the relevant code from my content.js file is below. I call this function once
function getMode(){
/*receives message from port
**communicates with sandboxed.html
*/
chrome.runtime.onConnect.addListener(function(port) {
console.assert(port.name == "mode");
port.onMessage.addListener(function(msg) {
if (msg.newMode){
mode = msg.newMode;
console.log("Mesage received: "+mode);
}
else
console.log("error receiving new mode, last mode was: " + mode);
});
});
}
The goal of this program is for the first script to send messages to the content.js when a div is clicked and for the 'content.js' file to receive those messages whenever they are sent.
the solution was to make a function that creates the port, with an input of tab. Basically, getTab will try to get the the value of the tab, and if we do have a tab it will run the callback function which is createPort which contains the information necessary to create the port and also the event handler for the click on the div.
function getTab(callback){
chrome.tabs.query({ currentWindow: true, active: true }, function(tabs) {
console.log(tabs[0]);
callback(tabs[0]);
});
}
function createPort(tab){
var port = chrome.tabs.connect(tab.id,{name: "mode"});
document.getElementById("stop").onclick = function(){
if(mode === "off")
mode = "on";
else
mode = "off";
setMode(port);
console.log("clikityclik");
};
}
var mode = "on"; //mode is preset to on in content.js
getTab(createPort);
I am making a chrome extension to keep refreshing a page unless stop button is chosen. But i am able to do it only once. Here is my code for background.js
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
switch(request.type) {
case "table-row-count_start":
alert("Refershing started");
RefreshAndCount();
break;
case "table-row-count_stop":
alert("Stop Refershing");
break;
}
return true;
});
var RefreshAndCount = function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type: "table-row-count"});
chrome.browserAction.setBadgeText({tabId: tabs[0].id, text: "Counting!"});
});
};
In content.js I did this :
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
alert(message.type);
switch(message.type) {
case "table-row-count":
var x = document.querySelector('table').rows.length;
chrome.storage.sync.set({'value': x}, function() {
console.log('Settings saved');
});
chrome.storage.sync.get(["value"], function(items){
console.log(items);
});
alert("Row count = " + x);
setTimeout(function(){
location.reload();
},100);
break;
}
});
chrome.storage.onChanged.addListener(function(changes, namespace) {
for (key in changes) {
if(key=='value'){
var storageChange = changes[key];
console.log('Storage key "%s" in namespace "%s" changed. ' +
'Old value was "%s", new value is "%s".',
key,
namespace,
storageChange.oldValue,
storageChange.newValue);
}
}
});
After refresh I want to print the current row count alert everytime. Please help how to do this .
This work fine, for a single refresh but after that I again had to choose the start button from popup.
I want some way that I need not click start button again and the whole process repeats, storing the previous row count in cache or something.
popup.js
window.onload = function() {
document.getElementById("mystartbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_start"
});
}
document.getElementById("mystopbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_stop"
});
}
}
Also help me How to keep on refershing that page even if I switch to other tab or minimise my chrome ?
You can use the chrome.storage.local to store data that will be saved over time and over context where you use it. You can set a boolean to true or false to enable or disable autoreload. Then you only have to set it at click on browser action and check it in the content-script to know if you have to reload.
A possible and simple implemtation should be like this : (It depends of the expected behavior)
content.js (have to be injected in the page to autoreload)
var reloadDuration = 5000;
function autoreload()
{
chrome.local.storage.get("autoreload_enabled", function(result)
{
if(result.autoreload_enabled)
{
chrome.runtime.sendMessage({type: "table-row-count"});
window.location.reload();
}
}
}
setTimeout(autoreload, reloadDuration);
This will reload your page every reloadDuration if the boolean set in chrome local storage named autoreload_enabled is true.
I have the following code in popup.js which responds to a button press to get all the tabs, create a new tab (template.html), and send the tabs as an array to the new tab. Later I will delete the current tabs and display the links on one page to save space (That's the idea of the extension).
function saveAll() {
var openTabs = [];
chrome.tabs.query({}, function(tabs) {
for (var i = 0; i < tabs.length; i++) {
openTabs[i] = tabs[i];
}
createSavedPage(openTabs);
});
}
function createSavedPage(tabsToSave) {
chrome.tabs.create({
"url": chrome.extension.getURL("template.html"),
"active": false
},
function(tab) {
sendListToPage(tab, tabsToSave);
}
);
}
function sendListToPage(tab, tabsArray) {
chrome.tabs.sendMessage(tab.id, {
"action": "fill-list",
"data": tabsArray
});
}
var saveAllButton = document.getElementById("select-all-tabs");
saveAllButton.addEventListener("click", saveAll);
The tab that is created includes a template.js file:
function fillList(array) {
var list = document.getElementById("link-list");
for (var item in array) {
//Something
}
}
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.action == "fill-list") {
var data = request.data;
fillList(data);
}
}
);
When I create the new tab, the message is sent from the extension but never received. What is causing this issue?
I also thought that the message was being sent before the created tab was fully loaded. So I've changed popup.js by adding a chrome.tabs.onUpdated listener:
function createSavedPage(tabsToSave) {
chrome.tabs.create({
"url": chrome.extension.getURL("template.html"),
"active": false
},
function(tab) {
chrome.tabs.onUpdated.addListener(function(tabId, info) {
if (tabId == tab.id && info.status == "complete")
sendListToPage(tab, tabsToSave);
});
}
);
}
And it seems to solve the issue. Is there still a better way?
I send a message from a ContextMenu within content.js to background.js. When I send a message, I expect to see an alert of just two variables which are sent with the request. When I send multiple request(few times in a row) I receive alerts including previously sent messages. It seems that all messages are stored somewhere. How do you disable this? I would like to see alerts of only the most recent message.
contents.js:
$(document).mousedown(function(event) {
var url = window.location.href;
var contents = window.getSelection().toString();
switch (event.which) {
case 3:
chrome.runtime.sendMessage({contents: contents, url: url}, function(response) {
//console.log(response.farewell);
});
break;
}
});
background.js
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
manifest.json
"background": {
"scripts": ["jquery-1.11.1.min.js", "background.js"],
//"page": "background.html",
"persistent": true
},
It's because of this code
chrome.extension.onMessage.addListener(function (message, sender, sendResponse) {
if (message.url) {
chrome.contextMenus.onClicked.addListener(function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
}
)
}
});
What you are saying is that every onMessage event add a listener for onClicked events. So if you send three messages you end up with three testFunc2 methods acting on onClicked events.
Since you are trying to use information from two different asynchronous events. You will have to store one of them temporarily. Something like this would probably work.
var lastMessage;
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
if (message.url) {
lastMessage = message;
} else {
lastMessage = undefined;
}
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if(lastMessage !== undefined) {
testFunc2(message, info, tab);
}
});
function testFunc2(info, tab){
alert(message.url);
alert(typeof message.contents);
// cleanup
lastMessage = undefined;
});