(Easy Fix) How to insert div via content.js Google Chrome Extension? - javascript

I'm want to create an overlay via content script (content.js) for my google chrome extension. How should I do this?
Here is the code that executes the content script:
chrome.webNavigation.onCommitted.addListener(function() {
chrome.windows.getCurrent(function (currentWindow) {
chrome.tabs.query({ active: true, windowId: currentWindow.id }, function (activeTabs) {
activeTabs.map(function (tab) {
chrome.tabs.executeScript(tab.id, { file: 'contentScript.js', allFrames: false });
});
});
});
}, {url: [{urlMatches : 'https://mail.google.com/'}]});
Here is my contentScript.js
window.addEventListener('DOMContentLoaded', setUpOverlay, false);
function setUpOverlay(){
//Set up overlay div in here
}

The best way to achieve what you want is to use the chrome message api and pass a message to the content script to execute the code
here is how it works:
//popup.js
chrome.tabs.query({active:true,currentWindow:true},(tabs)=>{
chrome.tabs.sendMessage(tabs[0].id,'execoverlay',(resp)=>{
console.log(resp.msg)
})
})
//contentScript.js
chrome.runtime.onMessage.addListener((request,sender,sendMessage)=>{
if(request==='execoverlay'){
// your code goes here
sendMessage({msg:'recieved'})
}
})

Related

How to use executeScript like a content script in chrome extension

I am using execute script, but it only works when a user clicks on the icon. How can I make it so that it runs when the user moves to a new page like a content script?
I tried calling the function within the page but that also does not work.
const page = () => {
alert("popup");
}
function test(){
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: page
});
});
}
test()//does not work

Manifest v3 inject script from popup.js

In manifest v2 this code worked and injected the script when button was clicked:
popup.js v2 (works)
document.addEventListener('DOMContentLoaded', function () {
// Get button by ID
var button = document.getElementById('btnScan');
// Define button on click action
button.onclick = function () {
chrome.tabs.executeScript(null, {
file: 'Scripts/script.js'
});
window.close();
}
});
Now in manifest v3, chrome.tabs.executeScript is replaced with chrome.scripting.executeScript.
scripting permission is added in manifest.json.
popup.js v3 (not working)
document.addEventListener('DOMContentLoaded', function () {
// Get button by ID
var button = document.getElementById('btnScan');
// Define Scan button on click action
button.onclick = function () {
chrome.scripting.executeScript
(
{
target: { tabId: null}, // ???????
files: ['Scripts/script.js']
}
);
window.close();
}
});
The problem is that chrome.tabs.executeScript requires tabId value as one of the parameters.
How can I get tabId value in popup.js or convert the manifest v2 version javascript so that it works the same?
Thanks to #wOxxOm who posted a link as a comment.
The solution was to get the active tab and use its tabId.
document.addEventListener('DOMContentLoaded', function () {
// Get button by ID
var button = document.getElementById('btnScan');
button.onclick = injectScript;
});
async function injectScript() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
await chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['Scripts/script.js']
});
window.close();
}

chrome.contextmenus how to get html instead of string

I'm new on chrome extension,
I'm creating a basic extension, thats will show the selected html with tags (spans, divs and all other DOMs) on an alert
I try this chrome.contextMenus.create (code below) but it showing just the selected string
chrome.contextMenus.create({title: "Selected HTML", contexts:["selection"], onclick: showSelectedHtml});
I just want to know if theres a way to get selected html doms(with tags if available) instead of string!
Thanks;
As you can see in the documentation contextMenus API can't do that.
The solution is to run a content script that gets the HTML and returns it into your background script.
manifest.json:
"permissions": ["activeTab", "contextMenus"],
"background": {
"scripts": ["background.js"],
"persistent": false
}
background.js:
// in Chrome the menus should be created only at install/update
chrome.runtime.onInstalled.addListener(() => {
chrome.contextMenus.create({
id: 'sel',
title: 'Selected HTML',
contexts: ['selection'],
}, () => chrome.runtime.lastError); // ignore errors about an existing id
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
chrome.tabs.executeScript(tab.id, {
code: `(${getSelectedHtml})()`,
frameId: info.frameId,
matchAboutBlank: true,
runAt: 'document_start',
}, data => {
if (chrome.runtime.lastError) {
alert('Error: ' + chrome.runtime.lastError.message);
} else {
prompt('HTML', data[0]);
}
});
});
// this function's code will be executed as a content script in the web page
function getSelectedHtml() {
const sel = getSelection();
let html;
if (sel.rangeCount) {
const div = document.createElement('div');
div.appendChild(sel.getRangeAt(0).cloneContents());
html = div.innerHTML;
}
return html || '';
}
Note: don't use the onclick property in contextMenus.create() because it doesn't work with "persistent":false background script, which is the preferred type (more info).

