Skip to content

Commit 09d8118

Browse files
authored
Part 2 of homework
1 parent e5fbffd commit 09d8118

10 files changed

Lines changed: 562 additions & 0 deletions

File tree

Week3/part2/App.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
'use strict';
2+
3+
/* global Util, Repository, Contributor */
4+
5+
class App {
6+
constructor(url) {
7+
this.initialize(url);
8+
}
9+
10+
/**
11+
* Initialization
12+
* @param {string} url The GitHub URL for obtaining the organization's repositories.
13+
*/
14+
async initialize(url) {
15+
// Add code here to initialize your app
16+
// 1. Create the fixed HTML elements of your page
17+
// 2. Make an initial XMLHttpRequest using Util.fetchJSON() to populate your <select> element
18+
19+
const root = document.getElementById('root');
20+
21+
Util.createAndAppend('h1', root, { text: 'It works!' }); // TODO: replace with your own code
22+
23+
try {
24+
const repos = await Util.fetchJSON(url);
25+
this.repos = repos.map(repo => new Repository(repo));
26+
// TODO: add your own code here
27+
} catch (error) {
28+
this.renderError(error);
29+
}
30+
}
31+
32+
/**
33+
* Removes all child elements from a container element
34+
* @param {*} container Container element to clear
35+
*/
36+
static clearContainer(container) {
37+
while (container.firstChild) {
38+
container.removeChild(container.firstChild);
39+
}
40+
}
41+
42+
/**
43+
* Fetch contributor information for the selected repository and render the
44+
* repo and its contributors as HTML elements in the DOM.
45+
* @param {number} index The array index of the repository.
46+
*/
47+
async fetchContributorsAndRender(index) {
48+
try {
49+
const repo = this.repos[index];
50+
const contributors = await repo.fetchContributors();
51+
52+
const container = document.getElementById('container');
53+
App.clearContainer(container);
54+
55+
const leftDiv = Util.createAndAppend('div', container);
56+
const rightDiv = Util.createAndAppend('div', container);
57+
58+
const contributorList = Util.createAndAppend('ul', rightDiv);
59+
60+
repo.render(leftDiv);
61+
62+
contributors
63+
.map(contributor => new Contributor(contributor))
64+
.forEach(contributor => contributor.render(contributorList));
65+
} catch (error) {
66+
this.renderError(error);
67+
}
68+
}
69+
70+
/**
71+
* Render an error to the DOM.
72+
* @param {Error} error An Error object describing the error.
73+
*/
74+
renderError(error) {
75+
return error;
76+
// console.log(error); // TODO: replace with your own code
77+
}
78+
}
79+
80+
const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
81+
82+
window.onload = () => new App(HYF_REPOS_URL);

Week3/part2/Contributor.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
/* global Util */
4+
5+
// eslint-disable-next-line no-unused-vars
6+
class Contributor {
7+
constructor(contributor) {
8+
this.contributor = contributor;
9+
}
10+
11+
/**
12+
* Render the contributor info to the DOM.
13+
* @param {HTMLElement} container The container element in which to render the contributor.
14+
*/
15+
render(container) {
16+
// TODO: replace the next line with your code.
17+
Util.createAndAppend('pre', container, JSON.stringify(this.contributor, null, 2));
18+
}
19+
}

Week3/part2/Repository.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
/* global Util */
4+
5+
// eslint-disable-next-line no-unused-vars
6+
class Repository {
7+
constructor(repository) {
8+
this.repository = repository;
9+
}
10+
11+
/**
12+
* Render the repository info to the DOM.
13+
* @param {HTMLElement} container The container element in which to render the repository.
14+
*/
15+
render(container) {
16+
// TODO: replace the next line with your code.
17+
Util.createAndAppend('pre', container, JSON.stringify(this.repository, null, 2));
18+
}
19+
20+
/**
21+
* Returns an array of contributors as a promise
22+
*/
23+
fetchContributors() {
24+
return Util.fetchJSON(this.repository.contributors_url);
25+
}
26+
27+
/**
28+
* Returns the name of the repository
29+
*/
30+
name() {
31+
return this.repository.name;
32+
}
33+
}

