diff --git a/book_apps/ch01/die_roller/index.html b/book_apps/ch01/die_roller/index.html new file mode 100644 index 0000000..d358458 --- /dev/null +++ b/book_apps/ch01/die_roller/index.html @@ -0,0 +1,22 @@ + + + + Die Roller + + + +

+ +

+

Click Reload to roll again!

+ + \ No newline at end of file diff --git a/book_apps/ch01/die_roller/main.css b/book_apps/ch01/die_roller/main.css new file mode 100644 index 0000000..3684cc6 --- /dev/null +++ b/book_apps/ch01/die_roller/main.css @@ -0,0 +1,12 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background-color: white; + margin: 1em auto; + width: 600px; + padding: 0 2em 0; + border: 1px solid black; + border-radius: 1em; +} +h1 { + color: cornflowerblue; +} diff --git a/book_apps/ch01/email_list/add.html b/book_apps/ch01/email_list/add.html new file mode 100644 index 0000000..44c079e --- /dev/null +++ b/book_apps/ch01/email_list/add.html @@ -0,0 +1,12 @@ + + + + + + Join Email List + + + +

Thanks for joining our email list!

+ + diff --git a/book_apps/ch01/email_list/email_list.js b/book_apps/ch01/email_list/email_list.js new file mode 100644 index 0000000..38742da --- /dev/null +++ b/book_apps/ch01/email_list/email_list.js @@ -0,0 +1,40 @@ +"use strict"; + +// define a function that gets an HTML element +function getElement(selector) { + return document.querySelector(selector); +} + +// define a function that handles the click event of the Join button +function joinButtonClick(event) { + // get user entries from text boxes + const email1 = getElement("#email_1").value; + const email2 = getElement("#email_2").value; + + // check user entries + let invalid = false; + if (email1 == "") { + getElement("#email_1_error").textContent = "Email is required."; + invalid = true; + } else { + getElement("#email_1_error").textContent = ""; + } + + if (email1 != email2) { + getElement("#email_2_error").textContent = "Emails must match."; + invalid = true; + } else { + getElement("#email_2_error").textContent = ""; + } + + // cancel form submit if any user entries are invalid + if (invalid) { + event.preventDefault(); + } +}; + +// add code that's run when the web page is loaded +document.addEventListener("DOMContentLoaded", () => { + // specify the function that's run when the Join button is clicked + getElement("#join_button").addEventListener("click", joinButtonClick); +}); \ No newline at end of file diff --git a/book_apps/ch01/email_list/index.html b/book_apps/ch01/email_list/index.html new file mode 100644 index 0000000..d3f5afd --- /dev/null +++ b/book_apps/ch01/email_list/index.html @@ -0,0 +1,32 @@ + + + + + + Email List + + + +

Email List

+
+
+ + + * +
+ +
+ + + * +
+ +
+ + +
+
+ + + \ No newline at end of file diff --git a/book_apps/ch01/email_list/main.css b/book_apps/ch01/email_list/main.css new file mode 100644 index 0000000..11a8d7e --- /dev/null +++ b/book_apps/ch01/email_list/main.css @@ -0,0 +1,26 @@ +body { + font-family: Arial, Helvetica, sans-serif; + margin: 1em auto; + width: 600px; + padding: 0 2em 0; + border: 1px solid black; + border-radius: 1em; +} +h1 { + color: cornflowerblue; +} +div { + margin-bottom: 1em; +} +label { + display: inline-block; + width: 11em; + text-align: right; +} +input { + margin-left: 1em; + margin-right: 0.5em; +} +span { + color: red; +} \ No newline at end of file diff --git a/book_apps/ch01/welcome/index.html b/book_apps/ch01/welcome/index.html new file mode 100644 index 0000000..09ceac0 --- /dev/null +++ b/book_apps/ch01/welcome/index.html @@ -0,0 +1,13 @@ + + + + Welcome + + +

Welcome to Modern JavaScript

