Inject jQuery into the current tab page - chrome extension - google-chrome-extension

I am new to chrome extensions, so I maybe using the wrong terms.
I have created a extension
manifest.json
{
"name": "Run code in page",
"version": "1.1",
"manifest_version": 2,
"content_scripts": [{
"js": ["contentscript.js"],
"matches": ["https://*/*"]
}],
"web_accessible_resources": ["*.js"],
"default_locale": "en"
}
contentscript.js
function injectScript(script) {
var s = document.createElement('script');
s.src = chrome.extension.getURL(script);
(document.head || document.documentElement).appendChild(s);
}
injectScript('script.js');
injectScript('otherscript.js');
script.js
console.log('script.js');
otherscript.js
console.log('otherscript.js');
This works, I see this in the output :
script.js
otherscript.js
All is good, both scripts are loading, I need jQuery to be added in the same way so that I can access jQuery from my script.
So, I
injectScript('jquery.js');
But now I get the following error
Denying load of chrome-extension://abdiolbenneaffeaedmfeeanlephlnoo/jquery.js. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
If I look at the DOM, I see this
<script src="chrome-extension://abdiolbenneaffeaedmfeeanlephlnoo/script.js"></script>
<script src="chrome-extension://abdiolbenneaffeaedmfeeanlephlnoo/otherscript.js"></script>
<script src="chrome-extension://abdiolbenneaffeaedmfeeanlephlnoo/jquery.js"></script>
If I put chrome-extension://abdiolbenneaffeaedmfeeanlephlnoo/jquery.js into the URL I can access it.
-- edit
If I load jquery externally it will load, so I guess I can just do that. eg
function injectExternalScript(script) {
var s = document.createElement('script');
s.src = script;
(document.head || document.documentElement).appendChild(s);
}
injectExternalScript('https://code.jquery.com/jquery-3.3.1.min.js');

If you want do inject jQuery into your extensions background page do in inside the manifest.json like so:
Example:
"background": {
"persistent": true,
"scripts": ["jquery-3.3.1.min.js", "background.js"]
},
Note: Make sure jQuery is first in the array so it loads before the actual background.js
But, in your case, you are not executing that code in the background nor are you injecting anything to it since you are mistaking a content script for a background page which you don't have.
I recommend you first read the official documentation regarding Chrome Extension Architecture before anything else.
You can also write code like so in your content.js to be injected directly into the DOM from your content script so you can avoid using multiple unnecessary .js files in your extension.
Content.js:
//Injects functions directly into the dom
function inject(fn) {
var script = document.createElement('script');
script.setAttribute("type", "application/javascript");
script.textContent = '(' + fn + ')();';
document.body.appendChild(script); // run the script
document.body.removeChild(script); // clean up
}
inject(function(){
// code that will be executed in the scope of the page
}
You can read more about this here.

This is really weird. You probably checked if the jquery.js file is in the root folder and with this name, right?
Well, in my case I wanted to add jQuery in all pages that match in content_scripts > matches so I just did something like this:
...
"content_scripts": [
{
"matches": [
"https://*/*"
],
"js": [
"assets/js/jquery.js",
"assets/js/contentscript.js"
]
}
],
...
So in this way I can use jQuery in contentscript.js file.

Related

Firefox extension content script does not load and append HTML

Everything below works in a Chrome extension but silently fails when ported to Firefox on:
loading the test.html unless I remove <style></style> from it
appending the #test_element to the body
Do styles have to go into a separate file for Firefox extension? Why does append() fail?
test.js
$(document).ready(function() {
$.get(chrome.extension.getURL('/html/test.html'), function(data) {
// not called unless style element is removed from HTML
// and never actually appended if it is removed
$(document.body).append($.parseHTML(data));
});
});
test.html
<style></style>
<div id="test_element">
<p>my name is cow</p>
</div>
manifest.json
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"icons": {
"64": "icons/icon-64.png"
},
"permissions": [
"tabs",
"storage",
"idle"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["lib/jquery.js", "src/test.js"]
}
],
"web_accessible_resources": [
"html/test.html"
]
}
It is not falling silently to me but gives me:
XML Parsing Error: junk after document element
Location: https://www.google.gr/
Line Number 2, Column 1
This is because it is not a valid XML document (one root element only should exists).
My way to make it work is the following:
test.html: (Make it valid)
<div>
<style></style>
<div id="test_element">
<p>my name is cow</p>
</div>
</div>
test.js: (Use XMLSerializer)
$(document).ready(function() {
$.get(chrome.extension.getURL('/html/test.html'), function(data) {
res = new XMLSerializer().serializeToString(data);
$(document.body).append(res);
});
});
For #1: see the solution by Christos. For #2: $.get() returns a string in Chrome but XMLDocument in Firefox (that must be serialized with serializeToString() before appending). Anyway, I removed jQuery to make the content script lighter (by the way, $(document).ready() is not required because by default content scripts are injected after DOM is ready):
var httpRequest = new XMLHttpRequest();
httpRequest.onload = function(data) {
httpRequest.onload = null;
var template = document.createElement('template');
template.innerHTML = data.target.responseText;
var element = template.content.firstChild;
document.body.appendChild(element);
}
httpRequest.open('GET', chrome.extension.getURL('/html/test.html'));
httpRequest.send();

