├── .gitignore ├── .idea ├── JS Applications.iml ├── modules.xml ├── vcs.xml └── workspace.xml ├── 01 Rest Services and AJAX ├── 01. JS-Applications-HTTP-and-REST-Services-Exercise.docx ├── 01. restCountries.txt └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ ├── server.js │ └── start.bat ├── 02. Asynchronous Programming and Promises ├── Exercise │ ├── 01.Bus-Stop │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 02. JS-Applications-Asynchronous-Programming-Exercise.docx │ ├── 02.Bus-Schedule │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 03.Forecaster │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 04.Locked-Profile │ │ ├── app.js │ │ ├── iconProfile2.png │ │ ├── index.html │ │ └── template.css │ ├── 05. Accordion │ │ ├── 02. Accordion.gif │ │ ├── accordion.css │ │ ├── accordion.js │ │ └── index.html │ ├── 06.Blog │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ └── server │ │ ├── data │ │ ├── advanced.json │ │ ├── blog.json │ │ ├── bus.json │ │ ├── collections.json │ │ ├── cookbook.json │ │ ├── forecaster.json │ │ ├── messenger.json │ │ └── phonebook.json │ │ ├── server.js │ │ └── start.bat └── Lab │ ├── 01.XHR │ ├── index.html │ ├── scripts │ │ └── app.js │ └── styles │ │ └── styles.css │ ├── 02. JS-Applications-Asynchronous-Programming-Lab.docx │ ├── 02.Github-Repos │ ├── index.html │ ├── scripts │ │ └── app.js │ └── styles │ │ └── styles.css │ ├── 03.Gighub-Commits │ ├── app.js │ ├── index.html │ └── styles.css │ ├── 04. Cookbook pt.1 │ ├── app.js │ ├── assets │ │ ├── fish.jpg │ │ ├── lasagna.jpg │ │ └── roast.jpg │ ├── example.html │ ├── index.html │ └── static │ │ └── site.css │ └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ ├── server.js │ └── start.bat ├── 03 Remote Data and Authentication ├── Exercise │ ├── 01.Messenger │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 02.Phonebook │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 03. JS-Applications-Data-and-Authentication-Exercise.docx │ ├── 03.Students │ │ ├── app.js │ │ ├── index.html │ │ └── styles.css │ ├── 04.Book-library │ │ ├── index.html │ │ ├── src │ │ │ ├── app.js │ │ │ ├── createFunctionality.js │ │ │ ├── editFunctionality.js │ │ │ ├── helper.js │ │ │ └── requests.js │ │ └── styles.css │ ├── 05.Fisher-Game │ │ ├── index.html │ │ ├── login.html │ │ ├── src │ │ │ ├── app.js │ │ │ ├── helper.js │ │ │ ├── requests.js │ │ │ └── templates.js │ │ └── static │ │ │ ├── login.css │ │ │ └── styles.css │ ├── 06.Furniture │ │ ├── homeLogged.html │ │ ├── index.html │ │ ├── login.html │ │ ├── src │ │ │ └── requests.js │ │ └── static │ │ │ └── style.css │ ├── server │ │ ├── data │ │ │ ├── advanced.json │ │ │ ├── blog.json │ │ │ ├── bus.json │ │ │ ├── collections.json │ │ │ ├── cookbook.json │ │ │ ├── forecaster.json │ │ │ ├── messenger.json │ │ │ └── phonebook.json │ │ └── server.js │ └── userAuthFunctionality │ │ ├── helper.js │ │ ├── login.js │ │ └── register.js └── Lab │ ├── 01 Cookbook part 2 │ ├── assets │ │ ├── fish.jpg │ │ ├── lasagna.jpg │ │ └── roast.jpg │ ├── create.html │ ├── index.html │ ├── login.html │ ├── register.html │ ├── src │ │ ├── app.js │ │ ├── createRecipe.js │ │ ├── helper.js │ │ ├── login.js │ │ ├── logout.js │ │ ├── part1App.js │ │ └── register.js │ └── static │ │ ├── form.css │ │ ├── recipe.css │ │ └── site.css │ ├── 03. JS-Applications-Data-and-Authentication-Lab.docx │ └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ └── server.js ├── 04 SPA ├── Exercise │ ├── 01.Forum │ │ ├── index.html │ │ ├── src │ │ │ ├── app.js │ │ │ ├── display.js │ │ │ ├── helper.js │ │ │ └── requests.js │ │ └── static │ │ │ ├── layout.css │ │ │ ├── new-theme.css │ │ │ ├── new-topic.css │ │ │ ├── profile.png │ │ │ ├── reset.css │ │ │ ├── responsive.css │ │ │ ├── style.css │ │ │ ├── theme-content.css │ │ │ ├── topic-content.css │ │ │ └── typography.css │ ├── 02.Movies │ │ ├── components │ │ │ ├── addMovieBtn.js │ │ │ ├── footer.js │ │ │ ├── movieComponent.js │ │ │ └── navBarComponent.js │ │ ├── index.html │ │ ├── src │ │ │ ├── app.js │ │ │ ├── createPageLayout.js │ │ │ ├── helper.js │ │ │ └── requests.js │ │ ├── static │ │ │ ├── css │ │ │ │ └── site.css │ │ │ └── favicon.ico │ │ └── views │ │ │ ├── addMovieView.js │ │ │ ├── editMovieView.js │ │ │ ├── homePageView.js │ │ │ ├── loginView.js │ │ │ ├── movieDetailsView.js │ │ │ └── registerView.js │ ├── 04. JS-Applications-Single-Page-Applications-Exercise.docx │ └── server │ │ ├── data │ │ ├── advanced.json │ │ ├── blog.json │ │ ├── bus.json │ │ ├── collections.json │ │ ├── cookbook.json │ │ ├── forecaster.json │ │ ├── messenger.json │ │ └── phonebook.json │ │ └── server.js └── Lab │ ├── 01.Calendar │ ├── index.html │ ├── src │ │ ├── app.js │ │ ├── displays.js │ │ └── helper.js │ └── style.css │ ├── 02 Cookbook Pt. 3 │ ├── assets │ │ ├── fish.jpg │ │ ├── lasagna.jpg │ │ └── roast.jpg │ ├── index.html │ ├── src │ │ ├── app.js │ │ ├── catalog.js │ │ ├── create.js │ │ ├── details.js │ │ ├── dom.js │ │ ├── edit.js │ │ ├── login.js │ │ └── register.js │ ├── static │ │ ├── form.css │ │ ├── recipe.css │ │ └── site.css │ └── tests │ │ ├── e2e.test.js │ │ └── mock-data.json │ ├── 04. JS-Applications-Single-Page-Applications-Lab.docx │ └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ └── server.js ├── 05 Architecture and Testing ├── Exercise │ ├── 01.Messenger │ │ ├── app.js │ │ ├── index.html │ │ ├── styles.css │ │ └── tests │ │ │ ├── e2e.test.js │ │ │ └── mockData.json │ ├── 02.Book-Library │ │ ├── app.js │ │ ├── e2e.test.js │ │ ├── index.html │ │ ├── mockData.json │ │ └── styles.css │ ├── 03.SoftTerest │ │ ├── .idea │ │ │ ├── .gitignore │ │ │ ├── 03.SoftTerest.iml │ │ │ ├── modules.xml │ │ │ └── vcs.xml │ │ ├── Components │ │ │ ├── Footer.js │ │ │ ├── Header.js │ │ │ ├── Notif.js │ │ │ └── PageLayout.js │ │ ├── Readme.md │ │ ├── Views │ │ │ ├── CreateIdeaView.js │ │ │ ├── DashboardView.js │ │ │ ├── DetailsView.js │ │ │ ├── HomeView.js │ │ │ ├── LoginView.js │ │ │ └── RegisterView.js │ │ ├── images │ │ │ ├── 01.svg │ │ │ ├── White-Abstract-Backgrounds-Gallery-47-Plus-PIC-WPW404836.jpg │ │ │ ├── best-pilates-youtube-workouts-2__medium_4x3.jpg │ │ │ ├── brightideacropped.jpg │ │ │ ├── creativity_painted_face.jpg │ │ │ ├── dinner.jpg │ │ │ └── idea.png │ │ ├── index.html │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── requests │ │ │ ├── backendAPI.js │ │ │ └── requests.js │ │ ├── server │ │ │ ├── data │ │ │ │ ├── advanced.json │ │ │ │ ├── blog.json │ │ │ │ ├── bus.json │ │ │ │ ├── collections.json │ │ │ │ ├── cookbook.json │ │ │ │ ├── forecaster.json │ │ │ │ ├── messenger.json │ │ │ │ └── phonebook.json │ │ │ └── server.js │ │ ├── src │ │ │ ├── app.js │ │ │ ├── contextAPI.js │ │ │ └── helper.js │ │ ├── styles │ │ │ ├── common.css │ │ │ ├── dashboard.css │ │ │ ├── home.css │ │ │ ├── ideas.css │ │ │ ├── login.css │ │ │ └── style.css │ │ └── tests │ │ │ ├── e2e.test.js │ │ │ └── mock-data.json │ ├── 05. JS-Applications-Architecture-and-Testing-Exercise.docx │ └── server │ │ ├── data │ │ ├── advanced.json │ │ ├── blog.json │ │ ├── bus.json │ │ ├── collections.json │ │ ├── cookbook.json │ │ ├── forecaster.json │ │ ├── messenger.json │ │ └── phonebook.json │ │ └── server.js └── Lab │ ├── 01. Accordion │ ├── accordion.css │ ├── accordion.js │ └── index.html │ ├── 05. JS-Applications-Architecture-and-Testing-Lab.docx │ └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ └── server.js ├── 06 Client Side Rendering (aka Templating) └── Exercise │ ├── 01.List-Towns │ ├── app.js │ ├── index.html │ ├── style.css │ └── templates.js │ ├── 02.HTTP-Status-Cats │ ├── app.js │ ├── catSeeder.js │ ├── example.html │ ├── images │ │ ├── cat100.jpg │ │ ├── cat200.jpg │ │ ├── cat204.jpg │ │ ├── cat301.jpg │ │ ├── cat304.jpg │ │ ├── cat400.jpg │ │ ├── cat404.jpg │ │ ├── cat406.jpg │ │ ├── cat410.jpg │ │ ├── cat500.jpg │ │ └── cat511.jpg │ ├── index.html │ ├── style.css │ └── templates.js │ ├── 03.Search-in-List │ ├── example.html │ ├── index.html │ ├── list.css │ ├── search.js │ ├── template.js │ └── towns.js │ ├── 04.Fill-Dropdown │ ├── filldropdown.css │ ├── index.html │ └── src │ │ ├── dropdown.js │ │ ├── requests.js │ │ └── templates.js │ ├── 05.Table-Search │ ├── example.html │ ├── index.html │ ├── solution.js │ ├── table.css │ └── templates.js │ ├── 06. JS-Applications-Client-Side-Rendering-Exercise.docx │ ├── 06.Book-Library │ ├── example.html │ ├── index.html │ ├── src │ │ ├── app.js │ │ ├── backendAPI.js │ │ ├── helper.js │ │ ├── requests.js │ │ └── templates.js │ └── styles.css │ └── server │ ├── data │ ├── advanced.json │ ├── blog.json │ ├── bus.json │ ├── collections.json │ ├── cookbook.json │ ├── forecaster.json │ ├── messenger.json │ └── phonebook.json │ └── server.js ├── 07 Routing └── Furniture │ ├── 07. JS-Applications-Routing-Execise.docx │ ├── Components │ ├── FurnitureCard.js │ ├── Header.js │ ├── NavLink.js │ └── PageLayout.js │ ├── Readme.md │ ├── Views │ ├── Catalog.js │ ├── Create.js │ ├── Dashboard.js │ ├── Details.js │ ├── Edit.js │ ├── Login.js │ └── Register.js │ ├── controllers │ ├── furnitureFormsController.js │ └── userFormsController.js │ ├── images │ ├── chair.jpg │ ├── sofa.jpg │ └── table.png │ ├── index.html │ ├── requests │ ├── backendAPI.js │ └── requests.js │ ├── server │ ├── data │ │ ├── advanced.json │ │ ├── blog.json │ │ ├── bus.json │ │ ├── collections.json │ │ ├── cookbook.json │ │ ├── forecaster.json │ │ ├── messenger.json │ │ └── phonebook.json │ └── server.js │ ├── src │ ├── app.js │ ├── contextAPI.js │ └── helper.js │ └── static │ └── style.css ├── 08 Modular Applications └── TeamManager │ ├── .idea │ └── vcs.xml │ ├── Components │ ├── Footer.js │ ├── Header.js │ └── PageLayout.js │ ├── README.md │ ├── Team manager task.docx │ ├── Views │ ├── BrowseView.js │ ├── CreateView.js │ ├── DetailsView.js │ ├── EditView.js │ ├── HomeView.js │ ├── LoginView.js │ ├── MyTeams.js │ └── RegisterView.js │ ├── assets │ ├── atat.png │ ├── hydrant.png │ ├── rocket.png │ └── team.png │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── requests │ ├── backendAPI.js │ └── requests.js │ ├── server │ ├── data │ │ ├── advanced.json │ │ ├── blog.json │ │ ├── bus.json │ │ ├── collections.json │ │ ├── cookbook.json │ │ ├── forecaster.json │ │ ├── messenger.json │ │ └── phonebook.json │ └── server.js │ ├── src │ ├── app.js │ ├── contextAPI.js │ └── helper.js │ ├── static │ ├── layout.css │ ├── modal.css │ └── site.css │ └── styles.css ├── 09 Exam Prep └── MemeLounge │ ├── .idea │ └── vcs.xml │ ├── Components │ ├── Footer.js │ ├── Header.js │ ├── Notif.js │ └── PageLayout.js │ ├── Meme-Longue_Условие.docx │ ├── Readme.md │ ├── Views │ ├── AllMemesView.js │ ├── CreateView.js │ ├── DetailsView.js │ ├── EditView.js │ ├── GuestHomeView.js │ ├── LoginView.js │ ├── RegisterView.js │ └── UserProfileView.js │ ├── images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 6.png │ ├── female.png │ ├── male.png │ └── welcome-meme.jpg │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── requests │ ├── backendAPI.js │ └── requests.js │ ├── server │ └── server.js │ ├── src │ ├── app.js │ ├── contextAPI.js │ └── helper.js │ ├── style │ ├── footer.css │ ├── login-register.css │ ├── meme-details.css │ ├── meme-feed.css │ ├── my-memes.css │ ├── navigation.css │ ├── notifications.css │ ├── site.css │ ├── styles.css │ ├── user-profile.css │ └── welcome.css │ └── tests │ ├── e2e.test.js │ └── mock-data.json ├── 10 Exam Prep 2 └── CarTube │ ├── CarTube_Условие.docx │ ├── Components │ ├── Footer.js │ ├── Header.js │ ├── Listing.js │ ├── Notif.js │ └── PageLayout.js │ ├── Readme.md │ ├── Views │ ├── AllListingsView.js │ ├── ByYearView.js │ ├── CreateListingView.js │ ├── DetailsView.js │ ├── EditView.js │ ├── HomePageView.js │ ├── LoginView.js │ ├── MyListingsView.js │ └── RegisterView.js │ ├── images │ ├── audia3.jpg │ ├── benz.jpg │ ├── bmw.jpg │ └── car-png.webp │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── requests │ ├── backendAPI.js │ └── requests.js │ ├── server │ └── server.js │ ├── src │ ├── app.js │ ├── contextAPI.js │ └── helper.js │ ├── style │ ├── car-listings.css │ ├── listing-details.css │ ├── login-register.css │ ├── navigation.css │ ├── search.css │ ├── site.css │ ├── styles.css │ └── welcome.css │ └── tests │ ├── e2e.test.js │ └── mock-data.json ├── README.md ├── applications_javascript.png ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /test.js 3 | /exam/ 4 | /08 Modular Applications/Exercise/node_modules/ 5 | /08 Modular Applications/Team Manager/node_modules/ 6 | /09 Exam Prep/MemeLounge/node_modules/ 7 | /05 Architecture and Testing/Exercise/03.SoftTerest/node_modules/ 8 | /10 Exam Prep 2/node_modules/ 9 | /10 Exam Prep 2/.idea/ 10 | /10 Exam Prep 2/CarTube/.idea/ 11 | /10 Exam Prep 2/CarTube/node_modules/ 12 | /07 Routing/Furniture/.idea/ 13 | /08 Modular Applications/TeamManager/.idea/ 14 | /09 Exam Prep/MemeLounge/.idea/ 15 | -------------------------------------------------------------------------------- /.idea/JS Applications.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /01 Rest Services and AJAX/01. JS-Applications-HTTP-and-REST-Services-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/01 Rest Services and AJAX/01. JS-Applications-HTTP-and-REST-Services-Exercise.docx -------------------------------------------------------------------------------- /01 Rest Services and AJAX/01. restCountries.txt: -------------------------------------------------------------------------------- 1 | - manual GET about bulgaria 2 | 3 | GET /rest/v2/name/Bulgaria HTTP/1.1 4 | Host: https://restcountries.eu -------------------------------------------------------------------------------- /01 Rest Services and AJAX/server/data/collections.json: -------------------------------------------------------------------------------- 1 | { 2 | "books": {}, 3 | "students": {}, 4 | "myboard": { 5 | "posts": {}, 6 | "comments": {} 7 | } 8 | } -------------------------------------------------------------------------------- /01 Rest Services and AJAX/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "messenger": { 3 | "-LxHVtajG3N1sU714pVj": { 4 | "author": "Spami", 5 | "content": "Hello, are you there?" 6 | }, 7 | "-LxIDxC-GotWtf4eHwV8": { 8 | "author": "Garry", 9 | "content": "Yep, whats up :?" 10 | }, 11 | "-LxIDxPfhsNipDrOQ5g_": { 12 | "author": "Spami", 13 | "content": "How are you? Long time no see? :)" 14 | }, 15 | "-LxIE-dM_msaz1O9MouM": { 16 | "author": "George", 17 | "content": "Hello, guys! :))" 18 | }, 19 | "-LxLgX_nOIiuvbwmxt8w": { 20 | "author": "Spami", 21 | "content": "Hello, George nice to see you! :)))" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /01 Rest Services and AJAX/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "phonebook": { 3 | "i1": { 4 | "person": "Maya", 5 | "phone": "+1-555-7653" 6 | }, 7 | "i2": { 8 | "person": "John", 9 | "phone": "+1-555-4986" 10 | }, 11 | "i3": { 12 | "person": "Nicolle", 13 | "phone": "+1-555-9124" 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /01 Rest Services and AJAX/server/start.bat: -------------------------------------------------------------------------------- 1 | node server.js -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/01.Bus-Stop/app.js: -------------------------------------------------------------------------------- 1 | async function getInfo () { 2 | const html = { 3 | stopName: document.getElementById(`stopName`), 4 | busses: document.getElementById(`buses`), 5 | stopID: document.getElementById(`stopId`) 6 | } 7 | 8 | html.stopName.innerHTML = '' 9 | html.busses.innerHTML = '' 10 | 11 | try { 12 | const data = await fetch(`http://localhost:3030/jsonstore/bus/businfo/${html.stopID.value}/1`) 13 | if (! data.ok) throw new Error() 14 | const deserialized = await data.json() 15 | 16 | html.stopName.innerHTML = deserialized.name 17 | Object.entries(deserialized.buses).forEach(([bus, time]) => { 18 | const e = document.createElement('li') 19 | e.innerHTML = `Bus ${bus} arrives in ${time}` 20 | 21 | html.busses.appendChild(e) 22 | }) 23 | 24 | } catch (e) { 25 | html.stopName.innerHTML = 'Error' 26 | } 27 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/01.Bus-Stop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bus Stop 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 |
18 | 19 |
20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/01.Bus-Stop/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | input[type=text] { 3 | padding: 12px 20px; 4 | margin: 8px 0; 5 | display: inline-block; 6 | border: 1px solid #ccc; 7 | border-radius: 4px; 8 | box-sizing: border-box; 9 | } 10 | input[type=button] { 11 | background-color: #4CAF50; 12 | color: white; 13 | padding: 10px 16px; 14 | border: none; 15 | border-radius: 4px; 16 | cursor: pointer; 17 | } 18 | input[type=button]:hover { 19 | background-color: #45a049; 20 | } 21 | body { 22 | margin: auto; 23 | width: 25%; 24 | text-align: center; 25 | padding: 20px; 26 | font-family: 'Open Sans', serif; 27 | } 28 | #stopName { 29 | font-size: 1.5em; 30 | margin: 8px 0; 31 | font-weight: 400; 32 | padding: 0.25em; 33 | border-radius: 4px; 34 | background-color: aquamarine; 35 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/02. JS-Applications-Asynchronous-Programming-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Exercise/02. JS-Applications-Asynchronous-Programming-Exercise.docx -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/02.Bus-Schedule/app.js: -------------------------------------------------------------------------------- 1 | function solve () { 2 | const html = { 3 | info: document.getElementById(`info`), 4 | depart: document.getElementById(`depart`), 5 | arrive: document.getElementById(`arrive`), 6 | } 7 | 8 | const getStop = async (name) => { 9 | try { 10 | const stop = await fetch(`http://localhost:3030/jsonstore/bus/schedule/${name}`) 11 | 12 | return await stop.json() 13 | } catch (e) { 14 | html.info.innerHTML = 'Error' 15 | html.arrive.disabled = true 16 | html.depart.disabled = true 17 | } 18 | } 19 | let nextStop 20 | let nextStopName = 'depot' 21 | 22 | 23 | async function depart () { 24 | html.depart.disabled = true 25 | html.arrive.disabled = false 26 | nextStop = await getStop(nextStopName) 27 | html.info.innerHTML = `Next stop ${nextStop.name}` 28 | } 29 | 30 | function arrive () { 31 | html.depart.disabled = false 32 | html.arrive.disabled = true 33 | 34 | html.info.innerHTML = `Arriving at ${nextStop.name}` 35 | nextStopName = nextStop.next 36 | } 37 | 38 | return { 39 | depart, 40 | arrive 41 | } 42 | } 43 | 44 | let result = solve() -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/02.Bus-Schedule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Bus Schedule 7 | 8 | 9 | 10 | 11 |
12 |
Not Connected
13 |
14 | 15 | 16 |
17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/02.Bus-Schedule/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | input[type=text] { 3 | padding: 12px 20px; 4 | margin: 8px 0; 5 | display: inline-block; 6 | border: 1px solid #ccc; 7 | border-radius: 4px; 8 | box-sizing: border-box; 9 | } 10 | input[type=button] { 11 | padding: 10px 16px; 12 | border: none; 13 | border-radius: 4px; 14 | cursor: pointer; 15 | } 16 | body { 17 | margin: auto; 18 | width: 25%; 19 | text-align: center; 20 | padding: 20px; 21 | font-family: 'Open Sans', serif; 22 | } 23 | #schedule { 24 | text-align: center; 25 | width: 400px; 26 | } 27 | input { 28 | width: 120px; 29 | } 30 | #info { 31 | background-color: aquamarine; 32 | border: 1px none black; 33 | border-radius: 4px; 34 | margin: 0.25em; 35 | } 36 | .info { 37 | font-size: 1.5em; 38 | padding: 0.25em; 39 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/03.Forecaster/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Forecaster 7 | 8 | 9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/03.Forecaster/styles.css: -------------------------------------------------------------------------------- 1 | #content { 2 | width: 75%; 3 | margin: 0 auto; 4 | } 5 | 6 | div.forecasts { 7 | display: inline-block; 8 | width: 30%; 9 | border: 1px solid aquamarine; 10 | border-radius: 4px; 11 | margin: 2% 2% 0.5% 0.5%; 12 | } 13 | 14 | div.forecast-info { 15 | border: 1px solid aquamarine; 16 | border-radius: 4px; 17 | margin-bottom: 1%; 18 | } 19 | 20 | #request { 21 | text-align: center; 22 | } 23 | 24 | .bl { 25 | width: 300px; 26 | } 27 | 28 | #current { 29 | text-align: center; 30 | font-size: 2em; 31 | } 32 | 33 | #upcoming { 34 | text-align: center; 35 | } 36 | 37 | .condition { 38 | text-align: left; 39 | display: inline-block; 40 | } 41 | 42 | .symbol { 43 | font-size: 4em; 44 | display: inline-block; 45 | } 46 | 47 | .forecast-data { 48 | display: block; 49 | } 50 | 51 | .upcoming { 52 | display: inline-block; 53 | margin: 1.5em; 54 | } 55 | 56 | .label { 57 | margin-top: 1em; 58 | font-size: 1.5em; 59 | background-color: aquamarine; 60 | font-weight: 400; 61 | } 62 | 63 | input { 64 | padding: 10px 12px; 65 | margin: 5px 0; 66 | display: inline-block; 67 | border: 1px solid #ccc; 68 | border-radius: 4px; 69 | } 70 | 71 | input[type=button] { 72 | background-color: aquamarine; 73 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/04.Locked-Profile/iconProfile2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Exercise/04.Locked-Profile/iconProfile2.png -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/04.Locked-Profile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Locked Profile 7 | 8 | 9 | 10 |
11 |
12 | 13 |
14 | 15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 |
23 |
24 | 25 | 26 | 27 | 28 |
29 | 30 |
31 | 32 |
33 |
34 | 35 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/05. Accordion/02. Accordion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Exercise/05. Accordion/02. Accordion.gif -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/05. Accordion/accordion.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Poppins"); 2 | 3 | body { 4 | font-family: "Poppins", sans-serif; 5 | } 6 | 7 | .accordion { 8 | border: 2px solid #cdc7c7; 9 | display: inline-block; 10 | width: 40%; 11 | font-size: 1.3rem; 12 | } 13 | 14 | .accordion p { 15 | margin: 1em; 16 | } 17 | 18 | .button { 19 | float: right; 20 | background: #393636; 21 | padding: 0.1em 1em 0.1em 1em; 22 | color: white; 23 | cursor: pointer; 24 | text-transform: uppercase; 25 | font-weight: bold; 26 | letter-spacing: 3px; 27 | } 28 | 29 | .extra { 30 | display: none; 31 | } 32 | 33 | .head { 34 | background: #ccccff; 35 | padding: 1em; 36 | } 37 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/05. Accordion/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Accordion 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/06.Blog/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Blog 7 | 8 | 9 | 10 | 11 |

All Posts

12 | 13 | 14 | 15 |

Post Details

16 | 17 |

Comments

18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/06.Blog/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | body { 3 | font-family: 'Open Sans', serif; 4 | } 5 | select { 6 | padding: 10px 15px; 7 | margin: 8px 0; 8 | display: inline-block; 9 | border: 1px solid #ccc; 10 | border-radius: 4px; 11 | } 12 | button { 13 | background-color: #4CAF50; 14 | color: white; 15 | padding: 10px 15px; 16 | margin: 8px 0; 17 | border: none; 18 | border-radius: 4px; 19 | cursor: pointer; 20 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/server/data/collections.json: -------------------------------------------------------------------------------- 1 | { 2 | "books": {}, 3 | "students": {}, 4 | "myboard": { 5 | "posts": {}, 6 | "comments": {} 7 | } 8 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "i1": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653" 5 | }, 6 | "i2": { 7 | "person": "John", 8 | "phone": "+1-555-4986" 9 | }, 10 | "i3": { 11 | "person": "Nicolle", 12 | "phone": "+1-555-9124" 13 | } 14 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Exercise/server/start.bat: -------------------------------------------------------------------------------- 1 | node server.js -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/01.XHR/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Document 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/01.XHR/scripts/app.js: -------------------------------------------------------------------------------- 1 | function loadRepos() { 2 | // this task is a copy paste of the presentation, not gonna waste 3 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/01.XHR/styles/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | body { 3 | font-family: "Open Sans", serif; 4 | } 5 | button { 6 | background-color: #4caf50; 7 | color: white; 8 | padding: 14px 20px; 9 | margin: 8px 0; 10 | border: none; 11 | border-radius: 4px; 12 | cursor: pointer; 13 | } 14 | button:hover { 15 | background-color: #45a049; 16 | } 17 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/02. JS-Applications-Asynchronous-Programming-Lab.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Lab/02. JS-Applications-Asynchronous-Programming-Lab.docx -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/02.Github-Repos/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Document 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/02.Github-Repos/scripts/app.js: -------------------------------------------------------------------------------- 1 | async function loadRepos () { 2 | const html = { 3 | nameField: document.getElementById(`username`), 4 | resultE: document.getElementById(`repos`), 5 | } 6 | 7 | const data = await fetch(`https://api.github.com/users/${html.nameField.value}/repos`) 8 | const deserilized = await data.json() 9 | 10 | html.resultE.innerHTML = '' 11 | 12 | deserilized.forEach(({ full_name, html_url }) => { 13 | const li = document.createElement('li') 14 | const a = document.createElement('a') 15 | a.innerHTML = full_name 16 | a.href = html_url 17 | 18 | li.appendChild(a) 19 | html.resultE.appendChild(li) 20 | }) 21 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/02.Github-Repos/styles/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | body { 3 | font-family: "Open Sans", serif; 4 | } 5 | button { 6 | background-color: #4caf50; 7 | color: white; 8 | padding: 14px 20px; 9 | margin: 8px 0; 10 | border: none; 11 | border-radius: 4px; 12 | cursor: pointer; 13 | } 14 | input[type=text] { 15 | padding: 12px 20px; 16 | margin: 8px 0; 17 | display: inline-block; 18 | border: 1px solid #ccc; 19 | border-radius: 4px; 20 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/03.Gighub-Commits/app.js: -------------------------------------------------------------------------------- 1 | async function loadCommits () { 2 | const html = { 3 | nameField: document.getElementById(`username`), 4 | repoField: document.getElementById(`repo`), 5 | resultE: document.getElementById(`commits`), 6 | } 7 | 8 | html.resultE.innerHTML = '' 9 | 10 | const eFactory = (tag, content = '') => { 11 | const e = document.createElement(tag) 12 | e.innerHTML = content 13 | 14 | return e 15 | } 16 | 17 | try { 18 | const data = await fetch(`https://api.github.com/repos/${html.nameField.value}/${html.repoField.value}/commits`) 19 | 20 | if (! data.ok) throw new Error(`${data.status} (${data.statusText})`) 21 | 22 | const deserialized = await data.json() 23 | 24 | deserialized.forEach(({ commit }) => html.resultE.appendChild(eFactory( 25 | 'li', 26 | `${commit.author.name}: ${commit.message}` 27 | ))) 28 | 29 | } catch (e) { 30 | html.resultE.appendChild(eFactory('li', e)) 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/03.Gighub-Commits/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Github Commits 7 | 8 | 9 | 10 | 11 | GitHub username: 12 |
13 | Repo: 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/03.Gighub-Commits/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | body { 3 | font-family: "Open Sans", serif; 4 | } 5 | input[type=text] { 6 | padding: 5px 10px; 7 | margin: 8px 0; 8 | display: inline-block; 9 | border: 1px solid #ccc; 10 | border-radius: 4px; 11 | } 12 | button { 13 | background-color: #4caf50; 14 | color: white; 15 | padding: 10px 14px; 16 | margin: 8px 0; 17 | border: none; 18 | border-radius: 4px; 19 | cursor: pointer; 20 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/fish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/fish.jpg -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/lasagna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/lasagna.jpg -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/roast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/assets/roast.jpg -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/04. Cookbook pt.1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Cookbook 7 | 8 | 9 | 10 | 11 | 12 |

My Cookbook

13 |
14 |

Loading...

15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/server/data/collections.json: -------------------------------------------------------------------------------- 1 | { 2 | "books": {}, 3 | "students": {}, 4 | "myboard": { 5 | "posts": {}, 6 | "comments": {} 7 | } 8 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "i1": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653" 5 | }, 6 | "i2": { 7 | "person": "John", 8 | "phone": "+1-555-4986" 9 | }, 10 | "i3": { 11 | "person": "Nicolle", 12 | "phone": "+1-555-9124" 13 | } 14 | } -------------------------------------------------------------------------------- /02. Asynchronous Programming and Promises/Lab/server/start.bat: -------------------------------------------------------------------------------- 1 | node server.js -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/01.Messenger/app.js: -------------------------------------------------------------------------------- 1 | function attachEvents () { 2 | const url = 'http://localhost:3030/jsonstore/messenger' 3 | 4 | const clearInputs = (arr) => arr.forEach(x => x.value = '') 5 | 6 | document.getElementById(`submit`).addEventListener('click', async () => { 7 | const author = document.querySelector('#controls > input[type=text]:nth-child(2)') 8 | const content = document.querySelector('#controls > input[type=text]:nth-child(5)') 9 | const rawData = { author: author.value, content: content.value } 10 | 11 | const response = await fetch(url, { 12 | method: 'post', 13 | headers: { 'Content-Type': 'application/json' }, 14 | body: JSON.stringify(rawData) 15 | }) 16 | 17 | clearInputs([author, content]) 18 | 19 | return response 20 | }) 21 | 22 | document.getElementById('refresh').addEventListener('click', async () => { 23 | const data = await fetch(url) 24 | const deserialized = await data.json() 25 | 26 | console.log(deserialized) 27 | document.getElementById(`messages`).innerHTML = 28 | Object.values(deserialized).map(x => `${x.author}: ${x.content}`).join('\n') 29 | }) 30 | } 31 | 32 | attachEvents() -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/01.Messenger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Messenger 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/01.Messenger/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | input[type=text] { 3 | padding: 12px 20px; 4 | margin: 8px 0; 5 | display: inline-block; 6 | border: 1px solid #ccc; 7 | border-radius: 4px; 8 | box-sizing: border-box; 9 | } 10 | input[type=button] { 11 | background-color: #4CAF50; 12 | color: white; 13 | padding: 10px 16px; 14 | border: none; 15 | border-radius: 4px; 16 | cursor: pointer; 17 | display: block; 18 | } 19 | input[type=button]:hover { 20 | background-color: #45a049; 21 | } 22 | body { 23 | margin: auto; 24 | text-align: center; 25 | padding: 20px; 26 | font-family: 'Open Sans', serif; 27 | } 28 | label { 29 | display: inline-block; 30 | width: 5em; 31 | } 32 | #author, 33 | #content { 34 | width: 30em; 35 | } 36 | #controls { 37 | width: 38em; 38 | } 39 | #submit, #refresh { 40 | display: inline-block; 41 | } 42 | #submit { 43 | margin: 32px; 44 | } 45 | 46 | #main{ 47 | width: 50%; 48 | margin: 0 auto; 49 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/02.Phonebook/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Phonebook 7 | 8 | 9 | 10 | 11 |

Phonebook

12 | 13 | 14 | 15 |

Create Contact

16 | Person: 17 |
18 | Phone: 19 |
20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/02.Phonebook/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | input[type=text] { 3 | 4 | padding: 12px 20px; 5 | margin: 8px 0; 6 | display: inline-block; 7 | border: 1px solid #ccc; 8 | border-radius: 4px; 9 | box-sizing: border-box; 10 | } 11 | 12 | button { 13 | background-color: #4CAF50; 14 | color: white; 15 | padding: 14px 20px; 16 | margin: 8px 0; 17 | border: none; 18 | border-radius: 4px; 19 | cursor: pointer; 20 | } 21 | 22 | button:hover { 23 | background-color: #45a049; 24 | } 25 | 26 | body{ 27 | font-family: 'Open Sans',serif; 28 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/03. JS-Applications-Data-and-Authentication-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/03 Remote Data and Authentication/Exercise/03. JS-Applications-Data-and-Authentication-Exercise.docx -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/04.Book-library/src/createFunctionality.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from './helper.js' 2 | import { postBook } from './requests.js' 3 | 4 | function createBookElement ({ author, title, id }) { 5 | const tr = document.createElement('tr') 6 | tr.id = id 7 | const btnTd = document.createElement('td') 8 | const delBtn = eFactory('button', 'Delete', 'deleteBook') 9 | const editBtn = eFactory('button', 'Edit', 'editBook') 10 | const data = [title, author].map(x => eFactory('td', x)) 11 | 12 | btnTd.append(editBtn, delBtn) 13 | tr.append(...data, btnTd) 14 | 15 | return tr 16 | } 17 | 18 | async function createBook (formData) { 19 | if (Object.values(formData).every(x => x !== '')) { 20 | await postBook(formData) 21 | } 22 | } 23 | 24 | export { createBook, createBookElement } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/04.Book-library/src/editFunctionality.js: -------------------------------------------------------------------------------- 1 | import { updateBookRequest, getBook, } from './requests.js' 2 | import { displayForm, } from './helper.js' 3 | 4 | async function displayEditForm (id, submitForm, editForm) { 5 | const bookData = await getBook(id) 6 | const inputs = [...editForm.children].filter(x => x.tagName === 'INPUT') 7 | 8 | displayForm(editForm, submitForm) 9 | 10 | inputs[0].value = bookData.title 11 | inputs[1].value = bookData.author 12 | 13 | sessionStorage.setItem('editID', id) 14 | } 15 | 16 | async function updateBook (e, data, submitForm, editForm) { 17 | await updateBookRequest(sessionStorage.getItem('editID'), data) 18 | displayForm(submitForm, editForm) 19 | } 20 | 21 | export { displayEditForm, updateBook } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/04.Book-library/src/helper.js: -------------------------------------------------------------------------------- 1 | function displayForm (form, form1) { 2 | form.style.display = 'block' 3 | form1.style.display = 'none' 4 | } 5 | 6 | function getFormData (form) { 7 | const formData = new FormData(form) 8 | 9 | return Object.fromEntries([...formData.entries()]) 10 | } 11 | 12 | function clearFields (form) { 13 | [...form.children].filter(x => x.tagName === 'INPUT').map(x => x.value = '') 14 | } 15 | 16 | function eFactory (tag, content = ' ', className = '') { 17 | const e = document.createElement(tag) 18 | e.innerHTML = content 19 | e.className = className 20 | 21 | return e 22 | } 23 | 24 | export { displayForm, getFormData, clearFields, eFactory } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/04.Book-library/src/requests.js: -------------------------------------------------------------------------------- 1 | async function getBooks () { 2 | const response = await fetch('http://localhost:3030/jsonstore/collections/books') 3 | 4 | return await response.json() 5 | } 6 | 7 | async function getBook (id) { 8 | const book = await fetch(`http://localhost:3030/jsonstore/collections/books/${id}`) 9 | 10 | return await book.json() 11 | } 12 | 13 | async function postBook (data) { 14 | const response = await fetch('http://localhost:3030/jsonstore/collections/books', { 15 | method: 'post', 16 | headers: { 'Content-Type': 'application/json' }, 17 | body: JSON.stringify(data) 18 | }) 19 | 20 | const result = await response.json() 21 | } 22 | 23 | async function removeBook (id) { 24 | const response = await fetch(`http://localhost:3030/jsonstore/collections/books/${id}`, { 25 | method: 'delete' 26 | }) 27 | 28 | return response.json() 29 | } 30 | 31 | async function updateBookRequest (id, data) { 32 | const ajax = await fetch(`http://localhost:3030/jsonstore/collections/books/${id}`, { 33 | method: 'PUT', 34 | headers: { 'Content-Type': 'application/json' }, 35 | body: JSON.stringify(data) 36 | }) 37 | 38 | return await ajax.json() 39 | } 40 | 41 | export { getBooks, getBook, postBook, removeBook, updateBookRequest } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/05.Fisher-Game/src/helper.js: -------------------------------------------------------------------------------- 1 | const getInputData = (parent) => [...parent.querySelectorAll('input')] 2 | const isOwner = (ownerId) => ownerId === sessionStorage.getItem('_id') 3 | const getCatchData = (parent) => 4 | getInputData(parent).reduce((a, v) => { 5 | a[v.className] = v.value 6 | return a 7 | }, {}) 8 | const isValidData = (parent) => getInputData(parent).every(x => x.value !== '') 9 | 10 | export { isOwner, getCatchData, isValidData } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/05.Fisher-Game/src/requests.js: -------------------------------------------------------------------------------- 1 | const baseUrl = 'http://localhost:3030/data/catches' 2 | 3 | async function getAllCatches () { 4 | const response = await fetch(baseUrl) 5 | 6 | return response.json() 7 | } 8 | 9 | async function createCatch (data) { 10 | const response = await fetch(baseUrl, { 11 | method: 'post', 12 | headers: { 13 | 'Content-Type': 'application/json', 14 | 'X-Authorization': sessionStorage.getItem('accessToken') 15 | }, 16 | body: JSON.stringify(data) 17 | }) 18 | const returnedData = await response.json() 19 | 20 | console.log(returnedData) 21 | } 22 | 23 | async function updateCatch (id, data) { 24 | const response = await fetch(`${baseUrl}/${id}`, { 25 | method: 'put', 26 | headers: { 27 | 'Content-Type': 'application/json', 28 | 'X-Authorization': sessionStorage.getItem('accessToken') 29 | }, 30 | body: JSON.stringify(data) 31 | }) 32 | const returnedData = await response.json() 33 | 34 | console.log(returnedData) 35 | } 36 | 37 | async function deleteCatch (id) { 38 | const response = await fetch(`${baseUrl}/${id}`, { 39 | method: 'delete', 40 | headers: { 41 | 'Content-Type': 'application/json', 42 | 'X-Authorization': sessionStorage.getItem('accessToken') 43 | } 44 | }) 45 | const returnedData = await response.json() 46 | 47 | console.log(returnedData) 48 | } 49 | 50 | export { createCatch, updateCatch, deleteCatch, getAllCatches } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/05.Fisher-Game/src/templates.js: -------------------------------------------------------------------------------- 1 | function catchTemplate ({ angler, weight, species, location, bait, captureTime, _id }, ownCatch) { 2 | const wrapper = document.createElement('div') 3 | wrapper.className = 'catch' 4 | wrapper.id = _id 5 | 6 | wrapper.innerHTML = ` 7 | 8 |
9 | 10 | 11 |
12 | 13 | 14 |
15 | 16 | 17 |
18 | 19 | 20 |
21 | 22 | 23 |
24 | 25 | ` 26 | 27 | return wrapper 28 | } 29 | 30 | export { catchTemplate } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/05.Fisher-Game/static/login.css: -------------------------------------------------------------------------------- 1 | form { 2 | padding: 32px; 3 | } 4 | 5 | label { 6 | display: block; 7 | position: relative; 8 | margin: 16px 0; 9 | text-align: right; 10 | padding-right: 520px; 11 | line-height: 48px; 12 | } 13 | 14 | input[type="text"], input[type="password"], textarea { 15 | position: absolute; 16 | right: 0px; 17 | width: 500px; 18 | padding: 8px; 19 | } 20 | 21 | textarea { 22 | height: 300px; 23 | resize: none; 24 | } 25 | 26 | .ml { 27 | height: 300px; 28 | } 29 | 30 | input[type="submit"] { 31 | display: block; 32 | border: none; 33 | margin: auto; 34 | background: #234465; 35 | color: white; 36 | padding: 8px 16px; 37 | text-decoration: none; 38 | font-size: 1.5rem; 39 | } 40 | 41 | input[type="submit"]:hover { 42 | background-color: #6c8b47; 43 | color: white; 44 | cursor: pointer; 45 | } 46 | 47 | button { 48 | width: 50%; 49 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/06.Furniture/src/requests.js: -------------------------------------------------------------------------------- 1 | async function register () { 2 | 3 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/userAuthFunctionality/helper.js: -------------------------------------------------------------------------------- 1 | const deserializeFormData = (form) => Object.fromEntries([...new FormData(form).entries()]) 2 | 3 | const redirect = (oldURI, newURI) => 4 | window.location.replace(window.location.pathname.replace(oldURI, newURI)) 5 | 6 | const displayMsg = (msg, output) => output ? output.innerHTML = msg : alert(msg) 7 | 8 | export { deserializeFormData, redirect, displayMsg } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/userAuthFunctionality/login.js: -------------------------------------------------------------------------------- 1 | import { deserializeFormData, redirect } from './helper.js' 2 | 3 | async function login (url, data) { 4 | 5 | const response = await fetch(url, { 6 | method: 'post', 7 | 'Content-Type': 'application/json', 8 | body: JSON.stringify(data) 9 | }) 10 | 11 | if (response.ok) { 12 | const user = await response.json() 13 | console.log(user) 14 | 15 | sessionStorage.setItem('accessToken', user.accessToken) 16 | sessionStorage.setItem('_id', user._id) 17 | } 18 | } 19 | 20 | document.addEventListener('DOMContentLoaded', () => { 21 | document.getElementById('login').addEventListener('submit', async e => { 22 | e.preventDefault() 23 | const data = deserializeFormData(e.target) 24 | 25 | await login(`http://localhost:3030/users/login`, data) 26 | redirect('login.html', 'index.html') 27 | }) 28 | }) 29 | 30 | export { login } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Exercise/userAuthFunctionality/register.js: -------------------------------------------------------------------------------- 1 | import { login } from './login.js' 2 | import { displayMsg, deserializeFormData, redirect } from './helper.js' 3 | 4 | function validateFields (data, output) { 5 | 6 | if (data.email === '' || data.password === '') { 7 | displayMsg(output, 'Email and Password must not be empty!') 8 | return false 9 | } 10 | if (data.password !== data.rePass) { 11 | displayMsg(output, 'Passwords do not match!') 12 | return false 13 | } 14 | 15 | return true 16 | } 17 | 18 | document.addEventListener('DOMContentLoaded', () => { 19 | document.getElementById('register').addEventListener('submit', async e => { 20 | e.preventDefault() 21 | const data = deserializeFormData(e.target) 22 | 23 | if (validateFields(data)) { 24 | await login(`http://localhost:3030/users/register`, data) 25 | redirect('login.html', 'index.html') 26 | } 27 | }) 28 | }) -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/fish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/fish.jpg -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/lasagna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/lasagna.jpg -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/roast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/03 Remote Data and Authentication/Lab/01 Cookbook part 2/assets/roast.jpg -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/create.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Cookbook 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

My Cookbook

16 | 20 |
21 |
22 |
23 |

New Recipe

24 |
25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Cookbook 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |

My Cookbook

15 | 26 |
27 |
28 |

Loading...

29 |
30 | 31 | 32 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Cookbook 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

My Cookbook

16 | 21 |
22 |
23 |
24 |

Login

25 |
26 | 27 | 28 | 29 |
30 |
31 |
32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | My Cookbook 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |

My Cookbook

16 | 21 |
22 |
23 |
24 |

Register

25 |
26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/app.js: -------------------------------------------------------------------------------- 1 | import loadRecipes from './part1App.js' 2 | import logout from './logout.js' 3 | 4 | 5 | function displayHeader () { 6 | const header = { 7 | loggedIn: document.getElementById('user'), 8 | loggedOut: document.getElementById(`guest`), 9 | } 10 | const logoutBtn = document.getElementById('logoutBtn') 11 | 12 | if (sessionStorage.accessToken) { 13 | header.loggedIn.style.display = 'inline-block' 14 | header.loggedOut.style.display = 'none' 15 | logoutBtn.addEventListener('click', logout) 16 | } else { 17 | header.loggedIn.style.display = 'none' 18 | header.loggedOut.style.display = 'inline-block' 19 | logoutBtn.removeEventListener('click', logout) 20 | } 21 | } 22 | 23 | document.addEventListener( 24 | 'DOMContentLoaded', 25 | () => { 26 | displayHeader() 27 | 28 | if (sessionStorage.accessToken) { 29 | loadRecipes( 30 | 'http://localhost:3030/data/recipes?select=_id%2Cname%2Cimg', 31 | 'http://localhost:3030/data/recipes' 32 | ) 33 | } 34 | } 35 | ) 36 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/createRecipe.js: -------------------------------------------------------------------------------- 1 | import { deserializeFormData, redirect } from './helper.js' 2 | 3 | 4 | async function createRecipe ({ name, img, ingredients, preparation }, url) { 5 | const request = await fetch(url, { 6 | method: 'post', 7 | headers: { 8 | 'X-Authorization': sessionStorage.getItem('accessToken'), 9 | 'Content-Type': 'application/json', 10 | }, 11 | body: JSON.stringify({ name, img, ingredients, preparation }) 12 | }) 13 | 14 | console.log(await request.json()) 15 | } 16 | 17 | document.addEventListener('DOMContentLoaded', () => { 18 | document.getElementById('createRecipe').addEventListener('submit', async e => { 19 | e.preventDefault() 20 | const data = deserializeFormData(e.target) 21 | 22 | await createRecipe(data, 'http://localhost:3030/data/recipes') 23 | redirect('create.html', 'index.html') 24 | }) 25 | }) -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/helper.js: -------------------------------------------------------------------------------- 1 | const displayMsg = (msg, output) => output ? output.innerHTML = msg : alert(msg) 2 | const deserializeFormData = (form) => Object.fromEntries([...new FormData(form).entries()]) 3 | const redirect = (oldURI, newURI) => 4 | window.location.replace(window.location.pathname.replace(oldURI, newURI)) 5 | 6 | export { displayMsg, deserializeFormData, redirect } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/login.js: -------------------------------------------------------------------------------- 1 | import { deserializeFormData, redirect } from './helper.js' 2 | 3 | 4 | async function login (url, data) { 5 | 6 | const response = await fetch(url, { 7 | method: 'post', 8 | 'Content-Type': 'application/json', 9 | body: JSON.stringify(data) 10 | }) 11 | 12 | if (response.ok) { 13 | console.log(response) 14 | const user = await response.json() 15 | 16 | sessionStorage.setItem('accessToken', user.accessToken) 17 | } 18 | } 19 | 20 | document.addEventListener('DOMContentLoaded', () => { 21 | document.getElementById('login').addEventListener('submit', async e => { 22 | e.preventDefault() 23 | const data = deserializeFormData(e.target) 24 | 25 | await login(`http://localhost:3030/users/login`, data) 26 | redirect('login.html', 'index.html') 27 | }) 28 | }) 29 | 30 | export { login } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/logout.js: -------------------------------------------------------------------------------- 1 | async function logout () { 2 | await fetch('http://localhost:3030/users/logout', { 3 | method: 'get', 4 | headers: { 5 | 'X-Authorization': sessionStorage.accessToken 6 | } 7 | }) 8 | 9 | sessionStorage.clear() 10 | } 11 | 12 | export default logout -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/src/register.js: -------------------------------------------------------------------------------- 1 | import { login } from './login.js' 2 | import { displayMsg, deserializeFormData, redirect } from './helper.js' 3 | 4 | function validateFields (data, output) { 5 | 6 | if (data.email === '' || data.password === '') { 7 | displayMsg(output, 'Email and Password must not be empty!') 8 | return false 9 | } 10 | if (data.password !== data.rePass) { 11 | displayMsg(output, 'Passwords do not match!') 12 | return false 13 | } 14 | 15 | return true 16 | } 17 | 18 | document.addEventListener('DOMContentLoaded', () => { 19 | document.getElementById('register').addEventListener('submit', async e => { 20 | e.preventDefault() 21 | const data = deserializeFormData(e.target) 22 | 23 | if (validateFields(data)) { 24 | await login(`http://localhost:3030/users/register`, data) 25 | redirect('register.html', 'index.html') 26 | } 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/static/form.css: -------------------------------------------------------------------------------- 1 | form { 2 | padding: 32px; 3 | } 4 | 5 | label { 6 | display: block; 7 | position: relative; 8 | margin: 16px 0; 9 | text-align: right; 10 | padding-right: 520px; 11 | line-height: 48px; 12 | } 13 | 14 | input[type="text"], input[type="password"], textarea { 15 | position: absolute; 16 | right: 0px; 17 | width: 500px; 18 | padding: 8px; 19 | } 20 | 21 | textarea { 22 | height: 300px; 23 | resize: none; 24 | } 25 | 26 | .ml { 27 | height: 300px; 28 | } 29 | 30 | input[type="submit"] { 31 | display: block; 32 | border: none; 33 | margin: auto; 34 | background-color: salmon; 35 | padding: 8px 16px; 36 | text-decoration: none; 37 | color: black; 38 | } 39 | 40 | input[type="submit"]:hover { 41 | background-color: #6c8b47; 42 | color: white; 43 | cursor: pointer; 44 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/01 Cookbook part 2/static/site.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; 3 | font-size: 16pt; 4 | padding: 0; 5 | margin: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | width: 980px; 11 | margin: 0 auto 0 auto; 12 | } 13 | 14 | header { 15 | padding: 32px; 16 | background-color: #cccccc; 17 | position: relative; 18 | } 19 | 20 | h1 { 21 | font-size: 150%; 22 | display: inline; 23 | } 24 | 25 | main { 26 | background-color: #666666; 27 | padding: 32px; 28 | } 29 | 30 | nav { 31 | display: inline-block; 32 | position: absolute; 33 | right: 16px; 34 | text-align: right; 35 | } 36 | 37 | nav div { 38 | display: inline-block; 39 | } 40 | 41 | nav a { 42 | display: inline-block; 43 | background-color: salmon; 44 | padding: 8px 16px; 45 | margin: 0 8px; 46 | text-decoration: none; 47 | color: black; 48 | } 49 | 50 | nav a:hover { 51 | background-color: #6c8b47; 52 | color: white; 53 | } 54 | 55 | a.active { 56 | background-color: #6c8b47; 57 | color: white; 58 | } 59 | 60 | #user { 61 | display: none; 62 | } 63 | 64 | #guest { 65 | display: none; 66 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/03. JS-Applications-Data-and-Authentication-Lab.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/03 Remote Data and Authentication/Lab/03. JS-Applications-Data-and-Authentication-Lab.docx -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /03 Remote Data and Authentication/Lab/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/src/helper.js: -------------------------------------------------------------------------------- 1 | const isValidData = obj => Object.values(obj).every(x => x !== '') 2 | 3 | const clearFormFields = (form) => [...form.querySelectorAll('input, textarea')] 4 | .forEach(x => x.value = '') 5 | 6 | function eFactory (tag, className = '', content = '') { 7 | const e = document.createElement(tag) 8 | e.classList.add(className) 9 | e.innerHTML = content 10 | 11 | return e 12 | } 13 | 14 | export { isValidData, clearFormFields, eFactory } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/src/requests.js: -------------------------------------------------------------------------------- 1 | async function createTopic (data, date) { 2 | const response = await fetch('http://localhost:3030/jsonstore/collections/myboard/posts', { 3 | method: 'post', 4 | headers: { 'Content-Type': 'application/json' }, 5 | body: JSON.stringify({ ...data, creationDate: date }) 6 | }) 7 | 8 | return await response.json() 9 | } 10 | 11 | async function getPosts () { 12 | const topicsResponse = await fetch('http://localhost:3030/jsonstore/collections/myboard/posts') 13 | const data = await topicsResponse.json() 14 | 15 | return Object.values(data) 16 | } 17 | 18 | async function getComments (topicName) { 19 | const response = await fetch('http://localhost:3030/jsonstore/collections/myboard/comments') 20 | const data = await response.json() 21 | const comments = Object.values(data).filter(x => x.topicName === topicName) 22 | 23 | return comments 24 | } 25 | 26 | async function postComment (data, topicName) { 27 | const response = await fetch('http://localhost:3030/jsonstore/collections/myboard/comments', { 28 | method: 'post', 29 | headers: { 'Content-Type': 'application/json' }, 30 | body: JSON.stringify({ ...data, topicName }) 31 | }) 32 | } 33 | 34 | export { createTopic, getPosts, getComments, postComment } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/static/layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | .site { 6 | max-width: 50em; 7 | margin: 0 auto; 8 | } 9 | 10 | table { 11 | border: 1px solid #CCC; 12 | width: 100%; 13 | border-spacing: 0.2em; 14 | margin-bottom: 1.5em; 15 | } 16 | 17 | table td, 18 | table th { 19 | border: 1px solid #CCC; 20 | padding: 0.4em 0.8em; 21 | } 22 | 23 | table td { 24 | background: #EEE; 25 | } 26 | 27 | table thead th, 28 | table tfoot td { 29 | font-weight: bold; 30 | text-align: left; 31 | background: #000; 32 | color: #FFF; 33 | } 34 | 35 | table tbody tr:nth-child(even) td { 36 | background: #CCC; 37 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/static/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Exercise/01.Forum/static/profile.png -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/static/reset.css: -------------------------------------------------------------------------------- 1 | /* 2 | *Removes all default whitespace 3 | */ 4 | 5 | * { 6 | padding: 0; 7 | margin: 0; 8 | } 9 | 10 | /* 11 | *Reset CSS model sizing calculations 12 | */ 13 | 14 | html { 15 | box-sizing: border-box; 16 | } 17 | 18 | *, *:before, *:after { 19 | box-sizing: inherit; 20 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/static/responsive.css: -------------------------------------------------------------------------------- 1 | @media (min-width: 800px) { 2 | html { 3 | font-size: 14px; 4 | } 5 | } 6 | 7 | @media (min-width: 1024px) { 8 | html { 9 | font-size: 16px; 10 | } 11 | } 12 | 13 | @media (min-width: 1280px) { 14 | html { 15 | font-size: 18px; 16 | } 17 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/01.Forum/static/typography.css: -------------------------------------------------------------------------------- 1 | html { 2 | font: 18px/1.5 Verdana, sans-serif; 3 | } 4 | 5 | body, form, input, textarea, option, select, button { 6 | font: inherit; 7 | } 8 | 9 | ul, ol { 10 | padding-bottom: 1.5em; 11 | } 12 | 13 | ul, ol { 14 | padding-left: 2.5em; 15 | } 16 | 17 | blockquote, h1, h2, h3, h4, h5, h6 { 18 | font-family: Georgia, serif; 19 | } 20 | 21 | h1, h2, h3, h4, h5, h6 { 22 | padding-bottom: 0.5rem; 23 | padding-top: 1.5rem; 24 | font-weight: normal; 25 | } 26 | 27 | h1 { 28 | font-size: 2.6em; 29 | } 30 | 31 | h2 { 32 | font-size: 2.0em; 33 | } 34 | 35 | h3 { 36 | font-size: 1.6em; 37 | } 38 | 39 | h4 { 40 | font-size: 1.4em; 41 | } 42 | 43 | h5 { 44 | font-size: 1.2em; 45 | } 46 | 47 | h6 { 48 | font-size: 1.0em; 49 | } 50 | 51 | p+h1, p+h2, p+h3, p+h4, p+h5, p+h6 { 52 | padding-top: 0.5em; 53 | } 54 | 55 | blockquote { 56 | padding: 0 2.5em; 57 | border-left: 2px solid #000000; 58 | font-family: Georgia, serif; 59 | margin-bottom: 1.5em; 60 | } 61 | 62 | blockquote, p { 63 | font-style: italic; 64 | } 65 | 66 | blockquote p+p { 67 | padding-top: 1.5em; 68 | } 69 | 70 | blockquote p:last-child { 71 | padding-bottom: 0; 72 | } 73 | 74 | blockquote p.author { 75 | text-align: right; 76 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/components/addMovieBtn.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | const addMovieBtn = eFactory( 4 | 'section', 5 | '', 6 | `Add Movie` 7 | ) 8 | addMovieBtn.id = 'add-movie-button' 9 | 10 | export { addMovieBtn } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/components/footer.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | const footer = eFactory('footerComponent', 'page-footerComponent font-small', `
© 2020 4 | JS 5 | Applications 6 |
`) 7 | 8 | export { footer } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/components/movieComponent.js: -------------------------------------------------------------------------------- 1 | import { eFactory, userLoggedIn } from '../src/helper.js' 2 | 3 | function getMovieComponent ({ img, title, _id }) { 4 | const innerHTML = `Card image cap 7 |
8 |

${title}

9 |
10 | ${userLoggedIn() 11 | ? `` 15 | : ''}` 16 | 17 | return eFactory('div', 'card mb-4', innerHTML) 18 | } 19 | 20 | export { getMovieComponent } 21 | 22 | -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/components/navBarComponent.js: -------------------------------------------------------------------------------- 1 | import { getNavBarLinks, eFactory } from '../src/helper.js' 2 | 3 | const createLink = (text) => `` 6 | 7 | const navBarComponent = () => eFactory('nav', 'navbar navbar-expand-lg navbar-dark bg-dark', `Movies 9 | `) 12 | 13 | export { navBarComponent } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Application 2020 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/src/createPageLayout.js: -------------------------------------------------------------------------------- 1 | import { navBarComponent } from '../components/navBarComponent.js' 2 | import { footer } from '../components/footer.js' 3 | 4 | function applyPageLayout (parent, pageLayout) { 5 | parent.innerHTML = '' 6 | parent.appendChild(pageLayout) 7 | 8 | return parent 9 | } 10 | 11 | function createPageLayout (data) { 12 | const wrapper = document.createDocumentFragment() 13 | wrapper.appendChild(navBarComponent()) 14 | 15 | if (data) wrapper.appendChild(data) 16 | 17 | wrapper.appendChild(footer) 18 | 19 | return wrapper 20 | } 21 | 22 | export { createPageLayout, applyPageLayout } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/static/css/site.css: -------------------------------------------------------------------------------- 1 | 2 | .card { 3 | min-width: 18rem; 4 | max-width: 18rem; 5 | } 6 | 7 | .card-img-top { 8 | width: 100%; 9 | height: 15vw; 10 | object-fit: cover; 11 | } 12 | 13 | .btn-group { 14 | margin-right: 20px; 15 | } 16 | 17 | .badge { 18 | margin-left: 10px; 19 | } 20 | 21 | .enrolled-span { 22 | padding: 2%; 23 | border-radius: 4px; 24 | } 25 | 26 | .notifications { 27 | background-color: rgba(238, 74, 74, 0.699); 28 | margin: 0 auto; 29 | text-align: center; 30 | padding: 1%; 31 | margin-top: 2%; 32 | margin-bottom: 2%; 33 | border-radius: 6px; 34 | color: white; 35 | font-style: italic; 36 | text-decoration: underline; 37 | box-shadow: 0 5px 10px #cccccc; 38 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Exercise/02.Movies/static/favicon.ico -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/views/addMovieView.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | const innerHTML = `
4 |

Add Movie

5 |
6 | 7 | 8 |
9 |
10 | 11 | 12 |
13 |
14 | 15 | 16 |
17 | 18 |
` 19 | 20 | const addMovieView = eFactory('section', '', innerHTML) 21 | addMovieView.id = 'add-movie' 22 | 23 | export { addMovieView } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/views/editMovieView.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | function editMovieView ({ title, description, img }) { 4 | const innerHTML = `
5 |

Edit Movie

6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 | 19 |
` 20 | 21 | const editMovieSection = eFactory('section', '', innerHTML) 22 | editMovieSection.id = 'edit-movie' 23 | 24 | return editMovieSection 25 | } 26 | 27 | export { editMovieView } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/views/loginView.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | const innerHTML = `
4 |
5 | 6 | 7 |
8 |
9 | 10 | 12 |
13 | 14 |
` 15 | 16 | const loginView = eFactory('section', '', innerHTML) 17 | loginView.id = 'form-login' 18 | 19 | export { loginView } 20 | -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/views/movieDetailsView.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | function movieDetailsView ({ title, img, description, _ownerId }, likesCount) { 4 | const isOwnMovie = _ownerId === sessionStorage.getItem('_id') 5 | 6 | const ownerButtons = `Delete 7 | Edit` 8 | 9 | const likeButton = `Like` 10 | 11 | const innerHTML = `
12 |
13 |

Movie title: ${title}

14 |
15 | Movie 16 |
17 |
18 |

Movie Description

19 |

${description}

20 | ${isOwnMovie 21 | ? ownerButtons 22 | : likeButton} 23 | Liked ${likesCount} 24 |
25 |
26 |
` 27 | 28 | const detailsSection = eFactory('section', '', innerHTML) 29 | detailsSection.id = 'movie-example' 30 | 31 | return detailsSection 32 | } 33 | 34 | export { movieDetailsView } -------------------------------------------------------------------------------- /04 SPA/Exercise/02.Movies/views/registerView.js: -------------------------------------------------------------------------------- 1 | import { eFactory } from '../src/helper.js' 2 | 3 | const innerHTML = `
4 |
5 | 6 | 7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 | 17 |
` 18 | 19 | const registerView = eFactory('section', '', innerHTML) 20 | 21 | export { registerView } -------------------------------------------------------------------------------- /04 SPA/Exercise/04. JS-Applications-Single-Page-Applications-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Exercise/04. JS-Applications-Single-Page-Applications-Exercise.docx -------------------------------------------------------------------------------- /04 SPA/Exercise/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /04 SPA/Exercise/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /04 SPA/Lab/01.Calendar/src/app.js: -------------------------------------------------------------------------------- 1 | import { loadView, displayMonth, displayYear, displayYears } from './displays.js' 2 | import { clickedValidMonth, clickedValidYear, validMonths } from './helper.js' 3 | 4 | const yearsView = document.getElementById('years') 5 | const years = [...document.getElementsByClassName('monthCalendar')].reduce((a, v) => { 6 | a[v.id] = v 7 | return a 8 | }, {}) 9 | const months = [...document.getElementsByClassName('daysCalendar')] 10 | 11 | loadView(yearsView) 12 | 13 | document.addEventListener('click', e => { 14 | if (clickedValidYear(e)) { 15 | displayYear(years, e.target.textContent.trim()) 16 | } else if (clickedValidMonth(e)) { 17 | const year = document.querySelector('caption').innerText 18 | const month = e.target.innerText.trim() 19 | const monthIndex = validMonths.findIndex(x => x === month) 20 | 21 | if (monthIndex !== -1) { 22 | displayMonth(months, monthIndex, year) 23 | } 24 | } 25 | 26 | if (e.target.tagName === 'CAPTION') { 27 | const captionText = e.target.innerText 28 | 29 | if (isNaN(captionText)) { 30 | const year = captionText.match(/[1-2]{1}[0-9]{3}/g) 31 | displayYear(years, year) 32 | } else { 33 | displayYears(yearsView) 34 | } 35 | } 36 | } 37 | ) -------------------------------------------------------------------------------- /04 SPA/Lab/01.Calendar/src/displays.js: -------------------------------------------------------------------------------- 1 | function loadView (newView) { 2 | document.body.innerHTML = '' 3 | document.body.appendChild(newView) 4 | } 5 | 6 | function displayYears (view) { 7 | loadView(view) 8 | } 9 | 10 | function displayYear (years, year) { 11 | loadView(years[`year-${year}`]) 12 | } 13 | 14 | function displayMonth (months, monthIndex, year) { 15 | const monthElement = months.find(x => x.id === `month-${year}-${monthIndex+1}`) 16 | loadView(monthElement) 17 | } 18 | 19 | export { loadView, displayYears, displayYear, displayMonth } -------------------------------------------------------------------------------- /04 SPA/Lab/01.Calendar/src/helper.js: -------------------------------------------------------------------------------- 1 | const clickedValidYear = e => 2 | e.path.some(x => x.id === 'years' && x.tagName === 'SECTION') && 3 | (e.target.className === 'date' || e.target.className === 'day') 4 | 5 | const clickedValidMonth = e => 6 | e.path.some(x => x.className === 'monthCalendar' && x.tagName === 'SECTION') 7 | 8 | const validMonths = [ 9 | 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' 10 | ] 11 | 12 | export { clickedValidYear, clickedValidMonth, validMonths } -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/assets/fish.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Lab/02 Cookbook Pt. 3/assets/fish.jpg -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/assets/lasagna.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Lab/02 Cookbook Pt. 3/assets/lasagna.jpg -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/assets/roast.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Lab/02 Cookbook Pt. 3/assets/roast.jpg -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/src/catalog.js: -------------------------------------------------------------------------------- 1 | import { e } from './dom.js'; 2 | import { showDetails } from './details.js'; 3 | 4 | async function getRecipes() { 5 | const response = await fetch('http://localhost:3030/data/recipes?select=' + encodeURIComponent('_id,name,img')); 6 | const recipes = await response.json(); 7 | 8 | return recipes; 9 | } 10 | 11 | function createRecipePreview(recipe) { 12 | const result = e('article', { className: 'preview', onClick: () => showDetails(recipe._id) }, 13 | e('div', { className: 'title' }, e('h2', {}, recipe.name)), 14 | e('div', { className: 'small' }, e('img', { src: recipe.img })), 15 | ); 16 | 17 | return result; 18 | } 19 | 20 | let main; 21 | let section; 22 | let setActiveNav; 23 | 24 | export function setupCatalog(targetMain, targetSection, onActiveNav) { 25 | main = targetMain; 26 | section = targetSection; 27 | setActiveNav = onActiveNav; 28 | } 29 | 30 | export async function showCatalog() { 31 | setActiveNav('catalogLink'); 32 | section.innerHTML = 'Loading…'; 33 | main.innerHTML = ''; 34 | main.appendChild(section); 35 | 36 | const recipes = await getRecipes(); 37 | const cards = recipes.map(createRecipePreview); 38 | 39 | const fragment = document.createDocumentFragment(); 40 | cards.forEach(c => fragment.appendChild(c)); 41 | section.innerHTML = ''; 42 | section.appendChild(fragment); 43 | } -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/src/dom.js: -------------------------------------------------------------------------------- 1 | export function e(type, attributes, ...content) { 2 | const result = document.createElement(type); 3 | 4 | for (let [attr, value] of Object.entries(attributes || {})) { 5 | if (attr.substring(0, 2) == 'on') { 6 | result.addEventListener(attr.substring(2).toLocaleLowerCase(), value); 7 | } else { 8 | result[attr] = value; 9 | } 10 | } 11 | 12 | content = content.reduce((a, c) => a.concat(Array.isArray(c) ? c : [c]), []); 13 | 14 | content.forEach(e => { 15 | if (typeof e == 'string' || typeof e == 'number') { 16 | const node = document.createTextNode(e); 17 | result.appendChild(node); 18 | } else { 19 | result.appendChild(e); 20 | } 21 | }); 22 | 23 | return result; 24 | } -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/static/form.css: -------------------------------------------------------------------------------- 1 | form { 2 | padding: 32px; 3 | } 4 | 5 | label { 6 | display: block; 7 | position: relative; 8 | margin: 16px 0; 9 | text-align: right; 10 | padding-right: 520px; 11 | line-height: 48px; 12 | } 13 | 14 | input[type="text"], input[type="password"], textarea { 15 | position: absolute; 16 | right: 0px; 17 | width: 500px; 18 | padding: 8px; 19 | } 20 | 21 | textarea { 22 | height: 300px; 23 | resize: none; 24 | } 25 | 26 | .ml { 27 | height: 300px; 28 | } 29 | 30 | input[type="submit"] { 31 | display: block; 32 | border: none; 33 | margin: auto; 34 | background-color: salmon; 35 | padding: 8px 16px; 36 | text-decoration: none; 37 | color: black; 38 | } 39 | 40 | input[type="submit"]:hover { 41 | background-color: #6c8b47; 42 | color: white; 43 | cursor: pointer; 44 | } -------------------------------------------------------------------------------- /04 SPA/Lab/02 Cookbook Pt. 3/static/site.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; 3 | font-size: 16pt; 4 | padding: 0; 5 | margin: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | body { 10 | width: 980px; 11 | margin: 0 auto 0 auto; 12 | } 13 | 14 | header { 15 | padding: 32px; 16 | background-color: #cccccc; 17 | position: relative; 18 | } 19 | 20 | h1 { 21 | font-size: 150%; 22 | display: inline; 23 | } 24 | 25 | main { 26 | background-color: #666666; 27 | padding: 32px; 28 | } 29 | 30 | nav { 31 | display: inline-block; 32 | position: absolute; 33 | right: 16px; 34 | text-align: right; 35 | } 36 | 37 | nav div { 38 | display: inline-block; 39 | } 40 | 41 | nav a { 42 | display: inline-block; 43 | background-color: salmon; 44 | padding: 8px 16px; 45 | margin: 0 8px; 46 | text-decoration: none; 47 | color: black; 48 | } 49 | 50 | nav a:hover { 51 | background-color: #6c8b47; 52 | color: white; 53 | } 54 | 55 | a.active { 56 | background-color: #6c8b47; 57 | color: white; 58 | } 59 | 60 | #user { 61 | display: none; 62 | } 63 | 64 | #guest { 65 | display: none; 66 | } 67 | 68 | #views { 69 | display: none; 70 | } -------------------------------------------------------------------------------- /04 SPA/Lab/04. JS-Applications-Single-Page-Applications-Lab.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/04 SPA/Lab/04. JS-Applications-Single-Page-Applications-Lab.docx -------------------------------------------------------------------------------- /04 SPA/Lab/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /04 SPA/Lab/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/01.Messenger/app.js: -------------------------------------------------------------------------------- 1 | function attachEvents() { 2 | document.getElementById('submit').addEventListener('click', async () => { 3 | const author = document.getElementById('author').value; 4 | const content = document.getElementById('content').value; 5 | 6 | await sendMessage({author, content}); 7 | 8 | document.getElementById('author').value = ''; 9 | document.getElementById('content').value = ''; 10 | }); 11 | 12 | document.getElementById('refresh').addEventListener('click', getMessages); 13 | } 14 | 15 | attachEvents(); 16 | 17 | 18 | async function getMessages() { 19 | const response = await fetch('http://localhost:3030/jsonstore/messenger'); 20 | const data = await response.json(); 21 | 22 | const messages = Object.values(data).map(v => `${v.author}: ${v.content}`).join('\n'); 23 | document.getElementById('messages').value = messages; 24 | } 25 | 26 | async function sendMessage(message) { 27 | const response = await fetch('http://localhost:3030/jsonstore/messenger', { 28 | method: 'post', 29 | headers: { 'Content-Type': 'application/json'}, 30 | body: JSON.stringify(message) 31 | }); 32 | const data = await response.json(); 33 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/01.Messenger/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Messenger 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/01.Messenger/styles.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans); 2 | input[type=text] { 3 | padding: 12px 20px; 4 | margin: 8px 0; 5 | display: inline-block; 6 | border: 1px solid #ccc; 7 | border-radius: 4px; 8 | box-sizing: border-box; 9 | } 10 | input[type=button] { 11 | background-color: #4CAF50; 12 | color: white; 13 | padding: 10px 16px; 14 | border: none; 15 | border-radius: 4px; 16 | cursor: pointer; 17 | display: block; 18 | } 19 | input[type=button]:hover { 20 | background-color: #45a049; 21 | } 22 | body { 23 | margin: auto; 24 | text-align: center; 25 | padding: 20px; 26 | font-family: 'Open Sans', serif; 27 | } 28 | label { 29 | display: inline-block; 30 | width: 5em; 31 | } 32 | #author, 33 | #content { 34 | width: 30em; 35 | } 36 | #controls { 37 | width: 38em; 38 | } 39 | #submit, #refresh { 40 | display: inline-block; 41 | } 42 | #submit { 43 | margin: 32px; 44 | } 45 | 46 | #main{ 47 | width: 50%; 48 | margin: 0 auto; 49 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/01.Messenger/tests/mockData.json: -------------------------------------------------------------------------------- 1 | { 2 | "messages": { 3 | "-LxHVtajG3N1sU714pVj": { 4 | "author": "Spami", 5 | "content": "Hello, are you there?" 6 | }, 7 | "-LxIDxC-GotWtf4eHwV8": { 8 | "author": "Garry", 9 | "content": "Yep, whats up :?" 10 | }, 11 | "-LxIDxPfhsNipDrOQ5g_": { 12 | "author": "Spami", 13 | "content": "How are you? Long time no see? :)" 14 | }, 15 | "-LxIE-dM_msaz1O9MouM": { 16 | "author": "George", 17 | "content": "Hello, guys! :))" 18 | }, 19 | "-LxLgX_nOIiuvbwmxt8w": { 20 | "author": "Spami", 21 | "content": "Hello, George nice to see you! :)))" 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/02.Book-Library/mockData.json: -------------------------------------------------------------------------------- 1 | { 2 | "d953e5fb-a585-4d6b-92d3-ee90697398a0": { 3 | "author": "J.K.Rowling", 4 | "title": "Harry Potter and the Philosopher's Stone" 5 | }, 6 | "d953e5fb-a585-4d6b-92d3-ee90697398a1": { 7 | "author": "Svetlin Nakov", 8 | "title": "C# Fundamentals" 9 | } 10 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/.idea/03.SoftTerest.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Components/Footer.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Footer = () => html` 4 | ` 9 | 10 | export { Footer } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Components/Notif.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Notif = (msg) => { 4 | return html` 5 |
6 |
7 | ${msg} 8 |
9 |
` 10 | } 11 | 12 | export { Notif } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Components/PageLayout.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { Header } from './Header.js' 3 | import { Footer } from './Footer.js' 4 | 5 | const PageLayout = (...children) => html` 6 | ${Header()} 7 |
8 | ${children} 9 |
10 | ${Footer()}` 11 | 12 | export { PageLayout } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Views/DashboardView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const IdeaCardComponent = ({ _id, title, img }) => { 4 | 5 | return html` 6 |
8 |
9 |

${title}

10 |
11 | Card image cap 12 | Details 13 |
` 14 | } 15 | 16 | const DashboardView = (ideas) => { 17 | 18 | return html` 19 |
20 | ${ideas ? ideas.map(IdeaCardComponent) : html`

No ideas yet! Be the first one 21 | :)

`} 22 |
` 23 | } 24 | 25 | export { DashboardView } 26 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Views/DetailsView.js: -------------------------------------------------------------------------------- 1 | import { html, nothing } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const DetailsView = ({ title, img, description, _id, _ownerId }) => { 4 | 5 | return html` 6 |
7 | 8 |
9 |

${title}

10 |

Description:

11 |

${description}

12 |
13 | ${_ownerId === sessionStorage.getItem('id') ? html` 14 |
15 | Delete 16 |
` : nothing} 17 |
` 18 | } 19 | 20 | export { DetailsView } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/Views/HomeView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const HomeView = () => { 4 | 5 | return html` 6 |
7 |
8 |
9 | 10 |
11 |
12 |

Do you wonder if your idea is good?

13 |

Join our family =)

14 |

Post your ideas!

15 |

Find what other people think!

16 |

Comment on other people's ideas.

17 |
18 |
19 |
20 | Get Started 21 |
22 |
` 23 | } 24 | 25 | export { HomeView } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/White-Abstract-Backgrounds-Gallery-47-Plus-PIC-WPW404836.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/White-Abstract-Backgrounds-Gallery-47-Plus-PIC-WPW404836.jpg -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/best-pilates-youtube-workouts-2__medium_4x3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/best-pilates-youtube-workouts-2__medium_4x3.jpg -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/brightideacropped.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/brightideacropped.jpg -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/creativity_painted_face.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/creativity_painted_face.jpg -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/dinner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/dinner.jpg -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/images/idea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/03.SoftTerest/images/idea.png -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | SoftTerest 7 | 8 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "softterest", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.html", 6 | "scripts": { 7 | "test": "mocha tests", 8 | "start": "http-server -a localhost -p 3000 -P http://localhost:3000?" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "lit-html": "^1.3.0", 14 | "page": "^1.11.6" 15 | }, 16 | "devDependencies": { 17 | "http-server": "^0.12.3", 18 | "chai": "^4.3.3", 19 | "mocha": "^8.3.0", 20 | "playwright-chromium": "^1.9.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/requests/backendAPI.js: -------------------------------------------------------------------------------- 1 | const origin = 'http://localhost:3030' 2 | 3 | const createOptions = (method = 'GET', body) => { 4 | const options = { 5 | method, 6 | headers: {}, 7 | } 8 | const token = sessionStorage.getItem('accessToken') 9 | 10 | if (token) { 11 | options.headers['X-Authorization'] = token 12 | } 13 | if (body) { 14 | options.headers['Content-Type'] = 'application/json' 15 | options.body = JSON.stringify(body) 16 | } 17 | 18 | return options 19 | } 20 | 21 | const request = async (uri, options) => { 22 | const URI = uri[0] === '/' ? uri : `/${uri}` 23 | let response = {} 24 | 25 | try { 26 | response = await fetch(`${origin}${URI}`, options) 27 | } catch (e) { 28 | throw new Error(e) 29 | } 30 | 31 | if (! response.ok) { 32 | throw new Error(response.status) 33 | } 34 | 35 | try { 36 | return await response.json() 37 | } catch (e) { 38 | return response 39 | } 40 | } 41 | 42 | const fetches = { 43 | get: async (uri) => await request(uri, createOptions()), 44 | post: async (uri, body) => await request(uri, createOptions('POST', body)), 45 | put: async (uri, body) => await request(uri, createOptions('PUT', body)), 46 | delete: async (uri) => await request(uri, createOptions('DELETE')), 47 | } 48 | 49 | export { fetches } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/requests/requests.js: -------------------------------------------------------------------------------- 1 | import { fetches } from './backendAPI.js' 2 | 3 | const user = { 4 | register: (body) => fetches.post('users/register', body), 5 | login: (body) => fetches.post('users/login', body), 6 | logout: () => fetches.get('users/logout'), 7 | } 8 | 9 | const ideas = { 10 | getAllIdeas: () => fetches.get('/data/ideas?select=_id%2Ctitle%2Cimg&sortBy=_createdOn%20desc'), 11 | createIdea: ({ title, description, img }) => fetches.post( 12 | '/data/ideas', 13 | { title, description, img } 14 | ), 15 | getIdea: (id) => fetches.get(`/data/ideas/${id}`), 16 | deleteIdea: (id) => fetches.delete(`/data/ideas/${id}`), 17 | } 18 | 19 | export { user, ideas } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/src/app.js: -------------------------------------------------------------------------------- 1 | import page from '../node_modules/page/page.mjs' 2 | import { renderView } from './helper.js' 3 | import { HomeView } from '../Views/HomeView.js' 4 | import { RegisterView } from '../Views/RegisterView.js' 5 | import { LoginView } from '../Views/LoginView.js' 6 | import { DashboardView } from '../Views/DashboardView.js' 7 | import { contextAPI } from './contextAPI.js' 8 | import { CreateIdeaView } from '../Views/CreateIdeaView.js' 9 | import { ideas } from '../requests/requests.js' 10 | import { DetailsView } from '../Views/DetailsView.js' 11 | 12 | page('/', () => renderView(HomeView())) 13 | page( 14 | '/dashboard', 15 | contextAPI.storeAllIdeas, 16 | (context) => renderView(DashboardView(context.allIdeas)) 17 | ) 18 | page('/details/:id', contextAPI.storeIdea, (context) => renderView(DetailsView(context.idea))) 19 | page('/create', () => renderView(CreateIdeaView())) 20 | page('/register', () => renderView(RegisterView())) 21 | page('/login', () => renderView(LoginView())) 22 | page() 23 | 24 | document.addEventListener('click', async (e) => { 25 | if (e.target.tagName === 'A' && e.target.classList.contains('detb')) { 26 | e.preventDefault() 27 | await ideas.deleteIdea(e.target.dataset.id) 28 | 29 | page.redirect('/dashboard') 30 | } 31 | }) 32 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/src/contextAPI.js: -------------------------------------------------------------------------------- 1 | import { ideas } from '../requests/requests.js' 2 | 3 | const contextAPI = { 4 | storeAllIdeas: async (context, next) => { 5 | context.allIdeas = await ideas.getAllIdeas() 6 | next() 7 | }, 8 | storeIdea: async (context, next) => { 9 | context.idea = await ideas.getIdea(context.params.id) 10 | next() 11 | } 12 | } 13 | 14 | 15 | export { contextAPI } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/src/helper.js: -------------------------------------------------------------------------------- 1 | import { render } from '../node_modules/lit-html/lit-html.js' 2 | import { PageLayout } from '../Components/PageLayout.js' 3 | 4 | const container = document.querySelector('body') 5 | const renderView = (view) => render(PageLayout(view), container) 6 | 7 | const isUserLogged = () => sessionStorage.getItem('accessToken') ? true : false 8 | 9 | const createFormObject = (form) => { 10 | const formData = new FormData(form) 11 | 12 | return Object.fromEntries([...formData.entries()]) 13 | } 14 | 15 | const saveUserInStorage = data => { 16 | sessionStorage.setItem('email', data.email) 17 | sessionStorage.setItem('username', data.username) 18 | sessionStorage.setItem('id', data._id) 19 | sessionStorage.setItem('accessToken', data.accessToken) 20 | sessionStorage.setItem('gender', data.gender) 21 | 22 | return data 23 | } 24 | 25 | const showNotification = (view, msg) => { 26 | renderView(view(msg)) 27 | 28 | setTimeout(() => renderView(view(msg)), 3000) 29 | } 30 | 31 | export { isUserLogged, createFormObject, saveUserInStorage, renderView, showNotification } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/styles/common.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0 auto; 3 | padding: 0; 4 | font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif; 5 | } 6 | 7 | body { 8 | background: url("../images/White-Abstract-Backgrounds-Gallery-47-Plus-PIC-WPW404836.jpg"); 9 | background-position: center; 10 | background-repeat: no-repeat; 11 | background-size: cover; 12 | } 13 | 14 | nav { 15 | position: fixed; 16 | top: 0; 17 | background-color: rgb(222, 230, 238); 18 | font-weight: bold; 19 | font-size: 20px; 20 | } 21 | 22 | footer { 23 | bottom: 0; 24 | width: 100%; 25 | height: 60px; 26 | line-height: 60px; 27 | background-color: #f5f5f5; 28 | color: rgba(0, 0, 0, 0.39); 29 | font-size: 20px; 30 | } 31 | 32 | .container-footer { 33 | position: relative; 34 | float: left; 35 | left: 30px; 36 | } 37 | 38 | nav a { 39 | text-decoration: none; 40 | color: rgb(27, 38, 49) 41 | } 42 | 43 | nav img { 44 | height: 3rem; 45 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/styles/home.css: -------------------------------------------------------------------------------- 1 | .home { 2 | background-color: rgba(0, 0, 0, 0.308); 3 | margin: 0.5em auto; 4 | margin-top: 5em; 5 | } 6 | 7 | .responsive { 8 | width: 100%; 9 | /* max-width: 400px; */ 10 | height: auto; 11 | } 12 | 13 | .btn { 14 | background-color: rgb(108, 107, 110); 15 | } 16 | 17 | .home-text { 18 | color: white; 19 | } 20 | 21 | .wrapper { 22 | position: relative; 23 | padding: 2em; 24 | } 25 | 26 | .wrapper .bottom { 27 | position: relative; 28 | width: 100%; 29 | top: 25%; 30 | } 31 | 32 | .btn { 33 | min-width: 20%; 34 | } 35 | 36 | textarea { 37 | resize: none; 38 | width: 100%; 39 | height: 6em; 40 | } 41 | 42 | .btn { 43 | font-weight: bold; 44 | color: white; 45 | text-transform: uppercase; 46 | letter-spacing: 1px; 47 | cursor: pointer; 48 | } 49 | 50 | .btn:hover { 51 | filter: brightness(90%); 52 | color: white; 53 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/styles/login.css: -------------------------------------------------------------------------------- 1 | .form-user { 2 | color: white; 3 | margin: 2em; 4 | } 5 | 6 | @media only screen and (min-width: 780px) { 7 | .row-form { 8 | position: relative; 9 | float: center; 10 | top: 20%; 11 | } 12 | } 13 | 14 | .btn { 15 | border: none; 16 | margin-top: 1em; 17 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/styles/style.css: -------------------------------------------------------------------------------- 1 | @import url("common.css"); 2 | @import url("home.css"); 3 | @import url("login.css"); 4 | @import url("dashboard.css"); 5 | @import url("ideas.css"); -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/03.SoftTerest/tests/mock-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "ideas": [ 3 | { 4 | "_ownerId": "0001", 5 | "title": "111111", 6 | "img": "http://site.com/111", 7 | "_createdOn": 1614949637888, 8 | "_id": "0003" 9 | }, 10 | { 11 | "_ownerId": "35c62d76-8152-4626-8712-eeb96381bea8", 12 | "title": "222222", 13 | "img": "http://site.com/222", 14 | "_createdOn": 1614949638158, 15 | "_id": "3987279d-0ad4-4afb-8ca9-5b256ae3b298" 16 | }, 17 | { 18 | "_ownerId": "35c62d76-8152-4626-8712-eeb96381bea8", 19 | "title": "333333", 20 | "img": "http://site.com/333", 21 | "_createdOn": 1614949638978, 22 | "_id": "8f414b4f-ab39-4d36-bedb-2ad69da9c830" 23 | } 24 | ], 25 | "details": { 26 | "_ownerId": "0001", 27 | "title": "111111", 28 | "description": "1111111111", 29 | "img": "http://site.com/111", 30 | "_createdOn": 1614949637888, 31 | "_id": "0003" 32 | } 33 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/05. JS-Applications-Architecture-and-Testing-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Exercise/05. JS-Applications-Architecture-and-Testing-Exercise.docx -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Exercise/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Lab/01. Accordion/accordion.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Poppins'); 2 | 3 | body { 4 | font-family: 'Poppins', sans-serif; 5 | } 6 | 7 | .accordion { 8 | border: 2px solid #cdc7c7; 9 | display: inline-block; 10 | width: 40%; 11 | font-size: 1.3rem; 12 | margin: 1em; 13 | } 14 | 15 | .accordion p { 16 | margin: 1em; 17 | } 18 | 19 | .button { 20 | float: right; 21 | background: #393636; 22 | padding: 0.1em 1em 0.1em 1em; 23 | color: white; 24 | cursor: pointer; 25 | text-transform: uppercase; 26 | font-weight: bold; 27 | letter-spacing: 3px; 28 | } 29 | 30 | .extra { 31 | display: none; 32 | } 33 | 34 | .head { 35 | background: #ccccff; 36 | padding: 1em; 37 | } 38 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Lab/01. Accordion/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Accordion 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /05 Architecture and Testing/Lab/05. JS-Applications-Architecture-and-Testing-Lab.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/05 Architecture and Testing/Lab/05. JS-Applications-Architecture-and-Testing-Lab.docx -------------------------------------------------------------------------------- /05 Architecture and Testing/Lab/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /05 Architecture and Testing/Lab/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/01.List-Towns/app.js: -------------------------------------------------------------------------------- 1 | import { render } from 'https://unpkg.com/lit-html?module' 2 | import { townsTemplate } from './templates.js' 3 | 4 | document.getElementsByTagName('form')[0].addEventListener('submit', e => { 5 | e.preventDefault() 6 | const formData = new FormData(e.target) 7 | const data = [...formData.values()][0].split(', ') 8 | 9 | render(townsTemplate(data), document.getElementById('root')) 10 | }) -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/01.List-Towns/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | List Towns 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 |
17 |
18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/01.List-Towns/templates.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | 3 | const townTemplate = (name) => html` 4 |
  • ${name}
  • ` 5 | 6 | const townsTemplate = (townsNames) => html` 7 | ` 10 | 11 | export { townsTemplate } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/app.js: -------------------------------------------------------------------------------- 1 | import { cats } from './catSeeder.js' 2 | import { render } from 'https://unpkg.com/lit-html?module' 3 | import { catsComponent } from './templates.js' 4 | 5 | render(catsComponent(cats), document.getElementById('allCats')) -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/catSeeder.js: -------------------------------------------------------------------------------- 1 | class Cat { 2 | constructor(id, statusCode, statusMessage, imageLocation) { 3 | this.id = id; 4 | this.statusCode = statusCode; 5 | this.statusMessage = statusMessage; 6 | this.imageLocation = imageLocation; 7 | } 8 | } 9 | 10 | const cats = [ 11 | new Cat('100', 100, 'Continue', 'cat100'), 12 | new Cat('200', 200, 'Ok', 'cat200'), 13 | new Cat('204', 204, 'No content', 'cat204'), 14 | new Cat('301', 301, 'Moved permanently', 'cat301'), 15 | new Cat('304', 304, 'Not modified', 'cat304'), 16 | new Cat('400', 400, 'Bad request', 'cat400'), 17 | new Cat('404', 404, 'Not Found', 'cat404'), 18 | new Cat('406', 406, 'Not Acceptable', 'cat406'), 19 | new Cat('410', 410, 'Gone', 'cat410'), 20 | new Cat('500', 500, 'Internal Server Error', 'cat500'), 21 | new Cat('511', 511, 'Network Authentication Required', 'cat511') 22 | ]; 23 | 24 | export { 25 | cats 26 | }; -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat100.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat200.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat204.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat204.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat301.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat301.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat304.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat304.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat400.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat400.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat404.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat406.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat406.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat410.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat410.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat500.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat500.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat511.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/images/cat511.jpg -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Http Status Cats 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 |
    15 | 16 | 17 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/02.HTTP-Status-Cats/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | ul li { 7 | display: inline-block; 8 | padding: 3rem; 9 | margin-bottom: 1.5rem; 10 | margin-left: 3.5rem; 11 | margin-top: 3rem; 12 | box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); 13 | } 14 | 15 | .info { 16 | display: inline-block; 17 | } 18 | 19 | .showBtn { 20 | position: relative; 21 | left: 1rem; 22 | border: none; 23 | background-color: #2AA5FE; 24 | width: 13rem; 25 | height: 3.5rem; 26 | color: #fff; 27 | border-radius: 17px; 28 | font-weight: 600; 29 | outline: none; 30 | } 31 | 32 | .status { 33 | position: relative; 34 | top: 1rem; 35 | text-align: center; 36 | left: 1rem; 37 | font-weight: 600; 38 | } 39 | 40 | .status p { 41 | padding: 1rem; 42 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Search in List 7 | 8 | 9 | 10 | 11 | 12 |
    13 |
    14 | 19 |
    20 | 21 | 22 |
    23 |
    24 | 25 | 26 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Search in List 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/list.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Raleway'); 2 | 3 | body { 4 | width: 20%; 5 | margin: 0 auto; 6 | font-family: 'Raleway',sans-serif; 7 | } 8 | article{ 9 | background: #34469c;; 10 | border-radius: 20px; 11 | margin-top: 20px; 12 | padding: 20px; 13 | } 14 | 15 | ul { 16 | list-style-type: none; 17 | padding: 0; 18 | } 19 | 20 | ul li { 21 | margin: 10px auto; 22 | width: 90%; 23 | text-align: left; 24 | color: white; 25 | } 26 | 27 | #searchText{ 28 | background: white; 29 | text-decoration: none; 30 | margin: 15px auto; 31 | width: 90%; 32 | padding:5px 10px; 33 | text-align: left; 34 | } 35 | 36 | button { 37 | background: white; 38 | margin-left:8px; 39 | padding: 8px 10px; 40 | border-radius: 15px; 41 | font-weight: bold; 42 | cursor: pointer; 43 | outline: none; 44 | color: #34469c;; 45 | text-transform: uppercase; 46 | border: 2px solid white; 47 | 48 | } 49 | 50 | button:hover { 51 | color: white; 52 | background: #34469c;; 53 | border: 2px solid white; 54 | } 55 | #result { 56 | padding: 10px; 57 | margin: 10px; 58 | color: white; 59 | } 60 | 61 | .active { 62 | font-weight: bold; 63 | text-decoration: underline; 64 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/search.js: -------------------------------------------------------------------------------- 1 | import { render } from 'https://unpkg.com/lit-html?module' 2 | import { template } from './template.js' 3 | import { towns } from './towns.js' 4 | 5 | render(template(towns), document.querySelector('body')) 6 | 7 | document.addEventListener('click', e => { 8 | if (e.target.tagName === 'BUTTON') { 9 | const value = document.getElementById(`searchText`).value 10 | const towns = [...document.getElementsByTagName('li')] 11 | let counter = 0 12 | 13 | towns.forEach(x => { 14 | x.className = '' 15 | if (x.innerText.toLocaleLowerCase().includes(value.toLocaleLowerCase())) { 16 | x.className = 'active' 17 | counter += 1 18 | } 19 | }) 20 | 21 | document.getElementById('result').innerText = 22 | counter !== 0 23 | ? `${counter} matches found` 24 | : '' 25 | } 26 | }) 27 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/template.js: -------------------------------------------------------------------------------- 1 | import { html, render } from 'https://unpkg.com/lit-html?module'; 2 | 3 | const template = (towns) => html` 4 |
    5 |
    6 | 10 |
    11 | 12 | 13 |
    14 |
    ` 15 | 16 | export { template } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/03.Search-in-List/towns.js: -------------------------------------------------------------------------------- 1 | export const towns = [ 2 | 'Sofia', 3 | 'Pleven', 4 | 'Varna', 5 | 'Plovdiv', 6 | 'Dolna Bania', 7 | 'Gorna Bania' 8 | ]; -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/04.Fill-Dropdown/filldropdown.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Raleway'); 2 | 3 | body { 4 | width: 40%; 5 | margin: 0 auto; 6 | padding-top: 20px; 7 | font-family: 'Raleway', sans-serif; 8 | } 9 | 10 | h1 { 11 | background-color: cadetblue; 12 | margin: 0; 13 | padding: 10px 20px; 14 | } 15 | 16 | article { 17 | background-color: #DDDDDD; 18 | padding: 10px 20px; 19 | } 20 | 21 | #menu { 22 | padding: 3px 7px; 23 | border-radius: 15px; 24 | } 25 | 26 | input, select { 27 | outline: none; 28 | padding: 5px; 29 | } 30 | select { 31 | margin-bottom: 12px; 32 | } 33 | 34 | input[type="text"] { 35 | border: 1px solid darkgray; 36 | border-radius: 15px; 37 | } 38 | 39 | input[type="submit"] { 40 | background: white; 41 | margin-left: 20px; 42 | padding: 5px 15px; 43 | border: 1px solid darkgray; 44 | border-radius: 15px; 45 | font-weight: bold; 46 | cursor: pointer; 47 | color: #8198A2; 48 | text-transform: uppercase; 49 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/04.Fill-Dropdown/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Fill Dropdown 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/04.Fill-Dropdown/src/dropdown.js: -------------------------------------------------------------------------------- 1 | import { render } from 'https://unpkg.com/lit-html?module' 2 | import { dropdownTemp } from './templates.js' 3 | import { getData, postEntry } from './requests.js' 4 | 5 | 6 | async function drawOptions () { 7 | const data = await getData() 8 | 9 | render(dropdownTemp(Object.values(data)), document.querySelector('body')) 10 | } 11 | 12 | await drawOptions() 13 | 14 | document.addEventListener('submit', async e => { 15 | e.preventDefault() 16 | const input = document.getElementById(`itemText`) 17 | 18 | await postEntry({ 19 | text: input.value 20 | }) 21 | await drawOptions() 22 | input.value = '' 23 | }) 24 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/04.Fill-Dropdown/src/requests.js: -------------------------------------------------------------------------------- 1 | async function checkOkToJSON (response) { 2 | if (! response.ok) { 3 | throw new Error(response.status) 4 | } 5 | 6 | return await response.json() 7 | } 8 | 9 | async function getData () { 10 | const response = await fetch('http://localhost:3030/jsonstore/advanced/dropdown ') 11 | 12 | return await checkOkToJSON(response) 13 | } 14 | 15 | async function postEntry (entry) { 16 | const response = await fetch('http://localhost:3030/jsonstore/advanced/dropdown ', { 17 | method: 'POST', 18 | headers: { 'Content-Type': 'application/json' }, 19 | body: JSON.stringify(entry) 20 | }) 21 | 22 | return await checkOkToJSON(response) 23 | } 24 | 25 | export { getData, postEntry } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/04.Fill-Dropdown/src/templates.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | 3 | const option = ({ text, _id }) => html` 4 | ` 5 | 6 | const dropdownTemp = (options) => html` 7 |

    Dropdown Menu

    8 |
    9 |
    10 | 13 |
    14 |
    15 | 18 | 19 | 20 |
    21 |
    ` 22 | 23 | export { dropdownTemp } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/05.Table-Search/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | TABLE - SEARCH ENGINE 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/05.Table-Search/solution.js: -------------------------------------------------------------------------------- 1 | import { render } from 'https://unpkg.com/lit-html?module' 2 | import { table } from './templates.js' 3 | 4 | async function getData () { 5 | const response = await fetch('http://localhost:3030/jsonstore/advanced/table') 6 | 7 | return response.json() 8 | } 9 | 10 | const data = await getData() 11 | 12 | const tableData = { 13 | headers: ['Student name', 'Student email', 'Student course',], 14 | bodyData: Object.values(data) 15 | } 16 | 17 | render(table(tableData), document.querySelector('body')) 18 | 19 | document.addEventListener('click', e => { 20 | if (e.target.tagName === 'BUTTON' && e.target.id === 'searchBtn') { 21 | const input = document.getElementById('searchField') 22 | const rows = [...document.getElementsByTagName('tr')].slice(1) 23 | rows.forEach(x => x.className = '') 24 | 25 | const selectedRows = rows 26 | .filter(x => x.textContent.toLocaleLowerCase() 27 | .includes(input.value.toLocaleLowerCase())) 28 | 29 | selectedRows.forEach(x => x.className = 'select') 30 | input.value = '' 31 | } 32 | }) -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/05.Table-Search/templates.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | 3 | const thCell = (content) => html` 4 | ${content}` 5 | 6 | const tdCell = (content) => html` 7 | ${content}` 8 | 9 | const tableHeader = (heads) => html` 10 | 11 | 12 | ${heads.map(x => thCell(x))} 13 | 14 | ` 15 | 16 | const tableBody = (bodyData) => html` 17 | 18 | ${bodyData.map(x => html` 19 | 20 | ${tdCell(`${x.firstName} ${x.lastName}`)} 21 | ${tdCell(x.email)} 22 | ${tdCell(x.course)} 23 | `)} 24 | 25 | ` 26 | 27 | const table = ({ headers, bodyData }) => html` 28 | 29 | ${tableHeader(headers)} 30 | ${tableBody(bodyData)} 31 | 32 | 33 | 37 | 38 | 39 |
    34 | 35 | 36 |
    ` 40 | 41 | export { table } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/06. JS-Applications-Client-Side-Rendering-Exercise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/06 Client Side Rendering (aka Templating)/Exercise/06. JS-Applications-Client-Side-Rendering-Exercise.docx -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/06.Book-Library/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Books 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/06.Book-Library/src/backendAPI.js: -------------------------------------------------------------------------------- 1 | const request = async (url, options = {}) => { 2 | const response = await fetch(url, options) 3 | const result = response.json() 4 | 5 | return result 6 | } 7 | 8 | const createOptions = (method = 'GET', headers = {}, data = {}) => { 9 | return { 10 | method, 11 | headers: { ...{ 'Content-Type': 'application/json', }, ...headers }, 12 | body: JSON.stringify(data) 13 | } 14 | } 15 | 16 | export { request, createOptions } 17 | 18 | -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/06.Book-Library/src/helper.js: -------------------------------------------------------------------------------- 1 | const clearInputs = (...inputs) => inputs.forEach(x => x.value = '') 2 | const getId = e => e.target.parentNode.parentNode.id 3 | const checkValidInput = (formData) => formData.every(x => x !== '' && x !== ' ') 4 | 5 | export { clearInputs, getId, checkValidInput } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/06.Book-Library/src/requests.js: -------------------------------------------------------------------------------- 1 | import { request, createOptions } from './backendAPI.js' 2 | 3 | const baseUrl = 'http://localhost:3030/jsonstore/collections/books' 4 | 5 | const loadBooks = async () => await request(baseUrl) 6 | const createBook = async data => request(baseUrl, createOptions('POST', undefined, data)) 7 | const getBook = async id => request(`${baseUrl}/${id}`) 8 | const updateBook = async (id, data) => await request( 9 | `${baseUrl}/${id}`, 10 | createOptions('PUT', undefined, data) 11 | ) 12 | 13 | const deleteBook = async (id) => request(`${baseUrl}/${id}`, createOptions('DELETE', undefined)) 14 | 15 | export { 16 | loadBooks, 17 | createBook, 18 | getBook, 19 | updateBook, 20 | deleteBook 21 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /06 Client Side Rendering (aka Templating)/Exercise/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /07 Routing/Furniture/07. JS-Applications-Routing-Execise.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/07 Routing/Furniture/07. JS-Applications-Routing-Execise.docx -------------------------------------------------------------------------------- /07 Routing/Furniture/Components/FurnitureCard.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | 3 | const FurnitureCard = ({ _id, img, description, price }) => { 4 | return html` 5 |
    6 |
    7 |
    8 | 9 |

    ${description}

    10 |
    11 |

    Price: ${price} $

    12 |
    13 |
    14 | Details 15 |
    16 |
    17 |
    ` 18 | } 19 | 20 | export { FurnitureCard } -------------------------------------------------------------------------------- /07 Routing/Furniture/Components/NavLink.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | 3 | const NavLink = ({ attributes, text }, click) => 4 | click 5 | ? html`${text}` 6 | : html`${text}` 7 | 8 | export { NavLink } -------------------------------------------------------------------------------- /07 Routing/Furniture/Components/PageLayout.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | import { Header } from './Header.js' 3 | 4 | const PageLayout = (...children) => html` 5 | ${Header()} 6 | ${children}` 7 | 8 | export { PageLayout } -------------------------------------------------------------------------------- /07 Routing/Furniture/Readme.md: -------------------------------------------------------------------------------- 1 |

    Prerequisites:

    2 | 3 | - Node JS 4 | 5 | __This project loads Lit-html and Page JS from CDN so it does not need anything else__ 6 | 7 |

    Execution:

    8 | 9 | 1. __run node server.js while at the server (server) folder in the terminal__ 10 | 2. __run npx lite-server while in the root (Furniture) folder in the terminal__ 11 | 12 |
    Alternatively:
    13 | 14 | _If you don't want to or can't use IDE, you can do the same by navigating to the same 15 | folders in the normal Windows explorer, opening CMD in that directory and writing the same commands._ -------------------------------------------------------------------------------- /07 Routing/Furniture/Views/Dashboard.js: -------------------------------------------------------------------------------- 1 | import { html } from 'https://unpkg.com/lit-html?module' 2 | import { furniture } from '../requests/requests.js' 3 | import { FurnitureCard } from '../Components/FurnitureCard.js' 4 | 5 | const Dashboard = (items) => { 6 | document.title = 'Dashboard' 7 | 8 | return html` 9 |
    10 |
    11 |
    12 |

    Welcome to Furniture System

    13 |

    Select furniture from the catalog to view details.

    14 |
    15 |
    16 |
    17 | ${items.map(x => FurnitureCard(x))} 18 |
    ` 19 | } 20 | 21 | export { Dashboard } -------------------------------------------------------------------------------- /07 Routing/Furniture/images/chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/07 Routing/Furniture/images/chair.jpg -------------------------------------------------------------------------------- /07 Routing/Furniture/images/sofa.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/07 Routing/Furniture/images/sofa.jpg -------------------------------------------------------------------------------- /07 Routing/Furniture/images/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/07 Routing/Furniture/images/table.png -------------------------------------------------------------------------------- /07 Routing/Furniture/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | Furniture 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /07 Routing/Furniture/requests/backendAPI.js: -------------------------------------------------------------------------------- 1 | const origin = 'http://localhost:3030' 2 | 3 | const createOptions = (method = 'GET', body) => { 4 | const options = { 5 | method, 6 | headers: {}, 7 | } 8 | const token = sessionStorage.getItem('accessToken') 9 | 10 | if (token) { 11 | options.headers['X-Authorization'] = token 12 | } 13 | if (body) { 14 | options.headers['Content-Type'] = 'application/json' 15 | options.body = JSON.stringify(body) 16 | } 17 | 18 | return options 19 | } 20 | 21 | const request = async (uri, options) => { 22 | const URI = uri[0] === '/' ? uri : `/${uri}` 23 | let response = {} 24 | 25 | try { 26 | response = await fetch(`${origin}${URI}`, options) 27 | } catch (e) { 28 | throw new Error(e) 29 | } 30 | 31 | if (! response.ok) { 32 | throw new Error(response.status) 33 | } 34 | 35 | try { 36 | return await response.json() 37 | } catch (e) { 38 | return response 39 | } 40 | } 41 | 42 | const fetches = { 43 | get: async (uri) => await request(uri, createOptions()), 44 | post: async (uri, body) => await request(uri, createOptions('POST', body)), 45 | put: async (uri, body) => await request(uri, createOptions('PUT', body)), 46 | delete: async (uri) => await request(uri, createOptions('DELETE')), 47 | } 48 | 49 | export { fetches } -------------------------------------------------------------------------------- /07 Routing/Furniture/requests/requests.js: -------------------------------------------------------------------------------- 1 | import { fetches } from './backendAPI.js' 2 | 3 | const user = { 4 | register: (body) => fetches.post('users/register', body), 5 | login: (body) => fetches.post('users/login', body), 6 | logout: () => fetches.get('users/logout'), 7 | } 8 | 9 | const furniture = { 10 | create: (body) => fetches.post('data/catalog', body), 11 | getAll: () => fetches.get('data/catalog'), 12 | details: (id) => fetches.get(`data/catalog/${id}`), 13 | update: (body, id) => fetches.put(`data/catalog/${id}`, body), 14 | delete: (id) => fetches.delete(`data/catalog/${id}`), 15 | my: (id) => fetches.get(`data/catalog?where=_ownerId%3D%22${id}%22`), 16 | } 17 | 18 | export { user, furniture } -------------------------------------------------------------------------------- /07 Routing/Furniture/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /07 Routing/Furniture/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /07 Routing/Furniture/src/contextAPI.js: -------------------------------------------------------------------------------- 1 | import { furniture } from '../requests/requests.js' 2 | 3 | const context = { 4 | storeAllFurniture: async (context, next) => { 5 | context.allFurniture = await furniture.getAll() 6 | next() 7 | }, 8 | storeFurnitureItem: async (context, next) => { 9 | context.currentItem = await furniture.details(context.params.id) 10 | context.currentItem.isOwn = context.currentItem._ownerId === sessionStorage.getItem('id') 11 | next() 12 | }, 13 | storeMyFurniture: async (context, next) => { 14 | const myId = sessionStorage.getItem('id') 15 | context.myFurniture = await furniture.my(myId) 16 | next() 17 | } 18 | } 19 | 20 | export { context } -------------------------------------------------------------------------------- /07 Routing/Furniture/src/helper.js: -------------------------------------------------------------------------------- 1 | const isUserLogged = () => sessionStorage.getItem('accessToken') ? true : false 2 | 3 | const createFormObject = (form) => { 4 | const formData = new FormData(form) 5 | 6 | return Object.fromEntries([...formData.entries()]) 7 | } 8 | 9 | export { isUserLogged, createFormObject } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Components/Footer.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Footer = () => html` 4 |
    5 | SoftUni © 2014-2021 6 |
    ` 7 | 8 | export { Footer } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Components/Header.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { user } from '../requests/requests.js' 3 | import { isUserLogged } from '../src/helper.js' 4 | import page from '../node_modules/page/page.mjs' 5 | 6 | const logout = async () => { 7 | try { 8 | await user.logout() 9 | } catch (e) { 10 | console.log(e) 11 | } 12 | 13 | sessionStorage.clear() 14 | page.redirect('/') 15 | } 16 | 17 | const NavLink = ({ route, text }) => 18 | route === 'javascript:void(0)' 19 | ? html`${text}` 20 | : html`${text}` 21 | 22 | 23 | const getHeaderLinks = (loggedIn) => { 24 | const linkObj = (route, text) => ({ route, text }) 25 | 26 | return loggedIn 27 | ? [ 28 | linkObj('/browse', 'Browse Teams'), 29 | linkObj('/myTeams', 'My Teams'), 30 | linkObj('javascript:void(0)', 'Logout'), 31 | ] : [ 32 | linkObj('/browse', 'Browse Teams'), 33 | linkObj('/login', 'Login'), 34 | linkObj('/register', 'Register'), 35 | ] 36 | } 37 | 38 | 39 | const Header = () => html` 40 |
    41 | 42 | 45 |
    ` 46 | 47 | export { Header } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Components/PageLayout.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { Header } from './Header.js' 3 | import { Footer } from './Footer.js' 4 | 5 | const PageLayout = (...children) => html` 6 | ${Header()} 7 |
    8 | ${children} 9 |
    10 | ${Footer()}` 11 | 12 | export { PageLayout } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/README.md: -------------------------------------------------------------------------------- 1 |

    Prerequisites:

    2 | 3 | - Node JS 4 | - lit-html 5 | - Page JS 6 | 7 |

    Execution:

    8 | 9 | 1. __run npm install while at the root(TeamManager) folder in terminal for lit-html and Page JS install__ 10 | 2. __run node server.js while at the server (server) folder in the terminal to run the Node JS server__ 11 | 3. __run npx lite-server while in the root (TeamManager) folder in the terminal, or use any server you like (http-server, live-server) etc.__ 12 | 13 |
    Alternatively:
    14 | 15 | _If you don't want to or can't use IDE, you can do the same by navigating to the same 16 | folders in the normal Windows explorer, opening CMD in that directory and writing the same commands._ -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Team manager task.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/Team manager task.docx -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Views/BrowseView.js: -------------------------------------------------------------------------------- 1 | import { html, nothing } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const TeamComponent = ({ _id, logoUrl, name, description, membersCount }) => html` 4 |
    5 | 6 |
    7 |

    ${name}

    8 |

    ${description}

    9 | ${membersCount} Member${membersCount === 1 ? nothing :'s'} 10 |
    See details
    11 |
    12 |
    ` 13 | 14 | const BrowseView = (isUserLogged, teams) => html` 15 |
    16 |
    17 |

    Team Browser

    18 |
    19 | 20 | ${isUserLogged ? html` 21 | ` : nothing} 24 | 25 | ${teams.map(x => TeamComponent(x))} 26 |
    ` 27 | 28 | export { BrowseView } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/Views/HomeView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { isUserLogged } from '../src/helper.js' 3 | 4 | const BtnComponent = (isUserLogged) => html` 5 | ${isUserLogged 6 | ? 'Browse Teams' 7 | : 'Sign Up Now'}` 8 | 9 | const HomeView = () => html` 10 |
    11 |
    12 | 13 |
    14 |

    Welcome to Team Manager!

    15 |

    Want to organize your peers? Create and manage a team for free.

    16 |

    Looking for a team to join? Browse our communities and find like-minded 17 | people!

    18 | ${BtnComponent(isUserLogged())} 19 |
    20 |
    21 |
    ` 22 | 23 | export { HomeView } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/assets/atat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/assets/atat.png -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/assets/hydrant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/assets/hydrant.png -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/assets/rocket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/assets/rocket.png -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/assets/team.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/assets/team.png -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Team Manager 10 | 11 | 12 | 13 |
    14 | 15 | -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TeamManager", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "isarray": { 8 | "version": "0.0.1", 9 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 10 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 11 | "dev": true 12 | }, 13 | "lit-html": { 14 | "version": "1.3.0", 15 | "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.3.0.tgz", 16 | "integrity": "sha512-0Q1bwmaFH9O14vycPHw8C/IeHMk/uSDldVLIefu/kfbTBGIc44KGH6A8p1bDfxUfHdc8q6Ct7kQklWoHgr4t1Q==", 17 | "dev": true 18 | }, 19 | "page": { 20 | "version": "1.11.6", 21 | "resolved": "https://registry.npmjs.org/page/-/page-1.11.6.tgz", 22 | "integrity": "sha512-P6e2JfzkBrPeFCIPplLP7vDDiU84RUUZMrWdsH4ZBGJ8OosnwFkcUkBHp1DTIjuipLliw9yQn/ZJsXZvarsO+g==", 23 | "dev": true, 24 | "requires": { 25 | "path-to-regexp": "~1.2.1" 26 | } 27 | }, 28 | "path-to-regexp": { 29 | "version": "1.2.1", 30 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.2.1.tgz", 31 | "integrity": "sha1-szcFwUAjTYc8hyHHuf2LVB7Tr/k=", 32 | "dev": true, 33 | "requires": { 34 | "isarray": "0.0.1" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TeamManager", 3 | "version": "1.0.0", 4 | "description": "

    Prerequisites:

    ", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "lit-html": "^1.3.0", 14 | "page": "^1.11.6" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/requests/backendAPI.js: -------------------------------------------------------------------------------- 1 | const origin = 'http://localhost:3030' 2 | 3 | const createOptions = (method = 'GET', body) => { 4 | const options = { 5 | method, 6 | headers: {}, 7 | } 8 | const token = sessionStorage.getItem('accessToken') 9 | 10 | if (token) { 11 | options.headers['X-Authorization'] = token 12 | } 13 | if (body) { 14 | options.headers['Content-Type'] = 'application/json' 15 | options.body = JSON.stringify(body) 16 | } 17 | 18 | return options 19 | } 20 | 21 | const request = async (uri, options) => { 22 | const URI = uri[0] === '/' ? uri : `/${uri}` 23 | let response = {} 24 | 25 | try { 26 | response = await fetch(`${origin}${URI}`, options) 27 | } catch (e) { 28 | throw new Error(e) 29 | } 30 | 31 | if (! response.ok) { 32 | throw new Error(response.status) 33 | } 34 | 35 | try { 36 | return await response.json() 37 | } catch (e) { 38 | return response 39 | } 40 | } 41 | 42 | const fetches = { 43 | get: async (uri) => await request(uri, createOptions()), 44 | post: async (uri, body) => await request(uri, createOptions('POST', body)), 45 | put: async (uri, body) => await request(uri, createOptions('PUT', body)), 46 | delete: async (uri) => await request(uri, createOptions('DELETE')), 47 | } 48 | 49 | export { fetches } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/requests/requests.js: -------------------------------------------------------------------------------- 1 | import { fetches } from './backendAPI.js' 2 | 3 | const user = { 4 | register: (body) => fetches.post('users/register', body), 5 | login: (body) => fetches.post('users/login', body), 6 | logout: () => fetches.get('users/logout'), 7 | } 8 | 9 | const teams = { 10 | getAll: () => fetches.get('/data/teams'), 11 | getAllMembers: () => fetches.get('/data/members?where=status%3D%22member%22'), 12 | createTeam: (body) => fetches.post('/data/teams', body), 13 | updateTeam: (id, body) => fetches.put(`/data/teams/${id}`, body), 14 | getTeam: (id) => fetches.get(`/data/teams/${id}`), 15 | becomeMember: body => fetches.post('/data/members', body), 16 | cancelRequest: id => fetches.delete(`/data/members/${id}`), 17 | approveRequest: (id, body) => fetches.put(`/data/members/${id}`, body), 18 | getAllTeamMembers: (teamId) => fetches.get(`/data/members?where=teamId%3D%22${teamId}%22&load=user%3D_ownerId%3Ausers`), 19 | getAllTeamsOfUser: (userId) => fetches.get(`/data/members?where=_ownerId%3D%22${userId}%22%20AND%20status%3D%22member%22&load=team%3DteamId%3Ateams`) 20 | } 21 | 22 | export { user, teams } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/server/data/messenger.json: -------------------------------------------------------------------------------- 1 | { 2 | "-LxHVtajG3N1sU714pVj": { 3 | "author": "Spami", 4 | "content": "Hello, are you there?" 5 | }, 6 | "-LxIDxC-GotWtf4eHwV8": { 7 | "author": "Garry", 8 | "content": "Yep, whats up :?" 9 | }, 10 | "-LxIDxPfhsNipDrOQ5g_": { 11 | "author": "Spami", 12 | "content": "How are you? Long time no see? :)" 13 | }, 14 | "-LxIE-dM_msaz1O9MouM": { 15 | "author": "George", 16 | "content": "Hello, guys! :))" 17 | }, 18 | "-LxLgX_nOIiuvbwmxt8w": { 19 | "author": "Spami", 20 | "content": "Hello, George nice to see you! :)))" 21 | } 22 | } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/server/data/phonebook.json: -------------------------------------------------------------------------------- 1 | { 2 | "2d5ae478-87c7-45fa-acf9-f04aa4724421": { 3 | "person": "Maya", 4 | "phone": "+1-555-7653", 5 | "_id": "2d5ae478-87c7-45fa-acf9-f04aa4724421" 6 | }, 7 | "6012c542-38e1-4660-ba40-1b109c40cb2f": { 8 | "person": "John", 9 | "phone": "+1-555-4986", 10 | "_id": "6012c542-38e1-4660-ba40-1b109c40cb2f" 11 | }, 12 | "d749a819-1e41-4c65-9ce2-7b429c4ebd0d": { 13 | "person": "Nicolle", 14 | "phone": "+1-555-9124", 15 | "_id": "d749a819-1e41-4c65-9ce2-7b429c4ebd0d" 16 | } 17 | } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/src/helper.js: -------------------------------------------------------------------------------- 1 | const isUserLogged = () => sessionStorage.getItem('accessToken') ? true : false 2 | 3 | const createFormObject = (form) => { 4 | const formData = new FormData(form) 5 | 6 | return Object.fromEntries([...formData.entries()]) 7 | } 8 | 9 | const saveUserInStorage = data => { 10 | sessionStorage.setItem('email', data.email) 11 | sessionStorage.setItem('username', data.username) 12 | sessionStorage.setItem('id', data._id) 13 | sessionStorage.setItem('accessToken', data.accessToken) 14 | 15 | return data 16 | } 17 | 18 | export { isUserLogged, createFormObject, saveUserInStorage } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/static/modal.css: -------------------------------------------------------------------------------- 1 | .overlay { 2 | /* display: none; */ 3 | background-color: rgba(100, 100, 100, 0.5); 4 | backdrop-filter: blur(5px); 5 | position: fixed; 6 | left: 0; 7 | top: 0; 8 | width: 100%; 9 | height: 100%; 10 | z-index: 100; 11 | } 12 | 13 | .modal { 14 | background-color: white; 15 | color: black; 16 | width: 500px; 17 | text-align: center; 18 | margin: auto; 19 | margin-top: 15vh; 20 | padding: 32px; 21 | } 22 | 23 | .modal p { 24 | margin-bottom: 32px; 25 | } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/static/site.css: -------------------------------------------------------------------------------- 1 | .hero { 2 | font-size: 125%; 3 | margin-top: 128px; 4 | } 5 | 6 | h2 { 7 | padding-bottom: 32px; 8 | } 9 | 10 | .tm-hero-col { 11 | margin-left: 314px; 12 | } 13 | 14 | .main-form label { 15 | display: block; 16 | margin: 16px auto; 17 | position: relative; 18 | } 19 | 20 | .main-form input[type="text"], .main-form input[type="password"] { 21 | padding: 4px 8px; 22 | display: block; 23 | width: 200px; 24 | position: absolute; 25 | top: 0; 26 | bottom: 0; 27 | right: 0; 28 | border: 1px solid #4f6457; 29 | } 30 | 31 | .main-form textarea { 32 | display: block; 33 | border: 1px solid #4f6457; 34 | width: 100%; 35 | resize: vertical; 36 | height: 300px; 37 | padding: 4px 8px; 38 | } 39 | 40 | .team-logo { 41 | width: 150px; 42 | height: 150px; 43 | margin: 32px; 44 | vertical-align: bottom; 45 | object-fit: contain; 46 | } 47 | 48 | .tm-preview { 49 | margin-left: 214px; 50 | padding: 32px; 51 | padding-left: 0; 52 | } 53 | 54 | .details { 55 | color: #999999; 56 | } 57 | 58 | .tm-members li { 59 | list-style: none; 60 | margin: 8px 0; 61 | } 62 | 63 | .clear { 64 | clear: both; 65 | } 66 | 67 | .action.tm-control { 68 | padding: 4px 8px; 69 | margin: 0 4px; 70 | } 71 | 72 | .error { 73 | text-align: center; 74 | color: red 75 | } -------------------------------------------------------------------------------- /08 Modular Applications/TeamManager/styles.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/08 Modular Applications/TeamManager/styles.css -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Components/Footer.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Footer = () => html` 4 |
    5 |

    Created by SoftUni Delivery Team

    6 |
    ` 7 | 8 | export { Footer } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Components/Notif.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Notif = (msg) => { 4 | return html` 5 |
    6 |
    7 | ${msg} 8 |
    9 |
    ` 10 | } 11 | 12 | export { Notif } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Components/PageLayout.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { Header } from './Header.js' 3 | import { Footer } from './Footer.js' 4 | 5 | const PageLayout = (...children) => html` 6 | ${Header()} 7 |
    8 | ${children} 9 |
    10 | ${Footer()}` 11 | 12 | export { PageLayout } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Meme-Longue_Условие.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/Meme-Longue_Условие.docx -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Views/AllMemesView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const SingleMemeComponent = ({ _id, title, imageUrl }) => { 4 | return html` 5 |
    6 |
    7 |
    8 |

    ${title}

    9 | meme-img 10 |
    11 |
    12 | Details 13 |
    14 |
    15 |
    ` 16 | } 17 | 18 | const AllMemesView = (memes) => { 19 | return html` 20 |
    21 |

    All Memes

    22 |
    23 | ${memes && memes.length !== 0 24 | ? memes.map(SingleMemeComponent) 25 | : html`

    No memes in database.

    `} 26 |
    27 |
    ` 28 | } 29 | 30 | export { AllMemesView } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Views/DetailsView.js: -------------------------------------------------------------------------------- 1 | import { html, nothing } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const DetailsView = ({ title, imageUrl, description, _id, _ownerId }) => { 4 | return html` 5 |
    6 |

    Meme Title: ${title} 7 | 8 |

    9 |
    10 |
    11 | meme-alt 12 |
    13 |
    14 |

    Meme Description

    15 |

    16 | ${description} 17 |

    18 | ${_ownerId === sessionStorage.getItem('id') 19 | ? html`Edit 20 | ` 21 | : nothing} 22 |
    23 |
    24 |
    ` 25 | } 26 | 27 | export { DetailsView } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Views/GuestHomeView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const GuestHomeView = () => { 4 | return html` 5 |
    6 |
    7 |

    Welcome To Meme Lounge

    8 | meme 9 |

    Login to see our memes right away!

    10 |
    11 | Login 12 | Register 13 |
    14 |
    15 |
    ` 16 | } 17 | 18 | export { GuestHomeView } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/Views/UserProfileView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const SingleMemeComponent = ({ title, imageUrl, _id }) => html` 4 |
    5 |

    ${title}

    6 | meme-img 7 | Details 8 |
    ` 9 | 10 | const UserProfileView = ({ username, email, memes, gender }) => { 11 | return html` 12 | ` 29 | } 30 | 31 | export { UserProfileView } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/1.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/2.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/3.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/4.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/6.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/female.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/female.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/male.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/male.png -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/images/welcome-meme.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/09 Exam Prep/MemeLounge/images/welcome-meme.jpg -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Meme Lounge 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meme-lounge", 3 | "version": "1.0.0", 4 | "description": "Meme Lounge Single Page Application", 5 | "main": "index.html", 6 | "scripts": { 7 | "test": "mocha tests", 8 | "start": "http-server -a localhost -p 3000 -P http://localhost:3000?" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "lit-html": "^1.3.0", 14 | "page": "^1.11.6" 15 | }, 16 | "devDependencies": { 17 | "chai": "^4.3.4", 18 | "http-server": "^0.12.3", 19 | "mocha": "^8.3.2", 20 | "playwright-chromium": "^1.9.2" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/requests/backendAPI.js: -------------------------------------------------------------------------------- 1 | const origin = 'http://localhost:3030' 2 | 3 | const createOptions = (method = 'GET', body) => { 4 | const options = { 5 | method, 6 | headers: {}, 7 | } 8 | const token = sessionStorage.getItem('accessToken') 9 | 10 | if (token) { 11 | options.headers['X-Authorization'] = token 12 | } 13 | if (body) { 14 | options.headers['Content-Type'] = 'application/json' 15 | options.body = JSON.stringify(body) 16 | } 17 | 18 | return options 19 | } 20 | 21 | const request = async (uri, options) => { 22 | const URI = uri[0] === '/' ? uri : `/${uri}` 23 | let response = {} 24 | 25 | try { 26 | response = await fetch(`${origin}${URI}`, options) 27 | } catch (e) { 28 | throw new Error(e) 29 | } 30 | 31 | if (! response.ok) { 32 | throw new Error(response.status) 33 | } 34 | 35 | try { 36 | return await response.json() 37 | } catch (e) { 38 | return response 39 | } 40 | } 41 | 42 | const fetches = { 43 | get: async (uri) => await request(uri, createOptions()), 44 | post: async (uri, body) => await request(uri, createOptions('POST', body)), 45 | put: async (uri, body) => await request(uri, createOptions('PUT', body)), 46 | delete: async (uri) => await request(uri, createOptions('DELETE')), 47 | } 48 | 49 | export { fetches } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/requests/requests.js: -------------------------------------------------------------------------------- 1 | import { fetches } from './backendAPI.js' 2 | 3 | const user = { 4 | register: (body) => fetches.post('users/register', body), 5 | login: (body) => fetches.post('users/login', body), 6 | logout: () => fetches.get('users/logout'), 7 | } 8 | 9 | const memes = { 10 | getAllMemes: () => fetches.get(`/data/memes?sortBy=_createdOn%20desc`), 11 | createMeme: ({ title, description, imageUrl }) => fetches.post( 12 | `/data/memes`, 13 | { title, description, imageUrl } 14 | ), 15 | getMeme: (id) => fetches.get(`/data/memes/${id}`), 16 | deleteMeme: (memeId) => fetches.delete(`/data/memes/${memeId}`), 17 | updateMeme: (memeId, body) => fetches.put(`/data/memes/${memeId}`, body), 18 | getAllUserMemes: (userId) => fetches.get(`/data/memes?where=_ownerId%3D%22${userId}%22&sortBy=_createdOn%20desc`) 19 | } 20 | 21 | export { user, memes } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/src/contextAPI.js: -------------------------------------------------------------------------------- 1 | import { GuestHomeView } from '../Views/GuestHomeView.js' 2 | import { AllMemesView } from '../Views/AllMemesView.js' 3 | import { memes } from '../requests/requests.js' 4 | 5 | const contextAPI = { 6 | pickHomePage: async (context, next) => { 7 | const allMemes = await memes.getAllMemes() 8 | 9 | context.homePage = sessionStorage.getItem('accessToken') 10 | ? () => AllMemesView(allMemes) 11 | : GuestHomeView 12 | 13 | next() 14 | }, 15 | storeAllMemes: async (context, next) => { 16 | context.allMemes = await memes.getAllMemes() 17 | next() 18 | }, 19 | storeMeme: async (context, next) => { 20 | context.meme = await memes.getMeme(context.params.id) 21 | next() 22 | }, 23 | storeUserData: async (context, next) => { 24 | context.user = { 25 | email: sessionStorage.getItem('email'), 26 | username: sessionStorage.getItem('username'), 27 | gender: sessionStorage.getItem('gender'), 28 | memes: await memes.getAllUserMemes(sessionStorage.getItem('id')) 29 | } 30 | next() 31 | } 32 | } 33 | 34 | export { contextAPI } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/src/helper.js: -------------------------------------------------------------------------------- 1 | import { render } from '../node_modules/lit-html/lit-html.js' 2 | import { PageLayout } from '../Components/PageLayout.js' 3 | 4 | const container = document.getElementById('container') 5 | const renderView = (view) => render(PageLayout(view), container) 6 | 7 | const isUserLogged = () => sessionStorage.getItem('accessToken') ? true : false 8 | 9 | const createFormObject = (form) => { 10 | const formData = new FormData(form) 11 | 12 | return Object.fromEntries([...formData.entries()]) 13 | } 14 | 15 | const saveUserInStorage = data => { 16 | sessionStorage.setItem('email', data.email) 17 | sessionStorage.setItem('username', data.username) 18 | sessionStorage.setItem('id', data._id) 19 | sessionStorage.setItem('accessToken', data.accessToken) 20 | sessionStorage.setItem('gender', data.gender) 21 | 22 | return data 23 | } 24 | 25 | const showNotification = (view, msg) => { 26 | renderView(view(msg)) 27 | 28 | setTimeout(() => renderView(view(msg)), 3000) 29 | } 30 | 31 | export { isUserLogged, createFormObject, saveUserInStorage, renderView, showNotification } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/footer.css: -------------------------------------------------------------------------------- 1 | .footer { 2 | position: fixed; 3 | left: 0; 4 | bottom: 0; 5 | width: 100%; 6 | background-color: #333333; 7 | color: white; 8 | text-align: center; 9 | } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/my-memes.css: -------------------------------------------------------------------------------- 1 | .meme-listings { 2 | width: 86%; 3 | height: 100%; 4 | display: flex; 5 | flex-wrap: wrap; 6 | margin: auto; 7 | } 8 | 9 | .my-meme { 10 | width: 25%; 11 | } 12 | 13 | .my-meme>img { 14 | margin: auto; 15 | display: block; 16 | width: 100%; 17 | cursor: pointer; 18 | } 19 | 20 | .meme-title { 21 | font-size: 30px; 22 | text-decoration: none; 23 | color: black; 24 | } 25 | 26 | .meme-title:hover { 27 | color: #4438ea; 28 | } 29 | 30 | #container>div.my-memes>div>div>div { 31 | padding-top: 20px; 32 | } 33 | 34 | .my-meme-btn { 35 | margin-top: 15px; 36 | background-color: blue; 37 | color: white; 38 | padding: 16px 20px; 39 | margin: 8px 0; 40 | border: none; 41 | cursor: pointer; 42 | width: 50%; 43 | opacity: 0.9; 44 | } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/navigation.css: -------------------------------------------------------------------------------- 1 | nav { 2 | background-color: #333; 3 | overflow: hidden; 4 | } 5 | 6 | 7 | /* Style the links inside the navigation bar */ 8 | 9 | nav a, nav span { 10 | float: left; 11 | color: #f2f2f2; 12 | text-align: center; 13 | padding: 14px 16px; 14 | text-decoration: none; 15 | font-size: 17px; 16 | } 17 | 18 | /* Change the color of links on hover */ 19 | 20 | nav a:hover { 21 | background-color: #ddd; 22 | color: black; 23 | } 24 | 25 | /* Add a color to the active/current link */ 26 | nav a, #common { 27 | float: left; 28 | } 29 | nav a.active { 30 | background-color: #0069d9; 31 | color: white; 32 | } 33 | 34 | .profile { 35 | float: right; 36 | } 37 | 38 | /* nav div.user { 39 | display: none; 40 | } */ -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/notifications.css: -------------------------------------------------------------------------------- 1 | #notifications { 2 | float: right; 3 | position: absolute; 4 | top: 0; 5 | right: 0; 6 | text-align: center; 7 | margin: 1em; 8 | } 9 | 10 | .notification { 11 | font-size: 1.5em; 12 | color: #ffffff; 13 | display: block; 14 | text-align: right; 15 | } 16 | 17 | .notification>span { 18 | display: inline-block; 19 | padding: 0.5em 2em 0.5em 2em; 20 | border-radius: 10px; 21 | } 22 | 23 | #loadingBox>span { 24 | background: #7CB3E9; 25 | } 26 | #infoBox>span { 27 | background: #393; 28 | } 29 | #errorBox>span { 30 | background: #F50; 31 | } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/site.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | body { 7 | font-family: 'Lato', sans-serif; 8 | overflow-x: hidden; 9 | } 10 | 11 | img { 12 | box-shadow: 2px 5px 13px 0px #000000, 8px -15px 31px -12px rgb(0 0 0 / 0%); 13 | margin-bottom: 15px; 14 | } 15 | 16 | .container { 17 | width: 50%; 18 | margin: auto; 19 | } 20 | 21 | .container.signin { 22 | margin-top: 20px; 23 | } 24 | 25 | textarea { 26 | height: 80px; 27 | } -------------------------------------------------------------------------------- /09 Exam Prep/MemeLounge/style/styles.css: -------------------------------------------------------------------------------- 1 | @import './navigation.css'; 2 | @import './site.css'; 3 | @import './welcome.css'; 4 | @import './notifications.css'; 5 | @import './login-register.css'; 6 | @import './meme-feed.css'; 7 | @import './my-memes.css'; 8 | @import './meme-details.css'; 9 | @import './user-profile.css'; 10 | @import './footer.css'; 11 | -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/CarTube_Условие.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/10 Exam Prep 2/CarTube/CarTube_Условие.docx -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Components/Footer.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Footer = () => html` 4 |
    5 |

    © All rights reserved

    6 |
    ` 7 | 8 | export { Footer } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Components/Header.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { user } from '../requests/requests.js' 3 | import { isUserLogged } from '../src/helper.js' 4 | import page from '../node_modules/page/page.mjs' 5 | 6 | const logout = async () => { 7 | try { 8 | await user.logout() 9 | } catch (e) { 10 | console.log(e) 11 | } 12 | 13 | sessionStorage.clear() 14 | page.redirect('/') 15 | } 16 | 17 | const getHeaderLinks = (loggedIn) => { 18 | const username = sessionStorage.getItem('username') 19 | 20 | return loggedIn 21 | ? html` 22 | ` 28 | : html` 29 |
    30 | Login 31 | Register 32 |
    ` 33 | } 34 | 35 | const Header = () => html` 36 | ` 42 | 43 | export { Header } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Components/Listing.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const ListingComponent = ({ _id, brand, model, year, price, imageUrl }) => { 4 | 5 | return html` 6 |
    7 |
    8 | 9 |
    10 |

    ${brand} ${model}

    11 |
    12 |
    13 |

    Year: ${year}

    14 |

    Price: ${price} $

    15 |
    16 |
    17 | Details 18 |
    19 |
    20 |
    ` 21 | } 22 | 23 | export { ListingComponent } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Components/Notif.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const Notif = (msg) => { 4 | return html` 5 |
    6 |
    7 | ${msg} 8 |
    9 |
    ` 10 | } 11 | 12 | export { Notif } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Components/PageLayout.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { Header } from './Header.js' 3 | import { Footer } from './Footer.js' 4 | 5 | const PageLayout = (...children) => html` 6 | ${Header()} 7 |
    8 | ${children} 9 |
    10 | ${Footer()}` 11 | 12 | export { PageLayout } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Views/AllListingsView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { ListingComponent } from '../Components/Listing.js' 3 | 4 | 5 | const AllListingsView = (listings) => { 6 | return html` 7 |
    8 |

    Car Listings

    9 |
    10 | ${listings.length > 0 11 | ? listings.map(ListingComponent) 12 | : html`

    No cars in database.

    `} 13 |
    14 |
    ` 15 | } 16 | 17 | export { AllListingsView } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Views/ByYearView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | import { ListingComponent } from '../Components/Listing.js' 3 | import page from '../node_modules/page/page.mjs' 4 | 5 | const displayMatches = async () => { 6 | const year = document.getElementById('search-input').value 7 | 8 | page.redirect(`/byYear?year=${year}`) 9 | } 10 | 11 | const ByYearView = (matches, year) => { 12 | console.log(matches, year) 13 | 14 | return html` 15 |
    16 |

    Filter by year

    17 | 18 |
    19 | 21 | 23 |
    24 | 25 |

    Results:

    26 |
    27 | ${matches.length > 0 28 | ? matches.map(ListingComponent) 29 | : html`

    No results.

    `} 30 |
    31 |
    ` 32 | } 33 | 34 | export { ByYearView } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Views/HomePageView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const HomePageView = () => { 4 | 5 | return html` 6 |
    7 |
    8 |

    Welcome To Car Tube

    9 | carIntro 10 |

    To see all the listings click the link below:

    11 |
    12 | Listings 13 |
    14 |
    15 |
    ` 16 | } 17 | 18 | export { HomePageView } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/Views/MyListingsView.js: -------------------------------------------------------------------------------- 1 | import { html } from '../node_modules/lit-html/lit-html.js' 2 | 3 | const ListingComponent = ({ _id, imageUrl, brand, model, price, year }) => { 4 | 5 | return html` 6 |
    7 |
    8 | 9 |
    10 |

    ${brand} ${model}

    11 |
    12 |
    13 |

    Year: ${year}

    14 |

    Price: ${price} $

    15 |
    16 |
    17 | Details 18 |
    19 |
    20 |
    ` 21 | } 22 | 23 | const MyListingsView = (listings) => { 24 | 25 | return html` 26 |
    27 |

    My car listings

    28 |
    29 | ${listings.length > 0 30 | ? listings.map(ListingComponent) 31 | : html`

    You haven't listed any cars yet.

    `} 32 |
    33 |
    ` 34 | } 35 | 36 | export { MyListingsView } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/images/audia3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/10 Exam Prep 2/CarTube/images/audia3.jpg -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/images/benz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/10 Exam Prep 2/CarTube/images/benz.jpg -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/images/bmw.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/10 Exam Prep 2/CarTube/images/bmw.jpg -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/images/car-png.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/10 Exam Prep 2/CarTube/images/car-png.webp -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Car Tube 7 | 8 | 9 | 10 | 11 | 12 |
    13 | 14 | 15 | -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "car-tube", 3 | "version": "1.0.0", 4 | "description": "Car Tube Single Page Application", 5 | "main": "index.html", 6 | "scripts": { 7 | "test": "mocha tests/e2e.test.js", 8 | "start": "http-server -a localhost -p 3000 -P http://localhost:3000?" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "lit-html": "^1.3.0", 14 | "page": "^1.11.6" 15 | }, 16 | "devDependencies": { 17 | "http-server": "^0.12.3", 18 | "playwright-chromium": "^1.9.2", 19 | "mocha": "^8.3.2", 20 | "chai": "^4.3.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/requests/backendAPI.js: -------------------------------------------------------------------------------- 1 | const origin = 'http://localhost:3030' 2 | 3 | const createOptions = (method = 'GET', body) => { 4 | const options = { 5 | method, 6 | headers: {}, 7 | } 8 | const token = sessionStorage.getItem('accessToken') 9 | 10 | if (token) { 11 | options.headers['X-Authorization'] = token 12 | } 13 | if (body) { 14 | options.headers['Content-Type'] = 'application/json' 15 | options.body = JSON.stringify(body) 16 | } 17 | 18 | return options 19 | } 20 | 21 | const request = async (uri, options) => { 22 | const URI = uri[0] === '/' ? uri : `/${uri}` 23 | let response = {} 24 | 25 | try { 26 | response = await fetch(`${origin}${URI}`, options) 27 | } catch (e) { 28 | throw new Error(e) 29 | } 30 | 31 | if (! response.ok) { 32 | throw new Error(response.status) 33 | } 34 | 35 | try { 36 | return await response.json() 37 | } catch (e) { 38 | return response 39 | } 40 | } 41 | 42 | const fetches = { 43 | get: async (uri) => await request(uri, createOptions()), 44 | post: async (uri, body) => await request(uri, createOptions('POST', body)), 45 | put: async (uri, body) => await request(uri, createOptions('PUT', body)), 46 | delete: async (uri) => await request(uri, createOptions('DELETE')), 47 | } 48 | 49 | export { fetches } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/requests/requests.js: -------------------------------------------------------------------------------- 1 | import { fetches } from './backendAPI.js' 2 | 3 | const user = { 4 | register: (body) => fetches.post('users/register', body), 5 | login: (body) => fetches.post('users/login', body), 6 | logout: () => fetches.get('users/logout'), 7 | } 8 | 9 | const cars = { 10 | getAllListings: () => fetches.get('/data/cars?sortBy=_createdOn%20desc'), 11 | createListing: ({ 12 | brand, 13 | model, 14 | description, 15 | year, 16 | imageUrl, 17 | price 18 | } 19 | ) => fetches.post('/data/cars', { 20 | brand, 21 | model, 22 | description, 23 | year, 24 | imageUrl, 25 | price 26 | } 27 | ), 28 | updateListing: (id, { 29 | brand, 30 | model, 31 | description, 32 | year, 33 | imageUrl, 34 | price 35 | } 36 | ) => fetches.put(`/data/cars/${id}`, { 37 | brand, 38 | model, 39 | description, 40 | year, 41 | imageUrl, 42 | price 43 | } 44 | ), 45 | getCurrentListing: (id) => fetches.get(`/data/cars/${id}`), 46 | deleteListing: (id) => fetches.delete(`/data/cars/${id}`), 47 | getSearchResults: (year) => fetches.get(`/data/cars?where=year%3D${year}`), 48 | getUserListings: (userId) => fetches.get(`/data/cars?where=_ownerId%3D%22${userId}%22&sortBy=_createdOn%20desc`), 49 | } 50 | 51 | export { user, cars } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/src/contextAPI.js: -------------------------------------------------------------------------------- 1 | import { cars, user } from '../requests/requests.js' 2 | 3 | const contextAPI = { 4 | loadAllListings: async (context, next) => { 5 | context.allListings = await cars.getAllListings() 6 | next() 7 | }, 8 | storeListing: async (context, next) => { 9 | context.currentListing = await cars.getCurrentListing(context.params.id) 10 | next() 11 | }, 12 | storeUserListings: async (context, next) => { 13 | const userId = sessionStorage.getItem('id') 14 | context.userListings = await cars.getUserListings(userId) 15 | next() 16 | }, 17 | storeSearchResults: async (context, next) => { 18 | console.log(context) 19 | const year = context.querystring === '' ? '' : context.querystring.split('=')[1] || '' 20 | context.searchResults = year !== '' ? await cars.getSearchResults(year) : [] 21 | context.year = year 22 | next() 23 | } 24 | } 25 | 26 | export { contextAPI } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/src/helper.js: -------------------------------------------------------------------------------- 1 | import { render } from '../node_modules/lit-html/lit-html.js' 2 | import { PageLayout } from '../Components/PageLayout.js' 3 | 4 | const container = document.getElementById('container') 5 | const renderView = (view) => render(PageLayout(view), container) 6 | 7 | const isUserLogged = () => sessionStorage.getItem('accessToken') ? true : false 8 | 9 | const createFormObject = (form) => { 10 | const formData = new FormData(form) 11 | 12 | return Object.fromEntries([...formData.entries()]) 13 | } 14 | 15 | const saveUserInStorage = data => { 16 | sessionStorage.setItem('username', data.username) 17 | sessionStorage.setItem('id', data._id) 18 | sessionStorage.setItem('accessToken', data.accessToken) 19 | 20 | return data 21 | } 22 | 23 | const clearForm = (formObj) => { 24 | console.log(Object.values(formObj)) 25 | Object.values(formObj).forEach(x => x = '') 26 | } 27 | 28 | 29 | const showNotification = (view, msg) => { 30 | renderView(view(msg)) 31 | 32 | setTimeout(() => renderView(view(msg)), 3000) 33 | } 34 | 35 | export { 36 | isUserLogged, 37 | createFormObject, 38 | saveUserInStorage, 39 | renderView, 40 | showNotification, 41 | clearForm 42 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/car-listings.css: -------------------------------------------------------------------------------- 1 | .listings { 2 | margin: auto; 3 | text-align: center; 4 | } 5 | 6 | .listing { 7 | box-sizing: border-box; 8 | text-align: left; 9 | display: inline-block; 10 | padding: 30px 50px; 11 | width: 350px; 12 | margin: 15px; 13 | margin-bottom: 50px; 14 | border-radius: 8px; 15 | border: 2px solid black; 16 | } 17 | 18 | .listing h2 { 19 | height: 2.5em; 20 | } 21 | 22 | .preview { 23 | height: 150px; 24 | width: 250px; 25 | text-align: center; 26 | } 27 | 28 | .preview>img { 29 | object-fit: contain; 30 | height: 150px; 31 | width: 250px; 32 | } 33 | 34 | .no-cars { 35 | margin: auto; 36 | font-size: 30px; 37 | text-align: center; 38 | } 39 | 40 | .data-info { 41 | margin-top: 8px; 42 | } 43 | 44 | h3 { 45 | font-size: 20px; 46 | } 47 | 48 | .button-carDetails { 49 | background-color: #4caf50; 50 | border: none; 51 | color: white; 52 | padding: 10px; 53 | width: 100px; 54 | margin: 2px; 55 | text-align: center; 56 | text-decoration: none; 57 | display: inline-block; 58 | font-size: 16px; 59 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/listing-details.css: -------------------------------------------------------------------------------- 1 | .listing-props { 2 | margin-top: 16px; 3 | list-style: none; 4 | } 5 | 6 | .listing-props>li { 7 | font-size: 20px; 8 | } 9 | .listing-props>li>span { 10 | font-weight: 600; 11 | display: inline-block; 12 | width: 80px; 13 | } 14 | 15 | .listings-buttons { 16 | text-align: center; 17 | margin: auto; 18 | margin-top: 34px; 19 | } 20 | 21 | .button-list { 22 | cursor: pointer; 23 | background-color: #4caf50; 24 | border: none; 25 | color: white; 26 | margin: auto; 27 | padding: 11px 30px; 28 | text-align: center; 29 | text-decoration: none; 30 | display: inline-block; 31 | font-size: 16px; 32 | } 33 | 34 | .details-info { 35 | max-width: 700px; 36 | margin: auto; 37 | } 38 | 39 | .details-info>img { 40 | display: block; 41 | margin: auto; 42 | margin-bottom: 16px; 43 | max-height: 455px; 44 | } 45 | 46 | .description-para { 47 | margin-top: 16px; 48 | font-size: 16px; 49 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/login-register.css: -------------------------------------------------------------------------------- 1 | /* Add padding to containers */ 2 | 3 | .container { 4 | background-color: white; 5 | padding: 16px; 6 | text-align: center; 7 | width: 500px; 8 | margin: auto; 9 | } 10 | 11 | /* Full-width input fields */ 12 | 13 | input[type="text"], input[type="number"], input[type="password"] { 14 | padding: 15px; 15 | margin: 5px 0 22px 0; 16 | width: 100%; 17 | border: none; 18 | background: #f1f1f1; 19 | box-sizing: border-box; 20 | } 21 | 22 | input[type="text"]:focus, input[type="number"]:focus, input[type="password"]:focus { 23 | background-color: #ddd; 24 | outline: none; 25 | } 26 | 27 | /* Overwrite default styles of hr */ 28 | 29 | hr { 30 | border: 1px solid #f1f1f1; 31 | margin-bottom: 25px; 32 | } 33 | 34 | /* Set a style for the submit/register button */ 35 | 36 | .registerbtn { 37 | background-color: #4CAF50; 38 | color: white; 39 | padding: 16px 20px; 40 | margin: 8px 0; 41 | border: none; 42 | cursor: pointer; 43 | opacity: 0.9; 44 | } 45 | 46 | .registerbtn:hover { 47 | opacity: 1; 48 | } 49 | 50 | /* Add a blue text color to links */ 51 | 52 | a { 53 | color: dodgerblue; 54 | } 55 | 56 | /* Set a grey background color and center the text of the "sign in" section */ 57 | 58 | .signin { 59 | padding: 16px; 60 | background-color: #f1f1f1; 61 | text-align: center; 62 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/navigation.css: -------------------------------------------------------------------------------- 1 | nav { 2 | background-color: #333; 3 | overflow: hidden; 4 | } 5 | 6 | #profile, #guest { 7 | float: right; 8 | } 9 | 10 | /* Style the links inside the navigation bar */ 11 | 12 | nav a { 13 | float: left; 14 | color: #f2f2f2; 15 | text-align: center; 16 | padding: 14px 16px; 17 | text-decoration: none; 18 | font-size: 17px; 19 | } 20 | 21 | /* Change the color of links on hover */ 22 | 23 | nav a:hover { 24 | background-color: #ddd; 25 | color: black; 26 | } 27 | 28 | /* Add a color to the active/current link */ 29 | 30 | nav a.active { 31 | background-color: #4CAF50; 32 | color: white; 33 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/search.css: -------------------------------------------------------------------------------- 1 | .searchCars input { 2 | display: block; 3 | width: 400px; 4 | margin-right: auto; 5 | margin-left: auto; 6 | } 7 | 8 | .searchCars { 9 | width: 100vw; 10 | position: relative; 11 | 12 | display: flex; 13 | flex-flow: column wrap; 14 | align-items: center; 15 | margin-bottom: 20px; 16 | } 17 | -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/site.css: -------------------------------------------------------------------------------- 1 | * { 2 | padding: 0; 3 | margin: 0; 4 | } 5 | 6 | body { 7 | font-family: 'Lato', sans-serif; 8 | } 9 | 10 | footer { 11 | position: absolute; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | background-color: #333333; 16 | color: white; 17 | text-align: center; 18 | padding: 16px; 19 | } 20 | 21 | #container { 22 | box-sizing: border-box; 23 | min-height: 100vh; 24 | position: relative; 25 | padding-bottom: 64px; 26 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/styles.css: -------------------------------------------------------------------------------- 1 | @import "site.css"; 2 | @import "welcome.css"; 3 | @import "car-listings.css"; 4 | @import "login-register.css"; 5 | @import "navigation.css"; 6 | @import "listing-details.css"; 7 | @import "search.css"; 8 | 9 | -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/style/welcome.css: -------------------------------------------------------------------------------- 1 | #main { 2 | background-color: white; 3 | font-family: 'Lato', sans-serif; 4 | } 5 | 6 | h1 { 7 | text-align: center; 8 | margin-top: 30px; 9 | font-size: 50px; 10 | } 11 | 12 | h2 { 13 | text-align: center; 14 | } 15 | 16 | .button { 17 | background-color: #4CAF50; 18 | /* Green */ 19 | border: none; 20 | color: white; 21 | padding: 15px 32px; 22 | text-align: center; 23 | text-decoration: none; 24 | display: inline-block; 25 | font-size: 16px; 26 | margin: 5px; 27 | } 28 | 29 | #welcome-container { 30 | width: 50%; 31 | margin: auto; 32 | text-align: center; 33 | } 34 | 35 | .hero { 36 | margin: 40px; 37 | max-width: 240px; 38 | } 39 | 40 | #button-div { 41 | padding-top: 10px; 42 | width: 37%; 43 | margin: auto; 44 | display: flex; 45 | } -------------------------------------------------------------------------------- /10 Exam Prep 2/CarTube/tests/mock-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "_id": "0001", 5 | "username": "Peter", 6 | "password": "123456", 7 | "accessToken": "AAAA" 8 | }, 9 | { 10 | "_id": "0002", 11 | "username": "John", 12 | "password": "123456", 13 | "accessToken": "BBBB" 14 | } 15 | ], 16 | "catalog": [ 17 | { 18 | "_id": "1001", 19 | "_ownerId": "0001", 20 | "brand": "brand1", 21 | "model": "model1", 22 | "description": "description1", 23 | "year": 2011, 24 | "imageUrl": "/images/1.png", 25 | "price": 1000 26 | }, 27 | { 28 | "_id": "1002", 29 | "_ownerId": "0001", 30 | "brand": "brand2", 31 | "model": "model2", 32 | "description": "description2", 33 | "year": 2012, 34 | "imageUrl": "/images/2.png", 35 | "price": 2000 36 | }, 37 | { 38 | "_id": "1003", 39 | "_ownerId": "0002", 40 | "brand": "brand3", 41 | "model": "model3", 42 | "description": "description3", 43 | "year": 2013, 44 | "imageUrl": "/images/3.png", 45 | "price": 3000 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /applications_javascript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/silverster0113/JS-Applications-February-2021/878573b5a22907f709083ce25dfcd511dcb78cce/applications_javascript.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-applications", 3 | "version": "1.0.0", 4 | "description": "Major Part of JS Applications Feb 2021 Lab and Exercises as well as Exams.", 5 | "main": "index.js", 6 | "dependencies": { 7 | "http-server": "^0.12.3", 8 | "lite-server": "^2.6.1", 9 | "sloc": "^0.2.1" 10 | }, 11 | "devDependencies": { 12 | "chai": "^4.3.4", 13 | "lit-html": "^1.3.0", 14 | "mocha": "^8.3.2", 15 | "playwright-chromium": "^1.9.2" 16 | }, 17 | "scripts": { 18 | "test": "echo \"Error: no test specified\" && exit 1" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/Sineastra/JS-Applications-February-2021.git" 23 | }, 24 | "author": "", 25 | "license": "ISC", 26 | "bugs": { 27 | "url": "https://github.com/Sineastra/JS-Applications-February-2021/issues" 28 | }, 29 | "homepage": "https://github.com/Sineastra/JS-Applications-February-2021#readme", 30 | "keywords": [] 31 | } 32 | --------------------------------------------------------------------------------