This is the multi-page printable view of this section. Click here to print.
Labs
1 - Lab 19 - 'I Want It Now': Frontend Build Tools
One of the challenges of building software for the web is the heterogeneity of the platforms that it runs on. Different browsers, different devices, different network conditions, and different user needs all complicate the web as a target. Developer Experience (DX) is a growing concern for dev teams, and there continue to be amazing leaps in tooling to improve it. Today we work with a few gateway tools, just try not to get too carried away with them.
Vite
Vite is a relatively new build tool to the scene that is designed to be fast. It has sooo many features, but we will only be using a few of them today.
Learning Objectives
Have your cake and eat it too with:
- future CSS features in today’s browsers with PostCSS
- future JS features in today’s browsers with Babel
Because frontend code runs in peoples’ browsers, and because people may not update their browsers regularly, it can be a challenge to decide how old a new feature must be before it is safe to use for a target audience. Tools like PostCSS and Babel permit us to write our code (CSS and JS, respectively) using the latest features, and then transpile it to a version that is more widely supported. This means that the tolls know about future features for web technologies (CSS and JS) and then given the developer’s intended “target audience”, the tool will know whether the feature is currently available to that target, and if not, will change the source code from what the developer wrote using the future feature, to a bit more code, but using only features that are currently available to the target. This makes the code easier to read and write, and also makes it more maintainable in the long run, while not sacrificing compatibility with older browsers.
PostCSS: using tomorrow’s CSS today
To follow changes to the CSS specification, consult the W3C’s CSS Working Group’s CSS Current Work page.
On that page you’ll find a list of specifications and their statuses, as well as links to the latest drafts of the specifications.
See for example the Selectors Level 4 specification which is currently listed as being in the Working Draft
stage, which defines among other things the :has()
pseudo-class.
With PostCSS included, vite will not only bundle your CSS files into a single minified file, but it will also transpile your CSS to be compatible with the browsers you specify. We will try out a few features future features in CSS, such as:
- custom media queries
- custom property
- custom selectors
- :has relational pseudo-class
- nesting
rebeccapurple
Babel: using tomorrow’s JS today
Babel does the same thing for JavaScript that PostCSS does for CSS. It will take your modern JavaScript code and transpile it to be compatible with the browsers you specify. We will try out a few features future features in JS, such as:
Steps
🚨 Server
tl;dr - don't use the Live Server extension
vite comes with its own development server.Setup
⚠️ Prereq
NodeJS
You must have already installed NodeJS to complete this lab.- get the code by accepting the github classroom assignment link from your instructor or use this starter code if you’re not one of our students.
- open a terminal to the same directory as the
package.json
file- one easy way to do this is to have opened the directory in vscode and press ctrl+` (or cmd+` on macOS) to open a terminal in that directory
- run
npm install
to install the dependencies of the project (which are listed in thepackage.json
file) - you should notice that a new directory called
node_modules
has been created in the project- the top-level directories within node_modules should include at least those dependencies defined in the
package.json
file, but will typically include very many more. - when you run
npm install
(ornpm i
for short), npm will look at thepackage.json
file and install the dependencies listed there, but then it will continue recursively installing your project’s direct dependencies’ dependencies, as well as the dependencies of those dependencies, and so on, until all dependencies are installed.
- the top-level directories within node_modules should include at least those dependencies defined in the
- run
npm run dev
to start the vite development server - if the browser doesn’t open automatically, you can press o in the terminal to open the browser to the correct address
Future CSS
- Notice how the
Hello Vite!
header element is purple? It’s currently JMU Purple. In order to style it this was from the css file, we must have the following three items. Inspect the element in your browser’s devtools and confirm that you can locate them:- there is some selector that matches the element (what selector do you see in the devtools inspector?)
- on that element the correct property should be identified (what property do you see in the devtools inspector?)
- the value of the property is set to JMU purple (`#450084) (what value do you see in the devtools inspector?)
- in your editor (vscode) look for the css file (it’s in the root, and it’s called
style.css
) - find the 3 things from above, but no in the css source code instead.
- what similarities and differences do you observe?
- in the css file, change things that are currently JMU purple (
#450084) to instead be
rebeccapurple` - once you save your file, you should see that the browser automatically reloads
- check in the browser devtools what color the heading is now set to
Future JS
Let’s add some code at the end of the main.js
file.
- use the
let
keyword to declare aisBig
variable and assign it the value of false - use
let
again to declare a variable callednum
and assign it the value of 100 - log the variables to the console
- reassign num to a larger number, define the number using the
_
separator for dividing the number into groups of 3 digits, like8_675_309
- log the variables to the console again
- let’s try out the logical assign operator
||=
, reassignisBig
to be true ifnum
is greater than 999isBig ||= num > 999
- log the variables to the console again
- kill the vite dev server by pressing (the same for all OSes) ctrl+c in the terminal where it’s running.
- FYI, this is a standard way to stop a running process in a terminal that you might want to remember for your other console work in web dev, and other contexts as well.
- push your code to your github classroom repository.
Tools
- In addition to having a dev server with the “live reloading” feature you’re used to from the vscode live server experience, vite also has a build command that will create a
dist
directory with the files that have been prepared for production, usually including the transpiling we’re exploring today as well as minifying. Run the build command withnpm run build
in the terminal. - find the newly created
dist
directory in the project and look through the files in it. You should see that:- in the css file, the value
rebeccapurple
has been replaced with a hex value - in the js file, the
_
separator has been removed from the large number - in the js file, the
||=
operator has been replaced with a more verbose version of the same logic.
- in the css file, the value
- take a look at
vite.config.js
:- see that the target audience for this app is set to be Firefox 69. see the commented out targets to see some of the other ways that we could specify the targets
- if there’s time, try changing the target and then running npm run build and seeing how the js and/or css changes.
- when I check the disk usage of this project at the time of this writing, the
node_modules
directory is about63MB
, while the actual source code for this project is only332KB
, and the built version is24KB
Carried Away
Tools
I want it all
Big number
2 - Lab 18 - WCAG Checklist
Learning Objectives
- Write regular expressions to parse a document’s contents
- Use capturing groups to isolate specific parts of a RegEx pattern
- Create HTML elements dynamically based on parsed text
- Use Git to collaborate with a large team
- Resolve merge conflicts when using Git collaboratively
Introduction
The W3C has put together a list of Web Content Accessibility Guidelines (WCAG) for developers to follow. One way of making sure your website follows these guidelines is to perform an “audit” on it, and inspect your site to make sure it meets the specified criteria.
For instance, WebAIM has condensed these guidelines into a printable checklist you can use when auditing your site. Now, the problem is, we want an interactive, digital checklist (save the 🌳s)!
Fortunately, you’ve found a solution: the (fictitious) company Check.life has a JavaScript library that makes a web page into an interactive checklist, given that the HTML follows a specific structure.
We’ve taken the text from the accessibility checklist and put it into four separate files, in Markdown format. Your goal will be to write code to convert the text from Markdown to HTML.
Getting Started
The accessibility guidelines are split up into four sections (Perceivable, Operable, Understandable, Robust), each in its own file. For this assignment, you will be placed on a team that is responsible for one of the four sections.
First, accept the GitHub Classroom assignment provided by your instructor.
You will be placed in one giant group – everyone will be sharing the same repository for this lab.
Have all team members use the Git command-line to clone the repo to their computer.
Instructions
Your task is to read in a text file (containing Markdown-formatted text) and create HTML elements to fill in the page.
We’ve broken the problem up into multiple functions for each section, so you can split the workload across team members. They will look like the following:
processFormatting(String) : String
- This function should do multiple RegEx “find-and-replaces” to convert the given Markdown text into HTML, for the formatting rules.
processChecklists(String) : String
- This function should do a RegEx “find-and-replace” to convert the given Markdown text into HTML, for only the Checklists.
processCriteria(String) : String
- This function should do a RegEx “find-and-replace” to convert the given Markdown text into HTML, for only the Criteria.
processGuidelines(String) : String
- This function should do a RegEx “find-and-replace” to convert the given Markdown text into HTML, for only the Guidelines.
These functions will be called one after the other, so the output of one function will be the input of the next. Finally, the output of processGuidelines
will be the HTML that will be inserted into the DOM.
Steps:
- Your team will need to code all four
process
functions.- In each function, you must only process the text that is relevant to that function. For example,
processChecklists
should not convert Markdown links to HTML. - We recommend you delegate each function to a “sub-team”
- You may want to reference this guide on using RexExp objects in JavaScript
- In each function, you must only process the text that is relevant to that function. For example,
- Try to test/develop your RegEx patterns in RegExr first! Here is one with example markdown.
- Don’t forget to test the webpage to make sure that your function is working properly!
- You may need to view the page’s source to see your converted output.
- You can also log the returned string to the console for debugging.
- After finishing a function, Make a commit in Git with your team’s name and the method name as the commit message, like
Team Kraken - processFormatting1
. - Synchronize (
git pull
from the server, thengit push
) your commits with the remote repository- You may (read: will likely) encounter merge conflicts after a
pull
! If you do, follow the steps here to resolve the conflict and commit the resolution.- You will need to make a decision on whether or not to include your code vs. the code from the remote.
- Make sure you test the website again to make sure you didn’t accidentally break anything 😖
- After resolving the conflict, commit it and then try to synchronize your commits again.
- If you get an error when
pull
ing, see if it mentions a default pull strategy or similar.- This means you need to set the default pull behavior. For this lab, we will want to tell it to
merge
. Run this command to set merge as the default:git config --global pull.merge true
- Next, repeat the
pull
andpush
again, following the instructions above.
- This means you need to set the default pull behavior. For this lab, we will want to tell it to
- You may (read: will likely) encounter merge conflicts after a
Tips for Success:
- Here is an example RegEx that searches for text marked for bold and replaces it with
<strong>
tags:let text = "Some text with __boldness__ and __strength__"; let re = new RegExp("__([^_]+?)__", "g"); OR let re = /__([^_]+?)__/g; text = text.replaceAll(re, "<strong>$1</strong>"); // Called on the String
- You can create a
RegExp
object using the constructor or a “RegExp literal”, with the slashes. - Pay attention to the flags (just
g
in this case)- These modify how the RegExp will work –
g
stands forglobal
and will let you use methods like a String’sreplaceAll()
method
- These modify how the RegExp will work –
- Take a look at the RegExr breakdown here for an explanation of the pattern
- You can create a
- For
processFormatting
, you should only need theg
flag, like above.- However, you will need to do multiple find-and-replaces in a row for the different formatting types!
- For
processChecklists
,processCriteria
, andprocessGuidelines
, you may need to use three flags:g
– global,m
– multiline (enables use of start^
and end$
of line), ands
– dotall (makes the dot.
match newlines as well)- Here is an example RegEx that uses all three flags:
This allows the pattern to match across lines, like so:
let re = new RegExp("^pat(.*)tern$", "gms"); OR let re = /^pat(.*)tern$/gms;
pat another line tern
- Here is an example RegEx that uses all three flags:
- You can make multiline strings using JavaScript template literals:
let html = `<div class="primary"> <a href="https://www.google.com/">Search</a> </div>`;
Markdown Format Guide
Take a look at the Markdown Basic Syntax, which includes the corresponding HTML for given Markdown text. Look at the Headings, Emphasis, and Lists sections.
To simplify, we will focus on the following rules for formatting:
- Italicized text is represented by one underscore surrounding some text (
_some text_
) and should use the<em>
tags (<em>some text</em>
) - Bold text is represented by two underscores on both sides (
__some text__
) and should use the<strong>
tags (<strong>some text</strong>
) code
text is represented by backticks surrounding some text (`some text`
) and should use the<code>
tags (<code>some text</code>
)- Links are represented by a pair of square brackets followed by parentheses (
[some text](URL)
). The link text is in the brackets, and the URL is in the parentheses (<a href="URL">some text</a>
)
Here’s a snippet from one of the checklist files:
#### Guideline 1.1: Provide text alternatives for any non-text content
* [1.1.1 Non-text Content](https://www.w3.org/TR/WCAG22/#non-text-content)
* Images, image buttons, and image map hot spots have appropriate, equivalent [alternative text](https://webaim.org/techniques/alttext/).
* Images that __do not__ convey content, are decorative, or contain content that is already conveyed in text are given empty _alternative text_ (`alt=""`) or implemented as CSS backgrounds. All linked images have descriptive alternative text.
<!--END CRITERION-->
<!--END GUIDELINE-->
This should translate into the following HTML:
<div class="guideline">
<h4>Guideline 1.1: Provide text alternatives for any non-text content</h4>
<ul class="criteria">
<li>
<a href="https://www.w3.org/TR/WCAG22/#non-text-content">1.1.1 Non-text Content</a>
<ul class="checklist">
<li>Images, image buttons, and image map hot spots have appropriate, equivalent <a href="https://webaim.org/techniques/alttext/">alternative text</a>.</li>
<li>Images that <strong>do not</strong> convey content, are decorative, or contain content that is already conveyed in text are given empty <em>alternative text</em> (<code>alt=""</code>) or implemented as CSS backgrounds. All linked images have descriptive alternative text.</li>
</ul>
</li>
</ul>
</div>
Format: Guidelines
Guidelines start with ####
(four pound signs and a space) and their title:
- The guideline’s content consists of everything after the guideline title and before
<!---END GUIDELINE--->
- In HTML, each guideline should be represented by a
<div>
with the classguideline
- The guideline title is the first element in the
<div>
and represented byh4
-level heading - After the title, there should be an unordered list
<ul>
with the classcriteria
- All content should be put in between the
<ul>
tags
For example:
#### Guideline 1.1: Provide text alternatives for any non-text content
...a bunch of content, including potentially some HTML...
<!--END CRITERION-->
<!--END GUIDELINE-->
should become:
<div class="guideline">
<h4>Guideline 1.1: Provide text alternatives for any non-text content</h4>
<ul class="criteria">
...a bunch of content, including potentially some HTML...
</ul>
</div>
Format: Criteria
Each criterion starts with *
at the beginning of a line (a star and a space) and their title:
- The criterion’s content consists of everything after the criterion title and before
<!--END CRITERION-->
- In HTML, each criterion should be represented by a list item
<li>
- The criterion title should be inside the
<li>
- After the title, but still inside the
<li>
, there should be an unordered list<ul>
with the classchecklist
- All content should be put in between the
<ul>
tags
For example:
* 1.1.1 Non-text Content
...a bunch of content, including potentially some HTML...
<!--END CRITERION-->
should become:
<li>
1.1.1 Non-text Content
<ul class="checklist">
...a bunch of content, including potentially some HTML...
</ul>
</li>
Format: Checklists
Each checklist item starts with *
(four spaces, a star, and a space):
- The item’s content is all on one line, after the
*
- In HTML, each item should be represented by a list item
<li>
- All content should be put in the
<li>
For example:
* A descriptive transcript of relevant content is provided for non-live audio-only (audio podcasts, MP3 files, etc.).
should become:
<li>A descriptive transcript of relevant content is provided for non-live audio-only (audio podcasts, MP3 files, etc.).</li>
3 - Lab 17 - Git Revert Undo
Learning Objectives
- pronounce “awry” as “uh-rye”
- executing the WAVE tool
- reading and understanding the WAVE tool output
- correcting issues identified by the WAVE tool
- committing changes to a git repository
- using
git revert
to undo a commit
Introduction
The WAVE tool is designed to facilitate the evaluation of web content for accessibility issues. It is a browser extension that can be used to identify potential issues in a web page. The tool provides a visual representation of the page with icons that indicate potential issues. Clicking on an icon will provide more information about the issue and suggestions for how to correct it.
Gitting Started
In this week’s prep you already checked that you have a few global git configuration options set (i.e. user.name
and user.email
), but it’s possible you’d enjoy having a few more in place. Here’s an excerpt from mine in case you’d like to have any of those options as well.
- Begin with the starting code provided by your instructor (e.g. from an assignment in your learning management system) or else in the these go to eleven repo (the best way to begin with such code is to
clone
it to your computer using the steps below).- open a terminal window
- navigate to a place where you’d like to work,
- e.g.
cd $HOME/Desktop
- if you’re on Windows and that failed, try this instead
cd $HOME/OneDrive/Desktop
- if you’re on Windows and that failed, try this instead
- it doesn’t matter exactly where you work as long as you know where it is.
- e.g.
- clone the git repository (if you first created a repository on github via github classroom assignment or instantiating the linked template repository, get the URL for cloning from that git repo you newly created and use it in place of the
git@github...
part in the following command), e.g.git clone git@github.com:hcientist/these-go-to-eleven.git
- if you now
ls
you should see that you have a directory namedthese-go-to-eleven
- navigate into this cloned repo by doing
cd these-go-to-eleven
- open the cloned repo in VS Code by typing
code .
- add your name to the
Contributors
section of theREADME.md
file.- open the
README.md
file - notice that even though the existing entries both begin with
1.
, they are rendered in the browser as consecutive increasing numbers. This is because the README file is written in a syntax called markdown. That markdown is being rendered as HTML, and the browser is interpreting the numbers as an ordered list. - add your name to the list, following the existing pattern
- save the file
- open the
- create a “restore point” including your changes by committing them to the local git repository
- in the terminal window, type
git status
to see what files have been changed - type
git add README.md
to stage the changes to the README file - type
git commit -m "added my name to the contributors list"
to commit the changes
- in the terminal window, type
- backup your changes by pushing them to the
remote
git repository- type
git push
to push the changes to the remote repository
- type
WAVE Evaluation
- Launch the VSCode Live Server and view the provided index.html file in your browser.
- enjoy your new drumkit
- open the WAVE tool by clicking on the WAVE icon in the browser toolbar
- click on the icons in the WAVE tool to view the issues identified by the tool
Correcting Document Structure Issues
- You should see
0 errors
if you run the WAVE tool against the providedindex.html
file. - However you should see several alerts, including these two:
No heading structure
No page regions
- Correct the first issue by adding an
h1
element to the page.- open the
index.html
file - add an
h1
element to the page as the first child of the body, give the element some text, you can choose what you want, but I choseThese go to 11...
- save the file
- refresh the page in the browser
- Confirm that the
No heading structure
alert is no longer present.- (optionally, you could create a “restore point” at this stage by committing your changes to the local git repository)
- open the
- Correct the second issue by adding a
main
element to the page.- wrap the current contents of the html
body
element in amain
element. - save the file
- refresh the page in the browser
- Confirm that the
No page regions
alert is no longer present.
- wrap the current contents of the html
- Create a “restore point” at this stage by committing your changes to the local git repository
- in the terminal window, type
git status
to see what files have been changed (it should only list theindex.html
file) - type
git add index.html
to stage the changes to the index.html file - type
git commit -m "fixed 2 WAVE alerts related to document structure"
to commit the changes
- in the terminal window, type
Correcting(?) Issues Related to Audio
- In the WAVE tool, you still see no errors, and should now only see the 9 alerts related to HTML5 audio elements.
- improve the accessibility of the page by adding transcripts to the audio elements.
- open the
index.html
file - in the content of each of the (9)
audio
elements, add 2 links: one to the transcript of the audio, and one to the audio itself (the transcript files do not actually exist yet).- e.g. change
to
<audio data-key="65" src="sounds/clap.wav"></audio>
<audio data-key="65" src="sounds/clap.wav"> <a href="sounds/clap.wav" download>Download the clap sound effect</a> or <a href="clap.txt" download="clap.txt">its transcript</a> </audio>
- e.g. change
- save the file
- open the
- Create a “restore point” at this stage by committing your changes to the local git repository
- in the terminal window, type
git status
to see what files have been changed (it should only list theindex.html
file) - type
git add index.html
to stage the changes to the index.html file - type
git commit -m "added transcripts to audio elements"
to commit the changes
- in the terminal window, type
Correcting “Corrections” 😒
- In the WAVE tool, what was the impact of adding the transcripts to the audio elements?
- not much. The alerts are still there. This doesn’t necessarily mean you failed, but in this case, it seems a bit unclear that the general recommendation applies to our scenario. as these audio files are only sound effects and as each is already labeled with a textual description, it’s not clear that a transcript is helping very much.
- that being said, the inner content of elements like
audio
andvideo
can be used to provide fallback content for browsers that don’t support the media type or for users who can’t access the media for some reason. So, it’s not a bad idea to provide a link to a transcript/the audio file to download, but it’s not clear that it’s necessary in this case.
- that being said, the inner content of elements like
- not much. The alerts are still there. This doesn’t necessarily mean you failed, but in this case, it seems a bit unclear that the general recommendation applies to our scenario. as these audio files are only sound effects and as each is already labeled with a textual description, it’s not clear that a transcript is helping very much.
- Undo the changes you made to the
index.html
file related to the audio elements.- in the command line, type
git log
to see the commit history. this history is displayed in reverse chronological order, with the most recent commit at the top.- the git log is typically displayed in program called a
pager
- the default pager is not well documented, it’s often
less
, but it could be one calledmore
on some systems. - when viewing the commit log in either
less
ormore
you can scroll through the log by using the arrow keys. to exit the pager, typeq
. (many othervi
keybindings would also work)
- the git log is typically displayed in program called a
- notice that the most recent commit is the one that you’d like to undo
- notice also that this most recent commit has the label
HEAD
next to it. - press
q
to exit the pager - type
git revert HEAD
to undo the most recent commit- it’s possible that you’ll be prompted to enter a commit message. if so type one and save the file.
- if you see something like the screenshot below, you’re now in a text editor called
vim
. - to enter text in
vim
, pressi
to enterinsert
mode. you should see-- INSERT --
at the bottom of the screen. type your commit message. when you’re done, pressesc
to exitinsert
mode. then type:wq
to write the file and quit the editor.
- if you see something like the screenshot below, you’re now in a text editor called
- it’s possible that you’ll be prompted to enter a commit message. if so type one and save the file.
- in the command line, type
- Submit the current state of your code according to your instructor’s instructions (e.g. by pushing to the github classroom repo).
4 - Lab 16 - Persistence: Import/Export
localStorage
using the FileReader to support export/import of app state.Learning Objectives
By the end of this lab, you should be able to:
- export from– and import to–
localStorage
Prerequisites
- beginning localStorage (e.g. as exercised in Labs 10 and 11)
- Familiarity with the browser’s
FileReader API
Instructions
- Begin with the starting code provided by your instructor (e.g. from an assignment in your learning management system) or else in the Transportodon repo
- Complete the Transportodon app as specified in the page’s aside.
5 - Lab 15 - Persistence: User Experience
localStorage
and location
Web APIs to create a more featureful user experience.Learning Objectives
By the end of this lab, you should be able to:
- create (receive/parse) a “sharable link” such that another user of your app would get to a particular state of the app
- export from– and import to
localStorage
Prerequisites
- beginning localStorage (e.g. as exercised in Labs 10 and 11)
- Familiarity with the browser’s
Location
interface (e.g. as outlined in prep 10)
Instructions
- Begin with the starting code in the Persistodon repo
- Complete the Persistodon app as specified in the page’s aside.
6 - Lab 14 - Play Fetch
Learning Objectives
By the end of this lab, you should be able to:
- Understand the different request methods and how they differ
- Use fetch() to interact with third-party APIs
- Modify an HTML page based on the result of an API call
Introduction
In this lab, you will use the knowledge you’ve learned about HTTP requests, asynchronous Javascript (including Promise
), and fetch()
to interact with a third-party API and use its results to modify an HTML page.
You’ll start by practicing your requests and learning about the different request methods and the different ways of formatting data for a request.
Then, you’ll retrieve data from an API and use it to populate a page and modify the DOM.
In the last part, you will write some starter code that interacts with the specific API you chose for the class project.
Getting Started
Start by going to the GitHub Classroom link provided by your instructor and accept the assignment. For this lab, you may work in your project groups.
Clone the created repository to your computer. You will need to use Live Preview or Live Server for this lab; opening the file directly in your browser may prevent some requests from working.
Open the repository folder in VS Code.
Part 1: Requests Practice – Echo (echo) Server
For this first part, we will be interacting with an “echo server” that simply echoes back the request that you give it. We’ll use Zuplo’s Echo API.
Start with the part1.html
and js/part1.js
files. You will see a couple of input fields and three buttons, plus an area for the output. Each of the buttons needs to make a specific request to the echo API, and then display the resulting JSON in the output. You shouldn’t need to modify the HTML for this lab, just reference it. Edit the JavaScript
-
Write the event handler for
get-btn
(this should be stubbed out for you inpart1.js
):-
This function should send a
GET
request to thehttps://echo.zuplo.io/api
endpoint. -
The request should include the name and the age as parameters in the URL’s query string
-
There are two ways of accomplishing this:
- Manually add the keys and values to the URL:
let resp = await fetch("https://www.mywebsite.com/search?q=" + query + "&page=" + pageNum);
- Use URLSearchParams and give the constructor an object containing the keys and values you want to encode:
(Note: the URLSearchParams constructor can also parse a query string, and then you can easily access its keys/values)
let params = new URLSearchParams( {q: query, page: pageNum} ); let resp = await fetch("https://www.mywebsite.com/search?" + params.toString());
- Manually add the keys and values to the URL:
-
After you get the response from the server, parse the body as JSON
-
Set the
textContent
of the<pre>
element (with the id ofoutput
) to a nicely-formatted version of that JSON:JSON.stringify(...)
can take in three parameters: the object you want to stringify, a “replacer” (which can be null), and the number of spaces to indent the JSON. This will produce a formatted version of the data:let data = { city: "Seattle", population: 757992, }; let formatted = JSON.stringify(data, null, 2); // JSON.stringify(object_to_format, null, num_spaces_for_indent)
-
Test the “GET” button (open the developer console to check for errors). You should see something like this:
Notice how the
"query"
attribute contains the parameters from the query string we gave.
-
-
Next, write the event handler for
post-json-btn
:-
This function should do the same thing, except, instead of a
GET
request, it should send aPOST
request. -
The body of the request should be JSON data that contains the
name
and theage
:- The
fetch()
function can accept a second argument, which is an object that specifies the request options:let options = { method: "POST", headers: { "Content-Type": "application/json", // or "application/x-www-form-urlencoded", "text/plain", etc. }, body: JSON.stringify( {q: query, page: pageNum} ), }; let resp = await fetch("https://www.mywebsite.com/search", options);
- The
-
Again, after you get the response, parse the body as JSON and display it in
output
. This should look like:Note how now the request’s data was found in
"body"
instead of"query"
.
-
-
Finally, write the event handler for
post-form-btn
:-
This function does the same as the last, but, instead of the data being formatted as JSON, the data should be formatted as “URL-encoded” form data. This is how HTML forms usually POST their data to a server.
-
The body of the request basically contains data in the same format as a query string:
let options = { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", }, body: new URLSearchParams( {q: query, page: pageNum} ), }; let resp = await fetch("https://www.mywebsite.com/search", options);
-
You should also parse the response’s body as JSON and display it in
output
. This should look like:Now, look at how the request’s data are formatted in the
"body"
.
-
With Part 1, you should feel comfortable using fetch()
to make requests and include data in both the query string and the request body. These are fundamental tools to add to your arsenal for dealing with any API you may encounter!
Part 2: List Those Users!
Now that we’ve practiced making API requests with a simple echo server, let’s go a little further and interact with an API that actually gives real (fake) data! We will use reqres.in
, which provides mock data via a simple set of API endpoints.
Open the part2.html
and js/part2.js
files. The HTML contains an example of how a user should be displayed and an empty <div>
with the id of user-list
.
- In
js/part2.js
, inside theDOMContentLoaded
event handler, write code to request the first page of users fromreqres.in
:- First, take a look at the API endpoints for
reqres.in
, specifically the “List Users” endpoint. - The base URL is
"https://reqres.in"
, and the endpoint is"/api/users"
. This means that the full URL you should send the request to is"https://reqres.in/api/users"
. - What request method does it use? (
GET
?POST
?PUT
?) - How do you specify which page to retrieve? (Query string? JSON body? Form body?)
- First, take a look at the API endpoints for
- Once you get the response from the API, you should parse the body as a JSON object.
- We don’t always do this; it depends on what the API endpoint returns! (aka we need to read the documentation)
- For
reqres.in
, all the endpoints return stringified JSON data in the response body.
- Next, you’ll want to loop over the returned list of users and create new elements in the HTML for each user.
- Take a look at the format of the returned data first on the
reqres.in
website! - Each new user added to the HTML should follow this format:
<div class="card"> <h2>Firstname Lastname</h2> <img src="https://reqres.in/img/faces/some_image.jpg" alt="Firstname Lastname"> </div>
- You can create the elements manually in JavaScript, you can clone the existing example, or you can create a
<template>
to use.- You may minimally modify the HTML to help you, but the format of each user must match the example above.
- Make sure each new user card is added to the
<div>
with the id ofuser-list
. Also don’t forget to add the"card"
class to the<div>
!
- Take a look at the format of the returned data first on the
The result should look like this:
Part 3: Your Project APIs
For this last part, you will interact with the two APIs you chose for your semester-long project. For now, you will simply make a request and display the response.
Open the part3.html
and js/part3.js
files. You will need to modify both the HTML and JS for this part.
- In
part3.html
, for API #1, replace[TODO]
with the name of one of your APIs. - Next, go to the documentation for your specified API. Find a specific endpoint you want to use. Take note of the following:
- What is the base URL for the API?
- (This is usually found in a “Getting Started” or “API Concepts” documentation)
- Does your API require authentication?
- (This is also usually found in “Getting Started” pages)
- What is the path to the specific endpoint?
- (Found on your specific endpoint’s documentation)
- What method does the endpoint use?
- (
GET
,POST
,PUT
,PATCH
,DELETE
)
- (
- How is the data specified?
- (In the query string? In the body as JSON/form-urlencoded?)
- What format is the data returned in?
- (JSON? Text? No data?)
- What is the base URL for the API?
- In the HTML, replace the
[TODO]
for the URL with the full URL of the endpoint you will be using. - Also replace the method (
[GET/POST/PUT/...]
) with just the specific one you will be using. - In the
js/part3.js
file, in the event handler for theapi-1-btn
, write code to make the request and output the returned data.- If your API’s response does not contain any data in the body, output the status code instead.
- I recommend using the MDN docs on
fetch()
as a reference. - Also
console.log(...)
the response object (fromfetch()
) so you can look at it in the developer console! - Make the output nicely formatted if it’s JSON, just like in Part 1.
- Test the button. Does it display anything? Make sure to open the developer console to check for errors!
- Usually the HTTP status code of the response can help diagnose what’s wrong.
- Sometimes, its as simple as missing a parameter, or forgetting to include the “Content-Type”!
- If you are getting an error saying something about “CORS” or “origin”:
- Does your API support CORS?
- (This can be found in the documentation or on the public api list if that’s where you found your API)
- What is CORS?
- Cross-Origin Resource Sharing (CORS) is a way for a server to say, “Hey, I’m allowing other webpages to access me! Here’s a list of the ones I approve of.”
- Without CORS enabled, web browsers will NOT allow a page to access that specific server/resource! This is for security reasons; otherwise, malicious websites could send requests to, say, your banking site, using your login credentials!
- However, server-side applications can still access that server; CORS is only for restricting client-side access.
- This means that we are unable to access it from anything we do in CS 343. We would need to access it via a backend.
- But wait! There’s a workaround:
- Simply tell a server to make the request for you!
- There’s a free “CORS Proxy” at corsproxy.io you can use. There is also allOrigins.win as an alternative.
- The CORS proxy will act as a intermediary between you and the API server. This does open up some concerns about latency and security, so only use it for non-sensitive data and only for this class.
- Does your API support CORS?
- Did your API return something about “unauthorized”?
- You may need to authenticate your app! Look in the documentation to see how you need to retrieve an “API key” or “access token” of some kind.
- This is usually then given to the API in the header of your request, or even in the query string.
- There are other methods of authorization, which may be more complicated to use.
- Are you using the Spotify API? It’s a little more complicated to authorize!
- You may need to authenticate your app! Look in the documentation to see how you need to retrieve an “API key” or “access token” of some kind.
- Usually the HTTP status code of the response can help diagnose what’s wrong.
- Once the first API is working, repeat the steps for the second API!
- This should give you a head start on the last part of the project.
- For your actual project, you will need to do something with the response, not just output it!
Submission
Commit and push your code back to GitHub.
7 - Lab 13 - HTTP Requests: Making Requests of Third-Party APIs
Learning Objectives
By the end of this lab, you should be able to:
- make requests to a third-party API using PostMan
- make requests to a third-party API using fetch
- handle successful and unsuccessful responses from a third-party API using Promises
Prerequisites
- Install PostMan
- Make a Canvas token (Note: In doing this, you will need a safe place to store a very long string. If you don’t already use a password manager, consider starting. Dr. Stewart loves 1Password, but it costs money. If you’re looking for a free option, consider Bitwarden).
- Go to your user settings in Canvas
- Scroll Down to the bottom of the “Approved Integrations” section and click the “+ New Access Token” button
- Give your token a name (e.g. “CS343 Demo Token”)
- Probably give a very short expiration like tomorrow since this is easy to create and you can always make another
- Click “Generate Token”
- Copy the token and store it in a safe place (e.g. password manager. Canvas will not show it to you again. If you don’t store it now you’ll have to make a new one.)
Test the Canvas API in PostMan
-
In PostMan, create a new collection named
Canvas
(this is just a way to organize your requests) -
In that collection (
Canvas
), find the (tiny?)Authorization
“tab” and click it and then- set the type to
Bearer Token
- paste in your Canvas token into the
Token
field - press your OS’s hotkey for saving (e.g. command + s on macOS and ctrl + s in all other OSes)
- set the type to
-
Within the Canvas collection, find the (tiny!)
Overview
“tab” and click it. -
Under
Add new
, clickHTTP request
-
Name your request
Get Courses
(in the first field that is focused automatically) -
where the placeholder says
Enter URL or paste text
, paste inhttps://canvas.jmu.edu/api/v1/courses
-
press your OS’s hotkey for saving (e.g. command + s on macOS and ctrl + s in all other OSes)
-
confirm that this request’s
Authorization
“tab” (so tiny!) has its type set toInherit auth from parent
Headers
“tab” (so tiny!)- (click
Hidden
first 🤦♂️) shows (among others) anAuthorization
key with valueBearer YOUR_TOKEN_HERE
- (click
-
press your OS’s hotkey for saving (e.g. command + s on macOS and ctrl + s in all other OSes)
-
press the blue
Send
button -
In the bottom half of PostMan (the Response section), you should soon see something like the following (a JSON array of all your current and past courses)
It's a bit long, does this thing make it a little easier to scroll past after a quick inspection?
[ { "id": 1997199, "name": "343 - S24 - Stewart", "account_id": 81707, "uuid": "FMElx6J6xp5QYV1k2dVyzyuRtbFbo5epwcnO7WeL", "start_at": null, "grading_standard_id": null, "is_public": false, "created_at": "2023-10-12T10:17:04Z", "course_code": "CS343S24", "default_view": "modules", "root_account_id": 81707, "enrollment_term_id": 7536, "license": "private", "grade_passback_setting": null, "end_at": null, "public_syllabus": true, "public_syllabus_to_auth": false, "storage_quota_mb": 15000000, "is_public_to_auth_users": false, "homeroom_course": false, "course_color": null, "friendly_name": null, "apply_assignment_group_weights": true, "calendar": { "ics": "..." }, "time_zone": "America/New_York", "blueprint": false, "template": false, "sis_course_id": "CS343_0001_SP24", "integration_id": null, "enrollments": [ { "type": "teacher", "role": "TeacherEnrollment", "role_id": 3374, "user_id": 5480485, "enrollment_state": "active", "limit_privileges_to_course_section": false } ], "hide_final_grades": false, "workflow_state": "available", "course_format": "on_campus", "restrict_enrollments_to_course_dates": true }, { "id": 1997223, "name": "347 - S24 - Stewart", "account_id": 81707, "uuid": "JWACwAeAmipqP03wjlxJM3rF5FMzlEy1YLW6mtIk", "start_at": null, "grading_standard_id": null, "is_public": false, "created_at": "2023-10-12T10:17:05Z", "course_code": "CS347S24", "default_view": "modules", "root_account_id": 81707, "enrollment_term_id": 7536, "license": "private", "grade_passback_setting": null, "end_at": null, "public_syllabus": true, "public_syllabus_to_auth": false, "storage_quota_mb": 15000000, "is_public_to_auth_users": false, "homeroom_course": false, "course_color": null, "friendly_name": null, "apply_assignment_group_weights": true, "calendar": { "ics": "..." }, "time_zone": "America/New_York", "blueprint": false, "template": false, "sis_course_id": "CS347_0002_SP24", "integration_id": null, "enrollments": [ { "type": "teacher", "role": "TeacherEnrollment", "role_id": 3374, "user_id": 5480485, "enrollment_state": "active", "limit_privileges_to_course_section": false }, { "type": "teacher", "role": "TeacherEnrollment", "role_id": 3374, "user_id": 5480485, "enrollment_state": "active", "limit_privileges_to_course_section": false } ], "hide_final_grades": false, "workflow_state": "available", "course_format": "on_campus", "restrict_enrollments_to_course_dates": true } ]
Test the Canvas API in the Browser via JavaScript
Canvas Tab
- open a tab to JMU’s Canvas (any page, perhaps you still have the settings tab open?) and login.
- open the browser’s developer tools and go to the javascript console
- paste in the following code and press enter:
const responsePromise = fetch('https://canvas.jmu.edu/api/v1/courses', { headers: { Authorization: 'Bearer YOUR_TOKEN_HERE' } });
- once you do that you should see just
<- undefined
⚠️ Initializers in js evaluate to undefined
In Javascript variable declaration initializers (e.g. for const), unlike assignment operators, returnundefined
. This is why you seeundefined
after running the code above. - As you saw in the reading, the
fetch
function from the browser’s Fetch API makes an HTTP request (represented in Javascript as a Request object) and (immediately) returns a Promise that will resolve to a(n HTTP) Response object when a response is received for the request. Use thethen
method on the Promise to handle the successful response. A very common way to handle responses to API calls like this one is to parse the response as JSON. Add the following code to the console and press enter to parse the response as json and to log the result of that (also asynchronous) parsing to the console:responsePromise .then(response => response.json()) .then(console.log);
- You should see the same JSON array of courses that you saw in PostMan.
Non-Canvas Tab
- open a tab to a page that’s not Canvas (maybe just use this tab for a quick test?)
- open the browser’s devtools to the javascript console
- press up on the keyboard to get back statement you made in the steps above that fetch from the canvas api
- press enter to run that fetch again, but now in this tab
- you should see an error in the console that says something like the following
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://canvas.jmu.edu/api/v1/courses. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 401.
Test the RhymeBrain API in PostMan
- In PostMan, create a new collection named
Unauth API Demos
- In that collection (
Unauth API Demos
), find the (tiny?)Overview
“tab” and click it. - Under
Add new
, clickHTTP request
- Name your request
Get Rhymes
(in the first field that is focused automatically) - where the placeholder says
Enter URL or paste text
, paste inhttps://rhymebrain.com/talk?function=getRhymes&word=web
- press your OS’s hotkey for saving (e.g. command + s on macOS and ctrl + s in all other OSes)
- press the blue
Send
button
🌈 This API does not protect against CORS
So you should be able to test it in any browser window you want, or by dropping the necessary code into your own site:
fetch('https://rhymebrain.com/talk?function=getRhymes&word=web')
.then(response => response.json())
.then(console.log);
Test some other API
- Find an API that you’re interested in (e.g. one from the list on the Final Project Page and try it out in PostMan and in Javascript in your browser’s devtools Javascript console.
- e.g. Dog Facts
8 - Lab 12 - Them Problem
Learning Objectives
By the end of this lab, you should be able to:
- call functions that return promises
- test functions that return promises
- recognize that not every problem is yours, but that some problems are “theirs”, “them problem"s if you will.
Goal
Provided with the starting code from the template here or from your instructor (check with them), create something similar to this demo available for mobile and desktop.
There are several “Them Problems” described by a pair of discordant emotional states in which “you” have a positive affect, but “they"have a negative affect, e.g.
- you
- poppin'
- they
- stoppin'
- you
- packin'
- they
- lackin'
Currently
In the provided starter code, the list of possible states “you” might be in comes from a call to a synchronous function (getYous
) that immediately returns a short array of strings. Once one of these is selected, the starting code retrieves the corresponding state that “they” might be in when it’s a “them problem” through a call to a synchronous function (getThey
). This function also immediately returns, but only 1 string.
Your task
- replace the call to
getYous
with a call togetOptions
which returns a promise that resolves to the array of strings. - replace the call to
getThey
with a call togetThemProblem
which returns a promise that resolves to the string.
Stretch Goals
JS
- invoke
toggleLoader
when appropriate to show the loading animation to give the visitor feedback that something is happening “in the background”.- note: this js function is already in the code and the necessary CSS is already in the provided CSS file.
- inspect and critique the JS code.
- did you see anything new (to you)?
- is it DRY?
- is it organized?
- is it performant?
- what would you change?
Content
Add to the collection of “them problems”
- how many can you come up with?
- do they rhyme?
- what’s your fav?
- did you add them successfully to your demo?
HTML
Inspect and critique the HTML structure
- did you see anything new (to you)?
- is the provided HTML semantic?
- is it accessible?
- is it responsive?
- is it performant?
- what would you change?
CSS
- Inspect and critique the aesthetic and user experience. try the site in:
- dark vs. light mode
- narrow vs. wide viewports
- on faster and slower(throttled) network connections
- Inspect and critique the CSS code.
- did you see anything new (to you)?
- is it DRY?
- is it organized?
- is it performant?
- what would you change?
9 - Lab 11 - Card Viewer
Greeting Cards, Part 2
In the previous lab, you made a page that lets users create greeting cards and save them to localStorage. But we need a way to view the cards, edit them, and delete them (read, update, and delete in the CRUD operations).
Let’s create a card viewer that displays the data for each card, with a way to edit and delete each one.
Getting Started
- Start with your code from the previous lab
- The assignment is available in GitHub Classroom using your instructor-provided link (in Canvas)
- Let your instructor know if you do not have a working
card-creator.html
orcreatecard.js
- Here are some more hints for completing the previous lab:
localStorage.setItem("cards", ...)
will completely replace the existing item in localStorage (meaning you will override the previous array of cards)- Thus, you need to make sure to load the existing array of cards with
localStorage.getItem("cards")
, push a new item to that array, and then save the whole array back to localStorage - Don’t forget that localStorage stores values as strings
- To convert an array or object to a string:
var a_string = JSON.stringify(an_object);
- To convert a string back to an array or object:
var an_object = JSON.parse(a_string);
- To convert an array or object to a string:
Open up the card-viewer.html
and scripts/viewcards.js
files. You will be working with these for the lab.
Loading and Looping
First, we will need to load the array of cards from localStorage so that we can loop over each card and display it.
-
In
viewcards.js
, use localStorage to get the item with the key"cards"
and convert it back to an array. Store this to a variable or constant calledcards
.- Don’t forget to use
JSON.parse(...)
!
- Don’t forget to use
-
Next, use a “traditional”
for
loop to loop over the array (using indices – this will be important later!)- Also important: use
let
instead ofvar
for your variables - Recommended: save
cards[i]
to a variable calledcard
to make it easier to reference
- Also important: use
-
Inside the loop, use
console.log(...)
to print the current card object in the iteration. -
Test your page in the browser and open the developer console
- FYI, you should always be testing your code like this to make sure there are no JavaScript errors!
-
You should see something like this:
Creating Multiple Cards
The next task you will tackle is to display a card for each item in the array. In the HTML, you will find a <main>
element with the id of card-list
. All the card displays should be a child of this element.
One way to do this is to create all the elements manually in JavaScript (using document.createElement(...)
) to form parts of a card, and then add it to the card list. This, however, is not maintainable. We should be able to define what we want a single card to look like in HTML and CSS and then reuse that code for each card.
The <template>
element makes our lives much easier. It lets us write HTML that doesn’t render in the browser, but can be cloned and inserted into our page.
-
First, take a look at this article on using templates: HTML
<template>
Tag- Look at the HTML for the examples. Do you see where the templates are defined?
- We can use
document.getElementById()
ordocument.querySelector()
to first select the template - We can then call the
.content.cloneNode(true)
method on that template, which will return a new Node representing a copy of that template - Then, we can append that copy somewhere on our page
-
Let’s apply the same principle to our card viewer:
- In your JavaScript, select the template element and save it to a variable named
template
.- (You can do this inside or outside the loop)
- Inside the loop, call
template.content.cloneNode(true)
to create a copy of the template, and then save it to a variable namedcardView
. - Finally, select the element with the
card-list
class, and call.appendChild(cardView)
on it to add the newly created card to the list.
- In your JavaScript, select the template element and save it to a variable named
-
Test your code. You should have multiple cards displayed, one for each card in localStorage:
Displaying the Data
Now, we need to populate the newly created cardView
with the data from the current card.
-
Put your code before you call
.appendChild()
, but after.cloneNode()
: -
First, select each of the
<span>
s that are used to display the card’s text and save them to variables:- For example,
let titleText = cardView.querySelector(".title-text");
- You should have five of these, one for each span.
- For example,
-
Set each of those
<span>
’stextContent
to the appropriate values from the current card- Remember that each card is an object, so you can access the attributes directly: e.g.,
card.title
- The five attributes are: to, from, title, subtitle, message
- Remember that each card is an object, so you can access the attributes directly: e.g.,
-
Test your code. Each card should display its corresponding text:
Deleting Cards
Let’s make the delete button work. To do so, we’ll need to do a few things.
- Continue with your code inside the loop. Make sure that the following lines are still before you call
.appendChild()
! - We need to make the delete button for the current card do something.
- First, select the delete button on the
cardView
- Then, add an event listener of type
"click"
- For the callback function, make an inline function – this is important!
- First, select the delete button on the
- When the button is clicked, we want to delete this card. The problem is, how does each delete button know which card its referring to?
- In the callback function, write
console.log(i)
to log the current index. - Test your page and open the developer console. Click on the delete buttons. Notice how each button correctly prints out the corresponding index!
- How does this work? When we create a function, JavaScript will “save” the state of our variables in something called a closure.
- If this isn’t working, you may have declared your variables with
var
instead oflet
. This is one of the advantages oflet
. It scopes the variable to the block instead of the function, which lets us keep its current state. - If closures scare you, there is an alternative method below
- In the callback function, write
- Now, in the button’s callback function:
- Make the button delete the item in the array at the current index
- Use the
.splice(...)
method to remove an item at a given index
- Use the
- Afterwards, save the array of cards back to localStorage
- Don’t forget to stringify it!
- Reload the page by calling
location.reload()
- We do this because, after deleting an item, the indices in the array are no longer valid, so let’s refresh the page and display all the cards again
- Make the button delete the item in the array at the current index
- Test your code. You should be able to delete a card and, once the page reloads, it should no longer be displayed.
(If you have time) Making the Cards Editable
Last but not least, let’s make the cards editable. You may have noticed that there’s a contenteditable
attribute on each of the <span>
s! This makes the element into something that works both as text and an input.
Elements with contenteditable
have an event called "input"
, which is fired whenever a user changes the value of the element.
-
Inside the loop, but still
appendChild
, let’s create a new function. Yes, right here.- Name the function
updateCard()
- Inside, you should set each of the current card object’s attributes (to, from, title, subtitle, message) to the content from the corresponding
<span>
s- For instance,
card.title = titleText.textContent;
orcards[i].title = ...
- For instance,
- Afterwards, save the entire array to localStorage again.
- Don’t forget to stringify it!
- Name the function
-
After the function definition, but still before
appendChild
, add an event listener for the"input"
event to all five<span>
s. Use yourupdateCard
function as the callback:- E.g.,
titleText.addEventListener("input", updateCard);
- E.g.,
-
Test your code by clicking in one of the fields and editing it. You should see the value change in localStorage:
- If you are having issues, double-check:
- Make sure you are using either
let
orconst
for your variables/constants, notvar
- Make sure you are passing
updateCard
as an argument, and not accidentally calling it withupdateCard()
- Make sure you are using either
- If you are having issues, double-check:
Alternative to Using Closures
Instead of using closures, you can also “store” the index of each card in the HTML elements themselves! We can create a custom HTML attribute, called a data attribute.
Here’s how that would work instead of closures:
- On each card view and/or each of the
<span>
s:- Add a new data attribute called
index
using JavaScript (aka"data-index"
in HTML)- Reference the MDN article for examples
- Set the value to the current index of the card
- Add a new data attribute called
- In your event handlers/callback functions, retrieve the
index
attribute.- Attributes are stored as strings, so you may need to convert it back to an int
- Use this value to specify which card to delete/update
Submission
Commit and push your code to GitHub.
10 - Lab 10 - Card Creator
Greeting Cards
In this (two-part) lab, you will write a tiny app to create greeting cards that you can send to your friends, family, and more! You will need the knowledge you’ve built in the past two preps (forms and localStorage).
For this lab, you will submit the assignment individually (but feel free to collaborate with others) via GitHub Classroom.
Getting Started
- Accept the assignment in GitHub Classroom using your instructor-provided link (in Canvas)
- Clone the newly-created repository on your computer
- Open the repository folder in VS Code
- Look over the provided code to get a feel for what it does and where you need to add your own
Creating the Form
We’ve provided the code and styles for the “preview” area of the page, but you’ll need to create a form and provide the functionality for a user to specify what their card’s title, message, to, from, etc. should be. Follow the image and the instructions below:
In card-creator.html
:
- Create an HTML
form
inside theform-area
- Give the form the class
card-form
- Give the form the class
- You will need four text
input
s and atextarea
, each with its ownlabel
- Put each group of
label
plusinput
in its owndiv
- Give this
div
a class ofform-group
- Give this
- Make sure to include
placeholder
text - You’ll want to make sure each element has a
name
andid
- Put each group of
- Add
button
s at the end of theform
- Put them inside a
div
with the classform-buttons
- The preview button should have
type="button"
- The save button should have
type="submit"
- Make sure they have
id
s, so you can access them easier in a script
- Put them inside a
Adding the Functionality
In the script.js
file, write some JavaScript to do the following:
- When the “preview” button is clicked, you should set the text in all the appropriate
span
s to the value of the corresponding control in the form. - When the “save” button is clicked, you should add the card to an array and save the array of cards to
localStorage
:-
You should start by loading the existing array from
localStorage
with the keycards
- If there doesn’t exist an entry with the key, create a new array and assign it to a variable
- If there does exist an entry with the key, you should parse it and assign it to a variable
-
Create a new JavaScript object (aka map/dictionary) to represent the current card
- It should have five properties:
to
,from
,title
,subtitle
, andmessage
- The properties should be set to the corresponding value from the form
- It should have five properties:
-
Add the new object to the end of the array
-
Store the array in
localStorage
to the entry with the keycards
, overwriting any existing entry- Don’t forget:
localStorage
only lets you store strings, so you’ll need to “stringify” the array!
- Don’t forget:
-
Saving multiple cards should result in an array containing all the cards. You can use the developer console in Chrome/Edge and Firefox to check if you’re doing this correctly:
-
Submission
Commit and push your code to GitHub.
11 - Lab 9 - Midterm 2 Review
Recent Topics
- URL Paths
- can you embed an image from your own site in a page? (like one where the jpg or png or whatever is in your site’s directory structure, rather than already hosted elsewhere)
- can you link to the image with an anchor element?
- can you link to another page on your site?
- do all of the above work locally as well as if you deploy to either GitHub Pages or w3stu?
- HTML
- forms
- text input fields
- submit button
- forms
- CSS
- selectors (review css diner)
- specificity (review [specificity explainer(https://css-tricks.com/specifics-on-css-specificity/) and css specificity calculator)
- Styling (arbitrary short list of examples, no guarantees)
- color
- text
- background
- border
- link
- visited link
- link currently hovered
- “active” link
- position (review quokka)
- relative
- absolute
- fixed
- text
- (color)
- weight
- size
- units
- absolute vs. relative
- color
- Layout
- padding vs. margins for spacing elements
- horizontal centering
- Flex
- vertical centering
- spacing along the primary vs. secondary flex axes
- grid
- rows
- cols
- areas
- padding vs. margins for spacing elements
- Responsive
- media queries
- viewport units
- JS
- Dom element
- selection
- “CRUD” operations
- create (and adding into the document)
- read
- update
- delete
- Event handling
- listening
- click, change, input, submit
- listening
- Dynamic styling
- via the classList attribute is preferred (why is that?)
- via the style attribute when necessary (e.g. Prep 7)
- Dom element
Review Instructions
Setup
- Create a directory for this lab, mine’s called
e2-review
- to give yourself a chance to check your understanding about URL paths:
- add a subdirectory for styles (mine’s called
styles
) - add a subdirectory for images (mine’s called
images
)- find any (benign) image on the web and save it in this subdirectory
- add a subdirectory to group a few of the pages (mine’s called
about
) - in the
e2-review
directory, create anindex.html
- in the
about
subdirectory, create aindex.html
and ateam.html
- add a subdirectory for styles (mine’s called
- create a file called
base.css
in thestyles
subdirectory - add a file called
script.js
- just have
script.js
console.log
something for now
- just have
- in the html pages
- put valid starter code (I typically use vscode’s built-in html snippet,
!
+ tab) - link the css file
- for now tell the css to make the background of the body a color that’s obviously not white just so that you can easily tell styles your css file are being applied
- embed
script.js
in each of your html files - add enough elements to demonstrate all the CSS. I’ll use at least:
- a header
- a nav
- link to all pages
- a main
- an image
- show the image you downloaded on every page
- (interrupt yourself here and jump down to Testing and test both locally and deployed)
- a form with a few fields (tip: for now probably have the form’s action be
#
and the method beget
) - optional additions
- a few divs
- a few sections
- a few links
- a few lists
- put valid starter code (I typically use vscode’s built-in html snippet,
- in
base.css
add enough styles to demonstrate all the CSS topics listed above- for example, you might add a rule that will change the color of the text in the nav when the link is hovered
- you might add a rule that will change the background color of the body when the window is less than 500px wide
- you might add a rule that will change the color of the text in the header when the link is hovered
- you might add a rule that will change the bg color and text color when the user prefers dark mode
- add a class that will change the color of the text in any elements that have the class to “another color”
- (interrupt yourself here and jump down to Testing and test both locally and deployed)
- in
script.js
add code that will demonstrate all the JS topics listed above- for example, you might add a button that when clicked will change the background color of the body
- you might add a form that:
- has a text input
- when submitted
- add a new list item to an existing list in the page where the new list item’s content is 2 things:
- text content is the value of the input
- a button that when clicked will remove the list item
- the input should be cleared after the new list item is added
- make it such that every click on the list item itself toggles the color of the list item between the default and “another color”
- add a new list item to an existing list in the page where the new list item’s content is 2 things:
- (interrupt yourself here and jump down to Testing and test both locally and deployed)
Testing
- Use the VSCode Live Server extension to test your site locally
- how will you know if it’s working?
- you should be able to be able to use your links to navigate to all the pages
- the css should be applied to every page (background color should be whatever you set it to in
base.css
) - the image should be displayed on every page
- how will you know if the js file has been embedded and is working correctly?
- how will you know if it’s working?
- once the site is working locally, deploy to either GitHub Pages or w3stu and confirm that the url references all work:
- confirm the css is applied to every page
- confirm the image is displayed on every page
- test the links to other pages from each page and ensure they’re working
12 - Lab 8 - Personal Professional Profile
Express yourself!
For this week-long lab, you will create a “Personal-Professional Profile”. It’s your chance to present yourself to future colleagues/employers/reporters/clients. This lab provides an opportunity to synthesize and reflect on the many topics we’ve covered in the course. To begin this project, we don’t provide any code (but may provide a git repository. Check your Canvas course), but of course you can pull from things you’ve read and or worked on previously.
Specs
- Your profile should include multiple pages.
- Across all the pages, your site should have:
- a consistent, non-default style. The guidelines for the final project would be a good starting place to check for basics.
- it is permissible to start with third-party CSS such as bootstrap if you wish.
- a navigation menu that links to all the pages.
- a consistent, non-default style. The guidelines for the final project would be a good starting place to check for basics.
- at least 3 pages:
- index.html - the landing page that briefly introduces you including at least:
- your name
- a picture of you or a placeholder image
- your professional status (e.g. undergraduate student)
- resume.html - targeted info for you to easily share with recruiters that has
- at least:
- a link to download a PDF of your resume
- optionally also:
- an html version of your resume right in the page
- at least:
- about.html - a more detailed page about you that includes at least:
- a longer bio
- some sort of “personal”/humanizing info about yourself such as:
- a list of your hobbies
- a list of your favorite books, movies, or music
- a list of your skills
- index.html - the landing page that briefly introduces you including at least:
Examples
There are many people out there with great examples, here’s a lazy convenient sample:
13 - Lab 7 - Dark Grid
Dark Grid
- Continue from where you left off last lab.
- Create a new file called
dark.css
- edit your
index.html
to include a link todark.css
in thehead
of the document just before it links todebug.css
- edit
dark.css
such that if the user has a “dark” preference, the page will be styled with a dark theme. - add a javascript file called script.js and a script tag to the bottom of the body of the html file that loads
script.js
. - in
script.js
, add an event listener such that when the user clicks any of the 3 nav items, the page will render with the selected color scheme.- most often, dynamic styling is best implemented via (a) defining style rules for corresponding classes in css and (b) adding/removing classes to the necessary elements dynamically
14 - Lab 6 - Tiny Grid
Tiny Grid
In this week’s prep, you completed a responsive grid design that uses two “breakpoints” to distinguish three layouts for a page. In this lab, you will continue with the same code base (but you should start from our version…), and will add in a 3rd breakpoint to now have a 4th layout for the page: a “tiny” layout.
- accept the github classroom assignment linked from your canvas course
- in doing so, tell github classroom that you’re in a group with your neighbor
- both you and your neighbor: clone the repository to your local machines
- Replace the fake name in the
README.md
’s Acknowledgements with your own name. - add the README.md changes to the staging area, commit the changes, and push the changes to the remote repository.
- edit the tiny.css such that when the viewport width is less than 375px, the layout changes such that only the “main article area” is displayed.
- add the tiny.css changes to the staging area, commit the changes, and push the changes to the remote repository.
Acknowledgements
Developers:
- Nay Bored
With huge thanks to the CS 343 cheat code Mozilla Developer Network.
15 - Lab 4.5 - Position with Quokkas! 😍
Quokkalot
⚠️ GitHub Classroom
This page is just to keep us all in communication. You must use the GitHub classroom link provided by your instructor for this assignment (from which you’ll get the starting code as well as the final version of the specs drafted below).Specs
- mark up the text in the html file (modified from wikipedia) with the appropriate tags
- the submission must pass html validation
- tell the html file to use the provided css file
- make the page look like the provided image, specifically:
- The main text has a width of
50rem
. - the figures have a width of
43rem
. - The main text and figures are centered horizontally in the page.
- The margin notes have a width of
12.5rem
. - The margin notes are “anchored” against their containing paragraphs.
- The margin notes have a bg color of 🐑 (
#BABABA
😂). - The margin notes have a text size of
0.75rem
. - The gap between the main text and the margin notes is
1rem
. - remove the placeholder style that makes the page awful (but totally helps ensure you’ve told the html file to use the css file)
- captions for the images should have a text size of
0.5rem
.
- The main text has a width of
Acknowledgements
With thanks to Dr. Chris Johnson for thinking this one up.
16 - Lab 5 - Clicking
Clicktastic
Flex
- Make an html page with a
style
element in thehead
and ascript
element at the end of thebody
. - Inside the
body
, add 2img
elements (you can use picsum.photos to get the URLs for these images). - style the
body
to have nomargin
- style the
body
to have aheight
of100vh
- style the
body
to be a flex container - style the flex container such that the 2 images are centered vertically
- style the flex container such that the 2 images are aligned to at the
start
, horizontally
JS
- Add an event listener such that when the body of the page is clicked, a new image is added to the page
- Update the event listener such that in addition to the above, clicking the image toggles the direction of the flex container from horizontal to vertical
17 - Lab 4 - Centering
1. Center an element horizontally
- Make a page with only 1 element inside body: main
- put 1 element only inside main: img
- use a square image (perhaps from https://picsum.photos or if you’re ready for the challenge, add some image of your own/ stolen from the web and test your ability to publish this code to github pages), restricted to 10rem in size
- without using flexbox or css-grid, write CSS rules to center the image horizontally in the page
2. Center an element vertically
- Duplicate the directory containing your code for the previous part (we’d like to keep it as a reference/example)
- update the style rules to also center the img vertically (you may use flexbox for this part)
18 - Lab 3 - Bootstrap
Overview
As we begin to look at how to specify the presentation of our webpages using CSS, this sneak peak is intended to help give you a sense of how much can be accomplished with CSS. (We will also write “vanilla” CSS that begins with no third-party code so that you know how these things are accomplished, and importantly how to modify them to suit your specific needs.) In this lab we introduce Bootstrap, but there are many design frameworks out there that provided excellent CSS starting points. For novices especially, design frameworks like Bootstrap are a great way to begin projects you intend to publish because typically the frameworks:
- are well-documented
- are well-tested
- in multiple browsers
- on multiple devices
- with many viewport sizes
- have solved issues novices aren’t even aware of yet
- have designed for accessibility
- have designed for responsiveness
- have designed for usability
- have designed for performance
- demonstrate best practices for CSS that works well with semantically-structured HTML (itself a best practice)
Specs
(Following the steps in later sections) Make a web page that has:
- a responsive navigation bar ("nav bar") at the top,
- one that has a “Responsive behavior” called a “Toggler” and
With a brand name shown on the left and toggler on the right
- one that has a “Responsive behavior” called a “Toggler” and
- a responsive content area after the nav such that:
- when the viewport is at least
768px
wide,- the left 2/3 of the content area’s will be the
main
content area - the remaining right 1/3 of the content area will be an area for
aside
content
- the left 2/3 of the content area’s will be the
- when the viewport is less than
768px
wide,- the
main
content will occupy the full width of its container - the
aside
content will come after themain
and will also occupy the full width of its container
- the
- when the viewport is at least
Starting Resources
Code
Bootstrap’s documentation has the perfect starting code for you ready to roll. We recommend you use the (first) code sample from #2 in the Quick start section (for now, you can ignore the other code samples on that page including the second code block in #2).
❤️ Favicon
By now, you’ve seen that most of what goes in an html document’s head
is metadata not immediately visible to the visitor, and that the content that will be rendered into the browser’s viewport is in the body
. The icon that will appear by default in alongside the site’s title in browsers’ tabs and which will be used in browsers’ histories and bookmarks is often called a favicon
.
This wesbos character has put a ton of useful resources on the web. While I appreciate a fun tone as much as the next prof, I think flicking off visitors on entering your site isn’t the way 🫣 I’d’ve done it. Nonetheless, FavFarm is pretty useful. Consider just referencing this example for now:
<link rel="icon" href="https://fav.farm/🕸️">
Placeholders
Placeholder text is often useful when you’re focussed only on the semantic structure and/or presentation of your page, but not yet its content. A common choice is lorem ipsum
text (for the curious: there’s always more to learn), which you can grab a small example in vscode by simply typing lorem
and accepting the emmet completion (via hitting tab or enter).
There’s also a delightful variety of these generators, e.g.:
- for text
- 🥓 Bacon Ipsum
- 🧁 Cupcake Ipsum
- 🚀 Space Ipsum
- 🧀 Cheese Ipsum
- 🏴☠️ Pirate Ipsum
- ➕ and 🤪 more
- for images
- 🏞️ Lorem Picsum
Step 1: Begin with the provided resources
- Start this activity as we generally recommend you start all of them
- create a file named
index.html
and paste the code sample from the bootstrap docs (linked above) into your otherwise emptyindex.html
file. - paste the provided favicon link into your
head
(see above). - delete the Hello, World heading.
- make
doctype
all caps.
⏸️ 🩺 Step 1 Check-up
At this point, your page should:
- have no visible content.
- have a spiderweb favicon, shown in the browser tab.
- have a title of
Bootstrap demo
, shown in the browser tab.
Step 2: Add some filler
So that you can see how the content of the is affected by the subsequent steps,
- create a
main
element as the first child of thebody
element - create an
h1
with the text contentBootstrap demo
as the first child of themain
element - paste 3+ paragraphs of your favorite lorem ipsum text (each paragraph should be wrapped in a
p
element) into themain
of your document (immediately following theh1
). - create an
aside
element as the second child of thebody
element - paste 3 more paragraphs of your favorite lorem ipsum text (each paragraph should be wrapped in a
p
element) into theaside
of your document.
⏸️ 🩺 Step 2 Check-up
At this point, your page should:
- have the browser tab items from check #1 above.
- have a top-level heading that says
Bootstrap demo
. - have several paragraphs that follow the heading.
- these paragraphs should be a little too tight on the top, right, and left sides of the viewport.
- have lovely, non-browser-default font choices (face, size, and weight).
Step 3: Add a nav bar
- Copy the 2nd example in the Bootstrap Components:::Navbar::Responsive:Toggler, the one described as
With a brand name shown on the left and toggler on the right
. - Paste the copied code the first
child
of thebody
in your document (i.e. it should immediately precede themain
element you created in the previous step).
⏸️ 🩺 Step 3 Check-up
At this point, your page should:
- look pretty similar to how it looked in check-up #2 above
- have a navbar before the h1 and other content.
- when the viewport is at least
992px
wide, the navbar should show all its content - else: the navbar should show only its “brand”) text that says
Navbar
on the far left and an icon for the “toggler” (much more often called a 🍔 “hamburger”) on the far right.- when the navbar’s in this “collapsed” state, clicking the hamburger should expand the navbar to show all its content, but now vertically stacked, smoothly animated pushing the rest of the page content further down the page. Clicking the hamburger again should “collapse” the navbar back to its “collapsed” state.
- when the viewport is at least
Note: it’s not only “clicking” the toggler that will expand/collapse the navbar. Often a more inclusive term for “using” the toggler or other graphical user interface element is “actioning”, i.e. “when the navbar’s in this ‘collapsed’ state, actioning the hamburger should expand the navbar…”. The difference is that technically click is a precise event that happens when a mouse button is pressed and released, but the toggler can be actioned by other means, e.g. by pressing the enter or space key when the toggler is focused, or by tapping the toggler when using a touchscreen device.
Step 4: Add a content area
- After the close tag of your
nav
element, add let’s add a container for the rest of our page’s content. Paste the following code after the</nav>
:-
<div class="container"> </div>
-
- Move both the
main
andaside
elements you created in the previous step into thediv
you just created. Sometimes doing something like this might be more simply specified as “wrap themain
andaside
elements in adiv
with the classcontainer
”.
⏸️ 🩺 Step 4 Check-up
At this point, your page should:
- look similar to the step#3 check-up description above.
- have a more reasonable amount of space between the content and the left and right edges of the viewport (when your viewport is at least
576px
wide).
Step 5: Implement responsive behavior
Bootstrap implements several pre-defined responsive “breakpoints”.
In this use of the term, a breakpoint
is not a place to pause code when using a debugger, like most of our prior uses of the term.
Rather, it means a value in a range the is used as the threshold for a change in presentation/behavior.
To accomplish the specs, we need to figure out where a viewport width 768px
falls in the range of Bootstrap’s breakpoints. According to the docs, viewports with a width of at least 768px
are considered “medium” which is represented in bootstrap’s classes with the abbreviated md
.
- Wrap the
main
andaside
elements in adiv
with the classrow
. (So you’re adding only onediv
element, but it will have two children:main
andaside
.)- so this new
div
should be the only child of thediv
with the classcontainer
you created in the previous step.
- so this new
- Add this class to your main element:
col-md-8
, which means that at viewport widths of at least768px
, the main element should be presented as a “column” (within the row you just added) that takes up 8/12ths of the width of its container. - Add this class to your aside element:
col-md-4
, which means that at viewport widths of at least768px
, the aside element should take up 4/12ths of the width of its container.
⏸️ 🧐 Check it
At this point, you should have a page that looks pretty different depending on the viewport width:
- width of
768px
or wider:- navbar at the top that looks like the one in the boostrap docs with a wide viewport:
- content area below the navbar that has 2 columns:
- the left column is 2/3 of the width of the content area
- the right column is 1/3 of the width of the content area
- navbar at the top that looks like the one in the boostrap docs with a wide viewport:
- width narrower than
768px
:- navbar at the top that looks like the one in the boostrap docs with a narrow viewport:
- content area below the navbar that has only 1 column showing:
- (first) the
main
content, followed by - the
aside
content
- (first) the
- navbar at the top that looks like the one in the boostrap docs with a narrow viewport:
You may find it convenient to use the devtools’ Responsive Design Mode to check how your pages behaves on wider vs. narrower viewports.
Step 6: Accordion
In Graphical User Interfaces on your computer, phone, watch, fridge? contact lens?!, you have become accustomed to some common ways for information to be presented and common dynamic behaviors of those presentations, let’s call a representation of information and its dynamic behavior a “widget”.
Bootstrap implements many commonly used “widgets” as components
. One of them is an accordion. Let’s try out the accordion.
- copy the first code example from the accordion docs and replace all the paragraphs in your
aside
with the code you copied.
Going Further
Navbar
Color the navbar
- read the docs and try to apply the
primary
color scheme
to the navbar- if you succeed, you may agree that the navbar looks nice, but now the search box looks weird. I think it looks better to make one more modification in this case: find the
form
in the navbar and add this attribute and value to it:data-bs-theme="light"
- oh dang, now the search button kinda sucks too huh? I think it looks better to make one more modification in this case: find the search
button
in the navbar. Notice it has the classbtn-outline-success
? drop the-outline
part of that class name. Dang, this is still pretty low contrast… 🤔 know what, make itbtn-light
. That seems alright.
- if you succeed, you may agree that the navbar looks nice, but now the search box looks weird. I think it looks better to make one more modification in this case: find the
Give the navbar margins to match content
- in your
nav
element, you’ll see one of the first children (which contains all the other descendants ofnav
) is an element with classcontainer-fluid
. Remove the-fluid
part of that class name. Read more on Bootstrap Containers if you like.
Navbar breakpoint
Currently the responsive behavior of the main content area is based on the md
breakpoint, which is at 768px
, but the navbar’s responsive behavior is based on the lg
breakpoint, which is at 992px
. This means that the navbar will be in its “collapsed” state when the viewport is between 768px
and 992px
wide, but the main content area will be in its “2 column” state. This is a little weird. How can you fix it?
Only show aside when there’s enough real estate
- read the docs (e.g. these about hiding elements) and try to make it that the
aside
is either hidden (on viewports narrower than768px
) or shown on wider viewports as previously specified (a column that takes 4/12 of the available width).
19 - Lab 2 - Document Structure with HTML
In this lab, you will be formatting a text document as an HTML version of this PDF. (Ignore the page break in the middle of that PDF, since HTML pages don’t have page breaks.) All of the text content is provided in the starter code below. You just need to format the document as HTML.
Starting Code
😉 Create a directory for this lab
As a reminder, in whatever location on your filesystem you will collect our course’s work (e.g. the suggested dev
directory), begin by:
- creating a directory specifically for this activity (name it something reasonable, e.g.
lab2
) - tell vscode to specifically open this directory (not its parent, the
dev
directory or any individual files)
Use the provided lab2.txt
to avoid copying and pasting large
chunks of text from the PDF. Lines beginning with #
are intended as
guidelines, and should be converted into HTML comments.
<!-- as a reminder HTML comments begin with those 4 characters at the beginning of this code sameple and end with the following 3 -->
Step 1: Basic HTML Documents
Your task is to add HTML elements to the provided text file to create the document structure. Note that the PDF was generated using a word processor and we are only using HTML. As such, some appearances (fonts, spacing, etc.) may not be exactly the same. You should try to make it as close as possible, however.
For this step, you need to have a correctly formatted header to create a valid HTML file. You also need to format all paragraphs and lists correctly.
You could approach this either by:
- renaming your downloaded copy of the provided
lab2.txt
toindex.html
and working directly there, or - creating a new file called
index.html
and copying selections fromlab2.txt
into it as you proceed through the lab.
Step 2: HTML Document Structure
Once you have all the previous components, you need to add the remaining HTML elements, such as the title, subtitle, and horizontal lines. You also need to add the JMU logo image at the bottom. The only things that should be missing at this point are the portions controlled by JavaScript.
Step 3: JavaScript Fundamentals
Once you have added the required HTML elements, you will need to add
JavaScript code in a few places. Each of these will require a separate
<script>
tag:
- Just after the (opening)
<body>
tag, create the variables as described in thelab2.txt
file. - Use one variable as a Boolean to determine whether or not to show the JMU logo image at the bottom.
- Use the other variables as Strings that contain both the level 3 heading tags and the corresponding text.
Submission
In addition to the formatting of your source code itself (which you should ensure vscode has done, using the defaults), your submission must also validate cleanly with no errors or warnings.
Note that publishing your file is not necessarily to test validation. The easiest way to test validation is to install a browser extension/add-on. Search in your browser’s extension tool for “HTML Validator” (by Marc Gueury, you should already have this if you completed the Dev Setup). You can also copy and paste the HTML into the validator itself (selecting the “text input” from the “Check by” drop-down list).
You will submit your index.html
file to Gradescope for
submission.
🛑 Don't publish to stu
You should not publish your code for this assignment tow3stu
,
as that makes it public for all to copy from. 😅
20 - Lab 1 - File Publishing and Validation
In this lab, you’ll practice using the web server infrastructure that will be available throughout this course.
stu
You should be able to access all JMU CS systems (includingstu.cs.jmu.edu
) using your e-ID (JMU email address without the @dukes.jmu.edu
part) and your standard JMU password. Please let me know ASAP if you have problems.
Background
Throughout this semester, you will frequently need to transfer data to w3stu.cs.jmu.edu
, the JMU CS web server for students. (Note that w3stu
is the same as stu
. When accessing your pages through a web browser, you will use w3stu
; when transferring files, you will use stu
.) As a CS student, you already have an account.
The easiest way to get started transferring files is to use FileZilla, a free, cross-platform, open-source file transfer application. From that site, download the program on your laptop or wherever you will be doing your development work.
The JMU CS Wiki has a page showing some FileZilla basics 🧠that perhaps you should check right quick. Once you have FileZilla installed, you will connect to stu.cs.jmu.edu
using the sftp://
protocol as shown in this screenshot, setting your username and password as appropriate. The first time you connect to stu
, you will get the “Unknown host key” pop-up box as shown; click “OK” to continue.
Make sure that the Host:
file is sftp://stu.cs.jmu.edu
and not just stu.cs.jmu.edu
. The default behavior for FileZilla is to use the insecure ftp://
instead of sftp://
. This will not work, as stu
does not accept incoming ftp://
connections.
Once connected, the right-hand side will show a folder path on the "Remote site:" that looks like /cs/home/stu/your_user_name
. This screenshot shows an example. Under the "Filename" list, scroll down until you see the "www" directory shortcut. Double-click on it and you will see something that looks like this screenshot. Notice that the "Remote site:" has changed to /cs/www/stu/your_user_name
, which is the base directory of your web site.
Any file that you drag-and-drop into this directory will be published on w3stu
automatically. If you copy a file called foo.html
into this directory, you can access that file by pointing a web browser to the URL https://w3stu.cs.jmu.edu/your_user_name/foo.html
. Within FileZilla, you can also create subdirectories to organize your site’s pages.
Note: If you are comfortable with working on the command line, you might try doing this lab using something like scp
or rsync
. You can find plenty of tutorials for either by searching. The scp
command line would look something like:
$ scp index.html <i>your_user_name</i>@stu.cs.jmu.edu:~/www/index.html
File Publishing
Your first task is to download and publish the following files based on the naming conventions shown below. Right-click on each to save a copy to the desktop on your computer.
Step 1: Publish index.html
Open the index.html
file in a text editor and change your name in the <meta> tag that indicates the “author” of the file.
Then transfer the index.html
file so that it can be accessed at the URL https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/
.
Note that you will need to create the cs343
directory in your www
directory and lab1
in cs343
.
www
directory but in www/cs343/lab1
. That way, if you already have an index.html
page, it will not be overwritten.Test this step by going to the URL in your web browser. If you click on any of the links, they should not work (giving you a 404 error).
Step 2: Publish the other files
Transfer the data.txt
file so that it is in the same directory as the index file. Click on the "text file" link from the index file and confirm that you can access it.
Transfer the linked.html
file, but you'll need to create a subdirectory and rename the file in the process. Once you've transferred the file, it should be in the www/cs343/lab1/linked
subdirectory and renamed as index.html
.
When you are finished, you should have the following files and directory structure, and all links in the index file should work:
https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/
https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/index.html
https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/data.txt
https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/linked/
https://w3stu.cs.jmu.edu/your_EID/cs343/lab1/linked/index.html
Validation and Minimization
Throughout the semester, your lab and project submissions need to successfully pass the W3C Nu HTML Validator. The provided index.html
file does not pass. Copy and paste the link to your published version and fix the error based on the feedback there. Do the same for the lab1/index.html
file. Note that there is one error there (use of <tt>
) that cannot be fixed based on what we have discussed so far.
Submission
- Download this file (named
site.txt
) and edit it with vscode. You should only need to replaceyour_EID
with your JMU EID. - Submit your modified version of the
site.txt
file to the Lab 1 assignment on Gradescope.