Google Chrome: updating extension in "Developer mode" (locally) from userscript

I created an extension for Google Chrome which runs a small userscript for designated web-page and makes some requests via background.js to the chrome APIs (such chrome.tabs and others).
now, I'm testing it locally in "Developer mode" like this:
I edit my userscript.js and background.js;
then I go to chrome://extensions tab in Google Chrome and manually reload (CTR+R) my extension from local D:\my-extension folder.
finally, I switch to the tab with designated web-page and reload it to see the changes.
the problem is:
since I'm a beginner, a lot of changes have to be done to my userscript.js and background.js before my extension and userscript start working as expected.
so, this process involves a lot of monotonous switching between extensions and page tabs while testing.
the idea is:
it would be nice to add a button or a shortcut key on the page where the userscript is being tested and attach a sort of 'update_extension_and_reload_page' function to it in my userscript, so that evey time when I click this button it will call extension update from the local folder D:\my-extension then followed by page reload. (another alternative would be to assign such 'update_extension_and_reload_page' function to extension's browser_action icon.)
now, I'm just interested:
is there any sort of 'chrome.extesion.update' method, so that I could make a request to it from my userscript.js via background.js and call automatic reload of the extension (in "Developer mode") without need to go to the chrome://extensions tab.
The extension can reload itself, by calling chrome.runtime.reload(), so it's a matter of triggering the extension to do it.
The code below attaches the following functionality to the browser-action button:
Keeps track of the active tab.
Reloads the extension.
Reloads the active tab.
manifest.json
...
"browser_action": {
"default_title": "Reload"
// "default_icon": {
// "19": "img/icon19.png",
// "38": "img/icon38.png"
// },
},
...
background.js
chrome.browserAction.onClicked.addListener(function (tab) {
localStorage.tabToReload = tab.id;
chrome.runtime.reload();
});
function reloadTab() {
var tabID = localStorage.tabToReload;
if (tabID) {
chrome.tabs.reload(parseInt(tabID));
delete(localStorage.tabToReload);
}
}
reloadTab();
...
See, also, this answer on how to automate the re-loading process.
is this what you are looking for?
https://chrome.google.com/webstore/detail/extensions-reloader/fimgfedafeadlieiabdeeaodndnlbhid
Credit goes go
How do I auto-reload a Chrome extension I'm developing?
slightly modified the ExpertSystem's code above to call reload of extension followed by reload of tab where the content script (userscript.js) is being performed, all triggered by #reload-btn button (in case the browser_action icon is occupied with popup.html).
manifest.json
...
"background":{ "scripts": ["background.js"]},
"content_scripts" : [{
"matches" : ["https://stackoverflow.com/*"],
"css": ["userscript.css"],
"js": ["jquery-latest.min.js", "userscript.js"],
"run_at":"document_end"
}],
"web_accessible_resources": ["jquery-latest.min.map"],
"permissions": ["tabs"],
"browser_action": {
"default_icon": "icon19.png",
"default_title": "My Extension Title",
"default_popup": "popup.html"
}
...
userscript.css
...
#reload-btn { position: fixed; top: 0; right: 0; } /* or any other position on the page */
...
userscript.js
...
$("body").prepend("<button id='reload-btn'>reload extension + page reload</button>"); // some shortcut key can be additionally assigned to this button
$("#reload-btn").on("click", function() {
chrome.runtime.sendMessage("please, reload me");
});
...
background.js
...
chrome.runtime.onMessage.addListener(
function(message, sender) {
if (message == "please, reload me"){
localStorage.tabToReload = sender.tab.id;
chrome.runtime.reload();
}
});
function reloadTab() {
var tabID = localStorage.tabToReload;
if (tabID) {
chrome.tabs.reload(parseInt(tabID));
delete(localStorage.tabToReload);
}
}
reloadTab();
...

How to change the default icon as soon as page loads?

I have this code to change my icon, but it only works when I click on it. How can I have the icon change as soon as the web page loads?
document.addEventListener('DOMContentLoaded', function () {
chrome.browserAction.setIcon({path: 'different_icon.png'});
});
You'll need to pass a message to the background page and change the icon there. For example, your manifest file would have this content script:
"content_scripts": [
{
"matches" : ["<all_urls>"],
"js" : ["content.js"],
"run_at": "document_end"
}
],
As you can see, it runs when the document is done loading. Your content script passes a message to the background page:
chrome.runtime.sendMessage({changeIcon: true});
And finally, your backgound page receives the message and changes the icon:
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.changeIcon) {
chrome.browserAction.setIcon({path: 'different_icon.png'});
}
}
);

Error in launching Chrome Extension for a specific page