+ + + \ No newline at end of file diff --git a/book_apps/ch01/welcome/main.css b/book_apps/ch01/welcome/main.css new file mode 100644 index 0000000..b0eca86 --- /dev/null +++ b/book_apps/ch01/welcome/main.css @@ -0,0 +1,11 @@ +body { + font-family: Arial, Helvetica, sans-serif; + margin: 0 auto; + padding: 0 2em 1em; + width: 600px; + border: 1px solid black; + border-radius: 1em; +} +h1 { + color: cornflowerblue; +} diff --git a/book_apps/ch02/miles_to_kms/index.html b/book_apps/ch02/miles_to_kms/index.html new file mode 100644 index 0000000..6c3074a --- /dev/null +++ b/book_apps/ch02/miles_to_kms/index.html @@ -0,0 +1,9 @@ + + + + Miles to Kilometers + + + + + \ No newline at end of file diff --git a/book_apps/ch02/miles_to_kms/miles_to_kms.js b/book_apps/ch02/miles_to_kms/miles_to_kms.js new file mode 100644 index 0000000..5e02e39 --- /dev/null +++ b/book_apps/ch02/miles_to_kms/miles_to_kms.js @@ -0,0 +1,13 @@ +"use strict"; + +// get miles from user +const miles = parseFloat(prompt("Miles:", 120)); + +// calculate kilometers +const kilometers = miles * 1.60934; + +// display results +const results = "Miles: " + miles + "\n" + + "Kilometers: " + kilometers.toFixed(2); + +alert(results); \ No newline at end of file diff --git a/book_apps/ch02/test_scores/index.html b/book_apps/ch02/test_scores/index.html new file mode 100644 index 0000000..04c69a5 --- /dev/null +++ b/book_apps/ch02/test_scores/index.html @@ -0,0 +1,9 @@ + + + + Test Scores + + + + + \ No newline at end of file diff --git a/book_apps/ch02/test_scores/test_scores.js b/book_apps/ch02/test_scores/test_scores.js new file mode 100644 index 0000000..a06442f --- /dev/null +++ b/book_apps/ch02/test_scores/test_scores.js @@ -0,0 +1,25 @@ +"use strict"; + +// initialize total variable +let total = 0; + +//get 3 scores from user and add them together +const score1 = parseInt(prompt("Enter first test score")); +total += score1; + +const score2 = parseInt(prompt("Enter second test score")); +total += score2; + +const score3 = parseInt(prompt("Enter third test score")); +total += score3; + +//calculate the average +const average = Math.round(total/3); + +// display the scores +const result = "Score 1 = " + score1 + "\n" + + "Score 2 = " + score2 + "\n" + + "Score 3 = " + score3 + "\n" + + "Average score = " + average; + +alert(result); \ No newline at end of file diff --git a/book_apps/ch03/future_value/future_value.js b/book_apps/ch03/future_value/future_value.js new file mode 100644 index 0000000..7b6227f --- /dev/null +++ b/book_apps/ch03/future_value/future_value.js @@ -0,0 +1,32 @@ +"use strict"; + +// get investment amount - loop until user enters a number +let investment = NaN; +while (isNaN(investment)) { + investment = parseFloat( + prompt("Enter investment amount", 10000)); +} + +// get interest rate - loop until user enters a number +let rate = NaN; +while (isNaN(rate)) { + rate = parseFloat(prompt("Enter interest rate", 4.5)); +} + +// get number of years - loop until user enters a number +let years = NaN; +while (isNaN(years)) { + years = parseInt(prompt("Enter years", 10)); +} + +// calulate future value +let futureValue = investment; +for (let i = 0; i < years; i++) { + futureValue += futureValue * rate / 100; +} + +// display results +alert("Investment amount: $" + investment + "\n" + + "Interest rate: " + rate + "%\n" + + "Years: " + years + "\n" + + "Future Value: $" + futureValue.toFixed(2)); \ No newline at end of file diff --git a/book_apps/ch03/future_value/index.html b/book_apps/ch03/future_value/index.html new file mode 100644 index 0000000..8bbfa68 --- /dev/null +++ b/book_apps/ch03/future_value/index.html @@ -0,0 +1,11 @@ + + + + + + Future Value Calculator + + + + + diff --git a/book_apps/ch03/guess_number/guess_number.js b/book_apps/ch03/guess_number/guess_number.js new file mode 100644 index 0000000..ea62cea --- /dev/null +++ b/book_apps/ch03/guess_number/guess_number.js @@ -0,0 +1,35 @@ +"use strict"; + +// get a random number between 1 and 20 +const num = Math.ceil(Math.random() * 20); + +// get the computer's guess +const computerGuess = Math.ceil(Math.random() * 20); + +// get the user's guess +const userGuess = parseInt(prompt("Enter a number between 1 and 20")); + +if (isNaN(userGuess)) { + alert("Not a valid number. Computer wins.") +} else if (userGuess < 1 || userGuess > 20) { + alert("Not a number between 1 and 20. Computer wins."); +} else { + let message = "The number is " + num + ".\n" + + "You guessed " + userGuess + + " and the computer guessed " + computerGuess + ".\n"; + + // compute the difference between the guesses and the number + const computerDiff = Math.abs(num - computerGuess); + const userDiff = Math.abs(num - userGuess); + + // determine the winner + if (userDiff === computerDiff) { + message += "It's a tie!"; + } else if (userDiff < computerDiff) { + message += "You WIN!"; + } else { + message += "Computer wins."; + } + + alert(message); +} diff --git a/book_apps/ch03/guess_number/index.html b/book_apps/ch03/guess_number/index.html new file mode 100644 index 0000000..3bbddaf --- /dev/null +++ b/book_apps/ch03/guess_number/index.html @@ -0,0 +1,13 @@ + + + + + + Guess the Number + + +

