diff --git a/Week1/homework/js-exercises/ex01-book-list/index.html b/Week1/homework/js-exercises/ex01-book-list/index.html
new file mode 100644
index 000000000..f7f8023a7
--- /dev/null
+++ b/Week1/homework/js-exercises/ex01-book-list/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Week1/homework/js-exercises/ex01-book-list/main.css b/Week1/homework/js-exercises/ex01-book-list/main.css
new file mode 100644
index 000000000..ed79574a0
--- /dev/null
+++ b/Week1/homework/js-exercises/ex01-book-list/main.css
@@ -0,0 +1,44 @@
+
+body {
+ margin: 0px;
+ padding: 0px;
+ font-size: 150%;
+ font-family: sans-serif;
+ }
+
+.cls_text_align_left {
+ text-align: left;
+ }
+
+.cls_text_align_right {
+ text-align: right;
+ }
+
+.cls_text_align_center {
+ text-align: center;
+ }
+
+.cls_background_color_gold {
+ background-color: gold;
+ }
+
+div {
+ padding:12px 16px;
+ margin: 20px 20px;
+ }
+
+th, td {
+ padding: 7px 10px 0px 9px;
+ border-radius: 4px;
+ }
+
+table tr:nth-child(odd) td {
+ background-color: gold;
+ }
+
+table tr:nth-child(even) td {
+ background-color: silver;
+ }
+
+;
+
diff --git a/Week1/homework/js-exercises/ex01-book-list/main.js b/Week1/homework/js-exercises/ex01-book-list/main.js
new file mode 100644
index 000000000..5ab73c01c
--- /dev/null
+++ b/Week1/homework/js-exercises/ex01-book-list/main.js
@@ -0,0 +1,84 @@
+
+{
+ 'use strict';
+
+ document.getElementById("id_page_title").innerHTML=
+ document.getElementById("id_page_header").innerHTML=
+ '(Homework: Javascript 2 - week 1) - (Exercise 01: The book list)';
+ document.body.style.backgroundColor='#25003e';
+
+ myBookList=[
+ { book_title : 'Nineteen Eighty-Four',
+ book_link : 'http://en.wikipedia.org/wiki/Nineteen_Eighty-Four',
+ book_author : 'George Orwell',
+ author_link : 'http://en.wikipedia.org/wiki/George_Orwell',
+ cover_image : 'http://upload.wikimedia.org/wikipedia/en/c/c3/1984first.jpg',
+ read_pending: false
+ },
+ { book_title : 'Das Parfum',
+ book_link : 'http://en.wikipedia.org/wiki/Perfume_(novel)',
+ book_author : 'Patrick Süskind',
+ author_link : 'http://en.wikipedia.org/wiki/Patrick_Süskind',
+ cover_image : 'http://upload.wikimedia.org/wikipedia/en/f/f5/PerfumeSuskind.jpg',
+ read_pending: true
+ },
+ { book_title : 'The Name of the Rose',
+ book_link : 'http://en.wikipedia.org/wiki/The_Name_of_the_Rose',
+ book_author : 'Umberto Eco',
+ author_link : 'http://en.wikipedia.org/wiki/Umberto_Eco',
+ cover_image : 'http://upload.wikimedia.org/wikipedia/en/e/eb/The_Name_of_the_Rose.jpg',
+ read_pending: false
+ }
+ ];
+
+ function addChild(prntRef,chldTag,chldClss,chldText){
+ let newLMNT=document.createElement(chldTag);
+ if (chldClss) {newLMNT.className=chldClss}
+ if (chldText) {newLMNT.innerHTML=chldText}
+ prntRef.appendChild(newLMNT);
+ return newLMNT
+ };
+
+ let divRef=addChild(document.body,'DIV','','');
+ divRef.style.backgroundColor='orange';
+ let tableRef=addChild(divRef,'TABLE','','');
+ tableRef.width='100%';
+ let rowRef=addChild(tableRef,'TR','','');
+ addChild(rowRef,'TH','cls_text_align_left','Book Title');
+ addChild(rowRef,'TH','cls_text_align_center','Author');
+ addChild(rowRef,'TH','cls_text_align_center','Book Cover');
+ addChild(rowRef,'TH','cls_text_align_center','Read Pending?');
+
+ let lmntRef;
+ myBookList.forEach((bookRef)=>{
+ rowRef=addChild(tableRef,'TR','','');
+ lmntRef=addChild(rowRef,'TD','',);
+ lmntRef=addChild(lmntRef,'A','',bookRef.book_title);
+ lmntRef.title='Click for transition to related wiki page.';
+ lmntRef.target='_blank';
+ lmntRef.href=bookRef.book_link;
+ lmntRef=addChild(rowRef,'TD','cls_text_align_center','');
+ lmntRef=addChild(lmntRef,'A','',bookRef.book_author);
+ lmntRef.title='Click for transition to related wiki page.';
+ lmntRef.target='_blank';
+ lmntRef.href=bookRef.author_link;
+ lmntRef=addChild(rowRef,'TD','cls_text_align_center','');
+ lmntRef=addChild(lmntRef,'IMG','','');
+ lmntRef.setAttribute('alt','Book cover: '+bookRef.book_title);
+ lmntRef.setAttribute('title','Book cover: '+bookRef.book_title);
+ lmntRef.setAttribute('width','128');
+ lmntRef.setAttribute('src',bookRef.cover_image);
+ lmntRef=addChild(rowRef,'TD','cls_text_align_center','');
+ lmntRef.style.padding='1em';
+ lmntRef=addChild(lmntRef,'SPAN',''
+ ,`I have ${bookRef.read_pending?"not":"already"
+ } read this book${bookRef.read_pending?" yet.":"."}`);
+ lmntRef.style.backgroundColor=(bookRef.read_pending?'pink':'lime');
+ lmntRef.style.padding='1em';
+ lmntRef.style.borderRadius='45%';
+ });
+
+};
+
+;
+
diff --git a/Week1/homework/js-exercises/ex02-about-me/about_me.html b/Week1/homework/js-exercises/ex02-about-me/about_me.html
new file mode 100644
index 000000000..afe0baa27
--- /dev/null
+++ b/Week1/homework/js-exercises/ex02-about-me/about_me.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
About Me
+
+ - Nickname:
+ - Favorite food:
+ - Hometown:
+
+
+
+
+
+
+
diff --git a/Week1/homework/js-exercises/ex02-about-me/main.css b/Week1/homework/js-exercises/ex02-about-me/main.css
new file mode 100644
index 000000000..cf05d2308
--- /dev/null
+++ b/Week1/homework/js-exercises/ex02-about-me/main.css
@@ -0,0 +1,31 @@
+
+body {
+ margin: 0px;
+ padding: 0px;
+ font-size: 150%;
+ font-family: sans-serif;
+ }
+
+.cls_text_align_left {
+ text-align: left;
+ }
+
+.cls_text_align_right {
+ text-align: right;
+ }
+
+.cls_text_align_center {
+ text-align: center;
+ }
+
+div {
+ padding: 12px 16px 8px 16px;
+ margin: 20px 18px;
+ }
+
+.cls_list_item {
+ color: maroon;
+ }
+
+;
+
diff --git a/Week1/homework/js-exercises/ex02-about-me/main.js b/Week1/homework/js-exercises/ex02-about-me/main.js
new file mode 100644
index 000000000..cb7e1527e
--- /dev/null
+++ b/Week1/homework/js-exercises/ex02-about-me/main.js
@@ -0,0 +1,83 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=
+ lmntRef.innerHTML='(Homework: Javascript 2 - week 1) - (Exercise 02: About me)';
+ document.body.style.backgroundColor='#25003e';
+ const imgTagUniqueID='apicture';
+ let lastRandomIndex=-1;
+
+ function randomData(){
+ const funnyData=[
+ { nickname : 'Professional Sleeper Pilot',
+ fav_food : 'Potato Flambe',
+ hometown : 'Cockaigne',
+ apicture : 'http://2.bp.blogspot.com/_A3GOyr0yK3Y/TNBaWhox5CI/AAAAAAAA71w/uFDigoTW004/s1600/earsbig.jpg',
+ },
+ { nickname : 'Shadow Accounting Dancer',
+ fav_food : 'Fish ratatouille',
+ hometown : 'Shangri-La',
+ apicture : 'http://3.bp.blogspot.com/-NJEdS0XD93o/TV6BdBhquJI/AAAAAAAAfFw/il2wlrrd-vY/s400/Weird_Faces_A_Guy_Can_Make_12.jpg',
+ },
+ { nickname : 'Electrician-Gynecologist',
+ fav_food : 'Green fried tomatoes',
+ hometown : 'El Dorado',
+ apicture : 'https://i.ytimg.com/vi/2FgJOB0DGg4/hqdefault.jpg',
+ },
+ { nickname : 'Occupational Hazard Engineer',
+ fav_food : 'Leftover morning pizza',
+ hometown : 'Atlantis',
+ apicture : 'https://cdn.quotesgram.com/img/61/15/1620699906-a_aaa-funny-face-.jpg',
+ }
+ ];
+ let rngIdx=-1;
+ do {rngIdx=Math.floor(Math.random()*funnyData.length)} while (rngIdx==lastRandomIndex);
+ lastRandomIndex=rngIdx;
+ const valueList=Object.values(funnyData[rngIdx]);
+ const keyList=Object.keys(funnyData[0]);
+ for (let i=0; i
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Week1/homework/js-exercises/ex05-cat-walk/index.html b/Week1/homework/js-exercises/ex05-cat-walk/index.html
new file mode 100644
index 000000000..bcab2dd60
--- /dev/null
+++ b/Week1/homework/js-exercises/ex05-cat-walk/index.html
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Week1/homework/js-exercises/ex05-cat-walk/main.css b/Week1/homework/js-exercises/ex05-cat-walk/main.css
new file mode 100644
index 000000000..ebf08d991
--- /dev/null
+++ b/Week1/homework/js-exercises/ex05-cat-walk/main.css
@@ -0,0 +1,34 @@
+
+body {
+ margin: 0px 18px;
+ padding: 0px;
+ font-size: 150%;
+ font-family: sans-serif;
+ }
+
+.cls_text_align_left {
+ text-align: left;
+ }
+
+.cls_text_align_right {
+ text-align: right;
+ }
+
+.cls_text_align_center {
+ text-align: center;
+ }
+
+div {
+ padding: 12px 16px 8px 16px;
+ margin: 20px 0px;
+ }
+
+/* for visual validation:
+ enable following style (by deleting the dot) to see the image with a border */
+.img {
+ border-style: solid;
+ border-color: gold;
+ }
+
+;
+
diff --git a/Week1/homework/js-exercises/ex05-cat-walk/main.js b/Week1/homework/js-exercises/ex05-cat-walk/main.js
new file mode 100644
index 000000000..6e67dc5f9
--- /dev/null
+++ b/Week1/homework/js-exercises/ex05-cat-walk/main.js
@@ -0,0 +1,14 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=
+ lmntRef.innerHTML=`(Homework: Javascript 2 - week 1) - (Exercise 05: The cat walk)`;
+ lmntRef.style.borderRadius='12px';
+ document.body.style.backgroundColor='#25003e';
+};
+
+;
+
diff --git a/Week1/homework/js-exercises/project-random-quotes/index.html b/Week1/homework/js-exercises/project-random-quotes/index.html
new file mode 100644
index 000000000..de955a63e
--- /dev/null
+++ b/Week1/homework/js-exercises/project-random-quotes/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Week1/homework/js-exercises/project-random-quotes/main.css b/Week1/homework/js-exercises/project-random-quotes/main.css
new file mode 100644
index 000000000..6732c9b5d
--- /dev/null
+++ b/Week1/homework/js-exercises/project-random-quotes/main.css
@@ -0,0 +1,27 @@
+
+body {
+ margin: 0px 18px;
+ padding: 0px;
+ font-size: 150%;
+ font-family: sans-serif;
+ }
+
+.cls_text_align_left {
+ text-align: left;
+ }
+
+.cls_text_align_right {
+ text-align: right;
+ }
+
+.cls_text_align_center {
+ text-align: center;
+ }
+
+div {
+ padding: 12px 16px 8px 16px;
+ margin: 20px 0px;
+ }
+
+;
+
diff --git a/Week1/homework/js-exercises/project-random-quotes/main.js b/Week1/homework/js-exercises/project-random-quotes/main.js
new file mode 100644
index 000000000..56db5b9c7
--- /dev/null
+++ b/Week1/homework/js-exercises/project-random-quotes/main.js
@@ -0,0 +1,105 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=
+ lmntRef.innerHTML=`(Homework: Javascript 2 - week 1) - (PROJECT: Random Quote Generator)`;
+ lmntRef.style.borderRadius='12px';
+ document.body.style.backgroundColor='#25003e';
+
+ lmntRef=document.createElement('DIV');
+ lmntRef.style.backgroundColor='orange';
+ lmntRef.style.position='absolute';
+ lmntRef.style.top='6em';
+ lmntRef.style.right='.8em';
+ lmntRef.className='cls_text_align_left';
+ lmntRef.style.borderRadius='40px 24px 50px 4px';
+ lmntRef.style.maxWidth='65%';
+ document.body.appendChild(lmntRef);
+ let qTextRef=document.createElement('H2');
+ qTextRef.innerHTML='Some Funny or Witty Quote';
+ qTextRef.style.textAlign='center';
+ lmntRef.appendChild(qTextRef);
+ let qPersonRef=document.createElement('P');
+ qPersonRef.innerHTML='by a Weird Person';
+ qPersonRef.style.textAlign='right';
+ lmntRef.appendChild(qPersonRef);
+ let btnRef=document.createElement('DIV');
+ btnRef.style.backgroundColor='gold';
+ btnRef.style.margin='0px 20px 8px 0px';
+ btnRef.style.padding='0.5em .8em';
+ btnRef.style.fontSize='.9em';
+ btnRef.style.display='inline-block';
+ btnRef.style.borderRadius='1.2em';
+ btnRef.innerHTML='Next Random Quote';
+ btnRef.addEventListener("click",randomQuote);
+ lmntRef.appendChild(btnRef);
+ let qRefreshRef=document.createElement('SPAN');
+ qRefreshRef.style.backgroundColor='gold';
+ qRefreshRef.style.margin='0px 0px 8px 20px';
+ qRefreshRef.style.padding='0.3em .5em';
+ qRefreshRef.style.fontSize='.7em';
+ qRefreshRef.style.borderRadius='1.2em';
+ qRefreshRef.innerHTML='auto refresh';
+ lmntRef.appendChild(qRefreshRef);
+
+ let lastRandomIndex=-1;
+ let nextRefresh=-1;
+
+ function updateRefreshText() {qRefreshRef.innerHTML=`Next auto-refresh in ${nextRefresh} sec.`};
+
+ function randomQuote(){
+ let quoteList=[
+ {qName:'Alan Dundes', qText:'Light travels faster than sound. This is why some people appear bright until you hear them speak.'},
+ {qName:'Albert Camus', qText:'Nobody realizes that some people expend tremendous energy merely to be normal.'},
+ {qName:'Albert Einstein', qText:'The difference between stupidity and genius is that genius has its limits.'},
+ {qName:'Alexander Woollcott', qText:'All the things I really like to do are either immoral, illegal or fattening.'},
+ {qName:'Ambrose Bierce', qText:'War is God’s way of teaching Americans geography.'},
+ {qName:'Andy Borowitz', qText:'It would be nice to spend billions on schools and roads, but right now that money is desperately needed for political ads.'},
+ {qName:'Andy Rooney', qText:'The average dog is a nicer person than the average person.'},
+ {qName:'Ann Landers', qText:'If you want your children to listen, try talking softly to someone else.'},
+ {qName:'Arthur C. Clarke', qText:'I don’t believe in astrology; I’m a Sagittarius and we’re skeptical.'},
+ {qName:'Ashleigh Brilliant', qText:'My opinions may have changed, but not the fact that I’m right.'},
+ {qName:'Benjamin Franklin', qText:'Wine is constant proof that God loves us and loves to see us happy.'},
+ {qName:'Benny Hill', qText:'Have you noticed that all the people in favor of birth control are already born?'},
+ {qName:'Bernard Baruch', qText:'Be who you are and say what you feel, because those who mind don’t matter and those who matter don’t mind.'},
+ {qName:'Bertrand Russell', qText:'Most people would sooner die than think; in fact, they do so.'},
+ {qName:'Bertrand Russell', qText:'The world is full of magical things patiently waiting for our wits to grow sharper.'},
+ {qName:'Betty White', qText:'Facebook just sounds like a drag, in my day seeing pictures of peoples vacations was considered a punishment.'},
+ {qName:'Bill Maher', qText:'Everything that used to be a sin is now a disease.'},
+ {qName:'Bill Watterson', qText:'The surest sign that intelligent life exists elsewhere in the universe is that it has never tried to contact us.'},
+ {qName:'Billy Connolly', qText:'Before you judge a man, walk a mile in his shoes. After that who cares? ... He’s a mile away and you’ve got his shoes!'},
+ {qName:'Billy Sunday', qText:'Going to church doesn’t make you a Christian any more than going to a garage makes you an automobile.'},
+ {qName:'Billy Wilder', qText:'If you’re going to tell people the truth, be funny or they’ll kill you.'},
+ {qName:'Bob Hope', qText:'A bank is a place that will lend you money if you can prove that you don’t need it.'},
+ {qName:'Bob Thaves', qText:'Inside me there’s a thin person struggling to get out, but I can usually sedate him with four or five cupcakes.'},
+ {qName:'Bryan White', qText:'We never really grow up, we only learn how to act in public.'},
+ {qName:'Buddy Hackett', qText:'As a child my family’s menu consisted of two choices: take it or leave it.'},
+ {qName:'Caroline Rhea', qText:'My favorite machine at the gym is the vending machine.'},
+ {qName:'Casey Stengel', qText:'All right everyone, line up alphabetically according to your height.'},
+ {qName:'DOT.NOT', qText:'Don’t cry because it happened. Rather smile ’cause it’s over.'},
+ {qName:'Charles de Gaulle', qText:'He who laughs last didn’t get the joke.'},
+ ];
+ let rngIdx=-1;
+ do {rngIdx=Math.floor(Math.random()*quoteList.length)} while (rngIdx==lastRandomIndex);
+ lastRandomIndex=rngIdx;
+ qTextRef.innerHTML=quoteList[lastRandomIndex].qText;
+ qPersonRef.innerHTML=quoteList[lastRandomIndex].qName;
+ nextRefresh=15;
+ updateRefreshText();
+ }
+
+ function quoteRefresh() {
+ nextRefresh-=1;
+ if (nextRefresh>0) {updateRefreshText()} else {randomQuote()};
+ }
+
+ randomQuote();
+ setInterval(quoteRefresh,1000);
+
+};
+
+;
+
diff --git a/Week2/homework/js-exercises/ex01-odd-ones-out/oddOnesOut.js b/Week2/homework/js-exercises/ex01-odd-ones-out/oddOnesOut.js
new file mode 100644
index 000000000..5e7abf1b7
--- /dev/null
+++ b/Week2/homework/js-exercises/ex01-odd-ones-out/oddOnesOut.js
@@ -0,0 +1,23 @@
+
+{
+ 'use strict';
+
+ function doubleEvenNumbers(numbers) {
+ return numbers.filter(aValue=>aValue%2==0).map(aValue=>aValue*2)};
+
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 2 - Exercise 01 - The odd ones out");
+ console.log("Practice with Array methods map & filter: rewrite given function doubleEvenNumbers()");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ let testValues=[1,2,3,4];
+ console.log(`Evoking doubleEvenNumbers([${testValues}]) yields this [${doubleEvenNumbers(testValues)}] result`);
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week2/homework/js-exercises/ex02-daily-salary/calcWorth.js b/Week2/homework/js-exercises/ex02-daily-salary/calcWorth.js
new file mode 100644
index 000000000..a722413ac
--- /dev/null
+++ b/Week2/homework/js-exercises/ex02-daily-salary/calcWorth.js
@@ -0,0 +1,34 @@
+
+{
+ 'use strict';
+
+ function calcDailySalary(objArray,hourlyWage) {
+ const dailyHours=objArray.map(currentRef=>Number(currentRef['duration']))
+ .reduce((totalValue,currentValue)=>totalValue+currentValue,0)/60;
+ return `Based on your hourly wage of €${hourlyWage} `
+ +`and the total of ${dailyHours} working hours `
+ +`your salary will be €${Math.round(100*dailyHours*hourlyWage)/100}`;
+ };
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 2 - Exercise 02 - What's your Workday's worth");
+ console.log("Practice with Array of objects: iteration and value sum");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ const mondayTasks = [
+ { name: 'Daily standup', duration: 30, },
+ { name: 'Feature discussion', duration: 120, },
+ { name: 'Development time', duration: 240, },
+ { name: 'Talk to different members from the product team', duration: 60, },
+ ];
+
+ console.log("Calculate the Day's salary based on following task schedule:");
+ console.log(mondayTasks);
+ console.log(calcDailySalary(mondayTasks,25));
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+;
+
diff --git a/Week2/homework/js-exercises/ex03-lemon-allergy/lemonAllergy.js b/Week2/homework/js-exercises/ex03-lemon-allergy/lemonAllergy.js
new file mode 100644
index 000000000..12fc17a6d
--- /dev/null
+++ b/Week2/homework/js-exercises/ex03-lemon-allergy/lemonAllergy.js
@@ -0,0 +1,33 @@
+
+{
+ 'use strict';
+
+ function filterFruits(fruitArray,allergicFruit) {
+ console.log(`Your mother bought you a basket of fruit, that contains [${fruitArray}]`);
+ let fResult=fruitArray.filter(lmnt=>lmnt.toLowerCase()!=allergicFruit.toLowerCase());
+ if (fruitArray.length==fResult.length) {
+ console.log(`How nice of her! She even remembered not to include any`+` ${allergicFruit}, which you are allergic to.`);
+ } else {
+ console.log(`Unfortunately she failed to remember that you are allergic to`+` ${allergicFruit}, which you asked her to remove.`);
+ console.log('Now the basket '+(fResult.length<1?'is sadly empty!':`contains [${fResult}].`));
+ }
+ return fResult;
+ }
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 2 - Exercise 03 - Lemon allergy");
+ console.log("Practice with Array filtering");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ filterFruits(['Apples','LeMons','Grapefruits','LemOns','Bananas','Watermelons','LemoNs'],'Lemons');
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+ filterFruits(['Apples','aPpLeS','APPLES'],'apples');
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+ filterFruits(['Apples','Lemons','Grapefruits','Bananas','Watermelons','Oranges'],'Grapes');
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+;
+
diff --git a/Week2/homework/js-exercises/ex04-collective-age/collectiveAge.js b/Week2/homework/js-exercises/ex04-collective-age/collectiveAge.js
new file mode 100644
index 000000000..56e73f580
--- /dev/null
+++ b/Week2/homework/js-exercises/ex04-collective-age/collectiveAge.js
@@ -0,0 +1,47 @@
+
+{
+ 'use strict';
+
+ function getCollectiveAge(objArray) {
+ function logMsg(msgHeader,msgText,msgValue) {
+ msgHeader?console.log(msgHeader):null; msgText?console.log(msgText):null;
+ msgValue?console.log(msgValue):null; console.log('-'+' -'.repeat(20)); };
+ function safeInt(inValue,defValue) {let fres=parseInt(inValue); return (isNaN(fres)?defValue:fres)};
+ logMsg('Collective age - aggregation exercise'
+ ,'Diferent solutions to get same result, calculated on following dataset:',objArray);
+ let sum1=objArray.map(lmnt=>safeInt(lmnt['age'],0)).reduce((aSum,lmnt)=>aSum+lmnt);
+ logMsg('Using map (as per exercise request) & reduce (to aggregate result)'
+ ,`Code: let sum1=objArray.map(lmnt=>safeInt(lmnt['age'],0)).reduce((aSum,lmnt)=>aSum+lmnt);`
+ ,`The aggregated value (collective age) is [${sum1}]`);
+ let sum2=0; objArray.map(lmnt=>(sum2+=safeInt(lmnt['age'],0)));
+ logMsg('Using only map (as per exercise request) for sum aggregation'
+ ,`Code: let sum2=0; objArray.map(lmnt=>(sum2+=safeInt(lmnt['age'],0)));`
+ ,`The aggregated value (collective age) is [${sum2}]`);
+ let sum3=objArray.reduce((aSum,lmnt)=>aSum+safeInt(lmnt['age'],0),0);
+ logMsg('Using only reduce (to aggregate wanted result)'
+ ,`Code: let sum3=objArray.reduce((aSum,lmnt)=>aSum+safeInt(lmnt['age'],0),0);`
+ ,`The aggregated value (collective age) is [${sum3}]`);
+ return sum3;
+ }
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 2 - Exercise 04 - Collective Age");
+ console.log("Practice with Array mapping and value aggregation ( .map and .reduce )");
+ console.log("- - - - - - - - - - - - - - - - - - - - -");
+ console.log("Bonus: safeguarding against NaN for non-numeric values or missing property in dataset");
+ console.log("- - - - - - - - - - - - - - - - - - - - -");
+ const hackYourFutureMembers = [
+ { name: 'Wouter', age: 33 },
+ { name: 'Federico', age: 32 },
+ { name: 'Someone old', ages: 452 },
+ { name: 'Too young', age: 'Young' },
+ { name: 'Noer', age: 27 },
+ { name: 'Tjebbe', age: 22 },
+ ];
+ getCollectiveAge(hackYourFutureMembers);
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+;
+
diff --git a/Week2/homework/js-exercises/ex05-favorite-hobbies/index.html b/Week2/homework/js-exercises/ex05-favorite-hobbies/index.html
new file mode 100644
index 000000000..de955a63e
--- /dev/null
+++ b/Week2/homework/js-exercises/ex05-favorite-hobbies/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Week2/homework/js-exercises/ex05-favorite-hobbies/main.css b/Week2/homework/js-exercises/ex05-favorite-hobbies/main.css
new file mode 100644
index 000000000..6732c9b5d
--- /dev/null
+++ b/Week2/homework/js-exercises/ex05-favorite-hobbies/main.css
@@ -0,0 +1,27 @@
+
+body {
+ margin: 0px 18px;
+ padding: 0px;
+ font-size: 150%;
+ font-family: sans-serif;
+ }
+
+.cls_text_align_left {
+ text-align: left;
+ }
+
+.cls_text_align_right {
+ text-align: right;
+ }
+
+.cls_text_align_center {
+ text-align: center;
+ }
+
+div {
+ padding: 12px 16px 8px 16px;
+ margin: 20px 0px;
+ }
+
+;
+
diff --git a/Week2/homework/js-exercises/ex05-favorite-hobbies/main.js b/Week2/homework/js-exercises/ex05-favorite-hobbies/main.js
new file mode 100644
index 000000000..3220eea66
--- /dev/null
+++ b/Week2/homework/js-exercises/ex05-favorite-hobbies/main.js
@@ -0,0 +1,107 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML
+ =`(Homework: Javascript 2 - week 2) - (Exercise 05: All your favorite hobbies)`;
+ lmntRef.style.borderRadius='12px';
+ document.body.style.backgroundColor='#25003e';
+
+ lmntRef=document.createElement('DIV');
+ lmntRef.innerHTML='Bonus content: the javascript file contains'
+ +' a randomPhraseComposer routine !';
+ lmntRef.style.backgroundColor='pink';
+ lmntRef.style.borderRadius='12px';
+ lmntRef.style.textAlign='center';
+ lmntRef.style.fontSize='85%';
+ document.body.appendChild(lmntRef);
+
+ lmntRef=document.createElement('DIV');
+ lmntRef.style.backgroundColor='orange';
+ lmntRef.style.borderRadius='.8em';
+ document.body.appendChild(lmntRef);
+
+ let msgRef=document.createElement('H4');
+ msgRef.innerHTML='Welcome my friend. Here is an extensive list of your hobbies:';
+ msgRef.style.margin='10px 0px 0px';
+ msgRef.style.padding='0px 0px';
+ lmntRef.appendChild(msgRef);
+
+ msgRef=document.createElement('SPAN');
+ msgRef.style.backgroundColor='gold';
+ msgRef.style.position='absolute';
+ msgRef.style.bottom='1em';
+ msgRef.style.right='1em';
+ msgRef.style.padding='8px 14px';
+ msgRef.style.margin='0px';
+ msgRef.style.borderRadius='.8em';
+ msgRef.style.fontSize='80%';
+ document.body.appendChild(msgRef);
+
+ let listRef=document.createElement('UL');
+ listRef.style.margin='10px 0px 10px 50px';
+ listRef.style.padding='0px 0px';
+ lmntRef.appendChild(listRef);
+
+ function randomPhraseComposer(listOfLists,maxPhraseCount) {
+ function spliceRandomArrayElement(anArray)
+ {return anArray.splice(Math.floor(Math.random()*anArray.length),1)};
+ let clonedList=[]; let resCount=maxPhraseCount?maxPhraseCount:undefined;
+ for (let i=0; iclonedList[i].length))
+ {resCount=clonedList[i].length};
+ };
+ let fResult=[];
+ for (let i=0; i0) {listRef.removeChild(listRef.childNodes[0])}
+ randomPhraseComposer([listPrefix,listMiddle,listSuffix],12).forEach(lmnt=>{
+ let chldRef=document.createElement('LI');
+ chldRef.innerHTML=lmnt;
+ chldRef.style.padding='3px 0px 3px 12px';
+ listRef.appendChild(chldRef);
+ });
+ nextRefresh=60;
+ refreshText();
+ };
+
+ showHobbies();
+ setInterval(()=>{nextRefresh-=1;if(nextRefresh>0){refreshText()}else{showHobbies()}},1000);
+};
+
+;
+
diff --git a/Week2/homework/js-exercises/project-countdown-timer/index.html b/Week2/homework/js-exercises/project-countdown-timer/index.html
new file mode 100644
index 000000000..d3aff861a
--- /dev/null
+++ b/Week2/homework/js-exercises/project-countdown-timer/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Countdown Timer
+
+
timer_status
+
+
+
timer_toggle
+
+
+
+
+
+
+
diff --git a/Week2/homework/js-exercises/project-countdown-timer/main.css b/Week2/homework/js-exercises/project-countdown-timer/main.css
new file mode 100644
index 000000000..27afa81b6
--- /dev/null
+++ b/Week2/homework/js-exercises/project-countdown-timer/main.css
@@ -0,0 +1,85 @@
+
+body {
+ margin: 0px 18px;
+ padding: 0px;
+ font-size: 1.5em;
+ font-family: sans-serif;
+ }
+
+div, p {
+ margin: 0px;
+ padding: 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 0px;
+ }
+
+#id_timer_background {
+ background-color: rgb(35,80,95);
+ color: wheat;
+ display: table;
+ margin: 0 auto;
+ border-radius: 50px 15px;
+ padding: 0px 30px 30px 30px;
+ }
+
+#id_timer_container {
+ border-style: outset;
+ border-color: navy;
+ border-radius: 60px;
+ border-width: 7px;
+ font-size: 1.6em;
+ padding: 30px 40px 20px 40px;
+ }
+
+#id_timer_element {
+ display: inline-block;
+ font-size: 2.8em;
+ margin: 0px 30px;
+ }
+
+#id_min_container, #id_sec_container {
+ display: inline-block;
+ }
+
+#id_timer_toggle {
+ background-color: #3b88c3;
+ display: table;
+ margin: 0 auto;
+ padding: 8px 20px;
+ border-radius: 20px;
+ }
+
+;
+
diff --git a/Week2/homework/js-exercises/project-countdown-timer/main.js b/Week2/homework/js-exercises/project-countdown-timer/main.js
new file mode 100644
index 000000000..44389cad1
--- /dev/null
+++ b/Week2/homework/js-exercises/project-countdown-timer/main.js
@@ -0,0 +1,57 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML=
+ `(Homework: Javascript 2 - week 2) - (PROJECT: Countdown Timer)`;
+ lmntRef.style.borderRadius='12px';
+ document.body.style.backgroundColor='#25003e';
+
+ const timerStatusRef=document.getElementById('id_timer_status');
+ const timerDisplayRef=document.getElementById('id_timer_element');
+ const timerMinGrpRef=document.getElementById('id_min_container');
+ const timerSecGrpRef=document.getElementById('id_sec_container');
+ const timerMinIncRef=document.getElementById('id_min_increase');
+ const timerMinDecRef=document.getElementById('id_min_decrease');
+ const timerSecIncRef=document.getElementById('id_sec_increase');
+ const timerSecDecRef=document.getElementById('id_sec_decrease');
+ const timerToggleRef=document.getElementById('id_timer_toggle');
+ const maxTimerTime=3599;
+ let timerIsActive=true;
+ let timerCurrentValue;
+ let countdownTimer;
+ document.body.onloadend=initializePage();
+
+ function initializePage() {
+ setTimeValue(0);
+ timerStatusRef.innerHTML='Set countdown time';
+ timerToggleRef.addEventListener("click",()=>
+ {timerIsActive=!timerIsActive; setTimeValue(timerCurrentValue)});
+ timerMinIncRef.addEventListener("click",()=>setTimeValue(timerCurrentValue+60));
+ timerMinDecRef.addEventListener("click",()=>setTimeValue(timerCurrentValue-60));
+ timerSecIncRef.addEventListener("click",()=>setTimeValue(timerCurrentValue+1));
+ timerSecDecRef.addEventListener("click",()=>setTimeValue(timerCurrentValue-1));
+ };
+
+ function setTimeValue(newValue) {
+ timerCurrentValue=(newValue<1?0:newValue>maxTimerTime?maxTimerTime:newValue);
+ timerIsActive=timerIsActive&&(timerCurrentValue>0);
+ timerStatusRef.innerHTML=(timerCurrentValue==0?'Timer has expired'
+ :timerIsActive?'Countdown in progress':'Countdown is Paused');
+ timerDisplayRef.innerHTML=('0'+String(Math.floor(timerCurrentValue/60))).substr(-2)
+ +':'+('0'+String(timerCurrentValue%60)).substr(-2);
+ timerToggleRef.innerHTML=(timerIsActive?'Pause countdown':'Resume countdown');
+ timerToggleRef.style.display=(timerCurrentValue==0?'none':'block');
+ timerMinGrpRef.style.visibility=(timerIsActive?'hidden':'visible');
+ timerSecGrpRef.style.visibility=(timerIsActive?'hidden':'visible');
+ if ((countdownTimer)&&(!timerIsActive))
+ {clearInterval(countdownTimer);countdownTimer=undefined};
+ if ((timerIsActive)&&(!countdownTimer))
+ {countdownTimer=setInterval(()=>{setTimeValue(timerCurrentValue-1)},1000)};
+ };
+};
+
+;
+
diff --git a/Week3/homework/js-exercises/ex01-add-six-closure.js b/Week3/homework/js-exercises/ex01-add-six-closure.js
new file mode 100644
index 000000000..f11dfb4c5
--- /dev/null
+++ b/Week3/homework/js-exercises/ex01-add-six-closure.js
@@ -0,0 +1,38 @@
+
+{
+ 'use strict';
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 3 - Exercise 01 - Add six");
+ console.log("Practice with closures");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ // define the closure generator
+ function createBase(paramBaseValue) {
+ const baseValue=paramBaseValue;
+ return (paramValue)=>{return paramValue+=baseValue};
+ }
+
+ // define all required tests
+ const testingList={ // this works ( even tho addSix is undeclared yet )
+ test_1:()=>addSix(9), // because: the function only executes when evoked,
+ test_2:()=>addSix(18), // which happens much later in the code,
+ test_3:()=>addSix(30), // and by that point addSix has already been defined
+ };
+
+ // create a closure containing a base value of 6
+ const addSix=createBase(6);
+
+ // evoke all required tests - console.log() each with the result
+ Object.keys(testingList).forEach((pLmnt,pIdx)=>{console.log(`${
+ pLmnt.replace(/_+/g,' ')} : ${
+ String(Object.values(testingList)[pIdx]).substr(4)} result is ${
+ testingList[pLmnt]()}`)});
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week3/homework/js-exercises/ex02-remove-duplicates.js b/Week3/homework/js-exercises/ex02-remove-duplicates.js
new file mode 100644
index 000000000..49de6f815
--- /dev/null
+++ b/Week3/homework/js-exercises/ex02-remove-duplicates.js
@@ -0,0 +1,52 @@
+
+{
+ 'use strict';
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 3 - Exercise 02 - Take out the duplicates");
+ console.log("Practice with array manipulation");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ const myNumberList=[4,6,4,5,6,3,4,7,2,5,8,4,1,9];
+ console.log(`my Number List [${joinQuoted(myNumberList)}]`);
+ console.log(`filter cloned (original array untouched) [${
+ joinQuoted(filterCloneUniqueArrayElements(myNumberList))}]`);
+ removeDuplicateArrayElements(myNumberList);
+ console.log(`uniquefied (applied on original array) [${joinQuoted(myNumberList)}]`);
+ console.log(` `);
+
+ const myCharList=['q','w','e','r','3','w','1','t','q','y',1];
+ console.log(`my Character List [${joinQuoted(myCharList)}]`);
+ console.log(`filter cloned (original array untouched) [${
+ joinQuoted(filterCloneUniqueArrayElements(myCharList))}]`);
+ removeDuplicateArrayElements(myCharList);
+ console.log(`uniquefied (applied on original array) [${joinQuoted(myCharList)}]`);
+
+ function joinQuoted (theArray,joinChar)
+ {return theArray.map(lmnt=>typeof(lmnt)=='string'
+ ?'"'+lmnt.replace(/\"/g,"'")+'"':lmnt).join(joinChar)};
+
+ function filterCloneUniqueArrayElements (theArray)
+ {return theArray.filter((pLmnt,pIdx,pArray)=>pIdx==pArray.indexOf(pLmnt))};
+
+ function objectifyCloneArrayElements (theArray) {
+ let unq={};
+ theArray.forEach(lmnt=>unq[lmnt]=1);
+ return Object.keys(unq);
+ };
+
+ function removeDuplicateArrayElements (theArray) {
+ let dupIndexList=[];
+ theArray.forEach((pLmnt,pIdx)=>pIdx==theArray.indexOf(pLmnt)?null:dupIndexList.unshift(pIdx));
+ //console.log(` indice of duplicate values [${dupIndexList}]`);
+ dupIndexList.forEach(pLmnt=>{theArray.splice(pLmnt,1)});
+ return theArray;
+ };
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week3/homework/js-exercises/ex03-guess-output-1.js b/Week3/homework/js-exercises/ex03-guess-output-1.js
new file mode 100644
index 000000000..2f68885e2
--- /dev/null
+++ b/Week3/homework/js-exercises/ex03-guess-output-1.js
@@ -0,0 +1,36 @@
+
+{
+ 'use strict';
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 3 - Exercise 03 - Guess the output");
+ console.log("Practice with closures");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ let a = 10;
+ const x = (function() {
+ a = 12;
+ return function() {
+ alert(a);
+ };
+ })();
+
+ console.log(`"x" is a Closure,`);
+ console.log(` which is a function defined and returned (as a result)`);
+ console.log(` from within another function.`);
+ console.log(` `);
+ console.log(`Closures have access to the scope of their constructor`);
+ console.log(` so "a" in "alert(a)" holds the value "12"`);
+ console.log(` `);
+ console.log(`Therefore evoking the closure "x()"`);
+ console.log(` will produce a popup window with the message "12"`);
+
+ x();
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week3/homework/js-exercises/ex04-guess-output-2.js b/Week3/homework/js-exercises/ex04-guess-output-2.js
new file mode 100644
index 000000000..6b9525078
--- /dev/null
+++ b/Week3/homework/js-exercises/ex04-guess-output-2.js
@@ -0,0 +1,59 @@
+
+{
+ 'use strict';
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 3 - Exercise 04 - Guess more");
+ console.log("Practice with closures");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ const x = 9;
+ function f1(val) {
+ val = val + 1;
+ return val;
+ }
+
+ const y = { x: 9 };
+ function f2(val) {
+ val.x = val.x + 1;
+ return val;
+ }
+
+ console.log(` `);
+ console.log(`"x" is a number, which is a primitive datatype. `);
+ console.log(` Function parameters of primitive type are passed by value `);
+ console.log(` meaning that any changes done inside the scope of "f1" `);
+ console.log(` is actually done to a local copy of the variable `);
+ console.log(` and will not affect the global variable. `);
+ console.log(` (even were it declared with "let" instead of "const")`);
+ console.log(` `);
+ console.log(`Therefore "console.log(f1(x))" would produce "10" `);
+ console.log(` which is the function's result `);
+ console.log(`Whereas "console.log(x)" would produces "9" `);
+ console.log(` both before and after calling "f1(x)" `);
+ console.log(` `);
+ console.log(`value of "x" before function = [${x}] `);
+ console.log(`value of function "f1(x)" = [${f1(x)}] `);
+ console.log(`value of "x" after function = [${x}] `);
+ console.log(` `);
+
+ console.log(` `);
+ console.log(`"y" in contrast, is an object datatype and "x" is a property of that onject. `);
+ console.log(` Value changes to properties of objects are not scope-specific `);
+ console.log(` regardless of the object declaration, either "const" or "let" `);
+ console.log(` `);
+ console.log(`Therefore "console.log(f2(y).x)" would produce "10" `);
+ console.log(` which is the value of the property "x" of the function's result `);
+ console.log(`Whereas "console.log(y.x)" would produce "9" before "f2(y)", but "10" after `);
+ console.log(` `);
+ console.log(`value of "y.x" before function = [${y.x}] `);
+ console.log(`value of function "f2(y).x" = [${f2(y).x}] `);
+ console.log(`value of "y.x" after function = [${y.x}] `);
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week3/homework/js-exercises/ex05-the-lottery.js b/Week3/homework/js-exercises/ex05-the-lottery.js
new file mode 100644
index 000000000..cd849ee24
--- /dev/null
+++ b/Week3/homework/js-exercises/ex05-the-lottery.js
@@ -0,0 +1,43 @@
+
+{
+ 'use strict';
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log("JS-2 - week 3 - Exercise 05 - The lottery machine");
+ console.log("Practice with callbacks");
+ console.log("- - - - - - - - - - - - - - - - - - - -");
+
+ runBingo( 10,15);
+ runBingo(-15,15);
+
+ function runBingo (lowRange,highRange) {
+ console.log(`Checking for Bingo for 3 and 5 in the range ${lowRange} to ${highRange} `);
+ bingoThreeFive(lowRange,highRange,threeCallback,fiveCallback);
+ }
+
+ function bingoThreeFive (pNumFrom,pNumTo,pCallbackThree,pCallbackFive) {
+ const startNumber=!pNumFrom?0:pNumFrom;
+ const stopNumber=!pNumTo?startNumber:pNumTo{
+ if ((lmnt%3==0)&&(pCallbackThree)) {pCallbackThree(lmnt)};
+ if ((lmnt%5==0)&&(pCallbackFive)) {pCallbackFive(lmnt)};
+ });
+ };
+
+ function threeCallback (theNumber) {
+ console.log(`We have a Winner for 3 on the value ${theNumber} `);
+ };
+
+ function fiveCallback (theNumber) {
+ console.log(`We have a Winner for 5 on the value ${theNumber} `);
+ };
+
+ console.log("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =");
+ console.log(" ");
+};
+
+
+;
+
diff --git a/Week3/homework/js-exercises/project-tip-calculator/index.html b/Week3/homework/js-exercises/project-tip-calculator/index.html
new file mode 100644
index 000000000..7376126e9
--- /dev/null
+++ b/Week3/homework/js-exercises/project-tip-calculator/index.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
id_service_quality_text
+
id_service_quality_tip
+
+
+
+
+ ➖
+ id_people_total_text
+ ➕
+
+
+
+
+
+
+
+
diff --git a/Week3/homework/js-exercises/project-tip-calculator/main.css b/Week3/homework/js-exercises/project-tip-calculator/main.css
new file mode 100644
index 000000000..b4dc8544e
--- /dev/null
+++ b/Week3/homework/js-exercises/project-tip-calculator/main.css
@@ -0,0 +1,235 @@
+
+body {
+ margin: 0px 18px;
+ padding: 0px;
+ font-size: 1.5em;
+ font-family: sans-serif;
+ }
+
+div, p {
+ margin: 0px;
+ padding: 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 0px;
+ }
+
+
+
+#id_calc_background {
+ background-color: rgb(85,50,75);
+ color: black;
+ display: table;
+ margin: 0 auto;
+ border-radius: 15px;
+ padding: 20px 60px;
+ height: 100%;
+ font-size: .85em;
+ text-align: center;
+ }
+
+#id_calc_header {
+ background-color: black;
+ color: wheat;
+ padding: 20px 40px 12px;
+ border-radius: 30px 30px 0px 0px;
+ }
+
+#id_calc_container_amount,
+#id_calc_container_service,
+#id_calc_container_sharing {
+ background: linear-gradient(to bottom right, wheat, #f5f7fa);
+ margin: 0px;
+ padding: 15px 20px 15px;
+ }
+
+#id_calc_container_amount {
+ padding-top: 20px;
+ }
+
+#id_calc_container_sharing {
+ padding-bottom: 16px;
+ }
+
+#id_calc_container_footer {
+ background: linear-gradient(to bottom right, gold, orange);
+ font-size: 1.2em;
+ margin: 0px;
+ padding: 15px 20px 15px;
+ border-radius: 0px 0px 30px 30px;
+ }
+
+#id_service_quality_header,
+#id_people_total_header,
+#id_bill_total_header {
+ font-size: 1.2em;
+ text-align: left;
+ padding: 0px 0px 10px;
+ }
+
+#id_people_total_header {
+ padding-bottom: 16px;
+ }
+
+#id_bill_total_edit {
+ font-size: 1.3em;
+ width: 6em;
+ margin-left: 6px;
+ text-align: right;
+ }
+
+#id_service_quality_group {
+ margin-left: 25px;
+ text-align: left;
+ padding-right: 3px;
+ font-size: 1.2em;
+ }
+
+#id_service_quality_styling {
+ display: inline-block;
+ padding: 0px 8px 5px;
+ vertical-align: bottom;
+ }
+
+#id_service_quality_rating {
+ position: relative;
+ height: 1.4em;
+ width: 7em;
+ margin: 0;
+ padding: 0;
+ background: url("./resources/star_empty.bmp");
+ background-size: 1.4em 1.4em;
+ display: inline-block;
+ }
+
+.cls_service_quality_label {
+ position: absolute;
+ height: 100%;
+ background-size: 1.4em 1.4em;
+ }
+
+.cls_service_quality_radio {
+ margin: 0;
+ position: absolute;
+ height: 1px;
+ width: 1px;
+ overflow: hidden;
+ clip: rect(1px,1px,1px,1px);
+ }
+
+#id_service_quality_rating .cls_service_quality_label:nth-of-type(1) {
+ z-index: 5;
+ width: 20%;
+ }
+
+#id_service_quality_rating .cls_service_quality_label:nth-of-type(2) {
+ z-index: 4;
+ width: 40%;
+ }
+
+#id_service_quality_rating .cls_service_quality_label:nth-of-type(3) {
+ z-index: 3;
+ width: 60%;
+ }
+
+#id_service_quality_rating .cls_service_quality_label:nth-of-type(4) {
+ z-index: 2;
+ width: 80%;
+ }
+
+#id_service_quality_rating .cls_service_quality_label:nth-of-type(5) {
+ z-index: 1;
+ width: 100%;
+ }
+
+.cls_service_quality_radio:checked + .cls_service_quality_label,
+.cls_service_quality_radio:focus + .cls_service_quality_label
+ /* ,.cls_service_quality_label:hover */
+ {
+ background-image: url("./resources/star_filled.bmp");
+ }
+
+/*
+.cls_service_quality_label:hover ~ .cls_service_quality_label {
+ background-image: url("./resources/star_empty.bmp");
+ }
+*/
+.cls_service_quality_label:hover {
+ cursor: pointer;
+ }
+
+.cls_service_quality_radio:focus ~ .cls_service_quality_focus {
+ position: absolute;
+ top: -3px;
+ right: -3px;
+ bottom: -3px;
+ left: -3px;
+ outline: 1px solid blue;
+ }
+
+#id_service_quality_text {
+ display: inline-block;
+ padding: 0px 0px 9px 8px;
+ margin: 0px;
+ vertical-align: bottom;
+ }
+
+#id_service_quality_tip {
+ font-size: 0.66em;
+ text-align: right;
+ margin: 0px 0px 0px;
+ }
+
+#id_people_total_sub,
+#id_people_total_add {
+ border: 1px solid blue;
+ border-radius: 45%;
+ padding: 3px 3px 1px;
+ width: 1.8em;
+ background: lightblue;
+ cursor: pointer;
+ display: inline-block;
+ }
+#id_people_total_sub:hover,
+#id_people_total_add:hover {
+ background: gold;
+ }
+
+#id_people_total_text {
+ font-size: 1.2em;
+ width: 8em;
+ display: inline-block;
+ }
+
+;
diff --git a/Week3/homework/js-exercises/project-tip-calculator/main.js b/Week3/homework/js-exercises/project-tip-calculator/main.js
new file mode 100644
index 000000000..3552f3810
--- /dev/null
+++ b/Week3/homework/js-exercises/project-tip-calculator/main.js
@@ -0,0 +1,124 @@
+
+{
+ 'use strict';
+
+ let lmntRef=document.getElementById('id_page_header');
+ lmntRef.style.backgroundColor='gold';
+ document.getElementById('id_page_title').innerHTML=lmntRef.innerHTML=
+ `(Homework: Javascript 2 - week 3) - (PROJECT: The Tip Calculator)`;
+ lmntRef.style.borderRadius='12px';
+ document.body.style.backgroundColor='#25003e';
+
+ const symbolCurrencyEuro='€';
+ const symbolApostrophe='’';
+
+ const billTotalEditRef=document.getElementById("id_bill_total_edit");
+ const qualityRadioRef=document.getElementsByClassName('cls_service_quality_radio');
+ const billPeopleSubRef=document.getElementById("id_people_total_sub");
+ const billPeopleAddRef=document.getElementById("id_people_total_add");
+ const arrowLeft =37;
+ const arrowUp =38;
+ const arrowRight=39;
+ const arrowDown =40;
+
+ const setBillData=createBillData();
+ initializePageData(0,2,1);
+
+ function initializePageData(pAmount,pRating,pSharing) {
+ qualityRadioRef[pRating].checked=true;
+ billTotalEditRef.value=pAmount;
+ setBillData(pAmount,pRating,pSharing);
+ for (let i=0; i<5; i++) {
+ switch (i) {
+ case 0 : qualityRadioRef[i].onkeydown=function(event){
+ if ([arrowDown,arrowUp,arrowLeft].indexOf(event.keyCode)>=0)
+ {event.preventDefault()}};
+ break;
+ case 4 : qualityRadioRef[i].onkeydown=function(event){
+ if ([arrowDown,arrowUp,arrowRight].indexOf(event.keyCode)>=0)
+ {event.preventDefault()}};
+ break;
+ default: qualityRadioRef[i].onkeydown=function(event){
+ if ([arrowDown,arrowUp].indexOf(event.keyCode)>=0)
+ {event.preventDefault()}};
+ }
+ qualityRadioRef[i].onchange=function() {setBillData(undefined,Number(this.value))};
+ }
+ billTotalEditRef.oninput=function() {setBillData(this.value)};
+ billPeopleSubRef.onclick=function(event) {setBillData(undefined,undefined,-1)};
+ billPeopleAddRef.onclick=function(event) {setBillData(undefined,undefined,1)};
+ }
+
+ function createBillData() {
+ const qualityRatingTextRef=document.getElementById('id_service_quality_text');
+ const qualityPercentTipRef=document.getElementById("id_service_quality_tip");
+ const billPeopleTextRef=document.getElementById("id_people_total_text");
+ const calcTipHeaderRef=document.getElementById("id_calc_tip_header");
+ const calcTipAmountRef=document.getElementById("id_calc_tip_amount");
+ const calcTipEachRef=document.getElementById("id_calc_tip_each");
+ calcTipAmountRef.style.paddingTop='4px';
+ const qualityList = [
+ { ratingPercent: 5, ratingText:'Poor' },
+ { ratingPercent: 10, ratingText:'Fair' },
+ { ratingPercent: 15, ratingText:'Good' },
+ { ratingPercent: 20, ratingText:'Very good' },
+ { ratingPercent: 30, ratingText:'Excellent' } ];
+ const maxValue=9999.99;
+ let propAmount = -1;
+ let propRating = -1;
+ let propSharing= 0;
+ return (pAmount,pRating,pSharing)=>{
+ if ([setAmount(pAmount),setRating(pRating),setSharing(pSharing)].indexOf(true)>-1) {
+ if ((isNaN(propAmount))||(propAmount<=0)||(propAmount>maxValue)) {
+ calcTipHeaderRef.innerHTML='Enter a positive bill amount';
+ calcTipAmountRef.innerHTML='Accepted values range';
+ calcTipEachRef.innerHTML ='between 0.01 and '+maxValue;
+ calcTipAmountRef.style.fontSize='';
+ } else {
+ calcTipHeaderRef.innerHTML='Tip amount';
+ calcTipAmountRef.innerHTML=symbolCurrencyEuro+' '+getFormatedTipAmount();
+ calcTipEachRef.innerHTML =propSharing>1?'each':' ';
+ calcTipAmountRef.style.fontSize='1.5em';
+ };
+ qualityRatingTextRef.innerHTML=getSecureRatingText();
+ qualityPercentTipRef.innerHTML=
+ `( calculating a ${getSecureRatingPercent()}% tip )`;
+ billPeopleTextRef.innerHTML=propSharing>1?propSharing+' people':'one person';
+ };
+ };
+ function getFormatedTipAmount(){
+ return (Math.round(propAmount*getSecureRatingPercent()/getSecureSharing())/100)
+ .toLocaleString(undefined,{minimumIntegerDigits:1,minimumFractionDigits:2});
+ }
+ function setAmount(param) {
+ let newAmount=param==undefined?propAmount:Number(param);
+ if (propAmount!=newAmount) {
+ propAmount=newAmount;
+ return true;
+ };
+ };
+ function setRating(param) {
+ let newRating=param==undefined?propRating:param;
+ if (propRating!=newRating) {
+ propRating=newRating;
+ return true;
+ };
+ };
+ function setSharing(param) {
+ let newSharing=param==undefined?propSharing:(propSharing+param)<1?
+ propSharing:(propSharing+param)>99?propSharing:propSharing+param;
+ if (propSharing!=newSharing) {
+ propSharing=newSharing;
+ return true;
+ };
+ };
+ function getSecureRatingText()
+ {return propRating<0?'-':propRating>4?'-':qualityList[propRating].ratingText};
+ function getSecureRatingPercent()
+ {return propRating<0?1:propRating>4?1:qualityList[propRating].ratingPercent};
+ function getSecureSharing(){return propSharing<1?1:propSharing};
+ }
+};
+
+;
+
diff --git a/Week3/homework/js-exercises/project-tip-calculator/resources/star_empty.bmp b/Week3/homework/js-exercises/project-tip-calculator/resources/star_empty.bmp
new file mode 100644
index 000000000..84ed413e6
Binary files /dev/null and b/Week3/homework/js-exercises/project-tip-calculator/resources/star_empty.bmp differ
diff --git a/Week3/homework/js-exercises/project-tip-calculator/resources/star_filled.bmp b/Week3/homework/js-exercises/project-tip-calculator/resources/star_filled.bmp
new file mode 100644
index 000000000..c394e4ad9
Binary files /dev/null and b/Week3/homework/js-exercises/project-tip-calculator/resources/star_filled.bmp differ