Chrome extension getSelection not working - javascript

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);
});
});
});
});

Related

Using a value from a textbox input on chrome extension as a variable in my content_scripts

I am trying to set a variable from a user textbox input so all my content_scripts can use it based on the amount that is set. In my case, I have a textbox input that is on my chrome extension. This textbox allows the user to input a number. In each of my content_scripts I have a random number generator function that will change based on the number user inputs in the text box. Ideally, I would like it to be without a set button. Also, I looked online mostly people are using the document.getElementById().value and assign it back to the javascript file, however, I am not getting the value from the DOM, I need to get it from popup.html. All my content_scripts are pretty much the same so I only showed one of them below. Please let me know if you want to see the others.
manifest.json
{
"manifest_version": 2,
"name": "My Page",
"description": "My Page",
"version": "1.0",
"permissions": [
"tabs",
"https://mywebpage.com/*",
"storage"
],
"browser_action": {
"default_icon": {
"30": "images/icons/30.png",
"48": "images/icons/48.png"
},
"default_popup": "popup.html"
},
"icons": {
"16": "images/icons/16.png",
"20": "images/icons/20.png",
"30": "images/icons/30.png",
"48": "images/icons/48.png",
"128": "images/icons/128.png"
}
}
popup.html
<!doctype html>
<html>
<body>
<input type="text" class="delay" name="delay" placeholder="Delay(s)">
<input type="button" value="set" onclick=" ">
<button class ="button button0" button id="clickactivity">Button</button>
<button class ="button button2" button id="clickactivity2">Button</button>
<button class ="button button5" button id="clickactivity5">Button</button>
<script src="popup.js"></script>
</body>
popup.js
function injectTheScript() {
chrome.tabs.query({active: true, currentWindow: true},
function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content_script.js"});
});
var delay = document.getElementById('delay').value; //added
chrome.storage.local.set({'delay': delay}); //added
}
function injectTheScript2() {
chrome.tabs.query({active: true, currentWindow: true},
function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content_script2.js"});
});
}
function injectTheScript5() {
chrome.tabs.query({active: true, currentWindow: true},
function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content_script5.js"});
});
}
document.getElementById('clickactivity').addEventListener('click', injectTheScript);
document.getElementById('clickactivity2').addEventListener('click', injectTheScript2);
document.getElementById('clickactivity5').addEventListener('click', injectTheScript5);
content_script.js:
var delay = ""; //added
chrome.storage.local.get(delay, function(result){ //added
delay = result.delay; //added
console.log("delay is: " + result.delay) //added
});
var userInputNum = //how can I get this value from popup.html
var delayMilliSeconds = Math.floor((Math.random() * userInputNum) + 1)
function outputNumber() {
console.log ("your variable is: " + userInputNum );
}
outputNumber();

sendMessage not working in chrome extension

I am trying to make a simple chrome extension. I'd be glad if someone can help.
Objective: When you click the button in extension popup (popup.html), the title of current webpage is displayed in div (with id 'div1').
Problem: I have searched internet for doing this and found that passing message can be used to achieve the same. So I tried my hands on it. But its not working. I want to know what went wrong.
Status:
= The extension is successfully imported in chrome.
= when extension icon is clicked, it shows proper popup.
= when button is clicked nothing happens.
= developer console shows no error.
Files:
=====================================
//manifest.json
{
"manifest_version": 2,
"name": "some_name_extension",
"version": "0.0.1",
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.2.1.js", "content_script.js"]
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
}
}
=====================================
<!-- popup.html -->
<! doctype html>
<html>
<head>
<title>
</title>
<script type="text/javascript" src="popup.js">
</script>
<style>
html
{
height: 200;
width: 200;
}
</style>
</head>
<body>
<button id="btn1">
click me!
</button>
<div id="div1">
(title will be displayed here)
</div>
</body>
</html>
=====================================
//content_script.js
document.addEventListener('DOMContentLoaded', function() {
var title1=document.getElementsByTagName("title")[0].innerHTML;
chrome.extension.onMessage.addListener(
function(msg, sender, sendResponse) {
if(sender=="popup")
{
chrome.extension.sendMessage(title1,"content","1");
}
});
});
=====================================
//popup.js
document.addEventListener('DOMContentLoaded', function() {
var mainBtn = document.getElementById('btn1');
mainBtn.addEventListener('click', function() {
chrome.extension.sendMessage("button_clicked","popup","1");
});
chrome.extension.onMessage.addListener(
function(msg, sender, sendResponse) {
if(sender=="content")
{
document.getElementById("div1").innerHTML=msg;
}
}
);
});
=====================================
link to jquery script file : https://code.jquery.com/jquery-3.2.1.js
sender is an object that's set by the browser automatically, not a string that you can pass yourself. Use the devtools debugger to inspect your code and variables by setting breakpoints inside the callbacks, don't write the code blindly.
There's no need to check the sender in this case because content scripts cannot message each other anyway.
The correct method of sending a message to a content script from the popup is chrome.tabs.sendMessage with tabId as the first parameter:
chrome.tabs.query({active: true, currentWindow: true}, ([tab]) => {
chrome.tabs.sendMessage(tab.id, {
action: 'setTitle',
title: title1,
});
});
To send many values at once use an object: {action: 'setTitle', title: title1} or {action: 'buttonClicked', data: 1} and so on.
chrome.extension is deprecated for messaging, use chrome.runtime
Your code doesn't use jQuery so there's no need to inject it in manifest.json

