Accessing the source of one tab in the extension's tab - javascript

I need to get the source code of the Active Tab when the extension icon is clicked; it needs to be visible in a new tab (because a pop up is limited to 800px, among other reasons).
I had no issue with this when I was using a popup, however, I now want to get the data into a new tab.
What is happening is the targetTab variable used in the onClicked callback contains the correct tab information. However, once the new tab (popup.html) is opened, nothing occurs; the document.body.innerHTML does not get changed.
Any ideas?
manifest.json
{
"name": "Stock Alert",
"description": "Create an alert and display streaming stock quotes.",
"version": "1.1",
"permissions": [
"https://www.gwm.ml.wallst.com/",
"https://*/*",
"http://*/*",
"tabs",
"activeTab"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_icon": "logo.png"
},
"manifest_version": 2
}
background.js
chrome.browserAction.onClicked.addListener(function(targetTab) {
chrome.tabs.create({'url': chrome.extension.getURL('popup.html')}, function(tab)
{
chrome.tabs.executeScript(
targetTab.id,
{
code: "document.getElementsByTagName('html')[0].innerHTML;"
},
function (sourceCode)
{
document.getElementById('dump').innerHTML = sourceCode;
});
});
});
popup.html (misnomer; this is the url of the new tab created onClicked)
<html>
<head>
<title>Stock Tracker</title>
<!--<script src="background.js"></script>-->
<link href="Streamer.css.package.css" rel="stylesheet" type="text/css">
</head>
<body>
<div id="out"></div>
<div id="dump"></div>
</body>
</html>

The issue is that the callback function is executed within the background page context. It will therefore try to find <div id="dump"></div> inside that page, rather than inside the popup page.
I've fiddled around, and I've came up with the following solution.
On click, get the content of the current page
Store that content in the background page
Load the popup.html
On load, get the code content from the background page
background.js
var myCode;
chrome.browserAction.onClicked.addListener(function(targetTab) {
chrome.tabs.executeScript(
targetTab.id,
{
code: "document.getElementsByTagName('html')[0].innerHTML;"
},
function (sourceCode)
{
myCode = sourceCode;
chrome.tabs.create({'url': chrome.extension.getURL('popup.html')});
});
});
popup.html
Add <script src="popup.js"></script>
popup.js
chrome.runtime.getBackgroundPage(function(bg)
{
document.getElementById('dump').innerHTML = bg.myCode;
});

Related

How to edit HTML of popup.html dynamically (Google Chrome Extension)? [duplicate]

I'm trying to create a Chrome extenstion that allows the user to get the selected text of a web page after clicking on a button and then log this text in the console.
But my code is working only if the text is selected from the HTML pop-up.
If i select a text from a random webpage and then click the "Save" button, then a blank line is printed in the console.
I guess my content.js file is not able to interact with the web page when the extension popup is displayed but I don't know how to resolve that. I know there are other similar questions but nothing I tried (message passing between different .js files for example) worked.
Here are my files :
manifest.json :
{
"manifest_version": 3,
"version": "1.0",
"name": "test",
"action": {
"default_popup": "index.html"
},
"permissions": [
"tabs",
"notifications"
],
"content_scripts": [
{ "matches": ["<all_urls>"],
"js" : ["content.js"]}
],
"background":
{
"service_worker": "background.js"
}}
index.html :
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
<p>Just some text.</p>
<button id="save-btn">SAVE SELECTION</button>
<script src="content.js"></script>
</body>
</html>
content.js :
const saveBtn = document.getElementById("save-btn")
saveBtn.addEventListener("click", function(){
console.log(window.getSelection().toString())
})
Remove content.js from index.html. Content scripts are for web pages, not for extension pages such as the popup.
Create index.js and load it in index.html:
<script src="index.js"></script>
</body>
index.js:
document.getElementById("save-btn").onclick = async () => {
const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
let result;
try {
[{result}] = await chrome.scripting.executeScript({
target: {tabId: tab.id},
function: () => getSelection().toString(),
});
} catch (e) {
return; // ignoring an unsupported page like chrome://extensions
}
document.body.append('Selection: ' + result);
};
edit manifest.json to allow code injection in the active tab on click:
"permissions": ["scripting", "activeTab"]
Note that the popup is a separate window so it has its own separate devtools and console: right-click inside the popup and select "inspect" in the menu.

Getting selected text in a Chrome extension

