chrome extension sendMessages more than one - javascript

Hello i'm trying to send message to popedup window, but when i close popup window end call it(from context menu) again.. it shows all last masseges..
How can i send only one message only to new opened window?
Manifest.json
{
"manifest_version": 2,
"name": "1tst",
"description": "sm txt",
"version": "0.1",
"author": "smwn",
"permissions": [
"activeTab",
"tabs",
"contextMenus"
],
"background": {
"scripts": ["sample.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["1.js"]
}]
}
sample.js
function genericOnClick(info, tab,selT) {
var vid;
var nw_tb;
chrome.tabs.create({
url: chrome.extension.getURL('1.html'),
active: false
}, function(tab) {
vid = tab.id;
// After the tab has been created, open a window to inject the tab
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true
// incognito, top, left, ...
},function(chromeWindow) {
//vid = chromeWindow.id;
}
);
});
chrome.windows.onCreated.addListener(function(tabb){
nw_tb = tabb.id;
alert("vid: "+vid+" nw_tb: "+nw_tb);
chrome.runtime.sendMessage(vid, {statn: selT});
return;
});
}
var title = "Test '%s' menu item";
var id = chrome.contextMenus.create({"title": title, "contexts":["selection"],
"onclick": function(info,tab){ genericOnClick(info,tab, info.selectionText);}
});
1.html
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<script src="1.js"></script>
</head>
<body>
</body>
</html>
1.js
window.onload=function(){
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
sendResponse({metroSTAT: "OK"});
alert(request.statn);
});
}

The problem
Every time genericOnClick() is called, it registers a new listener for the windows.onCreated event. Once registered, the listeners will trigger every time.
The solution
One of the many possible solutions is to "un-register" the listener once it is triggered for the first time (using removeListener()):
// Replace the following block:
chrome.windows.onCreated.addListener(function(tabb){
...
});
// With this:
chrome.windows.onCreated.addListener(function tmpListener(tabb) {
chrome.windows.onCreated.removeListener(tmpListener);
...
});

Related

Chrome Extension: Fetching the value of a DOM element

