In this lab, you will be practicing using different UI elements in HTML with a JavaScript program to perform some operations on user input. Specifically, you will finish a cryptogram generator, which takes any message as input and outputs a cipher message in a few different possible outputs.
We have provided encrypt-it.html
as a starting HTML
for you to use and build upon. You don't need to write any CSS in this lab, although you're free to add styling on your own!
Refer to the past few lecture slides for any needed JavaScript review!
The following is a (partial) list of HTML form elements. For more information on form elements, make sure to check W3Schools.
<input type="text">
(text input boxes)
<textarea>
(can use for user input of large amounts of text)<input type="checkbox">
(checkboxes can be used for multiple choice input)<input type="radio">
(radio buttons can be used for requiring exactly
one choice)<label>
(descriptive text labels)<select>
containing <option>
elements, optionally grouped together with
<optgroup>
For an example of using textarea and input, you can refer to a complete example Melissa introduced yesterday in class (a simple word counter webpage).
Two methods we will use a LOT are document.getElementById
and
document.querySelectorAll
. It's handy to
declare a shortcut to help us out. You may use the following in your JS
programs (these are exceptions to the rule of having description function
names):
function $(id) {
return document.getElementById(id);
}
function qsa(query) {
return document.querySelectorAll(query);
}
Example:
<button id="encrypt-it">Encrypt-It!<button>
let button = document.getElementById("encrypt-it");
let button2 = $("encrypt-it"); // returns the same as above.
The first task is to extend encrypt-it.html
by
adding UI controls. This starter HTML introduces two new elements that are
useful for grouping UI controls:
<fieldset>
: A container to group UI elements<legend>
: A legend for a fieldset
which appears by
default as the
text within the top-left borderWhen you open the HTML file, you should see two empty bordered fieldsets, each with a legend.
Move through the slides below to finish the starter HTML and add UI elements to these two fieldsets.
In the first <fieldset>
add:
<textarea>
. It
should be 10 rows by 60 columns.
The second <fieldset>
represents options for the cipher your program will
generate from the input text. In this <fieldset>
, add:
<label>
: "Cipher Type:"Expected output is provided on the slide below.
encrypt-it.js
Now you'll write a bit of JavaScript testing code that pops up an alert
box. This is just a test to make sure that your browser is running your JavaScript file, before we move on to the main execises.
encrypt-it.js
alert("Hello world!");
such that the alert is called when the page is loaded
HTML
page to your JavaScript file using a script
tagalert
message? If so, move on. Otherwise, double-check your script
tag syntax or ask a TA for helpNow let's set up a very basic JS event handler. Modify your JS code and
HTML
so that the "Hello, world!" alert
message won't
pop up until the user clicks the "Encrypt-It!" button.
Strategy:
window
's
load
event is needed (remeber we don't have access to the DOM
until the page is loaded).
alert
statement inside a new function
handleClick
.
handleClick
function is called.
alert
? If so, move on. Otherwise, double-check the syntax and
for both of your event listeners (window load and button click), or ask a TA for helpModify your JS code so that when the user clicks "Encrypt-It!", the text in
the input text area will be encrypted using a basic shift-cipher, and output
into the page's paragraph element with the id of output
.
Details:
document.getElementById
or
document.querySelector
to access a DOM element in JS.
handleClick
function so that when called, it now retrieves the textarea's text value and
generates a shift cipher (algorithm strategy discussed on the slide below; a
solution for this cipher function is provided at the very bottom if
you'd like to skip the algorithm part). This generated cipher will be
output as text in the #output
paragraph.
The rules of a shift cipher are fairly straightforward. Let the English alphabet we all know and love(?) be called A. Let the shift-encrypted alphabet be called C. For simplicity, we will shift letters in our encryption function by 1 letter. Then C is defined as mapping each letters in A to the letter alphabetically next. For example, 'a' is mapped to 'b', 'b' is mapped to 'c', ... and 'z' is mapped to 'a' (creating a cycle of 26 letters). In this exercise, we will consider uppercase letters and lowercase letters equivalent to one another (ie, 'a' is considered equal to 'A').
Visually, the cipher can be represented as the following:
input letter a b c d e f g h i j k l m n o p q r s t u v w x y z | | | | | | | | | | | | | | | | | | | | | | | | | | v v v v v v v v v v v v v v v v v v v v v v v v v v output letter b c d e f g h i j k l m n o p q r s t u v w x y z a
Your task in this part is to convert the text in the input text area from alphabet A to alphabet C. This is all you need to know to implement the cipher in this lab, but if you would like additional hints, there are some provided in the slide below.
Note that the value you get from the text area is just a long string. So your goal is to build up a new string that is the result of applying the cipher to each letter in the input text, in order, and adding it to your result string.
There are a few ways to go about this, but note that one of the most
intuitive approaches would be to use a for
loop through the input string and add 1 to each letter (letters are actually represented by numerical values, so this is a natural operation). To handle the z -> a shift, you can add a special case for each letter, or use mod arithmetic to avoid this extra case.
You may find charCodeAt(index)
and fromCharCode(asciiNum)
helpful for this problem.
If you get stuck on this function, you may refer to a sample solution on the slide below. But it's strongly recommended you implement it on your own!
One function solution is given below (you can also solve this with arrays):
/**
* Returns an encrypted version of the given text, where
* each letter is shifted alphabetically ahead by 1 letter,
* and 'z' is shifted to 'a' (creating an alphabetical cycle).
*/
function shiftCipher(text) {
text = text.toLowerCase();
let result = "";
for (let i = 0; i < text.length; i++) {
if (text[i] < 'a' || text[i] > 'z') {
result += text[i];
} else if (text[i] == 'z') {
result += 'a';
} else { // letter is between 'a' and 'y'
let letter = text.charCodeAt(i);
let resultLetter = String.fromCharCode(letter + 1);
result += resultLetter;
}
}
return result;
}
Now that you have a cool encryption feature implemented, let's add some features for the user to decorate their encrypted message.
We have broken this part into are a few smaller exercises - move down the slides to work through them!
Below is the expected output after all of the UI elements in this Part have been added:
First, we want to restrict the shift cipher functionality to only work when "Shift Cipher" is selected in the drop down menu. Only when this is the currently-selected option and then the "Encrypt-It" button is clicked should the input text be encrypted.
For dropdown menus, you can get the value of the current option
using el.value
, where el
is the DOM element for
the <select>
dropdown.
Add a "Reset" button to your HTML
with an id of reset
.
When the button is clicked, the text area and the output paragraph should
both be cleared using innerText
.
Add a checkbox
element following the boldy-emphasized label
"All Caps:" that when checked, makes all of the text in the output
paragraph appear only in
uppercase.
To do so, add a CSS file with a class ".uppercase" that
uses text-transform: "uppercase";
to make an element all-uppercase. When
the "All Caps" option is checked, the output paragraph should have this
class. When unchecked, it should not have this class so that it uses
whatever casing was used in the original input text.
Hint 1: The event corresponding to changing the state of a checkbox input as
checked/unchecked is change
.
Hint 2: To update the class list of a DOM element, you can use
el.classList.add("classname")
and
el.classList.remove("classname")
.
Add a radio
button
element to the second
fieldset
with two font size options: 12pt and 24pt. The text in
the output paragraph should have the font size of whatever is currently selected in
the radio button group. The radio
buttons should follow a
boldly-emphasized label, "Font Size:".
To minimize changing styles in JavaScript, you can add CSS classes to accomplish font size changes.
Note: This part is a more challenging feature we have provided if you'd like to explore a more advanced cipher algorithm and and add a few more UI features. We have also suggested other features to try on the next slide!
In this part, you will implement the "Randomized" cipher option. This is similar to the Shift Cipher, only "result alphabet" C is randomly-generated. In otherwords, each letter in the English alphabet is mapped to one of the 25 other letters, but no two letters may have the same mapping (e.g., "a" and "c" can not both map to "d").
First, you should modify your button event handler to determine whether the "Shift Cipher" or "Randomized Cipher" option is selected in the dropdown menu. If the "Randomized Cipher" option is selected, it should call a new function which outputs a randomized encrypted version of the input text area to the output div.
If you would like some hints for writing this algorithm, there are some in the slides below.
Because we aren't simply adding 1 to each letter (or mapping 'a' to 'z'), you might find an array helpful when creating a random cipher alphabet. One way to randomly-generate the cipher is to keep track of unchosen letters in the English alphabet using a string or array. Then, randomly choose one of the unchosen letters (you may find Math.floor()
and Math.random()
useful here).
Next, push this randomly-chosen letter to the end of the cipher array. Continue this process until you have removed all letters from your English alphabet and have 26 letters in your cipher array (where the first index is the letter randomly-chosen first, and the last index is the letter that was chosen last).
If you get stuck on this function, you may refer to a sample solution on the slide below. But it's strongly recommended you implement it on your own.
One possible solution is given below:
function generateCipher(text) {
let alphabet = "abcdefghijklmnopqrstuvwxyz".split("");
let cipher = [];
// it's poor style to hardcode a magic number like 26
let alphabetLength = alphabet.length;
for (let i = 0; i < alphabetLength; i++) {
let randomIndex = Math.floor(Math.random() * alphabet.length);
cipher.push(alphabet.splice(
[Math.floor(Math.random() * alphabet.length)], 1));
}
document.getElementById("output").innerText = cipher;
let result = "";
for (let i = 0; i < outputText.length; i++) {
if (text[i] >= 'a' && text[i] <= 'z') {
let letterCode = text.charCodeAt(i) - 'a'.charCodeAt(0);
result += cipher[letterCode];
} else {
result += text[i];
}
}
document.getElementById("output").innerText = result.replace(",", "");
}
Did you enjoy making your own encrypted messages? Here are a few other ideas to add to your file:
.txt
file of dictionary words, you can try to write a tool that takes input (probably from a Shift or Randomized cipher) and tries to decode it, matching sequences of characters to words in the dictionary.