chrome.tabs.query not executing

My js code just doesnt execute the chrome.tabs.query line. When I went through it stepwise over the debugger it will immediately go to the next executing statement ie return. I looked this up and I understand that this is an asynchronous call but even after waiting the debugger or alert inside the chrome.tabs.query just wouldn't hit. Please help.
/*
Given the name of a beast, get the URL to the corresponding image.
*/
debugger;
function beastNameToURL(beastName) {
switch (beastName) {
case "Save Session":
debugger;
chrome.tabs.query({currentWindow: true}, function(tabs) {
debugger;
alert("1");
tabs.forEach(function(tab){
unsafeWindow.console.log("helllllloooooooooooooooooo");
unsafeWindow.console.log(tab.url);
});
for (var tab of tabs) {
if (tab.active) {
console.log(tab.url);
}
}
});
return;
case "Load Session":
debugger;
return chrome.extension.getURL("beasts/snake.jpg");
case "Turtle":
return chrome.extension.getURL("beasts/turtle.jpg");
}
}
/*
Listen for clicks in the popup.
If the click is not on one of the beasts, return early.
Otherwise, the text content of the node is the name of the beast we want.
Inject the "beastify.js" content script in the active tab.
Then get the active tab and send "beastify.js" a message
containing the URL to the chosen beast's image.
*/
document.addEventListener("click", function(e) {
if (!e.target.classList.contains("btn")) {
return;
}
var chosenBeast = e.target.textContent;
var chosenBeastURL = beastNameToURL(chosenBeast);
chrome.tabs.executeScript(null, {
file: "/content_scripts/beastify.js"
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
});
});
I have also given permissions to tabs in the manifest.
{
"manifest_version": 2,
"name": "Session",
"version": "1.0",
"description": "Adds a browser action icon to the toolbar. Click the button to choose a beast. The active tab's body content is then replaced with a picture of the chosen beast. See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Examples#beastify",
"homepage_url": "https://github.com/mdn/webextensions-examples/tree/master/beastify",
"icons": {
"48": "icons/beasts-48.png"
},
"applications": {
"gecko": {
"id": "beastify#mozilla.org",
"strict_min_version": "45.0"
}
},
"permissions": [
"activeTab",
"tabs"
],
"browser_action": {
"default_icon": "icons/beasts-32.png",
"default_title": "Session",
"default_popup": "popup/choose_beast.html"
},
"web_accessible_resources": [
"beasts/frog.jpg",
"beasts/turtle.jpg",
"beasts/snake.jpg"
]
}

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.

Content.js script never called to count table rows and refresh page

I am making a chrome extension with two buttons : Start and Stop. On click of start button the html page, should start refreshing after a particular timer, and on click of stop it should stop refreshing.
The HTML page has a table in it say with id myTable.So after every refresh, I want to have row count of this table.
To get this I did something like this :
First for pop up, I made popup.js
window.onload = function() {
document.getElementById("startbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_start"
});
}
document.getElementById("stopbutton").onclick = function() {
chrome.extension.sendMessage({
type: "table-row-count_stop"
});
}
}
In 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.getSelected(null, function(tab){
chrome.tabs.sendMessage(tab.id, {type: "table-row-count"});
chrome.browserAction.setBadgeText({text: "Counting!"});
});
}
This will make call to content.js as we need to interact with DOM of HTML page. In this script I did something like this :
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
switch(message.type) {
case "table-row-count":
var x = document.getElementById("myTable").rows.length;
alert("Row count = " + x);
var Refresh = confirm("Do you want to refresh the page?");
if (Refresh)
{
setTimeout("location.reload(true);",5000);
}
break;
}
});
The script content.js is never called. I don't know why so. Please help.
Also it will be refreshing only once, how to keep refershing after fixed timer.
Here is manifest.json
{
"name": "Refresher",
"version": "0.0.1",
"manifest_version": 2,
"description" : "Refresh the site contents after a while",
"icons": { "32": "icon.jpg" },
"browser_action": {
"default_icon": { "32": "icon.jpg" },
"default_title": "Refersher",
"default_popup": "browseraction/popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": true
},
"content_scripts": [{
"matches": ["http://www.w3schools.com/html/tryit.asp?filename=tryhtml_table"],
"js": ["content.js"]
}]
}
In this case you've used a deprecated chrome.tabs.getSelected which returned the wrong tab with id -1 so the message was never delivered and an error was displayed in the console.
Use chrome.tabs.query:
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!"});
});
};
Also note how setBadgeText was used just for the specified tab.
N.B. Always, always use the debugger to check what's wrong. Thus you can stop using alert and start using console.log or inspect/watch the variables in the debugger.

Categories