I'm building my first Chrome extension and my goal is to fetch the value of a DOM element from the extension popup by the click of a button. I'm basically following the exact documentation on how to send a message but keep getting:
'Error: Could not establish connection. Receiving end does not exist.'
For now, I'm not even trying to return DOM data; just trying to console.log a message triggered by the extension and returned by the content script. Any idea what the issue might be?
Here's my setup:
manifest.jst
{
"name": "Fetch Test",
"description": "Fetch data from DOM",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html"
},
"permissions": ["activeTab", "tabs", "scripting"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content_script.js"]
}
]
}
popup.html
<html>
<body>
<div class="container">
<button id="fetch-button">Fetch</button>
</div>
</body>
</html>
<script src="popup.js"></script>
popup.js
document.getElementById("fetch-button").addEventListener("click", function () {
(async () => {
const [tab] = await chrome.tabs.query({
active: true,
lastFocusedWindow: true,
});
const response = await chrome.tabs.sendMessage(tab.id, {
greeting: "hello",
});
console.log(response);
})();
});
content_script.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(
sender.tab
? "from a content script:" + sender.tab.url
: "from the extension"
);
if (request.greeting === "hello") sendResponse({ farewell: "goodbye" });
});
This sample uses executeScript to get document.title.
manifest.json
{
"name": "Get document.title",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html"
}
}
popup.html
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
* {
font-size: x-large;
}
</style>
</head>
<body style="min-width:300px">
<div id="title"></div><br>
<script src="popup.js"></script>
</body>
</html>
popup.js
const getTitle = () => {
console.log("getTitle() = " + document.title);
return document.title;
}
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
console.log("Execute Script");
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: getTitle
}, (result) => {
console.log("Recv result = " + result[0].result);
document.getElementById("title").innerText = result[0].result;
});
});
You need to include the javascript files in your popup.html file like so. Does that help?
<html>
<head>
<script src="popup.js"></script>
<script src="content_script.js"></script>
</head>
<body>
<div class="container">
<button id="fetch-button">Fetch</button>
</div>
</body>
</html>
You can try to do a long-lived message passing.
popup.js
const extensionContentScriptPort = () => {
return (async function () {
const currentTabQuery = {
active: true,
currentWindow: true,
};
const currentTabId = (await chrome?.tabs?.query(currentTabQuery))?.[0].id;
return chrome?.tabs?.connect(currentTabId, {
name: 'EXTENSION_CONTENTSCRIPT',
});
})();
};
// Add Event Listener for receiving messages
extensionContentScriptPort.then(port =>
port.onMessage.addListener((extensionContentScriptMsg) => {
console.log(extensionContentScriptMsg);
});
);
// Post message to content script
document.getElementById("fetch-button").addEventListener("click", function () {
extensionContentScriptPort?.then(port => {
port.postMessage({
greeting: "hello"
})
});
});
content_script.js
chrome?.runtime?.onConnect?.addListener(function (extensionContentScriptPort) {
console.assert(extensionContentScriptPort?.name === 'EXTENSION_CONTENTSCRIPT');
extensionContentScriptPort?.onMessage?.addListener(function (
extensionContentScriptMsg,
) {
if (extensionContentScriptMsg?.greetings === "hello") {
return extensionContentScriptPort?.postMessage({
greetings_reply: "Hey, there!"
})
}
}
}

The output not shown in message passing

I am working on a google chrome extension project where content.js script sends message to popup.js. Also trying to get some text from content.js to be turned into the same thing but on popup.js. Here is all my code.
This is my manifest file.
manifest.json
{
"name": "hoko's ext",
"description": "my ext",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["https://*/*", "http://*/*"],
"js": ["content-script.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"tabs",
"activeTab"
]
}
This is the popup you get when you click on the icon in the toolbar.
popup.html
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>I am the popup</h1>
<p id="extensionpopupcontent"></p>
<script type="text/javascript" src="popup.js"></script>
</body>
</html>
This is my content script called content-script.js
function injectScript(file_path, tag) {
var node = document.getElementsByTagName(tag)[0];
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', file_path);
node.appendChild(script);
}
injectScript(chrome.runtime.getURL('inject.js'), 'body');
chrome.runtime.sendMessage(document.getElementsByTagName('title')[0].innerText);
In background.js, I am receiving the message from content-script.js.
chrome.runtime.onMessage.addListener(function(response, sender, sendResponse) {
function onMessage(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello") {
sendResponse({farewell: "goodbye"});
}
}
})
In popup.js, it is receiving from background.js to output the code from content-script.js.
window.addEventListener('DOMContentLoaded', () => {
let bg = chrome.extension.getBackgroundPage();
chrome.tabs.query({active: true, currentWindow: true}, tabs => {
chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
document.getElementById('extensionpopupcontent').innerHTML = response;
});
});
});
I believe I need to inject this script that is inject.js.
function click() {
return document.getElementsByTagName('title')[0].innerText;
}
click();
remove background and content_scripts in manifest.json
remove tabs from permissions in manifest.json
remove background.js, content-script.js, and inject.js
rewrite popup.js as follows:
chrome.tabs.query({ active: true, currentWindow: true }, tabs => {
document.getElementById('extensionpopupcontent').textContent = tabs[0]?.title;
});

Chrome Extension execute script doesn't render browser content value