Week3/part2/Util.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
// eslint-disable-next-line no-unused-vars
4+
class Util {
5+
static createAndAppend(name, parent, options = {}) {
6+
const elem = document.createElement(name);
7+
parent.appendChild(elem);
8+
Object.keys(options).forEach(key => {
9+
const value = options[key];
10+
if (key === 'text') {
11+
elem.textContent = value;
12+
} else {
13+
elem.setAttribute(key, value);
14+
}
15+
});
16+
return elem;
17+
}
18+
19+
static fetchJSON(url) {
20+
return new Promise((resolve, reject) => {
21+
const xhr = new XMLHttpRequest();
22+
xhr.open('GET', url);
23+
xhr.responseType = 'json';
24+
xhr.onload = () => {
25+
if (xhr.status < 400) {
26+
resolve(xhr.response);
27+
} else {
28+
reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
29+
}
30+
};
31+
xhr.onerror = () => reject(new Error('Network request failed'));
32+
xhr.send();
33+
});
34+
}
35+
}

Week3/part2/hyf.png

6.81 KB
Loading

Week3/part2/index.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
7+
<meta name="theme-color" content="#000000">
8+
<meta name="apple-mobile-web-app-capable" content="yes">
9+
<meta name="mobile-web-app-capable" content="yes">
10+
<meta name="format-detection" content="telephone=no">
11+
<link rel="apple-touch-icon" href="./hyf.png">
12+
<link rel="shortcut icon" type="image/png" href="./hyf.png" />
13+
<title>HYF-GITHUB</title>
14+
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet">
15+
<link rel="stylesheet" href="./style.css">
16+
</head>
17+
18+
<body>
19+
<div id="root"></div>
20+
<script src="./index.js"></script>
21+
</body>
22+
23+
</html>

