├── .eslintrc-FINISHED
├── .gitignore
├── .npmrc
├── base.css
├── exercises
├── 16 - Debugging
│ ├── debugging-FINISHED.js
│ ├── debugging-START.js
│ └── debugging.html
├── 20 - The DOM
│ ├── DOM-Cardio-FINISHED.html
│ ├── DOM-Cardio-FINISHED.js
│ ├── DOM-Cardio.html
│ ├── DOM-Cardio.js
│ ├── creating-FINISHED.js
│ ├── creating-with-strings-FINISHED.js
│ ├── creating-with-strings.js
│ ├── creating.js
│ ├── index-FINISHED.html
│ ├── index.html
│ ├── the-dom-FINISHED.js
│ ├── the-dom.js
│ ├── traversing-FINISHED.js
│ └── traversing.js
├── 29 - Events
│ ├── events-FINISHED.html
│ ├── events-FINISHED.js
│ ├── events.html
│ ├── events.js
│ ├── forms-FINISHED.html
│ ├── forms-FINISHED.js
│ ├── forms.html
│ └── forms.js
├── 33 - Etch-a-Sketch
│ ├── etch-a-sketch-FINISHED.js
│ ├── etch-a-sketch.js
│ └── index.html
├── 34 - Click Outside
│ ├── click-outside-FINISHED.html
│ ├── click-outside-FINISHED.js
│ ├── click-outside.html
│ └── click-outside.js
├── 35 - Scroll To Accept
│ ├── scroll-to-accept-FINISHED.html
│ ├── scroll-to-accept-FINISHED.js
│ ├── scroll-to-accept.html
│ └── scroll-to-accept.js
├── 36 - Tabs
│ ├── index.html
│ ├── tabs-finished.js
│ ├── tabs-style.css
│ └── tabs.js
├── 46 - Arrays
│ ├── array-loopings-methods-FINISHED.html
│ ├── array-loopings-methods-START.html
│ ├── array-methods-FINISHED.html
│ ├── array-methods-START.html
│ ├── for-loops-FINISHED.html
│ ├── for-loops-START.html
│ ├── reduce-challenge-FINISHED.html
│ └── reduce-challenge-START.html
├── 55 - Face Detection Censorship
│ ├── .npmrc
│ ├── face-FINISHED.html
│ ├── face.html
│ ├── package-lock.json
│ ├── package.json
│ ├── pixelated-face-DEMO.js
│ ├── pixelated-face-FINISHED.js
│ └── pixelated-face.js
├── 56 - Sarcastic Text
│ ├── index.html
│ ├── text-DEMO.js
│ ├── text-FINISHED.js
│ └── text.js
├── 57 - Shopping List
│ ├── index.html
│ ├── shopping-DEMO.js
│ ├── shopping-FINISHED.js
│ ├── shopping.css
│ └── shopping.js
├── 58 - Gallery
│ ├── gallery-DEMO.js
│ ├── gallery-FINISHED.js
│ ├── gallery-prototype-FINISHED.js
│ ├── gallery.css
│ ├── gallery.js
│ ├── images
│ │ ├── 270-camo-sunset.jpg
│ │ ├── TNF-fanorak.png
│ │ ├── canada-goose.jpg
│ │ ├── coral-yeti.jpg
│ │ ├── hondo.jpg
│ │ ├── kith-hoodie.jpg
│ │ ├── naked-and-famous-denim.jpg
│ │ ├── nudie-belt.jpg
│ │ ├── patagonia black hole.jpg
│ │ ├── rimowa.png
│ │ ├── ultra-boost.jpg
│ │ └── vapormax.jpg
│ └── index.html
├── 59 - Slider
│ ├── .npmrc
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── index-FINISHED.js
│ │ ├── index-prototype-FINISHED.js
│ │ └── index.js
│ └── style.scss
├── 72 - Async Prompts
│ ├── index.html
│ ├── scripts-FINISHED.js
│ ├── scripts.js
│ └── style.css
├── 73 - Async Typer
│ ├── index.html
│ ├── scripts-FINISHED.js
│ └── scripts.js
├── 75 - CORS and Recipes
│ ├── .npmrc
│ ├── index-FINISHED.html
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── scripts-FINISHED.js
│ └── scripts.js
├── 76 - Dad Jokes
│ ├── index-FINISHED.html
│ ├── index.html
│ ├── jokes-FINISHED.js
│ └── jokes.js
├── 77 - Currency Converter
│ ├── index.html
│ ├── money-FINISHED.js
│ ├── money.css
│ └── money.js
├── 79 - Currency Converter Modules Refactor - FINISHED
│ ├── currencies.js
│ ├── elements.js
│ ├── handlers.js
│ ├── index.html
│ ├── init.js
│ ├── lib.js
│ ├── money.css
│ ├── money.js
│ └── utils.js
├── 80 - Dad Jokes Modules - FINISHED
│ ├── data
│ │ └── buttonText.js
│ ├── index.html
│ ├── jokes.js
│ └── lib
│ │ ├── elements.js
│ │ ├── handlers.js
│ │ ├── index.js
│ │ └── utils.js
├── 81 - Dad Jokes Bundling - FINISHED
│ ├── .npmrc
│ ├── data
│ │ └── buttonText.js
│ ├── index.html
│ ├── jokes.js
│ ├── lib
│ │ ├── elements.js
│ │ ├── handlers.js
│ │ ├── index.js
│ │ └── utils.js
│ ├── package-lock.json
│ └── package.json
├── 82 - npm modules - FINISHED
│ ├── .npmrc
│ ├── index.html
│ ├── index.js
│ ├── package-lock.json
│ └── package.json
├── 83 - Security
│ ├── .npmrc
│ ├── index.html
│ ├── nasty-FINISHED.js
│ ├── nasty.js
│ ├── package-lock.json
│ └── package.json
├── 84 - Web Speech Colour Game
│ ├── .npmrc
│ ├── colors-FINISHED.js
│ ├── colors.js
│ ├── handlers-FINISHED.js
│ ├── handlers.js
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── speech-FINISHED.js
│ ├── speech.js
│ └── style.css
└── 85 - Audio Visualizer Oscilloscope
│ ├── .npmrc
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── sound-FINISHED.js
│ ├── sound.js
│ └── utils.js
├── function-definition.jpg
├── package.json
├── playground
├── apis-FINISHED.html
├── apis.html
├── arrays-FINISHED.html
├── arrays.html
├── async-await-FINISHED.html
├── async-await-error-handling-FINISHED.html
├── async-await-error-handling.html
├── async-await.html
├── bedmas-FINISHED.html
├── bedmas.html
├── bind-call-apply-FINISHED.html
├── bind-call-apply.html
├── classes-FINISHED.html
├── classes.html
├── closures-FINISHED.html
├── closures.html
├── custom-functions
│ ├── cf-FINISHED.js
│ ├── cf.js
│ ├── index-FINISHED.html
│ ├── index.html
│ ├── ways-to-make-a-function-FINISHED.js
│ └── ways-to-make-a-function.js
├── event-loop-FINISHED.html
├── event-loop.html
├── functions-FINISHED.html
├── functions.html
├── hoisting-FINISHED.html
├── hoisting-FINISHED.js
├── hoisting.html
├── hoisting.js
├── if-statements-FINISHED.html
├── if-statements.html
├── intervals-FINISHED.html
├── intervals.html
├── maps-FINISHED.html
├── maps.html
├── modules
│ ├── base.css
│ ├── currencies.js
│ ├── handlers-FINISHED.js
│ ├── handlers.js
│ ├── index-FINISHED.html
│ ├── index.html
│ ├── scripts-FINISHED.js
│ ├── scripts.js
│ ├── utils-FINISHED.js
│ ├── utils.js
│ ├── wes-FINISHED.js
│ └── wes.js
├── new-this-FINISHED.html
├── new-this.html
├── node-example.js
├── objects-FINISHED.html
├── objects.html
├── promise-chain-FINISHED.html
├── promises-FINISHED.html
├── promises.html
├── running-js-FINISHED.html
├── running-js.html
├── scope-FINISHED.html
├── scope-FINISHED.js
├── scope.html
├── scope.js
├── some-FINISHED.js
├── some.js
├── switch-statements-FINISHED.html
├── switch-statements.html
├── turtle.png
├── types-FINISHED.html
├── types-FINISHED.js
├── types.html
├── types.js
├── variables-FINISHED.html
└── variables.html
├── readme.md
└── snippets
├── README.md
├── htmlbase.html
└── htmlbase.json
/.eslintrc-FINISHED:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "wesbos"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .DS_Store
3 | haters/
4 | .cache/
5 | dist/
6 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/16 - Debugging/debugging-FINISHED.js:
--------------------------------------------------------------------------------
1 | const people = [
2 | { name: 'Wes', cool: true, country: 'Canada' },
3 | { name: 'Scott', cool: true, country: 'Merica' },
4 | { name: 'Snickers', cool: false, country: 'Dog Country' },
5 | ];
6 |
7 | people.forEach((person, index) => {
8 | console.groupCollapsed(`${person.name}`);
9 | console.log(person.country);
10 | console.log(person.cool);
11 | console.log('DONE');
12 | console.groupEnd(`${person.name}`);
13 | });
14 |
15 | console.table(people);
16 |
17 | // Console Methods
18 |
19 | // Callstack, Stack Trace
20 |
21 | // Grabbing Elements
22 |
23 | // Breakpoints
24 |
25 | // Scope
26 |
27 | // Network Requests
28 |
29 | // Break On Attribute
30 |
31 | // Some Setup Code
32 |
33 | function doALotOfStuff() {
34 | console.group('Doing some stuff');
35 | console.log('Hey Im one');
36 | console.warn('watch out!');
37 | console.error('hey');
38 | console.groupEnd('Doing some stuff');
39 | }
40 |
41 | function doctorize(name) {
42 | // console.count(`running Doctorize for ${name}`);
43 | return `Dr. ${name}`;
44 | }
45 |
46 | function greet(name) {
47 | doesntExist(); // Cause an error
48 | return `Hello ${name}`;
49 | }
50 |
51 | function go() {
52 | const name = doctorize(greet('Wes'));
53 | console.log(name);
54 | }
55 |
56 | function bootstrap() {
57 | console.log('Starting the app!');
58 | go();
59 | }
60 |
61 | // bootstrap();
62 |
63 | const button = document.querySelector('.bigger');
64 | button.addEventListener('click', function(e) {
65 | const newFontSize =
66 | parseFloat(getComputedStyle(e.currentTarget).fontSize) + 1;
67 | e.currentTarget.style.fontSize = `${newFontSize}px`;
68 | });
69 |
70 | // A Dad joke fetch
71 | async function fetchDadJoke() {
72 | const res = await fetch('https://icanhazdadjoke.com/', {
73 | headers: {
74 | Accept: 'text/plain',
75 | },
76 | });
77 | const joke = await res.text();
78 | console.log(joke);
79 | return joke;
80 | }
81 |
--------------------------------------------------------------------------------
/exercises/16 - Debugging/debugging-START.js:
--------------------------------------------------------------------------------
1 | const people = [
2 | { name: 'Wes', cool: true, country: 'Canada' },
3 | { name: 'Scott', cool: true, country: 'Merica' },
4 | { name: 'Snickers', cool: false, country: 'Dog Country' },
5 | ];
6 |
7 | people.forEach((person, index) => {
8 | console.log(person.name);
9 | });
10 |
11 | // Console Methods
12 |
13 | // Callstack
14 |
15 | // Grabbing Elements
16 |
17 | // Breakpoints
18 |
19 | // Scope
20 |
21 | // Network Requests
22 |
23 | // Break On Attribute
24 |
25 | // Some Setup Code
26 |
27 | function doctorize(name) {
28 | return `Dr. ${name}`;
29 | }
30 |
31 | function greet(name) {
32 | doesntExist();
33 | return `Hello ${name}`;
34 | }
35 |
36 | function go() {
37 | const name = doctorize(greet('Wes'));
38 | console.log(name);
39 | }
40 |
41 | const button = document.querySelector('.bigger');
42 | button.addEventListener('click', function(e) {
43 | const newFontSize =
44 | parseFloat(getComputedStyle(e.currentTarget).fontSize) + 1;
45 | e.currentTarget.style.fontSize = `${newFontSize}px`;
46 | });
47 |
48 | // A Dad joke fetch
49 | async function fetchDadJoke() {
50 | const res = await fetch('https://icanhazdadjoke.com/', {
51 | headers: {
52 | Accept: 'text/plain',
53 | },
54 | });
55 | const joke = await res.text();
56 | console.log(joke);
57 | return joke;
58 | }
59 |
--------------------------------------------------------------------------------
/exercises/16 - Debugging/debugging.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Make Me Bigger
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/DOM-Cardio-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dom Cardio
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
32 |
33 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/DOM-Cardio-FINISHED.js:
--------------------------------------------------------------------------------
1 | // Make a div
2 | const div = document.createElement('div');
3 | // add a class of wrapper to it
4 | div.classList.add('wrapper');
5 | // put it into the body
6 | document.body.appendChild(div);
7 |
8 | // make an unordered list
9 | const ul = `
10 | one
11 | two
12 | three
13 | `;
14 | // add three list items with the words "one, two three" in them
15 | // put that list into the above wrapper
16 | div.innerHTML = ul;
17 |
18 | // create an image
19 | const img = document.createElement('img');
20 | // set the source to an image
21 | img.src = 'https://picsum.photos/500';
22 | // set the width to 250
23 | img.width = 250;
24 | img.height = 250;
25 | // add a class of cute
26 | img.classList.add('cute');
27 | // add an alt of Cute Puppy
28 | img.alt = 'Cute Puppy!';
29 | // Append that image to the wrapper
30 | div.appendChild(img);
31 |
32 | // with HTML string, make a div, with two paragraphs inside of it
33 | const myHTML = `
34 |
35 |
Paragraph One
36 |
Paragraph Two
37 |
38 | `;
39 | const ulElement = div.querySelector('ul');
40 | console.log(ulElement);
41 | // put this div before the unordered list from above
42 | ulElement.insertAdjacentHTML('beforebegin', myHTML);
43 | // add a class to the second paragraph called warning
44 | const myDiv = div.querySelector('.myDiv');
45 | myDiv.children[1].classList.add('warning');
46 | // remove the first paragraph
47 | myDiv.firstElementChild.remove();
48 |
49 | // create a function called generatePlayerCard that takes in three arguments: name, age, and height
50 | function generatePlayerCard(name, age, height) {
51 | const html = `
52 |
53 |
${name} — ${age}
54 |
Their Height is ${height} and ${age} years old. In Dog years this person would be ${age *
55 | 7}. That would be a tall dog!
56 | × Delete
57 |
58 |
59 |
60 | `;
61 | return html;
62 | }
63 |
64 | // have that function return html that looks like this:
65 | //
66 | //
NAME — AGE
67 | //
They are HEIGHT and AGE years old. In Dog years this person would be AGEINDOGYEARS. That would be a tall dog!
68 | //
69 |
70 | // make a new div with a class of cards
71 | const cards = document.createElement('div');
72 | cards.classList.add('cards');
73 | // Have that function make 4 cards
74 | let cardsHTML = generatePlayerCard('wes', 12, 150);
75 | cardsHTML += generatePlayerCard('scott', 12, 150);
76 | cardsHTML += generatePlayerCard('kait', 12, 150);
77 | cardsHTML += generatePlayerCard('snickers', 12, 150);
78 |
79 | cards.innerHTML = cardsHTML;
80 | div.insertAdjacentElement('beforebegin', cards);
81 | // append those cards to the div
82 | // put the div into the DOM just before the wrapper element
83 | // Bonus, put a delete Button on each card so when you click it, the whole card is removed
84 |
85 | // select all the buttons!
86 | const buttons = document.querySelectorAll('.delete');
87 | // make out delete function
88 | function deleteCard(event) {
89 | const buttonThatGotClicked = event.currentTarget;
90 | // buttonThatGotClicked.parentElement.remove();
91 | buttonThatGotClicked.closest('.playerCard').remove();
92 | }
93 | // loop over them and attach a listener
94 | buttons.forEach(button => button.addEventListener('click', deleteCard));
95 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/DOM-Cardio.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dom Cardio
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/DOM-Cardio.js:
--------------------------------------------------------------------------------
1 | // Make a div
2 |
3 | // add a class of wrapper to it
4 |
5 | // put it into the body
6 |
7 | // make an unordered list
8 |
9 | // add three list items with the words "one, two, three" in them
10 | // put that list into the above wrapper
11 |
12 | // create an image
13 |
14 | // set the source to an image
15 | // set the width to 250
16 | // add a class of cute
17 | // add an alt of Cute Puppy
18 | // Append that image to the wrapper
19 |
20 | // with HTML string, make a div, with two paragraphs inside of it
21 | // put this div before the unordered list from above
22 |
23 | // add a class to the second paragraph called warning
24 | // remove the first paragraph
25 |
26 | // create a function called generatePlayerCard that takes in three arguments: name, age, and height
27 |
28 | // have that function return html that looks like this:
29 | //
30 | //
NAME — AGE
31 | //
They are HEIGHT and AGE years old. In Dog years this person would be AGEINDOGYEARS. That would be a tall dog!
32 | //
33 |
34 | // make a new div with a class of cards
35 |
36 | // make 4 player cards using generatePlayerCard
37 |
38 | // append those cards to the div
39 | // put the div into the DOM just before the wrapper element
40 | // Bonus, put a delete Button on each card so when you click it, the whole card is removed
41 |
42 | // select all the buttons!
43 | // make out delete function
44 | // loop over them and attach a listener
45 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/creating-FINISHED.js:
--------------------------------------------------------------------------------
1 | console.log('it works!');
2 |
3 | const myParagraph = document.createElement('p');
4 | myParagraph.textContent = 'I am a P';
5 | myParagraph.classList.add('special');
6 | console.log(myParagraph);
7 |
8 | const myImage = document.createElement('img');
9 | myImage.src = 'https://picsum.photos/500';
10 | myImage.alt = 'Nice photo';
11 |
12 | const myDiv = document.createElement('div');
13 | myDiv.classList.add('wrapper');
14 | console.log(myDiv);
15 |
16 | myDiv.appendChild(myParagraph);
17 | myDiv.appendChild(myImage);
18 |
19 | document.body.appendChild(myDiv);
20 |
21 | // oh shoot! we need to add somethint to the top. like a heading!
22 | const heading = document.createElement('h2');
23 | heading.textContent = 'Cool Things';
24 |
25 | myDiv.insertAdjacentElement('beforebegin', heading);
26 |
27 | //
28 | // One
29 | // two
30 | // three
31 | // four
32 | // five
33 | //
34 |
35 | const list = document.createElement('ul');
36 | const li = document.createElement('li');
37 | li.textContent = 'three';
38 | list.appendChild(li);
39 |
40 | document.body.insertAdjacentElement('afterbegin', list);
41 |
42 | const li5 = document.createElement('li');
43 | li5.textContent = 'Five';
44 | list.append(li5);
45 |
46 | const li1 = li5.cloneNode(true);
47 | li1.textContent = 'one';
48 | list.insertAdjacentElement('afterbegin', li1);
49 |
50 | const li4 = document.createElement('li');
51 | li4.textContent = 'four';
52 | li5.insertAdjacentElement('beforebegin', li4);
53 |
54 | const li2 = document.createElement('li');
55 | li2.textContent = 'two';
56 | li1.insertAdjacentElement('afterend', li2);
57 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/creating-with-strings-FINISHED.js:
--------------------------------------------------------------------------------
1 | const item = document.querySelector('.item');
2 |
3 | const width = 500;
4 | const src = `https://picsum.photos/${width}`;
5 | const desc = `Cute Pup `;
6 | const myHTML = `
7 |
8 |
Cute ${desc}
9 |
10 |
11 | `;
12 |
13 | // turn a string into a DOM element
14 | const myFragment = document.createRange().createContextualFragment(myHTML);
15 |
16 | document.body.appendChild(myFragment);
17 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/creating-with-strings.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/20 - The DOM/creating-with-strings.js
--------------------------------------------------------------------------------
/exercises/20 - The DOM/creating.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/20 - The DOM/creating.js
--------------------------------------------------------------------------------
/exercises/20 - The DOM/index-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | The DOM
8 |
9 |
10 |
11 |
12 |
13 | I am Wes, I love to bbq and Make websites!
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Hi I'm a item
23 |
24 |
25 |
26 |
27 | I am a heading
28 | I am hidden!
29 |
30 |
Hi I'm a item
31 |
32 |
33 | Im an article
34 | This is how many pizzas I ate! 🍕
35 |
36 |
37 |
38 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | The DOM
8 |
9 |
10 |
11 |
12 |
13 |
Hi I'm a item
14 |
15 |
Sub Div
16 |
Hi I'm a item
17 |
18 |
19 |
20 |
Hi I'm a item
21 |
Hi I'm a item
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/the-dom-FINISHED.js:
--------------------------------------------------------------------------------
1 | // const p = document.querySelector('p');
2 | // const imgs = document.querySelectorAll('.item img');
3 | // const item2 = document.querySelector('.item2');
4 | // const item2Image = item2.querySelector('img');
5 | // const heading = document.querySelector('h2');
6 |
7 | // console.log(heading.textContent);
8 | // console.log(heading.innerText);
9 | // // set the textContent property on that elment
10 | // // heading.textContent = 'Wes is cool';
11 | // // console.log(heading.textContent);
12 | // // console.log(heading.innerText);
13 |
14 | // console.log(heading.innerHTML);
15 | // console.log(heading.outerHTML);
16 |
17 | // const pizzaList = document.querySelector('.pizza');
18 | // console.log(pizzaList.textContent);
19 |
20 | // // pizzaList.textContent = `${pizzaList.textContent} 🍕`;
21 | // pizzaList.insertAdjacentText('afterbegin', '🍕');
22 | // pizzaList.insertAdjacentText('beforeend', '🍕');
23 |
24 | // Classes!
25 | const pic = document.querySelector('.nice');
26 | pic.classList.add('open');
27 | pic.classList.remove('cool');
28 |
29 | console.log(pic.classList);
30 |
31 | function toggleRound() {
32 | pic.classList.toggle('round');
33 | }
34 |
35 | pic.addEventListener('click', toggleRound);
36 |
37 | pic.alt = 'Cute Pup'; // setter
38 | console.log(pic.alt); // getter
39 | console.log(pic.naturalWidth); // getter
40 | pic.width = 200;
41 |
42 | // pic.setAttribute('wes-is-cool', 'REALLY CUTE PUP');
43 | // console.log(pic.getAttribute('alt'));
44 |
45 | const custom = document.querySelector('.custom');
46 | console.log(custom.dataset);
47 |
48 | custom.addEventListener('click', function() {
49 | alert(`Welcome ${custom.dataset.name} ${custom.dataset.last} `);
50 | });
51 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/the-dom.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/20 - The DOM/the-dom.js
--------------------------------------------------------------------------------
/exercises/20 - The DOM/traversing-FINISHED.js:
--------------------------------------------------------------------------------
1 | const wes = document.querySelector('.wes');
2 |
3 | // console.log(wes.children);
4 | // console.log(wes.firstElementChild);
5 | // console.log(wes.lastElementChild);
6 | // console.log(wes.previousElementSibling);
7 | // console.log(wes.nextElementSibling);
8 | // console.log(wes.parentElement);
9 |
10 | const p = document.createElement('p');
11 | p.textContent = 'I will be removed';
12 | document.body.appendChild(p);
13 |
14 | p.remove();
15 |
16 | console.log(p);
17 |
18 | document.body.appendChild(p);
19 |
--------------------------------------------------------------------------------
/exercises/20 - The DOM/traversing.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/20 - The DOM/traversing.js
--------------------------------------------------------------------------------
/exercises/29 - Events/events-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | JavaScript Events
8 |
9 |
10 |
11 |
12 | Click Me!
13 | Click me also!
14 |
15 | Buy Buttons!
16 | Buy Item 1
17 | Buy Item 2
18 | Buy Item 3
19 | Buy Item 4
20 | Buy Item 5
21 | Buy Item 6
22 | Buy Item 7
23 | Buy Item 8
24 | Buy Item 9
25 | Buy Item 10
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/exercises/29 - Events/events-FINISHED.js:
--------------------------------------------------------------------------------
1 | const butts = document.querySelector(".butts");
2 | const coolButton = document.querySelector(".cool");
3 |
4 | function handleClick() {
5 | console.log("🐛 IT GOT CLICKED!!!");
6 | }
7 |
8 | const hooray = () => console.log("HOORAY!");
9 |
10 | butts.addEventListener("click", function () {
11 | console.log("Im an anon!");
12 | });
13 | coolButton.addEventListener("click", hooray);
14 |
15 | butts.removeEventListener("click", handleClick);
16 |
17 | // Listen on multiple items
18 | const buyButtons = document.querySelectorAll("button.buy");
19 |
20 | function handleBuyButtonClick(event) {
21 | console.log("You clicked a button!");
22 | const button = event.target;
23 | // console.log(button.textContent);
24 | // console.log(parseFloat(event.target.dataset.price));
25 | console.log(event.target);
26 | console.log(event.currentTarget);
27 | console.log(event.target === event.currentTarget);
28 | // Stop this event from bubbling up
29 | // event.stopPropagation();
30 | }
31 |
32 | buyButtons.forEach(function (buyButton) {
33 | buyButton.addEventListener("click", handleBuyButtonClick);
34 | });
35 |
36 | window.addEventListener(
37 | "click",
38 | function (event) {
39 | console.log("YOU CLICKED THE WINDOW");
40 | console.log(event.target);
41 | console.log(event.type);
42 | // event.stopPropagation();
43 | console.log(event.bubbles);
44 | },
45 | { capture: true }
46 | );
47 |
48 | const photoEl = document.querySelector(".photo");
49 |
50 | photoEl.addEventListener("mouseenter", (e) => {
51 | console.log(e.currentTarget);
52 | console.log(this);
53 | });
54 |
--------------------------------------------------------------------------------
/exercises/29 - Events/events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | JavaScript Events
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/exercises/29 - Events/events.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/29 - Events/events.js
--------------------------------------------------------------------------------
/exercises/29 - Events/forms-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | HTML Forms
8 |
9 |
10 |
11 |
12 |
25 |
26 | aSDFASDF
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/exercises/29 - Events/forms-FINISHED.js:
--------------------------------------------------------------------------------
1 | const wes = document.querySelector('.wes');
2 |
3 | wes.addEventListener('click', function(event) {
4 | const shouldChangePage = confirm(
5 | 'This website might be malicious!, do you wish to proceed?'
6 | );
7 | if (!shouldChangePage) {
8 | event.preventDefault();
9 | }
10 | });
11 |
12 | const signupForm = document.querySelector('[name="signup"]');
13 |
14 | signupForm.addEventListener('submit', function(event) {
15 | const name = event.currentTarget.name.value;
16 | if (name.includes('chad')) {
17 | alert('Sorry bro');
18 | event.preventDefault();
19 | }
20 | });
21 |
22 | function logEvent(event) {
23 | console.log(event.type);
24 | console.log(event.currentTarget.value);
25 | }
26 | signupForm.name.addEventListener('keyup', logEvent);
27 | signupForm.name.addEventListener('keydown', logEvent);
28 | signupForm.name.addEventListener('focus', logEvent);
29 | signupForm.name.addEventListener('blur', logEvent);
30 | // 'keyup'
31 | // 'keydown'
32 | // 'focus'
33 | // 'blur'
34 |
35 | const photo = document.querySelector('.photo');
36 |
37 | function handlePhotoClick(event) {
38 | if (event.type === 'click' || event.key === 'Enter') {
39 | console.log('You clicked the photo');
40 | }
41 | }
42 |
43 | photo.addEventListener('click', handlePhotoClick);
44 | photo.addEventListener('keyup', handlePhotoClick);
45 |
--------------------------------------------------------------------------------
/exercises/29 - Events/forms.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | HTML Forms
8 |
9 |
10 |
11 |
12 |
13 |
14 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/exercises/29 - Events/forms.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/29 - Events/forms.js
--------------------------------------------------------------------------------
/exercises/33 - Etch-a-Sketch/etch-a-sketch-FINISHED.js:
--------------------------------------------------------------------------------
1 | // Select the elements on the page - canvas, shake button
2 | const canvas = document.querySelector('#etch-a-sketch');
3 | const ctx = canvas.getContext('2d');
4 | const shakebutton = document.querySelector('.shake');
5 | const MOVE_AMOUNT = 50;
6 | // Setup our canvas for drawing
7 | // make a variable called height and width from the same properties on our canvas.
8 | const { width, height } = canvas;
9 |
10 | let x = Math.floor(Math.random() * width);
11 | let y = Math.floor(Math.random() * height);
12 | // create random x and y starting points on the canvas
13 |
14 | ctx.lineJoin = 'round';
15 | ctx.lineCap = 'round';
16 | ctx.lineWidth = MOVE_AMOUNT;
17 |
18 | let hue = 0;
19 | ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
20 | ctx.beginPath(); // start the drawing
21 | ctx.moveTo(x, y);
22 | ctx.lineTo(x, y);
23 | ctx.stroke();
24 |
25 | // write a draw function
26 | function draw({ key }) {
27 | // increment the hue
28 | hue += 1;
29 | console.log(hue);
30 | ctx.strokeStyle = `hsl(${Math.random() * 360}, 100%, 50%)`;
31 | console.log(key);
32 | // start the path
33 | ctx.beginPath();
34 | ctx.moveTo(x, y);
35 | // move our x and y values depending on what the user did
36 | switch (key) {
37 | case 'ArrowUp':
38 | y -= MOVE_AMOUNT;
39 | break;
40 | case 'ArrowRight':
41 | x += MOVE_AMOUNT;
42 | break;
43 | case 'ArrowDown':
44 | y += MOVE_AMOUNT;
45 | break;
46 | case 'ArrowLeft':
47 | x -= MOVE_AMOUNT;
48 | break;
49 | default:
50 | break;
51 | }
52 | ctx.lineTo(x, y);
53 | ctx.stroke();
54 | }
55 |
56 | // write a handler for the keys
57 | function handleKey(e) {
58 | if (e.key.includes('Arrow')) {
59 | e.preventDefault();
60 | draw({ key: e.key });
61 | }
62 | }
63 | // clear /shke function
64 | function clearCanvas() {
65 | canvas.classList.add('shake');
66 | ctx.clearRect(0, 0, width, height);
67 | canvas.addEventListener(
68 | 'animationend',
69 | function() {
70 | console.log('Done the shake!');
71 | canvas.classList.remove('shake');
72 | },
73 | { once: true }
74 | );
75 | }
76 |
77 | // listen for arrow keys
78 | window.addEventListener('keydown', handleKey);
79 | shakebutton.addEventListener('click', clearCanvas);
80 |
--------------------------------------------------------------------------------
/exercises/33 - Etch-a-Sketch/etch-a-sketch.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/33 - Etch-a-Sketch/etch-a-sketch.js
--------------------------------------------------------------------------------
/exercises/33 - Etch-a-Sketch/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Etch A Sketch
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Shake!
16 |
17 |
18 |
19 |
20 |
21 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/exercises/34 - Click Outside/click-outside-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Wes Bos
16 |
Learn more →
17 |
18 |
19 |
20 |
Scott Tolinski
21 |
Learn more →
22 |
23 |
24 |
25 |
Kait Bos
26 |
Learn more →
27 |
28 |
29 |
30 |
Snickers the dog
31 |
Learn more →
32 |
33 |
34 |
35 |
36 |
41 |
42 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/exercises/34 - Click Outside/click-outside-FINISHED.js:
--------------------------------------------------------------------------------
1 | const cardButtons = document.querySelectorAll(".card button");
2 | const modalOuter = document.querySelector(".modal-outer");
3 | const modalInner = document.querySelector(".modal-inner");
4 |
5 | function handleCardButtonClick(event) {
6 | const button = event.currentTarget;
7 | const card = button.closest(".card");
8 | // Grab the image src
9 | const imgSrc = card.querySelector("img").src;
10 | const desc = card.dataset.description;
11 | const name = card.querySelector("h2").textContent;
12 | // populate the modal with the new info
13 | modalInner.innerHTML = `
14 |
18 | ${desc}
19 | `;
20 | // show the modal
21 | modalOuter.classList.add("open");
22 | }
23 |
24 | cardButtons.forEach((button) =>
25 | button.addEventListener("click", handleCardButtonClick)
26 | );
27 |
28 | function closeModal() {
29 | modalOuter.classList.remove("open");
30 | }
31 |
32 | modalOuter.addEventListener("click", function (event) {
33 | const isOutside = !event.target.closest(".modal-inner");
34 | if (isOutside) {
35 | closeModal();
36 | }
37 | });
38 |
39 | window.addEventListener("keydown", (event) => {
40 | console.log(event);
41 | if (event.key === "Escape") {
42 | closeModal();
43 | }
44 | });
45 |
--------------------------------------------------------------------------------
/exercises/34 - Click Outside/click-outside.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
Wes Bos
16 |
Learn more →
17 |
18 |
19 |
20 |
Scott Tolinski
21 |
Learn more →
22 |
23 |
24 |
25 |
Kait Bos
26 |
Learn more →
27 |
28 |
29 |
30 |
Snickers the dog
31 |
Learn more →
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/exercises/34 - Click Outside/click-outside.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/34 - Click Outside/click-outside.js
--------------------------------------------------------------------------------
/exercises/35 - Scroll To Accept/scroll-to-accept-FINISHED.js:
--------------------------------------------------------------------------------
1 | const terms = document.querySelector('.terms-and-conditions');
2 | const watch = document.querySelector('.watch');
3 | const button = document.querySelector('.accept');
4 |
5 | function obCallback(payload) {
6 | if (payload[0].intersectionRatio === 1) {
7 | button.disabled = false;
8 | // stop observing the button
9 | ob.unobserve(terms.lastElementChild);
10 | }
11 | }
12 | const ob = new IntersectionObserver(obCallback, {
13 | root: terms,
14 | threshold: 1,
15 | });
16 |
17 | ob.observe(terms.lastElementChild);
18 |
--------------------------------------------------------------------------------
/exercises/35 - Scroll To Accept/scroll-to-accept.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/35 - Scroll To Accept/scroll-to-accept.js
--------------------------------------------------------------------------------
/exercises/36 - Tabs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Tabs
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | JavaScript
18 |
19 | Ruby
20 |
21 |
22 | PHP
23 |
24 |
25 |
26 |
JavaScript is great!
27 |
28 |
31 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/exercises/36 - Tabs/tabs-finished.js:
--------------------------------------------------------------------------------
1 | const tabs = document.querySelector('.tabs');
2 | const tabButtons = tabs.querySelectorAll('[role="tab"]');
3 | const tabPanels = Array.from(tabs.querySelectorAll('[role="tabpanel"]'));
4 |
5 | function handleTabClick(event) {
6 | // hide all tab panels
7 | tabPanels.forEach(panel => {
8 | panel.hidden = true;
9 | });
10 | // mark all tabs as unselected
11 | tabButtons.forEach(tab => {
12 | // tab.ariaSelected = false;
13 | tab.setAttribute('aria-selected', false);
14 | });
15 | // mark the clicked tab as selected
16 | event.currentTarget.setAttribute('aria-selected', true);
17 | // find the associated tabPanel and show it!
18 | const { id } = event.currentTarget;
19 |
20 | /*
21 | METHOD 1
22 | const tabPanel = tabs.querySelector(`[aria-labelledby="${id}"]`);
23 | console.log(tabPanel);
24 | tabPanel.hidden = false;
25 | */
26 |
27 | // METHOD 2 - find in the array of tabPanels
28 | console.log(tabPanels);
29 | const tabPanel = tabPanels.find(
30 | panel => panel.getAttribute('aria-labelledby') === id
31 | );
32 | tabPanel.hidden = false;
33 | }
34 |
35 | tabButtons.forEach(button => button.addEventListener('click', handleTabClick));
36 |
--------------------------------------------------------------------------------
/exercises/36 - Tabs/tabs-style.css:
--------------------------------------------------------------------------------
1 | .tabs {
2 | display: grid;
3 | }
4 |
5 | [role="tablist"] {
6 | display: grid;
7 | grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
8 | grid-gap: 10px;
9 | }
10 |
11 | [role="tabpanel"] {
12 | background: var(--yellow);
13 | padding: 2rem;
14 | }
15 |
16 | button {
17 | background: var(--grey);
18 | border: 0;
19 | color: black;
20 | border-radius: 5px 5px 0 0;
21 | --bs-color: rgba(0,0,0,0.1);
22 | box-shadow: inset 0 -2px 5px var(--bs-color);
23 | cursor:pointer;
24 | }
25 |
26 | button[aria-selected="true"] {
27 | background: var(--yellow);
28 | box-shadow: none;
29 | color: rgba(0,0,0,0.7);
30 | }
31 |
32 | button:focus {
33 | outline: 0;
34 | --bs-color: rgba(0,0,0,0.6);
35 | }
36 |
--------------------------------------------------------------------------------
/exercises/36 - Tabs/tabs.js:
--------------------------------------------------------------------------------
1 | console.log('ya ya wes we get it.. IT WORKS!');
2 |
--------------------------------------------------------------------------------
/exercises/46 - Arrays/array-loopings-methods-START.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/exercises/46 - Arrays/array-methods-START.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/exercises/46 - Arrays/for-loops-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | For Loops
9 |
10 |
11 |
12 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/exercises/46 - Arrays/for-loops-START.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | For Loops
9 |
10 |
11 |
12 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/exercises/46 - Arrays/reduce-challenge-START.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Reduce!
8 |
9 |
10 |
11 |
12 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/face-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Censorship
7 |
8 |
35 |
36 |
37 |
38 |
39 |
40 | SCALE:
41 |
42 |
43 |
44 | SIZE:
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/face.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Censorship
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pixelated-face",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "pixelated-face.js",
6 | "scripts": {
7 | "start": "parcel face.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "browserslist": [
12 | "last 1 Chrome version"
13 | ],
14 | "dependencies": {
15 | "parcel": "2.0.1"
16 | }
17 | }
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/pixelated-face-DEMO.js:
--------------------------------------------------------------------------------
1 | // The face detection does not work on all browsers and operating systems.
2 | // If you are getting a `Face detection service unavailable` error or similar,
3 | // it's possible that it won't work for you at the moment.
4 |
5 | const faceDetector = new window.FaceDetector();
6 | const video = document.querySelector('video.webcam');
7 | const canvas = document.querySelector('canvas.video');
8 | const ctx = canvas.getContext('2d');
9 | const faceCanvas = document.querySelector('canvas.face');
10 | const faceCtx = faceCanvas.getContext('2d');
11 | const SCALE = 1.2;
12 | const SIZE = 10;
13 |
14 | async function populateVideo() {
15 | const stream = await navigator.mediaDevices.getUserMedia({
16 | video: { width: 1280, height: 720 },
17 | });
18 | video.srcObject = stream;
19 | await video.play();
20 | canvas.width = video.videoWidth;
21 | canvas.height = video.videoHeight;
22 | faceCanvas.width = video.videoWidth;
23 | faceCanvas.height = video.videoHeight;
24 | }
25 |
26 | async function detect() {
27 | const faces = await faceDetector.detect(video);
28 | // ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
29 | ctx.clearRect(0, 0, canvas.width, canvas.height);
30 | // paintFace(faces);
31 | faces.forEach(drawFace);
32 | faces.forEach(censor);
33 | requestAnimationFrame(detect);
34 | }
35 |
36 | function censor({ boundingBox: face }) {
37 | faceCtx.imageSmoothingEnabled = false;
38 | faceCtx.clearRect(0, 0, faceCanvas.width, faceCanvas.height);
39 | // First draw it small
40 | faceCtx.drawImage(
41 | video, // Where should I grab the photo from?
42 | face.x, // from what x and y should I start capturing from?
43 | face.y,
44 | face.width, // how wide and high should I capture from?
45 | face.height,
46 | face.x, // now to draw it, where should I start x and y?
47 | face.y,
48 | SIZE, // how wide and high should it be?
49 | SIZE
50 | );
51 |
52 | const width = face.width * SCALE;
53 | const height = face.height * SCALE;
54 |
55 | // then draw it back on, but scaled up
56 | faceCtx.drawImage(
57 | faceCanvas, // Where should I grab the photo from?
58 | face.x, // from what x and y should I start capturing from?
59 | face.y, // from what x and y should I start capturing from?
60 | SIZE,
61 | SIZE,
62 | // Drawing
63 | face.x - (width - face.width) / 2,
64 | face.y - (height - face.height) / 2,
65 | width,
66 | height
67 | );
68 | }
69 | function drawFace(face) {
70 | const { width, height, top, left } = face.boundingBox;
71 | ctx.strokeStyle = '#ffc600';
72 | ctx.lineWidth = 1;
73 | ctx.strokeRect(left, top, width, height);
74 | ctx.stroke();
75 | }
76 |
77 | populateVideo().then(detect);
78 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/pixelated-face-FINISHED.js:
--------------------------------------------------------------------------------
1 | // The face detection does not work on all browsers and operating systems.
2 | // If you are getting a `Face detection service unavailable` error or similar,
3 | // it's possible that it won't work for you at the moment.
4 |
5 | const video = document.querySelector('.webcam');
6 | const canvas = document.querySelector('.video');
7 | const ctx = canvas.getContext('2d');
8 | const faceCanvas = document.querySelector('.face');
9 | const faceCtx = faceCanvas.getContext('2d');
10 | const faceDetector = new window.FaceDetector();
11 | const optionsInputs = document.querySelectorAll(
12 | '.controls input[type="range"]'
13 | );
14 |
15 | const options = {
16 | SIZE: 10,
17 | SCALE: 1.35,
18 | };
19 |
20 | function handleOption(event) {
21 | const { value, name } = event.currentTarget;
22 | options[name] = parseFloat(value);
23 | }
24 | optionsInputs.forEach(input => input.addEventListener('input', handleOption));
25 |
26 | // Write a fucntion that will populate the users video
27 | async function populateVideo() {
28 | const stream = await navigator.mediaDevices.getUserMedia({
29 | video: { width: 1280, height: 720 },
30 | });
31 | video.srcObject = stream;
32 | await video.play();
33 | // size the canvases to be the same size as the video
34 | console.log(video.videoWidth, video.videoHeight);
35 | canvas.width = video.videoWidth;
36 | canvas.height = video.videoHeight;
37 | faceCanvas.width = video.videoWidth;
38 | faceCanvas.height = video.videoHeight;
39 | }
40 |
41 | async function detect() {
42 | const faces = await faceDetector.detect(video);
43 | // ask the browser when the next animation frame is, and tell it to run detect for us
44 | faces.forEach(drawFace);
45 | faces.forEach(censor);
46 | requestAnimationFrame(detect);
47 | }
48 |
49 | function drawFace(face) {
50 | const { width, height, top, left } = face.boundingBox;
51 | ctx.clearRect(0, 0, canvas.width, canvas.height);
52 | ctx.strokeStyle = '#ffc600';
53 | ctx.lineWidth = 2;
54 | ctx.strokeRect(left, top, width, height);
55 | }
56 |
57 | function censor({ boundingBox: face }) {
58 | faceCtx.imageSmoothingEnabled = false;
59 | faceCtx.clearRect(0, 0, faceCanvas.width, faceCanvas.height);
60 | // draw the small face
61 | faceCtx.drawImage(
62 | // 5 source args
63 | video, // where does the source come from?
64 | face.x, // where do we start the source pull from?
65 | face.y,
66 | face.width,
67 | face.height,
68 | // 4 draw args
69 | face.x, // where should we start drawing the x and y?
70 | face.y,
71 | options.SIZE,
72 | options.SIZE
73 | );
74 | // draw the small face back on, but scale up
75 |
76 | const width = face.width * options.SCALE;
77 | const height = face.height * options.SCALE;
78 | faceCtx.drawImage(
79 | faceCanvas, // source
80 | face.x, // where do we start the source pull from?
81 | face.y,
82 | options.SIZE,
83 | options.SIZE,
84 | // Drawing args
85 | face.x - (width - face.width) / 2,
86 | face.y - (height - face.height) / 2,
87 | width,
88 | height
89 | );
90 | }
91 |
92 | populateVideo().then(detect);
93 |
--------------------------------------------------------------------------------
/exercises/55 - Face Detection Censorship/pixelated-face.js:
--------------------------------------------------------------------------------
1 | // The face detection does not work on all browsers and operating systems.
2 | // If you are getting a `Face detection service unavailable` error or similar,
3 | // it's possible that it won't work for you at the moment.
4 |
--------------------------------------------------------------------------------
/exercises/56 - Sarcastic Text/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Text Generator
8 |
9 |
30 |
31 |
32 |
33 |
34 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/exercises/56 - Sarcastic Text/text-DEMO.js:
--------------------------------------------------------------------------------
1 | // functions as arguments
2 |
3 | const textarea = document.querySelector('[name="text"]');
4 | const result = document.querySelector('.result');
5 | const filterInputs = document.querySelectorAll('[name="filter"]');
6 |
7 | /* eslint-disable */
8 | const funkyLetters = {
9 | '-': '₋', '!': 'ᵎ', '?': 'ˀ', '(': '⁽', ')': '₎', '+': '⁺', '=': '₌', '0': '⁰', '1': '₁', '2': '²', '4': '₄', '5': '₅', '6': '₆', '7': '⁷', '8': '⁸', '9': '⁹', a: 'ᵃ', A: 'ᴬ', B: 'ᴮ', b: 'ᵦ', C: '𝒸', d: 'ᵈ', D: 'ᴰ', e: 'ₑ', E: 'ᴱ', f: '𝒻', F: 'ᶠ', g: 'ᵍ', G: 'ᴳ', h: 'ʰ', H: 'ₕ', I: 'ᵢ', i: 'ᵢ', j: 'ʲ', J: 'ᴶ', K: 'ₖ', k: 'ₖ', l: 'ˡ', L: 'ᴸ', m: 'ᵐ', M: 'ₘ', n: 'ₙ', N: 'ᴺ', o: 'ᵒ', O: 'ᴼ', p: 'ᵖ', P: 'ᴾ', Q: 'ᵠ', q: 'ᑫ', r: 'ʳ', R: 'ᵣ', S: 'ˢ', s: 'ˢ', t: 'ᵗ', T: 'ₜ', u: 'ᵘ', U: 'ᵤ', v: 'ᵛ', V: 'ᵥ', w: '𝓌', W: 'ʷ', x: 'ˣ', X: 'ˣ', y: 'y', Y: 'Y', z: '𝓏', Z: 'ᶻ' };
10 | /* eslint-enable */
11 |
12 | const filters = {
13 | sarcastic(letter, index) {
14 | if (index % 2) {
15 | return letter.toUpperCase();
16 | }
17 | return letter.toLowerCase();
18 | },
19 | funky(letter, index) {
20 | // first check if there is a letter in this case
21 | let funkyLetter = funkyLetters[letter];
22 | console.log(funkyLetter);
23 | if (!funkyLetter) {
24 | // then check for a lowercase version
25 | funkyLetter = funkyLetters[letter.toLowerCase()];
26 | }
27 | // if we still don't have something, just use the regular letter
28 | if (!funkyLetter) {
29 | funkyLetter = letter;
30 | }
31 | return funkyLetter;
32 | },
33 | unable(letter) {
34 | const random = Math.floor(Math.random() * 3);
35 | if (letter === ' ' && random === 2) {
36 | return '...';
37 | }
38 | return letter;
39 | },
40 | };
41 |
42 | function handleInput(text) {
43 | const filter = document.querySelector('[name="filter"]:checked').value;
44 | const mod = Array.from(text)
45 | .map(filters[filter])
46 | .join('');
47 | result.textContent = mod;
48 | }
49 |
50 | textarea.addEventListener('input', e => handleInput(e.target.value));
51 |
52 | filterInputs.forEach(input =>
53 | input.addEventListener('input', () => handleInput(textarea.value))
54 | );
55 |
--------------------------------------------------------------------------------
/exercises/56 - Sarcastic Text/text-FINISHED.js:
--------------------------------------------------------------------------------
1 | const textarea = document.querySelector('[name="text"]');
2 | const result = document.querySelector('.result');
3 | const filterInputs = Array.from(document.querySelectorAll('[name="filter"]'));
4 |
5 | /* eslint-disable */
6 | const funkyLetters = {
7 | '-': '₋', '!': 'ᵎ', '?': 'ˀ', '(': '⁽', ')': '₎', '+': '⁺', '=': '₌', '0': '⁰', '1': '₁', '2': '²', '4': '₄', '5': '₅', '6': '₆', '7': '⁷', '8': '⁸', '9': '⁹', a: 'ᵃ', A: 'ᴬ', B: 'ᴮ', b: 'ᵦ', C: '𝒸', d: 'ᵈ', D: 'ᴰ', e: 'ₑ', E: 'ᴱ', f: '𝒻', F: 'ᶠ', g: 'ᵍ', G: 'ᴳ', h: 'ʰ', H: 'ₕ', I: 'ᵢ', i: 'ᵢ', j: 'ʲ', J: 'ᴶ', K: 'ₖ', k: 'ₖ', l: 'ˡ', L: 'ᴸ', m: 'ᵐ', M: 'ₘ', n: 'ₙ', N: 'ᴺ', o: 'ᵒ', O: 'ᴼ', p: 'ᵖ', P: 'ᴾ', Q: 'ᵠ', q: 'ᑫ', r: 'ʳ', R: 'ᵣ', S: 'ˢ', s: 'ˢ', t: 'ᵗ', T: 'ₜ', u: 'ᵘ', U: 'ᵤ', v: 'ᵛ', V: 'ᵥ', w: '𝓌', W: 'ʷ', x: 'ˣ', X: 'ˣ', y: 'y', Y: 'Y', z: '𝓏', Z: 'ᶻ'
8 | };
9 | /* eslint-enable */
10 |
11 | const filters = {
12 | sarcastic(letter, index) {
13 | // if it is odd, it will return 1, and that is truthy, so this if statement will trip
14 | if (index % 2) {
15 | return letter.toUpperCase();
16 | }
17 | // if it is even, it will return zero and we will lowercase it
18 | return letter.toLowerCase();
19 | },
20 | funky(letter) {
21 | // first check if there is a funky letter for this case
22 | let funkyLetter = funkyLetters[letter];
23 | if (funkyLetter) return funkyLetter;
24 | // if there is not, check if there is a lowercase version
25 | funkyLetter = funkyLetters[letter.toLowerCase()];
26 | if (funkyLetter) return funkyLetter;
27 | // if there is nothing, return the regular letter
28 | return letter;
29 | },
30 | unable(letter) {
31 | const random = Math.floor(Math.random() * 3);
32 | if (letter === ' ' && random === 2) {
33 | return '...';
34 | }
35 | return letter;
36 | },
37 | };
38 |
39 | function transformText(text) {
40 | // const filter = document.querySelector('[name="filter"]:checked').value;
41 | const filter = filterInputs.find(input => input.checked).value;
42 | // take the text, and loop over each letter.
43 | const mod = Array.from(text).map(filters[filter]);
44 | result.textContent = mod.join('');
45 | }
46 |
47 | textarea.addEventListener('input', e => transformText(e.target.value));
48 |
49 | filterInputs.forEach(input =>
50 | input.addEventListener('input', () => {
51 | transformText(textarea.value);
52 | })
53 | );
54 |
--------------------------------------------------------------------------------
/exercises/56 - Sarcastic Text/text.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/56 - Sarcastic Text/text.js
--------------------------------------------------------------------------------
/exercises/57 - Shopping List/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Shopping List
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/exercises/57 - Shopping List/shopping-DEMO.js:
--------------------------------------------------------------------------------
1 | // Topics: Custom Events, Event Delegation, local storage, DOM Events, Object Reference,
2 |
3 | const shoppingForm = document.querySelector('.shopping');
4 | const list = document.querySelector('.list');
5 |
6 | let items = [];
7 |
8 | function mirrorToLocalStorage() {
9 | localStorage.setItem('items', JSON.stringify(items));
10 | }
11 |
12 | function restoreFromLocalStorage() {
13 | const lsItems = JSON.parse(localStorage.getItem('items'));
14 | if (lsItems.length) {
15 | items = lsItems;
16 | // fire event
17 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
18 | }
19 | }
20 |
21 | function handleSubmit(e) {
22 | e.preventDefault();
23 | if (!e.target.item.value) return;
24 | const item = {
25 | id: Date.now(),
26 | name: e.target.item.value,
27 | complete: false,
28 | };
29 | items.push(item);
30 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
31 | e.target.reset();
32 | }
33 |
34 | function markAsComplete(id) {
35 | const itemRef = items.find(item => item.id === id);
36 | console.log(itemRef);
37 | // this is just a reference to the item
38 | itemRef.complete = !itemRef.complete;
39 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
40 | }
41 |
42 | function deleteItem(id) {
43 | console.log(items, id);
44 | // find the item's index
45 | items = items.filter(item => item.id !== id);
46 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
47 | }
48 | function displayItems() {
49 | const html = items
50 | .map(
51 | item => `
52 |
55 | ${item.name}
56 | ×
57 | `
58 | )
59 | .join('');
60 | list.innerHTML = html;
61 | }
62 |
63 | shoppingForm.addEventListener('submit', handleSubmit);
64 |
65 | // List is an empty div where we add items with JS
66 | list.addEventListener('click', e => {
67 | if (e.target.matches('button')) {
68 | deleteItem(parseFloat(e.target.value));
69 | }
70 | });
71 |
72 | list.addEventListener('input', e => {
73 | if (e.target.matches('input')) {
74 | markAsComplete(parseFloat(e.target.value));
75 | }
76 | });
77 |
78 | list.addEventListener('itemsUpdated', displayItems);
79 | list.addEventListener('itemsUpdated', mirrorToLocalStorage);
80 |
81 | restoreFromLocalStorage();
82 |
83 | // Challenge - put the done items at the bottom
84 |
--------------------------------------------------------------------------------
/exercises/57 - Shopping List/shopping-FINISHED.js:
--------------------------------------------------------------------------------
1 | const shoppingForm = document.querySelector('.shopping');
2 | const list = document.querySelector('.list');
3 |
4 | // We need an array to hold our state
5 | let items = [];
6 |
7 | function handleSubmit(e) {
8 | e.preventDefault();
9 | console.log('submitted!!');
10 | const name = e.currentTarget.item.value;
11 | // if its empty, then dont submit it
12 | if (!name) return;
13 |
14 | const item = {
15 | name,
16 | id: Date.now(),
17 | complete: false,
18 | };
19 | // Push the items into our state
20 | items.push(item);
21 | console.log(`There are now ${items.length} in your state`);
22 | // Clear the form
23 | e.target.reset();
24 | // fire off a custom event that will tell anyone else who cares that the items have been updated!
25 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
26 | }
27 |
28 | function displayItems() {
29 | console.log(items);
30 | const html = items
31 | .map(
32 | item => `
33 |
38 | ${item.name}
39 | ×
43 | `
44 | )
45 | .join('');
46 | list.innerHTML = html;
47 | }
48 |
49 | function mirrorToLocalStorage() {
50 | console.info('Saving items to localstorage');
51 | localStorage.setItem('items', JSON.stringify(items));
52 | }
53 |
54 | function restoreFromLocalStorage() {
55 | console.info('Restoring from LS');
56 | // pull the items from LS
57 | const lsItems = JSON.parse(localStorage.getItem('items'));
58 | if (lsItems.length) {
59 | // items = lsItems;
60 | // lsItems.forEach(item => items.push(item));
61 | // items.push(lsItems[0], lsItems[1]);
62 | items.push(...lsItems);
63 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
64 | }
65 | }
66 |
67 | function deleteItem(id) {
68 | console.log('DELETIENG ITEM', id);
69 | // update our items array without this one
70 | items = items.filter(item => item.id !== id);
71 | console.log(items);
72 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
73 | }
74 |
75 | function markAsComplete(id) {
76 | console.log('Marking as complete', id);
77 | const itemRef = items.find(item => item.id === id);
78 | itemRef.complete = !itemRef.complete;
79 | list.dispatchEvent(new CustomEvent('itemsUpdated'));
80 | }
81 |
82 | shoppingForm.addEventListener('submit', handleSubmit);
83 | list.addEventListener('itemsUpdated', displayItems);
84 | list.addEventListener('itemsUpdated', mirrorToLocalStorage);
85 | // Event Delegation: We listen or the click on the list but then delegate the click over to the button if that is what was clicked
86 | list.addEventListener('click', function(e) {
87 | const id = parseInt(e.target.value);
88 | if (e.target.matches('button')) {
89 | deleteItem(id);
90 | }
91 | if (e.target.matches('input[type="checkbox"]')) {
92 | markAsComplete(id);
93 | }
94 | });
95 | restoreFromLocalStorage();
96 |
--------------------------------------------------------------------------------
/exercises/57 - Shopping List/shopping.css:
--------------------------------------------------------------------------------
1 | body {
2 | min-height: 100vh;
3 | display: grid;
4 | align-items: start;
5 | justify-items: center;
6 | }
7 |
8 | /* Shopping Form */
9 | .shopping {
10 | display: grid;
11 | grid-template-columns: 1fr auto;
12 | }
13 |
14 | .shopping-list {
15 | background: white;
16 | padding: 3rem;
17 | border-radius: 1rem;
18 | width: 500px;
19 | margin: 4rem 0;
20 | }
21 |
22 | .shopping-list ul {
23 | list-style: none;
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 | .shopping-item {
29 | padding: 1rem 0;
30 | display: grid;
31 | grid-template-columns: auto 1fr auto;
32 | grid-gap: 1rem;
33 | align-items: center;
34 | border-bottom: 1px solid var(--gray);
35 | }
36 |
37 | .shopping-item input[type="checkbox"] {
38 | margin-right: 1rem;
39 | }
40 |
41 | .shopping-item input[type="checkbox"]:checked + .itemName {
42 | opacity: 0.5;
43 | }
44 |
45 | .shopping-item button {
46 | padding: 0;
47 | font-size: 1rem;
48 | cursor: pointer;
49 | transition: transform 0.2s;
50 | }
51 |
52 | .shopping-item button:hover {
53 | transform: scale(1.4);
54 | }
55 |
--------------------------------------------------------------------------------
/exercises/57 - Shopping List/shopping.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/57 - Shopping List/shopping.js
--------------------------------------------------------------------------------
/exercises/58 - Gallery/gallery-DEMO.js:
--------------------------------------------------------------------------------
1 | // Topics: Design Pattern
2 | // Challenge: Add Arrows for prev/next
3 | // Challenge: add close button
4 |
5 | function Gallery(gallery) {
6 | if (!gallery) {
7 | throw new Error('No gallery Found!');
8 | }
9 |
10 | const images = Array.from(gallery.querySelectorAll('img'));
11 | const modal = document.querySelector('.modal');
12 | const prevButton = document.querySelector('.prev');
13 | const nextButton = document.querySelector('.next');
14 | let currentImage;
15 |
16 | function handleKeyUp(e) {
17 | if (e.key === 'Escape') closeModal();
18 | if (e.key === 'ArrowRight') showImage(currentImage.nextElementSibling);
19 | if (e.key === 'ArrowLeft') showImage(currentImage.previousElementSibling);
20 | }
21 |
22 | function handleClickOutside(e) {
23 | if (e.target === e.currentTarget) {
24 | closeModal();
25 | }
26 | }
27 | function showNextImage() {
28 | showImage(currentImage.nextElementSibling);
29 | }
30 | function showPreviousImage() {
31 | showImage(currentImage.previousElementSibling);
32 | }
33 |
34 | function openModal() {
35 | if (modal.matches('.open')) {
36 | console.info('modal already open');
37 | return;
38 | }
39 | // listen for keys
40 | modal.classList.add('open');
41 | window.addEventListener('keyup', handleKeyUp);
42 | modal.addEventListener('click', handleClickOutside);
43 | nextButton.addEventListener('click', showNextImage);
44 | prevButton.addEventListener('click', showPreviousImage);
45 | }
46 |
47 | function closeModal() {
48 | modal.classList.remove('open');
49 | window.removeEventListener('keyup', handleKeyUp);
50 | modal.removeEventListener('click', handleClickOutside);
51 | nextButton.removeEventListener('click', showNextImage);
52 | prevButton.removeEventListener('click', showPreviousImage);
53 | }
54 |
55 | function showImage(el) {
56 | if (!el) {
57 | console.info('No Image To Show');
58 | return;
59 | }
60 | modal.querySelector('img').src = el.src;
61 | modal.querySelector('h2').textContent = el.title;
62 | modal.querySelector('figure p').textContent = el.dataset.description;
63 | currentImage = el;
64 | openModal();
65 | }
66 |
67 | images.forEach(image =>
68 | image.addEventListener('click', e => showImage(e.currentTarget))
69 | );
70 | images.forEach(image =>
71 | image.addEventListener('keyup', e => {
72 | if (e.key === 'Enter') showImage(e.currentTarget);
73 | })
74 | );
75 | }
76 |
77 | const gallery1 = Gallery(document.querySelector('.gallery1'));
78 | const gallery2 = Gallery(document.querySelector('.gallery2'));
79 |
--------------------------------------------------------------------------------
/exercises/58 - Gallery/gallery-FINISHED.js:
--------------------------------------------------------------------------------
1 | function Gallery(gallery) {
2 | if (!gallery) {
3 | throw new Error('No Gallery Found!');
4 | }
5 | // select the elements we need
6 | const images = Array.from(gallery.querySelectorAll('img'));
7 | const modal = document.querySelector('.modal');
8 | const prevButton = modal.querySelector('.prev');
9 | const nextButton = modal.querySelector('.next');
10 | let currentImage;
11 |
12 | function openModal() {
13 | console.info('Opening Modal...');
14 | // First check if the modal is already open
15 | if (modal.matches('.open')) {
16 | console.info('Madal already open');
17 | return; // stop the function from running
18 | }
19 | modal.classList.add('open');
20 |
21 | // Event listeners to be bound when we open the modal:
22 | window.addEventListener('keyup', handleKeyUp);
23 | nextButton.addEventListener('click', showNextImage);
24 | prevButton.addEventListener('click', showPrevImage);
25 | }
26 |
27 | function closeModal() {
28 | modal.classList.remove('open');
29 | // TODO: add event listeners for clicks and keyboard..
30 | window.removeEventListener('keyup', handleKeyUp);
31 | nextButton.removeEventListener('click', showNextImage);
32 | prevButton.removeEventListener('click', showPrevImage);
33 | }
34 |
35 | function handleClickOutside(e) {
36 | if (e.target === e.currentTarget) {
37 | closeModal();
38 | }
39 | }
40 |
41 | function handleKeyUp(event) {
42 | if (event.key === 'Escape') return closeModal();
43 | if (event.key === 'ArrowRight') return showNextImage();
44 | if (event.key === 'ArrowLeft') return showPrevImage();
45 | }
46 |
47 | function showNextImage() {
48 | showImage(currentImage.nextElementSibling || gallery.firstElementChild);
49 | }
50 | function showPrevImage() {
51 | showImage(currentImage.previousElementSibling || gallery.lastElementChild);
52 | }
53 |
54 | function showImage(el) {
55 | if (!el) {
56 | console.info('no image to show');
57 | return;
58 | }
59 | // update the modal with this info
60 | console.log(el);
61 | modal.querySelector('img').src = el.src;
62 | modal.querySelector('h2').textContent = el.title;
63 | modal.querySelector('figure p').textContent = el.dataset.description;
64 | currentImage = el;
65 | openModal();
66 | }
67 |
68 | // These are our Event Listeners!
69 | images.forEach(image =>
70 | image.addEventListener('click', e => showImage(e.currentTarget))
71 | );
72 |
73 | // loop over each image
74 | images.forEach(image => {
75 | // attach an event listener for each image
76 | image.addEventListener('keyup', e => {
77 | // when that is keyup'd, check if it was enter
78 | if (e.key === 'Enter') {
79 | // if it was, show that image
80 | showImage(e.currentTarget);
81 | }
82 | });
83 | });
84 |
85 | modal.addEventListener('click', handleClickOutside);
86 | }
87 |
88 | // Use it on the page
89 |
90 | const gallery1 = Gallery(document.querySelector('.gallery1'));
91 | const gallery2 = Gallery(document.querySelector('.gallery2'));
92 |
--------------------------------------------------------------------------------
/exercises/58 - Gallery/gallery.css:
--------------------------------------------------------------------------------
1 | .galleries {
2 | padding: 2rem;
3 | display: grid;
4 | grid-template-columns: 1fr;
5 | grid-gap: 2rem;
6 | }
7 | .gallery {
8 | display: grid;
9 | width: 100%;
10 | grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
11 | grid-gap: 20px;
12 | align-items: stretch;
13 | background: white;
14 | padding: 2rem;
15 | }
16 |
17 | .gallery img {
18 | width: 100%;
19 | object-fit: cover;
20 | border:1px solid black;
21 | }
22 |
23 | .modal {
24 | position: fixed;
25 | background: rgba(0, 0, 0, 0.5);
26 | z-index: 2;
27 | top: 0;
28 | right: 0;
29 | bottom: 0;
30 | left: 0;
31 | display: grid;
32 | align-items: center;
33 | justify-items: center;
34 | pointer-events: none;
35 | opacity: 0;
36 | transition: opacity 0.5s;
37 | }
38 |
39 | .modalInner {
40 | border-radius: 4px;
41 | background: white;
42 | box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.05);
43 | transform: translateY(-100vh);
44 | transition: all 0.5s;
45 | max-width: 1000px;
46 | height: calc(100vh - 100px);
47 | display: grid;
48 | grid-template-columns: 50px 1fr 50px;
49 | color: black;
50 | margin: 3rem;
51 | }
52 |
53 | .modal figure {
54 | height: 100%;
55 | display: grid;
56 | margin: 0;
57 | grid-template-rows: 1fr auto;
58 | }
59 |
60 | .modal img {
61 | height: 100%;
62 | width: 100%;
63 | object-fit: contain;
64 | }
65 |
66 | .modal.open {
67 | opacity: 1;
68 | pointer-events: all;
69 | }
70 |
71 | .modal figcaption {
72 | padding: 10px;
73 | }
74 |
75 | .modal h2 {
76 | color: black;
77 | }
78 |
79 | .modal.open .modalInner {
80 | transform: translateY(0);
81 | }
82 |
--------------------------------------------------------------------------------
/exercises/58 - Gallery/gallery.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/gallery.js
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/270-camo-sunset.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/270-camo-sunset.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/TNF-fanorak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/TNF-fanorak.png
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/canada-goose.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/canada-goose.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/coral-yeti.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/coral-yeti.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/hondo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/hondo.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/kith-hoodie.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/kith-hoodie.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/naked-and-famous-denim.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/naked-and-famous-denim.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/nudie-belt.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/nudie-belt.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/patagonia black hole.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/patagonia black hole.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/rimowa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/rimowa.png
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/ultra-boost.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/ultra-boost.jpg
--------------------------------------------------------------------------------
/exercises/58 - Gallery/images/vapormax.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/58 - Gallery/images/vapormax.jpg
--------------------------------------------------------------------------------
/exercises/59 - Slider/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/59 - Slider/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | JavaScript Slider
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
1
15 |
2
16 |
3
17 |
4
18 |
5
19 |
6
20 |
7
21 |
8
22 |
9
23 |
10
24 |
11
25 |
12
26 |
13
27 |
14
28 |
15
29 |
16
30 |
17
31 |
18
32 |
19
33 |
20
34 |
35 |
36 | ← Prev
37 | Next →
38 |
39 |
40 |
41 |
42 |
43 |
0001
44 |
0002
45 |
0003
46 |
0004
47 |
0005
48 |
49 |
50 | ← Prev
51 | Next →
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/exercises/59 - Slider/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "slider",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "parcel index.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "sass": "^1.23.3"
13 | },
14 | "dependencies": {
15 | "parcel": "2.0.1"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/exercises/59 - Slider/src/index-FINISHED.js:
--------------------------------------------------------------------------------
1 | function Slider(slider) {
2 | if (!(slider instanceof Element)) {
3 | throw new Error('No slider passed in');
4 | }
5 | // create some variables for working iwth the slider
6 | let prev;
7 | let current;
8 | let next;
9 | // select the elements needed for the slider
10 | const slides = slider.querySelector('.slides');
11 | const prevButton = slider.querySelector('.goToPrev');
12 | const nextButton = slider.querySelector('.goToNext');
13 |
14 | function startSlider() {
15 | current = slider.querySelector('.current') || slides.firstElementChild;
16 | prev = current.previousElementSibling || slides.lastElementChild;
17 | next = current.nextElementSibling || slides.firstElementChild;
18 | console.log({ current, prev, next });
19 | }
20 |
21 | function applyClasses() {
22 | current.classList.add('current');
23 | prev.classList.add('prev');
24 | next.classList.add('next');
25 | }
26 |
27 | function move(direction) {
28 | // first strip all the classes off the current slides
29 | const classesToRemove = ['prev', 'current', 'next'];
30 | prev.classList.remove(...classesToRemove);
31 | current.classList.remove(...classesToRemove);
32 | next.classList.remove(...classesToRemove);
33 | if (direction === 'back') {
34 | // make an new array of the new values, and destructure them over and into the prev, current and next variables
35 | [prev, current, next] = [
36 | // get the prev slide, if there is none, get the last slide from the entire slider for wrapping
37 | prev.previousElementSibling || slides.lastElementChild,
38 | prev,
39 | current,
40 | ];
41 | } else {
42 | [prev, current, next] = [
43 | current,
44 | next,
45 | // get the next slide, or if it's at the end, loop around and grab the first slide
46 | next.nextElementSibling || slides.firstElementChild,
47 | ];
48 | }
49 |
50 | applyClasses();
51 | }
52 |
53 | // when this slider is created, run the start slider function
54 | startSlider();
55 | applyClasses();
56 |
57 | // Event listeners
58 | prevButton.addEventListener('click', () => move('back'));
59 | nextButton.addEventListener('click', move);
60 | }
61 |
62 | const mySlider = Slider(document.querySelector('.slider'));
63 | const dogSlider = Slider(document.querySelector('.dog-slider'));
64 |
--------------------------------------------------------------------------------
/exercises/59 - Slider/src/index-prototype-FINISHED.js:
--------------------------------------------------------------------------------
1 | function Slider(slider) {
2 | if (!(slider instanceof Element)) {
3 | throw new Error('No slider passed in');
4 | }
5 |
6 | // select the elements needed for the slider
7 | this.slides = slider.querySelector('.slides');
8 | this.slider = slider;
9 | const prevButton = slider.querySelector('.goToPrev');
10 | const nextButton = slider.querySelector('.goToNext');
11 |
12 | // when this slider is created, run the start slider function
13 | this.startSlider();
14 | this.applyClasses();
15 |
16 | // Event listeners
17 | prevButton.addEventListener('click', () => this.move('back'));
18 | nextButton.addEventListener('click', () => this.move());
19 | }
20 |
21 | Slider.prototype.startSlider = function() {
22 | this.current =
23 | this.slider.querySelector('.current') || this.slides.firstElementChild;
24 | this.prev =
25 | this.current.previousElementSibling || this.slides.lastElementChild;
26 | this.next = this.current.nextElementSibling || this.slides.firstElementChild;
27 | };
28 |
29 | Slider.prototype.applyClasses = function() {
30 | this.current.classList.add('current');
31 | this.prev.classList.add('prev');
32 | this.next.classList.add('next');
33 | };
34 |
35 | Slider.prototype.move = function(direction) {
36 | // first strip all the classes off the current slides
37 | const classesToRemove = ['prev', 'current', 'next'];
38 | this.prev.classList.remove(...classesToRemove);
39 | this.current.classList.remove(...classesToRemove);
40 | this.next.classList.remove(...classesToRemove);
41 | if (direction === 'back') {
42 | // make an new array of the new values, and destructure them over and into the prev, current and next variables
43 | [this.prev, this.current, this.next] = [
44 | // get the prev slide, if there is none, get the last slide from the entire slider for wrapping
45 | this.prev.previousElementSibling || this.slides.lastElementChild,
46 | this.prev,
47 | this.current,
48 | ];
49 | } else {
50 | [this.prev, this.current, this.next] = [
51 | this.current,
52 | this.next,
53 | // get the next slide, or if it's at the end, loop around and grab the first slide
54 | this.next.nextElementSibling || this.slides.firstElementChild,
55 | ];
56 | }
57 |
58 | this.applyClasses();
59 | };
60 |
61 | const mySlider = new Slider(document.querySelector('.slider'));
62 | const dogSlider = new Slider(document.querySelector('.dog-slider'));
63 |
64 | console.log(mySlider, dogSlider);
65 |
66 | window.dogSlider = dogSlider;
67 |
68 | window.addEventListener('keyup', function(e) {
69 | if (e.key === 'ArrowRight') {
70 | dogSlider.move();
71 | }
72 | if (e.key === 'ArrowLeft') {
73 | dogSlider.move('back');
74 | }
75 | });
76 |
--------------------------------------------------------------------------------
/exercises/59 - Slider/src/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/59 - Slider/src/index.js
--------------------------------------------------------------------------------
/exercises/59 - Slider/style.scss:
--------------------------------------------------------------------------------
1 | .slides {
2 | width: 800px;
3 | height: 500px;
4 | border:2px solid black;
5 | position: relative;
6 | margin: 0 auto;
7 | overflow: hidden;
8 | }
9 |
10 | .slide {
11 | position: absolute;
12 | background: var(--pink);
13 | height: 100%;
14 | width: 100%;
15 | display: grid;
16 | align-content: center;
17 | justify-content: center;
18 | color: white;
19 | font-size: 100px;
20 | font-family: sans-serif;
21 | border: 5px solid white;
22 | transition: all .25s;
23 | transform: translateX(-200%);
24 | }
25 |
26 | .slide.next + .slide {
27 | transform: translateX(200%);
28 | }
29 |
30 | .slide.prev {
31 | z-index: 10;
32 | transform: translateX(-100%);
33 | }
34 | .slide.current {
35 | z-index: 10;
36 | transform: translateX(0);
37 | }
38 | .slide.next {
39 | z-index: 10;
40 | transform: translateX(100%);
41 | }
42 |
43 | .controls {
44 | display: grid;
45 | grid-template-columns: repeat(auto-fit, minmax(200px, 200px));
46 | gap: 2rem;
47 | justify-content: center;
48 | padding: 2rem;
49 | }
50 |
--------------------------------------------------------------------------------
/exercises/72 - Async Prompts/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Async Prompt
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Enter Name
16 | Enter Age
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/exercises/72 - Async Prompts/scripts-FINISHED.js:
--------------------------------------------------------------------------------
1 | function wait(ms = 0) {
2 | return new Promise(resolve => setTimeout(resolve, ms));
3 | }
4 |
5 | async function destroyPopup(popup) {
6 | popup.classList.remove('open');
7 | await wait(1000);
8 | // remove the popup entirely!
9 | popup.remove();
10 | /* eslint-disable no-param-reassign */
11 | popup = null;
12 | /* eslint-enable no-param-reassign */
13 | }
14 |
15 | function ask(options) {
16 | return new Promise(async function(resolve) {
17 | // First we need to create a popup with all the fields in it
18 | const popup = document.createElement('form');
19 | popup.classList.add('popup');
20 | popup.insertAdjacentHTML(
21 | 'afterbegin',
22 | `
23 | ${options.title}
24 |
25 | Submit
26 |
27 | `
28 | );
29 |
30 | // check if they want a cancel button
31 | if (options.cancel) {
32 | const skipButton = document.createElement('button');
33 | skipButton.type = 'button';
34 | skipButton.textContent = 'Cancel';
35 | popup.firstElementChild.appendChild(skipButton);
36 | // TODO: listen for a click on that cancel button
37 | skipButton.addEventListener(
38 | 'click',
39 | function() {
40 | resolve(null);
41 | destroyPopup(popup);
42 | },
43 | { once: true }
44 | );
45 | }
46 | // listen for the submit event on the inputs
47 | popup.addEventListener(
48 | 'submit',
49 | function(e) {
50 | e.preventDefault();
51 | console.log('SUBMITTED');
52 | resolve(e.target.input.value);
53 | // remove it from the DOM entirely
54 | destroyPopup(popup);
55 | },
56 | { once: true }
57 | );
58 | // when someone does submit it, resolve the data that was in the input box!
59 |
60 | // insert that popup into the DOM
61 | document.body.appendChild(popup);
62 | // put a very small timeout before we add the open class
63 |
64 | await wait(50);
65 | popup.classList.add('open');
66 | });
67 | }
68 |
69 | // select all button that have a question
70 | async function askQuestion(e) {
71 | const button = e.currentTarget;
72 | const cancel = 'cancel' in button.dataset;
73 |
74 | const answer = await ask({
75 | title: button.dataset.question,
76 | cancel,
77 | });
78 | console.log(answer);
79 | }
80 |
81 | const buttons = document.querySelectorAll('[data-question]');
82 | buttons.forEach(button => button.addEventListener('click', askQuestion));
83 |
84 | const questions = [
85 | { title: 'What is your name?' },
86 | { title: 'What is your age?', cancel: true },
87 | { title: 'What is your dogs name?' },
88 | ];
89 |
90 | async function asyncMap(array, callback) {
91 | // make an array to store our results
92 | const results = [];
93 | // loop over our array
94 | for (const item of array) {
95 | results.push(await callback(item));
96 | }
97 | // when we are done the loop, return it!
98 | return results;
99 | }
100 |
101 | async function go() {
102 | const answers = await asyncMap(questions, ask);
103 | console.log(answers);
104 | }
105 |
106 | go();
107 |
108 | // async function askMany() {
109 | // for (const question of questions) {
110 | // const answer = await ask(question);
111 | // console.log(answer);
112 | // }
113 | // }
114 |
115 | // askMany();
116 |
--------------------------------------------------------------------------------
/exercises/72 - Async Prompts/scripts.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/72 - Async Prompts/scripts.js
--------------------------------------------------------------------------------
/exercises/72 - Async Prompts/style.css:
--------------------------------------------------------------------------------
1 | .popup {
2 | background: hsla(0, 0%, 30%, 0.5);
3 | position: fixed;
4 | height: 100vh;
5 | width: 100vw;
6 | transition: all 0.25s;
7 | top: 0;
8 | display: grid;
9 | justify-content: center;
10 | align-items: center;
11 | pointer-events: none;
12 | --opacity: 0;
13 | opacity: var(--opacity);
14 | }
15 |
16 | .popup fieldset {
17 | background: var(--grey);
18 | padding: 2rem;
19 | border: 3px solid var(--pink);
20 | border-radius: 5px;
21 | box-shadow: var(--box-shadow);
22 | transition: all 0.2s;
23 | --scale: 0.3;
24 | transform: scale(var(--scale));
25 | }
26 |
27 | .popup.open {
28 | --opacity: 1;
29 | pointer-events: all;
30 | }
31 |
32 | .popup.open fieldset {
33 | --scale: 1;
34 | }
35 |
--------------------------------------------------------------------------------
/exercises/73 - Async Typer/scripts-FINISHED.js:
--------------------------------------------------------------------------------
1 | function wait(ms = 0) {
2 | return new Promise(resolve => setTimeout(resolve, ms));
3 | }
4 |
5 | function getRandomBetween(min = 20, max = 150, randomNumber = Math.random()) {
6 | return Math.floor(randomNumber * (max - min) + min);
7 | }
8 |
9 | // async for of loop
10 | // async function draw(el) {
11 | // const text = el.textContent;
12 | // let soFar = '';
13 | // for (const letter of text) {
14 | // soFar += letter;
15 | // el.textContent = soFar;
16 | // // wait for some amount of time
17 | // const { typeMin, typeMax } = el.dataset;
18 | // const amountOfTimeToWait = getRandomBetween(typeMin, typeMax);
19 | // await wait(amountOfTimeToWait);
20 | // }
21 | // }
22 |
23 | // recursion
24 | function draw(el) {
25 | let index = 1;
26 | const text = el.textContent;
27 | const { typeMin, typeMax } = el.dataset;
28 | async function drawLetter() {
29 | el.textContent = text.slice(0, index);
30 | index += 1;
31 | const amountOfTimeToWait = getRandomBetween(typeMin, typeMax);
32 | // exit condition
33 | await wait(amountOfTimeToWait);
34 | if (index <= text.length) {
35 | drawLetter();
36 | // wait for some time
37 | }
38 | }
39 | // when this function draw() runs, kick off drawLetter
40 | drawLetter();
41 | }
42 |
43 | document.querySelectorAll('[data-type]').forEach(draw);
44 |
--------------------------------------------------------------------------------
/exercises/73 - Async Typer/scripts.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/73 - Async Typer/scripts.js
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/index-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Recipe Fetcher
8 |
9 |
30 |
31 |
32 |
33 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Recipe Fetcher
8 |
9 |
15 |
16 |
17 |
18 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dogrecipes",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "scripts.js",
6 | "scripts": {
7 | "start": "parcel index.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "parcel": "2.0.1"
13 | },
14 | "browserslist": [
15 | "last 1 chrome versions"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/scripts-FINISHED.js:
--------------------------------------------------------------------------------
1 | const baseEndpoint = 'https://recipes.beginnerjavascript.com/api';
2 | const proxy = `https://cors-anywhere.herokuapp.com/`;
3 | const form = document.querySelector('form.search');
4 | const recipesGrid = document.querySelector('.recipes');
5 |
6 | async function fetchRecipes(query) {
7 | const res = await fetch(`${proxy}${baseEndpoint}?q=${query}`);
8 | const data = await res.json();
9 | return data;
10 | }
11 |
12 | async function handleSubmit(event) {
13 | event.preventDefault();
14 | const el = event.currentTarget;
15 | console.log(form.query.value);
16 | fetchAndDisplay(form.query.value);
17 | }
18 |
19 | async function fetchAndDisplay(query) {
20 | // turn the form off
21 | form.submit.disabled = true;
22 | // submit the search
23 | const recipes = await fetchRecipes(query);
24 | console.log(recipes);
25 | form.submit.disabled = false;
26 | displayRecipes(recipes.results);
27 | }
28 |
29 | function displayRecipes(recipes) {
30 | console.log('Creating HTML');
31 | const html = recipes.map(
32 | recipe => `
33 |
${recipe.title}
34 |
${recipe.ingredients}
35 | ${recipe.thumbnail &&
36 | `
`}
37 |
View Recipe →
38 |
`
39 | );
40 | recipesGrid.innerHTML = html.join('');
41 | }
42 |
43 | form.addEventListener('submit', handleSubmit);
44 | // on page load run it with pizza
45 | fetchAndDisplay('pizza');
46 |
--------------------------------------------------------------------------------
/exercises/75 - CORS and Recipes/scripts.js:
--------------------------------------------------------------------------------
1 | // The Recipe Puppy API used in the course is broken
2 | // Please use this replacement API URL "https://recipes.beginnerjavascript.com/api"
3 |
--------------------------------------------------------------------------------
/exercises/76 - Dad Jokes/index-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dad Jokes
8 |
9 |
65 |
66 |
67 |
68 |
69 |
72 |
73 | Get A Joke
74 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/exercises/76 - Dad Jokes/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dad Jokes
8 |
9 |
19 |
20 |
21 |
22 |
23 |
26 |
Get A Joke
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/exercises/76 - Dad Jokes/jokes-FINISHED.js:
--------------------------------------------------------------------------------
1 | const jokeButton = document.querySelector('.getJoke');
2 | const jokeButtonSpan = jokeButton.querySelector('.jokeText');
3 | const jokeHolder = document.querySelector('.joke p');
4 | const loader = document.querySelector('.loader');
5 |
6 | const buttonText = [
7 | 'Ugh.',
8 | '🤦🏻♂️',
9 | 'omg dad.',
10 | 'you are the worst',
11 | 'seriously',
12 | 'stop it.',
13 | 'please stop',
14 | 'that was the worst one',
15 | ];
16 |
17 | async function fetchJoke() {
18 | // turn loader on
19 | loader.classList.remove('hidden');
20 | const response = await fetch('https://icanhazdadjoke.com', {
21 | headers: {
22 | Accept: 'application/json',
23 | },
24 | });
25 | const data = await response.json();
26 | // turn the loader off
27 | loader.classList.add('hidden');
28 | return data;
29 | }
30 |
31 | function randomItemFromArray(arr, not) {
32 | const item = arr[Math.floor(Math.random() * arr.length)];
33 | if (item === not) {
34 | console.log('Ahh we used that one last time, look again');
35 | return randomItemFromArray(arr, not);
36 | }
37 | return item;
38 | }
39 |
40 | async function handleClick() {
41 | const { joke } = await fetchJoke();
42 | jokeHolder.textContent = joke;
43 | jokeButtonSpan.textContent = randomItemFromArray(
44 | buttonText,
45 | jokeButtonSpan.textContent
46 | );
47 | }
48 |
49 | jokeButton.addEventListener('click', handleClick);
50 |
--------------------------------------------------------------------------------
/exercises/76 - Dad Jokes/jokes.js:
--------------------------------------------------------------------------------
1 | const buttonText = [
2 | 'Ugh.',
3 | '🤦🏻♂️',
4 | 'omg dad.',
5 | 'you are the worst',
6 | 'seriously',
7 | 'stop it.',
8 | 'please stop',
9 | 'that was the worst one',
10 | ];
11 |
--------------------------------------------------------------------------------
/exercises/77 - Currency Converter/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Currency Converter
8 |
9 |
10 |
11 |
12 |
13 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/exercises/77 - Currency Converter/money-FINISHED.js:
--------------------------------------------------------------------------------
1 | const fromSelect = document.querySelector('[name="from_currency"]');
2 | const fromInput = document.querySelector('[name="from_amount"]');
3 | const toSelect = document.querySelector('[name="to_currency"]');
4 | const toEl = document.querySelector('.to_amount');
5 | const form = document.querySelector('.app form');
6 | const endpoint = 'https://api.ratesapi.io/latest';
7 | const ratesByBase = {};
8 |
9 | const currencies = {
10 | USD: 'United States Dollar',
11 | AUD: 'Australian Dollar',
12 | BGN: 'Bulgarian Lev',
13 | BRL: 'Brazilian Real',
14 | CAD: 'Canadian Dollar',
15 | CHF: 'Swiss Franc',
16 | CNY: 'Chinese Yuan',
17 | CZK: 'Czech Republic Koruna',
18 | DKK: 'Danish Krone',
19 | GBP: 'British Pound Sterling',
20 | HKD: 'Hong Kong Dollar',
21 | HRK: 'Croatian Kuna',
22 | HUF: 'Hungarian Forint',
23 | IDR: 'Indonesian Rupiah',
24 | ILS: 'Israeli New Sheqel',
25 | INR: 'Indian Rupee',
26 | JPY: 'Japanese Yen',
27 | KRW: 'South Korean Won',
28 | MXN: 'Mexican Peso',
29 | MYR: 'Malaysian Ringgit',
30 | NOK: 'Norwegian Krone',
31 | NZD: 'New Zealand Dollar',
32 | PHP: 'Philippine Peso',
33 | PLN: 'Polish Zloty',
34 | RON: 'Romanian Leu',
35 | RUB: 'Russian Ruble',
36 | SEK: 'Swedish Krona',
37 | SGD: 'Singapore Dollar',
38 | THB: 'Thai Baht',
39 | TRY: 'Turkish Lira',
40 | ZAR: 'South African Rand',
41 | EUR: 'Euro',
42 | };
43 |
44 | function generateOptions(options) {
45 | return Object.entries(options)
46 | .map(
47 | ([currencyCode, currencyName]) =>
48 | `${currencyCode} - ${currencyName} `
49 | )
50 | .join('');
51 | }
52 |
53 | async function fetchRates(base = 'USD') {
54 | const res = await fetch(`${endpoint}?base=${base}`);
55 | const rates = await res.json();
56 | return rates;
57 | }
58 |
59 | async function convert(amount, from, to) {
60 | // first check if we even have the rates to convert from that currency
61 | if (!ratesByBase[from]) {
62 | console.log(
63 | `Oh no, we dont have ${from} to convert to ${to}. So gets go get it!`
64 | );
65 | const rates = await fetchRates(from);
66 | console.log(rates);
67 | // store them for next time
68 | ratesByBase[from] = rates;
69 | }
70 | // convert that amount that they passed it
71 | const rate = ratesByBase[from].rates[to];
72 | const convertedAmount = rate * amount;
73 | console.log(`${amount} ${from} is ${convertedAmount} in ${to}`);
74 | return convertedAmount;
75 | }
76 |
77 | function formatCurrency(amount, currency) {
78 | return Intl.NumberFormat('en-US', {
79 | style: 'currency',
80 | currency,
81 | }).format(amount);
82 | }
83 | async function handleInput(e) {
84 | const rawAmount = await convert(
85 | fromInput.value,
86 | fromSelect.value,
87 | toSelect.value
88 | );
89 | toEl.textContent = formatCurrency(rawAmount, toSelect.value);
90 | }
91 |
92 | const optionsHTML = generateOptions(currencies);
93 | // populate the options elements
94 | fromSelect.innerHTML = optionsHTML;
95 | toSelect.innerHTML = optionsHTML;
96 |
97 | form.addEventListener('input', handleInput);
98 |
--------------------------------------------------------------------------------
/exercises/77 - Currency Converter/money.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | background-color: #d0d0d0;
3 | }
4 |
5 | body {
6 | display: grid;
7 | grid-template-rows: 1fr;
8 | justify-content: center;
9 | align-items: center;
10 | min-height: 100vh;
11 | }
12 |
13 | .app {
14 | max-width: 800px;
15 | background: white;
16 | }
17 |
18 | .app form {
19 | border:0;
20 | display: grid;
21 | grid-template-columns: auto 1fr;
22 | grid-auto-rows: 1fr;
23 | font-size: 3rem;
24 | text-align: center;
25 | font-weight: 600;
26 | padding: 2rem;
27 | box-shadow: 0 0 10px rgba(0,0,0,0.2);
28 | grid-gap:2rem;
29 | align-items: stretch;
30 | }
31 |
32 |
33 | .app :is(button, input, select, textarea) {
34 | margin:0;
35 | text-align: center;
36 | font-weight: 600;
37 | border:0;
38 | }
39 |
40 | .app :is(button, input, select, textarea):focus {
41 | outline-color: violet;
42 | }
43 |
44 | .app input {
45 | width: 250px;
46 | }
47 |
48 | .app select {
49 | background: none;
50 | border:0;
51 | padding: 2rem;
52 | }
53 |
54 | .app form > * {
55 | background: var(--yellow);
56 | margin: 0;
57 | border-radius: 0;
58 | -webkit-appearance: none;
59 | display: grid;
60 | align-content: center;
61 | }
62 |
--------------------------------------------------------------------------------
/exercises/77 - Currency Converter/money.js:
--------------------------------------------------------------------------------
1 | const currencies = {
2 | USD: 'United States Dollar',
3 | AUD: 'Australian Dollar',
4 | BGN: 'Bulgarian Lev',
5 | BRL: 'Brazilian Real',
6 | CAD: 'Canadian Dollar',
7 | CHF: 'Swiss Franc',
8 | CNY: 'Chinese Yuan',
9 | CZK: 'Czech Republic Koruna',
10 | DKK: 'Danish Krone',
11 | GBP: 'British Pound Sterling',
12 | HKD: 'Hong Kong Dollar',
13 | HRK: 'Croatian Kuna',
14 | HUF: 'Hungarian Forint',
15 | IDR: 'Indonesian Rupiah',
16 | ILS: 'Israeli New Sheqel',
17 | INR: 'Indian Rupee',
18 | JPY: 'Japanese Yen',
19 | KRW: 'South Korean Won',
20 | MXN: 'Mexican Peso',
21 | MYR: 'Malaysian Ringgit',
22 | NOK: 'Norwegian Krone',
23 | NZD: 'New Zealand Dollar',
24 | PHP: 'Philippine Peso',
25 | PLN: 'Polish Zloty',
26 | RON: 'Romanian Leu',
27 | RUB: 'Russian Ruble',
28 | SEK: 'Swedish Krona',
29 | SGD: 'Singapore Dollar',
30 | THB: 'Thai Baht',
31 | TRY: 'Turkish Lira',
32 | ZAR: 'South African Rand',
33 | EUR: 'Euro',
34 | };
35 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/currencies.js:
--------------------------------------------------------------------------------
1 | const currencies = {
2 | USD: 'United States Dollar',
3 | AUD: 'Australian Dollar',
4 | BGN: 'Bulgarian Lev',
5 | BRL: 'Brazilian Real',
6 | CAD: 'Canadian Dollar',
7 | CHF: 'Swiss Franc',
8 | CNY: 'Chinese Yuan',
9 | CZK: 'Czech Republic Koruna',
10 | DKK: 'Danish Krone',
11 | GBP: 'British Pound Sterling',
12 | HKD: 'Hong Kong Dollar',
13 | HRK: 'Croatian Kuna',
14 | HUF: 'Hungarian Forint',
15 | IDR: 'Indonesian Rupiah',
16 | ILS: 'Israeli New Sheqel',
17 | INR: 'Indian Rupee',
18 | JPY: 'Japanese Yen',
19 | KRW: 'South Korean Won',
20 | MXN: 'Mexican Peso',
21 | MYR: 'Malaysian Ringgit',
22 | NOK: 'Norwegian Krone',
23 | NZD: 'New Zealand Dollar',
24 | PHP: 'Philippine Peso',
25 | PLN: 'Polish Zloty',
26 | RON: 'Romanian Leu',
27 | RUB: 'Russian Ruble',
28 | SEK: 'Swedish Krona',
29 | SGD: 'Singapore Dollar',
30 | THB: 'Thai Baht',
31 | TRY: 'Turkish Lira',
32 | ZAR: 'South African Rand',
33 | EUR: 'Euro',
34 | };
35 |
36 | export default currencies;
37 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/elements.js:
--------------------------------------------------------------------------------
1 | export const fromSelect = document.querySelector('[name="from_currency"]');
2 | export const fromInput = document.querySelector('[name="from_amount"]');
3 | export const toSelect = document.querySelector('[name="to_currency"]');
4 | export const toEl = document.querySelector('.to_amount');
5 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/handlers.js:
--------------------------------------------------------------------------------
1 | import { convert } from './lib.js';
2 | import { formatCurrency } from './utils.js';
3 | import { fromInput, fromSelect, toSelect, toEl } from './elements.js';
4 |
5 | export async function handleInput(e) {
6 | const rawAmount = await convert(
7 | fromInput.value,
8 | fromSelect.value,
9 | toSelect.value
10 | );
11 | toEl.textContent = formatCurrency(rawAmount, toSelect.value);
12 | }
13 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Currency Converter
8 |
9 |
10 |
11 |
12 |
13 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/init.js:
--------------------------------------------------------------------------------
1 | import { fromSelect, toSelect } from './elements.js';
2 | import { generateOptions } from './utils.js';
3 | import currencies from './currencies.js';
4 | import { handleInput } from './handlers.js';
5 |
6 | export function init() {
7 | // when the page loads, this code runs!
8 | const form = document.querySelector('.app form');
9 |
10 | const optionsHTML = generateOptions(currencies);
11 | // populate the options elements
12 | fromSelect.innerHTML = optionsHTML;
13 | toSelect.innerHTML = optionsHTML;
14 |
15 | form.addEventListener('input', handleInput);
16 | }
17 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/lib.js:
--------------------------------------------------------------------------------
1 | const endpoint = 'https://api.exchangeratesapi.io/latest';
2 | const ratesByBase = {};
3 |
4 | export async function fetchRates(base = 'USD') {
5 | const res = await fetch(`${endpoint}?base=${base}`);
6 | const rates = await res.json();
7 | return rates;
8 | }
9 |
10 | export async function convert(amount, from, to) {
11 | // first check if we even have the rates to convert from that currency
12 | if (!ratesByBase[from]) {
13 | console.log(
14 | `Oh no, we dont have ${from} to convert to ${to}. So gets go get it!`
15 | );
16 | const rates = await fetchRates(from);
17 | console.log(rates);
18 | // store them for next time
19 | ratesByBase[from] = rates;
20 | }
21 | // convert that amount that they passed it
22 | const rate = ratesByBase[from].rates[to];
23 | const convertedAmount = rate * amount;
24 | console.log(`${amount} ${from} is ${convertedAmount} in ${to}`);
25 | return convertedAmount;
26 | }
27 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/money.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | background-color: #d0d0d0;
3 | }
4 |
5 | body {
6 | display: grid;
7 | grid-template-rows: 1fr;
8 | justify-content: center;
9 | align-items: center;
10 | min-height: 100vh;
11 | }
12 |
13 | .app {
14 | max-width: 800px;
15 | background: white;
16 | }
17 |
18 | .app form {
19 | border:0;
20 | display: grid;
21 | grid-template-columns: auto 1fr;
22 | grid-auto-rows: 1fr;
23 | font-size: 3rem;
24 | text-align: center;
25 | font-weight: 600;
26 | padding: 2rem;
27 | box-shadow: 0 0 10px rgba(0,0,0,0.2);
28 | grid-gap:2rem;
29 | align-items: stretch;
30 | }
31 |
32 |
33 | .app :is(button, input, select, textarea) {
34 | margin:0;
35 | text-align: center;
36 | font-weight: 600;
37 | border:0;
38 | }
39 |
40 | .app :is(button, input, select, textarea):focus {
41 | outline-color: violet;
42 | }
43 |
44 | .app input {
45 | width: 250px;
46 | }
47 |
48 | .app select {
49 | background: none;
50 | border:0;
51 | padding: 2rem;
52 | }
53 |
54 | .app form > * {
55 | background: var(--yellow);
56 | margin: 0;
57 | border-radius: 0;
58 | -webkit-appearance: none;
59 | display: grid;
60 | align-content: center;
61 | }
62 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/money.js:
--------------------------------------------------------------------------------
1 | import { init } from './init.js';
2 |
3 | // start the app!
4 | const app = document.querySelector('.app');
5 |
6 | app.addEventListener('mouseenter', init, { once: true });
7 |
--------------------------------------------------------------------------------
/exercises/79 - Currency Converter Modules Refactor - FINISHED/utils.js:
--------------------------------------------------------------------------------
1 | export function generateOptions(options) {
2 | return Object.entries(options)
3 | .map(
4 | ([currencyCode, currencyName]) =>
5 | `${currencyCode} - ${currencyName} `
6 | )
7 | .join('');
8 | }
9 |
10 | export function formatCurrency(amount, currency) {
11 | return Intl.NumberFormat('en-US', {
12 | style: 'currency',
13 | currency,
14 | }).format(amount);
15 | }
16 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/data/buttonText.js:
--------------------------------------------------------------------------------
1 | const buttonText = [
2 | 'Ugh.',
3 | '🤦🏻♂️',
4 | 'omg dad.',
5 | 'you are the worst',
6 | 'seriously',
7 | 'stop it.',
8 | 'please stop',
9 | 'that was the worst one',
10 | ];
11 |
12 | // default export (only one per file)
13 | export default buttonText;
14 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dad Jokes
8 |
9 |
65 |
66 |
67 |
68 |
69 |
72 |
73 | Get A Joke
74 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/jokes.js:
--------------------------------------------------------------------------------
1 | import { handleClick } from './lib/handlers.js';
2 | import { jokeButton } from './lib/elements.js';
3 |
4 | jokeButton.addEventListener('click', handleClick);
5 |
6 | console.log('heyy');
7 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/lib/elements.js:
--------------------------------------------------------------------------------
1 | export const jokeButton = document.querySelector('.getJoke');
2 | export const jokeButtonSpan = jokeButton.querySelector('.jokeText');
3 | export const jokeHolder = document.querySelector('.joke p');
4 | export const loader = document.querySelector('.loader');
5 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/lib/handlers.js:
--------------------------------------------------------------------------------
1 | import { fetchJoke } from './index.js';
2 | import { loader, jokeHolder, jokeButtonSpan } from './elements.js';
3 | import { randomItemFromArray } from './utils.js';
4 | import buttonText from '../data/buttonText.js';
5 |
6 | // Named export
7 | export async function handleClick() {
8 | const { joke } = await fetchJoke(loader);
9 | jokeHolder.textContent = joke;
10 | jokeButtonSpan.textContent = randomItemFromArray(
11 | buttonText,
12 | jokeButtonSpan.textContent
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/lib/index.js:
--------------------------------------------------------------------------------
1 | // Named Export (we can have lots of these)
2 | export async function fetchJoke(loader) {
3 | // turn loader on
4 | loader.classList.remove('hidden');
5 | const response = await fetch('https://icanhazdadjoke.com', {
6 | headers: {
7 | Accept: 'application/json',
8 | },
9 | });
10 | const data = await response.json();
11 | // turn the loader off
12 | loader.classList.add('hidden');
13 | return data;
14 | }
15 |
--------------------------------------------------------------------------------
/exercises/80 - Dad Jokes Modules - FINISHED/lib/utils.js:
--------------------------------------------------------------------------------
1 | // named export
2 | export function randomItemFromArray(arr, not) {
3 | const item = arr[Math.floor(Math.random() * arr.length)];
4 | if (item === not) {
5 | console.log('Ahh we used that one last time, look again');
6 | return randomItemFromArray(arr, not);
7 | }
8 | return item;
9 | }
10 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/data/buttonText.js:
--------------------------------------------------------------------------------
1 | const buttonText = [
2 | 'Ugh.',
3 | '🤦🏻♂️',
4 | 'omg dad.',
5 | 'you are the worst',
6 | 'seriously',
7 | 'stop it.',
8 | 'please stop',
9 | 'that was the worst one',
10 | ];
11 |
12 | // default export (only one per file)
13 | export default buttonText;
14 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Dad Jokes
8 |
9 |
65 |
66 |
67 |
68 |
69 |
72 |
73 | Get A Joke
74 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/jokes.js:
--------------------------------------------------------------------------------
1 | import { handleClick } from './lib/handlers.js';
2 | import { jokeButton } from './lib/elements.js';
3 |
4 | jokeButton.addEventListener('click', handleClick);
5 |
6 | console.log('heyy');
7 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/lib/elements.js:
--------------------------------------------------------------------------------
1 | export const jokeButton = document.querySelector('.getJoke');
2 | export const jokeButtonSpan = jokeButton.querySelector('.jokeText');
3 | export const jokeHolder = document.querySelector('.joke p');
4 | export const loader = document.querySelector('.loader');
5 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/lib/handlers.js:
--------------------------------------------------------------------------------
1 | import { fetchJoke } from './index.js';
2 | import { loader, jokeHolder, jokeButtonSpan } from './elements.js';
3 | import { randomItemFromArray } from './utils.js';
4 | import buttonText from '../data/buttonText.js';
5 |
6 | // Named export
7 | export async function handleClick() {
8 | const { joke } = await fetchJoke(loader);
9 | jokeHolder.textContent = joke;
10 | jokeButtonSpan.textContent = randomItemFromArray(
11 | buttonText,
12 | jokeButtonSpan.textContent
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/lib/index.js:
--------------------------------------------------------------------------------
1 | // Named Export (we can have lots of these)
2 | export async function fetchJoke(loader) {
3 | // turn loader on
4 | loader.classList.remove('hidden');
5 | const response = await fetch('https://icanhazdadjoke.com', {
6 | headers: {
7 | Accept: 'application/json',
8 | },
9 | });
10 | const data = await response.json();
11 | // turn the loader off
12 | loader.classList.add('hidden');
13 | return data;
14 | }
15 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/lib/utils.js:
--------------------------------------------------------------------------------
1 | // named export
2 | export function randomItemFromArray(arr, not) {
3 | const item = arr[Math.floor(Math.random() * arr.length)];
4 | if (item === not) {
5 | console.log('Ahh we used that one last time, look again');
6 | return randomItemFromArray(arr, not);
7 | }
8 | return item;
9 | }
10 |
--------------------------------------------------------------------------------
/exercises/81 - Dad Jokes Bundling - FINISHED/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dadjokes",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "jokes.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "scripts": {
10 | "start": "parcel index.html",
11 | "build": "parcel build index.html"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "devDependencies": {
16 | "parcel": "2.0.1"
17 | },
18 | "browserslist": [
19 | "last 1 chrome versions"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/exercises/82 - npm modules - FINISHED/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/82 - npm modules - FINISHED/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Modules
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/exercises/82 - npm modules - FINISHED/index.js:
--------------------------------------------------------------------------------
1 | import wait from 'waait';
2 | import { name } from 'faker';
3 | import { formatDistance, format } from 'date-fns';
4 | import axios from 'axios';
5 | import { intersection, isEqual } from 'lodash';
6 | import to from 'await-to-js';
7 |
8 | const fakeNames = Array.from(
9 | { length: 10 },
10 | () => `${name.firstName()} ${name.lastName()}`
11 | );
12 |
13 | async function go() {
14 | console.log('Going!');
15 | await wait(200);
16 | console.log('ending!');
17 | }
18 |
19 | const diff = formatDistance(new Date(), new Date(2020, 3, 4, 10, 32, 0), {
20 | addSuffix: true,
21 | }); //= > 'in about 1 hour'
22 | console.log(diff);
23 |
24 | const date = new Date();
25 |
26 | // January the 12th 2020
27 | const formatted = format(date, `LLLL 'the' do y`);
28 | console.log(formatted);
29 |
30 | async function getJoke() {
31 | const { data } = await axios.get('https://icanhazdadjoke.com', {
32 | headers: {
33 | Accept: 'application/json',
34 | },
35 | });
36 | console.log(data);
37 | }
38 |
39 | // getJoke();
40 |
41 | const a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
42 | const b = [5, 3, 8, 3, 7, 453, 34];
43 |
44 | const sameValues = intersection(a, b);
45 | console.log(sameValues);
46 |
47 | const person1 = { name: 'wes' };
48 | const person2 = { name: 'wes' };
49 |
50 | console.log(isEqual(person1, person2));
51 |
52 | function checkIfNameIsCool(firstName) {
53 | return new Promise(function(resolve, reject) {
54 | if (firstName === 'Wes') {
55 | resolve('Cool name');
56 | return;
57 | }
58 | reject(new Error('Bad Name'));
59 | });
60 | }
61 |
62 | async function checkName() {
63 | const [err, successValue] = await to(checkIfNameIsCool('snickers'));
64 | if (err) {
65 | // deal with it
66 | console.log(err);
67 | } else {
68 | console.log(successValue);
69 | }
70 | }
71 |
72 | checkName();
73 |
--------------------------------------------------------------------------------
/exercises/82 - npm modules - FINISHED/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "npmmodules",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "parcel index.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "parcel": "2.0.1"
13 | },
14 | "dependencies": {
15 | "await-to-js": "^2.1.1",
16 | "axios": "^0.19.0",
17 | "date-fns": "^2.8.0",
18 | "faker": "^4.1.0",
19 | "lodash": "^4.17.15",
20 | "waait": "^1.0.5"
21 | },
22 | "browserslist": [
23 | "last 1 chrome versions"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/exercises/83 - Security/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/83 - Security/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Nasty!
8 |
9 |
10 |
49 |
50 |
51 |
52 |
53 |
54 | FarceBook
55 | Send $1,000,000
56 | Send a DM
57 | Unfriend Someone
58 | Post Nasty Message
59 |
60 |
61 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/exercises/83 - Security/nasty-FINISHED.js:
--------------------------------------------------------------------------------
1 | import { sanitize } from "dompurify";
2 |
3 | const input = document.querySelector('[name="input"]');
4 | const output = document.querySelector(".output");
5 | const buttons = document.querySelectorAll("nav button");
6 | input.addEventListener("input", () => {
7 | const clean = sanitize(input.value, {
8 | FORBID_ATTR: ["width", "height", "style"],
9 | FORBID_TAGS: ["style"],
10 | });
11 | output.innerHTML = clean.replace(/\n/g, " ");
12 | });
13 |
14 | // trigger an input even on page load
15 | input.dispatchEvent(new Event("input"));
16 |
17 | buttons.forEach((button) =>
18 | button.addEventListener("click", (e) => {
19 | alert(e.currentTarget.textContent);
20 | })
21 | );
22 |
--------------------------------------------------------------------------------
/exercises/83 - Security/nasty.js:
--------------------------------------------------------------------------------
1 | import { sanitize } from 'dompurify';
2 |
3 | const input = document.querySelector('[name="input"]');
4 | const output = document.querySelector('.output');
5 | const buttons = document.querySelectorAll('nav button');
6 | input.addEventListener('input', () => {
7 | output.innerHTML = input.value.replace(/\n/g, ' ');
8 | });
9 |
10 | // trigger an input even on page load
11 | input.dispatchEvent(new Event('input'));
12 |
13 | buttons.forEach(button =>
14 | button.addEventListener('click', e => {
15 | alert(e.currentTarget.textContent);
16 | })
17 | );
18 |
--------------------------------------------------------------------------------
/exercises/83 - Security/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "security",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "parcel index.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "dompurify": "^2.0.7"
13 | },
14 | "devDependencies": {
15 | "parcel": "2.0.1"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/handlers-FINISHED.js:
--------------------------------------------------------------------------------
1 | import { isValidColor } from "./colors";
2 |
3 | function logWords(results) {
4 | // console.log(results[results.length - 1][0].transcript);
5 | }
6 |
7 | export function handleResult({ results }) {
8 | logWords(results);
9 | const words = results[results.length - 1][0].transcript;
10 | // lowercase everything
11 | let color = words.toLowerCase();
12 | // strip any spaces out
13 | color = color.replace(/\s/g, "");
14 | // check if it is a valid colour
15 | if (!isValidColor(color)) return; // thats all folks
16 | // if it is, then show the UI for that
17 | const colorSpan = document.querySelector(`.${color}`);
18 | colorSpan.classList.add("got");
19 | console.log(colorSpan);
20 | console.log("This is a valid color!");
21 | console.log(color);
22 | // change the background color
23 | document.body.style.backgroundColor = color;
24 | }
25 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/handlers.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/84 - Web Speech Colour Game/handlers.js
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Web Speech Colours
7 |
8 |
9 |
10 |
11 |
12 | Say a Color
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-speech-colours",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "colors.js",
6 | "scripts": {
7 | "start": "parcel index.html"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "browserslist": [
12 | "last 1 chrome versions"
13 | ],
14 | "devDependencies": {
15 | "parcel": "2.0.1"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/speech-FINISHED.js:
--------------------------------------------------------------------------------
1 | import { handleResult } from "./handlers";
2 | import { colorsByLength, isDark } from "./colors";
3 |
4 | const colorsEl = document.querySelector(".colors");
5 |
6 | function displayColors(colors) {
7 | return colors
8 | .map(
9 | (color) =>
10 | `${color} `
13 | )
14 | .join("");
15 | }
16 |
17 | window.SpeechRecognition =
18 | window.SpeechRecognition || window.webkitSpeechRecognition;
19 |
20 | function start() {
21 | // see if their browser supports this
22 | if (!window.SpeechRecognition) {
23 | console.log("Sorry your browser does not support speech reco. ");
24 | return;
25 | }
26 | // it does work
27 | console.log("Starting...");
28 | // make a new speech reco
29 | const recognition = new SpeechRecognition();
30 | recognition.continuous = true;
31 | recognition.interimResults = true;
32 | recognition.onresult = handleResult;
33 | recognition.start();
34 | }
35 |
36 | start();
37 | colorsEl.innerHTML = displayColors(colorsByLength);
38 |
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/speech.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/84 - Web Speech Colour Game/speech.js
--------------------------------------------------------------------------------
/exercises/84 - Web Speech Colour Game/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | transition: background-color 0.4s;
3 | font-family: sans-serif;
4 | text-align: center;
5 | }
6 |
7 | h1 {
8 | font-size: 10rem;
9 | margin: 5rem 0 0 0;
10 | transition: all 0.4s;
11 | position: relative;
12 | color: rgba(0, 0, 0, 0.4);
13 | }
14 |
15 | .colors {
16 | display: flex;
17 | flex-wrap: wrap;
18 | margin: 5rem;
19 | }
20 |
21 | .colors span {
22 | color: rgba(0, 0, 0, 0.4);
23 | flex:1;
24 | padding: 1rem;
25 | font-weight: 900;
26 | }
27 |
28 | .colors span.dark {
29 | color: rgba(255, 255, 255, 0.75);
30 | }
31 |
32 | @keyframes jump {
33 | from {
34 | transform: scale(2.5) rotate(-3deg);
35 | box-shadow: var(--box-shadow);
36 | }
37 | to {
38 | transform: scale(1) rotate(0);
39 | }
40 | }
41 |
42 | .colors span.got {
43 | text-decoration: line-through;
44 | animation: jump 0.2s ease-in-out 2 alternate-reverse;
45 | }
46 |
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/.npmrc:
--------------------------------------------------------------------------------
1 | fund=false
2 | audit=false
3 | legacy-peer-deps=true
4 |
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Audio Analyzer
9 |
10 |
11 |
12 |
13 |
14 |
15 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "oscilloscope",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "browserslist": [
7 | "last 1 chrome version"
8 | ],
9 | "scripts": {
10 | "start": "parcel index.html"
11 | },
12 | "author": "",
13 | "license": "ISC",
14 | "devDependencies": {
15 | "parcel": "2.0.1"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/sound-FINISHED.js:
--------------------------------------------------------------------------------
1 | import { hslToRgb } from "./utils";
2 |
3 | const WIDTH = 1500;
4 | const HEIGHT = 1500;
5 | const canvas = document.querySelector("canvas");
6 | const ctx = canvas.getContext("2d");
7 | canvas.width = WIDTH;
8 | canvas.height = HEIGHT;
9 | let analyzer;
10 | let bufferLength;
11 |
12 | function handleError(err) {
13 | console.log("You must give access to your mic in order to proceed");
14 | }
15 |
16 | async function getAudio() {
17 | const stream = await navigator.mediaDevices
18 | .getUserMedia({ audio: true })
19 | .catch(handleError);
20 | const audioCtx = new AudioContext();
21 | analyzer = audioCtx.createAnalyser();
22 | const source = audioCtx.createMediaStreamSource(stream);
23 | source.connect(analyzer);
24 | // How much data should we collect
25 | analyzer.fftSize = 2 ** 8;
26 | // pull the data off the audio
27 | // how many pieces of data are there?!?
28 | bufferLength = analyzer.frequencyBinCount;
29 | const timeData = new Uint8Array(bufferLength);
30 | const frequencyData = new Uint8Array(bufferLength);
31 | drawTimeData(timeData);
32 | drawFrequency(frequencyData);
33 | }
34 |
35 | function drawTimeData(timeData) {
36 | // inject the time data into our timeData array
37 | analyzer.getByteTimeDomainData(timeData);
38 | // now that we have the data, lets turn it into something visual
39 | // 1. Clear the canvas TODO
40 | ctx.clearRect(0, 0, WIDTH, HEIGHT);
41 | // 2. setup some canvas drawing
42 | ctx.lineWidth = 10;
43 | ctx.strokeStyle = "#ffc600";
44 | ctx.beginPath();
45 | const sliceWidth = WIDTH / bufferLength;
46 | let x = 0;
47 | timeData.forEach((data, i) => {
48 | const v = data / 128;
49 | const y = (v * HEIGHT) / 2;
50 | // draw our lines
51 | if (i === 0) {
52 | ctx.moveTo(x, y);
53 | } else {
54 | ctx.lineTo(x, y);
55 | }
56 | x += sliceWidth;
57 | });
58 |
59 | ctx.stroke();
60 |
61 | // call itself as soon as possible
62 | requestAnimationFrame(() => drawTimeData(timeData));
63 | }
64 |
65 | function drawFrequency(frequencyData) {
66 | // get the frequency data into our frequencyData array
67 | analyzer.getByteFrequencyData(frequencyData);
68 | // figure out the bar width
69 | const barWidth = (WIDTH / bufferLength) * 2.5;
70 | let x = 0;
71 | frequencyData.forEach((amount) => {
72 | // 0 to 255
73 | const percent = amount / 255;
74 | const [h, s, l] = [360 / (percent * 360) - 0.5, 0.8, 0.5];
75 | const barHeight = HEIGHT * percent * 0.5;
76 | // TODO: Convert the colour to HSL TODO
77 | const [r, g, b] = hslToRgb(h, s, l);
78 | ctx.fillStyle = `rgb(${r},${g},${b})`;
79 | ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
80 | x += barWidth + 2;
81 | });
82 |
83 | requestAnimationFrame(() => drawFrequency(frequencyData));
84 | }
85 |
86 | getAudio();
87 |
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/sound.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/exercises/85 - Audio Visualizer Oscilloscope/sound.js
--------------------------------------------------------------------------------
/exercises/85 - Audio Visualizer Oscilloscope/utils.js:
--------------------------------------------------------------------------------
1 | export function hslToRgb(h, s, l) {
2 | let r;
3 | let g;
4 | let b;
5 |
6 | if (s == 0) {
7 | r = g = b = l; // achromatic
8 | } else {
9 | const hue2rgb = function hue2rgb(p, q, t) {
10 | if (t < 0) t += 1;
11 | if (t > 1) t -= 1;
12 | if (t < 1 / 6) return p + (q - p) * 6 * t;
13 | if (t < 1 / 2) return q;
14 | if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
15 | return p;
16 | };
17 |
18 | const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
19 | const p = 2 * l - q;
20 | r = hue2rgb(p, q, h + 1 / 3);
21 | g = hue2rgb(p, q, h);
22 | b = hue2rgb(p, q, h - 1 / 3);
23 | }
24 |
25 | return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
26 | }
27 |
--------------------------------------------------------------------------------
/function-definition.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/function-definition.jpg
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beginner-javascript",
3 | "version": "1.0.0",
4 | "description": "Starter Files and Solutions for the BeginnerJavaScript.com Course",
5 | "main": "index.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git+https://github.com/wesbos/beginner-javascript.git"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "bugs": {
13 | "url": "https://github.com/wesbos/beginner-javascript/issues"
14 | },
15 | "homepage": "https://github.com/wesbos/beginner-javascript#readme"
16 | }
17 |
--------------------------------------------------------------------------------
/playground/apis-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | APIs
8 |
9 |
10 |
11 |
12 |
13 |
14 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/playground/apis.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | APIs
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/arrays-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/playground/arrays.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/async-await-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Async Await
8 |
9 |
10 |
11 |
12 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/playground/async-await-error-handling-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Async Await
8 |
9 |
10 |
11 |
12 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/playground/async-await-error-handling.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Async Await
8 |
9 |
10 |
11 |
12 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/playground/async-await.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Async Await
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/bedmas-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | BEDMAS
8 |
9 |
10 |
11 |
12 | B rackets
13 | E xponents
14 | D ivision
15 | M ultiplication
16 | A ddition
17 | S ubtraction
18 |
19 |
28 |
29 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/playground/bedmas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | BEDMAS
8 |
9 |
10 |
11 |
12 | B rackets
13 | E xponents
14 | D ivision
15 | M ultiplication
16 | A ddition
17 | S ubtraction
18 |
19 |
28 |
29 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/playground/bind-call-apply-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Bind Call and Apply!
8 |
9 |
10 |
11 |
12 | Hey
13 | Click me
14 |
15 |
Hey im in a wrapper
16 |
17 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/playground/bind-call-apply.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Bind Call and Apply!
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/classes-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Classes
8 |
9 |
10 |
11 |
12 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/playground/classes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Classes
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/closures-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/playground/closures.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/custom-functions/cf-FINISHED.js:
--------------------------------------------------------------------------------
1 | // Function Definition
2 | function calculateBill(billAmount, taxRate = 0.13, tipRate = 0.15) {
3 | // this is the function body
4 | console.log('Running Calculate Bill!!');
5 | const total = billAmount + billAmount * taxRate + billAmount * tipRate;
6 | return total;
7 | }
8 |
9 | // Function Call. Or **Run**
10 | const wesTotal = 500;
11 | const wesTaxRate = 0.3;
12 | // const myTotal = calculateBill(wesTotal, wesTaxRate);
13 |
14 | // Function Definition
15 | function sayHiTo(firstName) {
16 | return `Hello ${firstName}`;
17 | }
18 |
19 | // const greeting = sayHiTo('Wes');
20 | // console.log(greeting);
21 |
22 | function doctorize(name) {
23 | return `Dr. ${name}`;
24 | }
25 |
26 | function yell(name = 'Silly Goose') {
27 | return `HEY ${name.toUpperCase()}`;
28 | }
29 |
30 | const myBill4 = calculateBill(100, undefined, 0.2);
31 | console.log(myBill4);
32 |
--------------------------------------------------------------------------------
/playground/custom-functions/cf.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/playground/custom-functions/cf.js
--------------------------------------------------------------------------------
/playground/custom-functions/index-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Click Me!
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/playground/custom-functions/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/custom-functions/ways-to-make-a-function-FINISHED.js:
--------------------------------------------------------------------------------
1 | // function doctorize(firstName) {
2 | // return `Dr. ${firstName}`;
3 | // }
4 |
5 | // Anon Function
6 | // function (firstName) {
7 | // return `Dr. ${firstName}`;
8 | // }
9 |
10 | // Function Expression
11 | // const doctorize = function(firstName) {
12 | // return `Dr. ${firstName}`;
13 | // };
14 |
15 | /* eslint-disable */
16 | const inchToCM = inches => inches * 2.54;
17 |
18 | // function add(a, b = 3) {
19 | // const total = a + b;
20 | // return total;
21 | // }
22 |
23 | // const add = (a, b = 3) => a + b;
24 |
25 | // returning an object
26 |
27 | // function makeABaby(first, last) {
28 | // const baby = {
29 | // name: `${first} ${last}`,
30 | // age: 0
31 | // }
32 | // return baby;
33 | // }
34 |
35 | const makeABaby = (first, last) => ({ name: `${first} ${last}`, age: 0 });
36 |
37 |
38 | // IIFE
39 | // Immediately Invoked Function Expression
40 |
41 | (function(age) {
42 | return `You are cool and age ${age}`;
43 | })(10);
44 |
45 | // Methods!!!
46 | const wes = {
47 | name: 'Westopher Bos',
48 | // Method!
49 | sayHi: function() {
50 | console.log(`Hey ${this.name}`);
51 | return 'Hey Wes';
52 | },
53 | // Short hand Method
54 | yellHi() {
55 | console.log('HEY WESSSSS');
56 | },
57 | // Arrow function
58 | wisperHi: () => {
59 | console.log('hii wesss im a mouse');
60 | }
61 | }
62 |
63 | // Callback Functions
64 | // Click Callback
65 | const button = document.querySelector('.clickMe');
66 |
67 | function handleClick() {
68 | console.log('Great Clicking!!');
69 | }
70 |
71 | button.addEventListener('click', function() {
72 | console.log('NIce Job!!!');
73 | });
74 |
75 | // Timer Callback
76 | setTimeout(() => {
77 | console.log('DONE! Time to eat!');
78 | }, 1000);
79 |
--------------------------------------------------------------------------------
/playground/custom-functions/ways-to-make-a-function.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wesbos/beginner-javascript/9b7e0da744ed19cd3f81bb453d96964ccd7b5e89/playground/custom-functions/ways-to-make-a-function.js
--------------------------------------------------------------------------------
/playground/event-loop-FINISHED.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Event Loop
8 |
9 |
10 |
11 |
12 |
39 | Click Me
40 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/playground/event-loop.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Event Loop
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/functions.html:
--------------------------------------------------------------------------------
1 |