The Guess the Number App

+

Click Reload to play again.

+ + + \ No newline at end of file diff --git a/book_apps/ch03/magic_eight_ball/index.html b/book_apps/ch03/magic_eight_ball/index.html new file mode 100644 index 0000000..28541ff --- /dev/null +++ b/book_apps/ch03/magic_eight_ball/index.html @@ -0,0 +1,13 @@ + + + + + + Magic Eightball + + +

Magic Eightball

+

Click Reload to ask another question.

+ + + \ No newline at end of file diff --git a/book_apps/ch03/magic_eight_ball/magic_eight_ball.js b/book_apps/ch03/magic_eight_ball/magic_eight_ball.js new file mode 100644 index 0000000..05502ad --- /dev/null +++ b/book_apps/ch03/magic_eight_ball/magic_eight_ball.js @@ -0,0 +1,48 @@ +"use strict"; + +// get user's question +const question = prompt("Please enter a yes or no question.") + +if (question) { + let answer = ""; + + // get a random number between 1 and 9 + const num = Math.ceil(Math.random() * 9); + + switch (num) { + case 1: + answer = "It is certain."; + break; + case 2: + answer = "Reply hazy, try again."; + break; + case 3: + answer = "Don't count on it."; + break; + case 4: + answer = "It is decidedly so."; + break; + case 5: + answer = "Without a doubt."; + break; + case 6: + answer = "Ask again later."; + break; + case 7: + answer = "My sources say no."; + break; + case 8: + answer = "Most likely."; + break; + case 9: + answer = "Signs point to yes."; + break; + default: + answer = "Something went wrong."; + break; + } + alert(question + "\n" + + answer); +} else { + alert("You didn't enter a question."); +} \ No newline at end of file diff --git a/book_apps/ch04/bio/bio.js b/book_apps/ch04/bio/bio.js new file mode 100644 index 0000000..1f40497 --- /dev/null +++ b/book_apps/ch04/bio/bio.js @@ -0,0 +1,29 @@ +"use strict"; + +// get name, dob, and colors and split into arrays +const names = prompt("Enter your full name").split(" "); +const dob = prompt("Enter your DOB in mm-dd-yyyy format").split("-"); +const colors = prompt("Enter your favorite colors, separated by commas") + .split(","); + +// capitalize each name +for (let i in names) { + const firstLetter = names[i].substring(0, 1).toUpperCase(); + const restOfName = names[i].substring(1).toLowerCase(); + names[i] = firstLetter + restOfName; +} + +// trim any spaces from colors +for (let i in colors) { + colors[i] = colors[i].trim(); +} + +// create a display string for the colors +const firstColors = colors.slice(0, -1); +const lastColor = colors.at(-1); +const colorString = `${firstColors.join(", ")} and ${lastColor}`; + +// display bio +alert(`Hello, my name is ${names.join(" ")}. +I was born in ${dob[2]}. +I have ${colors.length} favorite colors: ${colorString}.`); diff --git a/book_apps/ch04/bio/index.html b/book_apps/ch04/bio/index.html new file mode 100644 index 0000000..fe7651a --- /dev/null +++ b/book_apps/ch04/bio/index.html @@ -0,0 +1,10 @@ + + + + + The Bio App + + + + + \ No newline at end of file diff --git a/book_apps/ch04/email_check/email_check.js b/book_apps/ch04/email_check/email_check.js new file mode 100644 index 0000000..98a8a84 --- /dev/null +++ b/book_apps/ch04/email_check/email_check.js @@ -0,0 +1,18 @@ +"use strict"; + +let isValid = false; +while (!isValid) { + const email = prompt("Enter your email address:"); + if (email.startsWith("_") || email.startsWith(".")) { + alert("Email address may not start with a period or underscore."); + } else if (!email.includes("@")) { + alert("Email address must contain an @ symbol."); + } else if (!email.includes(".")) { + alert("Email address must contain a period."); + } else if (!email.includes(".", email.indexOf("@"))) { + alert("The period must come after the @ symbol."); + } else { + alert(`You entered: ${email}.\nThis is a valid email address.`); + isValid = true; + } +} diff --git a/book_apps/ch04/email_check/index.html b/book_apps/ch04/email_check/index.html new file mode 100644 index 0000000..43a9733 --- /dev/null +++ b/book_apps/ch04/email_check/index.html @@ -0,0 +1,10 @@ + + + + + The Email Check App + + + + + \ No newline at end of file diff --git a/book_apps/ch04/test_scores/index.html b/book_apps/ch04/test_scores/index.html new file mode 100644 index 0000000..b72d91e --- /dev/null +++ b/book_apps/ch04/test_scores/index.html @@ -0,0 +1,13 @@ + + + + + Average Test Scores + + +
+

