beginner to chrome extension - javascript

I am trying to learn chrome extensions and I am trying to build a simple one which tries to find if there are forms or not in webpage.
My code is as simple as possible and the following snippet is content script - javascript.js and popup page - index.html.
function sendMessage() {
chrome.extension.sendMessage({
action: "findurls"
});
}
document.addEventListener('DOMContentLoaded', function () {
var show = document.getElementById('show');
show.addEventListener('click', findValidForms);
});
const findValidForms = () => {
let list = [];
let message = "Available forms are: \n ";
let forms = document.querySelectorAll('form');
if (forms.length > 0) {
for (var i = 0; i < forms.length; i++) {
list.push(forms[i].action);
message += `${list[i]}<br />`;
}
}
else {
message = "no forms";
}
alert(message);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>testing</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="cgi">
<div class="heading">
<h3 center> Test title </h3>
</div>
<div id='ah!'> </div>
<button id='show'>find forms</button>
<script src="jquery-3.5.0.min.js"></script>
<script type="text/javascript" src="javascript.js"></script>
</body>
</html>
manifest:
"manifest_version": 2,
"name": "form",
"version": "1.0",
"description": "find form url ",
"icons": {
"16": "chrome_16.png",
"32": "chrome_32.png"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"javascript.js",
"jquery-3.5.0.min.js"
],
"css": [
"style.css"
]
}
],
"browser_action": {
"default_icon": "chrome_16.png",
"default_popup":"index.html",
"default_title": "test"
},
"permissions": [
"activeTab"
]
}
background.js:
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse)
{
if (request.action == "findurls")
chrome.tabs.executeScript({ file: 'test.js' });
}
);
Thanks

Clicked the button placed in index.html, the extension should send a message to content script - javascript.js in your solution. So the content script needs a event listener that monitors the message triggered from background script. Once it's arrived, the corresponding method should be executed.
Here is the quick link to resolve but let me briefly describe here.
Create a js file (ie index.js) and inject into your index.html. (honestly, popup.html and popup.js will be better than the current name - index). Give this code into the index.js
In your content script - index.js, add the code to listen message sent from the popup page's script (index.js) with handler the current function you created. (Original function name was Forms)
popup.js
const sendMessage = () => {
chrome.tabs.query(
{
active: true,
currentWindow: true
}, (tabs) => {
chrome.tabs.sendMessage(
tabs[0].id,
{
action: "get-urls"
}, (response) => {
console.log(response)
}
);
}
);
}
document.addEventListener('DOMContentLoaded', function () {
var geturls = document.getElementById('btn-get-urls');
geturls.addEventListener('click', sendMessage);
});
content_script.js
const FindAllForms = () => {
let list = [],
message = "Available forms are: \n ",
availableForms = document.querySelectorAll('form');
if (availableForms.length > 0) {
for (var i = 0; i < availableForms.length; i++) {
list.push(availableForms[i].action);
message += "" + list[i] + "" + "\n";
}
}
else {
message = "no forms";
}
alert(message);
}
chrome.extension.onMessage.addListener(
(request, sender, sendResponse) => {
if (request.action == "get-urls") {
FindAllForms()
sendResponse({'success': true})
}
}
);
In the popup script, you should send a message to current/active tab's content script as this answer.
I hope this will help you.
Thank you

Related

Send message to background.js from options.js in Chrome Extension