Week3/part2/index.js

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
'use strict';
2+
3+
{
4+
function fetchJSON(url) {
5+
return new Promise((resolve, reject) => {
6+
const xhr = new XMLHttpRequest();
7+
xhr.open('GET', url);
8+
xhr.responseType = 'json';
9+
xhr.onload = () => {
10+
if (xhr.status < 400) {
11+
resolve(xhr.response);
12+
} else {
13+
reject(new Error(`Network error: ${xhr.status} - ${xhr.statusText}`));
14+
}
15+
};
16+
xhr.onerror = () => reject(new Error('Network request failed'));
17+
xhr.send();
18+
});
19+
}
20+
21+
function createAndAppend(name, parent, options = {}) {
22+
const elem = document.createElement(name);
23+
parent.appendChild(elem);
24+
Object.keys(options).forEach(key => {
25+
const value = options[key];
26+
if (key === 'text') {
27+
elem.textContent = value;
28+
} else {
29+
elem.setAttribute(key, value);
30+
}
31+
});
32+
return elem;
33+
}
34+
35+
// Display repository options in the header
36+
function selectOptions(nameOption) {
37+
const selectRepoHYF = document.getElementById('selectRepoHYF');
38+
for (let i = 0; i < nameOption.length; i++) {
39+
createAndAppend('option', selectRepoHYF, { value: i, text: nameOption[i].name });
40+
}
41+
}
42+
43+
// Information on left side inside a table
44+
function displayInformation(element) {
45+
const container = document.getElementById('container');
46+
const infoDiv = createAndAppend('div', container, {
47+
id: 'leftArea',
48+
class: 'left-div whiteframe',
49+
});
50+
createAndAppend('table', infoDiv, { id: 'table' });
51+
const table = document.getElementById('table');
52+
createAndAppend('tbody', table, { id: 'tbody' });
53+
function createTableRow(label, description) {
54+
const tRow = createAndAppend('tr', table);
55+
createAndAppend('td', tRow, { text: label, class: 'label' });
56+
createAndAppend('td', tRow, { text: description });
57+
}
58+
59+
createTableRow('Repository: ', element.name);
60+
createTableRow('Description: ', element.description);
61+
createTableRow('Forks : ', element.forks);
62+
const date2 = new Date(element.updated_at).toLocaleString();
63+
createTableRow('Updated: ', date2);
64+
}
65+
66+
// Show contributors
67+
function contributorsList(element) {
68+
fetchJSON(element.contributors_url).then(data => {
69+
const container = document.getElementById('container');
70+
createAndAppend('div', container, {
71+
id: 'rightArea',
72+
class: 'right-div whiteframe',
73+
});
74+
const rightArea = document.getElementById('rightArea');
75+
createAndAppend('p', rightArea, {
76+
text: 'Contributions',
77+
class: 'contributor-header',
78+
});
79+
createAndAppend('ul', rightArea, {
80+
id: 'contList',
81+
class: 'contributor-list',
82+
});
83+
let contributorURL;
84+
let contributorItem;
85+
let contributorData;
86+
const contList = document.getElementById('contList');
87+
for (let i = 0; i < data.length; i++) {
88+
contributorURL = createAndAppend('a', contList, {
89+
href: data[i].html_url,
90+
target: '_blank',
91+
});
92+
contributorItem = createAndAppend('li', contributorURL, {
93+
class: 'contributor-item',
94+
});
95+
96+
createAndAppend('img', contributorItem, {
97+
src: data[i].avatar_url,
98+
class: 'contributor-avatar',
99+
});
100+
contributorData = createAndAppend('div', contributorItem, {
101+
class: 'contributor-data',
102+
});
103+
createAndAppend('div', contributorData, { text: data[i].login });
104+
createAndAppend('div', contributorData, {
105+
text: data[i].contributions,
106+
class: 'contributor-badge',
107+
});
108+
}
109+
});
110+
}
111+
112+
async function main(url) {
113+
const root = document.getElementById('root');
114+
try {
115+
const data = await fetchJSON(url);
116+
data.sort((a, b) => a.name.localeCompare(b.name));
117+
createAndAppend('header', root, { id: 'topArea', class: 'header' });
118+
const topArea = document.getElementById('topArea');
119+
createAndAppend('p', topArea, { id: 'title', text: 'HYF Repositories' });
120+
createAndAppend('select', topArea, { id: 'selectRepoHYF', class: 'repo-selector' });
121+
createAndAppend('div', root, { id: 'container' });
122+
selectOptions(data);
123+
displayInformation(data[0]);
124+
contributorsList(data[0]);
125+
126+
document.getElementById('selectRepoHYF').onchange = function startListener() {
127+
const selectedItem = this.options[this.selectedIndex].value;
128+
const infoLeft = document.getElementById('leftArea');
129+
infoLeft.parentNode.removeChild(infoLeft);
130+
const contributors = document.getElementById('rightArea');
131+
contributors.parentNode.removeChild(contributors);
132+
133+
displayInformation(data[selectedItem]);
134+
contributorsList(data[selectedItem]);
135+
};
136+
} catch (err) {
137+
createAndAppend('div', root, { text: err.message, class: 'alert-error' });
138+
}
139+
}
140+
141+
const HYF_REPOS_URL = 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100';
142+
143+
window.onload = () => main(HYF_REPOS_URL);
144+
}

Week3/part2/index2.html

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta
6+
name="viewport"
7+
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
8+
/>
9+
<meta name="theme-color" content="#000000" />
10+
<meta name="apple-mobile-web-app-capable" content="yes" />
11+
<meta name="mobile-web-app-capable" content="yes" />
12+
<meta name="format-detection" content="telephone=no" />
13+
<link rel="apple-touch-icon" href="./hyf.png" />
14+
<link rel="shortcut icon" type="image/png" href="./hyf.png" />
15+
<title>HYF-GITHUB</title>
16+
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700" rel="stylesheet" />
17+
<link rel="stylesheet" href="./style.css" />
18+
</head>
19+
20+
<body>
21+
<div id="root"></div>
22+
<script src="./Util.js"></script>
23+
<script src="./Repository.js"></script>
24+
<script src="./Contributor.js"></script>
25+
<script src="./App.js"></script>
26+
</body>
27+
</html>

0 commit comments

Comments
 (0)