The Test Scores App

+ +
+ + \ No newline at end of file diff --git a/book_apps/ch04/test_scores/test_scores.js b/book_apps/ch04/test_scores/test_scores.js new file mode 100644 index 0000000..406511a --- /dev/null +++ b/book_apps/ch04/test_scores/test_scores.js @@ -0,0 +1,34 @@ +"use strict"; + +const scores = []; + +// get scores from the user +while (true) { + const entry = prompt("Enter a test score. Or, enter 'x' to exit."); + if (entry === 'x' || entry === null) { + break; + } + + const score = parseInt(entry); + if (score >= 0 && score <= 100) { + scores[scores.length] = score; + } else { + alert("Score must by a valid number from 0 through 100."); + } +} + +// if there are no scores, notify user +if (scores.length === 0) { + alert("You didn't enter any scores."); +} else { // otherwise, calculate the total and create a display string + let total = 0; + let scoresString = ""; + for (let i in scores) { + total += scores[i]; + scoresString += `Score ${parseInt(i) + 1}: ${scores[i]}\n`; + } + const average = total/scores.length; + + // display the scores and their average + alert(`${scoresString}Average score: ${average.toFixed(2)}`); +} \ No newline at end of file diff --git a/book_apps/ch04/test_scores2/index.html b/book_apps/ch04/test_scores2/index.html new file mode 100644 index 0000000..b72d91e --- /dev/null +++ b/book_apps/ch04/test_scores2/index.html @@ -0,0 +1,13 @@ + + + + + Average Test Scores + + +
+

The Test Scores App

