this is my background.js
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [
// When a page contains a <video> tag...
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostEquals: 'www.youtube.com'}
})
],
// ... show the page action.
actions: [new chrome.declarativeContent.ShowPageAction() ]
}]);
});
});
where should I insert my ajax? and how to use jquery? like $.post in my background.js?
Related
Forgive me for any glaring mistakes as I am new to chrome extensions, but this error with Chrome's message passing API has been discussed here, here, and here in the past and the common response is along the lines of 'disable existing Chrome extensions, one of them is causing the error'. Is this the best that can be accomplished? Are we supposed to just roll over and accept the fact that our extensions will conflict with others? Returning true or returning a Promise for the listener callback function and using sendResponse does not solve the problem for me.
Currently, I can only get the new value stored in chrome.storage.local (no errors) by disabling all other chrome extensions, removing the extension and loading back up the unpacked extension. The code interestingly only seems to work on developer.chrome.com, it doesn't work at all on the other "matches" URLs in manifest.json.
I think that there is some significance in the await and async operators in solving this issue but I am unsure how to properly implement it.
manifest.json:
{
"manifest_version": 2,
"name": "my extension",
"version": "1.0",
"description": "its my extension",
"permissions": [
"declarativeContent",
"storage",
"activeTab"
],
"content_scripts": [
{
"matches": [
"*://developer.chrome.com/*",
"*://bbc.co.uk/*",
"*://theguardian.com/*",
"*://dailymail.co.uk/*"
],
"js": ["content.js"]
}
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_security_policy": "script-src 'self' https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js; object-src 'self'",
"page_action": {
"default_popup": "popup.html"
},
"icons": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}
popup.html:
<!DOCTYPE html>
<html>
<head>
<title>my extension</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="popup.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>my extension</h1>
<h2>Article: <span id="article-headline"></span></h2>
<button id="detect-article">Detect Article</button>
</body>
</html>
popup.js:
$(document).ready(function() {
$("#detect-article").click(function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs){
chrome.tabs.sendMessage(tabs[0].id, {request: "Requesting headline"}, function(response) {
console.log("Requesting headline")
});
});
});
})
function getHeadline(changes) {
let changedValues = Object.keys(changes);
//console.log(changedValues);
for (var item of changedValues) {
console.log("new value: " + changes[item].newValue);
$("#article-headline").text(changes[item].newValue)
}
}
chrome.storage.onChanged.addListener(getHeadline);
content.js:
function handleRequest(message, sender, sendResponse) {
console.log("Request recieved");
let headlineList = document.getElementsByTagName("h1");
chrome.storage.local.set({headline: headlineList[0].innerText}, function() {
console.log("'" + headlineList[0].innerText + "' stored in local storage");
});
return true;
}
chrome.runtime.onMessage.addListener(handleRequest);
background.js:
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostContains: 'developer.chrome.com' },
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostContains: 'bbc.co.uk' },
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostContains: 'theguardian.com' },
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostContains: 'dailymail.co.uk' },
}),
],
actions: [new chrome.declarativeContent.ShowPageAction()]
}]);
});
});
Many thanks for taking the time to look/re-look at this issue, solutions pertaining to the aforementioned 'disable existing extensions' are not what I am looking for.
When you specify a callback for sendMessage you're telling the API that you NEED a response so when your content script doesn't respond using sendResponse the API thinks something terrible happened and reports it as such!
Reminder: when editing content scripts make sure to reload both the extension on chrome://extensions page and the tabs that should have this content script.
If you need a response from asynchronously running code such as chrome API callback:
Keep return true
Call sendResponse(someImportantData) inside the callback
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
chrome.storage.local.set({foo: 'bar'}, () => {
sendResponse('whatever');
});
return true;
});
Same for Promise, but don't use async for the onMessage listener, more info.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
fetch(message.url).then(r => r.text())
.then(t => sendResponse({ok: t}))
.catch(e => sendResponse({err: e.message}));
return true;
});
If you need a response and it can be sent immediately:
Replace return true with sendResponse
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
sendResponse('whatever');
});
If you don't need any response:
Remove the callback in sendMessage
chrome.tabs.sendMessage(tabs[0].id, {request: "Requesting headline"});
Remove return true - all it does currently is telling the API to keep the messaging port open indefinitely, which will never be used by you, so it's just a memory leak source.
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
// do something
// don't return true
// ManifestV2: don't call sendResponse
// ManifestV3 bug: uncomment the next line
// sendResponse();
});
For ManifestV3 in Chrome 99, 100, 101 you need a dummy sendResponse() call.
I have this code to activate an extension only if a certain website is visited. I've noticed that the extension icon will be always clickable and will be not grey if the url isn't mathcing with the condition setted and when the desired website is visited and the url match, if the user click on the extension icon, the popup will not be opened. How I can fix?
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { hostEquals: 'www.example.com/video/*', schemes: ["https"] },
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
chrome.pageAction.onClicked.addListener( () => {
chrome.windows.create({
url: chrome.runtime.getURL('popup.html'),
width: 500,
height: 295,
type: 'popup'
});
});
Your rule for hostEquals will never match anything because per the documentation it's compared against the host part of a URL e.g. simply www.example.com so it can't have / or *. Note that chrome.declarativeContent uses its own filtering system, it does not support any of the usual matching patterns used by content_scripts or webRequest.
Solution 1:
{ hostEquals: 'www.example.com', pathPrefix: '/video/', schemes: ['https'] }
Solution 2:
{ urlPrefix: 'https://www.example.com/video/' }
I need the extension to be available only when the user is logged in to the parent site i.e www.flyship.com and also to the sites which are mentioned in the manifest.json.
"content_scripts": [
{
"matches": [
"*://*.flyship.com/*",
"*://app.yield.io/*",
"*://*.indeedjobs.com/*"
],
"js": ["scripts/content.js","scripts/index.js"]
}
],
In the background.js i am checking if the user is logged in to flyship.com using this code
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse){
if(request.login === "logged"){
checkUser(request, sender, sendResponse);
// checkforValidUrl();
}
return true;
}
function checkUser(request, sender, sendResponse){
chrome.cookies.get({url : "https://www.flyship.com/app", name: "csrftoken"}, function(cookie){
const CSRF = cookie.value;
sendResponse({token: CSRF});
console.log(CSRF);
});
}
I need the extension to be greyed out on all the other sites except the mentioned sites in manifest.json that too only when the user is logged in to flyship.com.
P.S : i have tried with declarativeContent but it doesn't seem to be working for me or maybe atleast am not able to deduce it according to my needs. following is the code that iam checking the urls on
function checkforValidUrl(){
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: '*://*.flyship.com/*' },
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: '*://app.yield.io/*' }
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'https://www.indeedjobs.com/*' }
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
}
I have been banging my head since 1 week to solve this problem reading docs and what not.A polite help in this regard would be very helpful.
I have an chrome extension, with 2 content script injected by manifest and one background script.
{
"manifest_version": 2,
"name": "Test",
"permissions": [
"tabs", "<all_urls>", "activeTab", "storage"
],
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": [
"content/autofill/lib_generic.js",
"content/autofill/lib.js"],
"run_at": "document_end"
}
],
"web_accessible_resources": [
"content/specific_scripts/*"
],
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
lib_generic.js contains one function named apply_forms(...) (its description is not important). The function is called from lib.js file. But this procedure doesn't work with several pages, so for each such page a I have a special script - also with only one function named apply_forms(...).
I have a function, which takes current domain as input and returns name of desired specific script or false if generic should be used.
There is too many files and it's logic is more complicated, so I can't just list all (url, script) pairs in "content_scripts" directive (I also don't want to inject all specific files as content script).
I've tried something like this in background (note that it's only for demonstration):
var url = ""; //url of current tab
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete") {
var filename = getSpecificFilename(url);
chrome.tabs.executeScript(tabId, {file: filename}, function() {
//script injected
});
}
});
NOTE: getSpecificFilename(...) will always return a name
But I get Unchecked runtime.lastError while running tabs.executeScript: Cannot access a chrome:// URL on the 5th line.
Can anyone help me with this? Is it the good way to "override` function definition dynamically, or should I go different way (which one, then).
Thanks.
This means, probably, that you're getting an onUpdated event on an extension/internals page (popup? options page? detached dev tools?).
One option is to filter by URL:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete") {
if(!tab.url.match(/^http/)) { return; } // Wrong scheme
var filename = getSpecificFilename(url);
chrome.tabs.executeScript(tabId, {file: filename}, function() {
//script injected
});
}
});
Another (and probably better) option is to make your content script request this injection:
// content script
chrome.runtime.sendMessage({injectSpecific : true}, function(response) {
// Script injected, we can proceed
if(response.done) { apply_forms(/*...*/); }
else { /* error handling */ }
});
// background script
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
if(message.injectSpecific){
var filename = getSpecificFilename(sender.url);
chrome.tabs.executeScript(sender.tab.id, {file: filename}, function() {
sendResponse({ done: true });
});
return true; // Required for async sendResponse()
}
});
This way you know that a content script is injected and initiated this.
I need to add some Regex inside my chrome.declarativeContent.PageStateMatcher.
So far I have
var matcher = new chrome.declarativeContent.PageStateMatcher({
pageUrl: {
urlContains: "something.com/someRegex/something"
}
});
Essentially I want to have a regular expression to evaluate to "something.com/4-5 char string/somithing".
How would I do this? Is this possible to do with chrome.declarativeContent.PageStateMatcher?
Thanks
Instead of urlContains use urlMatches
This is what I'm using for both domain fedmich.com and fedche.com
chrome.runtime.onInstalled.addListener(function() {
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
chrome.declarativeContent.onPageChanged.addRules([
{
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: '(fedmich|fedche)\.com' },
})
],
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
documentation is here https://developer.chrome.com/extensions/events#property-UrlFilter-hostEquals
The regular expressions use the RE2 syntax.
https://code.google.com/p/re2/wiki/Syntax
In https://developer.chrome.com/extensions/events#property-UrlFilter-hostEquals it describes urlMatches case.