diff --git a/README.md b/README.md
index 34103e174..f2daf04b7 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,3 @@
-> 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).
# Module #4 - JavaScript 3: Object-Oriented Programming and working with APIs (Frontend)
@@ -81,8 +79,10 @@ With this out of the way we can get started!
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!
+If you feel ready for the next challenge, click [here](https://www.github.com/SocialHackersCodeSchool/Node.js) to go to Node.js!
+
+## Credit:
+This curriculum is developed by HackYourFuture, modifications, and changes can be found in this Fork. (edited)
-_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 :)_
This work is licensed under a Creative Commons Attribution 4.0 International License.
diff --git a/Week1/MAKEME.md b/Week1/MAKEME.md
index 7b3cb47b8..645733b59 100644
--- a/Week1/MAKEME.md
+++ b/Week1/MAKEME.md
@@ -73,7 +73,7 @@ Figure 1 below shows an example of what your application will look like.
This application does 2 things:
-1. It makes connection to the GitHub API and retrieves all the repositories found in the [HackYourFuture account](https://www.github.com/hackyourfuture).
+1. It makes connection to the GitHub API and retrieves all the repositories found in the [HackYourFuture account](https://www.github.com/SocialHackersCodeSchool).
2. It displays those repositories in an alphabetically-oreded list. When a user clicks on any of the repository names it will show more details about it.
### Getting an overview
diff --git a/Week1/homework/jsexercises/DogGallery/dogGallery.css b/Week1/homework/jsexercises/DogGallery/dogGallery.css
new file mode 100644
index 000000000..e2b355fe4
--- /dev/null
+++ b/Week1/homework/jsexercises/DogGallery/dogGallery.css
@@ -0,0 +1,73 @@
+* {
+ padding: 0px;
+ margin: 0px;
+ box-sizing: border-box;
+ }
+
+ body {
+ background: rgb(44, 43, 43);
+ }
+
+ body div {
+ float: left;
+ padding-bottom: 10vh;
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ color: white;
+ }
+
+ body div div {
+ padding: 2%;
+ max-height: 20%;
+ width: 100%;
+ display: flex;
+ flex-flow: row;
+ justify-content: center;
+ }
+
+ h1 {
+ margin-top: 50px;
+ }
+
+ p {
+ margin-top: 30px;
+ margin-bottom: 10px;
+ font-size: 120%;
+ }
+
+ img {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 2vh;
+ margin-bottom: 2vh;
+ height: 20vh;
+ }
+
+ input[type=button] {
+ width: 30%;
+ height: 50%;
+ margin-right: 3%;
+ margin-left: 3%;
+ font-size: 4vh;
+ }
+
+ .leftSide {
+ width: 20%;
+ background: rgb(44, 43, 43);
+ }
+
+ .centerSide {
+ height: auto;
+ min-height: 100vh;
+ width: 60%;
+ background: rgb(0, 0, 0);
+ }
+
+ .rightSide {
+ width: 20%;
+ background: rgb(44, 43, 43);
+ }
+
+
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/DogGallery/dogGallery.html b/Week1/homework/jsexercises/DogGallery/dogGallery.html
new file mode 100644
index 000000000..d9dc97114
--- /dev/null
+++ b/Week1/homework/jsexercises/DogGallery/dogGallery.html
@@ -0,0 +1,102 @@
+
+
+
+
+ Time
+
+
+
+
+
 
+
+
+
+
Dog Gallery
+
+
+
+
+
+
+
+
+
 
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/DogGallery/dogGallery.js b/Week1/homework/jsexercises/DogGallery/dogGallery.js
new file mode 100644
index 000000000..a19f88239
--- /dev/null
+++ b/Week1/homework/jsexercises/DogGallery/dogGallery.js
@@ -0,0 +1,66 @@
+
+// Inside the same file write two programs: one with XMLHttpRequest, and the other with axios
+// Each function should make an API call to the given endpoint: https://xkcd.com/info.0.json
+// Log the received data to the console
+// Render the img property into an tag in the DOM
+// Incorporate error handling
+
+// STEP 1 with XMLHttpRequest
+//const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
+//const xhr2 = new XMLHttpRequest();
+/*
+const getData = () => {
+ const promise = new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', "https://xkcd.com/info.0.json", true);
+ xhr.send();
+ xhr.addEventListener("readystatechange", processRequest, false);
+
+ function processRequest(e) {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ const dato = JSON.parse(xhr.responseText);
+ resolve(dato); // We could just send dato for all the general data
+ }
+ }
+
+ xhr.onerror = () => {
+ reject("Something ain't going well...");
+ }
+ });
+ return promise;
+}
+
+getData()
+ .then(responseData => {
+ console.log(responseData);
+ loadNewElements();
+ })
+ .catch(err => {
+ console.log(err);
+ });
+*/
+// STEP 2 AXIOS
+
+const axios = require('axios'); // We have to load in the library first
+
+axios
+ .get('https://xkcd.com/info.0.json')
+ .then(responseText => {
+ //const specificData = responseText.data.results[0].name.first;
+ console.log(responseText.data.img); // We could just send responseText.data for all the general data
+ })
+ .catch(function(error) {
+ console.log("Something went wrong. Error '" + error + "' detected.");
+ });
+
+
+ function loadNewElements(){
+ const div = document.querySelector(".centerSide");
+ const parr1 = document.createElement("p");
+ // const parr2 = document.createElement("p");
+ // const img1 = document.createElement("img");
+ // const img2 = document.createElement("img");
+
+ parr1.innerHTML = "Image with XHR:"
+ div.appendChild(parr1);
+ }
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/Humor/humor.css b/Week1/homework/jsexercises/Humor/humor.css
new file mode 100644
index 000000000..ad118fa17
--- /dev/null
+++ b/Week1/homework/jsexercises/Humor/humor.css
@@ -0,0 +1,45 @@
+* {
+ padding: 0px;
+ margin: 0px;
+ box-sizing: border-box;
+ }
+
+ body div {
+ height: 100vh;
+ float: left;
+ display: flex;
+ flex-flow: column;
+ align-items: center;
+ color: white;
+ }
+
+ h1 {
+ margin-top: 50px;
+ }
+
+ p {
+ margin-top: 30px;
+ margin-bottom: 10px;
+ font-size: 120%;
+ }
+
+ img {
+ width: 40vw;
+ }
+
+ .leftSide {
+ width: 20%;
+ background: rgb(44, 43, 43);
+ }
+
+ .centerSide {
+ width: 60%;
+ background: rgb(0, 0, 0);
+ }
+
+ .rightSide {
+ width: 20%;
+ background: rgb(44, 43, 43);
+ }
+
+
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/Humor/humor.html b/Week1/homework/jsexercises/Humor/humor.html
new file mode 100644
index 000000000..d43c3063e
--- /dev/null
+++ b/Week1/homework/jsexercises/Humor/humor.html
@@ -0,0 +1,85 @@
+
+
+
+
+ Time
+
+
+
+
+
 
+
+
+
+
XHR and AXIOS
+
+
+
+
 
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/Humor/humor.js b/Week1/homework/jsexercises/Humor/humor.js
new file mode 100644
index 000000000..a19f88239
--- /dev/null
+++ b/Week1/homework/jsexercises/Humor/humor.js
@@ -0,0 +1,66 @@
+
+// Inside the same file write two programs: one with XMLHttpRequest, and the other with axios
+// Each function should make an API call to the given endpoint: https://xkcd.com/info.0.json
+// Log the received data to the console
+// Render the img property into an tag in the DOM
+// Incorporate error handling
+
+// STEP 1 with XMLHttpRequest
+//const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
+//const xhr2 = new XMLHttpRequest();
+/*
+const getData = () => {
+ const promise = new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', "https://xkcd.com/info.0.json", true);
+ xhr.send();
+ xhr.addEventListener("readystatechange", processRequest, false);
+
+ function processRequest(e) {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ const dato = JSON.parse(xhr.responseText);
+ resolve(dato); // We could just send dato for all the general data
+ }
+ }
+
+ xhr.onerror = () => {
+ reject("Something ain't going well...");
+ }
+ });
+ return promise;
+}
+
+getData()
+ .then(responseData => {
+ console.log(responseData);
+ loadNewElements();
+ })
+ .catch(err => {
+ console.log(err);
+ });
+*/
+// STEP 2 AXIOS
+
+const axios = require('axios'); // We have to load in the library first
+
+axios
+ .get('https://xkcd.com/info.0.json')
+ .then(responseText => {
+ //const specificData = responseText.data.results[0].name.first;
+ console.log(responseText.data.img); // We could just send responseText.data for all the general data
+ })
+ .catch(function(error) {
+ console.log("Something went wrong. Error '" + error + "' detected.");
+ });
+
+
+ function loadNewElements(){
+ const div = document.querySelector(".centerSide");
+ const parr1 = document.createElement("p");
+ // const parr2 = document.createElement("p");
+ // const img1 = document.createElement("img");
+ // const img2 = document.createElement("img");
+
+ parr1.innerHTML = "Image with XHR:"
+ div.appendChild(parr1);
+ }
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/PROJECT/hyf.png b/Week1/homework/jsexercises/PROJECT/hyf.png
new file mode 100644
index 000000000..76bc5a13b
Binary files /dev/null and b/Week1/homework/jsexercises/PROJECT/hyf.png differ
diff --git a/Week1/homework/jsexercises/PROJECT/index.html b/Week1/homework/jsexercises/PROJECT/index.html
new file mode 100644
index 000000000..b70aa21a7
--- /dev/null
+++ b/Week1/homework/jsexercises/PROJECT/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
HYF Repositories
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/PROJECT/index.js b/Week1/homework/jsexercises/PROJECT/index.js
new file mode 100644
index 000000000..bf6c0edfb
--- /dev/null
+++ b/Week1/homework/jsexercises/PROJECT/index.js
@@ -0,0 +1,115 @@
+'use strict';
+
+{
+ function fetchJSON(url, cb) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ cb(null, xhr.response);
+ } else {
+ cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.onerror = () => cb(new Error('Network request failed'));
+ xhr.send();
+ }
+
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+
+ Object.entries(options).forEach(([key, value]) => {
+ // JS3-1 START Modified Lines
+ if (key === 'errText') {
+ elem.innerHTML = value;
+ } else {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ if (key === 'text') {
+ innerSpan.innerHTML += "Repository: ";
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = options.url;
+ innerSpan.appendChild(innerLink);
+ innerSpan.innerHTML += " ";
+ } else if (key === 'desc') {
+ innerSpan.innerHTML += "Description: " + value + " ";
+ } else if (key === 'forks') {
+ innerSpan.innerHTML += "Forks: " + value + " ";
+ } else if (key === 'update') {
+ innerSpan.innerHTML += "Update: " + formatDate(value);
+ } else if (key === 'url') {
+ console.log(innerSpan.innerHTML);
+ }
+ // JS3-1 END Modified Lines
+ else {
+ elem.setAttribute(key, value);
+ }
+ elem.appendChild(innerSpan);
+ }
+ });
+ parent.appendChild(elem);
+ //elem.innerHTML += ""; // JS3-1 Modified Line
+ return elem;
+ }
+
+ // JS3-1 Modified line
+ function renderRepoDetails(repo, ul) {
+ createAndAppend('li', ul, {
+ text: repo.name, desc: repo.description, forks: repo.forks,
+ update: repo.updated_at, url: repo.html_url
+ });
+ }
+
+ // JS3-1 START Function that formats the Dates
+ function formatDate(sentDate) {
+ let date = new Date(sentDate);
+ let hours = date.getHours();
+ let minutes = date.getMinutes();
+ let seconds = date.getSeconds();
+ let ampm = hours >= 12 ? 'PM' : 'AM';
+ hours = hours % 12;
+ hours = hours ? hours : 12; // the hour '0' should be '12'
+ minutes = minutes < 10 ? '0' + minutes : minutes;
+ seconds = seconds < 10 ? '0' + seconds : seconds;
+ const strTime = hours + ':' + minutes + ':' + seconds + ' ' + ampm;
+ return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + ", " + strTime;
+ }
+ // JS3-1 END
+ // JS3-1 START Function that sorts th array
+ function sortArray(arrayToSort) {
+ arrayToSort.sort(function (a, b) {
+ if (a.name.toLowerCase() > b.name.toLowerCase()) {
+ return 1;
+ }
+ if (a.name.toLowerCase() < b.name.toLowerCase()) {
+ return -1;
+ }
+ // a must be equal to b
+ return 0;
+ });
+ return arrayToSort;
+ }
+ // JS3-1 END
+
+ function main(url) {
+ fetchJSON(url, (err, repos) => {
+ const root = document.getElementById('root');
+ if (err) {
+ createAndAppend('div', root, {
+ errText: err.message, //JS3-1 Modified Line
+ class: 'alert-error',
+ });
+ return;
+ }
+ const ul = createAndAppend('ul', root);
+ repos = sortArray(repos); //JS3-1 Sort the array of objects before displaying them
+ repos.forEach(repo => renderRepoDetails(repo, ul));
+ });
+ }
+
+const HYF_REPOS_URL =
+ 'https://api.github.com/orgs/HackYourFuture/repos?per_page=10';
+ window.onload = () => main(HYF_REPOS_URL);
+}
diff --git a/Week1/homework/jsexercises/PROJECT/style.css b/Week1/homework/jsexercises/PROJECT/style.css
new file mode 100644
index 000000000..fb5757a62
--- /dev/null
+++ b/Week1/homework/jsexercises/PROJECT/style.css
@@ -0,0 +1,50 @@
+* {
+ padding: 0px;
+ margin: 0px;
+ box-sizing: border-box;
+}
+
+li {
+ margin: 3px;
+ padding: 3vh;
+ border-style: hidden;
+ border-color: rgb(194, 191, 191);
+ border-width: 2px;
+ box-shadow: 1px 1px 5px #7e7b7b;
+}
+
+li span {
+ display: block;
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-family: sans-serif;
+ white-space: pre-wrap;
+}
+
+a {
+ text-decoration: underline;
+ color: blue;
+}
+
+a:hover {
+ cursor: pointer;
+}
+
+.mainTitle{
+ background-color: rgb(63, 81, 181);
+ color: white;
+ font-family: sans-serif;
+ font-size: 50%;
+ padding: 3vh;
+}
+
+.mainTitle span {
+ font-weight: normal;
+}
+
+.alert-error {
+ margin-top: 4px;
+ padding: 3vh;
+ background-color: rgb(248, 215, 218);
+ color: rgb(92, 60, 60);
+}
\ No newline at end of file
diff --git a/Week1/homework/jsexercises/Who.js b/Week1/homework/jsexercises/Who.js
new file mode 100644
index 000000000..fb3033709
--- /dev/null
+++ b/Week1/homework/jsexercises/Who.js
@@ -0,0 +1,51 @@
+// Write a function that makes an API call to https://www.randomuser.me/api
+
+// Inside the same file write two functions: one with XMLHttpRequest, and the other with axios
+// Each function should make an API call to the given endpoint: https://www.randomuser.me/api
+// Log the received data to the console
+// Incorporate error handling
+
+
+// STEP 1 with XMLHttpRequest
+var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
+
+const getData = () => {
+ const promise = new Promise((resolve, reject) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', "https://www.randomuser.me/api", true);
+ xhr.send();
+ xhr.addEventListener("readystatechange", processRequest, false);
+
+ function processRequest(e) {
+ if (xhr.readyState == 4 && xhr.status == 200) {
+ const dato = JSON.parse(xhr.responseText);
+ const specificData = dato.results[0].name.first;
+ resolve(specificData); // We could just send dato for all the general data
+ }
+ }
+
+ xhr.onerror = () => {
+ reject("Something ain't going well...");
+ }
+ });
+ return promise;
+}
+
+getData()
+ .then(responseData => console.log(responseData))
+ .catch(err => {
+ console.log(err);
+ });
+
+// STEP 2 AXIOS
+const axios = require('axios'); // We have to load in the library first
+
+axios
+ .get('https://www.randomuser.me/api')
+ .then(responseText => {
+ const specificData = responseText.data.results[0].name.first;
+ console.log(specificData); // We could just send responseText.data for all the general data
+ })
+ .catch(function(error) {
+ console.log("Something went wrong. Error " + error + " destected.");
+ });
diff --git a/Week1/homework/readme.txt b/Week1/homework/readme.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/Week1/homework/readme.txt
@@ -0,0 +1 @@
+
diff --git a/Week2/homework/jsexercises/PROJECT/hyf.png b/Week2/homework/jsexercises/PROJECT/hyf.png
new file mode 100644
index 000000000..76bc5a13b
Binary files /dev/null and b/Week2/homework/jsexercises/PROJECT/hyf.png differ
diff --git a/Week2/homework/jsexercises/PROJECT/index.html b/Week2/homework/jsexercises/PROJECT/index.html
new file mode 100644
index 000000000..fc915cbc5
--- /dev/null
+++ b/Week2/homework/jsexercises/PROJECT/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
HYF Repositories
+
+
+
+
+
+
Contributions
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week2/homework/jsexercises/PROJECT/index.js b/Week2/homework/jsexercises/PROJECT/index.js
new file mode 100644
index 000000000..319662ec7
--- /dev/null
+++ b/Week2/homework/jsexercises/PROJECT/index.js
@@ -0,0 +1,250 @@
+'use strict';
+
+{
+ //JS3-2 START Select Listener
+ const selectEl = document.querySelector("#repositories");
+ selectEl.addEventListener("change", (event) => {
+ displaySelectedRepo(event.target.value);
+ displayContributors(event.target.value); //JS3-2 After all the Li Elements are created keeps only the selected one visible.
+ });
+
+ //JS3-2 END Select Listener
+ /* JS3-2 Modified function (Now with fetch)
+ function fetchJSON(url, cb) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ cb(null, xhr.response);
+ } else {
+ cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.onerror = () => cb(new Error('Network request failed'));
+ xhr.send();
+ } */
+
+ //JS3-2 START New fetchJSON function that uses fetch instead of xhr
+ function fetchJSON(url, cb) {
+ fetch(url)
+ .then(res => res.json())
+ .then(data => cb(null, data))
+ .catch(err => cb(new Error(`Network error.`)))
+ }
+ //JS3-2 END
+
+ //JS3-2 START New function that uses fetch instead of xhr
+ function fetchJSONContributors(contrData) {
+ Promise.all(contrData.map(dato => {
+ fetch(dato.url)
+ .then(res => res.json())
+ .then(data => contributorsAux(null, data, dato.id))
+ }))
+ .then(res2 => console.log("Everything went well.."))
+ .catch(res => console.log("One URL failed..."))
+ }
+ //JS3-2 END
+
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+
+ Object.entries(options).forEach(([key, value]) => {
+ // JS3-1 START Modified Lines
+ if (key === 'errText') {
+ elem.innerHTML = value;
+ } else {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ if (key === 'text') {
+ innerSpan.innerHTML += "Repository: ";
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = options.url;
+ innerSpan.appendChild(innerLink);
+ innerSpan.innerHTML += " ";
+ } else if (key === 'desc') {
+ innerSpan.innerHTML += "Description: " + value + " ";
+ } else if (key === 'forks') {
+ innerSpan.innerHTML += "Forks: " + value + " ";
+ } else if (key === 'update') {
+ innerSpan.innerHTML += "Update: " + formatDate(value);
+ } else if (key === 'url') {
+ //displaySelectedRepo();
+ }
+ // JS3-1 END Modified Lines
+ else {
+ elem.setAttribute(key, value);
+ }
+ elem.appendChild(innerSpan);
+ }
+ });
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ //JS3-2 Function that creates and append only for contributors
+ function createAndAppendContributors(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ const contrDiv = document.createElement("div");
+ contrDiv.setAttribute("class", "contributorData");
+ const contributorURL = options.url;
+
+ Object.entries(options).forEach(([key, value]) => {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+
+ if (key === 'img') {
+ const contImage = document.createElement("img");
+ contImage.src = value;
+ contrDiv.appendChild(contImage);
+ } else if (key === 'text') {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = contributorURL;
+ innerSpan.appendChild(innerLink);
+ contrDiv.appendChild(innerSpan);
+ } else if (key === 'contr') {
+ const innerSpan = document.createElement("span");
+ innerSpan.setAttribute("class", "numberContributions");
+ innerSpan.innerHTML = value;
+ contrDiv.appendChild(innerSpan);
+ }
+ });
+ elem.appendChild(contrDiv);
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ // JS3-1 Modified line
+ function renderRepoDetails(repo, ul) {
+ contributorsURLArray.push({id: repo.id, url: repo.contributors_url}); //JS3-2 The contributors Array receives a new url.
+ createAndAppend('li', ul, {
+ text: repo.name, desc: repo.description, forks: repo.forks,
+ update: repo.updated_at, url: repo.html_url
+ });
+ }
+
+ // JS3-2 New Function that adds the li's for the contributors
+ function renderRepoContributorDetails(repo, ul) {
+ createAndAppendContributors('li', ul, {
+ img: repo.avatar_url, text: repo.login, contr: repo.contributions, url: repo.html_url
+ });
+ }
+
+ // JS3-1 START Function that formats the Dates
+ function formatDate(sentDate) {
+ let date = new Date(sentDate);
+ let hours = date.getHours();
+ let minutes = date.getMinutes();
+ let seconds = date.getSeconds();
+ let ampm = hours >= 12 ? 'PM' : 'AM';
+ hours = hours % 12;
+ hours = hours ? hours : 12; // the hour '0' should be '12'
+ minutes = minutes < 10 ? '0' + minutes : minutes;
+ seconds = seconds < 10 ? '0' + seconds : seconds;
+ const strTime = hours + ':' + minutes + ':' + seconds + ' ' + ampm;
+ return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + ", " + strTime;
+ }
+ // JS3-1 END
+ // JS3-1 START Function that sorts an array alphabetically
+ function sortArray(arrayToSort) {
+ arrayToSort.sort(function (a, b) {
+ if (a.name.toLowerCase() > b.name.toLowerCase()) {
+ return 1;
+ }
+ if (a.name.toLowerCase() < b.name.toLowerCase()) {
+ return -1;
+ }
+ // a must be equal to b
+ return 0;
+ });
+ return arrayToSort;
+ }
+ // JS3-1 END
+ // JS3-2 START Function that populates the Select Element
+ function populateSelect(repos){
+ selectEl.innerHTML = "";
+ repos.forEach((repo, i) => {
+ repositoriesOrder.push(repo.id); // Here the reporitories of the ID's are stored in alphabetical order
+ selectEl.innerHTML += ``;
+ })
+ }
+ // JS3-1 END
+
+ // JS3-2 START Function that verifies the position of the UL to be stored
+ function positionID(repositoryID, URLId){
+ let finalId = 0;
+ repositoryID.forEach((repo, i) => {
+ if(repo === URLId)
+ finalId = i;
+ })
+ return finalId;
+ }
+ // JS3-1 END
+
+ // JS3-2 START Function that displays the selected Element
+ function displaySelectedRepo(value = 0){
+ const liEls = document.querySelectorAll(".repo-container li");
+ if(liEls.length > 0){
+ liEls.forEach(listelement => {
+ listelement.style.display = "none";
+ })
+ liEls[value].style.display = "block";
+ } else
+ console.log("Houston, we got a problem...");
+ }
+ // JS3-2 END
+
+ // JS3-2 START Function that displays the selected Element contributors
+ function displayContributors(value = 0){
+ if(contributorsUl.length > 0){
+ contributorsUl.forEach(listelement => {
+ listelement.style.display = "none";
+ })
+ contributorsUl[value].style.display = "block";
+ } else
+ console.log("Houston, we got a problem...");
+ }
+ // JS3-2 END
+
+ //JS3-2 Auxiliary function for the contributors display
+ function contributorsAux(err, contributors, id){
+ const root = document.querySelector('.contributors-container');
+ if (err) {
+ return new Error("A contributor URL failed...");
+ }
+ const ul = createAndAppend('ul', root);
+ contributorsUl[positionID(repositoriesOrder, id)] = ul;
+ contributors.forEach(contributor => renderRepoContributorDetails(contributor, ul));
+ displayContributors(); //JS3-2 After all the Li Elements are created keeps only the selected one visible.
+ }
+
+ function main(url) {
+ fetchJSON(url, (err, repos) => {
+ const root = document.querySelector('.repo-container');
+ if (err) {
+ createAndAppend('div', root, {
+ errText: err.message, //JS3-1 Modified Line
+ class: 'alert-error',
+ });
+ return;
+ }
+ const ul = createAndAppend('ul', root);
+ repos = sortArray(repos); //JS3-1 Sort the array of objects before displaying them
+ populateSelect(repos); //JS3-2 Populate the Select element.
+ repos.forEach(repo => renderRepoDetails(repo, ul));
+ displaySelectedRepo(); //JS3-2 After all the Li Elements are created keeps only the selected one visible.
+ fetchJSONContributors(contributorsURLArray) //JS3-2 After the repos, comes the list of contributors
+ });
+ }
+
+ let repositoriesOrder= [];
+ let contributorsUl = []; //JS3-2 List of Ul of contributors
+ let contributorsURLArray = []; //JS3-2 Contributors URL Array
+ const HYF_REPOS_URL =
+ 'https://api.github.com/orgs/HackYourFuture/repos?per_page=10';
+ window.onload = () => main(HYF_REPOS_URL);
+}
diff --git a/Week2/homework/jsexercises/PROJECT/style.css b/Week2/homework/jsexercises/PROJECT/style.css
new file mode 100644
index 000000000..08395db8c
--- /dev/null
+++ b/Week2/homework/jsexercises/PROJECT/style.css
@@ -0,0 +1,159 @@
+* {
+ padding: 0px;
+ margin: 0px;
+ box-sizing: border-box;
+}
+
+a {
+ text-decoration: underline;
+ color: blue;
+}
+
+a:hover {
+ cursor: pointer;
+}
+
+a:visited {
+ color: purple;
+}
+
+img{
+ width: 60px;
+ margin-right: 2vw;;
+}
+
+li {
+ margin: 3px;
+ padding: 3vh;
+ border-style: hidden;
+ border-color: rgb(194, 191, 191);
+ border-width: 2px;
+ box-shadow: 1px 1px 5px #7e7b7b;
+ list-style-type: none;
+}
+
+li span {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-family: sans-serif;
+ white-space: pre-wrap;
+}
+
+/*JS3-2 START Modified Text. Attributes for Select element */
+select {
+ margin-left: 15px;
+ height: 25px;
+ width: 200px;
+}
+/*JS3-2 END Modified Text. Helps to place the select element after the Title ina row. */
+
+section{
+ width: 50%;
+}
+
+.alert-error {
+ margin-top: 4px;
+ padding: 3vh;
+ background-color: rgb(248, 215, 218);
+ color: rgb(92, 60, 60);
+}
+
+/*JS3-2 START Modified Text. Div that contains two sections */
+.containers{
+ display: flex;
+ flex-direction: row;
+}
+/*JS3-2 END Modified Text. Div that contains two sections */
+
+.contributorData {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.contributorData a{
+ text-decoration: none;
+}
+
+.mainTitle{
+ display: flex; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ flex-direction: row; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ justify-content: flex-start; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ align-items: baseline; /*JS3-2 Modified Text. Helps to place the select element after the Title ina row. */
+ background-color: rgb(63, 81, 181);
+ color: white;
+ font-family: sans-serif;
+ font-size: 50%;
+ padding: 3vh;
+}
+
+.mainTitle span {
+ font-weight: normal;
+}
+
+.numberContributions {
+ margin-left: auto;
+ padding: 4px;
+ padding-left: 7px;
+ padding-right: 7px;
+ border-radius: 5px;
+ font-size: 12px;;
+ background-color: rgb(124, 111, 111);
+ color: white;
+}
+
+/* JS3-2 Line that separates the block style of the li span of the containers from the contributors. */
+.repo-container li span {
+ display: block;
+}
+
+#contributions {
+ margin: 3px;
+ padding: 3vh;
+ border-style: hidden;
+ border-color: rgb(194, 191, 191);
+ border-width: 2px;
+ border-bottom: none;
+ box-shadow: 1px 1px 5px #7e7b7b;
+ list-style-type: none;
+ color: rgb(165, 159, 159);
+}
+
+/* RESPONSIVENESS*/
+/* Mobile phones */
+@media screen and (max-width: 450px) {
+ section{
+ width: 100%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: column;
+ }
+}
+
+/* RESPONSIVENESS*/
+/* TABLETS */
+@media screen and (min-width: 451px) and (max-width: 800px) {
+ section{
+ width: 50%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: row;
+ }
+}
+
+/* RESPONSIVENESS*/
+/* LARGER SCREENS */
+@media screen and (min-width: 801px) {
+ section{
+ width: 50%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: row;
+ }
+}
diff --git a/Week2/homework/jsexercises/readme.txt b/Week2/homework/jsexercises/readme.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/Week2/homework/jsexercises/readme.txt
@@ -0,0 +1 @@
+
diff --git a/Week2/homework/readme.txt b/Week2/homework/readme.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/Week2/homework/readme.txt
@@ -0,0 +1 @@
+
diff --git a/Week3/homework/js-exercises/ContributorsView.js b/Week3/homework/js-exercises/ContributorsView.js
new file mode 100644
index 000000000..7866acc38
--- /dev/null
+++ b/Week3/homework/js-exercises/ContributorsView.js
@@ -0,0 +1,74 @@
+'use strict';
+
+{
+ const { createAndAppend } = window.Util;
+
+ class ContributorsView {
+ constructor(container) {
+ this.container = container;
+ }
+
+ update(state) {
+ if (!state.error) {
+ this.render(state.contributors);
+ }
+ }
+
+ /**
+ * Renders the list of contributors
+ * @param {Object[]} contributors An array of contributor objects
+ */
+ render(contributors) {
+ // TODO: replace this comment and the console.log with your own code
+ console.log('ContributorsView', contributors);
+ const root = document.querySelector('#root');
+
+ const ul = document.createElement("ul");
+ root.appendChild(ul);
+ contributors.forEach(contributor => this.renderRepoContributorDetails(contributor, ul));
+ }
+
+ renderRepoContributorDetails(repo, ul) {
+ this.createAndAppendContributors('li', ul, {
+ img: repo.avatar_url, text: repo.login, contr: repo.contributions, url: repo.html_url
+ });
+ }
+
+ createAndAppendContributors(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ const contrDiv = document.createElement("div");
+ contrDiv.setAttribute("class", "contributorData");
+ const contributorURL = options.url;
+
+ Object.entries(options).forEach(([key, value]) => {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+
+ if (key === 'img') {
+ const contImage = document.createElement("img");
+ contImage.src = value;
+ contrDiv.appendChild(contImage);
+ } else if (key === 'text') {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = contributorURL;
+ innerSpan.appendChild(innerLink);
+ contrDiv.appendChild(innerSpan);
+ } else if (key === 'contr') {
+ const innerSpan = document.createElement("span");
+ innerSpan.setAttribute("class", "numberContributions");
+ innerSpan.innerHTML = value;
+ contrDiv.appendChild(innerSpan);
+ }
+ });
+ elem.appendChild(contrDiv);
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ }
+
+ window.ContributorsView = ContributorsView;
+}
diff --git a/Week3/homework/js-exercises/PROJECT/hyf.png b/Week3/homework/js-exercises/PROJECT/hyf.png
new file mode 100644
index 000000000..76bc5a13b
Binary files /dev/null and b/Week3/homework/js-exercises/PROJECT/hyf.png differ
diff --git a/Week3/homework/js-exercises/PROJECT/index.html b/Week3/homework/js-exercises/PROJECT/index.html
new file mode 100644
index 000000000..dbd26013a
--- /dev/null
+++ b/Week3/homework/js-exercises/PROJECT/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ HYF-GITHUB
+
+
+
+
+
+
+
+
HYF Repositories
+
+
+
+
+
+
Contributions
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Week3/homework/js-exercises/PROJECT/index.js b/Week3/homework/js-exercises/PROJECT/index.js
new file mode 100644
index 000000000..62bb0d833
--- /dev/null
+++ b/Week3/homework/js-exercises/PROJECT/index.js
@@ -0,0 +1,255 @@
+'use strict';
+
+{
+ //JS3-2 START Select Listener
+ const selectEl = document.querySelector("#repositories");
+ selectEl.addEventListener("change", (event) => {
+ displaySelectedRepo(event.target.value);
+ displayContributors(event.target.value); //JS3-2 After all the Li Elements are created keeps only the selected one visible.
+ });
+
+ //JS3-2 END Select Listener
+ /* JS3-2 Modified function (Now with fetch)
+ function fetchJSON(url, cb) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.responseType = 'json';
+ xhr.onload = () => {
+ if (xhr.status >= 200 && xhr.status <= 299) {
+ cb(null, xhr.response);
+ } else {
+ cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
+ }
+ };
+ xhr.onerror = () => cb(new Error('Network request failed'));
+ xhr.send();
+ } */
+
+ //JS3-3 START New fetchJSON function that uses fetch instead of xhr, and async functions
+ async function fetchJSON(url, cb) {
+ try {
+ console.log("Reached point");
+ const res = await axios.get(url);
+ cb(null, res.data);
+ fetchContributors(contributorsURLArray) //JS3-3 After the repos, comes the list of contributors
+ } catch(err){
+ cb(new Error(`Network error.`));
+ }
+ }
+ //JS3-2 END
+
+ //JS3-2 START New function that uses fetch instead of xhr
+ async function fetchContributors(contrData) {
+ try{
+ await Promise.all(contrData.map(async function(dato) {
+ let res = await axios.get(dato.url);
+ contributorsAux(null, res.data, dato.id);
+ }))
+ } catch(err){
+ console.log("One URL failed...");
+ }
+ }
+ //JS3-2 END
+
+ function createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+
+ Object.entries(options).forEach(([key, value]) => {
+ // JS3-1 START Modified Lines
+ if (key === 'errText') {
+ elem.innerHTML = value;
+ } else {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ if (key === 'text') {
+ innerSpan.innerHTML += "Repository: ";
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = options.url;
+ innerSpan.appendChild(innerLink);
+ innerSpan.innerHTML += " ";
+ } else if (key === 'desc') {
+ innerSpan.innerHTML += "Description: " + value + " ";
+ } else if (key === 'forks') {
+ innerSpan.innerHTML += "Forks: " + value + " ";
+ } else if (key === 'update') {
+ innerSpan.innerHTML += "Update: " + formatDate(value);
+ } else if (key === 'url') {
+ //displaySelectedRepo();
+ }
+ // JS3-1 END Modified Lines
+ else {
+ elem.setAttribute(key, value);
+ }
+ elem.appendChild(innerSpan);
+ }
+ });
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ //JS3-2 Function that creates and append only for contributors
+ function createAndAppendContributors(name, parent, options = {}) {
+ const elem = document.createElement(name);
+ const contrDiv = document.createElement("div");
+ contrDiv.setAttribute("class", "contributorData");
+ const contributorURL = options.url;
+
+ Object.entries(options).forEach(([key, value]) => {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+
+ if (key === 'img') {
+ const contImage = document.createElement("img");
+ contImage.src = value;
+ contrDiv.appendChild(contImage);
+ } else if (key === 'text') {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = contributorURL;
+ innerSpan.appendChild(innerLink);
+ contrDiv.appendChild(innerSpan);
+ } else if (key === 'contr') {
+ const innerSpan = document.createElement("span");
+ innerSpan.setAttribute("class", "numberContributions");
+ innerSpan.innerHTML = value;
+ contrDiv.appendChild(innerSpan);
+ }
+ });
+ elem.appendChild(contrDiv);
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ // JS3-1 Modified line
+ function renderRepoDetails(repo, ul) {
+ contributorsURLArray.push({id: repo.id, url: repo.contributors_url}); //JS3-2 The contributors Array receives a new url.
+ createAndAppend('li', ul, {
+ text: repo.name, desc: repo.description, forks: repo.forks,
+ update: repo.updated_at, url: repo.html_url
+ });
+ }
+
+ // JS3-2 New Function that adds the li's for the contributors
+ function renderRepoContributorDetails(repo, ul) {
+ createAndAppendContributors('li', ul, {
+ img: repo.avatar_url, text: repo.login, contr: repo.contributions, url: repo.html_url
+ });
+ }
+
+ // JS3-1 START Function that formats the Dates
+ function formatDate(sentDate) {
+ let date = new Date(sentDate);
+ let hours = date.getHours();
+ let minutes = date.getMinutes();
+ let seconds = date.getSeconds();
+ let ampm = hours >= 12 ? 'PM' : 'AM';
+ hours = hours % 12;
+ hours = hours ? hours : 12; // the hour '0' should be '12'
+ minutes = minutes < 10 ? '0' + minutes : minutes;
+ seconds = seconds < 10 ? '0' + seconds : seconds;
+ const strTime = hours + ':' + minutes + ':' + seconds + ' ' + ampm;
+ return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + ", " + strTime;
+ }
+ // JS3-1 END
+ // JS3-1 START Function that sorts an array alphabetically
+ function sortArray(arrayToSort) {
+ arrayToSort.sort(function (a, b) {
+ if (a.name.toLowerCase() > b.name.toLowerCase()) {
+ return 1;
+ }
+ if (a.name.toLowerCase() < b.name.toLowerCase()) {
+ return -1;
+ }
+ // a must be equal to b
+ return 0;
+ });
+ return arrayToSort;
+ }
+ // JS3-1 END
+ // JS3-2 START Function that populates the Select Element
+ function populateSelect(repos){
+ selectEl.innerHTML = "";
+ repos.forEach((repo, i) => {
+ repositoriesOrder.push(repo.id); // Here the reporitories of the ID's are stored in alphabetical order
+ selectEl.innerHTML += ``;
+ })
+ }
+ // JS3-1 END
+
+ // JS3-2 START Function that verifies the position of the UL to be stored
+ function positionID(repositoryID, URLId){
+ let finalId = 0;
+ repositoryID.forEach((repo, i) => {
+ if(repo === URLId)
+ finalId = i;
+ })
+ return finalId;
+ }
+ // JS3-1 END
+
+ // JS3-2 START Function that displays the selected Element
+ function displaySelectedRepo(value = 0){
+ const liEls = document.querySelectorAll(".repo-container li");
+ if(liEls.length > 0){
+ liEls.forEach(listelement => {
+ listelement.style.display = "none";
+ })
+ liEls[value].style.display = "block";
+ } else
+ console.log("Houston, we got a problem...");
+ }
+ // JS3-2 END
+
+ // JS3-2 START Function that displays the selected Element contributors
+ function displayContributors(value = 0){
+ if(contributorsUl.length > 0){
+ contributorsUl.forEach(listelement => {
+ listelement.style.display = "none";
+ })
+ contributorsUl[value].style.display = "block";
+ } else
+ console.log("Houston, we got a problem...");
+ }
+ // JS3-2 END
+
+ //JS3-2 Auxiliary function for the contributors display
+ function contributorsAux(err, contributors, id){
+ const root = document.querySelector('.contributors-container');
+ if (err) {
+ return new Error("A contributor URL failed...");
+ }
+ const ul = createAndAppend('ul', root);
+ contributorsUl[positionID(repositoriesOrder, id)] = ul;
+ contributors.forEach(contributor => renderRepoContributorDetails(contributor, ul));
+ displayContributors(); //JS3-2 After all the Li Elements are created, it keeps only the selected one visible.
+ }
+
+ function main(url) {
+ fetchJSON(url, (err, repos) => {
+ const root = document.querySelector('.repo-container');
+ if (err) {
+ createAndAppend('div', root, {
+ errText: err.message, //JS3-1 Modified Line
+ class: 'alert-error',
+ });
+ return;
+ }
+ const ul = createAndAppend('ul', root);
+ repos = sortArray(repos); //JS3-1 Sort the array of objects before displaying them
+ populateSelect(repos); //JS3-2 Populate the Select element.
+ repos.forEach(repo => renderRepoDetails(repo, ul));
+ displaySelectedRepo(); //JS3-2 After all the Li Elements are created keeps only the selected one visible.
+ //fetchJSONContributors(contributorsURLArray) //JS3-2 After the repos, comes the list of contributors
+ });
+ }
+
+ let repositoriesOrder= [];
+ let contributorsUl = []; //JS3-2 List of Ul of contributors
+ let contributorsURLArray = []; //JS3-2 Contributors URL Array
+ const HYF_REPOS_URL =
+ 'https://api.github.com/orgs/HackYourFuture/repos?per_page=10';
+ window.onload = () => main(HYF_REPOS_URL);
+}
diff --git a/Week3/homework/js-exercises/PROJECT/style.css b/Week3/homework/js-exercises/PROJECT/style.css
new file mode 100644
index 000000000..08395db8c
--- /dev/null
+++ b/Week3/homework/js-exercises/PROJECT/style.css
@@ -0,0 +1,159 @@
+* {
+ padding: 0px;
+ margin: 0px;
+ box-sizing: border-box;
+}
+
+a {
+ text-decoration: underline;
+ color: blue;
+}
+
+a:hover {
+ cursor: pointer;
+}
+
+a:visited {
+ color: purple;
+}
+
+img{
+ width: 60px;
+ margin-right: 2vw;;
+}
+
+li {
+ margin: 3px;
+ padding: 3vh;
+ border-style: hidden;
+ border-color: rgb(194, 191, 191);
+ border-width: 2px;
+ box-shadow: 1px 1px 5px #7e7b7b;
+ list-style-type: none;
+}
+
+li span {
+ margin-top: 5px;
+ margin-bottom: 5px;
+ font-family: sans-serif;
+ white-space: pre-wrap;
+}
+
+/*JS3-2 START Modified Text. Attributes for Select element */
+select {
+ margin-left: 15px;
+ height: 25px;
+ width: 200px;
+}
+/*JS3-2 END Modified Text. Helps to place the select element after the Title ina row. */
+
+section{
+ width: 50%;
+}
+
+.alert-error {
+ margin-top: 4px;
+ padding: 3vh;
+ background-color: rgb(248, 215, 218);
+ color: rgb(92, 60, 60);
+}
+
+/*JS3-2 START Modified Text. Div that contains two sections */
+.containers{
+ display: flex;
+ flex-direction: row;
+}
+/*JS3-2 END Modified Text. Div that contains two sections */
+
+.contributorData {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+}
+
+.contributorData a{
+ text-decoration: none;
+}
+
+.mainTitle{
+ display: flex; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ flex-direction: row; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ justify-content: flex-start; /*JS3-2 Modified Text. Helps to place the select element after the Title in a row. */
+ align-items: baseline; /*JS3-2 Modified Text. Helps to place the select element after the Title ina row. */
+ background-color: rgb(63, 81, 181);
+ color: white;
+ font-family: sans-serif;
+ font-size: 50%;
+ padding: 3vh;
+}
+
+.mainTitle span {
+ font-weight: normal;
+}
+
+.numberContributions {
+ margin-left: auto;
+ padding: 4px;
+ padding-left: 7px;
+ padding-right: 7px;
+ border-radius: 5px;
+ font-size: 12px;;
+ background-color: rgb(124, 111, 111);
+ color: white;
+}
+
+/* JS3-2 Line that separates the block style of the li span of the containers from the contributors. */
+.repo-container li span {
+ display: block;
+}
+
+#contributions {
+ margin: 3px;
+ padding: 3vh;
+ border-style: hidden;
+ border-color: rgb(194, 191, 191);
+ border-width: 2px;
+ border-bottom: none;
+ box-shadow: 1px 1px 5px #7e7b7b;
+ list-style-type: none;
+ color: rgb(165, 159, 159);
+}
+
+/* RESPONSIVENESS*/
+/* Mobile phones */
+@media screen and (max-width: 450px) {
+ section{
+ width: 100%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: column;
+ }
+}
+
+/* RESPONSIVENESS*/
+/* TABLETS */
+@media screen and (min-width: 451px) and (max-width: 800px) {
+ section{
+ width: 50%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: row;
+ }
+}
+
+/* RESPONSIVENESS*/
+/* LARGER SCREENS */
+@media screen and (min-width: 801px) {
+ section{
+ width: 50%;
+ }
+
+ .containers{
+ display: flex;
+ flex-direction: row;
+ }
+}
diff --git a/Week3/homework/js-exercises/RepoView.js b/Week3/homework/js-exercises/RepoView.js
new file mode 100644
index 000000000..647e01b4f
--- /dev/null
+++ b/Week3/homework/js-exercises/RepoView.js
@@ -0,0 +1,85 @@
+'use strict';
+
+{
+ const { createAndAppend } = window.Util;
+
+ class RepoView {
+ constructor(container) {
+ this.container = container;
+ }
+
+ update(state) {
+ if (!state.error) {
+ this.render(state.selectedRepo);
+ }
+ }
+
+ /**
+ * Renders the repository details.
+ * @param {Object} repo A repository object.
+ */
+ render(repos) {
+ // TODO: replace this comment and the console.log with your own code
+ const root = document.querySelector('#root');
+ this.refreshElements(root);
+ const ul = this.createAndAppend('ul', root);
+ this.createAndAppend('li', ul, {
+ text: repos.name, desc: repos.description, forks: repos.forks,
+ update: repos.updated_at, url: repos.html_url
+ });
+ }
+
+ refreshElements(root){
+ const ulArray = document.querySelectorAll("ul");
+ if(ulArray.length > 0){
+ ulArray.forEach(ulElement => root.removeChild(ulElement))
+ }
+ }
+
+ createAndAppend(name, parent, options = {}) {
+ const elem = document.createElement(name);
+
+ Object.entries(options).forEach(([key, value]) => {
+ const innerSpan = document.createElement("span");
+ const innerLink = document.createElement("a");
+ if (key === 'text') {
+ innerSpan.innerHTML += "Repository: ";
+ innerLink.target = "_blank";
+ innerLink.innerText = value;
+ innerLink.href = options.url;
+ innerSpan.appendChild(innerLink);
+ innerSpan.innerHTML += " ";
+ } else if (key === 'desc') {
+ innerSpan.innerHTML += "Description: " + value + " ";
+ } else if (key === 'forks') {
+ innerSpan.innerHTML += "Forks: " + value + " ";
+ } else if (key === 'update') {
+ innerSpan.innerHTML += "Update: " + this.formatDate(value);
+ } else if (key === 'url') {
+ } else {
+ elem.setAttribute(key, value);
+ }
+ elem.appendChild(innerSpan);
+ });
+ parent.appendChild(elem);
+ return elem;
+ }
+
+ formatDate(sentDate) {
+ let date = new Date(sentDate);
+ let hours = date.getHours();
+ let minutes = date.getMinutes();
+ let seconds = date.getSeconds();
+ let ampm = hours >= 12 ? 'PM' : 'AM';
+ hours = hours % 12;
+ hours = hours ? hours : 12; // the hour '0' should be '12'
+ minutes = minutes < 10 ? '0' + minutes : minutes;
+ seconds = seconds < 10 ? '0' + seconds : seconds;
+ const strTime = hours + ':' + minutes + ':' + seconds + ' ' + ampm;
+ return date.getMonth() + 1 + "/" + date.getDate() + "/" + date.getFullYear() + ", " + strTime;
+ }
+
+ }
+
+ window.RepoView = RepoView;
+}
diff --git a/Week3/homework/js-exercises/readme.txt b/Week3/homework/js-exercises/readme.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/Week3/homework/js-exercises/readme.txt
@@ -0,0 +1 @@
+
diff --git a/Week3/homework/readme.txt b/Week3/homework/readme.txt
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/Week3/homework/readme.txt
@@ -0,0 +1 @@
+