+ +
+ + \ No newline at end of file diff --git a/book_apps/ch04/test_scores2/test_scores.js b/book_apps/ch04/test_scores2/test_scores.js new file mode 100644 index 0000000..d44edb1 --- /dev/null +++ b/book_apps/ch04/test_scores2/test_scores.js @@ -0,0 +1,39 @@ +"use strict"; + +const scores = []; + +while (true) { + const entry = prompt("Enter a test score. Or, enter 'x' to exit."); + if (entry === 'x' || entry === null) { + break; + } + + const score = parseInt(entry); + if (score >= 0 && score <= 100) { + scores.push(score); + } else { + alert("Score must by a valid number from 0 through 100."); + } +} + +const len = scores.length; +if (len === 0) { + alert("You didn't enter any scores."); +} else { + // calculate total and average + let total = 0; + for (let score of scores) { + total += score; + } + const average = total/len; + + // get the last 3 scores in reverse order + const lastScores = (len <= 3) ? scores.slice() : scores.slice(len - 3, len); + lastScores.reverse(); + + // display score data + alert("Scores: " + scores.join(", ") + "\n" + + "Total: " + total + "\n" + + "Average: " + average.toFixed(2) + "\n" + + "Last 3: " + lastScores.join(", ")); +} \ No newline at end of file diff --git a/book_apps/ch05/bio/bio.js b/book_apps/ch05/bio/bio.js new file mode 100644 index 0000000..cdabb12 --- /dev/null +++ b/book_apps/ch05/bio/bio.js @@ -0,0 +1,46 @@ +"use strict"; + +function getAsArray(promptMsg, separator = " ") { + return prompt(promptMsg).split(separator); +} + +// use rest operator for the following functions so can accept either a +// comma-separated list of arguments or an array with a spread operator +function capitalize(...words) { + const capitalizedWords = []; + for (let word of words) { + const firstLetter = word.substring(0,1).toUpperCase(); + const restOfWord = word.substring(1).toLowerCase(); + capitalizedWords.push(firstLetter + restOfWord); + } + return capitalizedWords; +} + +function trim(...items) { + const trimmedItems = []; + for (let item of items) { + trimmedItems.push(item.trim()); + } + return trimmedItems; +} + +function getColorsString(...items) { + const firstItems = items.slice(0, -1); + const lastItem = items.at(-1); + return `${firstItems.join(", ")} and ${lastItem}`; +} + +function displayBio(names, dob, colors) { + alert("Hello, my name is " + names.join(" ") + ".\n" + + "I was born in " + dob.at(-1) + ".\n" + + "I have " + colors.length + " favorite colors: " + + getColorsString(...colors) + "."); +} + +const names = capitalize(...getAsArray("Enter your full name")); +const dob = getAsArray("Enter your DOB in mm-dd-yyyy format", "-"); + +const msg = "Enter your favorite colors, separated by commas"; +const colors = trim(...getAsArray(msg, ",")); + +displayBio(names, dob, colors); \ No newline at end of file diff --git a/book_apps/ch05/bio/index.html b/book_apps/ch05/bio/index.html new file mode 100644 index 0000000..94aff23 --- /dev/null +++ b/book_apps/ch05/bio/index.html @@ -0,0 +1,9 @@ + + + + The Bio App + + + + + \ No newline at end of file diff --git a/book_apps/ch05/future_value/future_value.js b/book_apps/ch05/future_value/future_value.js new file mode 100644 index 0000000..3d1966e --- /dev/null +++ b/book_apps/ch05/future_value/future_value.js @@ -0,0 +1,30 @@ +"use strict"; + +function getNumber(promptMsg, defaultValue) { + let num = NaN; + while (isNaN(num)) { + num = parseFloat(prompt(promptMsg, defaultValue)); + } + return num; +} + +function calcFutureValue(investment, rate, years) { + let futureValue = investment; + for (let i = 0; i < years; i++) { + futureValue += futureValue * rate / 100; + } + return futureValue; +} + +function displayResults(investment, rate, years, futureValue) { + alert("Investment amount: $" + investment + "\n" + + "Interest rate: " + rate + "%\n" + + "Years: " + years + "\n" + + "Future Value: $" + futureValue.toFixed(2)); +} + +const investment = getNumber("Enter investment amount as xxxxx.xx", 10000); +const rate = getNumber("Enter interest rate as xx.x", 7.5); +const years = getNumber("Enter number of years", 10); +const futureValue = calcFutureValue(investment, rate, years); +displayResults(investment, rate, years, futureValue); \ No newline at end of file diff --git a/book_apps/ch05/future_value/index.html b/book_apps/ch05/future_value/index.html new file mode 100644 index 0000000..8974baf --- /dev/null +++ b/book_apps/ch05/future_value/index.html @@ -0,0 +1,12 @@ + + + + + + Future Value Calculator + + +

The Future Value Calculator

+ + + \ No newline at end of file diff --git a/book_apps/ch05/guess_number/guess.js b/book_apps/ch05/guess_number/guess.js new file mode 100644 index 0000000..2b946fb --- /dev/null +++ b/book_apps/ch05/guess_number/guess.js @@ -0,0 +1,51 @@ +"use strict"; + +// global variables +let randomNum = 0; +let tries = 0; + +// helper function +const getRandomInt = (max = 100) => { + let num = Math.random() * max; // get a random number between 0 and max + num = Math.ceil(num); // round up to nearest integer + return num; +}; + +// event handler functions +const guessClick = () => { + const guess = parseInt(document.querySelector("#number").value); + + let message = ""; + if (isNaN(guess)) { + message = "Not a valid number. Please enter a valid number." + } else if (guess < 1 || guess > 10) { + message = "Invalid number. Enter a number between 1 and 10."; + } else if (guess < randomNum) { + message = "Too small. Try again."; + tries++; + } else if (guess > randomNum) { + message = "Too big. Try again."; + tries++; + } else if (guess === randomNum) { + tries++; + const lastWord = (tries === 1) ? "try" : "tries"; + message = `You guessed it in ${tries} ${lastWord}!`; + } + document.querySelector("#message").textContent = message; +}; + +const playAgainClick = () => { + randomNum = getRandomInt(10); + tries = 0; + document.querySelector("#number").value = ""; + document.querySelector("#message").textContent = ""; +}; + +document.addEventListener("DOMContentLoaded", () => { + playAgainClick(); // initial a new game + + document.querySelector("#guess").addEventListener( + "click", guessClick); + document.querySelector("#play_again").addEventListener( + "click", playAgainClick); +}); \ No newline at end of file diff --git a/book_apps/ch05/guess_number/index.html b/book_apps/ch05/guess_number/index.html new file mode 100644 index 0000000..eaaf434 --- /dev/null +++ b/book_apps/ch05/guess_number/index.html @@ -0,0 +1,20 @@ + + + + + + Guess the Number + + + +

Guess the Number

+

It's between 1 and 10.

+ + + +
+ + + + + \ No newline at end of file diff --git a/book_apps/ch05/guess_number/main.css b/book_apps/ch05/guess_number/main.css new file mode 100644 index 0000000..e038a07 --- /dev/null +++ b/book_apps/ch05/guess_number/main.css @@ -0,0 +1,15 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background-color: white; + margin: 1em auto; + width: 600px; + padding: 0 2em 1em; + border: 1px solid black; + border-radius: 1em; +} +h1 { + color: cornflowerblue; +} +input, button { + margin: 0 0.5em 1em 0; +} \ No newline at end of file diff --git a/book_apps/ch05/typewriter/index.html b/book_apps/ch05/typewriter/index.html new file mode 100644 index 0000000..2e47ba0 --- /dev/null +++ b/book_apps/ch05/typewriter/index.html @@ -0,0 +1,14 @@ + + + + + + My Typewriter App + + + +