How to get iframeId in a contextMenus onclick event handler?

I am developing a Mozilla WebExtension. I want to inject a JavaScript file only into the frame in which I have clicked on the context menu selection created with contextMenus.create().
I am using:
browser.contextMenus.create({
"title": "Records",
"contexts": ["all","link"],
"id" : "M1",
"onclick": onClickContextMenu,
}, function() { });
function onClickContextMenu(info, tab){
var clickedFrameID=""; //How do I get the actual frameId where click occurred?
browser.tabs.executeScript(tab.id,{
file: "fileName.js",
allFrames: false,
frameId: clickedFrameID
}, function() {
console.log("Script injected");
});
}
How to get clickedFrameID?
After Making so many testing me (Chandrakant Thakkar) and my team leader Mr. Nitin Makwana got the solution for this situation,
First I have injected "messageListener.js" file in all frames from manifest.json file as
"content_scripts": [
{
"matches": ["https://*/*","http://*/*"],
"css":["jquery-ui.css"],
"js": [
"jquery.js",
"jquery-ui.js",
"content_scripts/msg_listener.js"
],
"all_frames":true
}
Then in "messageListener.js" file created "contextMenu" Listener and send message to Background js file when I click contextMenu (Right Click Of Mouse)
as
document.addEventListener("contextmenu", handleContextMenu, false);
function handleContextMenu(event){
browser.runtime.sendMessage("abc#gmail.com",{type:
"onContextMenuClicked", sender:event });
}
here, "abc#gmail.com" is id of my web extension where I want to send message.
Then, In my background js file I have declared on global variable named "clickedFrameID" and in same file I have added onMessage Listener as below
browser.runtime.onMessage.addListener(
function(msg, sender, callback) {
if(msg.type === 'onContextMenuClicked')
{
if(sender.hasOwnProperty("frameId")){
clickedFrameID=sender.frameId;
}else{
clickedFrameID="";
}
}
});
Now I have injected "fileName.js" file in specific Frame as Below
var clickedFrameID=""; //This is a Global Variable
browser.contextMenus.create({
"title": "Records",
"contexts": ["all","link"],
"id" : "M1",
"onclick": onClickContextMenu,
}, function() { });
function onClickContextMenu(info, tab){
var options={};
if(clickedFrameID !="" && clickedFrameID!=null &&
clickedFrameID!=undefined )
{
options={
file: "fileName.js",
allFrames: false,
frameId: clickedFrameID
};
}
browser.tabs.executeScript(tab.id,options, function() {
console.log("Script injected");
});
}
Now "fileName.js" will be injected in specific frame in that I have right clicked.
Thanks #wOxxOm, #MohammedAshrafali, #Makyen to take interest

Sending messages from devtools panel to new tab in Chrome extensions

I should send data from my devtools panel to tab. When I send a message using chrome.tabs.sendMessage, why is it not received?
panel.js
$(".options").on("submit", "form", function(e) {
e.preventDefault();
newTabPort = chrome.runtime.connect({ name: "new tab" });
newTabPort.postMessage($(this).serializeArray());
});
background.js
chrome.runtime.onConnect.addListener(function(port) {
port.onMessage.addListener(function(message) {
console.log(message);
});
if (port.name == "new tab") {
chrome.tabs.create({'url': chrome.extension.getURL('page/request_sending_page.html')}, function(tab) {});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var activeTab = tabs[0];
chrome.tabs.sendMessage(activeTab.id, {message: "olololololololo"});
});
}
});
my_extension_page.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
$("body").append("Hello world <br>");
$("body").append(request.message);
});
Thank you!
All Chrome API with function callbacks are asynchronous, so in your code chrome.tabs.create is executed after the entire function code has completed, thus chrome.tabs.query on the next line doesn't see the newly created tab.
Move the code that should work with the result of the asynchronous call into the callback
Wait for the new tab to be completely loaded before sending the message
There's no need for chrome.extension.getURL when you open the tab from background script.
chrome.tabs.create({url: '/page/request_sending_page.html'}, function(tab) {
var newTabId = tab.id;
chrome.tabs.onUpdated.addListener(function onComplete(tabId, info, tab) {
if (tabId == newTabId && info.status == "complete") {
chrome.tabs.onUpdated.removeListener(onComplete);
chrome.tabs.sendMessage(tabId, {message: "olololololololo"});
}
});
});
P.S. manifest.json: "permissions": ["tabs"]

Categories