All I am trying to do change the value of popup.html on the basis of Specific URL. So I am sending message to background.js when user click on change ID of H2 from popup.html render the content by using specific JavaScript file
manifest.json
{
"manifest_version": 2,
"name": "Helpfullio",
"version": "0.1",
"content_scripts": [{
"matches": [
"*://google.com/*/*",
],
"js": ["jquery-3.2.1.js"]
}],
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"permissions": ["tabs","http://*/*", "https://*/*"]
}
popup.html
<html>
<head>
</head>
<body>
<h2 id="change">Change ___________</h2>
<script src="popup.js"></script>
</body>
</html>
popup.js
function clickHandler(e) {
chrome.runtime.sendMessage({directive: "popup-click"}, function(response) {
// this.close(); finishes processing request
});
}
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('change').addEventListener('click', clickHandler);
})
background.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
switch (request.directive) {
case "popup-click":
chrome.tabs.query({
'active': true, 'lastFocusedWindow': true
}, function (tabs) {
var url = tabs[0].url;
var result = url.split('/');
var hostname = result[2];
if("bitlock" == hostname){
chrome.tabs.executeScript(null, {
file: "render.js",
// allFrames: true
});
}else{
hrome.tabs.executeScript(null, {
file: "secondrender.js",
// allFrames: true
});
}
sendResponse({});
});
break;
default:
alert("Unmatched request of '" + request + "' from script to background.js from " + sender);
}
}
);;
JavaScript doesn't render the content of popup.html as it is not finding the elementID "change" . SO here how can I give reference of popup.html file in render.js file
render.js
document.getElementById("change").textContent = 'new text';

chrome.runtime.onMessage.addListener is undefined in content script

Im trying to send message to Background, and as well receive back to content script.
This is my content_script.js
init();
function init() {
function notifyBackgroundPage(event) {
chrome.runtime.sendMessage(chromeExtID, {
greeting: "Greeting from the content script"
});
}
window.addEventListener("click", notifyBackgroundPage);
// accept messages from background
// below line addListener is undefined
chrome.runtime.onMessage.addListener(function backgroundListener(request, sender, sendResponse) {
console.log("BgExt.js says: " + request);
});
}
BgExt.js
define([], function GmailExt() {
return {
start: function () {
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
console.log('inside response');
// to send back your response to the current tab
chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, {farewell: response}, function (response) {
});
});
return true;
}
);
}
};
});
This GmailExt file is loaded inside all.js (while all.js is inserted in index.html)
require([
"base_host/chrome/Server",
"kernel/Kernel",
"hydra/version",
"base_host/chrome/StartupConfig",
"hydra/apps",
"dojo/_base/Deferred",
"talkto_util/common",
"dojo/i18n!base_host/nls/CommonStrings",
"base_host/chrome/BgExt",
"dojo/domReady!"
], function (Server, Kernel, version, StartupConfig, apps, Deferred, talktoUtil, nls, BgExt) {
document.getElementById("logoMessage").innerText = nls.simple_secure_text;
var host = new Server();
//if app and not extension
chrome.browserAction && chrome.browserAction.onClicked.addListener(function() {
Deferred.when(kernel.onInit(), function () {
host.appManager.showShell();
});
return true;
});
BgExt.start();
});
client_base/host/chrome/index.html
<!DOCTYPE HTML>
<html>
<head>
<!-- Background Page for Extension/app -->
<title>Flock</title>
<meta charset="UTF-8">
<!--BUILD_REPLACE_BLOCK_START-->
<!-- This block will be remove by build.
All the files from libs/common/files.txt would be prepended to dojo.js -->
<script type="text/javascript" src="../../../hydra/src/libs/common/dojoConfig.js"></script>
<script type="text/javascript" src="../../../hydra/src/libs/common/underscore.js"></script>
<script type="text/javascript" src="../../../hydra/src/libs/common/underscore-ext.js"></script>
<!--BUILD_REPLACE_BLOCK_END-->
<script type="text/javascript" src="../../../hydra/src/libs/dojotoolkit/dojo/dojo.js"></script>
<script type="text/javascript" src="all.js"></script>
</head>
<body>
</body>
</html>
Manifest.json
{
"manifest_version": 2,
"content_security_policy": "script-src 'self' 'unsafe-eval' https://j.maxmind.com https://ssl.google-analytics.com https://flock-apps.flock.co https://flock-apps.flock-staging.co https://flock-apps.flock.com https://flock-apps.flock-staging.com; object-src 'self'",
"minimum_chrome_version": "22",
"options_page": "client_base/host/chrome/static/crx_browser_actions/index.html?app=preferences",
"name": "__MSG_extName__",
"description": "__MSG_extDescription__",
"background": {
"page": "client_base/host/chrome/index.html",
"persistent": true
},
"browser_action": {
"default_popup": "/gmail_ext/popup.html"
},
"web_accessible_resources": [
"client_base/host/chrome/static/blank.gif",
"gmail_ext/icons.png",
"gmail_ext/jquery-3.2.1.min.js",
"gmail_ext/gmail.js",
"gmail_ext/content_script.js"
],
"permissions": [
"<all_urls>",
"unlimitedStorage",
"notifications",
"idle",
"background",
"tabs",
"activeTab"
],
"optional_permissions": [
"clipboardWrite"
],
"externally_connectable": {
"matches": [
"https://*.google.com/*",
"http://localhost/*",
]
},
"content_scripts": [
{
"matches": [
"*://mail.google.com/*"
],
"css": [
"/gmail_ext/content_script.css"
],
"js": [
"/gmail_ext/loader.js"
],
"run_at": "document_end"
}
],
"version": "1.0"
}
I fixed it. The Solution was since I was using loader.js to load my content script and jquery via chrome.extension.getURL('/gmail_ext/content_script.js');
And was using "content_script.js" as a web_accessible_resources only loader.js had access to chrome object.
And yes, its a Dojo project, you can see the Working Extension here : https://chrome.google.com/webstore/detail/flock-chat-for-teams-and/enfaahabcinohafeakbliimmoholjeip?hl=en
I'm using page events now as showed here : https://developer.chrome.com/extensions/content_scripts#host-page-communication
At the top of loader.js I added below:
function initPort() {
var contentScriptPort,
chromeExtID = "lddaepjihbpbfpegjhjnkffjmmoigphe";
contentScriptPort = chrome.runtime.connect(chromeExtID);
contentScriptPort.onMessage.addListener(function (message) {
// Send data back to content script received from Background.
window.postMessage({type: "FROM_BACKGROUND", emails: message}, "*");
});
window.addEventListener("message", function _postMessage(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
// console.log("Content script received: " + event.data.emails);
contentScriptPort.postMessage(event.data);
}
}, false);
}
initPort();