I'm writing a simple Chrome extension that displays a JavaScript alert saying "Hello World". In this example I have specified that the extension will only run for google.com (by putting this in the permissions property within manifest.json).
Even after everything in the target page has loaded, the alert doesn't appear. Here is my script so far:
File: manifest.json
{
"name": "Hello",
"version": "1.0",
"description": "Says hello to Google",
"permissions": ["http://*.google.com/"]
"browser_action": {
"popup": "Hello.html"
}
}
File: Hello.html
<script language="Javascript">
alert("Hello World");
</script>
You are adding a browser action popup, which adds a button to the top-right of your browser. (It's probably invisible because you haven't specified an image for it. There should be some empty space to the right of your address bar; try clicking it to see your Hello.html in a popup.)
What you want is a content script. Content scripts can get injected into every page that Chrome loads. You can use the matches and exclude_matches sub-items in your manifest file to specify which pages get your injected script.
{
"name": "Hello",
"version": "1.0",
"description": "Says hello to Google",
"permissions": ["tabs", "*://*.google.com/*"],
"content_scripts": [
{
"matches": ["*://*.google.com/*"],
"js": ["hello.js"]
}
]
}
Make sure you rename Hello.html to hello.js (and get rid of the <script> tags).
Note also that I changed your http://*.google.com/ to *://*.google.com/* so that it will apply to Google over HTTP and HTTPS (and the trailing * ensures that it will apply to all pages on google.com, not just the main page).
I came across this answer trying to find a way to only enable the icon on certain pages this is how I did it. Docs
background.js
chrome.runtime.onInstalled.addListener(function() {
chrome.tabs.onActivated.addListener(async info => {
const tab = await chrome.tabs.get(info.tabId);
const isGithub = tab.url.startsWith('https://github.com/');
isGithub
? chrome.action.enable(tab.tabId)
: chrome.action.disable(tab.tabId);
});
});
make sure to add tabs permission in manifest
First of all there are 2 types of extensions:
1. Browser Action - which work for multiple websites or almost all websites
2. Page Action - which work for specific websites or webpages [which is needed
in our case]
Follow these steps to show your extension only on google:
Step 1: Go to manifest.json file and add the below code snippet
"background":{
"scripts":["background.js"],
"persistent":false
}
***also make sure you have page action not browser action**
"page_action" : { "default_popup":"your_popup.html" }
Step 2: Now add permissions in manifest:
"permissions":["declarativeContent"]
Step 3: Now create background.js in root folder of extension and add the
below code in it, this will let the extension to work only on
urls that contain google.com
// When the extension is installed or upgraded ...
chrome.runtime.onInstalled.addListener(function() {
// Replace all rules ...
chrome.declarativeContent.onPageChanged.removeRules(undefined,
function() {
// With a new rule ...
chrome.declarativeContent.onPageChanged.addRules([
{
// That fires when a page's URL contains a 'g' ...
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlContains: 'google.com' },
})
],
// And shows the extension's page action.
actions: [ new chrome.declarativeContent.ShowPageAction() ]
}
]);
});
});
Step 4: Now reload your extension, you'll find that your extension will work
only for google.com
Hope this solved your query, If Yes, then Upvote the answer Thanks!

Trivial Chrome pageAction extension not working

I'm trying to write a trivial Chrome pageAction extension to change all anchors on a page from one domain to another... but I can't quite seem to get it to work, and I'm having trouble debugging it.
Am I misunderstanding how this kind of extension needs to be built? Or am I just misusing the API?
manifest.json:
{
"name": "theirs2ours",
"version": "1.0",
"description": "Changes all 'their' URLs to 'our' URLs.",
"background_page": "background.html",
"permissions": [
"tabs"
],
"page_action": {
"default_icon": "cookie.png",
"default_title": "theirs2ours"
},
"content_scripts": [
{
"matches": ["http://*/*"],
"js": ["content.js"]
}
]
}
background.html:
<html>
<head>
<script type='text/javascript'>
chrome.tabs.onSelectionChanged.addListener(function(tabId) {
chrome.pageAction.show(tabId);
});
chrome.tabs.getSelected(null, function(tab) {
chrome.pageAction.show(tab.id);
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.sendRequest(tab.id, {}, null);
});
</script>
</head>
<body>
</body>
</html>
content.js:
var transform = function() {
var theirs = 'http://www.yourdomain.com';
var ours = 'http://sf.ourdomain.com';
var anchors = document.getElementsByTagName('a');
for (var a in anchors) {
var link = anchors[a];
var href = link.href;
if (href.indexOf('/') == 0) link.href = ours + href;
else if (href.indexOf(theirs) == 0) link.href = href.replace(theirs, ours);
}
};
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
transform();
});
I think this is not the way to do the extension you want.
First of all, I assume you want to replace the anchors when you click the page action button.
The manifest you have injects content.js on every page, no matter if you click or not the page action button.
I suggest you remove the content_scripts field from your manifest, and inject content.js manually, with
chrome.tabs.executeScript(tabId, {file:'content.js'})
You should do this in the page action's click listener.
By the way, in that listener you are sending a request to the content script, but it hasn't a listener to listen to such request message. In this extension you won't need to use senRequest.
You're not requesting permission to run content scripts on these pages. The matches for content scripts determines what pages they are executed in but you still need to request permission to inject scripts in to these pages.
"permissions": [
"tabs",
"http://*/*"
]

Resources