From efe5741cc5b85e2e1b5407a1d099b651a566bc39 Mon Sep 17 00:00:00 2001 From: "dot.not" Date: Thu, 26 Mar 2020 22:24:02 +0200 Subject: [PATCH 01/17] Commiting JS-3 Homework for week 1 & 2 --- .../js-exercises/common-files/api-axios.js | 17 + .../js-exercises/common-files/api-xhr.js | 22 ++ .../js-exercises/ex01-random-user/index.html | 28 ++ .../js-exercises/ex01-random-user/main.css | 67 ++++ .../js-exercises/ex01-random-user/main.js | 60 +++ .../js-exercises/ex02-random-humor/index.html | 30 ++ .../js-exercises/ex02-random-humor/main.css | 87 +++++ .../js-exercises/ex02-random-humor/main.js | 84 ++++ .../ex03-dog-photo-gallery/index.html | 24 ++ .../ex03-dog-photo-gallery/main.css | 78 ++++ .../ex03-dog-photo-gallery/main.js | 50 +++ .../project-hack-your-repo-I/hyf.png | Bin 0 -> 9116 bytes .../project-hack-your-repo-I/index.html | 23 ++ .../project-hack-your-repo-I/index.js | 94 +++++ .../project-hack-your-repo-I/style.css | 138 +++++++ .../project-hack-your-repo-II/hyf.png | Bin 0 -> 9116 bytes .../project-hack-your-repo-II/index.html | 66 ++++ .../project-hack-your-repo-II/index.js | 367 ++++++++++++++++++ .../project-hack-your-repo-II/options.png | Bin 0 -> 1348 bytes .../project-hack-your-repo-II/style.css | 204 ++++++++++ 20 files changed, 1439 insertions(+) create mode 100644 Week1/homework/js-exercises/common-files/api-axios.js create mode 100644 Week1/homework/js-exercises/common-files/api-xhr.js create mode 100644 Week1/homework/js-exercises/ex01-random-user/index.html create mode 100644 Week1/homework/js-exercises/ex01-random-user/main.css create mode 100644 Week1/homework/js-exercises/ex01-random-user/main.js create mode 100644 Week1/homework/js-exercises/ex02-random-humor/index.html create mode 100644 Week1/homework/js-exercises/ex02-random-humor/main.css create mode 100644 Week1/homework/js-exercises/ex02-random-humor/main.js create mode 100644 Week1/homework/js-exercises/ex03-dog-photo-gallery/index.html create mode 100644 Week1/homework/js-exercises/ex03-dog-photo-gallery/main.css create mode 100644 Week1/homework/js-exercises/ex03-dog-photo-gallery/main.js create mode 100644 Week1/homework/js-exercises/project-hack-your-repo-I/hyf.png create mode 100644 Week1/homework/js-exercises/project-hack-your-repo-I/index.html create mode 100644 Week1/homework/js-exercises/project-hack-your-repo-I/index.js create mode 100644 Week1/homework/js-exercises/project-hack-your-repo-I/style.css create mode 100644 Week2/homework/project-hack-your-repo-II/hyf.png create mode 100644 Week2/homework/project-hack-your-repo-II/index.html create mode 100644 Week2/homework/project-hack-your-repo-II/index.js create mode 100644 Week2/homework/project-hack-your-repo-II/options.png create mode 100644 Week2/homework/project-hack-your-repo-II/style.css diff --git a/Week1/homework/js-exercises/common-files/api-axios.js b/Week1/homework/js-exercises/common-files/api-axios.js new file mode 100644 index 000000000..adf85c0b9 --- /dev/null +++ b/Week1/homework/js-exercises/common-files/api-axios.js @@ -0,0 +1,17 @@ + + function requestByAxios (theURL,onSuccess,onFailure) { + axios.get(theURL) + .then(function(aResponse) { + // console.log('Axios call success! '); + // console.log(aResponse); + onSuccess(aResponse.data); + }) + .catch(function(anError) { + // console.log('Axios call failed with following message: '); + // console.log(anError); + onFailure('Axios',undefined,anError); + }); + }; + +; + diff --git a/Week1/homework/js-exercises/common-files/api-xhr.js b/Week1/homework/js-exercises/common-files/api-xhr.js new file mode 100644 index 000000000..5ca0ce102 --- /dev/null +++ b/Week1/homework/js-exercises/common-files/api-xhr.js @@ -0,0 +1,22 @@ + + function requestByXHR (theURL,onSuccess,onFailure) { + let myXHR=new XMLHttpRequest(); + myXHR.onreadystatechange=function() { + if (myXHR.readyState===XMLHttpRequest.DONE){ + if (myXHR.status===200) { + // console.log('XHR call success! '); + // console.log(JSON.parse(myXHR.responseText)); + onSuccess(JSON.parse(myXHR.responseText)); + } else { + // console.log(`XHR call failed with status=[${myXHR.status}] `); + // if (myXHR.statusText) {console.log(myXHR.statusText)}; + onFailure('XHR',myXHR.status,myXHR.statusText); + }; + }; + }; + myXHR.open("GET",theURL,true); + myXHR.send(); + }; + +; + diff --git a/Week1/homework/js-exercises/ex01-random-user/index.html b/Week1/homework/js-exercises/ex01-random-user/index.html new file mode 100644 index 000000000..401112b91 --- /dev/null +++ b/Week1/homework/js-exercises/ex01-random-user/index.html @@ -0,0 +1,28 @@ + + + + + + + + + + +
+ +
+
+ +
+
+
+ +
+ + + + + + + + diff --git a/Week1/homework/js-exercises/ex01-random-user/main.css b/Week1/homework/js-exercises/ex01-random-user/main.css new file mode 100644 index 000000000..489920058 --- /dev/null +++ b/Week1/homework/js-exercises/ex01-random-user/main.css @@ -0,0 +1,67 @@ + +* { + box-sizing: border-box; + margin: 0px; + padding: 0px; +} + +body { + margin: 0px 18px; + font-family: sans-serif; + font-size: 1.5em; +} + +table { + padding: 0px 0px 10px; +} + +td { + padding: 0px 12px 3px 0px; +} + +hr { + display: block; + margin: 12px auto 12px; + color: navy; + border-style: outset; + border-width: 2px; +} + +.cls_text_align_left { + text-align: left; +} + +.cls_text_align_right { + text-align: right; +} + +.cls_text_align_center { + text-align: center; +} + +.cls_unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +#id_page_header { + padding: 12px 16px 8px 16px; + margin: 20px 0 0; +} + +.cls_api_data_container { + background: linear-gradient(to bottom right, orange, gold); + border-radius: 12px; + font-size: 1.2rem; + padding: 20px; + margin-top: 15px; + margin-left: 10px; + display: inline-block; +} + +; + diff --git a/Week1/homework/js-exercises/ex01-random-user/main.js b/Week1/homework/js-exercises/ex01-random-user/main.js new file mode 100644 index 000000000..2c32e0ca9 --- /dev/null +++ b/Week1/homework/js-exercises/ex01-random-user/main.js @@ -0,0 +1,60 @@ + +{ + 'use strict'; + + let lmntRef=document.getElementById('id_page_header'); + lmntRef.style.backgroundColor='gold'; + document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML= + `(Homework: Javascript 3 - week 1) - (Exercise 01: randomuser API with XHR & Axios)`; + lmntRef.style.borderRadius='12px'; + document.body.style.backgroundColor='#102030'; + + const symbolEuro='€'; + const symbolApostrophe='’'; /* ’ or ´ or ‘ */ + + const xhrListRef=document.getElementById('id_list_xhr_data'); + const axiosListRef=document.getElementById('id_list_axios_data'); + const targetURL='https://www.randomuser.me/api'; + + apiCallThroughXHR(); + apiCallThroughAxios(); + + function apiCallThroughXHR(){ + xhrListRef.innerHTML=createProgressHTML(); + requestByXHR(targetURL,(apiData)=>{xhrListRef.innerHTML=createDataHTML(apiData.results[0])} + ,(apiMethod,errorStatus,errorMsg)=>{xhrListRef.innerHTML=createErrorHTML(errorStatus,errorMsg)}); + }; + + function apiCallThroughAxios() { + axiosListRef.innerHTML=createProgressHTML(); + requestByAxios(targetURL,(apiData)=>{axiosListRef.innerHTML=createDataHTML(apiData.results[0])} + ,(apiMethod,errorStatus,errorMsg)=>{axiosListRef.innerHTML=createErrorHTML(errorStatus,errorMsg)}); + }; + + function createDataHTML(theData) { + return `Name(${theData.name.title}) ${ + theData.name.first} ${theData.name.last} ` + + `Gender${theData.gender} ` + + `Born${theData.dob.date.substr(0,10)} ` + + `Age${theData.dob.age} ` + + `Email${theData.email} ` + + `Country${theData.location.country} ` + + `City${theData.location.city} `; + } + + function createErrorHTML(theStatus,theMessage) { + return 'ResultUnsuccessful ' + + ' ' + + `Status code${theStatus} ` + + ' ' + + `Message${theMessage} `; + } + + function createProgressHTML() + {return 'RequestSending in progress... ';} + +} + + +; + diff --git a/Week1/homework/js-exercises/ex02-random-humor/index.html b/Week1/homework/js-exercises/ex02-random-humor/index.html new file mode 100644 index 000000000..e8740c1bd --- /dev/null +++ b/Week1/homework/js-exercises/ex02-random-humor/index.html @@ -0,0 +1,30 @@ + + + + + + + + + + +
+ +
+ +
+ + +
+ +
+
+
+ + + + + + + + diff --git a/Week1/homework/js-exercises/ex02-random-humor/main.css b/Week1/homework/js-exercises/ex02-random-humor/main.css new file mode 100644 index 000000000..7feef5b12 --- /dev/null +++ b/Week1/homework/js-exercises/ex02-random-humor/main.css @@ -0,0 +1,87 @@ + +* { + box-sizing: border-box; + margin: 0px; + padding: 0px; +} + +body { + margin: 0px 18px; + font-family: sans-serif; + font-size: 1.5em; +} + +table { + border-spacing: 0; +} + +tr { + background: linear-gradient(to bottom right, gold, orange); +} + +td { + vertical-align: top; + padding: 1px 4px; + max-width: 58vw; + overflow: hidden; + text-overflow: ellipsis; +} + +img { + margin: 0 10px 10px 0; + height: 100%; + border-width: 2px; + border-style: outset; +} + +hr { + display: block; + margin: 12px auto 12px; + color: navy; + border-style: outset; + border-width: 2px; +} + +.cls_text_align_left { + text-align: left; +} + +.cls_text_align_right { + text-align: right; +} + +.cls_text_align_center { + text-align: center; +} + +.cls_unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.cls_page_header { + padding: 12px 16px 8px 16px; + margin: 20px 0px; +} + +.cls_api_container { + background-color: orange; + font-size: 1.2rem; + padding: 12px 16px; + margin-top: 10px; + border-radius: 16px; +} + +.cls_api_data_container { + padding-top: 10px; + display: flex; + flex-wrap: wrap; +} + + +; + diff --git a/Week1/homework/js-exercises/ex02-random-humor/main.js b/Week1/homework/js-exercises/ex02-random-humor/main.js new file mode 100644 index 000000000..1c900154a --- /dev/null +++ b/Week1/homework/js-exercises/ex02-random-humor/main.js @@ -0,0 +1,84 @@ + +{ + 'use strict'; + + let lmntRef=document.getElementById('id_page_header'); + lmntRef.style.backgroundColor='gold'; + document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML= + `(Homework: Javascript 3 - week 1) - (Exercise 02: Load image given by API with XHR & Axios)`; + lmntRef.style.borderRadius='12px'; + document.body.style.backgroundColor='#102030'; + lmntRef=document.getElementById('id_page_info'); + lmntRef.style.backgroundColor='gold'; + lmntRef.innerHTML='Using randomuser’s api for images since xkcd’s api is throwing CORB'; + lmntRef.style.borderRadius='12px'; + + const symbolEuro='€'; + const symbolApostrophe='’'; /* ’ or ´ or ‘ */ + + const dataTableRef=document.getElementById('id_api_data_table'); + const dataImageRef=document.getElementById('id_api_data_image'); + + const targetURL='https://www.randomuser.me/api'; + + apiCallThroughXHR(); + + function apiCallThroughXHR(){ + showRequestStart('XHR'); + requestByXHR(targetURL,showRequestData,showRequestError); + }; + + function apiCallThroughAxios() { + showRequestStart('Axios'); + requestByAxios(targetURL,showRequestData,showRequestError); + }; + + function showRequestStart(theMethod) { + resetInfo(); + dataTableRef.innerHTML= + 'Requestin progress... ' + + ' ' + + `from${targetURL} ` + + ' ' + + `with${theMethod} `; + }; + + function showRequestError(theMethod,theStatus,theMessage) { + resetInfo(); + dataTableRef.innerHTML= + `RequestUnsuccessful ` + + ' ' + + `from${targetURL} ` + + ' ' + + `with${theMethod} ` + + ' ' + + `Status code${theStatus} ` + + ' ' + + `Message${theMessage} `; + }; + + function showRequestData(theData) { + const myData=theData.results[0]; + resetInfo(); + dataTableRef.innerHTML= + `Name(${myData.name.title}) ${ + myData.name.first} ${myData.name.last} ` + + `Gender${myData.gender} ` + + `Born${myData.dob.date.substr(0,10)} ` + + `Age${myData.dob.age} ` + + `Email${myData.email} ` + + `Country${myData.location.country} ` + + `City${myData.location.city} `; + dataImageRef.setAttribute('src',myData.picture.large); + dataImageRef.hidden=false; + }; + + function resetInfo() { + dataTableRef.innerHTML=''; + dataImageRef.hidden=true; + }; +}; + + +; + diff --git a/Week1/homework/js-exercises/ex03-dog-photo-gallery/index.html b/Week1/homework/js-exercises/ex03-dog-photo-gallery/index.html new file mode 100644 index 000000000..08675e679 --- /dev/null +++ b/Week1/homework/js-exercises/ex03-dog-photo-gallery/index.html @@ -0,0 +1,24 @@ + + + + + + + + + + +
+ + + +

id_api_status_text

+ + + + + + + + + diff --git a/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.css b/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.css new file mode 100644 index 000000000..589e4eda3 --- /dev/null +++ b/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.css @@ -0,0 +1,78 @@ + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background-color: #102030; + font-size: 1.2rem; + color: gold; + margin: 0px 18px; + font-family: sans-serif; +} + +ul { + list-style-type: none; + display: grid; + grid-template-columns:repeat(auto-fit,minmax(24rem,1fr)); + grid-gap: 4px 6px; + transform: rotate(180deg); +} + +li { + transform: rotate(180deg); + max-width: 84vmin; +} + +img { + width: 100%; +} + +hr { + display: block; + margin: 12px auto 12px; + color: navy; + border-style: outset; + border-width: 2px; +} + +.cls_text_align_left { + text-align: left; +} + +.cls_text_align_right { + text-align: right; +} + +.cls_text_align_center { + text-align: center; +} + +.cls_unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.cls_page_header { + background-color: gold; + font-size: 1.5em; + color: black; + border-radius: 12px; + margin: 20px 0px; + padding: 12px 16px 8px 16px; +} + +#id_api_status_text { + margin-top: 10px; + margin-bottom: 10px; +} + + +; + diff --git a/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.js b/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.js new file mode 100644 index 000000000..b4594230f --- /dev/null +++ b/Week1/homework/js-exercises/ex03-dog-photo-gallery/main.js @@ -0,0 +1,50 @@ + +{ + 'use strict'; + + let lmntRef=document.getElementById('id_page_header'); + document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML= + `(Homework: Javascript 3 - week 1) - (Exercise 03: Dog photo API with XHR & Axios)`; + + const symbolEuro='€'; + const symbolApostrophe='’'; /* ’ or ´ or ‘ */ + + const dataTextRef=document.getElementById('id_api_status_text'); + const dataListRef=document.getElementById('id_api_data_list'); + + const targetURL='https://dog.ceo/api/breeds/image/random'; + + apiCallThroughXHR(); + + function apiCallThroughXHR(){ + showRequestStart('XHR'); + requestByXHR(targetURL,showRequestData,showRequestError); + }; + + function apiCallThroughAxios() { + showRequestStart('Axios'); + requestByAxios(targetURL,showRequestData,showRequestError); + }; + + function showRequestStart(theMethod) { + dataTextRef.innerHTML=`API Request at ${targetURL} by ${theMethod}`; + }; + + function showRequestError(theMethod,theStatus,theMessage) { + dataTextRef.innerHTML=theMethod+` Request failed with status=[${ + theStatus}] and message=[${theMessage}] `; + }; + + function showRequestData(theData) { + const itemRef=document.createElement('LI'); + dataListRef.appendChild(itemRef); + const imgRef=document.createElement('IMG'); + imgRef.setAttribute('src',theData.message); + itemRef.appendChild(imgRef); + dataTextRef.innerHTML='Concluded'; + }; +}; + + +; + diff --git a/Week1/homework/js-exercises/project-hack-your-repo-I/hyf.png b/Week1/homework/js-exercises/project-hack-your-repo-I/hyf.png new file mode 100644 index 0000000000000000000000000000000000000000..76bc5a13b4a53ea97a6c09ca5fe399f40ab20e4e GIT binary patch literal 9116 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 GkN*WepL25n literal 0 HcmV?d00001 diff --git a/Week1/homework/js-exercises/project-hack-your-repo-I/index.html b/Week1/homework/js-exercises/project-hack-your-repo-I/index.html new file mode 100644 index 000000000..9c8f80c1a --- /dev/null +++ b/Week1/homework/js-exercises/project-hack-your-repo-I/index.html @@ -0,0 +1,23 @@ + + + + + + + + + + + + + HYF-GITHUB + + + + + +
+ + + + \ No newline at end of file diff --git a/Week1/homework/js-exercises/project-hack-your-repo-I/index.js b/Week1/homework/js-exercises/project-hack-your-repo-I/index.js new file mode 100644 index 000000000..45b769764 --- /dev/null +++ b/Week1/homework/js-exercises/project-hack-your-repo-I/index.js @@ -0,0 +1,94 @@ + +'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); + parent.appendChild(elem); + Object.entries(options).forEach(([key, value]) => { + if (key === 'text') { + elem.textContent = value; + } else { + elem.setAttribute(key, value); + } + }); + return elem; + } + + function renderRepoDetails(repo, ul) { + createAndAppend('li', ul, { text: repo.name }); + } + + function renderRepoData(repoData,ul) { + const extractDateTime=(dtString)=>dtString.substr(0,10)+' '+dtString.substr(11,8); + const rowHTML=(aLabel,aValue,aLink)=>{ + const anStr='title="Click for transition to related page." target="_blank"'; + aValue=((aValue==undefined)||(aValue==null)||(String(aValue).trim()==='')) + ?'-':aValue; + aValue=((aLink==undefined)||(aLink==null)||(String(aLink).trim()==='')) + ?aValue:`${aValue}`; + return `${aLabel}${aValue}` + }; + repoData.sort((argA,argB)=>argA.name.localeCompare(argB.name)); + for (let i=0; i<10; i++) { + const symbolExpandCollapse=(isHidden)=>isHidden?'➕':'➖'; // or '⏬ ':'⏫ ' + const listItemRef=createAndAppend('LI',ul); + const initialHidden=false; + const itemRef=createAndAppend('DIV',listItemRef,{id:'id'+'_data_item_'+i + ,class:'cls_hover_highlight',text:`(${ + symbolExpandCollapse(initialHidden)}) `+repoData[i].name + ,title:'Click to expand / collapse the details'}); + itemRef.onclick=function(e) { + const trgtRef=document.getElementById(this.id+'_detail'); + trgtRef.hidden=!trgtRef.hidden; + this.textContent='('+symbolExpandCollapse(trgtRef.hidden) + +this.textContent.substr(2); + } + const detailRef=createAndAppend('DIV',listItemRef + ,{id:itemRef.id+'_detail',class:'cls_alt_color'}); + detailRef.hidden=initialHidden; + const tableRef=createAndAppend('TABLE',detailRef); + tableRef.innerHTML= rowHTML('Name (and link):',repoData[i].name,repoData[i].html_url) + + rowHTML('Description:',repoData[i].description) + + rowHTML('Forks:',repoData[i].forks_count) + + rowHTML('Created:',extractDateTime(repoData[i].created_at)) + + rowHTML('Updated:',extractDateTime(repoData[i].updated_at)); + }; + }; + + function main(url) { + const root=document.getElementById('root'); + createAndAppend('DIV',root,{class:'cls_colored_header',text:'HYF Repositories'}); + root.setAttribute('class','cls_unselectable'); + fetchJSON(url, (err, repos) => { + if (err) { + createAndAppend('div',root,{text:err.message,class:'alert-error'}); + return; + } + renderRepoData(repos,createAndAppend('UL',root)); + }); + } + + const HYF_REPOS_URL = + 'https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; + window.onload = () => main(HYF_REPOS_URL); +}; + + +; + diff --git a/Week1/homework/js-exercises/project-hack-your-repo-I/style.css b/Week1/homework/js-exercises/project-hack-your-repo-I/style.css new file mode 100644 index 000000000..31425126a --- /dev/null +++ b/Week1/homework/js-exercises/project-hack-your-repo-I/style.css @@ -0,0 +1,138 @@ + + +:root { + --normal_back_color: wheat; + --normal_text_color: black; + --attention_back_color: lightblue; + --alternate_back_color: #0a1a3e; // dark blue-black + --alternate_text_color: #efefef; + --interactive_back_color: silver; + --interactive_text_color: black; + --hover_back_color: orange; + --hover_text_color: black; + --focus_back_color: yellow; + --focus_text_color: black; + --alert_back_color: red; + --alert_text_color: gold; +} + + +* { + vertical-align: middle; + padding: 0; + margin: 0; + cursor: default; + box-sizing: border-box; +} + + +:focus { + background-color: var(--focus_back_color); + outline: none; +} + + +body { + background-color: var(--normal_back_color); + color: var(--alternate_back_color); + margin-top: 5px; + font-size: 1.5rem; + font-family: "Roboto", sans-serif; +} +body:before { + background: url("./hyf.png"); + background-size: cover; + content: " "; + position: fixed; + z-index: -1; + width: 42vmin; + height: 42vmin; + top: 1rem; + right: 1rem; + opacity: 0.24; +} + + +div { + padding: 16px 20px; +} + + +li { + list-style-type: none; +} + + +td { + padding: 0px 12px 3px 0px; + vertical-align: top; +} + + +a { + background-color: var(--interactive_back_color); + padding: 0 12px; +} +a:hover { + background-color: var(--hover_back_color); + text-decoration: none; +} + + +.cls_colored_header { + background: linear-gradient(to right, var(--attention_back_color) , rgba(128,128,128,0) ); + font-weight: bold; + font-size: 1.7rem; + font-style: italic; +} + + +.cls_alt_color { + background: linear-gradient(to right, var(--attention_back_color) , rgba(128,128,128,0) ); +} + + +.cls_hover_highlight { + background: linear-gradient(to right, var(--interactive_back_color) , rgba(128,128,128,0) ); + margin-top: 8px; + font-weight: bold; + z-index: 1; + position: relative; +} +.cls_hover_highlight::before { + background: linear-gradient(to right, var(--hover_back_color) , rgba(128,128,128,0.05) ); + content: ""; + position: absolute; + opacity: 0; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: -1; + transition: opacity 203ms linear; +} +.cls_hover_highlight:hover::before { + opacity: 1; +} + + +.alert-error { + background: linear-gradient(to right, var(--alert_back_color) , rgba(128,128,128,0) ); + color: var(--alert_text_color); + font-size: 2rem; + font-weight: bold; +} + + +.cls_unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + + +; + diff --git a/Week2/homework/project-hack-your-repo-II/hyf.png b/Week2/homework/project-hack-your-repo-II/hyf.png new file mode 100644 index 0000000000000000000000000000000000000000..76bc5a13b4a53ea97a6c09ca5fe399f40ab20e4e GIT binary patch literal 9116 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 GkN*WepL25n literal 0 HcmV?d00001 diff --git a/Week2/homework/project-hack-your-repo-II/index.html b/Week2/homework/project-hack-your-repo-II/index.html new file mode 100644 index 000000000..845356a90 --- /dev/null +++ b/Week2/homework/project-hack-your-repo-II/index.html @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + HYF-GITHUB + + + + + + + +
+

+ Due to GitHub’s strict rules on API request frequency, + you may experience a "forbidden" response. +

+

+ In that case ( or for testing, or even for fun ) + you can use the following options to "emulate" + API data fetching with sample / random Data. +

+

+ Note: set options persist even after page refresh, + thus enabling them to influence the initial auto-fetch + that creates the Repository List. +

+ + + + + + + + + + + + + + + + + +
Return emulated data on next fetch ?
Force example error on next fetch ?
Force empty result on next fetch ?
Keep Options visible on page refresh ?
+
+ +
+ + + + + diff --git a/Week2/homework/project-hack-your-repo-II/index.js b/Week2/homework/project-hack-your-repo-II/index.js new file mode 100644 index 000000000..1b9c17ae9 --- /dev/null +++ b/Week2/homework/project-hack-your-repo-II/index.js @@ -0,0 +1,367 @@ + +'use strict'; + +{ + const root=document.getElementById('root'); + // root.setAttribute('class','cls_unselectable'); + // + const hdrRef=addToDOM('DIV',root,{class:'cls_colored_header'}); + const msgRef=addToDOM('SPAN',addToDOM('DIV',hdrRef + ,{class:'cls_responsive_child cls_padded_area'}) + ,{text:'API data request in progress'}); + const dtlRef=addToDOM('DIV',root,{class:'cls_responsive_parent'}); + const contribSymbolKey=Symbol('DOT.NOT: contributor list key'); + // + const optEmulation =document.getElementById('id_opt_emulation'); + const optForceError=document.getElementById('id_opt_force_error'); + const optForceEmpty=document.getElementById('id_opt_force_empty'); + const optKeepVisible=document.getElementById('id_opt_keep_visible'); + const optAreaRef=document.getElementById('id_options_area'); + optAreaRef.hidden=!optKeepVisible.checked; + const optButton=document.getElementById('id_options_image'); + const optBtnTitle=()=>{return `Tap to ${optAreaRef.hidden?'show':'hide'} Options`}; + optButton.title=optBtnTitle(); + optButton.onclick=()=>{ + optAreaRef.hidden=!optAreaRef.hidden; + optButton.title=optBtnTitle(); + }; + let repoData=[],selectRef; + const rootURL='https://api.github.com/orgs/HackYourFuture/repos?per_page=100'; + // + window.onload=()=>{ + fetchWrapper('repositories',(theResponse)=>{ + repoData=clone_JSON_object(theResponse) // theResponse + .map(lmnt=>{return { + name :getSecureValue(lmnt.name,'- not named -'), + description :getSecureValue(lmnt.description,'-'), + forks_count :getSecureValue(lmnt.forks_count,'0'), + created_at :getSecureValue(lmnt.created_at,'-'), + updated_at :getSecureValue(lmnt.updated_at,'-'), + html_url :getSecureValue(lmnt.html_url), + contributors_url:getSecureValue(lmnt.contributors_url), + }}) + .sort((argA,argB)=>argA.name.localeCompare(argB.name)); + createRepoSelectionList(); + },(anError)=>{ + msgRef.textContent='API data request error.'; + addToDOM('div',root,{text:anError,class:'cls_error_alert'}); + }); + }; + + function createRepoSelectionList () { + if (repoData.length<1) { msgRef.textContent='No repositories available!'; + } else { + msgRef.textContent='HYF Repositories'; + selectRef=addToDOM('SELECT',addToDOM('DIV',hdrRef + ,{class:'cls_responsive_child cls_padded_area'})); + selectRef.innerHTML=repoData.reduce((tot,cur,idx)=> + tot+``,''); + selectRef.onchange=createRepoDetails; + createRepoDetails(); + } + }; + + function createRepoDetails() { + const had_onchange=(selectRef.onchange!==null); + if (had_onchange) {selectRef.onchange=null}; + const current_repoID=Number(selectRef.value); + removeChildrenFromDOM(dtlRef); + const repoRef=addToDOM('TABLE',addToDOM('DIV',addToDOM('DIV',dtlRef + ,{class:'cls_responsive_child'}),{class:'cls_alt_color cls_padded_area'})); + const theRepo=repoData[current_repoID]; + repoRef.innerHTML= tableRowHTML('Repository:',theRepo.name,theRepo.html_url) + + tableRowHTML('Description:',theRepo.description) + + tableRowHTML('Forks:',theRepo.forks_count) + + tableRowHTML('Created:',extractDateTime(theRepo.created_at)) + + tableRowHTML('Updated:',extractDateTime(theRepo.updated_at)); + const listRef=addToDOM('DIV',dtlRef + ,{class:'cls_responsive_child cls_alt_color cls_padded_area'}); + const titleRef=addToDOM('P',listRef,{text:'API data request in progress'}); + if (theRepo[contribSymbolKey]==undefined) { + fetchWrapper(theRepo.contributors_url,(theResponse)=>{ + theRepo[contribSymbolKey]=clone_JSON_object(theResponse) + .map(lmnt=>{return { + html_url :getSecureValue(lmnt.html_url), + avatar_url :getSecureValue(lmnt.avatar_url), + login :getSecureValue(lmnt.login,'-'), + contributions:getSecureValue(lmnt.contributions,'0') + }}); + createContribList(theRepo[contribSymbolKey]); + },(anError)=>{ + /* + // ignore any possible errors + // instead act as if contrib request returned empty list + // + // because the actual repo list contains repos + // that return an error when asked for contributors + // + // repos with error in contributor links + // english-booster + // hyfer-infra + // + // repo without contributors + // DataStructures + // + // + // BUT: make sure to console.log the link and error + // + titleRef.textContent='API data request error.'; + addToDOM('DIV',listRef,{text:anError}) + finalizeRepoDetails(); + */ + console.log('API request error for url',theRepo.contributors_url); + console.log('Error message',anError); + theRepo[contribSymbolKey]=[]; + createContribList(theRepo[contribSymbolKey]); + }); + } else { + createContribList(theRepo[contribSymbolKey]); + }; + function createContribList(theData) { + if (theData.length<1) {titleRef.textContent='No contributors available!'} + else { + titleRef.innerHTML='Contributions'; + const contRef=addToDOM('TABLE',addToDOM('DIV',listRef) + ,{class:'cls_span_full_parent_width'}); + let theHTML=''; + theData.forEach(lmnt=>{ + const theIMG=``; + theHTML+=`${tableCellHTML(theIMG)}${ + tableCellHTML(lmnt.login,lmnt.html_url)}${ + tableCellHTML(lmnt.contributions)}`; + }); + contRef.innerHTML=theHTML; + }; + finalizeRepoDetails(); + }; + function finalizeRepoDetails() { + if (current_repoID!=selectRef.value) {createRepoDetails()}; + if (had_onchange) {selectRef.onchange=createRepoDetails}; + }; + function tableRowHTML(aLabel,aValue,aLink) { + return `${tableCellHTML(aLabel,null,false,true)}${ + tableCellHTML(aValue,aLink,true)}`; + }; + function tableCellHTML(theValue,theLink=null,makeBold=false,makeItalic=false) { + let result=getValidAnchor(theValue,theLink); + if (makeBold) {result=`${result}`}; + if (makeItalic) {result=`${result}`}; + return `${result}`; + }; + function getValidAnchor(aText,aLink) { + const trg='title="Tap for transition to related page." target="_blank"'; + return isUndefinedNullEmpty(aLink)?aText:`${aText}`; + }; + function extractDateTime(dtString){ + return dtString.substr(0,10)+' '+dtString.substr(11,8); + }; + }; + + function isUndefinedNullEmpty(theData) { + return (theData==undefined)||(theData==null)||(String(theData).trim()===''); + }; + + function getSecureValue(theData,defValue='') { + return isUndefinedNullEmpty(theData)?defValue:theData; + }; + + function clone_JSON_object(theObject) {return JSON.parse(JSON.stringify(theObject))}; + + function addToDOM(theTag,theParent,theOptions={}) { + const lmnt=document.createElement(theTag); + Object.entries(theOptions).forEach(([aKey,aValue])=>{ + if (aKey==='text') {lmnt.textContent=aValue} + else {lmnt.setAttribute(aKey,aValue)}; + }); + theParent.appendChild(lmnt); + return lmnt; + }; + + function removeChildrenFromDOM (theLmnt) { + while (theLmnt.hasChildNodes()) { + removeChildrenFromDOM(theLmnt.lastChild); + theLmnt.removeChild(theLmnt.lastChild); + }; + }; + + function fetchWrapper (theResource,onData,onError) { + if (optEmulation.checked) { + if (theResource==='repositories') { + fetchTestData(optForceError.checked,optForceEmpty.checked + ,theResource,onData,onError); + } else { + fetchTestData(optForceError.checked,optForceEmpty.checked + ,'contributors',onData,onError); + }; + } else { + if (theResource==='repositories') { + if (optForceError.checked) { + const targetURL='https://api.github.com/orgs/HackYourFuture/Prepos?per_page=1'; + fetchData(targetURL,onData,onError); + } else if (optForceEmpty.checked) { + fetchTestData(false,true,theResource,onData,onError); + } else { + fetchData(rootURL,onData,onError); + }; + } else { + if (optForceError.checked) { + const targetURL='https://api.github.com/orgs/HackYourFuture/Prepos?per_page=1'; + fetchData(targetURL,onData,onError); + } else if (optForceEmpty.checked) { + fetchTestData(false,true,theResource,onData,onError); + } else { + fetchData(theResource,onData,onError); + }; + }; + }; + }; + + function fetchData (dataURL,dataCallback,errorCallback) { + fetch(dataURL) + .then((theResponse)=>{ + if (!theResponse.ok) { + const errPrefix=`Request Error: status=${theResponse.status} msg=`; + throw errPrefix+theResponse.statusText; + }; + return theResponse.json(); + }) + .then((theData)=>{dataCallback(theData)}) + .catch((anError)=>{errorCallback(anError)}); + }; + + function fetchTestData (produceError,produceEmpty,dataURL,dataCallback,errorCallback) { + function getRandomNumberBetween (minValue,maxValue){return (Math.floor(Math.pow(10,14)* + Math.random()*Math.random())%(maxValue-minValue+1))+minValue}; + function delayedCallback(argDelay,argCB,argData) {setTimeout(()=>{argCB(argData)},argDelay)}; + const repositories = [ + {name:'One Thing', description:'description of 1st One Thing', forks_count:7, + created_at:'2005-04-24T07:20:48Z', updated_at:'2019-01-11T18:21:37Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'one Thing', description:'description of 2nd one Thing', forks_count:3, + created_at:'2006-03-23T07:19:38Z', updated_at:'2017-09-05T15:52:37Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'one thing', description:'description of 3rd one thing', forks_count:1, + created_at:'2008-01-21T07:17:18Z', updated_at:'2013-11-15T11:02:37Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'One thing', description:'description of 4th One thing', forks_count:6, + created_at:'2007-02-22T07:18:28Z', updated_at:'2015-07-25T13:48:37Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'another thing', description:'another thing (missing link)', forks_count:4, + created_at:'2017-04-03T17:26:16Z', updated_at:'2020.01.11T05:46:02Z', + }, + {name:'that’s the thing', description:'description of that’s the thing', forks_count:1, + created_at:'2016-08-07T19:17:31Z', updated_at:'2017-09-14T10:34:47Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'The others', description:'description of The others', forks_count:7, + created_at:'2014-12-25T05:57:35Z', updated_at:'2020-02-13T21:31:47Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'JustLookAtThisGargantuanRepositoryNameWithEmptyDescription', description:' ', forks_count:9, + created_at:'2011-10-04T21:49:54Z', updated_at:'2013-05-10T16:01:23Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'that thing again', description:'description of that thing again', forks_count:3, + created_at:'2017-03-14T02:20:29Z', updated_at:'2020-03-01T06:34:36Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'just some more', description:'just some more (link is null)', forks_count:5, + created_at:'2015-10-12T00:14:52Z', updated_at:'2018-10-20T10:31:57Z', + html_url:null}, + {name:'everything', description:'everything (empty link)', forks_count:4, + created_at:'2016-03-30T01:25:17Z', updated_at:'2019-04-30T15:42:34Z', + html_url:' '}, + // {name:'everything else', description:'description of everything else', forks_count:4, + {name:'everything else (missing description and dates)', forks_count:4, + //created_at:'2017-09-23T21:15:20Z', updated_at:'2020-01-11T15:02:51Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + //{name:'another life', description:'description of another life', forks_count:3, + {name:'another life (null description & dates)', description:null, forks_count:3, + //created_at:'2015-07-17T22:41:40Z', updated_at:'2017-05-28T19:04:24Z', + created_at:null, updated_at:'', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'one more please', description:'description of one more please', forks_count:2, + created_at:'2014-02-28T12:54:51Z', updated_at:'2020-02-15T19:51:54Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'Another brand', description:'description of another brand', forks_count:8, + created_at:'2013-06-21T04:36:50Z', updated_at:'2018-12-16T07:11:13Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'useless things', description:'description of useless things', forks_count:6, + created_at:'2011-01-31T09:23:38Z', updated_at:'2017-11-28T10:34:16Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'good to know', description:'description of good to know', forks_count:0, + created_at:'2019-02-23T06:32:43Z', updated_at:'2020-01-05T02:09:21Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'turn around', description:'description of turn around', forks_count:2, + created_at:'2013-11-19T17:34:22Z', updated_at:'2016-07-30T16:48:14Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'turn some more', description:'description of turn some more', forks_count:0, + created_at:'2014-05-09T15:29:00Z', updated_at:'2019-09-04T12:02:45Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:' ', description:'description of (empty name)', forks_count:' ', + created_at:'2015.06.04T17:50:07Z', updated_at:'2020-02-01T01:29:33Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + { description:'description of (missing name)', + created_at:'2015.06.04T17:50:07Z', updated_at:'2020-02-01T01:29:33Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:null, description:'description of (null name)', forks_count:null, + created_at:'2015.06.04T17:50:07Z', updated_at:'2020-02-01T01:29:33Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'abusing power', description:'everything you ever wanted to know but where afraid to ask' + , forks_count:12, + created_at:'2011-11-22T05:05:18Z', updated_at:'2020-03-01T06:20:51Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'what a name', description:'description of what a name', forks_count:6, + created_at:'2017-12-10T08:37:15Z', updated_at:'2017-12-30T17:32:15Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + {name:'what goes there', description:'description of what goes there', forks_count:0, + created_at:'2012-02-14T15:01:08Z', updated_at:'2020-02-25T01:41:41Z', + html_url:'https://github.com/SocialHackersCodeSchool'}, + ]; + const contrib_img_url = [ + 'https://avatars3.githubusercontent.com/u/8708858?v=4', + 'https://avatars3.githubusercontent.com/u/969026?v=4', + 'https://avatars3.githubusercontent.com/u/33282467?v=4', + 'https://avatars0.githubusercontent.com/u/651290?v=4', + 'https://avatars2.githubusercontent.com/u/17527017?v=4', + 'https://avatars0.githubusercontent.com/u/13186712?v=4', + 'https://avatars0.githubusercontent.com/u/15912395?v=4', + 'https://avatars0.githubusercontent.com/u/1047135?v=4', + 'https://avatars3.githubusercontent.com/u/45293?v=4', + 'https://avatars3.githubusercontent.com/u/22626039?v=4', + 'https://avatars3.githubusercontent.com/u/658656?v=4', + 'https://avatars3.githubusercontent.com/u/988347?v=4', + 'https://avatars3.githubusercontent.com/u/33317975?v=4', + 'https://avatars0.githubusercontent.com/u/25272822?v=4', + 'https://avatars0.githubusercontent.com/u/6762913?v=4', + 'https://avatars2.githubusercontent.com/u/33654086?v=4', + 'https://avatars1.githubusercontent.com/u/10981911?v=4', + 'https://avatars0.githubusercontent.com/u/43432?v=4', + 'https://avatars0.githubusercontent.com/u/32513012?v=4', + 'https://avatars2.githubusercontent.com/u/7113309?v=4', + 'https://avatars0.githubusercontent.com/u/2788771?v=4', + ]; + if (produceError) { + delayedCallback(567,errorCallback,'Error: status=707 msg="Example error".'); + } else if (produceEmpty) { + delayedCallback(678,dataCallback,[]); + } else { + let theData=[]; + if (dataURL=='repositories') {theData=clone_JSON_object(repositories)} + else if (dataURL=='contributors') { + const resultLength=getRandomNumberBetween(0,20); + for (let i=0; i<=resultLength; i++) { + const theLink=contrib_img_url.splice(getRandomNumberBetween(0,contrib_img_url.length-1),1); + theData.push({ + html_url : theLink, + avatar_url : theLink, + login : Math.random().toString(36).substring(2), + contributions : getRandomNumberBetween(1,99) + }); + } + }; + delayedCallback(789,dataCallback,theData); + }; + }; + +}; + + +; + diff --git a/Week2/homework/project-hack-your-repo-II/options.png b/Week2/homework/project-hack-your-repo-II/options.png new file mode 100644 index 0000000000000000000000000000000000000000..3703ca053837ee3b3c9c985ae7947b97978579fc GIT binary patch literal 1348 zcmV-K1-tr*P)~3df zQ?k82I75cX?z%<9c$3X$&Y5%1x#!&Too|5uc#%6bGz{Zc0FwK7gE6-4o(0g=)fMjS z?7Zd^@wvGDbY0&I;P+H2^<7Zc(a{kP%9bx* z-d8UGUDux_gsftWeco~jbX|Xo5b~k>c+9e_J*H_^03eY_Bq*hy0N5HZJ5{Y#-?)7F zat;8Z(P&7P*F(S+IpdbjZ0NB*PZj>>$yQKhndV0haD^@T7F`u}?Ip38^rH*@oNF+i5pja$A zo-CP64z;zl9ReWxY_p|O$;jvPPRlr87{;(K?en!-ZOi!h_=RXRs>rfD0^mge-LAd> z;G|_)`%Tj&l7PrCjB{Q(Ip;5>QmGSteSNX^_VynEbTu%W zxq0*E_KO!Unr4**^dv7K?=?NlF6h4z6%Ec zUwh60z%{^1#5rMncFT-(E+T#0jI(s4UBJ8i3Yp7`g3f&K0YzzI`7RnSWHPz8 zt*z~|Kz?6MrBYu8-yIkjcuEk2wT!WYckRn49*;jEisEU%%yFE}nM~&FJ^3 Date: Thu, 26 Mar 2020 22:43:44 +0200 Subject: [PATCH 02/17] Create README.md --- Week2/homework/README.md | 87 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Week2/homework/README.md diff --git a/Week2/homework/README.md b/Week2/homework/README.md new file mode 100644 index 000000000..b6eb7e17c --- /dev/null +++ b/Week2/homework/README.md @@ -0,0 +1,87 @@ + + +About this web page : +==================================== +Extra effort was included to fortify the page from breaking due to bad / unexpected data. + +For this reason extra functionality was included and there exists an option +(actually it is the initial page mode) to run the page in emulation mode, +wherein the data is not requested through an API call, +but is instead supplied by an internal function, +that produces data with diverse errors, emissions and unexpected / invalid values. + +To that end, a special "options" section has been added to the top of the page, +whence from the page behavior can be influenced. + +All the originally-required essential HTML elements are produced through javascript code. +The only additions to the actual html file are those introduced for the new "options" section, +and that only so they can retain their settings between page refreshes. + + +About the "options" section : +==================================== +The upper section, named "options", can be temporary hidden +by clicking the black cog on the upper right corner. +If so, it will stay hidden until revealed by clicking the same icon +(or when you refresh the web page and option #4 is checked) + +It can be kept permanently hidden after page refresh, by un-checking option #4, +in which case it can be toggled visible / hidden by tapping the cog icon. + +By default the options are set to emulate API calls, +and will do so while option #1 named is checked. + +Options #1 , #2 and #3 will influence the next fetch operation. +(Meaning you could mix & match "emulated" and "live" data) +An exception to that is: when the page gets refreshed, there are 2 consecutive fetches, +both of which are subjected to those options. + +Error production (option #2) is done by: +a. in case of emulated data a sample error is thrown +b. in case of real API call, the URL is slightly altered to produce an error response + +Empty datasets are always emulated, regardles of option #1 + +In case when options #3 and #4 are both checked, then option #3 has precedence, +meaning an error result will be produced before an empty dataset. + + +About the "emulated" data : +==================================== +The emulated "repositories" result consists of a special data collection +with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, +test values, missing names, same names with upper/lower case differences, etc... +It is supposed to test all possible problems a page may encounter, +and has to fortify against in order not to break. + +The subsequent "contributors" results are semi-random, meaning that names are completely random +but images and links are real but inserted into random objects, +and also the resulting list length is randomized. + + +About the "live" API data : +==================================== +Some subsequent (contributor list) fetches fail because of bad links. +Located (so far) repos with such are: + english-booster + hyfer-infra +Those 2 hold broken values in their "contributors_url" +Evoking the address on that url, even in the browser, yields an empty page. + +Also the repo "DataStructures" has an empty contrib list result. + + +About the data in general : +==================================== +In case of subsequent fetch errors (those for contributors) I have opted not to display an error +but instead to just log the error and the link, +and then let the page behave as if an empty result was received. + +In order to avoid web traffic, "contributors" fetching is done once for each repo, +and that result is stored and used until page refresh. + +That means that, once a result has been received, +whether it is an actual list, an empty dataset or an error which results in an empty dataset, +that will be the result displayed +each time the user selects that repo from the repo selection element. +. From 98d971d195ee9fef463d7d00914962c9a96a511a Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:44:39 +0200 Subject: [PATCH 03/17] Update README.md --- Week2/homework/README.md | 53 ++++++++++++---------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index b6eb7e17c..5a9d850be 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -4,37 +4,26 @@ About this web page : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. -For this reason extra functionality was included and there exists an option -(actually it is the initial page mode) to run the page in emulation mode, -wherein the data is not requested through an API call, -but is instead supplied by an internal function, -that produces data with diverse errors, emissions and unexpected / invalid values. +For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, emissions and unexpected / invalid values. -To that end, a special "options" section has been added to the top of the page, -whence from the page behavior can be influenced. +To that end, a special "options" section has been added to the top of the page, whence from the page behavior can be influenced. All the originally-required essential HTML elements are produced through javascript code. -The only additions to the actual html file are those introduced for the new "options" section, -and that only so they can retain their settings between page refreshes. +The only additions to the actual html file are those introduced for the new "options" section, and that only so they can retain their settings between page refreshes. About the "options" section : ==================================== -The upper section, named "options", can be temporary hidden -by clicking the black cog on the upper right corner. -If so, it will stay hidden until revealed by clicking the same icon -(or when you refresh the web page and option #4 is checked) +The upper section, named "options", can be temporary hidden by clicking the black cog on the upper right corner. +If so, it will stay hidden until revealed by clicking the same icon (or when you refresh the web page and option #4 is checked) -It can be kept permanently hidden after page refresh, by un-checking option #4, -in which case it can be toggled visible / hidden by tapping the cog icon. +It can be kept permanently hidden after page refresh, by un-checking option #4, in which case it can be toggled visible / hidden by tapping the cog icon. -By default the options are set to emulate API calls, -and will do so while option #1 named is checked. +By default the options are set to emulate API calls, and will do so while option #1 named is checked. Options #1 , #2 and #3 will influence the next fetch operation. (Meaning you could mix & match "emulated" and "live" data) -An exception to that is: when the page gets refreshed, there are 2 consecutive fetches, -both of which are subjected to those options. +An exception to that is: when the page gets refreshed, there are 2 consecutive fetches, both of which are subjected to those options. Error production (option #2) is done by: a. in case of emulated data a sample error is thrown @@ -42,21 +31,15 @@ b. in case of real API call, the URL is slightly altered to produce an error res Empty datasets are always emulated, regardles of option #1 -In case when options #3 and #4 are both checked, then option #3 has precedence, -meaning an error result will be produced before an empty dataset. +In case when options #3 and #4 are both checked, then option #3 has precedence, meaning an error result will be produced before an empty dataset. About the "emulated" data : ==================================== -The emulated "repositories" result consists of a special data collection -with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, -test values, missing names, same names with upper/lower case differences, etc... -It is supposed to test all possible problems a page may encounter, -and has to fortify against in order not to break. +The emulated "repositories" result consists of a special data collection with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, test values, missing names, same names with upper/lower case differences, etc... +It is supposed to test all possible problems a page may encounter, and has to fortify against in order not to break. -The subsequent "contributors" results are semi-random, meaning that names are completely random -but images and links are real but inserted into random objects, -and also the resulting list length is randomized. +The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real but inserted into random objects, and also the resulting list length is randomized. About the "live" API data : @@ -73,15 +56,9 @@ Also the repo "DataStructures" has an empty contrib list result. About the data in general : ==================================== -In case of subsequent fetch errors (those for contributors) I have opted not to display an error -but instead to just log the error and the link, -and then let the page behave as if an empty result was received. +In case of subsequent fetch errors (those for contributors) I have opted not to display an error but instead to just log the error and the link, and then let the page behave as if an empty result was received. -In order to avoid web traffic, "contributors" fetching is done once for each repo, -and that result is stored and used until page refresh. +In order to avoid web traffic, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. -That means that, once a result has been received, -whether it is an actual list, an empty dataset or an error which results in an empty dataset, -that will be the result displayed -each time the user selects that repo from the repo selection element. +That means that, once a result has been received, whether it is an actual list, an empty dataset or an error which results in an empty dataset, that will be the result displayed each time the user selects that repo from the repo selection element. . From 405958bbc8a083932338f63cc95aeff2e65e1d09 Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:45:19 +0200 Subject: [PATCH 04/17] Update README.md --- Week2/homework/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 5a9d850be..7976aa2de 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -1,6 +1,6 @@ -About this web page : +About this Project (web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. From c96e44a1766b7ed7e8c4e3a66e8f43241d5830ac Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:55:10 +0200 Subject: [PATCH 05/17] Update README.md --- Week2/homework/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 7976aa2de..457137ec1 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -4,7 +4,7 @@ About this Project (web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. -For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, emissions and unexpected / invalid values. +For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent and unexpected or invalid values. To that end, a special "options" section has been added to the top of the page, whence from the page behavior can be influenced. @@ -38,6 +38,8 @@ About the "emulated" data : ==================================== The emulated "repositories" result consists of a special data collection with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, test values, missing names, same names with upper/lower case differences, etc... It is supposed to test all possible problems a page may encounter, and has to fortify against in order not to break. +. + The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real but inserted into random objects, and also the resulting list length is randomized. From 3d5fe932e77dad3ee16bdae74cbc4e80a8ef9b5b Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:55:41 +0200 Subject: [PATCH 06/17] Update README.md --- Week2/homework/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 457137ec1..fed7506aa 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -63,4 +63,3 @@ In case of subsequent fetch errors (those for contributors) I have opted not to In order to avoid web traffic, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. That means that, once a result has been received, whether it is an actual list, an empty dataset or an error which results in an empty dataset, that will be the result displayed each time the user selects that repo from the repo selection element. -. From f1ede7df893ce6089ac4acda8679e99fc8a4d59e Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 22:56:45 +0200 Subject: [PATCH 07/17] Update README.md --- Week2/homework/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index fed7506aa..12f9c5448 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -4,7 +4,7 @@ About this Project (web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. -For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent and unexpected or invalid values. +For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent, unexpected or invalid values. To that end, a special "options" section has been added to the top of the page, whence from the page behavior can be influenced. From 6aff0bb8148be74e3d2d16375649f2bc353f235f Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:13:39 +0200 Subject: [PATCH 08/17] Update README.md --- Week2/homework/README.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 12f9c5448..4d98f7dee 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -4,7 +4,7 @@ About this Project (web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. -For this reason extra functionality was included and there exists an option (actually it is the initial page mode) to run the page in emulation mode, wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent, unexpected or invalid values. +For this reason extra functionality was included and there exists an option to run the page in data emulation mode (which actually is the initial page mode), wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent, unexpected or invalid values. To that end, a special "options" section has been added to the top of the page, whence from the page behavior can be influenced. @@ -14,22 +14,21 @@ The only additions to the actual html file are those introduced for the new "opt About the "options" section : ==================================== -The upper section, named "options", can be temporary hidden by clicking the black cog on the upper right corner. -If so, it will stay hidden until revealed by clicking the same icon (or when you refresh the web page and option #4 is checked) +The "options" section can be toggled to visible / hidden by tapping the cog icon on the upper right corner. +If hidden, it will stay so until revealed by taping the same icon (or when you refresh the web page and option #4 is checked) +It can be kept permanently hidden after page refresh, by un-checking option #4. -It can be kept permanently hidden after page refresh, by un-checking option #4, in which case it can be toggled visible / hidden by tapping the cog icon. +By default the options are set to emulate API calls, and will do so while option #1 is checked. -By default the options are set to emulate API calls, and will do so while option #1 named is checked. - -Options #1 , #2 and #3 will influence the next fetch operation. -(Meaning you could mix & match "emulated" and "live" data) -An exception to that is: when the page gets refreshed, there are 2 consecutive fetches, both of which are subjected to those options. +Options #1 , #2 and #3 will influence the next fetch operation +(meaning you could mix & match "emulated" and "live" data) +except when the page gets refreshed, where there are 2 consecutive fetches, both of which are subjected to the specified options. Error production (option #2) is done by: -a. in case of emulated data a sample error is thrown -b. in case of real API call, the URL is slightly altered to produce an error response + a. in case of emulated data a sample error is thrown + b. in case of real API call, the URL is slightly altered to produce an error response -Empty datasets are always emulated, regardles of option #1 +Empty datasets (option #3) are always emulated, regardles of option #1 In case when options #3 and #4 are both checked, then option #3 has precedence, meaning an error result will be produced before an empty dataset. @@ -38,16 +37,14 @@ About the "emulated" data : ==================================== The emulated "repositories" result consists of a special data collection with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, test values, missing names, same names with upper/lower case differences, etc... It is supposed to test all possible problems a page may encounter, and has to fortify against in order not to break. -. - -The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real but inserted into random objects, and also the resulting list length is randomized. +The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real, tho inserted into random objects, and also the resulting contributor list length is randomized. About the "live" API data : ==================================== Some subsequent (contributor list) fetches fail because of bad links. -Located (so far) repos with such are: +Located repos with links that fail are: english-booster hyfer-infra Those 2 hold broken values in their "contributors_url" @@ -58,8 +55,8 @@ Also the repo "DataStructures" has an empty contrib list result. About the data in general : ==================================== -In case of subsequent fetch errors (those for contributors) I have opted not to display an error but instead to just log the error and the link, and then let the page behave as if an empty result was received. +In case of subsequent fetch errors (those for contributors) I have opted not to display an error but instead to just log the error and the link in the console, and then let the page behave as if an empty result was received. -In order to avoid web traffic, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. +In order to avoid web traffic, and possible github request refusal due to frequency, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. That means that, once a result has been received, whether it is an actual list, an empty dataset or an error which results in an empty dataset, that will be the result displayed each time the user selects that repo from the repo selection element. From 2a884c75ed1324e40f8fd41f7e07c9ee421cbfc4 Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:14:41 +0200 Subject: [PATCH 09/17] Update README.md --- Week2/homework/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 4d98f7dee..3f9d15312 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -1,6 +1,6 @@ -About this Project (web page) : +About the Project (the web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. From 03519107db2298bd56bb0c5b7585f7f23ddb2ff0 Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:17:52 +0200 Subject: [PATCH 10/17] Update README.md --- Week2/homework/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 3f9d15312..24953f1eb 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -25,8 +25,8 @@ Options #1 , #2 and #3 will influence the next fetch operation except when the page gets refreshed, where there are 2 consecutive fetches, both of which are subjected to the specified options. Error production (option #2) is done by: - a. in case of emulated data a sample error is thrown - b. in case of real API call, the URL is slightly altered to produce an error response +1. in case of emulated data a sample error is thrown +and 2. in case of real API call, the URL is slightly altered to produce an error response Empty datasets (option #3) are always emulated, regardles of option #1 @@ -45,8 +45,9 @@ About the "live" API data : ==================================== Some subsequent (contributor list) fetches fail because of bad links. Located repos with links that fail are: - english-booster - hyfer-infra +1. english-booster +and 2. hyfer-infra + Those 2 hold broken values in their "contributors_url" Evoking the address on that url, even in the browser, yields an empty page. From 4927ad632a24d4f9f3a574cb1b36182576cf14b3 Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:19:04 +0200 Subject: [PATCH 11/17] Update README.md --- Week2/homework/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 24953f1eb..f342e5d36 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -26,7 +26,7 @@ except when the page gets refreshed, where there are 2 consecutive fetches, both Error production (option #2) is done by: 1. in case of emulated data a sample error is thrown -and 2. in case of real API call, the URL is slightly altered to produce an error response +2. in case of real API call, the URL is slightly altered to produce an error response Empty datasets (option #3) are always emulated, regardles of option #1 @@ -46,7 +46,7 @@ About the "live" API data : Some subsequent (contributor list) fetches fail because of bad links. Located repos with links that fail are: 1. english-booster -and 2. hyfer-infra +2. hyfer-infra Those 2 hold broken values in their "contributors_url" Evoking the address on that url, even in the browser, yields an empty page. From b3c609031a8dee858151cac6f2b83f894d35fd2b Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:20:32 +0200 Subject: [PATCH 12/17] Update README.md --- Week2/homework/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index f342e5d36..2740bd1f4 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -28,6 +28,7 @@ Error production (option #2) is done by: 1. in case of emulated data a sample error is thrown 2. in case of real API call, the URL is slightly altered to produce an error response + Empty datasets (option #3) are always emulated, regardles of option #1 In case when options #3 and #4 are both checked, then option #3 has precedence, meaning an error result will be produced before an empty dataset. @@ -36,6 +37,7 @@ In case when options #3 and #4 are both checked, then option #3 has precedence, About the "emulated" data : ==================================== The emulated "repositories" result consists of a special data collection with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, test values, missing names, same names with upper/lower case differences, etc... + It is supposed to test all possible problems a page may encounter, and has to fortify against in order not to break. The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real, tho inserted into random objects, and also the resulting contributor list length is randomized. From 5f0fa534c8447164f85ce0c85b8a12ce660053fa Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:23:04 +0200 Subject: [PATCH 13/17] Update README.md --- Week2/homework/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 2740bd1f4..366ad24d2 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -38,7 +38,7 @@ About the "emulated" data : ==================================== The emulated "repositories" result consists of a special data collection with a multitude of nonexistent, erroneous, null, undefined, empty or missing values, test values, missing names, same names with upper/lower case differences, etc... -It is supposed to test all possible problems a page may encounter, and has to fortify against in order not to break. +It is supposed to represent possible data problems a page may encounter, and has to fortify against in order to work correctly. The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real, tho inserted into random objects, and also the resulting contributor list length is randomized. From c5b4f238fc889ee3eb810c3eb37a6ede5c6fe11a Mon Sep 17 00:00:00 2001 From: student0b4dc0d3 <57763845+student0b4dc0d3@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:34:24 +0200 Subject: [PATCH 14/17] Update README.md --- Week2/homework/README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 366ad24d2..6d6782826 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -4,25 +4,30 @@ About the Project (the web page) : ==================================== Extra effort was included to fortify the page from breaking due to bad / unexpected data. -For this reason extra functionality was included and there exists an option to run the page in data emulation mode (which actually is the initial page mode), wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent, unexpected or invalid values. +For this reason extra functionality was included and there exists an option to run the page in data emulation mode +(which actually is the initial page mode), +wherein the data is not requested through an API call, but is instead supplied by an internal function, that produces data with diverse errors, nonexistent, unexpected or invalid values. To that end, a special "options" section has been added to the top of the page, whence from the page behavior can be influenced. All the originally-required essential HTML elements are produced through javascript code. + The only additions to the actual html file are those introduced for the new "options" section, and that only so they can retain their settings between page refreshes. About the "options" section : ==================================== The "options" section can be toggled to visible / hidden by tapping the cog icon on the upper right corner. -If hidden, it will stay so until revealed by taping the same icon (or when you refresh the web page and option #4 is checked) + +If hidden, it will stay so until revealed by taping the same icon (or when you refresh the web page and option #4 is checked). + It can be kept permanently hidden after page refresh, by un-checking option #4. By default the options are set to emulate API calls, and will do so while option #1 is checked. -Options #1 , #2 and #3 will influence the next fetch operation -(meaning you could mix & match "emulated" and "live" data) -except when the page gets refreshed, where there are 2 consecutive fetches, both of which are subjected to the specified options. +Options #1 , #2 and #3 will influence the next fetch operation. +(meaning you could mix & match "emulated" and "live" data). +An Exception is when the page gets refreshed, where there are 2 consecutive fetches, both of which are subjected to the specified options. Error production (option #2) is done by: 1. in case of emulated data a sample error is thrown @@ -40,7 +45,7 @@ The emulated "repositories" result consists of a special data collection with a It is supposed to represent possible data problems a page may encounter, and has to fortify against in order to work correctly. -The subsequent "contributors" results are semi-random, meaning that names are completely random but images and links are real, tho inserted into random objects, and also the resulting contributor list length is randomized. +The subsequent "contributors" results are semi-random, meaning that names are completely random, but images and links are real, tho inserted into random objects, and also the resulting contributor list length is randomized. About the "live" API data : @@ -50,8 +55,9 @@ Located repos with links that fail are: 1. english-booster 2. hyfer-infra -Those 2 hold broken values in their "contributors_url" -Evoking the address on that url, even in the browser, yields an empty page. +Those 2 hold broken values in their "contributors_url". + +Evoking the addresses of those urls in the browser yields empty pages. Also the repo "DataStructures" has an empty contrib list result. @@ -60,6 +66,6 @@ About the data in general : ==================================== In case of subsequent fetch errors (those for contributors) I have opted not to display an error but instead to just log the error and the link in the console, and then let the page behave as if an empty result was received. -In order to avoid web traffic, and possible github request refusal due to frequency, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. +In order to avoid web traffic, and possible API request refusal due to frequency, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. That means that, once a result has been received, whether it is an actual list, an empty dataset or an error which results in an empty dataset, that will be the result displayed each time the user selects that repo from the repo selection element. From 0dc16bd73518a958ffd4f883423922080d16976d Mon Sep 17 00:00:00 2001 From: "dot.not" Date: Tue, 31 Mar 2020 17:43:19 +0300 Subject: [PATCH 15/17] Commiting JS-3 Homework for week 3 --- Week2/homework/README.md | 6 + Week3/homework/README.md | 5 + .../project-hack-your-repo-III/App.js | 56 +++++++++ .../ContributorsView.js | 48 ++++++++ .../project-hack-your-repo-III/ErrorView.js | 31 +++++ .../project-hack-your-repo-III/HeaderView.js | 46 +++++++ .../project-hack-your-repo-III/Model.js | 68 +++++++++++ .../project-hack-your-repo-III/Observable.js | 20 +++ .../project-hack-your-repo-III/README.md | 46 +++++++ .../project-hack-your-repo-III/RepoView.js | 48 ++++++++ .../project-hack-your-repo-III/Util.js | 81 +++++++++++++ .../project-hack-your-repo-III/hyf.png | Bin 0 -> 9116 bytes .../project-hack-your-repo-III/index.html | 37 ++++++ .../project-hack-your-repo-III/style.css | 114 ++++++++++++++++++ 14 files changed, 606 insertions(+) create mode 100644 Week3/homework/README.md create mode 100644 Week3/homework/project-hack-your-repo-III/App.js create mode 100644 Week3/homework/project-hack-your-repo-III/ContributorsView.js create mode 100644 Week3/homework/project-hack-your-repo-III/ErrorView.js create mode 100644 Week3/homework/project-hack-your-repo-III/HeaderView.js create mode 100644 Week3/homework/project-hack-your-repo-III/Model.js create mode 100644 Week3/homework/project-hack-your-repo-III/Observable.js create mode 100644 Week3/homework/project-hack-your-repo-III/README.md create mode 100644 Week3/homework/project-hack-your-repo-III/RepoView.js create mode 100644 Week3/homework/project-hack-your-repo-III/Util.js create mode 100644 Week3/homework/project-hack-your-repo-III/hyf.png create mode 100644 Week3/homework/project-hack-your-repo-III/index.html create mode 100644 Week3/homework/project-hack-your-repo-III/style.css diff --git a/Week2/homework/README.md b/Week2/homework/README.md index 6d6782826..7aadbe9c2 100644 --- a/Week2/homework/README.md +++ b/Week2/homework/README.md @@ -69,3 +69,9 @@ In case of subsequent fetch errors (those for contributors) I have opted not to In order to avoid web traffic, and possible API request refusal due to frequency, "contributors" fetching is done once for each repo, and that result is stored and used until page refresh. That means that, once a result has been received, whether it is an actual list, an empty dataset or an error which results in an empty dataset, that will be the result displayed each time the user selects that repo from the repo selection element. + + +Bunus objective: undesired API request prevention +==================================== +Additional effort was put into the prevention of consecutive API requests when the contents of the repo SELECT item are scrolled rapidly through by the user. To that end, once a repo-change has initiated an API request, all subsequent repo-change-handling is halted until that API request has concluded. + diff --git a/Week3/homework/README.md b/Week3/homework/README.md new file mode 100644 index 000000000..7fe0d07aa --- /dev/null +++ b/Week3/homework/README.md @@ -0,0 +1,5 @@ + +Homework folder for JS-3 - week 3 + +===================== + diff --git a/Week3/homework/project-hack-your-repo-III/App.js b/Week3/homework/project-hack-your-repo-III/App.js new file mode 100644 index 000000000..8788f8b85 --- /dev/null +++ b/Week3/homework/project-hack-your-repo-III/App.js @@ -0,0 +1,56 @@ +'use strict'; + +{ + const accounts = { + hyf: { + name: 'HackYourFuture', + type: 'org', + }, + microsoft: { + name: 'Microsoft', + type: 'org', + }, + jim: { + name: 'remarcmij', + type: 'user', + }, + }; + + const { Model, HeaderView, RepoView, ContributorsView, ErrorView } = window; + const { createAndAppend } = window.Util; + + class App { + constructor(account) { + const containers = App.renderContainers(); + + const model = new Model(account); + const fetchData = model.fetchData.bind(model); + + model.subscribe(new HeaderView(account, containers.header, fetchData)); + model.subscribe(new RepoView(containers.repo)); + model.subscribe(new ContributorsView(containers.contributors)); + model.subscribe(new ErrorView(containers.error)); + + fetchData(); + } + + static renderContainers() { + const root = document.getElementById('root'); + const header = createAndAppend('header', root, { class: 'header' }); + const error = createAndAppend('div', root); + const main = createAndAppend('main', root, { + class: 'main-container', + }); + const repo = createAndAppend('section', main, { + class: 'repo-container whiteframe', + }); + const contributors = createAndAppend('section', main, { + class: 'contributors-container whiteframe', + }); + return { header, error, main, repo, contributors }; + } + } + + const ACCOUNT_KEY = 'hyf'; + window.onload = () => new App(accounts[ACCOUNT_KEY]); +} diff --git a/Week3/homework/project-hack-your-repo-III/ContributorsView.js b/Week3/homework/project-hack-your-repo-III/ContributorsView.js new file mode 100644 index 000000000..86a7f6f41 --- /dev/null +++ b/Week3/homework/project-hack-your-repo-III/ContributorsView.js @@ -0,0 +1,48 @@ +'use strict'; + +{ + // DOT.NOT:JS-3:w-3:project: include additional utility functions + const { createAndAppend , createTableRowHTML , + getValidValue , createTableCellObject } = window.Util; + + class ContributorsView { + constructor(container) { + this.container = container; + // DOT.NOT:JS-3:w-3:project: additional rendering / styling elements + const wrapper=createAndAppend('DIV',this.container + ,{id:'id_wrap_contributors'}); + this.titleRef=createAndAppend('P',wrapper,{id:'id_title_contributors'}); + this.dataList=createAndAppend('TABLE',wrapper + ,{id:'id_table_contributors'}); + } + + update(state) { + if (!state.error) { + this.render(state.contributors); + } + } + + /** + * Renders the list of contributors + * @param {Object[]} contributors An array of contributor objects + */ + render(contributors) { + // DOT.NOT:JS-3:w-3:project: implement contributors rendering + const cntrbTitle=(cnt)=>`${cnt<1?'No':cnt} Contributor${cnt===1?'':'s'}`; + this.titleRef.innerHTML=cntrbTitle((contributors.length||0)); + let theHTML=''; + if ((contributors) && (contributors.length>0)) { + theHTML=contributors.reduce((tot,cur)=>tot+createTableRowHTML([ + createTableCellObject(``), + createTableCellObject(getValidValue(cur.login), + getValidValue(cur.html_url),true), + createTableCellObject(getValidValue(cur.contributions,0)),]),''); + }; + this.dataList.innerHTML=theHTML; + }; + + } + + window.ContributorsView = ContributorsView; +} diff --git a/Week3/homework/project-hack-your-repo-III/ErrorView.js b/Week3/homework/project-hack-your-repo-III/ErrorView.js new file mode 100644 index 000000000..67ad53087 --- /dev/null +++ b/Week3/homework/project-hack-your-repo-III/ErrorView.js @@ -0,0 +1,31 @@ +'use strict'; + +{ + const { createAndAppend } = window.Util; + + class ErrorView { + constructor(container) { + this.container = container; + } + + update(state) { + this.render(state.error); + } + + /** + * Renders an error for the 'error' message type. + * @param {Error} error An Error object + */ + render(error) { + this.container.innerHTML = ''; + if (error) { + createAndAppend('div', this.container, { + text: error.message, + class: 'alert alert-error', + }); + } + } + } + + window.ErrorView = ErrorView; +} diff --git a/Week3/homework/project-hack-your-repo-III/HeaderView.js b/Week3/homework/project-hack-your-repo-III/HeaderView.js new file mode 100644 index 000000000..11f9c8971 --- /dev/null +++ b/Week3/homework/project-hack-your-repo-III/HeaderView.js @@ -0,0 +1,46 @@ +'use strict'; + +{ + const { createAndAppend } = window.Util; + + class HeaderView { + constructor(account, header, fetchData) { + this.account = account; + this.header = header; + this.fetchData = fetchData; + this.select = null; + } + + update(state) { + if (!this.select && !state.error) { + this.render(state.repos); + } + } + + /** + * Renders the data for the 'select' message type. Create a