Add CSS to pages through a CSS file - google-chrome-extension

I was wondering if it was possible to add CSS to pages through a CSS file, similarly to adding JS to pages through a JS file (contentscript). So, I could just define what pages said CSS file would work on and then it would take effect just like a contentscript. I understand that it is possible to add CSS through a JavaScript file, but it would be more convenient to do it this way instead if possible. If it's not possible, then of course I must use contentscript, but I would first like to know before I rule out any possibilities. I've searched and received no answers - either I'm searching wrong or it really isn't possible. Chrome extensions have come a long way, though, so I'm still not ruling it out until someone who knows can tell me yes & how or no. Thanks for any responses.

Your manifest file must contain a content script pointing to a CSS file, that will load when a url matches your selected url fields...
"content_scripts": [ {
"css": [ "scrollbars.css" ],
"matches": [ "http://www.google.com/*" ]
} ],
This is the same method you would use to inject javascript code, except you would point to a js file instead...
More information here...

manifest.json:
"web_accessible_resources": [
"css/style.css"
],
content-script.js:
var a = chrome.extension.getURL("css/style.css");
$('<link rel="stylesheet" type="text/css" href="' + a + '" >').appendTo("head");
My extension using jQuery

similarly like we add JavaScript in content_scripts also add CSS
Method-1
"content_scripts": [
{
"matches": ["<all_urls>"],
"css": ["css/style.css"],
"js": ["jquery-1.10.2.min.js","content.js","my.min.js"]
}],
add one more thing on web_accessible_resources
"web_accessible_resources": [
"css/style.css"
]
if you used any external JavaScript then also add URL in permission tab.
"permissions": ["tabs", <all_urls>","http://*/","http://example.com/"]
Method-2
also same this thing using vai programming injection and insertCSS().
chrome.tabs.insertCSS(integer tabId, object details, function callback)
NOTE : web_accessible_resources add .css is not mandatory but as of chrome extension forum is good practice.

Related

How to use BOTH theme and content-scripts in manifest.json Chrome Extension?

I'm trying to make a chrome theme that has both stylistic features (in the manifest "theme" element) and a content script (in "content-scripts" element). I've encountered a strange error where the content script only runs when there is no "theme" element.
My content-script.js is just-
console.log("content-script.js");
When I format my manifest.json file like this with no "theme" element it works-
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"]
}
]
}
But when I add even an empty theme element my content script does not run-
{
"manifest_version": 2,
"name": "Test",
"version": "1.0",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content-script.js"]
}
],
"theme": {}
}
Anyone know why this happens, and how I can fix it?
You cannot. In Chrome, themes and extensions are two different things.
A theme is a special kind of extension that changes the way the browser looks. Themes are packaged like regular extensions, but they don't contain JavaScript or HTML code.
That's why when you include the "theme" field in your manifest.json, your extension can't run any content scripts.
I'd recommend you check the Regular Extension Documentation and also the Theme Documentation to see differences between each of them.
For Firefox, though, there is a theme API available.

Invisible tabs in chrome extension