I can find plenty of questions for sending a message from Bbackground to content scripts or from popup to background scripts, but I can't find any on how to send a message from options.js (triggered from my options page) to background.js for my Chrome extension
manifest.js
{
...
"manifest_version": 3,
"permissions": [
"alarms",
"contextMenus",
"notifications",
"storage"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"options_page": "options.html",
"icons": {
"48": "/assets/icons/icon-48.png",
"128": "/assets/icons/icon-128.png"
}
}
Code in options.js
// Save options
document.querySelector('#save').addEventListener('click', ()=> {
// Check for selected regions
let selectedRegions = [];
regionChecks.forEach(elm => {
if (elm.checked)
selectedRegions.push(elm.id.replace('region-', ''))
});
// Save selections
chrome.storage.sync.set({ 'regions': selectedRegions });
// Check for refresh period
let refreshPeriod = document.querySelector('#refresh');
if (refreshPeriod) {
refreshPeriod = parseInt(refreshPeriod.value);
if (refreshPeriod === NaN) {
refreshPeriod = 5;
} else if(refreshPeriod < 2) {
refreshPeriod = 2;
} else if (refreshPeriod > 120) {
refreshPeriod = 120;
}
// Save period
chrome.storage.sync.set({ 'refresh': refreshPeriod });
}
// Loop through features and remove if region gone
chrome.storage.local.get(['features'], featuresData => {
let featureCount = 0;
if (featuresData.features) {
featureSet = featuresData.features;
Object.keys(featureSet).forEach(key => {
if (!selectedRegions.includes(featureSet[key].Region)) {
delete featureSet[key];
} else if (featureSet[key].Status !== "read") {
featureCount = featureCount + 1;
}
});
// Update features data
chrome.storage.local.set({ 'features': featureSet });
// Update the badge
if (featureCount > 0) {
chrome.action.setBadgeText({ text: featureCount.toString() });
} else {
chrome.action.setBadgeText({ text: '' });
}
}
});
// Trigger an update
chrome.runtime.sendMessage('', {
type: 'update'
});
// Close the options page
close();
});
Code in background.js
// Listen for messages
chrome.runtime.onMessage.addListener(data => {
console.log(data);
if (data.type === 'update') {
scheduleRequest();
}
});
But nothing is happening
I've tried using tabs.sendMessage, but even if I put tabs in permissions it tells me that it isn't defined when I add it to the function chrome.tabs.sendMessage(tabs[0].id, {...
My test results contradict your claim.
manifest.json
{
"manifest_version": 3,
"name": "hoge",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"options_page": "options.html"
}
background.js
// Listen for messages
chrome.runtime.onMessage.addListener(data => {
console.log(data);
if (data.type === 'update') {
console.log("hoge")
// scheduleRequest();
}
});
options.js
// Trigger an update
chrome.runtime.sendMessage('', {
type: 'update'
});
options.html
<html>
<body>
options page
<script src="options.js"></script>
</body>
</html>
After some input from #woxxom and #Norio, and a little bit more troubleshooting, this is how I managed to get it to work
option.js:
// Trigger an update
chrome.runtime.sendMessage({ type: 'update' }, result => {
// Close the options page
close();
});
I had to move the close(); event into the return function so it didn't prematurely close off the code. I also had to have a paramter in the return function for some reason otherwise it wouldn't run with an empty arrow function.
background.js:
// Listen for messages
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.type === 'update') {
startRequest(true).then(sendResponse);
return true;
}
});
My function to be triggered in the background.js file was already an async promise function, so I had to add a .then() for the onMessage response function to trigger once it had run. It also wouldn't work without having return true; in there.

setTimeout to chrome.scripting.executeScript

I was trying to set Timeout to my extension popup .I see after the work is done, it doesn't get automatically closed until clicked on somewhere on the page. I was trying to set timeout for auto closing of my extension popup. Below is my code.
a.addEventListener("click", async () => {
button.style.backgroundColor = 'white';
document.getElementById("button").style.backgroundColor = 'white';
chrome.scripting.executeScript({
target: { tabId: tab.id },
func: codeWork,
});
});
I followed many suggestions available but it is throwing the error shown in Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in Content Security Pol
Please help me on how to set timer to my popup function.
Also my func:codeWork return response. The response might contain error. I want to change the color of the button based on the response . How to do that ?
Any help is really appreciated!!!!
This is the answer to the first question.
This sample popup will automatically close after 10 seconds.
popup.js
const elmCounter = document.getElementById("counter");
counter();
async function counter() {
for (let i = 0; i < 10; i++) {
elmCounter.innerText = i;
await new Promise(r => setTimeout(r, 1000));
}
window.close();
}
popup.html
<!DOCTYPE html>
<html>
<body>
<div id="counter">
<script src="popup.js"></script>
</body>
</html>
manifest.json
{
"name": "hoge",
"version": "1.0",
"manifest_version": 3,
"action": {
"default_popup": "popup.html"
}
}
This is the answer to the second question.
popup.js
const elmExec = document.getElementById("exec");
elmExec.onclick = async () => {
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
await chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: func
});
}
const func = () => {
const color = ["red", "blue", "green"];
const getRandomInt = (max) => {
return Math.floor(Math.random() * max);
}
chrome.runtime.sendMessage({ color: color[getRandomInt(3)] });
}
chrome.runtime.onMessage.addListener((message) => {
elmExec.style.backgroundColor = message.color;
});
popup.html
<!DOCTYPE html>
<html>
<body>
<div id="counter">
<input type="button" id="exec" value="exec">
<script src="popup.js"></script>
</body>
</html>
manifest.json
{
"name": "hogehoge",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"activeTab",
"scripting"
],
"action": {
"default_popup": "popup.html"
}
}

How to pass the highlighted element to the popup.js file so that I can manipulate it to make changes

manifest file for the extension
{
"manifest_version": 2,
"name": "Bookmarker",
"version": "1.0",
"description": "Bookmark pages so that you can continue reading it next time",
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"permissions": ["activeTab"]
}
content.js file where i am getting the highlighted element but am not able to pass it to the popup.js file
// Look for a "mouse up event"
document.addEventListener('mouseup', selectedText);
// Handle the mouse up event
function selectedText(event) {
// See what text has been selected by the user
var selected = window.getSelection().anchorNode.parentNode;
console.log(selected);
// Make sure something actually was selected
// if (selected.length > 0) {
// Send the message to the background script
// Can't be sent to the pop-up as the pop-up might
// not be open
chrome.runtime.sendMessage({ word: selected });
// } else {
// console.log('error');
// }
}
receiving message from the content.js file and passing it to the popup.js file
// Listen for messages
chrome.runtime.onMessage.addListener(receiver);
// A "global" variable to store the word selected by the user
var word;
// Get the message from the content script
function receiver(request, sender, sendResponse) {
// Save the word
word = request.word;
}
console.log(word);
popup.html template for the extension
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<h1 id="h">Bookmark curent location</h1>
<button id="highlight">highlight</button>
<script src="popup.js"></script>
</body>
</html>
popup.js file where I want to manipulate the highlighted element through dom methods
var word = chrome.extension.getBackgroundPage().word;
console.log(word);
// const selectedButton = document.getElementById('highlight');
// const heading = document.getElementById('h');
// selectedButton.addEventListener('click', () => {});

