diff --git a/.vscode/settings.json b/.vscode/settings.json index f7a55df12..e2e5d8e80 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,9 @@ "editor.detectIndentation": false, "editor.tabSize": 2, "cSpell.words": [ + "Cramer", + "linebreak", + "plusplus", "tabindex" ] } \ No newline at end of file diff --git a/homework/App.js b/homework/App.js index 5f81a47a1..c38143143 100644 --- a/homework/App.js +++ b/homework/App.js @@ -72,7 +72,7 @@ class App { * @param {Error} error An Error object describing the error. */ renderError(error) { - console.log(error); // TODO: replace with your own code + throw new Error(error); // TODO: replace with your own code } } diff --git a/homework/index.js b/homework/index.js index d8a04f271..44393a060 100644 --- a/homework/index.js +++ b/homework/index.js @@ -1,47 +1,153 @@ -'use strict'; - -{ - function fetchJSON(url, cb) { - const xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.responseType = 'json'; - xhr.onload = () => { - if (xhr.status < 400) { - cb(null, xhr.response); - } else { - cb(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`)); - } - }; - xhr.onerror = () => cb(new Error('Network request failed')); - xhr.send(); - } +const mainDiv = document.body; +function createElement(parentElement, element, nameId) { + const newElement = document.createElement(element); + newElement.setAttribute('id', nameId); + parentElement.appendChild(newElement); + return newElement; +} - function createAndAppend(name, parent, options = {}) { - const elem = document.createElement(name); - parent.appendChild(elem); - Object.keys(options).forEach(key => { - const value = options[key]; - if (key === 'text') { - elem.textContent = value; - } else { - elem.setAttribute(key, value); - } - }); - return elem; - } +const fetchRepositories = async url => { + const response = await fetch(url); + const dataList = await response.json(); + return dataList; +}; + +const createOption = (item, index) => { + const newOption = document.createElement('option'); + const repositoriesSelect = document.getElementById('repositoriesSelect'); + newOption.className = 'repositoryOption'; + newOption.text = item.name; + newOption.value = index; + repositoriesSelect.appendChild(newOption); +}; + +function appendToLi(indexLi, element, nameIdP1, textNodeP1, nameIdP2, textNodeP2) { + const p1 = createElement(indexLi, element, nameIdP1); + const contentP1 = document.createTextNode(textNodeP1); + p1.appendChild(contentP1); + const p2 = createElement(indexLi, element, nameIdP2); + const contentP2 = document.createTextNode(textNodeP2); + p2.appendChild(contentP2); +} - function main(url) { - fetchJSON(url, (err, data) => { - const root = document.getElementById('root'); - if (err) { - createAndAppend('div', root, { text: err.message, class: 'alert-error' }); - } else { - createAndAppend('pre', root, { text: JSON.stringify(data, null, 2) }); - } - }); +function createList(parentElement, element, lio, li1, li2, li3, aUrl) { + for (let y = 0; y < 4; y++) { + createElement(parentElement, element, `li${y}`); } + const liTags = document.getElementsByTagName('li'); + const p0 = createElement(liTags[0], 'p', 'repository'); + const contentP0 = document.createTextNode('Repository:'); + p0.appendChild(contentP0); + const aElement = createElement(liTags[0], 'a', 'repositoryValue'); + aElement.href = aUrl; + const aContent = document.createTextNode(lio); + aElement.appendChild(aContent); + appendToLi(liTags[1], 'p', 'description', 'Description:', 'descriptionValue', li1); + appendToLi(liTags[2], 'p', 'forks', 'Forks:', 'forksValue', li2); + appendToLi(liTags[3], 'p', 'updated', 'Updated:', 'updatedValue', li3); +} + +function handleContributors(contributors) { + const rightDiv = document.getElementById('rightDiv'); + rightDiv.innerHTML = ''; + const contributorsTitle = createElement(rightDiv, 'div', 'contributorsTitle'); + const contributorsTitleContent = document.createTextNode('Contributors'); + contributorsTitle.appendChild(contributorsTitleContent); + contributors.forEach(contributor => { + // create subDiv for each contributor + const subDiv = document.createElement('div'); + subDiv.className = 'contributor'; + rightDiv.appendChild(subDiv); + const image = document.createElement('img'); + image.className = 'image'; + image.setAttribute('src', contributor.avatar_url); + subDiv.appendChild(image); + const login = createElement(subDiv, 'p', 'login'); + const loginContent = document.createTextNode(contributor.login); + login.appendChild(loginContent); + const contributions = createElement(subDiv, 'p', 'contributions'); + const contributionsContent = document.createTextNode(contributor.contributions); + contributions.appendChild(contributionsContent); + }); +} - const REPOS_URL = 'https://api.github.com/orgs/foocoding/repos?per_page=100'; +const logContributors = async url => { + try { + const contributorsData = await fetchRepositories(url); + const FooCodingContributors = contributorsData.sort((a, b) => + a.login.localeCompare(b.login, 'fr', { ignorePunctuation: true }), + ); + handleContributors(FooCodingContributors); + } catch (error) { + const errorDiv = createElement(mainDiv, 'div', 'errorDiv'); + const errorContent = document.createTextNode('error'); + errorDiv.appendChild(errorContent); + } +}; - window.onload = () => main(REPOS_URL); +function createPage(repositories) { + // create upperDiv + const upperDiv = createElement(mainDiv, 'div', 'upperDiv'); + const upperDivP = createElement(upperDiv, 'p', 'upperDivP'); + const upperDivPContent = document.createTextNode('FooCoding Repositories'); + upperDivP.appendChild(upperDivPContent); + const select = createElement(upperDiv, 'select', 'repositoriesSelect'); + repositories.forEach(createOption); + // create leftRightDivDiv + const leftRightDiv = createElement(mainDiv, 'div', 'leftRightDiv'); + // create leftDiv + const leftDiv = createElement(leftRightDiv, 'div', 'leftDiv'); + const repositoryDetails = createElement(leftDiv, 'ul', 'repositoryDetails'); + const defaultRepository = repositories[0]; + const updated = defaultRepository.updated_at; + const formatUpdated = updated.replace(/T/, ', ').replace(/Z/, ''); + createList( + repositoryDetails, + 'li', + defaultRepository.name, + defaultRepository.description, + defaultRepository.forks, + formatUpdated, + defaultRepository.html_url, + ); + // create rightDiv + createElement(leftRightDiv, 'div', 'rightDiv'); + // fetch contributors to implement the rightDiv + const defaultContributorsUrl = defaultRepository.contributors_url; + logContributors(defaultContributorsUrl); + // addEventListener on select change + select.addEventListener('change', () => { + const liElement = document.querySelectorAll('li'); + for (let i = 0; i < liElement.length; i++) { + liElement[i].parentElement.removeChild(liElement[i]); + } + const selectedRepository = repositories[select.value]; + const updatedForSelect = selectedRepository.updated_at; + const formatUpdatedForSelect = updatedForSelect.replace(/T/, ', ').replace(/Z/, ''); + createList( + repositoryDetails, + 'li', + selectedRepository.name, + selectedRepository.description, + selectedRepository.forks, + formatUpdatedForSelect, + ); + const ContributorsUrl = selectedRepository.contributors_url; + logContributors(ContributorsUrl); + }); } + +const logData = async url => { + try { + const repositoriesData = await fetchRepositories(url); + const FooCodingRepositories = repositoriesData.sort((a, b) => + a.name.localeCompare(b.name, 'fr', { ignorePunctuation: true }), + ); + createPage(FooCodingRepositories); + } catch (error) { + const errorDiv = createElement(mainDiv, 'div', 'errorDiv'); + const errorContent = document.createTextNode('error'); + errorDiv.appendChild(errorContent); + } +}; +logData('https://api.github.com/orgs/foocoding/repos?per_page=100'); diff --git a/homework/style.css b/homework/style.css index a8985a8a5..cfcb5c955 100644 --- a/homework/style.css +++ b/homework/style.css @@ -1,3 +1,129 @@ -.alert-error { - color: red; -} \ No newline at end of file +body { + max-width: 768px; + width: 100%; + margin-top: 0px; + margin-right: auto; + margin-left: auto; + background-color: #d3d3d3; + font-family: 'Roboto', sans-serif; + text-align: left; + color: rgb(0, 0, 0, 87%); +} +#upperDiv { + display: flex; + width: 93%; + margin-left: 3%; + margin-right: 4%; + background-color: #0072ce; +} +#upperDivP { + color: white; + width: 40%; + padding-left: 2%; + font-size: 10px; +} +#repositoriesSelect { + width: 40%; + border-radius: 4px; + font-size: 9px; +} +#leftRightDiv { + display: flex; + font-size: 8px; +} +#leftDiv { + margin-top: 2%; + margin-left: 3%; + margin-right: 3%; + width: 45%; + height: 45%; + background-color: white; +} +#rightDiv { + width: 45%; + margin-top: 2%; + background-color: white; +} +ul { + margin-right: 4%; +} +#li0, +#li1, +#li2, +#li3 { + display: flex; +} +#repository, +#description, +#forks, +#updated { + width: 30%; + margin-top: 1%; + margin-left: 0%; + font-weight: bold; +} +#repositoryValue, +#descriptionValue, +#forksValue, +#updatedValue { + width: 70%; + margin-top: 1%; + padding-left: 6%; + padding-right: 6%; +} +#contributorsTitle { + margin-left: 10%; + font-weight: bold; + color: #a9a9a9; + margin-top: auto; + padding-top: 4%; + padding-bottom: 4%; +} +.contributor { + display: flex; + margin-top: auto; + border-bottom: 0.3px solid #a9a9a9; + padding-top: 4%; + padding-bottom: 4%; +} +.contributor > .image { + width: 20%; + height: 20%; + margin-left: 10%; + border-radius: 4px; +} +#login { + width: 30%; + margin-top: 15%; + margin-left: 3%; + font-weight: bold; +} +#contributions { + width: 8%; + height: 14%; + margin-top: 15%; + margin-left: 20%; + background-color: rgb(169, 169, 169); + text-align: center; + border-radius: 4px; + font-weight: bold; + color: white; +} +@media (min-width: 769px) and (max-width: 1024px) { + #leftRightDiv { + font-size: 12px; + } +} +@media (min-width: 1025px) and (max-width: 1280px) { + #upperDivP { + width: 30%; + font-size: 14px; + } + #repositoriesSelect { + width: 22%; + font-size: 12px; + } + #leftRightDiv { + font-size: 14px; + } +}
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: