I'm migrating my v2 extension to v3. Now, the first thing that is not clear to me is how the content script is loaded into the page. I've implemented it as follows (background script):
chrome.action.onClicked.addListener(tab => {
chrome.windows.create({
// Just use the full URL if you need to open an external page
url: chrome.runtime.getURL("hello.html"),
type: "panel", height: 200, width:200
}, (win) => {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
const currTab = tabs[0];
if (currTab) {
chrome.scripting.executeScript({
target: {tabId: currTab.id},
files: ['/content.js'],
}, () => { });
}
});
});
});
I think that this example is my best attempt :)
So, when I run this code I get the following error in the console:
Unchecked runtime.lastError: Cannot access contents of url "". Extension manifest must request permission to access this host.
Here is my manifest:
{
"name": "Hello, World!",
"version": "1.0",
"manifest_version": 3,
"background": { "service_worker": "background.js" },
"action": {
"default_icon": {
"16": "icon16.png"
}
},
"permissions": [
"tabs",
"bookmarks",
"unlimitedStorage",
"activeTab",
"scripting"
],
"optional_permissions": [],
"host_permissions": [
"*://*/*"
],
"web_accessible_resources": [
{
"resources": ["/content.js"],
"matches": [],
"extension_ids": [],
"use_dynamic_url": true
}
]
}
If I'm on the right path here, there must be something missing in my manifest. Any suggestions?
try the following :-
chrome.action.onClicked.addListener(insertScript)
async function insertScript() {
tabId = await getTabId();
chrome.scripting.executeScript({
target: {tabId: tabId}
files: ['/content.js']
})
}
async function getTabId() {
var tabs = await chrome.tabs.query({active: true, currentWindow: true});
return tabs[0].id;
}
Related
In my extension I have a button in a popup.js file that runs a listener for a button press and sends a command to a content.js file.
document.querySelector('#btn').addEventListener('click', () => {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) =>
chrome.tabs.sendMessage(tabs[0].id, { command: 'getClientName' })
);
});
My content.js file is a little involved and grabs some information off the page to copy to the clipbaord, but for purposes of my problem I just need a listener to wait for the command "getClientName" then save a value to the clipboard like below.
chrome.runtime.onMessage.addListener((msg, sender, response) => {
navigator.clipboard.writeText("I did it 2!")
.then(() => {alert("I did it 2!");
})
.catch(() => {
alert("I didn't it 2");
})
});
However, I cannot get navigator.clipboard.writeText() to work from the content.js page. It will only work if I run it directly from popup.js, which doesn't really work since I need to pull information off the page.
Right now it gets sent to .catch() and sends me the error message.
Manifest (replaced the actual URL in my manifest with "all" for privacy reasons):
{
"manifest_version": 3,
"name": "The Magic Button",
"version": "1.0.0",
"description": "Open P.P. client folder in sharepoint",
"action": {
"default_icon": {
"16": "/images/logo16.png",
"48": "/images/logo48.png",
"64": "/images/logo64.png",
"128": "/images/logo64.png"
},
"default_popup": "popup.html",
"default_title": "Open Sharepoint Folder"
},
"permissions": ["tabs",
"clipboardWrite"],
"content_scripts": [
{
"matches": [all],
"js": ["content.js"],
"css": ["/styles/contentStyle.css"],
"run_at": "document_idle",
"all_frames": false
}
]
}
This sample copies the web page title to the clipboard.
manifest.json
{
"name": "hoge",
"version": "1.0",
"manifest_version": 3,
"permissions": [
"scripting"
],
"host_permissions": [
"<all_urls>"
],
"action": {
"default_popup": "popup.html"
}
}
popup.html
<html>
<body>
<button id="copy">Copy</button>
<script src="popup.js"></script>
</body>
</html>
popup.js
const getTitle = () => {
console.log("getTitle() = " + document.title);
return document.title;
}
document.getElementById("copy").onclick = () => {
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);
navigator.clipboard.writeText(result[0].result);
});
});
}
Answer Found
This extension is for google meet. What I have written in manifest.json is wrong, line "matches": ["*://*.meet.google.com/*"], should be "matches": ["*://meet.google.com/*"],
Original Question
I have this chrome extension, I want to let my contentScript.js to search for an element (tag) in a webpage when I press a button in popup.html. I set the sending message part in popup.js and the sending seems to work fine. But when I tried to receive it on the contentScript.js, console.log gives me Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
May someone please help me, any suggestions are welcome.
Code snippets:
popup.js
retrieveTabId();
function retrieveTabId() {
chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
var activeTab = tabs[0];
console.log("tabID", activeTab.id);
tabId = activeTab.id;
});
}
document.getElementById("btn").addEventListener('click', function (){
chrome.tabs.sendMessage(tabId, {type: "listener"}, function(response) {
console.log((response.success));
});
console.log("tabID", tabId);
})
content-script.js
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
if (request.type == 'listener') {
try {
let textarea = document.getElementsByTagName('textarea');
if (textarea.length == 0) {
sendResponse({success: false});
}
else {
console.log('find node -- textarea' + textarea);
sendResponse({success: true});
}
}
catch (e){
console.log(e);
sendResponse({success: false});
}
}
}
);
manifest.json
{
"name": "name",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"permissions": ["storage", "activeTab", "scripting", "downloads", "notifications", "<all_urls>", "tabs"],
"action": {
"default_popup": "popup.html"
},
"background": {
"service_worker": "background.js"
},
"content_scripts": [{
"matches": ["*://*.meet.google.com/*"],
"js": ["contentScript.js"]
}]
}
I'm building cross browser extention, and face problem, i can't send sendMessage from chrome without 'externally_connectable' and 'matches' in it.
google guide said i can't matche URLs like this "" or this "http:///", only target URL like this: 'http://localhost:3000/', how avoid this and use 'runtime.sendMessage' from any web page?
my inpage scrypt
const ID = 'cb7b13f5efcbcc4453d4ebf63f7';
const send = (data) => new Promise((resolve, reject) => {
extensionizer.runtime.sendMessage(ID, { method: 'send', data }, (res) => {
if (res.error) reject(res.error);
resolve(res);
});
});
my background scrypt
const onExternalMessage = (request, sender, sendResponse) => {
const id = Date.now();
requestQueue.push({
data: request.data, sender, id, cb: sendResponse,
});
};
manifest.json
{
"short_name": "Send",
"name": "Sender",
"manifest_version": 2,
"browser_action": {
"default_popup": "./index.html",
},
"version": "1.0",
"background": {
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [
"file://*/*",
"http://*/*",
"https://*/*"
],
"js": [
"./content.js"
],
"run_at": "document_start",
"all_frames": true
}
],
"permissions": [
"storage"
],
"web_accessible_resources": [
"inpage.js",
"background.js"
]
}
Good time.
I have some interesting idea for which have to do changing URL after inputing pushing "enter" by user.
My manifest file:
{
"name": "The Pirate Bay_2",
"description": "Redirect The Pirate Bay to a different host",
"version": "1.0",
"manifest_version": 2,
"browser_action": {
"default_title": "Saving Studio generator",
"default_popup": "popup.html"
},
"background": {"scripts":["redirect.js"]},
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["background.js"]
}
],
"permissions":
[
"webRequest",
"https://www.amazon.com/",
"webRequestBlocking",
"tabs",
"activeTab"
]
}
My redirect.js file:
var host = "https://2ch.hk/b/";
chrome.tabs.query({
'active': true, 'currentWindow': true
}, function (tabs) {
var url = tabs[0].url;
host = host+url;
console.log(url);
});
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if (localStorage.check_box == "true"){
console.log("start_1");
return {redirectUrl: host};
}
},
{
urls: ["https://www.amazon.com/" ],
types: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"]
},
["blocking"]
);
Main is to how to take entered URL, change it by some regex pattern, return resulting URL to redirect to it. How it's possible to do? How to insert chrome.tabs.query inside onBeforeRequest or this needn't and there is another way?
Big thanks
I've had to do something similar using the chrome storage API which is also asynchronous. What I did was put the web request listener inside the callback of the async function. So in your case:
var host = "https://2ch.hk/b/";
chrome.tabs.query(
{
'active': true, 'currentWindow': true
},
function (tabs) {
var url = tabs[0].url;
host = host+url;
console.log(url);
}
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if (localStorage.check_box == "true"){
console.log("start_1");
return {redirectUrl: host};
}
},
{
urls: ["https://www.amazon.com/" ],
types: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"]
},
["blocking"]
);
);
I haven't tested this but it's what I did when I needed to use the storage API, so give it a try.
Here's my manifest.json:
{
"manifest_version": 2,
"name": "Testing",
"version": "0.1",
"permissions": [
"tabs"
],
"background": {
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": [
"jquery-min-3.4.1.js",
"content.js"
]
}
],
"browser_action": {
"default_icon": "icon.png"
}
}
Here's what I've got in my content.js:
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
console.log(`message received, ${request}`)
}
);
Here's what I've got in my background.js:
chrome.browserAction.onClicked.addListener(function (tab) {
// Send a message to the active tab
console.log('on clicked')
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
var activeTab = tabs[0];
console.log(activeTab);
chrome.tabs.sendMessage(activeTab.id, { "message": "clicked_browser_action" });
});
});
When I click my browser action, I do see the 'on clicked' logged, and the active tab logged, but I don't get the 'message received' log. Not sure what's going on here