I'm trying to create a Chrome extenstion that allows the user to get the selected text of a web page after clicking on a button and then log this text in the console.
But my code is working only if the text is selected from the HTML pop-up.
If i select a text from a random webpage and then click the "Save" button, then a blank line is printed in the console.
I guess my content.js file is not able to interact with the web page when the extension popup is displayed but I don't know how to resolve that. I know there are other similar questions but nothing I tried (message passing between different .js files for example) worked.
Here are my files :
manifest.json :
{
"manifest_version": 3,
"version": "1.0",
"name": "test",
"action": {
"default_popup": "index.html"
},
"permissions": [
"tabs",
"notifications"
],
"content_scripts": [
{ "matches": ["<all_urls>"],
"js" : ["content.js"]}
],
"background":
{
"service_worker": "background.js"
}}
index.html :
<html>
<head>
<link rel="stylesheet" href="index.css">
</head>
<body>
<p>Just some text.</p>
<button id="save-btn">SAVE SELECTION</button>
<script src="content.js"></script>
</body>
</html>
content.js :
const saveBtn = document.getElementById("save-btn")
saveBtn.addEventListener("click", function(){
console.log(window.getSelection().toString())
})
Remove content.js from index.html. Content scripts are for web pages, not for extension pages such as the popup.
Create index.js and load it in index.html:
<script src="index.js"></script>
</body>
index.js:
document.getElementById("save-btn").onclick = async () => {
const [tab] = await chrome.tabs.query({active: true, currentWindow: true});
let result;
try {
[{result}] = await chrome.scripting.executeScript({
target: {tabId: tab.id},
function: () => getSelection().toString(),
});
} catch (e) {
return; // ignoring an unsupported page like chrome://extensions
}
document.body.append('Selection: ' + result);
};
edit manifest.json to allow code injection in the active tab on click:
"permissions": ["scripting", "activeTab"]
Note that the popup is a separate window so it has its own separate devtools and console: right-click inside the popup and select "inspect" in the menu.

Chrome extension working on two tabs

I am trying to create a Chrome extension that retrieves some content from the DOM of the current tab, then opens a new tab, and performs an operation on this new tab using the previously retrieved content.
I am attempting to use callbacks to perform this sequence, but I can't figure out a proper way to do it. Now I am able to execute the first script, and get the content from the current tab DOM: what I still can't do is passing this content to the second script, utilities2.js, to be executed on the new tab.
Here's my current code:
popup.html
<!doctype html>
<html>
<head><title>Extension</title></head>
<body>
<button id="clickactivity">Click here</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
function injectTheScript() {
var tempStorage;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "content_script.js"}, function(results){
tempStorage = results[0];
});
chrome.tabs.create({"url":"http://www.google.com","selected":true}, function(tab) {
});
});
}
document.getElementById('clickactivity').addEventListener('click', injectTheScript);
contentScript.js
function execContentScript() {
var code = document.getElementById('textarea').value;
return code;
}
execContentScript();
manifest.json
{
"manifest_version": 2,
"name": "My extension",
"description": "My extension",
"version": "1.0",
"permissions": ["tabs", "<all_urls>","activeTab"],
"browser_action": {
"default_popup": "popup.html"
}
}
You can store the content in the local storage of Chrome extension and after navigating to next tab, you can get the content from local storage of Chrome.
The following code may help you in this case:
chrome.storage.local.set({key: value}, function() {
console.log('Value is set to ' + value);
});
chrome.storage.local.get(['key'], function(result) {
console.log('Value currently is ' + result.key);
});
If you want to learn more about the local storage of Chrome, please read from here.
Edit:
I think you don't have idea of background scripts in the Chrome extension. Background scripts which have highest privileges to run the Chrome commands.
The complete workflow will be as follows:
popup.js is included as script
When you click button, injectTheScript function will be called from popup.js
Then it will get the element id from page and then send the request to background.js
Then background.js will save the value to Chrome storage
Then background.js will create new tab
After successful creation of tab, it will execute callback function and get the value from storage of Chrome
The following is the complete code of working extension:
manifest.json
{
"manifest_version": 2,
"name": "My extension",
"description": "My extension",
"version": "1.0",
"permissions": ["tabs", "<all_urls>","activeTab","storage"],
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
popup.html
<!doctype html>
<html>
<head><
title>Extension</title>
</head>
<body>
<button id="clickactivity">Click here</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
function injectTheScript() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var code="abc";
//var code = document.getElementById('textarea').value;
chrome.runtime.sendMessage({type: "navigate",value:code}, function(response) {
console.log('code saved to local storage');
});
});
}
document.getElementById('clickactivity').addEventListener('click', injectTheScript);
background.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.type == "navigate"){
chrome.storage.sync.set({key: request.value}, function() {
console.log('Background got request for saving the code '+request.value+' to local storage');
chrome.tabs.create({"url":"http://www.google.com","selected":true}, function( tab) {
console.log('navigated to new tab');
chrome.storage.sync.get(['key'], function(result) {
console.log('new tab key is '+result.key);
});
});
});
}
});
You don't need utilities2.js and content_script.js.
I've tested the code and it's working according to your requirements.
You can not see the console output if anything is consoled in background page. To see the output on console (for anything in background), open the link chrome://extensions
and click the button Background Page as following
A new window will appear as following

