Radical Software
LCST 2234, Fall 2021 (CRN 9430)
Rory Solomon
Project 2, Tutorial 3: Options
Plan for today:

I. Providing an extension icon
Let's first see how to add a custom icon for your extension. This is pretty easy:
{ "manifest_version": 2, "name": "Rory's First Extension", "description": "This is my first attempt at a browser extension!", "version": "0.1", "content_scripts": [ { "matches": [ "*://*/*", "file://*" ], "js": [ "content.js" ], "run_at": "document_idle" } ], "icons": { "128": "images/icon.png" } }
Note the comma that I have to add after the square bracket that
ends the content_scripts
list. Probably on line 17
for you. Let's see what happens if you forget to add that
— what is the error message?
Now you would need to put a file
named icon.jpg
inside a folder
(directory) called images
in
your project-2
folder. You can name the
file whatever you'd like, but just make sure that the filename
is the same as what you specify
in manifest.json
.
Here I have specified to use that is meant to be 128 pixels
wide, and 128 pixels tall. So the .png
file I'm using should have those dimensions.
The Google Chrome documentation on extension icons states that "You should always provide a 128x128 icon; it's used during installation and by the Chrome Web Store. Extensions should also provide a 48x48 icon, which is used in the extensions management page (chrome://extensions)." That documentation states that "you can also specify a 16x16 icon to be used as the favicon for an extension's pages."
You don't really need to provide all of these. If you only provide one, the browser will try to automatically re-size, which may or may not look up to your standards. If you want to be thorough, provide these multiple sizes.
II. Adding extension options
Options give some control & configurability to whoever is using your extension — whoever has installed it into their browser and is using it. The way you add these options is my creating a simple HTML page with a web form that has some input fields, with this the user can specify some values and press a submit button, when that happens your code will store those values, and then elsewhere in your extension you will access those values from the extension storage and use them in your code in some way.
As an example, let's build on what we've done so far. Last week
we ended with an example that replaces all instances of one work
or phrase with another. My example replaced the
with WHAT
. This week, let's see how we could let
the user specify a word or phrase to replace, and a word or
phrase to replace it with.
(a) The options user interface
To get started with options, we first have to
specify the HTML file that will be displayed when the user
clicks "Options" for your extension in the extensions menu. You
specify this by adding to manifest.json
:
],
"options_page": "options.html",
"icons": {
Note that this snippet is in
between content_scripts
and icons
,
probably on line 18 for you. The order of fields
in manifest.json
is actually not super
important, but you'll probably want to keep yours the same or
similar to my examples to make sure you have the syntax correct.
Now let's create that file! Make a new file in Atom, save it,
and make sure you name it options.html
and save it into your project-2
folder. Let's add this code to the file:
<!DOCTYPE html> <html> <body> <div> From text: <input id="fromField" type="text" /> To text: <input id="toField" type="text" /> <button type="button" id="button">Set text</button> </div> </body> </html>
The input
tags are inputs into which the user can
specify values. If you were really using this in your project,
you should probably specify some additional helper text to the
explain to the user what is going on. You could do that with
some plain text included in a <p> <p>
tag above or below the <input>
fields.
From text:
is what will be displayed to the user,
and fromField
is the name we will use for this
field elsewhere in our code.
(b) Saving option values
Now we need to create the Javascript code that will handle
saving these values when the user clicks Set text
.
<html>
<script src="options.js"></script>
<body>
Now we have to implement that. Create a new file in Atom, save
it as options.js
and add in this code:
let fromTextElement = document.getElementById('fromField'); let toTextElement = document.getElementById('toField'); let setButtonElement = document.getElementById('button'); setButtonElement.addEventListener('click', function() { chrome.storage.sync.set({ fromStored: fromTextElement.value, toStored: toTextElement.value}); });
The three ...Element
variables are the various HTML
elements in the DOM
(the document) that we want to access from our
Javascript code.
The next chunk of code listens for when
the setButtonElement
receives a click
event. When that happens, we get the value of
each field (e.g., fromTextElement.value
), put that
into a dictionary. A
dictionary is a group
of key-value pairs specified in Javascript and
many programming languages by curly
braces { }
So what the above code does is save (or store)
the values that the user specifies into this thing
called chrome.storage
, when the user clicks
the Set text
button.
(c) Using option values
Now we have to use those values somewhere in our code. We will do this in our content script. Let's make a new one for this tutorial.
Create another new file, let's call
it tutorial3-content.js
, and save it to
your project-2
folder. (Remember to
make sure to be careful and precise about capitalization,
punctuation, and spaces!)
Modify manifest.json
to use this
new content script:
"content_scripts": [
{
"matches": [
"*://*/*",
"file://*"
],
"js": [
"tutorial3-content.js"
],
"run_at": "document_end"
}
],
Now modify tutorial3-content.js
to look
like this:
// Technique 3 chrome.storage.sync.get({fromStored: "", toStored: ""}, function(result) { var html = document.querySelector('html'); var walker = document.createTreeWalker(html, NodeFilter.SHOW_TEXT); var node; while (node = walker.nextNode()) { node.nodeValue = node.nodeValue.replace(/the /gi, 'WHAT') } }
That is using the same code from last week, but places inside
this new block that get()
s these values from
the chrome.storage
so that we can use them. But
we're not using them yet. Make this change:
while (node = walker.nextNode()) { var re = new RegExp(result.fromStored,"gi") node.nodeValue = node.nodeValue.replace(re, result.toStored); }
Other things ...
We should show the user what the previously saved values
are. In options.js
:
chrome.storage.sync.get({fromStored: "", toStored: ""}, function(result) { fromText.value = result.fromStored; toText.value = result.toStored; });
And we can add a clear button to clear the
values. In options.html
:
<button type="button" id="clear">Clear text</button>
And handle that:
let clearButton = document.getElementById('clear'); // ... clearButton.addEventListener('click', function() { chrome.storage.sync.clear(); fromText.value = ""; toText.value = ""; });Last Updated: Thu Oct 28 2021 16:05:47 GMT+0000 (Coordinated Universal Time)