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 :)_ 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 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 @@ +