Chrome plugin - How to modify dynamically added content on a webpage from a content script

I've literally been stuck on this for 2 full days so any help would be greatly appreciated.
I'm trying to build a chrome plugin that will modify the text of an element that has id ='MTG_INSTR$2'. The issue appears to be that this element only loads after some javascript is executed. Even if I wait for this element to load, when my plugin executes this line,
var els = document.getElementById('MTG_INSTR$2')
els is null. I've attached the full code below.
PS: when debugging in chrome I can see that it has the correct document and that the MTG_INSTR$2 id is within the document
manifest.json
{
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
"manifest_version": 2,
"name": "extensiontest",
"version": "0.2",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["jquery-3.2.1.min.js","content.js"]
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup":"popup.html"
},
"permissions": [
"tabs"
]
}
content.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if( request.message === "start" ) {
start();
}
}
);
function start(){
var els = document.getElementById('#MTG_INSTR$2'); //first sign of the issue, els is always left null
console.log(els);
alert("started");
}
popup.js
$(document).ready(function(){
$('body').on('click', '#button1', function(){
chrome.tabs.query({currentWindow: true, active: true}, function (tabs){
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {"message": "start"});
});
});
});
popup.html
<!DOCTYPE html>
<html>
<head>
<script src = "jquery-3.2.1.min.js"></script>
<script src="popup.js"></script>
</head>
<body>
<input id="button1" type=button value=clickme></input>
</body>
</html>
You need to remove the hash in :
var els = document.getElementById('#MTG_INSTR$2');
Good way would be :
var els = document.getElementById('MTG_INSTR$2');

Categories

Resources