Using browser_action to apply css styling - css

I am new to chrome extension development. I am writing a chrome extension that will inject CSS into the page. I've been successful in doing this by specifying the css file in manifest.json.
I now want to apply different css (files) depending on a link or button selected on a popup triggered through a browser_action. So clicking link 1 will apply style-red.css and clicking link 2 will apply style-blue.css. A third "reset" button should reset css back to its original state (removing the custom style red or blue css files).
My manifest.json is as follows:
{
"name": "Redesign",
"version": "1.0",
"manifest_version": 2,
"content_scripts": [
{
"matches": ["*://*.my-site.com/*"],
"js": ["jquery-3.1.0.min.js", "script.js"]
}
],
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"tabs", "*://*.my-site.com/*"
]
}
My current approach is to have a listener in script.js listening for the button pressed in popup.html. Depending on the button pressed, the following script.js will add the corresponding CSS file into my-site.com using the jquery below:
$(document).ready(function() {
var path = chrome.extension.getURL('style-red.css');
$('head').append($('<link>')
.attr("rel","stylesheet")
.attr("type","text/css")
.attr("href", path));
});
I tried to use the above jquery in script.js (without the browser_action in the manifest.json) thinking script.js will get automatically loaded but the CSS does not get applied to my-site.com. What am I doing wrong or is there simpler Javascript without the need for a full jquery library to be added?
And even if the jquery works, how do I apply a different CSS file based on the choice in popup.html as well as reset the css back to its original styling upon user choice?

To insert css file in content scripts, you need to declare the css file as web_accessible_resources
To dynamically insert css files, see chrome.tabs.insertCSS, it can be called in extension context, such as popup page.

Related

Custom background for Chrome new tab replacement extension

I'm developing a new tab replacement extension for Google Chrome and I'd like to allow the user to customize the background, to do so I'm using the storage.sync API as suggested by this page.
The problem is that the style changes are applied asynchronously, so the default background (white) is briefly used during the page load resulting in unpleasing flashes.
Possible (unsatisfying) solutions are:
do not allow to change the background;
hard code a black background in the CSS (and move the problem to custom light backgrounds);
use a CSS transition (still super-ugly).
What could be an alternative approach?
Follows a minimal example.
manifest.json
{
"manifest_version": 2,
"name": "Dummy",
"version": "0.1.0",
"chrome_url_overrides": {
"newtab": "newtab.html"
},
"permissions": [
"storage"
]
}
newtab.html
<script src="/newtab.js"></script>
newtab.js
chrome.storage.sync.get({background: 'black'}, ({background}) => {
document.body.style.background = background;
});
I come up with a reasonable solution. Basically since the localStorage API is synchronous we can use it as a cache for storage.sync.
Something like this:
newtab.js
// use the value from cache
document.body.style.background = localStorage.getItem('background') || 'black';
// update the cache if the value changes from the outside (will be used the next time)
chrome.storage.sync.get({background: 'black'}, ({background}) => {
localStorage.setItem('background', background);
});
// this represents the user changing the option
function setBackground(background) {
// save to storage.sync
chrome.storage.sync.set({background}, () => {
// TODO handle error
// update the cache
localStorage.setItem('background', background);
});
}
This doesn't work 100% of the times but neither do the simple:
document.body.style.background = 'black';
So it's good enough.¹
¹ In the real extension I change the CSS variables directly and I obtain much better results than setting the element style.

Choose between different style for an Ember.JS application