Chrome extension getSelection not working

I am trying to create a chrome extension which only consist of a button. When this button is clicked, it should make an alert box which contains the highlighted textarea on a page. I can't get it to work. I can make it alert a hardcoded string, but not make it alert some highlighted text / selected textarea on a page.
Here is the javascript code popup.js:
document.addEventListener('DOMContentLoaded', function() {
test.addEventListener('click', function() {
var selObj = document.getSelection();
alert(selObj);
}, false);
}, false);
manifest.json
{
"manifest_version": 2,
"name": "test ",
"description": "test",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab"
]
}
popup.html
<
!doctype html>
<html>
<head>
<title>Test</title>
<script src="popup.js"></script>
</head>
<body>
<h1>Test</h1>
<button id="test">Test</button>
</body>
</html>
You could fetch the selection by loading a script into the page using the executeScript method in the Tabs API. You may have to add the tabs permission to your manifest.json.
To execute the script you first need to fetch the tab ID, you can do that using query and querying on fetching the active tab in the current window.
document.addEventListener('DOMContentLoaded', function() {
const test = document.querySelector('#test');
test.addEventListener('click', function() {
chrome.tabs.query({ currentWindow: true, active: true }, (tabs) => {
chrome.tabs.executeScript(tabs[0].id, { code: `document.getSelection().toString()` }, (result) => {
alert(result);
});
});
});
});

Removing the injected script through the chrome extension

I'm building a chrome dev tool extension to capture page elements and store. For now, I'm able to capture the page element by using click method in the content script which I've injected. To send the captured element from content script to background script, I used stopPropagation and preventDefault methods to disable the click event on the element.
Problem Statement: Now I would like to revert to the element's default event after selecting an element. This is where I'm stuck on how to revert back.
manifest.json:
{
"name": "My app",
"version": "0.0.1",
"description": "My app",
"manifest_version": 2,
"devtools_page": "devtools.html",
"background": {
"scripts": [
"background.js"
]
},
"permissions": [
"tabs",
"http://*/*",
"https://*/*",
"file://*/*"
]
}
The devtools.html has devtools.js script which creates the new tab panel in chrome dev tools and loads the panel.html.
panel.html:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<button id="insertscript">Insert script</button>
<button id="clearscript">Clear Script</button>
<input type="text" id="tagName" />
<script src="panel.js"></script>
<script src="background.js"></script>
</body>
</html>
panel.js:
(function createChannel() {
var port = chrome.extension.connect({
name: "Sample Communication" //Given a Name
});
port.onMessage.addListener(function (message) {
document.querySelector('#tagName').value = message.tagName;
});
}());
function sendObjectToInspectedPage(message) {
message.tabId = chrome.devtools.inspectedWindow.tabId;
chrome.extension.sendMessage(message);
}
document.querySelector('#insertscript').addEventListener('click', function() {
sendObjectToInspectedPage({action: "script", content: "selectitem.js"});
}, false);
document.querySelector('#clearscript').addEventListener('click', function() {
sendObjectToInspectedPage({action: "clear-script", content: "clearscript.js"});
}, false);
background.js:
chrome.extension.onConnect.addListener(function (port) {
var extensionListener = function(message, sender, sendResponse) {
if (message.tabId && message.content) {
// Attach a script to inspected page
if (message.action === "script") {
chrome.tabs.executeScript(message.tabId, {file: "assets/jquery-2.0.3.js"});
chrome.tabs.executeScript(message.tabId, {file: message.content});
} else if (message.action === "clear-script") {
chrome.tabs.executeScript(message.tabId, {code: "document.removeEventListener('click', onClick);"});
}
} else {
port.postMessage(message);
}
if (message.type === "selectedElement") {
sendResponse(message);
}
};
chrome.extension.onMessage.addListener(extensionListener);
port.onDisconnect.addListener(function(port) {
chrome.extension.onMessage.removeListener(extensionListener);
});
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
return true;
});
selectitem.js:
function onClick(evt) {
evt.stopPropagation();
evt.preventDefault();
var elem = document.elementFromPoint(evt.clientX, evt.clientY);
chrome.extension.sendMessage({
type: "selectedElement",
tagName: elem.tagName
});
}
document.addEventListener('click', onClick, true);
Now when I click on Clear script method, I wanted to remove the stopPropagation and preventDefault which I added in selectitem.js. Because the element which I've selected could be an Anchor tag or Button or can be anything which is clickable.
I don't know on how to do this.
I found the solution with the help of this script: https://github.com/oldprojects/Simple-JavaScript-DOM-Inspector/blob/master/inspector.js
Thought this might be helpful for anyone, hence adding this as an answer.

Categories