My Typewriter App

+

+        
+    
+
\ No newline at end of file
diff --git a/book_apps/ch05/typewriter/typewriter.css b/book_apps/ch05/typewriter/typewriter.css
new file mode 100644
index 0000000..401143b
--- /dev/null
+++ b/book_apps/ch05/typewriter/typewriter.css
@@ -0,0 +1,9 @@
+body {
+    font-family: Arial, Helvetica, sans-serif;
+    background-color: white;
+    margin: 1em;
+    padding: 0 2em 1em;
+}
+h1 {
+    color: cornflowerblue;
+}
\ No newline at end of file
diff --git a/book_apps/ch05/typewriter/typewriter.js b/book_apps/ch05/typewriter/typewriter.js
new file mode 100644
index 0000000..79d4160
--- /dev/null
+++ b/book_apps/ch05/typewriter/typewriter.js
@@ -0,0 +1,23 @@
+"use strict";
+
+document.addEventListener("DOMContentLoaded", () => {
+    
+    document.addEventListener("keydown", event => {
+        const pre = document.querySelector("#text");
+
+        const validChars = `abcdefghijklmnopqrstuvwxyz
+            ABCDEFGHIJKLMNOPQRSTUVWXYZ
+            1234567890~!@#$%^&*()_+-=\;:'",.`;
+
+        if (validChars.includes(event.key)) {
+            pre.textContent += event.key;    
+        }
+        else if (event.key.toLowerCase() === "enter") {
+            pre.textContent += "\n";
+        } 
+        else if (event.key.toLowerCase() === "backspace") {
+            // remove last character 
+            pre.textContent = pre.textContent.slice(0, -1);  
+        }
+    });
+});
\ No newline at end of file
diff --git a/book_apps/ch06/faqs/faqs.css b/book_apps/ch06/faqs/faqs.css
new file mode 100644
index 0000000..ab8ffdb
--- /dev/null
+++ b/book_apps/ch06/faqs/faqs.css
@@ -0,0 +1,41 @@
+body {
+    font-family: Arial, Helvetica, sans-serif;
+    background-color: white;
+    margin: 1em auto;
+    width: 500px;
+    padding: 0 2em 1em;
+    border: 1px solid black;
+    border-radius: 1em;
+}
+h1 { 
+    font-size: 150%;
+}
+h2 {
+    font-size: 120%;
+    padding: 0 0 0 1.5em;
+    cursor: pointer;
+    background: url(images/plus.png) no-repeat left center;
+}
+h2.minus {
+    background: url(images/minus.png) no-repeat left center;
+}
+a {
+    color: black; 
+    text-decoration: none; 
+}
+a:focus, a:hover {
+    color: blue;
+}
+div {
+    display: none;
+}
+div.open {
+    display: block;
+}
+li {
+    padding-bottom: .25em;
+}
+p {
+    padding-bottom: .25em;
+    padding-left: 2em;
+}
\ No newline at end of file
diff --git a/book_apps/ch06/faqs/faqs.js b/book_apps/ch06/faqs/faqs.js
new file mode 100644
index 0000000..092cfbb
--- /dev/null
+++ b/book_apps/ch06/faqs/faqs.js
@@ -0,0 +1,24 @@
+"use strict";
+
+// the event handler for the click event of each 

