diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..1c1b99549 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "extends": ["airbnb-base", "prettier"], + "plugins": ["prettier"], + "env": { + "browser": true, + "jest": true + }, + "globals": { + "page": true, + "browser": true, + "context": true, + "jestPuppeteer": true, + "axios": "readonly" + }, + "rules": { + "prettier/prettier": ["error"], + "class-methods-use-this": "off", + "strict": "off", + "no-plusplus": "off", + "linebreak-style": "off", + "no-restricted-syntax": "off", + "no-param-reassign": [ + "error", + { + "props": false + } + ] + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..416795af1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +## For further details please lookup: +## https://help.github.com/articles/dealing-with-line-endings/#platform-all diff --git a/.gitignore b/.gitignore index 6c589c2f8..171af4338 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,4 @@ typings/ .netlify dist/ +iPhoneX.png diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..5e1bae462 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - '10' + +script: + - npm run lint diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..469f36b11 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + "recommendations": [ + "CoenraadS.bracket-pair-colorizer", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "ritwickdey.LiveServer", + "streetsidesoftware.code-spell-checker", + "techer.open-in-browser" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index f7a55df12..183110862 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,13 @@ "editor.detectIndentation": false, "editor.tabSize": 2, "cSpell.words": [ - "tabindex" - ] -} \ No newline at end of file + "READYSTATE", + "Traversy", + "ajaxcrash", + "networkidle", + "remarcmij", + "tabindex", + "whiteframe" + ], + "deno.enable": false +} diff --git a/README.md b/README.md index fa97dad57..55310b364 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,131 @@ -> Please help us improve and share your feedback! If you find better tutorials -or links, please share them by [opening a pull request](https://github.com/HackYourFuture/JavaScript3/pulls). +# DEPRECATED - JavaScript 3 +This module has been replace with the Using API's module, find it [here](https://github.com/HackYourFuture/UsingAPIs) -# HackYourFuture JavaScript 3 +```Welcome to JavaScript3! Congratulations on making it this far. You're well on your way to the top! -Here you can find course content and homework for the JavaScript3 modules +A big part of being a programmer means moving data from one place to another. It also means working with other people's software. In this module you'll be learning about one of the core things of what makes a web developer: working with APIs! -|Week|Topic|Read|Homework| -|----|-----|----|--------| -|1.|• Structure for a basic SPA (Single Page Application)
• [XMLHttpRequests](../../../fundamentals/blob/master/fundamentals/XMLHttpRequest.md)
• API calls|[Reading Week 1](/Week1/README.md)|[Homework Week 1](/Week1/MAKEME.md)| -|2.|• [Event Loop (order of execution)](../../../fundamentals/blob/master/fundamentals/event_loop.md)
• [Promises](../../../fundamentals/blob/master/fundamentals/promises.md)|[Reading Week 2](/Week2/README.md)|[Homework Week 2](/Week2/MAKEME.md)| -|3.|• [try...catch](../../../fundamentals/blob/master/fundamentals/try_catch.md)
• [async/await](../../../fundamentals/blob/master/fundamentals/async_await.md)
• [The `this` keyword](../../../fundamentals/blob/master/fundamentals/this.md)
• call, apply, bind
• [Object Oriented Programming and ES6 Classes](../../../fundamentals/blob/master/fundamentals/oop_classes.md)|[Reading Week 3](/Week3/README.md)|[Homework Week 3](/Week3/MAKEME.md)| +On top of that you'll also learn how to think differently about _how_ you write your programs. Like in any field, once you've mastered a particular way of doing things you start thinking about how it could be done in a smarter, different way. In programming we call these `paradigms` and in this module you'll learn one such paradigm: Object-Oriented Programming! -__Kind note:__ +## Before you start -We expect you to __always__ come prepared to the class on Sunday. +In the following weeks we will be using a "style guide" to help you write _"clean code"_. Because code is not only meant to be run by computers, but also to be read by humans (your colleagues, and the future version of you), it's best to make your code good. If your code is readable and nicely formatted, you're doing your colleages (and future you) a great service. The idea of a "style guide" comes from visual design, where companies often have a "visual style". For example, watch the following video to get an idea of this: -### Overall -A good understanding of all the above mentioned topics. Want to check your Knowledge? Go through the [JavaScript Fundamentals README](../../../fundamentals/blob/master/README.md) and research/ ask for help (Slack!) with the concepts that are not entirely clear. +### Setup Style Guide -*The HackYourFuture curriculum is subject to CC BY copyright. This means you can freely use our materials, but just make sure to give us credit for it :)* +Similar to how designers have style guides for their design work, programmers often have "programming style guides". This is set of rules to follow when writing/formatting your code. The styleguide we'll be using is the one from Airbnb: -Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License. +- [Front-end Style Guides](https://fronteers.nl/congres/2015/sessions/front-end-style-guides-anna-debenham) + +The style guide we'll be using is the one from Airbnb: + +- [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) + +While you do not need to read this guide in detail, it is recommended that you look at sections 1-8, 12-13, 15-21 and 23. + +We also have tools that can automatically check whether your code is correctly formatted according to a style guide. These tools are called "linters". We will be using the JavaScript linter called "ESLint". The following packages are already added to this repository's `package.json`: + +The required packages you need to install before you write code according to the style guide are the following: + +`json +"eslint" +"eslint-config-airbnb-base" +"eslint-config-prettier" +"eslint-plugin-import" +"eslint-plugin-prettier" +"prettier" +` + +They are already in this repository's `package.json` so all you have to do now to prepare is to execute the following command at the root of this module directory: + +`md +npm install +` + +### Forking the right repository + +Before you start with the homework, make sure you've made a fork of the right repository: [HackYourHomework/JavaScript3](https://www.github.com/hackyourhomework/javascript3)). Once you've cloned it to your computer you can proceed by making GIT branches for each week. Start at the `master` branch and execute the following (note that they're 3 different commands): + +`bash +foo@bar:~$ git branch week1-YOURNAME +foo@bar:~$ git branch week2-YOURNAME +foo@bar:~$ git branch week3-YOURNAME +` + +Then execute `git checkout week1-YOURNAME` and you can get started! + +If you have any questions or if something is not entirely clear ¯\_(ツ)\_/¯, please ask/comment on Slack! + +## Learning goals + +In order to successfully complete this module you will need to master the following: + +- Learn what an `Application Programming Interface` (API) is +- Catch up on the `history of JavaScript` +- Understand how to write more readable `asynchronous JavaScript` +- Connect with different `public APIs` +- Build a `Single Page Application` (SPA) +- Work with pre-existing code +- Learn about `Object-Oriented Programming` + +## How to use this repository + +### Repository content + +This repository consists of 3 essential parts: + +1. `README`: this document contains all the required theory you need to understand **while** working on the homework. It contains not only the right resources to learn about the concepts, but also lectures done by HackYourFuture teachers. This is the **first thing** you should start with every week +2. `MAKEME`: this document contains the instructions for each week's homework. Start with the exercises rather quickly, so that you can ground the concepts you read about earlier. +3. `LESSONPLAN`: this document is meant for teachers as a reference. However, as a student don't be shy to take a look at it as well! + +### How to study + +Let's say you are just starting out with the JavaScript3 module. This is what you do... + +1. The week always starts on **Wednesday**. First thing you'll do is open the `README.md` for that week. For the first week of `JavaScript3`, that would be [Week1 Reading](/Week1/README.md) +2. You spend **Wednesday** and **Thursday** going over the resources and try to get a basic understanding of the concepts. In the meanwhile, you'll also implement any feedback you got on last week's homework (from the JavaScript2 module) +3. On **Friday** you start with the homework, found in the `MAKEME.md`. For the first week of `JavaScript3`, that would be [Week1 Homework](/Week1/MAKEME.md) +4. You spend **Friday** and **Saturday** playing around with the exercises and write down any questions you might have +5. **DEADLINE 1**: You'll submit any questions you might have before **Saturday 23.59**, in the class channel +6. On **Sunday** you'll attend class. It'll be of the Q&A format, meaning that there will be no new material. Instead your questions shall be discussed and you can learn from others +7. You spend **Monday** and **Tuesday** finalizing your homework +8. **DEADLINE 2**: You submit your homework to the right channels (GitHub) before **Tuesday 23.59**. If you can't make it on time, please communicate it with your mentor +9. Start the new week by going back to point 1! + +In summary: + +![Weekflow](assets/weekflow.png) + +To have a more detailed overview of the guidelines, please read [this document](https://docs.google.com/document/d/1JUaEbxMQTyljAPFsWIbbLwwvvIXZ0VCHmCCN8RaeVIc/edit?usp=sharing) or ask your mentor/class on Slack! + +### Video lectures + +For each module HackYourFuture provides you with video lectures. These are made by experienced software developers who know what they're talking about. The main teacher for this module will be [Stasel Seldin](https://hackyourfuture.slack.com/team/UQJGC1MSL): senior iOS developer! + +You can find out more about him here: + +- [GitHub](https://github.com/Stasel) +- [@Stasel on Slack](https://hackyourfuture.slack.com/team/UQJGC1MSL) + +Learn from Stasel in the following playlist of videos he has made for you! (Click on the image to open the link) + +HYF Video + +## Planning + +| Week | Topic | Reading Materials | Homework | Lesson Plan | +| ---- | ------------------------------------------------------------------------------------------- | ------------------------------ | ------------------------------- | -------------------------------------- | +| 1. | Application Programming Interface (API), AJAX, Modules & Libraries | [Reading W1](/Week1/README.md) | [Homework W1](/Week1/MAKEME.md) | [Lesson Plan W1](/Week1/LESSONPLAN.md) | +| 2. | Promises, Fetch API, JavaScript Versions, 'this' keyword, Arrow functions | [Reading W2](/Week2/README.md) | [Homework W2](/Week2/MAKEME.md) | [Lesson Plan W1](/Week2/LESSONPLAN.md) | +| 3. | Object-Oriented Programming (OOP), ES6 Classes, Async/await, Thinking like a programmer III | [Reading W3](/Week3/README.md) | [Homework W3](/Week3/MAKEME.md) | [Lesson Plan W1](/Week3/LESSONPLAN.md) | +| 4. | Final JavaScript Test | [Details](test.md) | - | - | + +## Finished? + +Did you finish the module? High five! + +If you feel ready for the next challenge, click [here](https://www.github.com/HackYourFuture/Node.js) to go to Node.js! + +_The HackYourFuture curriculum is subject to CC BY copyright. This means you can freely use our materials, but just make sure to give us credit for it :)_ + +Creative Commons License
This work is licensed under a Creative Commons Attribution 4.0 International License.``` diff --git a/Week1/LESSONPLAN.md b/Week1/LESSONPLAN.md new file mode 100644 index 000000000..a0d1c8f0e --- /dev/null +++ b/Week1/LESSONPLAN.md @@ -0,0 +1,141 @@ +# Lesson Plan JavaScript3 Week 1 + +## Agenda + +The purpose of this class is to introduce to the student: + +- What are `APIs` and how to interact with them +- What is `AJAX` and how to apply it (`XMLHttpRequest`) +- How to use libraries (`axios`) + +## Core concepts + +FIRST HALF (12.00 - 13.30) + +## 1. What are APIs and how to interact with them + +### Explanation +- APIs are created by providers and used by consumers (BE provider, FE consumer) +- Part of an application that can be communicated with from an outside source +- Connect to it using "endpoints" +- Software well-known APIs (Fb APIs, Twitter APIs, Maps APIs, weather APIs); +- API doesn't care which language or technology is used in the consumer or the provider + +#### Types of APIs: +- Private: for employees only under a company network for internal use. +- Semi-private: for clients who paid for the API. +- Public: for everyone on the web. + +#### Architecture styles of API: +- Single purpose: API that gives a direct and specific service. +- Aggregated API: one API as a wrapper for multiple APIs. +- Web services API: punch of APIs working together to forma whole app. + +#### Basic structure of REST API + +- Endpoint: https://api.example.com +- Endpoint with version: https://api.example.com/v1 +- Resources: +* https://api.example.com/v1/users +* https://api.example.com/v1/users/create +* https://api.example.com/v1/users/1 +* https://api.example.com/v1/users/1/edit +- Query params: +* https://api.example.com/v1/users?limit=10 +### Example +- Give real life example like (Devices like TV, any machine + electricity power socket interface which provides power to any external device) + +### Excercise + +### Essence +- Mostly used to request data from some service +- Communication between software and user needs UI interface but software and software needs API as an interface. + +## 2. What is `AJAX` and how to apply it (`XMLHttpRequest`) + +### Explanation +- Before AJAX all page reload for all requests, via refreshing the url in the address bar with the new resource. +- It's a technique, not a technology +- `AJAX` stands for Asynchronous JavaScript and XML +- Nowadays we use `JSON` instead of `XML` +- Fetch data without reloading the page +- The XMLHttpRequest API is defined in the browser (window.XMLHttpRequest) +### Example +Example using the XMLHttpRequest + +```javascript +const oReq = new XMLHttpRequest(); +oReq.open('GET', `https://api.openweathermap.org/data/2.5/weather?q=${cityName}`); +oReq.send(); +oReq.addEventListener('load', function (event) { + const data = JSON.parse(this.response); + if (data.cod >= 400) { + // error + console.log(data.message); + } else { + //success + console.log(data.coord.lat); + } +}); + +// or another way of getting data +oReq.load = function (event) { + // use oReq.response or this.response + const data = JSON.parse(this.response); + if (data.cod >= 400) { + // error + console.log(data.message); + } else { + //success + console.log(data.coord.lat); + } +}; + +``` + +### Excercise + +Steps of doing the following example:- +** Install the live server plugin in VS (go to plugins -> live server -> install) +1. Create self-invoked function to wrap your code +2. Create an object instance of `XMLHttpRequest` +3. Call the `open` function to fill it with the Request URL and the request Method +4. Call the `send` function to make the request +5. Add event listener with a callback for the sucess event `load` + +### Essence + +SECOND HALF (14.00 - 16.00) + +## 3. How to use libraries (`axios`) + +### Explanation +- A library is a code solution a developer (or a team) has written to a common problem +- Usually open-source +- Helps to solve a problem within an application +- Read the documentation on how to use it +### Example +Same example but using axios +```javascript +axios + .get(`https://api.openweathermap.org/data/2.5/weather?q=${cityName}`) + .then(function (response) { + // handle success + console.log(response.data); + }).catch(function (error) { + // handle error + console.log(error); + }).finally(function () { + // always be executed + console.log('I am always here') + }); +``` + +> Note: Give example at the end with binding/showing these data in a DOM element like a
or a list instead of only showing them on the console using console.log. + +### Excercise +### Essence + + + + diff --git a/Week1/MAKEME.md b/Week1/MAKEME.md index 76498c97d..6f040f6bc 100644 --- a/Week1/MAKEME.md +++ b/Week1/MAKEME.md @@ -1,229 +1,134 @@ -# Homework Week 1 +# Homework JavaScript3 Week 1 -``` -Topics discussed this week: -• Structure for a basic SPA -• XMLHttpRequests -• API calls -``` - ->[Here](/Week3/README.md) you find the readings you have to complete before the ninth lecture. - -## Step 1: Feedback - -**_Deadline Monday_** - -Please provide feedback on last week's homework from a fellow student as a GitHub issue. - -## Step 2: Single Page Application :sweat_drops: - -**_Deadline Thursday_** - -_This homework is more extensive and challenging than previous homework! Please read the instructions below carefully and follow them with great attention to detail. Start this homework as soon as you can and allow time for discussion and questions (slack!)._ - -### 2.1 Introduction - -You are going to write a _Single Page Application_ (SPA) that uses the [GitHub API](https://developer.github.com/guides/getting-started/). - -This application should display information about the available [HYF GitHub repositories](https://github.com/hackyourfuture). The functionalities we would like to see in your application are as follows: +## **Todo list** -- The user should be able to select a repository from a list of available repositories. -- The application should display high-level information about the selected repository and show a list of its contributors. -- When clicking on the name of the selected repository the GitHub page for the corresponding repository should be opened in a new browser tab. -- When clicking on a contributor, the GitHub page for the contributor should be opened in a new browser tab. - -Figure 1 below shows an example of what your application could look like. Note that this is just an example. If you find it boring or unimaginative, please improve on it! On the other hand, a simpler version is OK too, so long as you implement the expected functionality. - -![UI Example](./assets/hyf-github.png) - -In this assignment you will built upon some existing code that is already pre-written by your teachers. Your homework consist of writing the code to make the application work as requested per week. - -Figure 1. Example User Interface using [Material Design](https://material.io/guidelines/) principles. - -A live version of this application can be found here: http://hyf-github.netlify.com/ - -### 2.2 The GitHub API - -#### 2.2.1 Get a list of HYF repositories - -You can fetch a list of HYF repositories through this API endpoint ([What is an API Endpoint?](https://teamtreehouse.com/community/what-is-an-api-endpoint)): - -``` -https://api.github.com/orgs/HackYourFuture/repos?per_page=100 -``` +1. Practice the concepts +2. JavaScript exercises +3. Code along +4. PROJECT: Hack Your Repo I -If you open this URL in the browser (_try it!_) you will receive JSON data about the available HYF repositories. This is the data that you will need to work with in this assignment. +## **1. Practice the concepts** -Note the query string `?per_page=100` in the above URL. If you don't specify this query string you will only get the first 30 repositories (the default `per_page` is 30). HackYourFuture has more than 30 repositories but less than 100. +This week's concepts can be challenging, therefore let's get an easy introduction using some interactive exercises! Check the following resources out and start practicing: -The returned JSON data contains some basic information about each repository, such as `name`, `full_name`, `description` etc. There are also many properties that contain URLs that can be used to obtain detail information about certain aspects of the repository. +- [Learn JavaScript: Requests](https://www.codecademy.com/learn/introduction-to-javascript/modules/intermediate-javascript-requests) -#### 2.2.2 Get contributor information for a repository +## **2. JavaScript exercises** -The JSON data that is returned from the initial request to get repository information includes a property named `contributors_url`. Use the value of this property to fetch a list of contributors. +> Inside of your `JavaScript3` fork and inside of the `Week1` folder, create a folder called `homework`. Inside of that folder, create a folder called `js-exercises`. For all the following exercises create a new `.js` file in that folder (3 files in total). Make sure the name of each file reflects its content: for example, the filename for exercise one could be `getRandomUser.js`. -#### 2.2.3 GitHub API documentation +**Exercise 1: Who do we have here?** -You can find detailed information about the GitHub API by means of the link listed below. However, the documentation is very extensive and not easy to digest. For this homework it is not necessary to study the GitHub API documentation. We provide the link here for completeness. +Wouldn't it cool to make a new friend with just the click of a button? -> GitHub API documentation: https://developer.github.com/v3/ +Write a function that makes a HTTP Request to `https://www.randomuser.me/api` -### 2.3 Preparation +- Inside the JavaScript file write two functions: one with `XMLHttpRequest`, and the other with `axios` +- Each function should make a HTTP Request to the given endpoint: `https://www.randomuser.me/api` +- Log the received data to the console +- Incorporate error handling: log to the console the error message -You will be working on this same application during the next three weeks. For each week you will need to create a new Git branch, as listed in the Table 1 below. +**Exercise 2: Programmer humor** -| Week | Branch | Assignment | -|:----:|--------|------------| -| 1 | `week1` | Create a basic application using callbacks to handle network requests. | -| 2 | `week2` | - Refactor the callbacks to promises.
- Make the UI responsive.| -| 3 | `week3` | - Refactor the application to use ES6 Classes and async/await.
- Make the app ARIA-compliant. | +Who knew programmers could be funny? -Table 1. Homework schedule +Write a function that makes a HTTP Request to `https://xkcd.now.sh/?comic=latest` -**Instructions** +- Inside the same file write two programs: one with `XMLHttpRequest`, and the other with `axios` +- Each function should make a HTTP Request to the given endpoint: `https://xkcd.now.sh/?comic=latest` +- Log the received data to the console +- Render the `img` property into an `` tag in the DOM +- Incorporate error handling: log to the console the error message -1. Fork the JavaScript3 repository (_this repository_) to your own GitHub account. -2. Clone the fork to your laptop. -3. Open the `homework` folder inside the cloned repository in VSCode. -4. Create a new branch for the week 1 homework with the following command: +**Exercise 3: Dog photo gallery** - ``` - git checkout -b week1 - ``` +Let's make a randomized dog photo gallery! -### 2.4 Code Overview +Write a function that makes a HTTP Request to `https://dog.ceo/api/breeds/image/random`. It should trigger after clicking a button in your webpage. Every time the button is clicked it should append a new dog image to the DOM. -The files that make up the application are located in the `src` folder. It contains the following files: +- Create an `index.html` file that will display your random image +- Add 2 ` + +

+

User

+
+

Users

+
+ + + + diff --git a/Week1/traversy_ajax_crash/ajax2.js b/Week1/traversy_ajax_crash/ajax2.js new file mode 100644 index 000000000..58225f09c --- /dev/null +++ b/Week1/traversy_ajax_crash/ajax2.js @@ -0,0 +1,56 @@ +'use strict'; + +{ + function loadUser() { + const xhr = new XMLHttpRequest(); + xhr.open('GET', 'user.json', true); + + xhr.onload = () => { + if (xhr.status === 200) { + const user = JSON.parse(xhr.responseText); + + let output = ''; + + output += + ``; + + document.getElementById('user').innerHTML = output; + } + }; + + xhr.send(); + } + + function loadUsers() { + const xhr = new XMLHttpRequest(); + xhr.open('GET', 'users.json', true); + + xhr.onload = () => { + if (xhr.status === 200) { + const users = JSON.parse(xhr.responseText); + + let output = ''; + + for (const user of users) { + output += + ``; + } + + document.getElementById('users').innerHTML = output; + } + }; + + xhr.send(); + } + + document.getElementById('button1').addEventListener('click', loadUser); + document.getElementById('button2').addEventListener('click', loadUsers); +} diff --git a/Week1/traversy_ajax_crash/ajax3.html b/Week1/traversy_ajax_crash/ajax3.html new file mode 100644 index 000000000..8ccbdbbaa --- /dev/null +++ b/Week1/traversy_ajax_crash/ajax3.html @@ -0,0 +1,29 @@ + + + + + + + Codestin Search App + + + + +

+

Github Users

+
+ + + + diff --git a/Week1/traversy_ajax_crash/ajax3.js b/Week1/traversy_ajax_crash/ajax3.js new file mode 100644 index 000000000..3cbe12dbf --- /dev/null +++ b/Week1/traversy_ajax_crash/ajax3.js @@ -0,0 +1,32 @@ +'use strict'; + +{ + // Load Github Users + function loadUsers() { + const xhr = new XMLHttpRequest(); + xhr.open('GET', 'https://api.github.com/users', true); + + xhr.onload = () => { + if (xhr.status === 200) { + const users = JSON.parse(xhr.responseText); + + let output = ''; + for (const user of users) { + output += + `
` + + `` + + `
`; + } + + document.getElementById('users').innerHTML = output; + } + }; + + xhr.send(); + } + + document.getElementById('button').addEventListener('click', loadUsers); +} diff --git a/Week1/traversy_ajax_crash/sample.txt b/Week1/traversy_ajax_crash/sample.txt new file mode 100644 index 000000000..9e1cc3268 --- /dev/null +++ b/Week1/traversy_ajax_crash/sample.txt @@ -0,0 +1 @@ +Lorem ipsum dolor sit amet consectetur adipisicing elit. Inventore beatae vitae nulla itaque, assumenda optio libero maxime perferendis fugit, vel et ad tenetur fuga temporibus. Adipisci laboriosam veritatis eaque atque reiciendis. Modi expedita neque libero fugit adipisci molestiae? Porro harum consequuntur excepturi minima corporis culpa quisquam non at quia quaerat? \ No newline at end of file diff --git a/Week1/traversy_ajax_crash/user.json b/Week1/traversy_ajax_crash/user.json new file mode 100644 index 000000000..539f902a2 --- /dev/null +++ b/Week1/traversy_ajax_crash/user.json @@ -0,0 +1,5 @@ +{ + "id":1, + "name":"Rick", + "email":"rick@gmail.com" +} \ No newline at end of file diff --git a/Week1/traversy_ajax_crash/users.json b/Week1/traversy_ajax_crash/users.json new file mode 100644 index 000000000..857664f2d --- /dev/null +++ b/Week1/traversy_ajax_crash/users.json @@ -0,0 +1,17 @@ +[ + { + "id":1, + "name":"Rick", + "email":"rick@gmail.com" + }, + { + "id":2, + "name":"Glenn", + "email":"glenn@gmail.com" + }, + { + "id":3, + "name":"Negan", + "email":"negan@gmail.com" + } +] diff --git a/Week2/LESSONPLAN.md b/Week2/LESSONPLAN.md new file mode 100644 index 000000000..59587c5f4 --- /dev/null +++ b/Week2/LESSONPLAN.md @@ -0,0 +1,462 @@ +# Lesson Plan JavaScript3 Week 2 + +## Agenda + +The purpose of this class is to introduce to the student: + +- How to use the `fetch` API to do AJAX calls +- The structure and use of `Promises` +- The `this` keyword and its relationship with `scope` + +## Core concepts + +FIRST HALF (12.00 - 13.30) + +## 1. Promises + +### Explanation +- JS versions https://www.w3schools.com/js/js_versions.asp + - the javascript language evolves, new things are added and some thing become obsolete +- It's a way to introduce asynchronicity to your application +- Makes asynchronous code read like it's synchronous + + +In the examples `setTimeout` is used to illustrate asynchronous code. In the real world there will be some code doing useful work here, for example `fetch`. + +**Callback** +```javascript +let didFinishHomework = true; +let doHomeWork = function (cb) { + setTimeout(function () { + if ( didFinishHomework ) + cb(null); // call callback function with NO error and no data + else + cb(new Error('homework not done, too lazy')); // call callback function with error + }, 1000); +} + + +doHomeWork(function (err) { + if ( err ) + console.warn(err.message); + else + console.log('home work is done now'); +}) +``` + +**Promise** +```javascript +let didFinishHomework = true; +let promiseToDoHomeWork = new Promise(function (resolve, reject) { + setTimeout(function () { + if ( didFinishHomework ) + resolve(); // goto then + else + reject(new Error('homework not done, too lazy')); // goto catch and pass the error + }, 1000); +}); + +promiseToDoHomeWork + .then(function () { console.log('home work is done now'); }) + .catch(function (err) { console.warn(err); }) + +``` + +**!!! Students should watch this video !!!** +- https://youtu.be/RvYYCGs45L4 + + +### Example + +#### Nested callback/promises example + +```javascript +let attendClass = function (cb) { + setTimeout(function () { + if ( true ) + cb(null, 'I attend the class'); // call the callback function with no Error and some data + else + cb(new Error('class not attended, stayed home')); // call the callback function with an Error + }, 1000); +} + +let didFinishHomework = true; +let doTheHomeWork = function (message, cb) { + setTimeout(function () { + if ( didFinishHomework ) + cb(null, message + ' then I did the homework'); // call the callback function with no Error and some data + else + cb(new Error('homework not done, was lazy')); // call the callback function with an Error + }, 1000); +} + +let submitHomeWork = function (message, cb) { + setTimeout(function () { + if ( true ) + cb(null, message + ' so I submit my homework'); // call the callback function with no Error and some data + else + cb(new Error('homework not submited, github is down')); // call the callback function with an Error + }, 1000); +} + +// call attendClass, after it is finished call doTheHomeWork then submitHomeWork. In each step pass the output of the previous step. In case of an error show it in the console + +attendClass(function (err, data) { + if ( err ) + console.warn(err.message); + else + doTheHomeWork(data, function (err1, data1) { + if ( err1 ) + console.warn(err1.message); + else + submitHomeWork(data1, function (err2, data2) { + if ( err2 ) + console.warn(err2.message); + else + console.log(data2) + }); + }) +}) +``` +Mention how this nested structure is hard to understand and read. Multiple variables with similar names and error handling is all over the place. +Simulate an error in doTheHomeWork by setting `didFinishHomework = false` and run the example again + +```javascript + +let attendClass = function () { + return new Promise(function (resolve, reject) { + setTimeout(function () { + if ( true ) + resolve('I attend the class'); // goto then and pass the data + else + reject(new Error('class not attended, stayed home')); // goto catch and pass the error + }, 1000); + }); +} + +let didFinishHomework = true; +let doTheHomeWork = function (message) { + return new Promise(function (resolve, reject) { + setTimeout(function () { + if ( true ) + resolve(message + ' then I did the homework'); // goto then and pass the data + else + reject(new Error('homework not done, was lazy')); // goto catch and pass the error + }, 1000); + }); +} + +let submitHomeWork = function (message) { + return new Promise(function (resolve, reject) { + setTimeout(function () { + if ( true ) + resolve(message + ' so I submit my homework'); // goto then and pass the data + else + reject(new Error('homework not submited, github is down')); // goto catch and pass the error + }, 1000);; + }); +} + +attendClass() + .then(function (result) { + return doTheHomeWork(result); + }) + .then(function (result) { + return submitHomeWork(result); + }) + .then(function (result) { + console.log(result); + }) + .catch(function (error) { // catches all errors + console.warn(error.message); + }); + + +``` +Simulate an error in doTheHomeWork by setting `didFinishHomework = false` and run the example again. + +- Promise.all + +Imagine that you are cleaning your house. If you are going to to it alone then it will take you the whole day. However if you ask your friend to help then you can be done in half the time. + +```javascript +Promise.all([cleanKitchen("Me"), cleanBathroom("friend")]).then(function ([res1, res2]) { console.log('all finished') }); +``` + +- Promise.race + +Sometimes I get really hungry. Then I want to eat as soon as possible. So I order a pizza. But I never know how long it will take for the pizza to arrive. And I am really hungry. So I start frying some potatotes. When at one of them is ready either the pizza has arrived or the frites are done then I will eat and I do not have to wait for the other one. + +```javascript +Promise.race([fryPotatoes(), orderPizza()]).then(function (food) { console.log('I am eating: '+food) }); +``` + +### Exercise + +#### Easy exercise (see difficult exercise alternative below) + +**Part 1** +Rewrite the following code to use promise instead of callbacks. *As preparation for `fetch`* + +```javascript +{ +const WEATHER_URL = `https://api.openweathermap.org/data/2.5/weather?q=amsterdam&appid=316f8218c0899311cc029a305f39575e`; + +function fetchResourceAsCallback(url, cb) { + const oReq = new XMLHttpRequest(); + oReq.open('GET', url); + oReq.send(); + oReq.addEventListener('load', function (event) { + const response = JSON.parse(this.response); + if (response.code >= 400) { + // error + cb(new Error("Failed to get because:"+response));/´// call callback function with an error + } else { + //success + cb(null, response); // call callback function with NO error and pass the response + } + }); +} + +fetchResourceAsCallback(WEATHER_URL, + function (err, data) { + if ( err ) + console.warn(err.message); + else + console.log(data); + } +); + +function fetchResourceAsPromise(url) { + // your code goes in here +} + +fetchResourceAsPromise(WEATHER_URL) +.then(function (result) { + console.log(result); +}) +.catch(function (err) { + console.warn(err.message); +}); +} + +``` + +**Part 2** + +Use `Promise.all` to load data for multiple cities in parallel. Ask students to discuss in which scenarios it would be better to load data in parallel. In what scenarios is loading data in parallel not better. + +```javascript + +const URLS_TO_LOAD = [ 'https://samples.openweathermap.org/data/2.5/weather?q=London&appid=316f8218c0899311cc029a305f39575e', 'https://api.openweathermap.org/data/2.5/weather?q=amsterdam&appid=316f8218c0899311cc029a305f39575e']; +``` + +* Hint: use `map` to convert from an array of URLs to an array of promises. + +**Alternative exercise - Cooking pasta** + +**❗❗❗ Difficult exercise ❗❗❗** + +> Async can be hard to understand without real live example. Cooking is a great example of mixed synchronous and asynchronous tasks. In this assignment we'll cook pasta with promises 💍 + + +Let's say we want a program to cook some pasta. Some of the steps involved in cooking pasta are: + +1. Gathering the ingredients (pasta, garlic, tomatoes, sage, butter) +2. Cutting the garlic +3. Cutting the tomatoes +4. Cooking the water +5. Cooking the pasta +6. Baking the garlic +7. Baking the tomatoes + X. Mixing the pasta with sauce + +If we do this synchronously there is no chance of it becoming a good meal because the pasta would be cold by the time the vegetables are ready. It would also take way too long this way. So let's fix that! + +1. Think about how to do this asynchronously; which tasks could be run at the same time? What steps should wait for what other steps? Try to write down a basic recipe (don't write any code yet!) +2. Now convert your recipe to pseudocode (in markdown). The point is to name functions and show which functions call which other functions. The logic should be there but we'll write the code in the next step. +3. Write the actual code using promises. Add timeouts to each task (estimate how many minutes a task would take and then set the timeout to that many seconds so 8 minutes for cooking pasta would be 8 seconds in your programme) +4. Can you get the code to work like you would cook pasta in the kitchen? Try using Promise.all if you want to wait for several tasks to finish. + + + +> Async await really helps simplify asynchronous (promisified) code. The previous example can be improved by applying it. + +5. Try rewriting your previous attempt using Async/Await. ⏰🍝⏰ + + + +### Essence + +- It's the accepted solution to [callback hell](http://callbackhell.com/) +- in terms of features it does not offer something new, everything one can do with promises could also be done with callbacks but it is easier to write and read the code when promises are used + +## 2. How to use the `fetch` API to do AJAX calls + +### Explanation +- Modern replacement of XMLHttpRequest +- Uses Promise structure +- The Fetch API is defined in the browser (window.fetch) +- Only modern browsers support it (show [caniuse.com](https://caniuse.com/#feat=fetch)) +- Fetch API documentations by mozilla [link](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) +### Example + +### Excercise +``` +fetch('https://seriousnews.com/api/headlines') + .then(function (response) { + response.json(); + }).then(headlines => { + console.log(headlines) + }).catch(error => console.log(error)); +``` +### Essence + +SECOND HALF (14.00 - 16.00) + +## 3. The `this` keyword and its relationship with `scope` + +### Explanation +- The environment(or scope) in which the line is being executed is know as “Execution Context” +- The object that `this` refers to, changes every time execution context is changed. +- Whatever is calling the function passes the `this` value to it by default. +- We can pass specific `this` by `.bind`, `.call` or `.apply` +- By default, “this” refers to global object which is `global` in case of NodeJS and `window` object in case of browser + +### Example + +#### this refers to new instance (constructors) + +```javascript +function logColor() { + // this inside the function refers to the calling javascript object + console.log('This refers to: ',this); + console.log('Color of this is: '+this.color); +} +let dog = { age: 5, color: 'brown', logColor: logColor}; +let car = { model: 'bmw', color: 'orange', logColor: logColor }; + +console.log('log color called with dog') +dog.logColor(); +console.log('log color called with car') +car.logColor(); +``` + +- In Javascript, property of an object can be a method or a simple value. +- When an Object’s method is invoked then “this” refers to the object which contains the method being invoked. + + +#### “this” refers to global object +```javascript +function logColor() { + // this inside the function refers to the calling javascript object + console.log('This refers to: ',this); + console.log('Color of this is: '+this.color); +} + +console.log('log color called with no object') +logColor(); // no calling object so "this" refers to window by default +``` +> Note: the value of “this” depends on how a method is being invoked as well. + +#### “this” with call, apply methods +- These methods can be used to set custom value of `this` to the execution context of function, also they can pass arguments/parameters to the function + +```javascript +function logColor() { + // this inside the function refers to the calling javascript object + console.log('This refers to: ',this); + console.log('Color of this is: '+this.color); +} +let cat = { likes: 'milk', color: 'white'}; +logColor.call(cat); // calls the logColor function with cat as "this" +``` + +#### “this” with bind method +`bind` only create a copy of the function with the binded `this` inside without calling the function. +``` +function callAfterOneSecond(cb) { + setTimeout(function () { + cb(); + }, 1000); +} +function logColor() { + // this inside the function refers to the calling javascript object + console.log('This refers to: ',this); + console.log('Color of this is: '+this.color); +} +let cat = { likes: 'milk', color: 'white'}; +let boundLogColor = logColor.bind(cat); // returns a function that can be executed later +console.log(boundLogColor); +// a few lines later +boundLogColor(); // executes logColor with cat as "this" + +// callAfterOneSecond(boundLogColor); +``` + + +> Note: If `strict mode` is enabled for any function then the value of “this” will be “undefined” as in strict mode, global object refers to undefined in place of windows object. + +``` +function foo() { + 'use strict'; + console.log("Simple function call") + console.log(this === window); +} + +foo(); //prints false on console as in “strict mode” value of “this” in global execution context is undefined. +``` + +#### “this” in arrow functions +- The `this` value inside the arrow function gets binded and calculated and assigned based on its wrapper/container/parent `this` value. +- The methods call(), apply(), and bind() will not change the value of this in arrow functions + +Students will learn mroe about this when learning about classes in javascript. + + +### Excercise +In this excercise, let the students guess the result and then go line by line as if you were an interpreter and execute the code. Or use the debugger tools on devtools to execute line by line. + + +```javascript +let user = { + a: 2, + b: 3, + print: function () { + console.log(multiply(this.a, this.b)); + } +} +user.a = 5; +user.print(); +user.b = 10; +function multiply(p, q) { + return p * q; +} +``` + +Variant two (if students find variant one too easy) + +```javascript +let user = { + a: 2, + b: 3, + print: function () { + multiply(this.a, this.b, function (total) { + console.log(total); + console.log(this.a * this.b); + }) + } +} +user.a = 5; +user.print() +user.b = 10; +function multiply(p, q, callback) { + callback(p * q); +} +``` + +### Essence +this is special keyword in javascript. this refers to different things depending on how a function is called. + + + diff --git a/Week2/MAKEME.md b/Week2/MAKEME.md index 04c09b4da..d4f082dee 100644 --- a/Week2/MAKEME.md +++ b/Week2/MAKEME.md @@ -1,77 +1,130 @@ -# Homework Week 2 +# Homework JavaScript3 Week 2 +## **Todo list** + +1. Practice the concepts +2. JavaScript exercises +3. Code along +4. PROJECT: Hack Your Repo II + +## **1. Practice the concepts** + +Let's start this week off with some interactive exercises! Visit the following link to get started: + +- [Learn JavaScript: Promises](https://www.codecademy.com/learn/introduction-to-javascript/modules/javascript-promises) + +## **2. JavaScript exercises** + +> Inside of your `JavaScript3` fork and inside of the `Week2` folder, create a folder called `homework`. Inside of that folder, create a folder called `js-exercises`. For all the following exercises create a new `.js` file in that folder (3 files in total). Make sure the name of each file reflects its content: for example, the filename for exercise one could be `getName.js`. + +**Exercise 1: John who?** + +Take a look at the following function (and try it out in your console): + +```js +const getAnonName = (firstName, callback) => { + setTimeout(() => { + if (!firstName) + return callback(new Error("You didn't pass in a first name!")); + + const fullName = `${firstName} Doe`; + + return callback(fullName); + }, 2000); +}; + +getAnonName('John', console.log); ``` -Topics discussed this week: -• Async vs Sync -• Event Loop (order of execution) -• Promises -``` -## Step 1: Read +Rewrite this function, but replace the callback syntax with the Promise syntax: + +- Have the `getAnonName` function return a `new Promise` that uses the `firstName` parameter +- If the Promise `resolves`, pass the full name as an argument to resolve with +- If the Promise `rejects`, pass an error as the argument to reject with: "You didn't pass in a first name!" + +**Exercise 2: Is it bigger than 10?** + +Write a function called `checkDoubleDigits` that: + +- Takes 1 argument: a number +- Returns a `new Promise` +- If the number is bigger than 10, resolve with the string: "The number is bigger than 10!" +- If the number is smaller than 10, reject with the error: "Error! The number is smaller than 10..." + +**Exercise 3: Gotta catch 'em all** -- Read this article on scopes & closures: [explaining-javascript-scope-and-closures](https://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/) +> Inside of your `homework` folder, create another folder called `pokemon-app`. There, create an `index.html` and `script.js` file -- If you are still not completely clear on promises, here are some additional resources :ring: +Let's catch all original 151 Pokemon in our own little web application! Here's an example of what you'll be building for this exercise: - - [Google's post about Promises](https://developers.google.com/web/fundamentals/getting-started/primers/promises) - - [A nice article from David Walsh](https://davidwalsh.name/promises) - - [A real life example](https://github.com/mdn/js-examples/blob/master/promises-test/index.html) - - [stackoverflow](http://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript) - - YouTube: [promises](https://www.youtube.com/watch?v=WBupia9oidU) +![Pokemon App](./../assets/pokemon-app.gif) +In this exercise you're going to do several things: -## Step 2: Implement requested PR changes +1. Create and append DOM elements using JavaScript only +2. Fetch data twice from a public API [PokeAPI](https://pokeapi.co/) +3. Display the results in the DOM. -- Fix Requested Changes (if any) on the Pull Request. +Here are the requirements: -## Step 3: Convert callbacks to promises +- Create 3 functions: `fetchData`, `addPokemonToDOM` and `main` +- The `main` function executes the other functions and contains all the variables +- In the `fetchData` function, make use of `fetch` and its Promise syntax in order to get the data from the public API +- Execute the `main` function when the window has finished loading -**_Deadline Thursday_** +## **3. Code along** -### 3.1 Preparation +In the following "code along" you'll be building a complete Weather App that makes use of the [Darksky API](https://darksky.net). -The homework for week 2 will build on the work you did in week 1. You will create a new branch based on the `week1` branch. +Enjoy! -1. Make sure that you committed all changes in the week 1 version of your homework. -2. Create a new `week2` branch: +- [Build a Weather App with Vanilla JavaScript Tutorial](https://www.youtube.com/watch?v=wPElVpR1rwA) - ``` - git checkout -b week2 - ``` +## **4. PROJECT: Hack Your Repo II** -### 3.2 Assignment +> This week we'll continue building on our work from last week. Make sure to navigate to the `hackyourrepo-app` folder and start based on the code you wrote! -You will continue to work on the files `index.js` and (possibly) `style.css`. +This week we'll do a couple of things: + +1. We'll remove our HTML elements and remake them using JavaScript only! +2. We'll replace our placeholder data with real data from the GitHub API +3. We'll display this data in a separate column of the user interface + +On the surface, it'll look exactly the same. But functionally, it'll based around JavaScript only! + +Here are the requirements: + +- Remove the HTML elements you created last week, and only keep the ` + + diff --git a/Week2/traversy_async_crash/promises.js b/Week2/traversy_async_crash/promises.js new file mode 100644 index 000000000..97a1428b4 --- /dev/null +++ b/Week2/traversy_async_crash/promises.js @@ -0,0 +1,68 @@ +const posts = [ + { title: 'Post One', body: 'This is post one' }, + { title: 'Post Two', body: 'This is post two' }, +]; + +function getPosts() { + setTimeout(() => { + let output = ''; + posts.forEach(post => { + output += `
  • ${post.title}
  • `; + }); + document.body.innerHTML = output; + }, 1000); +} + +function createPost(post) { + return new Promise((resolve, reject) => { + setTimeout(() => { + posts.push(post); + + const error = false; + + if (!error) { + resolve(); + } else { + reject(new Error('Something went wrong')); + } + }, 2000); + }); +} + +// createPost({ title: 'Post Three', body: 'This is post three' }) +// .then(getPosts) +// .catch(err => console.log(err)); + +// Async / Await +// async function init() { +// await createPost({ title: 'Post Three', body: 'This is post three' }); + +// getPosts(); +// } + +// init(); + +// Async / Await / Fetch +async function fetchUsers() { + const res = await fetch('https://jsonplaceholder.typicode.com/users'); + + const data = await res.json(); + + console.log(data); +} + +fetchUsers(); + +// Promise.all +// const promise1 = Promise.resolve('Hello World'); +// const promise2 = 10; +// const promise3 = new Promise((resolve, reject) => +// setTimeout(resolve, 2000, 'Goodbye') +// ); +// const promise4 = fetch('https://jsonplaceholder.typicode.com/users').then(res => +// res.json() +// ); + +// Promise.all([promise1, promise2, promise3, promise4]).then(values => +// console.log(values) +// ); diff --git a/Week3/LESSONPLAN.md b/Week3/LESSONPLAN.md new file mode 100644 index 000000000..356427f3b --- /dev/null +++ b/Week3/LESSONPLAN.md @@ -0,0 +1,48 @@ +# Lesson Plan JavaScript3 Week 3 + +## Agenda + +The purpose of this class is to introduce to the student: + +- The purpose and use of `async/await` +- What is `Object-Oriented Programming` (OOP) is and how it's applied to JavaScript +- How to use ES6 `classes` + +## Core concepts +FIRST HALF (12.00 - 13.30) +## 1. async/await + +### Explanation +- It's an upgrade to `Promises` +- Makes writing an asynchronous function more readable +### Example +### Excercise +### Essence + + +## 2.Object-Oriented Programming (OOP) + +### Explanation +- It's a programming style; it defines how to organise your application +- In OOP each program would be split up into self-contained objects, that then communicate with each other +- Each object represents a part of the application: it contains its own data and logic +- OOP is meant to make thinking about your applications easier, by having each object represent a real-life entity (i.e. Users, Profiles, Products) +### Example +### Excercise +### Essence + + +SECOND HALF (14.00 - 16.00) + +## 3.ES6 classes + +### Explanation +- `classes` are a modern way of creating objects in JavaScript +- It's `syntactical sugar` for object constructors +- A `class` is a blueprint of an object, that can be instantiated +### Example +### Excercise +### Essence + + + diff --git a/Week3/MAKEME.md b/Week3/MAKEME.md index ad6e7286e..7e1046f70 100644 --- a/Week3/MAKEME.md +++ b/Week3/MAKEME.md @@ -1,140 +1,163 @@ -# Homework Week 3 +# Homework JavaScript3 Week 3 -``` -Topics discussed this week: -• Object Oriented Programming and ES6 Classes -• The this keyword -• call, apply, bind -``` +## **Todo list** + +1. Practice the concepts +2. JavaScript exercises +3. Code along +4. PROJECT: Hack Your Repo III + +## **1. Practice the concepts** + +Let's continue exercising those programming muscles! Go through the following exercises: + +- [Learn JavaScript: Objects](https://www.codecademy.com/learn/introduction-to-javascript/modules/learn-javascript-objects) +- [Learn JavaScript: Classes](https://www.codecademy.com/learn/introduction-to-javascript/modules/learn-javascript-classes) +- [Learn JavaScript: Async/Await](https://www.codecademy.com/learn/introduction-to-javascript/modules/asynch-js) +## **2. JavaScript exercises** -## Step 1: Fix requested changes +> Inside of your `JavaScript3` fork and inside of the `Week3` folder, create a folder called `homework`. Inside of that folder, create a folder called `js-exercises`. For all the following exercises create a new `.js` file in that folder (3 files in total). Make sure the name of each file reflects its content: for example, the filename for exercise one could be `getName.js`. -_Deadline Monday_ +**Exercise 1: Promise me to wait** -- Fix Requested Changes (if any) on the Pull Request. +In this exercise you'll practice refactoring `Promise` syntax into `async/await` + `try/catch` syntax. Rewrite exercise A & B using `async/await` + `try/catch` syntax. -## Step 2 +```js +// Exercise A +function getData(url) { + fetch(url) + .then(response => response.json) + .then(json => console.log(json)) + .catch(error => console.log(error)); +} -**_Deadline Thursday_** +getData('https://randomfox.ca/floof/'); -### 2.1 Preparation +// Exercise B +const arrayOfWords = ['cucumber', 'tomatos', 'avocado']; -**Read the fundamental pages on:** +const makeAllCaps = array => { + return new Promise((resolve, reject) => { + let capsArray = array.map(word => { + if (typeof word === 'string') { + return word.toUpperCase(); + } else { + reject('Error: Not all items in the array are strings!'); + } + }); + resolve(capsArray); + }); +}; -- [try...catch](../../../../fundamentals/blob/master/fundamentals/try_catch.md) -- [async/await](../../../../fundamentals/blob/master/fundamentals/async_await.md) +makeAllCaps(arrayOfWords) + .then(result => console.log(result)) + .catch(error => console.log(error)); +``` + +**Exercise 2: Classify** + +In this exercise you'll read a little story. It's your job to turn the characters in it into classes and instantiate the class into the characters you read about! +```md +# STORY -The homework for week 3 will build on the work you did in week 2. You will create a new branch based on the `week2` branch. +Abdulkareem is a 35 year old man, that lives in Riyadh. He has a wife and 3 children. As a day job he's a construction worker, that makes houses. He likes to eat dates and smoke water pipe. + +Abdulkareem has a horse, named Adel. The horse is 15 years old and has the color brown. Usually the horse eats grass or helps transport materials for Abdulkareem. + +And they lived happily ever after! +``` -1. Make sure that you committed all changes in the week 2 version of your homework. -2. Create a new `week3` branch: +After reading this story, you have to: - ``` - git checkout -b week3 - ``` +- Create a class for Adbulkareem and Adel +- Instantiate those classes to create an Abdulkareem object and Adel object -### 2.2 Assignment +**Exercise 3: Trivia time!** -This week you will work with all JavaScript files in the `src` folder. The assignment consists of two parts: +Don't you just love trivia games? Let's make our own! -1. Refactor all `.then()` and `.catch()` methods with `async`/`await` and `try...catch`. -2. Make your app ARIA-compliant (see below). -3. Refactor your application to use ES6 classes. +In this exercise you'll make use of the [Open Trivia Database API](https://opentdb.com/). You are going to fetch 5 random trivia questions and then inject them into the DOM, inside of an accordion. It should behave similar to this: +![Trivia App](./../assets/trivia-app.gif) -#### 2.2.1 async/await +Here are the requirements: -**Instructions:** +- Create a folder called `trivia-app`, that includes an HTML, CSS and JavaScript file +- Link them all together in the HTML file +- Only provide the basic structure in the HTML file. All other DOM elements are to be created using JavaScript +- No CSS frameworks are allowed! +- Sometimes the strings you get back from the API contains HTML entities (like `"e;`). Find out a way to turn this into regular text +- Make use of the following endpoint: https://opentdb.com/api.php?amount=5 -1. Refactor all `.then()` and `.catch()` methods with `async`/`await` and `try...catch`. +## **3. Code along** -2. Make sure that your error handling code still works. See the week2 MAKEME on how to force an error response from GitHub. +In this weeks `code along` you'll be building a Bookmarker application. It'll allow a user to add in URLs of their favorite websites in order to save it into a list. +Happy learning! -#### 2.2.2 ES6 Classes +- [BookMarker Application](https://www.youtube.com/watch?v=32qhBZacCNc) -**_Deadline Saturday_** +## **4. PROJECT: Hack Your Repo III** -This final assignment requires you to go the extra mile and master Object Oriented Programming and ES6 classes. +> This week we'll continue building on our work from last week. Make sure to navigate to the `hackyourrepo-app` folder and start based on the code you wrote! -In this assignment you need to redistribute and adapt the code from `index.js` to the files `App.js`, `Repository.js` and `Contributor.js`. You do not need to modify `Util.js`. +Our application is looking pretty nice so far! This week we'll do 2 things: -| File | Description | -|------------------|-------------| -| `App.js` | The `App` class contains the start-up code and manages the overall orchestration of the app. | -| `Repository.js` | The `Repository` class holds code and data for a single repository. | -| `Contributor.js` | The `Contributor` class holds code and data for a single contributor. | -| `Util.js` | The `Util` class contains static helper methods for use in the other classes. | +1. We'll refactor and modularize our application +2. We'll add a feature: pagination! -The `App.js`, `Repository.js` and `Contributor.js` files each contain skeleton code that you can use to migrate portions of your code from `index.js` to. +Let's break each of them apart. -_Read:_ +### 4.1 Refactor and modularize application -- HYF fundamental: [ES6 Classes](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/oop_classes.md#es6-classes) -- More on ES6 classes: [ES6 Classes in Depth](https://ponyfoo.com/articles/es6-classes-in-depth) +We'll first start off with refactoring, so that we have a clean codebase to build upon. -_Instructions:_ +Like you've learned this week, refactoring is all about writing "clean code": code that is readible and easy to add to. -1. Copy `index.html` to file named `classes.html` and change the content of the `body` tag of `classes.html` as follows: +When writing the JavaScript code last week, most likely you wrote everything in a single JavaScript file (the `script.js` one). This week we'll create many more files, that we then will all bring together in that `script.js` file to execute. This act is called `modularization`, and you'll practice with this more and more as time goes on. - ```html - -
    - - - - - - ``` +Next to that you'll refactor your code using the software design principles you've learned about this week: DRY, KISS and others you might have picked up. How does would look like exactly in your codebase is left up to you. -#### 2.2.3 ARIA-compliance (BONUS) +Here are the requirements: -Please review the material from the HTML/CSS module: [Get familiar with Accessible Rich Internet Applications (ARIA)](https://github.com/HackYourFuture/HTML-CSS/tree/master/Week1#get-familiar-with-accessible-rich-internet-applications-aria). +- Create a separate `.js` for every function you create +- Import all top-level functions into the `script.js` file to execute when the window has loaded +- Rewrite your logic to be as simple as possible. Use loops and logical operators when needed +- Rename your functions and variables to be as semantic as possible +- Store all your JavaScript files, besides `script.js` in a folder called `util` (short for utility functions) -For the GitHub application ARIA-compliance means that the Contributors list should either be a native HTML list (i.e. using `ul` and `li` elements) or otherwise marked with an appropriate ARIA **role**. Furthermore, a user should be able to navigate through all interactive elements using the keyboard (e.g., using the **Tab** key). Pressing **Enter** on such an element should be equivalent to clicking the mouse. +> Utility functions are reusable functions that are made to solve common problems. They are regular functions that perform tasks like: performing a calculation, transform one data type into another or perform a DOM operation. -#### 2.2.4 Handing in your homework +### 4.2 Add a feature: Pagination -- Have you removed all commented out code (should never be present in a PR)? -- Have you used `const` and `let` and avoided `var`? -- Do the variable, function and argument names you created follow the [Naming Conventions](../../../../fundamentals/blob/master/fundamentals/naming_conventions.md)? -- Is your code well-formatted (see [Code Formatting](../../../../fundamentals/blob/master/fundamentals/naming_conventions.md))? -- Have you resolved all issues flagged by ESLint and the spell checker (no wavy red and green underlines in VSCode)? +You might have noticed that when a user selects a repository that has many contributors, the page's height becomes bigger and bigger (thus forcing the user to scroll down). Let's change that by adding pagination! -If the answer is 'yes' to all preceding questions you are ready to follow these instructions: +What is pagination? Take a look at this: -1. Push your `week3` branch to GitHub: +![Pagination Example](https://lorisleiva.com/content/images/2020/10/laravel-pagination-with-tailwindcss.png) - ``` - git push -u origin week3 - ``` +In the illustration, each number represents a page. You might have seen it before on websites like Amazon, when you're browsing through different products. -2. Create a pull request for your `week3` branch. +We'll replicate this functionality to allow a user to browse through different contributors without have to scroll incessantly. -## Step 3: Read before next lecture +Here are the requirements: -_Deadline Sunday morning_ +- Each "page" should contain at maximum 5 contributors. If the repository selected contains more than 5 contributors, it will get split up unto a different page (and thus create another addition) +- Slice the array into smaller parts and create a new page every time the maximum has been reached +- Allow a user to click from page to page by clicking on the number, or an arrow to go one page forward or backward -Go trough the reading material in the [README.md](https://github.com/HackYourFuture/Node.js) of the Node repository to prepare for your next class. +Good luck! -## Alternative _BONUS_ : Code Kata Race +## **SUBMIT YOUR HOMEWORK!** -If you haven't already join our clan: "Hack Your Future" in codewars +After you've finished your todo list it's time to show us what you got! The homework that needs to be submitted is the following: -Solve the following problems: -- [Problem 1](https://www.codewars.com/kata/keep-up-the-hoop) -- [Problem 2](https://www.codewars.com/kata/find-the-first-non-consecutive-number) -- [Problem 3](https://www.codewars.com/kata/negation-of-a-value) -- Some more [Homework](https://www.codewars.com/collections/hyf-homework-1) +1. PROJECT: HackYourRepo III -_Hints_ -- Hint for Q1: split your code into two parts, one part for the case that one of the two strings has an extra letter at the start or the end but is otherwise identical & one part for the case that the strings are the same length but one character is different in one of the strings -- Also for Q1 this function on strings might be useful: [JavaScript String slice() method](https://www.w3schools.com/jsref/jsref_slice_string.asp) -- Also potentially useful: [JavaScript String charAt() Method](https://www.w3schools.com/jsref/jsref_charat.asp) -- [Hint for Q2](https://www.w3schools.com/jsref/jsref_sort.asp) Also there are no sample tests, you need to use submit +Upload your homework to your forked JavaScript3 repository in GitHub. Make a pull request to the teacher's forked repository. -Remember the person with the most kata points gets a prize from Gijs (and you can do exercises on this website without us assigning them - anything kyu 7 or kyu 8 you can try to do - kyu 6 or lower is probably too hard) --> +> Forgotten how to upload your homework? Go through the [guide](../hand-in-homework-guide.md) to learn how to do this again. --[MORE BONUS](https://www.codewars.com/collections/hyf-homework-1-bonus-credit) :collision: +_Deadline Saturday 23.59 CET_ diff --git a/Week3/README.md b/Week3/README.md index 2c317379f..03d8d09ab 100644 --- a/Week3/README.md +++ b/Week3/README.md @@ -1,29 +1,343 @@ -# Reading material for the third lecture: +# Reading Material JavaScript3 Week 3 +## Agenda + +These are the topics for week 3: + +1. Object-Oriented Programming (OOP) + - 3 main paradigms + - A different way of thinking + - 4 pillars of OOP +2. ES6 Classes + - Data structures revisited + - Objects + - Factory functions + - Constructor functions + - Classes +3. Async/Await + - Catching errors with try/catch +4. Thinking like a programmer III + +## 0. Video Lectures + +Your teacher Stasel has made video lectures for this week's material. You can find them here: [Videos 9 - 10](https://www.youtube.com/playlist?list=PLVYDhqbgYpYVchJ9QQ3rC2WxYKrOiceYX) + +HYF Video + +## 1. Object-Oriented Programming (OOP) + +So far we've learned about various programming concepts. These are the basics of what makes up any application: it's the **WHAT** of writing applications. However, now that you're familiar with them it's time to go to the next level: the **HOW** of writing applications. + +Like in any field, you first have to master the basics before you can create your own style of creating something new. Let's say that you want to start playing a musical instrument: the piano. At first you have to learn the basics: the different scales, notes, melodies, tempo (music basics), then you have to learn how to compose songs (writing notes in the correct order). Once you understand all of that is it time to learn a specific **style** of composing songs. + +It's the same way with programming. At first you're learning about variables, functions, loops, etc. (the basics), then you learn how to build applications (writing code in the correct order). Once you've learned all of this you can start thinking about the **style** of building applications. + +### 3 main styles (paradigms) + +There are 3 big programming styles (or to use a fancier term: paradigms) popular right now: + +1. Procedural +2. Object-Oriented +3. Functional + +Up until now you implicitly learned a basic way of writing code, called `procedural programming`. In this style we break problems up into functions and variables, and execute them as one long procedure. There is no real thought behind code organization or reusability, it just needs to be executed. In this style we essentially say: "Hey computer do this, then that, and also this and later that." There is not much thought put into it. + +Take this example: + +```js +const numbers = [14, 5, 25, 8]; + +const filterDoubleDigits = numbers => { + return numbers.filter(number => { + return number < 10; + }); +}; + +filterDoubleDigits(numbers); +``` + +Every line is executed, and this works. However, there is no real organization to the lines. This is ok when your code base is small. + +But what if your application counts 1000's of lines of code? + +You can imagine that reading and understanding what's happening is going to be much more difficult then. + +As software increases in complexity, files become bigger and contain more code. The logical rules also become increasingly more complex. This has led programmers to start thinking more about code organization. As a result different programming styles (paradigms) have evolved. + +The fundamental question people asked was: **how can we make writing code more organized and readable?** + +### A different way of thinking + +Object Oriented Programming (OOP) is another style (or paradigm) of building applications. It's not a language, technology or tool: it's a **set of ideas on how to approach writing software**. + +Instead of writing loose variables and functions, we try to group them together in order to create entities. An example of an entity is a Person, Animal or Vehicle. By having different entities we can make them "talk to each other"! + +The central question asked in OOP is this: **how can we structure our applications in a way that reflects the real world?** + +> Just to make sure you completely get the idea here: OOP is about a different way of thinking about how to write software. The concepts of variables, functions, promises, API (calls) and error handling all still apply. It's just that the way code is organised is different. Instead of creating long procedures, we create objects that interact with each other. + +For further study, check the following: + +- [Computer programming: What is object-oriented language?](https://www.youtube.com/watch?v=SS-9y0H3Si8) +- [Object-oriented programming — the basics](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_%E2%80%94_the_basics) + +### 4 pillars of OOP + +Almost anything that evolves within programming does so to solve a certain problem. HTML was developed to make document sharing over the Internet simple and straightforward. CSS was developed to make documents more user-friendly. + +The problems that OOP tries to solve is the question we saw before: how can we write code in an organized and reusable fashion? + +The answer that OOP gives us can be summarised in 4 pillars. To illustrate these pillars let's use a simple example: + +```js +const person = { + name: 'Mohammad', + age: 28, + walk() { + return `${this.name} is walking!`; + }, +}; ``` -In week three we will discuss the following topics: -• Object Oriented Programming and ES6 Classes -• The this keyword -• call, apply, bind + +1. **Encapsulation**: In the example data and operations (that manipulate that data)are grouped together. This is called `encapsulation`. The main benefit is that this keeps our code organised. The second benefit is that putting objects inside of a 'capsule' we can prevent direct manipulation by outside sources, this is called `data hiding`. This reduces dependencies between objects, so that change in one place doesn't affect the rest of the application. + +2. **Abstraction**: Let's say we had a Complexity of logic hidden away, creating a simpler interface (remote controller to a tv). Only expose the essentials. Abstracting away complexities to create an easier to use element. + +3. **Inheritance**: eliminates redundant code by inheriting properties and methods in new instances. This encourages code reusability. + +4. **Polymorphism**: an object can have many forms of expression, depending on the context. Let's say we inherit + +Any class that exists or is made follows these pillars. + +For further study check out the following resources: + +- [How to explain object-oriented programming concepts to a 6-year-old](https://www.freecodecamp.org/news/object-oriented-programming-concepts-21bb035f7260/) +- [JavaScript OOP Crash Course (ES5 & ES6)](https://www.youtube.com/watch?v=vDJpGenyHaA) +- [Object-Oriented Programming & Classes](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/oop_classes.md) + +## 2. ES6 Classes + +### Data structures revisited + +Programming is about 2 things: **information** and **communication of that information**. Everything else flows from those two basic ideas. In programming we take this idea of "information" apart and categorize it into what we call `data structures`. Each data structure breaks down "information" in a specific category, for example for words we use `strings`. For numbers we use `numbers`. + +### Objects + +In JavaScript, objects are special. In your programming so far you most likely have created objects like this: + +```js +const anObj = { + name: 'Cool Object', +}; +``` + +This is called an `object literal`, and it's a valid way of creating an object. However, writing it like this "abstracts away" a lot of what's happening behind the scenes. + +> To abstract away refers to intentionally hiding the details of how something complex works in order to simplify things conceptually. For example, the remote to your television is a complex device, but all of this is abstracted away so you don't have to deal with it. You just press the ON button and it works. + +You can write the same thing by using the Object `constructor function`. + +```js +const anObj = new Object(); +anObj.name = 'Cool Object'; ``` -Here are resources that we like you to read as a preparation for the third lecture: +Well, what is a constructor function? To understand that we need to start at the beginning first: `factory functions`. + +### Factory functions + +If we want to create an object we can just use an `object literal` and we're done. But what if we want to create hundreds of copies (or as we say in programming, 'instances') of that same object? + +For that we use `factory functions`. Don't let the name mislead you though, a factory function is just a regular function. However, the single differentiating factor is that it always returns an object instance: it is a factory that produces object instances, hence the name `factory function`. Here's an example: + +```js +// Defining a blueprint for a person: +function createPerson(name, age) { + var obj = { + name: name, + age: age, + walk: function() { + console.log(`${this.name} is walking!`); + }, + }; + // other code to manipulate our object in some way here + return obj; +} +``` + +This is the most simple way of defining a `template`/`blueprint`/`class` (these are all synonyms in this context) and creating object instances from it. Now every time we call this function we're creating a new person object. + +```js +const noer = createPerson('Noer', 27); +const wouter = createPerson('Wouter', 33); +const federico = createPerson('Federico', 32); +``` + +Go through the following to learn more about factory functions: + +- [The Factory Pattern](https://www.youtube.com/watch?v=0jTfc4wY6bM) +- [JavaScript Factory Functions](https://www.youtube.com/watch?v=jpegXpQpb3o) + +### Constructor functions + +`Constructor functions` are ordinary functions that have a special purpose: to create object instances. You can consider them the more advanced version of `factory functions`. + +Here's an example: + +```js +// // Defining a blueprint for a person: +function Person(name, age) { + this.name = name; + this.age = age; +} +``` + +The difference with a factory function is the way to instantiate it. Instead of just calling it we have to use the keyword `new`, like so: + +```js +const noer = new Person('Noer', 27); +``` + +Learn more about constructor functions: + +- [JavaScript Constructor Functions](https://www.youtube.com/watch?v=23AOrSN-wmI) +- [Constructors and object instances](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances) + +### Classes + +A `class` is an essential idea within OOP: it's a **blueprint/template** of an entity. When we define a class we give it properties and behaviors. For example, a Person class can have a `name`, `age` and `gender`; these are the properties of the Person. Additionally, a Person can also `talk`, `walk` `sleep`; these are the behaviors of the Person. + +![OOP Classes](../assets/OOP.png) + +Let's take an example of a class, written in ES6 syntax: + +```js +class Person { + constructor(name, age, gender) { + this.name = name; + this.age = age; + this.gender = gender; + } + + talk(sentence) { + console.log(sentence); + } + + sleep() { + console.log('Zzzzzzzzz....'); + } +} +``` + +When defined like above, it's merely a definition. It's not an `instance` of it. Or in other words: it's a new blueprint we've created, but not yet a real person. + +To create a real Person, we have to `instantiate` it: + +```js +const aisha = new Person('Aisha', 25, 'Female'); + +aisha.talk('Hi! My name is Aisha!'); // Result: Hi! My name is Aisha! +``` + +> An ES6 class is essentially the same thing as a constructor function, only written in a clearer and more straightforward way. You can call it an upgrade to constructor functions (similar to how Promises are an upgrade to callbacks). + +Go through the following to learn more about classes: + +- [Object Oriented JavaScript With ES6: The Class](https://www.youtube.com/watch?v=sJvPXb_lmPE) +- [An overview of ES6 classes](https://thecodebarbarian.com/an-overview-of-es6-classes) + +## 3. Async/Await + +Last week you learned about Promises. To recap, here's what we learned: in order to introduce **asynchronicity** in our applications we use `callbacks`. This allows us to perform multiple operations simultaneously, i.e. fetch data while a user is still able to navigate the page. + +At first we learned about callbacks, as a way to do this: + +```js +function someFunc(param1, callback) { + const result = callback(param1); + return result; +} +``` + +Then we learned about how Promises are an improvement upon callbacks, by providing the developer with a more readable syntax that avoids **callback hell**. Here's the basic structure again: + +```js +new Promise(reject, resolve).then(...); +``` + +And now we've arrived at the latest upgrade of the callback mechanism: `async/await`. This construct is part of **ECMAScript 6** and its main benefit is to make using callbacks even more readable. Here's how it might look in action: + +```js +async fetchData () { + const fetchedData = await fetch('https://randomuser.me/api/'); + const parsedData = await fetchedData.json(); + return parsedData; +} +``` + +How do we use it? We put the keyword `async` in front of the function declaration that will contain asynchronous code. Then in every line that returns a Promise we put the keyword `await` in front. That's it. + +For more research, check the following resources: + +- [The Evolution of Callbacks, Promises & Async/Await](https://www.youtube.com/watch?v=gB-OmN1egV8) +- [Async JS Crash Course - Callbacks, Promises, Async/Await](https://www.youtube.com/watch?v=PoRJizFvM7s) + +### Catching errors + +As you might have noticed, the `async/await` keywords don't give us a way catching errors like it does in the Promise object. + +But before we get into that, we should define "catching errors" a little bit. By "catching errors" we mean: + +1. that a line of code has caused an error (because of incorrect syntax or data type) +2. that the program has shutdown to prevent any other errors from happening +3. that the application gives feedback to the developer and/or user about where the error came from + +In the Promise object, we can use the function `catch` to take care of errors. It takes in a callback, which automatically receives an error object. Here's an example: + +```js +Promise.catch(function(error) { + console.log(error); +}); +``` + +With the `async/await` keywords, we don't get a `catch` function to use. So instead we have to use some other solution: the `try... catch` block. It's also an addition to the language, given to us by **ECMAScript 6**: + +```js + // This function will run. If anything goes wrong... + async fetchData () { + try { + const fetchedData = await fetch('https://randomuser.me/api/'); + const parsedData = await fetchedData.json(); + return parsedData; + } catch (err) { + // ...the code in this block will execute. The error that has been created will now be inserted into `err` + console.log('Oops, something went wrong!', err); + } + } +``` + +Learn more about it here: + +- [JavaScript Try Catch & Error Handling ES6 Tutorial](https://www.youtube.com/watch?v=ye-aIwGJKNg) +- [Error handling, "try..catch"](https://javascript.info/try-catch) -### Fundamentals +## 4. Thinking like a programmer III -- [Object-Oriented Programming & Classes](../../../../fundamentals/blob/master/fundamentals/oop_classes.md) -- [What is 'this'?](../../../../fundamentals/blob/master/fundamentals/this.md) +As our applications grow bigger, they increase in complexity. This can make our programs harder to understand. In order to make things as clear and easy to understand as possible, we need to regularly tidy up our code. In the industry we call this act `refactoring`. The result of this is what we like to call `clean code`. -### `call` `apply`, `bind` +- (Code Refactoring)[https://www.youtube.com/watch?v=vhYK3pDUijk] +- (Refactoring JavaScript with pipeline style programming)[https://www.youtube.com/watch?v=38q7aSu52NY] -- [Function.prototype.call()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) -- [Function.prototype.apply()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply) -- [Function.prototype.bind()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) +As a great programmer, you always want to be writing clean code. This means: code that's well-organized in small files that you can easily read and understand in order to comprehend what the application is trying to do. +There are many ways to write clean code. Some of them you might have heard: Don't Repeat Yourself (DRY) or Keep It Simple, Stupid (KISS) are two things to keep in mind. There are many others and you are encouraged to do your own research! -## Recommended Readings +Here are already a couple of them to get you started: -[Eloquent JavaScript: Chapter 6 - The Secret Life of Objects](http://eloquentjavascript.net/06_object.html). Read up to the section of **Maps**. +- [Top 5 Programming Principles that any software engineer should follow](https://www.youtube.com/watch?v=d-KbEQM0724) +- [Programming Terms: DRY (Don't Repeat Yourself)](https://www.youtube.com/watch?v=IGH4-ZhfVDk) +- [The KISS Principle in Software Development — Everything You Need to Know](https://medium.com/@devisha.singh/the-kiss-principle-in-software-development-everything-you-need-to-know-dd8ea6e46bcd) +## Finished? -_Please go through the material and come to class prepared!_ \ No newline at end of file +Are you finished with going through the materials? High five! If you feel ready to get practical, click [here](./MAKEME.md). diff --git a/Week3/assets/JavaScript3_classes.png b/Week3/assets/JavaScript3_classes.png new file mode 100644 index 000000000..22b6c0ccb Binary files /dev/null and b/Week3/assets/JavaScript3_classes.png differ diff --git a/Week3/traversy_fetch_api/app.js b/Week3/traversy_fetch_api/app.js new file mode 100644 index 000000000..5cd28c9c0 --- /dev/null +++ b/Week3/traversy_fetch_api/app.js @@ -0,0 +1,72 @@ +/* eslint-disable no-console */ + +'use strict'; + +{ + function getText() { + fetch('sample.txt') + .then(res => res.text()) + .then(data => { + document.getElementById('output').innerHTML = data; + }) + .catch(err => console.log(err)); + } + + function getUsers() { + fetch('users.json') + .then(res => res.json()) + .then(data => { + let output = '

    Users

    '; + data.forEach(user => { + output += ` + + `; + }); + document.getElementById('output').innerHTML = output; + }); + } + + function getPosts() { + fetch('https://jsonplaceholder.typicode.com/posts') + .then(res => res.json()) + .then(data => { + let output = '

    Posts

    '; + data.forEach(post => { + output += ` +
    +

    ${post.title}

    +

    ${post.body}

    +
    + `; + }); + document.getElementById('output').innerHTML = output; + }); + } + + function addPost(e) { + e.preventDefault(); + + const title = document.getElementById('title').value; + const body = document.getElementById('body').value; + + fetch('https://jsonplaceholder.typicode.com/posts', { + method: 'POST', + headers: { + Accept: 'application/json, text/plain, */*', + 'Content-type': 'application/json', + }, + body: JSON.stringify({ title, body }), + }) + .then(res => res.json()) + .then(data => console.log(data)); + } + + document.getElementById('getText').addEventListener('click', getText); + document.getElementById('getUsers').addEventListener('click', getUsers); + document.getElementById('getPosts').addEventListener('click', getPosts); + document.getElementById('addPost').addEventListener('submit', addPost); +} diff --git a/Week3/traversy_fetch_api/index.html b/Week3/traversy_fetch_api/index.html new file mode 100644 index 000000000..d64b48f95 --- /dev/null +++ b/Week3/traversy_fetch_api/index.html @@ -0,0 +1,46 @@ + + + + + + + Codestin Search App + + + +
    +

    Fetch API Sandbox

    +
    + + + +
    +
    +
    +
    +
    + +
    +
    + +
    + +
    +
    + + + diff --git a/Week3/traversy_fetch_api/sample.txt b/Week3/traversy_fetch_api/sample.txt new file mode 100644 index 000000000..03ffbce09 --- /dev/null +++ b/Week3/traversy_fetch_api/sample.txt @@ -0,0 +1 @@ +I am a sample text file \ No newline at end of file diff --git a/Week3/traversy_fetch_api/users.json b/Week3/traversy_fetch_api/users.json new file mode 100644 index 000000000..857664f2d --- /dev/null +++ b/Week3/traversy_fetch_api/users.json @@ -0,0 +1,17 @@ +[ + { + "id":1, + "name":"Rick", + "email":"rick@gmail.com" + }, + { + "id":2, + "name":"Glenn", + "email":"glenn@gmail.com" + }, + { + "id":3, + "name":"Negan", + "email":"negan@gmail.com" + } +] diff --git a/Week3/traversy_oop_crash/1_basics_literals.js b/Week3/traversy_oop_crash/1_basics_literals.js new file mode 100644 index 000000000..be9f63cca --- /dev/null +++ b/Week3/traversy_oop_crash/1_basics_literals.js @@ -0,0 +1,21 @@ +// Object Literal +const book1 = { + title: 'Book One', + author: 'John Doe', + year: 2013, + getSummary: function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + }, +}; + +const book2 = { + title: 'Book Two', + author: 'Jane Doe', + year: 2016, + getSummary: function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + }, +}; + +console.log(book1.getSummary()); +console.log(book2.getSummary()); diff --git a/Week3/traversy_oop_crash/2_constructor.js b/Week3/traversy_oop_crash/2_constructor.js new file mode 100644 index 000000000..311ca291d --- /dev/null +++ b/Week3/traversy_oop_crash/2_constructor.js @@ -0,0 +1,20 @@ +// Constructor +function Book(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + this.getSummary = function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + }; +} + +// Instantiate an Object +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); + +console.log(book1.getSummary()); +console.log(book2.getSummary()); + +console.log(book1); + +book1.turnPage(); diff --git a/Week3/traversy_oop_crash/3_prototypes.js b/Week3/traversy_oop_crash/3_prototypes.js new file mode 100644 index 000000000..abaf231fd --- /dev/null +++ b/Week3/traversy_oop_crash/3_prototypes.js @@ -0,0 +1,34 @@ +// Constructor +function Book(title, author, year) { + this.title = title; + this.author = author; + this.year = year; +} + +Book.prototype.getSummary = function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; +}; + +Book.prototype.getAge = function() { + const years = new Date().getFullYear() - this.year; + return `${this.title} is ${years} years old.`; +}; + +// Revise / Change Year +Book.prototype.revise = function(newYear) { + this.year = newYear; + this.revised = true; +}; + +// Instantiate an Object +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); + +console.log(book1.getSummary()); +console.log(book2.getSummary()); + +console.log(book2); +book2.revise(2018); +console.log(book2); + +console.log(book2.getAge()); diff --git a/Week3/traversy_oop_crash/4_inheritance.js b/Week3/traversy_oop_crash/4_inheritance.js new file mode 100644 index 000000000..91c7b7fa1 --- /dev/null +++ b/Week3/traversy_oop_crash/4_inheritance.js @@ -0,0 +1,37 @@ +// Book Constructor +function Book(title, author, year) { + this.title = title; + this.author = author; + this.year = year; +} + +Book.prototype.getSummary = function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; +}; + +Book.prototype.getAge = function() { + const years = new Date().getFullYear() - this.year; + return `${this.title} is ${years} years old.`; +}; + +// Magazine Constructor +function Magazine(title, author, year, month) { + Book.call(this, title, author, year); + this.month = month; +} + +// Inherit Prototype +Magazine.prototype = Object.create(Book.prototype); + +// Use Magazine Constructor +Magazine.prototype.constructor = Magazine; + +Magazine.prototype.updateMonth = function(month) { + this.month = month; +}; + +// Instantiate Magazine Object +const mag1 = new Magazine('Mag One', 'John Doe', 2018, 'Jan'); + +console.log(mag1); +console.log(mag1.getSummary()); diff --git a/Week3/traversy_oop_crash/5_object_create.js b/Week3/traversy_oop_crash/5_object_create.js new file mode 100644 index 000000000..90a73204b --- /dev/null +++ b/Week3/traversy_oop_crash/5_object_create.js @@ -0,0 +1,25 @@ +// Object of Protos +const bookProtos = { + getSummary: function() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + }, + getAge: function() { + const years = new Date().getFullYear() - this.year; + return `${this.title} is ${years} years old.`; + }, +}; + +// Create Object +const book1 = Object.create(bookProtos); +book1.title = 'Book One'; +book1.author = 'John Doe'; +book1.year = 2013; + +const book2 = Object.create(bookProtos, { + title: { value: 'Book Two' }, + author: { value: 'Jane Doe' }, + year: { value: 2016 }, +}); + +console.log(book1); +console.log(book2); diff --git a/Week3/traversy_oop_crash/6_classes.js b/Week3/traversy_oop_crash/6_classes.js new file mode 100644 index 000000000..5349c0008 --- /dev/null +++ b/Week3/traversy_oop_crash/6_classes.js @@ -0,0 +1,42 @@ +class Book { + constructor(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + } + + getSummary() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + } + + getAge() { + const years = new Date().getFullYear() - this.year; + return `${this.title} is ${years} years old.`; + } + + revise(newYear) { + this.year = newYear; + this.revised = true; + } + + static topBookStore() { + return 'Barnes & Noble'; + } +} + +// Instantiate an Object +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); + +console.log(book1); + +console.log(book1.getSummary()); +console.log(book2.getSummary()); + +console.log(book2); +book2.revise(2018); +console.log(book2); + +console.log(book2.getAge()); + +console.log(Book.topBookStore()); diff --git a/Week3/traversy_oop_crash/7_subclasses.js b/Week3/traversy_oop_crash/7_subclasses.js new file mode 100644 index 000000000..d69a1db7a --- /dev/null +++ b/Week3/traversy_oop_crash/7_subclasses.js @@ -0,0 +1,28 @@ +class Book { + constructor(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + } + + getSummary() { + return `${this.title} was written by ${this.author} in ${this.year}.`; + } +} + +class Magazine extends Book { + constructor(title, author, year, month) { + super(title, author, year); + this.month = month; + } + + updateMonth(month) { + this.month = month; + } +} + +// Instantiate Magazine Object +const mag1 = new Magazine('Mag One', 'John Doe', 2018, 'Jan'); + +console.log(mag1); +console.log(mag1.getSummary()); diff --git a/Week3/traversy_oop_crash/README.md b/Week3/traversy_oop_crash/README.md new file mode 100644 index 000000000..25bfed3a4 --- /dev/null +++ b/Week3/traversy_oop_crash/README.md @@ -0,0 +1,362 @@ +# OOP Crash Course + +This README is a companion to Brad Traversy's YouTube [JavaScript OOP Crash Course (ES5 & ES6)](https://www.youtube.com/watch?v=vDJpGenyHaA&t=1055s). It describes how one of the key concepts of Object Oriented Programming, **inheritance**, is implemented in JavaScript. Both explicit (pre-ES6) **prototype-based inheritance** as well as ES6 **classes-based inheritance** is covered. However, the principles of OOP itself are not discussed in this document. + +Note that it is not necessary in your daily programming to have full knowledge of all the finer details of prototypal inheritance. As can be seen in this document those details can quickly become rather complex. An overall awareness of the concept of a **prototype** chain as the underlying infrastructure for supporting inheritance will suffice. + +What _is_ important is that you understand the **ES6 class syntax** and how to implement a **class inheritance** with the **extends** keyword (see **6_classes** and **7_subclasses** below). + +>Note: The names of the sections below correspond to the equally named JavaScript example files. + +To run the code: + +1. Open **index-all.html** by right-clicking the file in the VSCode Explorer and select **Open with Live Server**. +2. Open the Chrome Developer Tools console. +3. Select the file to run from the select box. + +To examine a particular example in the Chrome Developer Tools, modify **index.html** to load the desired JavaScript file and open **index.html** in the browser. + +## 1_basics_literals + +This is the most direct way of 'manually' creating objects and does not introduce any new concepts. + +## 2_constructors + +Prior to ES6, prototypal inheritance required the use of **constructor** functions. These are regular JavaScript functions that are intended to be used in combination with the `new` keyword. By convention, constructor function names start with an upper case letter (CamelCase). + +When a function is called with `new`, its `this` value will be set to an empty object. By default, this empty object is linked through its **prototype chain** to [`Object.prototype`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Object_instances_and_Object_prototype_object) (which in itself is an object). That is why methods such as `.hasOwnProperty()` and `.toString()` can be called on _any_ object: they are defined on `Object.prototype`. This is illustrated in Figure 1 below which corresponds to the following code snippet: + +```js +function Book(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + this.getSummary = function() { + //... + }; +} + +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); +``` + +In this example, each **Book** object gets, in addition to its data properties, its own copy of the `.getSummary()` method. This is wasteful in both memory space and execution time. Instead, shared functions should be assigned to the prototype of the constructor function, as will be shown in the next section. + + +![2_constructor](./assets/2_constructor.png) +Figure 1. Prototypal linkage and the prototype chain. + +Note that all object instances created with the same constructor function share a single copy of the function's prototype object: + +```js +book1.__proto__ === Book.prototype // true +book2.__proto__ === Book.prototype // true +``` + +Output from `console.log(book1)`: + +``` +Book {title: "Book One", author: "John Doe", year: 2013, getSummary: ƒ} + author: "John Doe" + getSummary: ƒ () + title: "Book One" + year: 2013 + __proto__: + constructor: ƒ Book(title, author, year) + __proto__: + constructor: ƒ Object() + hasOwnProperty: ƒ hasOwnProperty() + isPrototypeOf: ƒ isPrototypeOf() + ... +``` + +## 3_prototypes + +Functions assigned to the prototype of the constructor function are shared across all object instances created with that same constructor function, as shown in Figure 2. + +```js +function Book(title, author, year) { + this.author = author; + this.title = title; + this.year = year; +} + +Book.prototype.getSummary = function() { + //... +}; + +Book.prototype.getAge = function() { + //... +}; + +Book.prototype.revise = function(newYear) { + //... +}; + +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); +``` + +![3_prototypes](./assets/3_prototypes.png) +Figure 2. Methods defined in the prototype of the constructor function are shared by all object instances. + +When calling a method (using dot notation) on an object, JavaScript will first look on the object itself for the method. If not found, it will inspect the **prototype** of the object (using its `__proto__` property). If still not found it will go to the next prototype in the chain, and so on, ultimately arriving at `Object.prototype` for a final inspection. + +For instance, the method `.getSummary()` is not found on the `book1` object. Following the prototype chain, JavaScript finds it on `Book.prototype`. In another example, `.toString()` is not found on the `book1` object, nor on its `Book.prototype`. It _is_ however found on `Object.prototype`. + +But if we attempt to call a `.turnPage()` method on `book1` JavaScript will not find it on the object itself, nor anywhere on its prototype chain. Consequently, JavaScript will throw a run time error: + +```js +book1.turnPage(); // Uncaught TypeError: book1.turnPage is not a function +``` + +Output from `console.log(book1)`: + +``` +Book {title: "Book One", author: "John Doe", year: 2013} + author: "John Doe" + title: "Book One" + year: 2013 + __proto__: + getAge: ƒ () + getSummary: ƒ () + revise: ƒ (newYear) + constructor: ƒ Book(title, author, year) + __proto__: + constructor: ƒ Object() + hasOwnProperty: ƒ hasOwnProperty() + isPrototypeOf: ƒ isPrototypeOf() + ... +``` + +## 4_inheritance + +An object can inherit behaviour from another object through prototypal linkage. In this example, a **Magazine** object becomes an extended version of a **Book** object. All methods from the base object are also accessible from the inheriting object and both object use a shared **this** value. + +```js +function Book(title, author, year) { + this.title = title; + this.author = author; + this.year = year; +} + +Book.prototype.getSummary = function() { + //... +}; + +Book.prototype.getAge = function() { + //... +}; + +function Magazine(title, author, year, month) { + Book.call(this, title, author, year); + this.month = month; +} + +Magazine.prototype = Object.create(Book.prototype); +Magazine.prototype.constructor = Magazine; + +Magazine.prototype.updateMonth = function(month) { + //... +}; + +const mag1 = new Magazine('Mag One', 'John Doe', 2018, 'Jan'); +``` + + +Firstly, remember that when a function is called with `new`, its `this` value is initialized with an empty object (prototype linked to `Object.prototype`). + +In order to initialize the base object (in this example **Book**), its constructor function must be called, with the `this` value set to that of the calling constructor (here, **Magazine**). + +This is done with the [Function.prototype.call()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call) method (see Figure 4 below), passing the `this` value of the calling constructor as its first argument. If the called constructor expects arguments they are passed as additional arguments following the `this` value. In this example, the called constructor for **Book** expects the arguments `title`, `author` and `year`. + +```js +function Magazine(title, author, year, month) { + Book.call(this, title, author, year); + //... +} +``` + +Next, the prototype of the calling constructor must be linked to the called constructor. This is done with the help of [Object.create()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create). + +```js +Magazine.prototype = Object.create(Book.prototype); +``` + +Finally, we must update the `.constructor` property of the prototype to point to the correct constructor function. + +```js +Magazine.prototype.constructor = Magazine; +``` + +With all this, the prototypal linkage is complete, as shown in Figure 3 below. + +![4_inheritance](./assets/4_inheritance.png) +Figure 3. Prototype chain from explicit prototypal inheritance. + +From [MDN instanceof](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof): _The **instanceof operator** tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object._ + +```js +console.log(mag1 instanceof Magazine); // true +console.log(mag1 instanceof Book); // true +console.log(mag1 instanceof Object); // true +``` + +Output from `console.log(mag1)`: + +``` +Magazine {title: "Mag One", author: "Jon Doe", year: 2018, month: "Jan"} + author: "John Doe" + month: "Jan" + title: "Mag One" + year: 2018 + __proto__: Book + constructor: ƒ Magazine(title, author, year, month) + updateMonth: ƒ (month) + __proto__: + getAge: ƒ () + getSummary: ƒ () + constructor: ƒ Book(title, author, year) + __proto__: + constructor: ƒ Object() + hasOwnProperty: ƒ hasOwnProperty() + isPrototypeOf: ƒ isPrototypeOf() + ... +``` + +![function_proto](./assets/function_proto.png) +Figure 4. Every JavaScript function is prototype-linked to `Function.prototype`, which in its turn if is linked to `Object.prototype`. A function can have properties and methods, just like any object. + +```js +console.log(typeof Book === 'function'); // true +console.log(Book instanceof Function); // true +console.log(Book instanceof Object); // true +console.log(Book.__proto__ === Function.prototype); // true +console.log(typeof Function === 'function'); // true +``` + +## 5_object_create + +The method of implementing prototypal inheritance demonstrated in this example is uncommon in practice and will not be further discussed here. + +## 6_classes.js + +The pre-ES6 method of implementing explicit prototypal linkage is rather cumbersome as you may have concluded already. Fortunately, ES6 classes make implementing inheritance far simpler as shown in the code snippets below. They still use prototypal linkage behind the scenes, but using a more elegant syntax, familiar from other object-oriented languages such as Java, C++ and C#. This more palatable class syntax in ES6 JavaScript is sometimes referred to as _syntactic sugar_. + +```js +class Book { + constructor(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + } + + getSummary() { + //... + } + + getAge() { + //... + } + + revise(newYear) { + //... + } +} + +const book1 = new Book('Book One', 'John Doe', 2013); +const book2 = new Book('Book Two', 'Jane Doe', 2016); +``` + +Similar to the non-ES6 case, all object instances created from the same class share a single copy of its underlying prototype object: + +```js +book1.__proto__ === Book.prototype // true +book2.__proto__ === Book.prototype // true +``` + +![6_classes](./assets/6_classes.png) +Figure 5. ES6 classes: identical to Figure 1, except that the Book constructor is now a `class`. + +Output from `console.log(book1)`: + +``` +Book {title: "Book One", author: "John Doe", year: 2013} + author: "John Doe" + title: "Book One" + year: 2013 + __proto__: + constructor: class Book + getAge: ƒ getAge() + getSummary: ƒ getSummary() + revise: ƒ revise(newYear) + __proto__: + constructor: ƒ Object() + hasOwnProperty: ƒ hasOwnProperty() + isPrototypeOf: ƒ isPrototypeOf() + ... +``` + + +## 7_subclasses + +Inheriting from a base class is easy using ES6 class syntax. A class can inherit from another class by means of the `extends` keyword. This automatically sets up the required prototypal linkage, as shown in Figure 6 below. + +```js +class Book { + constructor(title, author, year) { + this.title = title; + this.author = author; + this.year = year; + } + + getSummary() { + //... + } +} + +class Magazine extends Book { + constructor(title, author, year, month) { + super(title, author, year); + this.month = month; + } + + updateMonth(month) { + //... + } +} + +const mag1 = new Magazine('Mag One', 'John Doe', 2018, 'Jan'); +``` + +In OOP parlance, the class that inherits from the base class (in this example, **Magazine**) is called a **subclass** of the class it extends. The base class itself (here, **Book**) is called the **superclass**. + +![7_subclasses](./assets/7_subclasses.png) +Figure 6. ES6 class-based inheritance: `extends`. + +```js +console.log(mag1 instanceof Magazine); // true +console.log(mag1 instanceof Book); // true +console.log(mag1 instanceof Object); // true +``` + +Output from `console.log(mag1)`: + +``` +Magazine {title: "Mag One", author: "Jon Doe", year: 2018, month: "Jan"} + author: "Jon Doe" + month: "Jan" + title: "Mag One" + year: 2018 + __proto__: Book + constructor: class Magazine + updateMonth: ƒ updateMonth(month) + __proto__: + constructor: class Book + getSummary: ƒ getSummary() + __proto__: + constructor: ƒ Object() + hasOwnProperty: ƒ hasOwnProperty() + isPrototypeOf: ƒ isPrototypeOf() + ... +``` diff --git a/Week3/traversy_oop_crash/assets/2_constructor.png b/Week3/traversy_oop_crash/assets/2_constructor.png new file mode 100644 index 000000000..3273ed14b Binary files /dev/null and b/Week3/traversy_oop_crash/assets/2_constructor.png differ diff --git a/Week3/traversy_oop_crash/assets/3_prototypes.png b/Week3/traversy_oop_crash/assets/3_prototypes.png new file mode 100644 index 000000000..c6adfe891 Binary files /dev/null and b/Week3/traversy_oop_crash/assets/3_prototypes.png differ diff --git a/Week3/traversy_oop_crash/assets/4_inheritance.png b/Week3/traversy_oop_crash/assets/4_inheritance.png new file mode 100644 index 000000000..20b015418 Binary files /dev/null and b/Week3/traversy_oop_crash/assets/4_inheritance.png differ diff --git a/Week3/traversy_oop_crash/assets/6_classes.png b/Week3/traversy_oop_crash/assets/6_classes.png new file mode 100644 index 000000000..a682e3c1e Binary files /dev/null and b/Week3/traversy_oop_crash/assets/6_classes.png differ diff --git a/Week3/traversy_oop_crash/assets/7_subclasses.png b/Week3/traversy_oop_crash/assets/7_subclasses.png new file mode 100644 index 000000000..bee3ede9a Binary files /dev/null and b/Week3/traversy_oop_crash/assets/7_subclasses.png differ diff --git a/Week3/traversy_oop_crash/assets/function_proto.png b/Week3/traversy_oop_crash/assets/function_proto.png new file mode 100644 index 000000000..b873bf80a Binary files /dev/null and b/Week3/traversy_oop_crash/assets/function_proto.png differ diff --git a/Week3/traversy_oop_crash/index-all.html b/Week3/traversy_oop_crash/index-all.html new file mode 100644 index 000000000..2c521f00f --- /dev/null +++ b/Week3/traversy_oop_crash/index-all.html @@ -0,0 +1,23 @@ + + + + + + + Codestin Search App + + +

    Brad Traversy's OOP Crash Course

    + + + + diff --git a/Week3/traversy_oop_crash/index-all.js b/Week3/traversy_oop_crash/index-all.js new file mode 100644 index 000000000..c55ea7e5c --- /dev/null +++ b/Week3/traversy_oop_crash/index-all.js @@ -0,0 +1,13 @@ +'use strict'; + +{ + const select = document.getElementById('select'); + select.addEventListener('change', async () => { + console.clear(); + console.log(select.value); + const response = await fetch(select.value); + const code = await response.text(); + // eslint-disable-next-line no-eval + eval(code); + }); +} diff --git a/Week3/traversy_oop_crash/index.html b/Week3/traversy_oop_crash/index.html new file mode 100644 index 000000000..847313fc3 --- /dev/null +++ b/Week3/traversy_oop_crash/index.html @@ -0,0 +1,12 @@ + + + + + + + Codestin Search App + + + + + diff --git a/apps/hackyourinfo/index.js b/apps/hackyourinfo/index.js new file mode 100755 index 000000000..112296d8c --- /dev/null +++ b/apps/hackyourinfo/index.js @@ -0,0 +1,105 @@ +const express = require('express') +const fs = require('fs-extra') +const path = require('path') +const bodyParser = require('body-parser') +const cors = require('cors') + +const rootDir = path.resolve(__dirname) +const infoDir = path.join(rootDir, 'info') + +const app = express() + +app.use(bodyParser.json()) +app.use(cors()) + +app.post('/:name.json', async (request, response) => { + try { + const filename = path.join(infoDir, `${request.params.name}.json`) + await fs.ensureDir(infoDir) + await fs.writeFile(filename, JSON.stringify(request.body, null, 2)) + response.statusCode = 200 + response.json({ ok: true }) + } catch (error) { + response.statusCode = 500 + response.json({ error: "An error occurred" }) + console.error(error) + } + + response.end() +}) + +app.get('/_all.json', async (request, response) => { + try { + await fs.ensureDir(infoDir) + const files = await fs.readdir(infoDir) + const promises = files.map(file => fs.readFile(path.join(infoDir, file), 'utf8').then(raw => [file, raw])) + const raws = await Promise.all(promises) + + const result = {} + for (const [file, raw] of raws) { + result[file.replace(/\.json$/, '')] = JSON.parse(raw) + } + response.json(result) + } catch (error) { + response.statusCode = 500 + response.json({ error: "An error occurred" }) + console.error(error) + } + response.end() +}) + +app.get('/:name.json', async (request, response) => { + try { + const filename = path.join(infoDir, `${request.params.name}.json`) + await fs.ensureDir(infoDir) + const raw = await fs.readFile(filename, 'utf8') + response.json(JSON.parse(raw)) + } catch (error) { + if (error.code === 'ENOENT') { + response.statusCode = 404 + response.json({ error: "File not found" }) + } else { + response.statusCode = 500 + response.json({ error: "An error occurred" }) + console.error(error) + } + } + response.end() +}) + +app.delete('/_all.json', async (request, response) => { + try { + await fs.emptyDir(infoDir) + response.json({ ok: true }) + } catch (error) { + response.statusCode = 500 + response.json({ error: "An error occurred" }) + console.error(error) + } + response.end() +}) + +app.delete('/:name.json', async (request, response) => { + try { + await fs.ensureDir(infoDir) + await fs.unlink(path.join(infoDir, `${request.params.name}.json`)) + response.json({ ok: true }) + } catch (error) { + if (error.code !== 'ENOENT') { + response.statusCode = 500 + response.json({ error: "An error occurred" }) + console.error(error) + } else { + response.json({ ok: true }) + } + } + response.end() +}) + +app.use((request, response) => { + response.statusCode = 404 + response.json({ error: "Not found" }) + response.end() +}) + +app.listen(process.env.PORT || 80) \ No newline at end of file diff --git a/apps/hackyourinfo/package.json b/apps/hackyourinfo/package.json new file mode 100755 index 000000000..a226417ab --- /dev/null +++ b/apps/hackyourinfo/package.json @@ -0,0 +1,18 @@ +{ + "name": "hackyourinfo", + "version": "1.0.0", + "description": "Small webserver for class collaboration.", + "main": "index.js", + "author": "Joost Lubach", + "license": "MIT", + "private": false, + "dependencies": { + "body-parser": "^1.18.3", + "cors": "^2.8.5", + "express": "^4.16.4", + "fs-extra": "^7.0.1" + }, + "scripts": { + "start": "node ." + } +} diff --git a/apps/hackyourinfo/yarn.lock b/apps/hackyourinfo/yarn.lock new file mode 100755 index 000000000..ed49c5de4 --- /dev/null +++ b/apps/hackyourinfo/yarn.lock @@ -0,0 +1,383 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accepts@~1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +body-parser@1.18.3, body-parser@^1.18.3: + version "1.18.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" + integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + dependencies: + bytes "3.0.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "~1.6.3" + iconv-lite "0.4.23" + on-finished "~2.3.0" + qs "6.5.2" + raw-body "2.3.3" + type-is "~1.6.16" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express@^4.16.4: + version "4.16.4" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" + integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + dependencies: + accepts "~1.3.5" + array-flatten "1.1.1" + body-parser "1.18.3" + content-disposition "0.5.2" + content-type "~1.0.4" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.1.1" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.2" + path-to-regexp "0.1.7" + proxy-addr "~2.0.4" + qs "6.5.2" + range-parser "~1.2.0" + safe-buffer "5.1.2" + send "0.16.2" + serve-static "1.13.2" + setprototypeof "1.1.0" + statuses "~1.4.0" + type-is "~1.6.16" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" + integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.4.0" + unpipe "~1.0.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +iconv-lite@0.4.23: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ipaddr.js@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e" + integrity sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@~1.37.0: + version "1.37.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.37.0.tgz#0b6a0ce6fdbe9576e25f1f2d2fde8830dc0ad0d8" + integrity sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== + +mime-types@~2.1.18: + version "2.1.21" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.21.tgz#28995aa1ecb770742fe6ae7e58f9181c744b3f96" + integrity sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + dependencies: + mime-db "~1.37.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +parseurl@~1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +proxy-addr@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" + integrity sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.8.0" + +qs@6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + +raw-body@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" + integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + dependencies: + bytes "3.0.0" + http-errors "1.6.3" + iconv-lite "0.4.23" + unpipe "1.0.0" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +"statuses@>= 1.4.0 < 2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +type-is@~1.6.16: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= diff --git a/assets/API.png b/assets/API.png new file mode 100644 index 000000000..374cedca9 Binary files /dev/null and b/assets/API.png differ diff --git a/assets/OOP.png b/assets/OOP.png new file mode 100644 index 000000000..12adc9c5c Binary files /dev/null and b/assets/OOP.png differ diff --git a/assets/homework-submission.png b/assets/homework-submission.png new file mode 100644 index 000000000..d5962dee2 Binary files /dev/null and b/assets/homework-submission.png differ diff --git a/assets/javascript3.png b/assets/javascript3.png new file mode 100644 index 000000000..fe3fc019a Binary files /dev/null and b/assets/javascript3.png differ diff --git a/assets/pokemon-app.gif b/assets/pokemon-app.gif new file mode 100644 index 000000000..0eae9ca6a Binary files /dev/null and b/assets/pokemon-app.gif differ diff --git a/assets/stasel.png b/assets/stasel.png new file mode 100644 index 000000000..0ea55707c Binary files /dev/null and b/assets/stasel.png differ diff --git a/assets/submit-homework.png b/assets/submit-homework.png new file mode 100644 index 000000000..9d577a58e Binary files /dev/null and b/assets/submit-homework.png differ diff --git a/assets/trivia-app.gif b/assets/trivia-app.gif new file mode 100644 index 000000000..27be8dd2d Binary files /dev/null and b/assets/trivia-app.gif differ diff --git a/assets/weekflow.png b/assets/weekflow.png new file mode 100644 index 000000000..9da097126 Binary files /dev/null and b/assets/weekflow.png differ diff --git a/hackyourrepo-app/hyf.png b/hackyourrepo-app/hyf.png new file mode 100755 index 000000000..76bc5a13b Binary files /dev/null and b/hackyourrepo-app/hyf.png differ diff --git a/hackyourrepo-app/index.html b/hackyourrepo-app/index.html new file mode 100755 index 000000000..2b202e708 --- /dev/null +++ b/hackyourrepo-app/index.html @@ -0,0 +1,25 @@ + + + + + + + + + + + + Codestin Search App + + + + + + + diff --git a/hackyourrepo-app/script.js b/hackyourrepo-app/script.js new file mode 100755 index 000000000..a2206d1ed --- /dev/null +++ b/hackyourrepo-app/script.js @@ -0,0 +1,5 @@ +"use strict"; + +/* + Write here your JavaScript for HackYourRepo! +*/ diff --git a/hackyourrepo-app/style.css b/hackyourrepo-app/style.css new file mode 100755 index 000000000..5b3acae8a --- /dev/null +++ b/hackyourrepo-app/style.css @@ -0,0 +1,3 @@ +/* + Write here your CSS rules for HackYourRepo! +*/ diff --git a/hand-in-homework-guide.md b/hand-in-homework-guide.md new file mode 100644 index 000000000..710ff3cf3 --- /dev/null +++ b/hand-in-homework-guide.md @@ -0,0 +1,37 @@ +# How to hand in homework + +In this module you'll submit your homework only using GIT and GitHub. + +1. [GitHub](https://www.github.com/HackYourFuture/JavaScript3) + +## 1. GitHub homework guide + +HYF Video + +Watch the video (by clicking the image) or go through the following walk-through to learn how to submit your homework: + +ONE TIME ONLY (START OF EVERY MODULE) + +1. Create a [fork](https://help.github.com/en/articles/fork-a-repo) of the following repository: [HackYourHomework/JavaScript3](https://www.github.com/hackyourhomework/javascript3). You do this by using the `fork` option on the top right +2. Navigate to the URL of the forked repository (it should be in your personal GitHub account, under "repositories", under the name `/JavaScript3`) +3. Clone the repository, using SSH, to your local machine. You can do this by typing in `git clone ` in the command line +4. On your local machine, navigate to the folder using the command line +5. Make sure you've cloned it correctly by running `git status` and `git remote -v` from the command line + +EVERY WEEK + +1. Create a new branch for each week you have homework. For example, for the week 1 homework for JavaScript3 create a branch called `week-1-homework-YOUR_NAME` +2. Inside the week folder, create another folder called `homework`. Create your homework files in there, while on the correct branch +3. Once you're finished, `add` and `commit` everything. Make the commit message meaningful, for example `finished project for homework week1` +4. Push the branch to your forked repository (`/JavaScript3`) +5. On the GitHub page of this repository, click on the `create pull request` button. Make sure the `base repository` is `HackYourHomework/JavaScript3`, on branch master +6. Give the pull request a title in the following format: + +```markdown +Homework week 1 +``` + +7. Submit the pull request from your forked repository branch into the `master` branch of the original repository (`HackYourHomework/JavaScript3`) +8. Do a little victory dance because you did it! Good job! + +If you have any questions or if something is not entirely clear ¯\\\_(ツ)\_/¯, please ask/comment on Slack! diff --git a/homework/.eslintrc b/homework/.eslintrc deleted file mode 100644 index ae8189517..000000000 --- a/homework/.eslintrc +++ /dev/null @@ -1,47 +0,0 @@ -{ - "env": { - "browser": true, - "commonjs": true, - "es6": true, - "node": true - }, - "parserOptions": { - "ecmaVersion": 2017, - "ecmaFeatures": { - "jsx": true - }, - "sourceType": "module" - }, - "extends": [ - "eslint:recommended" - ], - "rules": { - "no-const-assign": "warn", - "no-this-before-super": "warn", - "no-undef": "warn", - "no-unreachable": "warn", - "no-unused-vars": "warn", - "constructor-super": "warn", - "valid-typeof": "warn", - "no-var": "warn", - "prefer-const": "warn", - "no-multiple-empty-lines": "warn", - "eol-last": [ - "error", - "always" - ], - "no-console": "off", - "camelcase": "warn", - "eqeqeq": [ - "error", - "always", - { - "null": "ignore" - } - ], - "semi": [ - "warn", - "always" - ] - } -} \ No newline at end of file diff --git a/homework/src/App.js b/homework/src/App.js deleted file mode 100644 index 3e0660ccc..000000000 --- a/homework/src/App.js +++ /dev/null @@ -1,81 +0,0 @@ -'use strict'; - -/* global Util, Repository, Contributor */ - -class App { - constructor(url) { - this.initialize(url); - } - - /** - * Initialization - * @param {string} url The GitHub URL for obtaining the organization's repositories. - */ - async initialize(url) { - // Add code here to initialize your app - // 1. Create the fixed HTML elements of your page - // 2. Make an initial XMLHttpRequest using Util.fetchJSON() to populate your element with sorted