Practice Exercise
In this exercise, we will practice working with HTML, images, URLs, the DOM, events, and JavaScript to create an interactive web page.
-
Create a folder called
catson your computer -
Create a file inside the
catsfolder namedindex.html -
Open a terminal to your
catsfolder (i.e.,cd cats) -
In your terminal, start a web server by running the following command:
npx http-server(alternatively, you can use the command:npx lite-server, refer week 5 notes) -
Open the
catsfolder in Visual Studio Code -
Edit the
index.htmlfile so it contains a basic HTML5 web page, including a<head>,<body>, etc. Try to do it from memory first, then look up what you've missed. -
Save
index.htmland try loading it in your browser by visiting your local web server athttp://localhost:8080/index.html -
In your editor, modify the
bodyof yourindex.htmlfile to contain the text of the poem in cats.txt. Use HTML tags to markup the poem for the web. Your page should have a proper heading for the title, each line should break at the correct position, and the poet's name should be bold. -
Add an image of a cat to the page below the text. You can use https://upload.wikimedia.org/wikipedia/commons/c/c1/Sixweeks_old_cat%28aka%29.jpg.
-
Adjust the
widthof your image so it fits nicely on your page. What happens if you adjust thewidthandheight? -
Create a new file in your
catsfolder calledscript.js. Add the following line of JavaScript:console.log('cats!'); -
Add a
scriptelement to the bottom of yourbody(i.e., right before the closing</body>tag). Set itssrcto a file calledscript.js:<script src="script.js"></script>
</body> -
Refresh your web page in the browser, and open your browser's
Dev Tools, andWeb Console. Make sure you can see thecats!message printed in the log. -
Try changing
cats!inscript.jsto some other message, save yourscript.jsfile, and refresh your browser. Make sure your console updates with the new message. -
Modify
index.htmland update your<img>tag: add an attributeid="cat-picture"and remove thesrc="...":<!-- NOTE: there is no longer a src attribute in our HTML, we'll do it JavaScript below -->
<img id="cat-picture" /> -
Modify your
script.jsfile to add the following code:window.onload = function () {
let img = document.getElementById('cat-picture');
img.src =
'https://upload.wikimedia.org/wikipedia/commons/c/c1/Six_weeks_old_cat_%28aka%29.jpg';
}; -
Save your
script.jsfile and reload your browser. Do you still see a cat? If not, check your web console for any errors. -
Modify your
script.jsand change your cat URL used byimg.srcto use https://cataas.com/cat. The cataas.com site provides cat pictures as a service via URL parameters. Savescript.jsand reload your page a few times. Do you see a different cat each time? -
Modify your
script.jsfile to move your image code to a separate function. Make sure it still works the same way when you're done (save and test in your browser):function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
window.onload = loadCatPicture; -
Rewrite
script.jsto update the picture after 5 seconds:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
window.onload = function () {
loadCatPicture();
// Call the loadCatPicture function again in 5s
setTimeout(loadCatPicture, 5 * 1_000 /* 5s = 5000ms */);
}; -
Rewrite
script.jsto update the picture every 15 seconds, forever:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
window.onload = function () {
loadCatPicture();
// Call the loadCatPicture function every 15000ms
setInterval(loadCatPicture, 15 * 1_000 /* 15s = 15000ms */);
}; -
Rewrite
script.jsto update the picture only when the user clicks somewhere in the window:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
window.onload = function () {
loadCatPicture();
// Call the loadCatPicture function when the user clicks in the window
window.onclick = loadCatPicture;
}; -
Modify
index.htmland put a<div>...</div>around all the text of the poem. Give yourdivanid="poem-text"attribute:<div id="poem-text">
<p>Cats sleep anywhere, any table, any chair....</p>
...
</div> -
Rewrite
script.jsto load the picture only when the user clicks on the text of the poem:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
let poemText = document.getElementById('poem-text');
poemText.onclick = loadCatPicture; -
Rewrite
script.jsto also load the picture only when the user presses a key on the keyboard:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
let poemText = document.getElementById('poem-text');
poemText.onclick = loadCatPicture;
window.onkeypress = function (event) {
let keyName = event.key;
console.log('Key Press event', keyName);
loadCatPicture();
}; -
Rewrite
script.jsto also load the picture only when the user presses a key on the keyboard, but only one ofb, m, s, n, p, x:function loadCatPicture() {
let img = document.getElementById('cat-picture');
img.src = 'https://cataas.com/cat';
}
let poemText = document.getElementById('poem-text');
poemText.onclick = loadCatPicture;
window.onkeypress = function (event) {
let keyName = event.key;
console.log('Key Press event', keyName);
switch (keyName) {
case 'b':
case 'm':
case 's':
case 'n':
case 'p':
case 'x':
loadCatPicture();
break;
default:
console.log('Ignoring key press event');
}
}; -
Rewrite
script.jsto also load the picture only when the user presses a key on the keyboard, but only one ofb, m, s, n, p, x, and load the picture with one of the supported cataas filters:function loadCatPicture(filter) {
let url = 'https://cataas.com/cat';
let img = document.getElementById('cat-picture');
// If the function is called with a filter argument, add that to URL
if (filter) {
console.log('Using cat picture filter', filter);
url += `?filter=${filter}`;
}
img.src = url;
}
let poemText = document.getElementById('poem-text');
poemText.onclick = function () {
loadCatPicture();
};
window.onkeypress = function (event) {
let keyName = event.key;
console.log('Key Press event', keyName);
switch (keyName) {
case 'b':
return loadCatPicture('blur');
case 'm':
return loadCatPicture('mono');
case 's':
return loadCatPicture('sepia');
case 'n':
return loadCatPicture('negative');
case 'p':
return loadCatPicture('paint');
case 'x':
return loadCatPicture('pixel');
default:
console.log('Ignoring key press event');
}
}; -
Rewrite
script.jsso that we only load a new cat picture when the old picture is finished loading (don't send too many requests to the server). Also, add some cache busting:// Demonstrate using a closure, and use an immediately executing function to hide
// an `isLoading` variable (i.e., not global), which will keep track of whether
// or not an image is being loaded, so we can ignore repeated requests.
let loadCatPicture = (function () {
let isLoading = false;
// This is the function that will be bound to loadCatPicture in the end.
return function (filter) {
if (isLoading) {
console.log('Skipping load, already in progress');
return;
}
let img = document.getElementById('cat-picture');
function finishedLoading() {
isLoading = false;
// Remove unneeded event handlers so `img` can be garbage collected.
img.onload = null;
img.onerror = null;
img = null;
}
img.onload = finishedLoading;
img.onerror = finishedLoading;
// If the function is called with a filter argument, add that to URL
let url = 'https://cataas.com/cat';
// Add something unique (and meaningless) to the query string, so the browser
// won't cache this URL, but always load it again
url += '?nocache=' + Date.now();
if (filter) {
console.log('Using cat picture filter', filter);
url += '&filter=' + filter;
}
// Finally, set isLoading to true, and begin loading image
isLoading = true;
img.src = url;
};
})();
let poemText = document.getElementById('poem-text');
poemText.onclick = function () {
loadCatPicture();
};
window.onkeypress = function (event) {
switch (event.key) {
case 'b':
return loadCatPicture('blur');
case 'm':
return loadCatPicture('mono');
case 's':
return loadCatPicture('sepia');
case 'n':
return loadCatPicture('negative');
case 'p':
return loadCatPicture('paint');
case 'x':
return loadCatPicture('pixel');
default:
console.log('Ignoring key press event');
break;
}
};