element +const toggleVisibility = evt => { + const h2 = evt.currentTarget; // get the

element + const div = h2.nextElementSibling; // get the
element + + h2.classList.toggle("minus"); + div.classList.toggle("open"); + + evt.preventDefault(); // cancel default action of child element +}; + +document.addEventListener("DOMContentLoaded", () => { + // get the

elements + const h2s = document.querySelectorAll("#faqs h2"); + + // attach event handler for each

tag + for (let h2 of h2s) { + h2.addEventListener("click", toggleVisibility); + } + // set focus on first tag + h2s[0].firstChild.focus(); +}); \ No newline at end of file diff --git a/book_apps/ch06/faqs/images/minus.png b/book_apps/ch06/faqs/images/minus.png new file mode 100644 index 0000000..a168c8a Binary files /dev/null and b/book_apps/ch06/faqs/images/minus.png differ diff --git a/book_apps/ch06/faqs/images/plus.png b/book_apps/ch06/faqs/images/plus.png new file mode 100644 index 0000000..bb4b98e Binary files /dev/null and b/book_apps/ch06/faqs/images/plus.png differ diff --git a/book_apps/ch06/faqs/index.html b/book_apps/ch06/faqs/index.html new file mode 100644 index 0000000..7b0ed83 --- /dev/null +++ b/book_apps/ch06/faqs/index.html @@ -0,0 +1,35 @@ + + + + + + FAQs + + + + +

JavaScript FAQs

+ +

What is JavaScript?

+
+

JavaScript is a scripting language that you can use to make websites + interactive.

+
+ +

Why use JavaScript?

+
+
    +
  • It has simple syntax that's easy to learn.
  • +
  • It's versatile.
  • +
  • It's one of the most popular programming languages.
  • +
+
+ +

Which browsers support JavaScript?

+
+

All the major modern browsers support JavaScript.

+
+ + + + \ No newline at end of file diff --git a/book_apps/ch06/image_swap/image_swap.css b/book_apps/ch06/image_swap/image_swap.css new file mode 100644 index 0000000..5b34961 --- /dev/null +++ b/book_apps/ch06/image_swap/image_swap.css @@ -0,0 +1,16 @@ +body { + font-family: Arial, Helvetica, sans-serif; + background-color: white; + margin: 1em auto; + width: 550px; + padding: 0 1em 1em 0; + border: 1px solid black; + border-radius: 1em; + text-align: center; +} +h1, h2 { + color: cornflowerblue; +} +li { + display: inline; +} \ No newline at end of file diff --git a/book_apps/ch06/image_swap/image_swap.js b/book_apps/ch06/image_swap/image_swap.js new file mode 100644 index 0000000..2aa0ac5 --- /dev/null +++ b/book_apps/ch06/image_swap/image_swap.js @@ -0,0 +1,32 @@ +"use strict"; + +const getElement = selector => document.querySelector(selector); + +document.addEventListener("DOMContentLoaded", () => { + // get the main image and caption elements + const mainImage = getElement("#main_image"); + const caption = getElement("#caption"); + + // get all the elements in the