I basically want to automate a website by using a Chrome extension. But this website has extremely much client-side code, so it's really hard to find out which request I need to make in order to get the needed information.
The easiest way I can think of would be to use a content script to enter text in input elements and click buttons, like this (with jQuery in this case):
$.ready(function(){
$("#input").val("foo");
$("#submit").click();
});
Quite similar to this question: Injecting input into a tab opened by a Chrome Extension, but the interaction with that website should not be visible.
So: Can I open pages in chrome from an extension, that are not visible to the user and use them to interact with websites?
If you want the page to be completely invisible, I believe that the only option is to load it into an iframe on the background page. You can then access the page within the iframe using content scripts, just as you would access any normal visible page.
Since many sites limit embedding using the X-Frame-Options header, you will likely have to use the webRequest API to remove that header before loading the page into an iframe. Some pages also use other techniques to prevent embedding that might further complicate this.
Example code:
manifest.json
{
"manifest_version": 2,
"name": "Hidden page in background",
"description": "Interact with a hidden page in background",
"version": "1.0",
"background": {
"page": "background.html",
"persistent": true
},
"content_scripts": [
{
"matches": ["*://*.google.fr/*"],
"js": ["contentscript.js"],
"all_frames": true
}
],
"permissions": ["*://*.google.fr/*", "webRequest", "webRequestBlocking"]
}
background.html
<!DOCTYPE html>
<html>
<head>
<script src="background.js"></script>
</head>
<body>
<iframe id="iframe1" width="1000 px" height="600 px" src="http://www.google.fr"></iframe>
</body>
</html>
background.js
// This is to remove X-Frame-Options header, if present
chrome.webRequest.onHeadersReceived.addListener(
function(info) {
var headers = info.responseHeaders;
var index = headers.findIndex(x=>x.name.toLowerCase() == "x-frame-options");
if (index !=-1) {
headers.splice(index, 1);
}
return {responseHeaders: headers};
},
{
urls: ['*://*.google.fr/*'], //
types: ['sub_frame']
},
['blocking', 'responseHeaders']
);
contentscript.js
var elementToInsert = document.createElement("h1");
elementToInsert.textContent = "This text comes from my content script.";
document.body.insertBefore(elementToInsert, document.body.firstChild);
Couple of notes:
The removal of X-Frame-Options header is not limited to the background page here. It would allow embedding of the relevant page in iframes on any other page as well. Unfortunately, Chrome does not seem to support the ALLOW-FROM uri value that could be used to limit embedding to your extension only.
Content script is being injected to all pages here. You could inject it programmatically only to the iframe on the background page, but that gets a bit more complicated.
I used www.google.fr as an example, because it uses X-Frame-Options, but does not use any other techniques to prevent embedding. I used the French domain because google.com tends to redirect to local country-level domains automatically.
See tabs.create, you could call the following code creating an invisible tab (not active).
chrome.tabs.create({ url: 'https://www.google.com', active: false, });

Firefox addon development - tabs api - blacklist url patterns from inject the exstension code (like in chrome)

