diff --git a/.eslintrc.json b/.eslintrc.json index 53642f8ce..1c1b99549 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,5 +1,5 @@ { - "extends": ["airbnb", "prettier"], + "extends": ["airbnb-base", "prettier"], "plugins": ["prettier"], "env": { "browser": true, @@ -9,7 +9,8 @@ "page": true, "browser": true, "context": true, - "jestPuppeteer": true + "jestPuppeteer": true, + "axios": "readonly" }, "rules": { "prettier/prettier": ["error"], @@ -17,6 +18,7 @@ "strict": "off", "no-plusplus": "off", "linebreak-style": "off", + "no-restricted-syntax": "off", "no-param-reassign": [ "error", { 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 f9ecd22b9..e14914b2e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,12 @@ "editor.detectIndentation": false, "editor.tabSize": 2, "cSpell.words": [ + "READYSTATE", + "Traversy", + "ajaxcrash", "networkidle", - "tabindex" + "remarcmij", + "tabindex", + "whiteframe" ] -} \ No newline at end of file +} diff --git a/README.md b/README.md index fa97dad57..1cf77c02d 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ or links, please share them by [opening a pull request](https://github.com/HackY # HackYourFuture JavaScript 3 -Here you can find course content and homework for the JavaScript3 modules +Here you can find course content and homework for the JavaScript3 modules. |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)| +|1.|• Structure for a basic SPA (Single Page Application)
• AJAX & XMLHttpRequests
• API calls|[Reading Week 1](/Week1/README.md)|[Homework Week 1](/Week1/MAKEME.md)| +|2.|• Event Loop (order of execution)
• Promises|[Reading Week 2](/Week2/README.md)|[Homework Week 2](/Week2/MAKEME.md)| +|3.|• fetch, axios
• async/await
• try...catch
• The `this` keyword
• call, apply, bind
• Object Oriented Programming and ES6 Classes|[Reading Week 3](/Week3/README.md)|[Homework Week 3](/Week3/MAKEME.md)| __Kind note:__ @@ -18,6 +18,6 @@ We expect you to __always__ come prepared to the class on Sunday. ### 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. -*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 :)* +*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/MAKEME.md b/Week1/MAKEME.md index c09be166f..515032461 100644 --- a/Week1/MAKEME.md +++ b/Week1/MAKEME.md @@ -19,14 +19,12 @@ _This homework is more extensive and challenging than previous homework! Please 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: +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 in the first week are as follows: -- 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. +- The application should fetch repository information for the HYF GitHub account and display summary information for each repository. +- This list of repositories should be sorted alphabetically by repository name. -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. +Figure 1 below shows an example of what your application could look like. ![UI Example](./assets/hyf-github.png) @@ -48,11 +46,7 @@ If you open this URL in the browser (_try it!_) you will receive JSON data about 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. -#### 1.2.2 Get contributor information for a repository - -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. - -#### 1.2.3 GitHub API documentation +#### 1.2.2 GitHub API documentation 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. @@ -70,11 +64,11 @@ While you do not need to read this guide in detail, it is recommended that you r You will be working on the 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. -| Week | Branch | Assignment | -| :--: | ------- | -------------------------------------------------------------------------------------------------------------------------------- | -| 1 | `week1` | - Create a basic application using callbacks to handle network requests. | -| 2 | `week2` | Based on the `week1` branch:
- Refactor the callbacks to promises.
- Make the UI responsive. | -| 3 | `week3` | Based on the `week2` branch:
- Refactor the application to use ES6 Classes and async/await.
- Make the app ARIA-compliant. | +| Week | Branch | Assignment | +| :--: | ------- | ---------- | +| 1 | `week1` | - Create a basic application using callbacks to handle network requests. | +| 2 | `week2` | Based on the `week1` branch:
- Display details on a single repository and its contributors
- Refactor the callbacks to promises. | +| 3 | `week3` | Based on the `week2` branch:
- Refactor the application to use `fetch` and `async`/`await`.
- Reuse portions of the code to complete a provided Object Oriented (OOP) version of the application that uses ES6 classes. | Table 1. Homework schedule @@ -83,17 +77,13 @@ You will be working on the same application during the next three weeks. For eac 1. Fork the JavaScript3 repository (_this repository_) to your own GitHub account. 2. Clone the fork to your laptop. 3. Open the newly created `JavaScript3` folder from the cloned repository in VSCode. -4. Install the following extension in VSCode: - - **Prettier - Code formatter**. - -5. Open a Terminal window in VSCode and type the following command to install Prettier and ESLint tools as required for the homework: +4. Open a Terminal window in VSCode and type the following command to install Prettier and ESLint tools as required for the homework: ``` npm install ``` -6. Create a new branch for the week 1 homework with the following command: +5. Create a new branch for the week 1 homework with the following command: ``` git checkout -b week1 @@ -135,37 +125,23 @@ _**Do not change or delete any files outside of the `homework` folder!**_ | `createAndAppend` | A utility function for easily creating and appending HTML elements. | | `main` | Contains the start-up code for the application. | - `index.js` also contains a constant with the URL for the HYF repositories as listed in section 2.2.1: + `index.js` also contains a constant with the URL required for fetching information about the HYF repositories: ```js const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; ``` -3. Open the `index.html` file in your browser. Notice that it produces the same JSON output that you saw previously when you opened the URL directly in the browser. +3. Open the `index.html` file in your browser. You will see an unordered list with the names of the HYF repositories. -4. Review the `main()` function in `index.js` and examine how this code renders the JSON output in the browser by means of a `pre` HTML element (for demonstration purposes). +4. Review the `main()` function in `index.js` and examine how this code fetches the JSON data and calls renders the data as unordered list in the web page. ### 1.6 Week 1 Assignment -The assignment is to produce an application similar to the one illustrated in Figure 1 above. - -It should include the following components: - -1. An HTML `select` element from which the user can select a HYF repository. This `select` element must be populated with `option` elements, one for each HYF repository. -2. A left-hand column that displays basic information about the selected repository. -3. A right-hand column that displays a list of contributors to the repository. +1. The assignment is to produce an application similar to the one illustrated in Figure 1 above. - > In case you run out of time, you can also do the contributors list in week 2. +2. You should render network errors to the DOM (see Figure 2 below for an example). Do not use `console.log` as regular users will not see the console output. Use the predefined `alert-error` class from `style.css` to style your error. -**Functional Requirements:** - -1. The list of repositories in the `select` element should be sorted (case-insensitive) on repository name. -2. At start-up your application should display information about the first repository as displayed in the `select` element. -3. When the user changes the selection, the information in the web page should be refreshed for the newly selected repository. -4. You should be able to click on the repository name of the selected repository to open a new browser tab with the GitHub page for that repository. -5. You should be able to click on a contributor to open a new browser tab with the GitHub page for that contributor. -6. You should render network errors to the DOM (see Figure 2 below for an example). Do not use `console.log` as regular users will not see the console output. Use the predefined `alert-error` class from `style.css` to style your error. -7. Your UI should be responsive. Try it with Chrome Developer Tools in the browser, using a mobile phone format and a tablet format, portrait and landscape. If necessary, you can also do this work in week 2. +3. Your UI should be responsive. Try it with Chrome Developer Tools in the browser, using a mobile phone format and a tablet format, portrait and landscape. If necessary, you can also do this work in week 2. ![Error rendering](./assets/hyf-github-error.png) @@ -179,19 +155,11 @@ It should include the following components: **`style.css`** -- Add your own styling. - -**Hints:** +- Add your own CSS styling. Use `style.css` for all your styling your HTML. Avoid using JavaScript for styling unless there is a genuine need. -- Add one `option` element per repository to the `select` element, where each `option` element has the array index of the repository as its `value` attribute and the name of the repository as its text content: + **You are not allowed to use a CSS library such as Bootstrap.** - ```html - - ``` +**Hints:** * To sort the list repositories use [`.sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) and [`.localeCompare()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare). @@ -199,11 +167,12 @@ It should include the following components: * To force a `404` network error so that you can test the rendering of errors, change the URL to make an invalid GitHub request, e.g. append an `x` to `orgs`: `orgsx`. + ### 1.7 Handing in your homework If necessary, review the instructions how to [Hand in homework](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/homework_pr.md) using GitHub pull request. -To test whether your code will be accepted when you submit your homework as a pull request you need to ensure that it does not contain ESLinr errors. Open a terminal window in VSCode and type the following command: +To test whether your code will be accepted when you submit your homework as a pull request you need to ensure that it does not contain ESLint errors. Open a terminal window in VSCode and type the following command: ``` npm test diff --git a/Week1/README.md b/Week1/README.md index 6756bb92d..4e586c32d 100644 --- a/Week1/README.md +++ b/Week1/README.md @@ -3,32 +3,73 @@ ``` In week one we will discuss the following topics: • Structure for a basic SPA (Single Page Application) -• XMLHttpRequests +• AJAX & XMLHttpRequests • API calls ``` Here are resources that we like you to read as a preparation for the first lecture: -### Fundamentals +## 1. DOM manipulation -- [XMLHttpRequest](../../../../fundamentals/blob/master/fundamentals/XMLHttpRequest.md) +To refresh your DOM manipulation skills, watch this YouTube video series from Traversy Media: -### APIs +- [JavaScript DOM Crash Course](https://youtu.be/0ik6X4DJKCc). -- Read about APIS: https://www.programmableweb.com/api-university/what-are-apis-and-how-do-they-work +You will be using these particular DOM manipulation methods and properties in the JS3 homework for the next three weeks: -### XMLHttpRequests +#### Course Video Part 1 (39 mins): + +- `document.getElementById()` +- `element.textContent` + +#### Course Video Part 2 (21 mins): + +- `document.createElement()` +- `element.setAttribute()` +- `element.appendChild()` + +#### Course Video Part 3 (34 mins): + +- `change` event (` + + + + + ``` -You will continue to work on the files `index.js` and (possibly) `style.css`. +* To sort the list repositories use [`.sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) and [`.localeCompare()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare). -- Complete your GitHub app code from the previous week, if needed, to meet the requirements from that week's assignment. -- Replace all asynchronous callbacks (e.g. as used with `XMLHttpRequest`) by ES6 promises. -- Beautify your app's styling. -- If not yet completed in week 1, make your app responsive (use CSS media queries and [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)). +* Use CSS media queries and [Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) to make the UI responsive. -### 3.3 Handing in your homework +### Handing in your homework If necessary, review the instructions how to [Hand in homework](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/homework_pr.md) using GitHub pull request. -To test whether your code will be accepted when you submit your homework as a pull request you need to ensure that it does not contain ESLinr errors. Open a terminal window in VSCode and type the following command: +To test whether your code will be accepted when you submit your homework as a pull request you need to ensure that it does not contain ESLint errors. Open a terminal window in VSCode and type the following command: ``` npm test diff --git a/Week2/README.md b/Week2/README.md index e55018f74..0955302f2 100644 --- a/Week2/README.md +++ b/Week2/README.md @@ -9,16 +9,24 @@ In week two we will discuss the following topics: Here are resources that we like you to read as a preparation for the second lecture: -### Async VS Sync +## Async vs Sync -- [Stacks/Queues](https://www.youtube.com/watch?v=wjI1WNcIntg) (5 mins) -- Read about Asynchronous vs. Synchronous programming: http://www.hongkiat.com/blog/synchronous-asynchronous-javascript/ -- [Why closures are helpful with async code](http://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript) +Watch this YouTube video (24 mins) from Traversy Media, introducing **promises** and **async/await**. In this week's lecture and homework we will focus on promises as an elegant replacement for callbacks. Next week we will cover async/await, which provides an alternative syntax for 'consuming' promises. -### Fundamentals +- [Async JS Crash Course - Callbacks, Promises, Async Await](https://youtu.be/PoRJizFvM7s) -- [Event Loop](../../../../fundamentals/blob/master/fundamentals/event_loop.md) -- [Promises](../../../../fundamentals/blob/master/fundamentals/promises.md) +Read about Asynchronous vs Synchronous: + +- [Understanding Synchronous and Asynchronous JavaScript](http://www.hongkiat.com/blog/synchronous-asynchronous-javascript/) + +## Event Loop + +- HYF Fundamental - [The Event Loop](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/event_loop.md) + +## ES6 Promises + +- [A Simple Guide to ES6 Promises](https://codeburst.io/a-simple-guide-to-es6-promises-d71bacd2e13a) +- HYF Fundamental - [Promises](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/promises.md) _Please go through the material and come to class prepared!_ diff --git a/Week2/assets/week2.png b/Week2/assets/week2.png new file mode 100644 index 000000000..0a3be59cd Binary files /dev/null and b/Week2/assets/week2.png differ diff --git a/Week2/traversy_async_crash/README.md b/Week2/traversy_async_crash/README.md new file mode 100644 index 000000000..cc2b9076e --- /dev/null +++ b/Week2/traversy_async_crash/README.md @@ -0,0 +1,4 @@ +``` +// source: Async JS Crash Course - Callbacks, Promises, Async Await +// https://youtu.be/PoRJizFvM7s +``` \ No newline at end of file diff --git a/Week2/traversy_async_crash/callbacks.js b/Week2/traversy_async_crash/callbacks.js new file mode 100644 index 000000000..d2bf54d76 --- /dev/null +++ b/Week2/traversy_async_crash/callbacks.js @@ -0,0 +1,23 @@ +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, callback) { + setTimeout(() => { + posts.push(post); + callback(); + }, 2000); +} + +createPost({ title: 'Post Three', body: 'This is post three' }, getPosts); diff --git a/Week2/traversy_async_crash/index.html b/Week2/traversy_async_crash/index.html new file mode 100644 index 000000000..94b42e6e0 --- /dev/null +++ b/Week2/traversy_async_crash/index.html @@ -0,0 +1,13 @@ + + + + + + + Codestin Search App + + + + + + 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/MAKEME.md b/Week3/MAKEME.md index dcdb081fe..dabca83d2 100644 --- a/Week3/MAKEME.md +++ b/Week3/MAKEME.md @@ -13,11 +13,20 @@ _Deadline Monday_ - Fix Requested Changes (if any) on the Pull Request. -## Step 2 +## Step 2: Create a new branch + +1. Make sure that your `week2` branch is checked out and clean. +2. Create a new branch for the week 3 homework: + + ``` + git checkout -b week3 + ``` + +## Step 3 **_Deadline Thursday_** -### 2.1 Preparation +### 3.1 Preparation **Read the fundamental pages on:** @@ -33,7 +42,7 @@ The homework for week 3 will build on the work you did in week 2. You will creat git checkout -b week3 ``` -### 2.2 Assignment +### 3.2 Assignment The assignment consists of two parts. @@ -44,13 +53,13 @@ In the first part you will modify the 'promise' homework in the from week 2 (in In the second part you will 'refactor' your application to use ES6 classes. For this, you need to modify the files in the `homework-classes` folder. -#### 2.2.1 Replace XMLHttpRequest with fetch +#### 3.2.1 Replace XMLHttpRequest with fetch Replace `XMLHttpRequest` in the `fetchJSON` function with `fetch`. Because `fetch` returns a promise out of the box there is no need create a promise yourself with `new Promise(...)`. > `fetch` does not throw an error for HTTP errors. Review the documentation for [`response.ok`](https://developer.mozilla.org/en-US/docs/Web/API/Response/ok) for a clue how detect HTTP errors. -#### 2.2.2 async/await +#### 3.2.2 async/await **Instructions:** @@ -58,38 +67,72 @@ Replace `XMLHttpRequest` in the `fetchJSON` function with `fetch`. Because `fetc 2. Make sure that your error handling code still works. See the week2 MAKEME on how to force an error response from GitHub. -#### 2.2.3 ES6 Classes +#### 3.2.3 Object Orientation and ES6 classes **_Deadline Saturday_** -This final assignment requires you to go the extra mile and master Object Oriented Programming and ES6 classes. +This final assignment requires you to go the extra mile and get acquainted with Object Oriented Programming and ES6 classes. + +Object Oriented Programming is a vast topic and in this homework we can only scratch the surface. The approach we have taken here is for you, as aspiring junior developer, to complete an application for which the groundwork has been done by an experienced developer. You may find it difficult to understand the full details of the application, however this is not unlike a real world situation where you will be expected to make relative small modifications to a complex application, without breaking anything. + +> Note that OOP does not play the same, central role in JavaScript as it does in other languages, such as Java, C++ and C#. In JavaScript it is more common to decompose a larger application into JavaScript modules (but which could still contain classes), as you will come across in the Node.js module. -> The files to be modified are in the **homework-classes** folder. +> The relevant files for this part of the homework can be found in the **homework-classes** folder. -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`. +| File | Description | +| ------------------- | ----------- | +| index.html | The application's HTML file. | +| style.css | CSS styling. | +| hyf.png | The HYF logo. | +| App.js | The **App** class is the main container class for the app. | +| Observable.js | The **Observable** class is a base class implementing functionality of the Observer pattern. | +| Model.js | The **Model** class is concerned with all data handling (e.g. fetching). Extends the Observable class. | +| HeaderView.js | The **HeaderView** class renders the header with the select element. | +| RepoView.js | The **RepoView** class renders the details for the selected repository. | +| ContributorsView.js | The **ContributorsView** class renders the contributors for the selected repository. | +| ErrorView.js | The **ErrorView** class renders an error, if present. | +| Util.js | The **Utility** class provides (static) utility functions. | -| File | Description | -| ---------------- | -------------------------------------------------------------------------------------------- | -| `index.html` | The application's HTML file. | -| `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. Copy CSS styling from your non-OOP version of the homework into **style.css**. +2. Add and adapt code from your non-OOP version of the homework to **RepoView.js** and **ContributorsView.js**. +3. Do not change any other files at this point. -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. +Modify the **RepoView.js** and **ContributorsView.js** files, by adding and adapting code from your non-OOP version of the homework to these files. You should also copy the styling from your non-OOP version. Other files should not be modified. + +Figure 1 below illustrates the interrelationship between the various classes in the application using a [UML Class Diagram](https://en.wikipedia.org/wiki/Class_diagram). This particular one was created with with **LucidChart** ([YouTube tutorial](https://youtu.be/UI6lqHOVHic), 10 mins). + +![JavaScript3_classes](./assets/JavaScript3_classes.png) +Figure 1. A UML Class Diagram showing the interrelationship between the classes in this app. + +You can conclude the following from this diagram: + +1. The **Model** class **extends** (_inherits from_) the **Observable** class. Views (i.e., 'observers') can subscribe to the Model and get notified on data updates. + +2. There are four View classes that implement the **IObservable** interface, i.e. they implement the required `update()` method: + - **HeaderView** + - **RepoView** + - **ContributorsView** + - **ErrorView**. + +3. The **SelectView** class calls the `fetchData()` method from the **Model** class to request a data fetch. _Read:_ - 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) -#### 2.2.4 ARIA-compliance (BONUS) +#### 3.2.4 axios + +1. Modify the `fetchJSON` static method in **Model.js** to replace **fetch** with **axios**. +2. Add a ` + + 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/homework-classes/App.js b/homework-classes/App.js index 7cc1c5772..8788f8b85 100644 --- a/homework-classes/App.js +++ b/homework-classes/App.js @@ -1,78 +1,56 @@ 'use strict'; -/* global Util, Repository, Contributor */ - -class App { - constructor(url) { - this.mainContainer = null; - 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 + * and its