The issue I have is that I can't find a way to 'change' the css style within my application.
The thing that I want to access is for example: I have a red theme, but I want that the user can choose an other predefined theme, like a green, or a blue theme.
The idea is that I have different app.css, how can I change between one another, I can't find method to do so. Maybe I can do it in my environnement.js?
Any tips is apreciated.
tl;dr: How to set multiple css style in our Ember.JS app?
You can achieve this by generating multiple stylesheets, see: https://ember-cli.com/asset-compilation#configuring-output-paths
I suggest using ember-cli-head to add a specific link element with the additional theme stylesheet. You could set the stylesheet in your head.hbs using the headData service.
Full Example:
ember-cli-build.js
var app = new EmberApp({
outputPaths: {
app: {
css: {
// app/styles/red.css
'red': '/assets/themes/red.css'
}
}
},
// Exclude theme css files from fingerprinting,
// otherwise your file is named `red-somehash.css`
// which we don't (easily) now at runtime.
fingerprint: {
exclude: [ 'red.css' ]
}
})
head.hbs
{{#if theme}}
<link rel="stylesheet" href="/assets/{{theme}}.css">
{{/if}}
some-component.js (or Route or whatever)
export default Ember.Component.extend({
headData: Ember.inject.service(),
actions: {
setTheme(themeName) {
this.set('headData.theme')
}
}
})

Firefox Extension - including CSS in manifest.json

My manifest is not working when I add CSS into it, while it works in Chrome Extension when I do like that.
Here how my manifest looks:
"css": ["css/jquery-ui.css", "css/font-awesome.css", "css/simplegrid.css", "css/basic.css"],
"js": ["jquery.js", "jquery-ui.js", "myPeaceFile.js"],
myPeaceFile.js works, jquery's are working. But CSS files are not.
I previously asked question about jquery's not working. It looked like this:
"js": ["peace.js", "jquery.js"] - didn't work.
Then I was suggested this and it worked:
"js": ["jquery.js", "peace.js"]
Is it something similar? Please help.
Thanks!
You can attach CSS to pages using Style, in your main.js define a style and attach this style to the contentscript.
var { Style } = require('sdk/stylesheet/style');
var style = Style({
uri: './bootstrap.css'
});
tabs.on('ready', function(tab) {
let worker = tab.attach({
contentScriptFile: [
data.url("jquery.min.js"),
data.url("jquery-ui/jquery-ui.min.js"),
data.url("mycontent-script.js"),
]
});
attach(style, tab);
});
At the Style constructor in the second line you can pass a string, or an array of strings, that represents local URI to stylesheet. In this case the ./bootstrap.css is in the data folder of the extension.

chrome extension content script can not access to iframes

i want to make a chrome extension on google reader and i found a problem. content script can not access to iframes. For all n, window.frames[n] = undefined. And i have this "all_frames": true in manifest.json. Or someone could tell me how to add a button under each article. Thank you!
From taking a quick look at Google Reader's rendered HTML, the only button that is in an IFRAME appears to be the Google Plus +1 button - all the other buttons are not in an IFRAME. So you don't need to worry about the IFRAME.
I'm assuming that the existing buttons are the buttons that appear underneath each article: +1, Share, Email, Keep Unread, Add Tags.
If you want to add a new button to the existing article buttons all you need to do is enumerate the DOM - specifically the "entry-actions" DIV classes and append say a new SPAN with your element/button to each article.
I suspect (but not sure) that Reader may dynamically update the DOM with new articles. If this is the case you may need to track new articles being added to the DOM so you can add your button again. To do this add an event listener for DOMNodeInserted - e.g.
document.addEventListener('DOMNodeInserted', onNodeInserted, false);
UPDATE:
The reason you can't see ".entry-actions" class is because it is added dynamically.
Here is a working very basic example. This will monitor the DOM and when it sees an entry-actions DIV that doesn't have our ".myclass" SPAN button, will add it.
You need to have jquery included in your extension for this to work. I've used jquery-1.7.1.min.js in this example. You will also need an icon file called foo.png too if you cut and paste the example.
manifest.json
{
// Required
"name": "Foo Extension",
"version": "0.0.1",
// Recommended
"description": "A plain text description",
"icons": { "48": "foo.png" },
//"default_locale": "en",
// Pick one (or none)
"browser_action": {
"default_icon": "Foo.png", // optional
"default_title": "Foo Extension" // optional; shown in tooltip
},
"permissions": [ "http://*/", "https://*/", "tabs" ],
"content_scripts": [
{
"matches": ["http://*/*", "https://*/*"],
"js": ["jquery-1.7.1.min.js", "content_script.js" ],
"run_at": "document_idle"
}
]
}
content_script.js
var timer;
document.addEventListener('DOMNodeInserted', onNodeInserted, false);
function onNodeInserted(e)
{
if(timer) clearTimeout(timer);
timer = setTimeout("addButtons()", 250);
}
function addButtons()
{
console.log('add buttons');
var $actions = $(".entry-actions").filter(function() {
return $(this).find('.myclass').length === 0;
});
$actions.append('<span class="myclass">My button</span>');
}

Google Chrome Extensions - Can't load local images with CSS

I have a simple Chrome extension that uses the content script feature to modify a website. More specifically, the background-image of said website.
For some reason I can't seem to be able to use local images, even though they are packed in the extension.
body {
background: #000 url('image.jpg') !important;
background-repeat: repeat !important;
}
That's it, the simplest CSS... but it won't work. The browser doesn't load the image.
Chrome has i18n support that provides the ability to reference your extension in your CSS. I keep my images in an image folder in the extension, so reference assets in the CSS like so:
background-image:url('chrome-extension://__MSG_##extension_id__/images/main.png');
Your image URL should look like chrome-extension://<EXTENSION_ID>/image.jpg
You would be better off replacing css through javascript. From docs:
//Code for displaying <extensionDir>/images/myimage.png:
var imgURL = chrome.extension.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
There are a lot of older answers and solutions to this question.
As of August 2015 (using Chrome 45 and Manifest version 2), the current "best practice" for linking to local images within Chrome Extensions is the following approach.
1) Link to the asset in your CSS using a relative path to your extension's images folder:
.selector {
background: url('chrome-extension://__MSG_##extension_id__/images/file.png');
}
2) Add the individual asset to to the web_accessible_resources section of your extension's manifest.json file:
"web_accessible_resources": [
"images/file.png"
]
Note: This method is suitable for a few files, but doesn't scale well with many files.
Instead, a better method is to leverage Chrome's support for match patterns to whitelist all files within a given directory:
{
"name": "Example Chrome Extension",
"version": "0.1",
"manifest_version": 2,
...
"web_accessible_resources": [
"images/*"
]
}
Using this approach will allow you to quickly and effortlessly use images in your Chrome Extension's CSS file using natively supported methods.
One option would be to convert your image to base64:
and then put the data right into your css like:
body { background-image: url(data:image/png;base64,iVB...); }
While this might not be an approach you would want to use when regularly developing a webpage, it is a great option due to some of the constraints of building a Chrome Extension.
My solution.
With Menifest v2 you need to add web_accessible_resources to the file and then use chrome-extension://__MSG_##extension_id__/images/pattern.png as the url in your css file.
CSS:
#selector {
background: #fff url('chrome-extension://__MSG_##extension_id__/images/pattern.png');
}
Manifest.json
{
"manifest_version": 2,
"name": "My Extension Name",
"description": "My Description",
"version": "1.0",
"content_scripts": [
{
"matches": ["https://mydomain.com/*"],
"css": ["style.css"]
}
],
"permissions": [
"https://mydomain.com/"
],
"browser_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "My Extension Name"
},
"web_accessible_resources": [
"images/pattern.png"
]
}
p.s. Your manifest.json might look different to this one.
This CSS-version-only works in extension environment (app page, popup page, background page, option page) as well as content_scripts CSS file.
In .less file, I always set a variable at the beginning:
#extensionId : ~"__MSG_##extension_id__";
Then later, if you want to refer to extension-local-resource like images, use:
.close{
background-image: url("chrome-extension://#{extensionId}/images/close.png");
}
One thing to mention is that in the web_accessible_resources you can use wildcards. So instead of
"images/pattern.png"
You can use
"images/*"
Just to clarify, according to the documentation, every file in an extension is also accessible by an absolute URL like this:
chrome-extension://<extensionID>/<pathToFile>
Note the <extensionID> is a unique identifier that the extension system generates for each extension. You can see the IDs for all your loaded extensions by going to the URL chrome://extensions. The <pathToFile> is the location of the file under the extension's top folder; it's the same as the relative URL.
...
Changing background image in CSS:
#id { background-image:
url("chrome-extension://<extensionID>/<pathToFile>"); }
Changing background image in CSS through JavaScript:
document.getElementById('id').style.backgroundImage =
"url('chrome-extension://<extensionID>/<pathToFile>')");
Changing background image in CSS through jQuery:
$("#id").css("background-image",
"url('chrome-extension://<extensionID>/<pathToFile>')");
For manifest v3, there are some modifications:
chrome.extension.getUrl() -> chrome.runtime.getUrl()
"web_accessible_resources" -> "web_accessible_resources.resources"
fill in "web_accessible_resources.matches"
2, 3 like this:
"web_accessible_resources": [{
"resources": ["images/logo.png"],
"matches": ["<all_urls>"],
}],
reference:
https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/#web-accessible-resources
Those answers above are great but your extension gets a new id every time it gets installed, so putting the id manually doesn't work if you gonna make it public at some point.
Here's my solution using manifest v.3:
//Get the url from some file within your extension's folder and store it on a global variable
var url = chrome.runtime.getURL('my_extension/img/Icon.svg');
//Take off the last part from the url string
url = url.replace('img/Icon.svg', '');
Now replace the src attribute for a custom one on every img tag and keep the file path as it's value like this:
<img ref-file="img/IconStop.svg" alt="">
Then run this function after loading the html:
loadImgs = function () {
$("img[ref-file]").each(function() {
var ref_file = $(this).attr('ref-file');
url = url + ref_file;
$(this).attr('src', url);
});
}

Resources