I am using the addons sdk/tabs api to inject content scripts into tabs when they are loaded like this:
tabs.on(ready, function (tab) {
var worker = tab.attach({
contentScriptWhen: 'end',
contentScriptFile: myAwesomeArrayOfScripts
});
...
Is there an easy way i can prevent the attach on domain patterns?
Most importantly i need to prevent it to work on about: domains like the new tab page of firefox.
Obviously i'm able to control execution with code like this:
if (tab.url.indexOf('about:') === 0) return;
But it looks very unclear solution compared to chrome declarative manifest, where you can have this:
"content_scripts": [
{
"matches": [ "http://*/*", "https://*/*", "file://*/*" ],
Is there anything similar? Firefox documentation is confusing... too many things and too many versions and articles from the past.
Use the sdk/page-mod module instead of attaching content scripts via tabs events if you want to declare a content script. Then you can use the includeand exclude keys to specify URL patterns (exclude was introduced in Firefox 32).
Using Firefox's tab.attach is similar to chrome.tabs.executeScript, which should only be used to imperatively execute a content script.

Is it possible to access the contents of iframe via chrome extension?

I want to ask is there ANY way or extension that can pre-highlight text within the iframe whenever a new window is opened containing iframe? I have tried many extension but none of them works.
I need to filter out content based on certain keywords and the content is within iframe. I can do it with CTRL+F but there are many keywords like 10-15 within each article to be found. So it makes my job very tough and time consuming. Few extensions that I have tried from chrome are multi highlighter, pearls, FF but none of them seems to work.
I also know the reason why these extension can't access content within the iframe i.e. due to cross origin policies.
But I also remember around an year ago I worked with chrome extension named 'Autofill' that could pre-select form elements whenever I opened new chrome window containing iframe.
So is there any work around?
You can set your extension permission to run content scripts in all frames as document at http://developer.chrome.com/extensions/content_scripts.html#registration by setting all_frames to true in the content scripts section of your manifest file. Adding to Google's example from that page, part of your manifest file might look like
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"],
"all_frames": true
}
],
...
}
You'll need to be careful since your content scripts are going to be inject into the page once for the parent page and one for each iFrame on the page. Once your content script is injected into all frames on the page you can work your magic with finding and highlighting text.
if (window === top) {
console.log('Running inside the main document', location.href);
} else {
console.log('Running inside the frame document', location.href,
[...document.querySelectorAll('*')]);
}

Chrome extension background page html not working

I am trying to understand chrome background pages. I managed to get background.js script running after cannibalizing on the of examples and it pops up with an alert box every time a user visits a page. However, when I take the same script and move it to a background.html file, I cannot seem to get the file to execute.
I have updated the the manifest file to a page (instead of script) and the extension loads fine. I have also tried playing around with either having the javascript in a script tag directly in the body or in a function as it is now that is called onload on the body or in the head.
Perhaps I don't understand the concept of what a background.html page is used for in a Chrome extension?
Manifest file:
{
"name": "Testing Extension",
"version": "0.2",
"background": { "pages": ["background.html"] },
"permissions": [
"tabs", "https://mail.google.com/*", "http://*/*, https://*/*"
],
"browser_action": {
"name": "Do some action",
"icons": ["icon.png"]
},
"manifest_version": 2,
"web_accessible_resources": ["injectImage.js", "background.html"]
}
injectImage.js
alert('Got Here');
'use strict';
chrome.browserAction.onClicked.addListener(function (tab) {
chrome.tabs.executeScript(null, {file: "injectImage.js"});
});
chrome.browserAction.setBadgeBackgroundColor({color: [0, 200, 0, 100]});
var i = 0;
window.setInterval(function () {
chrome.browserAction.setBadgeText({text: String(i)});
i++;
}, 10);
background.html
<!DOCTYPE html>
<html>
<head>
<script src="jquery-1.8.0.min.js"></script>
<script src="injectImage.js"></script>
</head>
<body>
</body>
</html>
currently this code doesn't seem to do anything other than put an icon in the top right corner.
Your background is only one page and acts like a local server that can send and receive data between the content_scripts and default_popup or other extension pages.
For anyone starting out, look at each example's manifest version, which is defined in manifest.json. Version 2 has stricter security policies and inline javascript is invalid so copying sample v1 code and pasting it into background.html will not work anymore. All scripts need to be in an external file that can be included in an HTML file using the src attribute like <script src="main.js"></script>
My understanding is that you have four commonly used components for a basic extension:
DOM of the tab being viewed which can only be accessed by content_scripts
content_scripts is an array of javascript files identified in manifest.json that are sequentially injected directly into the tab's DOM. Apparently the JS variables and functions from the tab and your content_scripts cannot interact.
One background HTML page which Chrome either generates by concatenating an array of scripts OR is defined as one page, commonly named background.html.
{"browser_action" : {"default_popup" : "popup.html"}} is an optional user interface defined in manifest.json that is displayed when someone clicks your extension icon. The popup has no way to reach the tab's DOM so if the tab's content matters then it must be requested using Chrome messages like chrome.extension.sendMessage
Your background is defined either as one or more scripts:
"background": {
"scripts": ["background.js"]
},
Or as a page:
"background": {
"page": "background.html"
},
If you want to find out what is happening inside of the background then you can use console.log but in order to inspect the output you have to launch the inspector from the Extensions page. You can even see that the background file is always named "_generated_background_page.html".
You have a typo in your manifest file. Including a background page should look like this:
"background": {"page": "background.html"}
OR you can directly define js instead of defining a background page and referencing a script file in it (Inline scripts are not allowed as per Content Security Policy (CSP))
"background": {
"scripts": ["background.js"]
},
For version 3
background pages are replaced by service_workers in MV3
Replace background.page or background.scripts with background.service_worker in manifest.json.
{
"manifest_version": 3,
"name": "",
"background": {
"service_worker": "background.js"
}
}
One more gotcha not mentioned here. Doing <script src="myscript"/> doesn't work :P, you have to type it out completely with <script src="myscript"></script>. Took me a bit to figure that out.

Resources