Chrome Plugin Context Menu behaves differently when Plugin is being inspected

I'm working on a Google Chrome extension that stores some values in local storage when a context menu item is clicked. I'm noticing however, that the behavior of the extension is different depending on if is being inspected or not. An example plugin is as follows:
manifest.json
{
"manifest_version": 2,
"name": "contextMenuTest",
"description": "contextMenuTest",
"version": "0.1",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"activeTab",
"storage",
"unlimitedStorage",
"contextMenus",
"notifications"
],
"icons": {
"16": "icon.png"
}
}
popup.html
<!doctype html>
<html>
<head>
<script src= "popup.js"></script>
</head>
<body>
<button id="setContextMenuButton">Set context menu</button>
<button id="showResultButton">Show Answer</button>
</body>
</html>
popup.js
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("setContextMenuButton").addEventListener("click", onsetcontextmenubuttonclick);
document.getElementById("showResultButton").addEventListener("click", onshowresultbuttonclick);
});
function onsetcontextmenubuttonclick() {
chrome.storage.local.clear(function() {
chrome.contextMenus.removeAll(function() {
chrome.contextMenus.create(
{
"title": "test",
"contexts": ["selection"],
"onclick": function(info, tab) {
chrome.storage.local.set({"test":"test"});
}
}
);
});
});
}
function onshowresultbuttonclick() {
chrome.storage.local.get("test", function(items) {
console.log(items);
});
}
The expected behavior occurs when inspecting the popup: inspect the popup, click the "Set Context Menu" button, select some text and right click it, click "test" in the context menu, then inspect the popup and click the "Show Answer" button. chrome.storage.local.set() set the value for "test", so chrome.storage.local.get() is able to retrieve it properly and display {test: "test"}.
However, when carrying out the same steps without the first step of inspecting the popup, {} is displayed instead, implying that chrome.storage.local.set() did not properly set the value for "test" when the popup was not being inspected.
There is a similar question here, but it didn't quite answer my question.
Why would the context menu behave differently depending on if the plugin is being inspected or not, and how would I fix this?

Chrome extension to change DOM with a button in extension popup

i am completely new to chrome extension development.
I am trying to change the DOM (append data to active webpage) when clicked on a button in the extension popup. How is this possible.
the manifest file
{
"manifest_version": 2,
"name": "test 2",
"description": "test ext 2",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js": ["jquery.min.js", "main.js"]
}
],
"permissions": [
"activeTab"
]
}
suppose if the popup.html file is
<!doctype html>
<html>
<head>
<title>test extension 2</title>
<script src="popup.js"></script>
</head>
<body>
<a id="button">button</a>
</body>
</html>
and when i click on #button, i want to execute some jquery code in main.js file which will append some data to the active webpage.
Thank you.
Use Programmatic injection. You could register event listener in popup.js and call chrome.tabs.executeScript to inject some js code/file to current active tab. This requires host permissions.
popup.js
document.getElementById('button').addEventListener('click', function() {
chrome.tabs.query({ active: true, currentWindow: true}, function(activeTabs) {
// WAY 1
chrome.tabs.executeScript(activeTabs[0].id, { code: 'YOUR CODE HERE' });
});
});
Use Message Passing. You could call chrome.tabs.sendMessage in popup.js and listen to that via chrome.runtime.onMessage in content.js.
popup.js
// WAY 2 (Replace WAY1 with following line)
chrome.tabs.sendMessage(activeTabs[0].id, { action: 'executeCode' });
content.js
chrome.runtime.onMessage.addListener(function(request) {
if(request.action === 'executeCode') {
// YOUR CODE HERE
}
});
Use Storage. You could call chrome.storage.local.set in popup.js and listen to storage change in content.js via chrome.storage.onChanged.
popup.js
// WAY 3 (Replace WAY1 with following line)
chrome.storage.local.set({ action: 'executeCode' });
content.js
chrome.storage.onChanged.addListener(function(changes) {
var action = changes['action'];
if(action.newValue === 'executeCode') {
// YOUR CODE HERE
}
});

Categories

Resources