From c8a4158fdda2c5fc0d617e729713fb1ab135188f Mon Sep 17 00:00:00 2001 From: Maaxym Date: Sat, 18 Aug 2018 11:59:41 +0300 Subject: [PATCH 01/10] only one index.html. all pages in own class. class fetcher for getting data from server. --- phone-book/add-user.html | 19 ----- phone-book/edit-contact.html | 20 ----- phone-book/index.html | 9 ++- phone-book/keypad.html | 20 ----- phone-book/node.js | 23 ++++++ phone-book/src/add-user.js | 59 ++------------ phone-book/src/app.js | 142 +++++++++++++++++++++++++++++++++ phone-book/src/contacts.js | 141 +++++++++++++------------------- phone-book/src/edit-contact.js | 69 ++-------------- phone-book/src/fetcher.js | 18 +++++ phone-book/src/keypad.js | 91 ++++----------------- phone-book/src/user.js | 61 ++------------ phone-book/user.html | 19 ----- 13 files changed, 282 insertions(+), 409 deletions(-) delete mode 100644 phone-book/add-user.html delete mode 100644 phone-book/edit-contact.html delete mode 100644 phone-book/keypad.html create mode 100644 phone-book/node.js create mode 100644 phone-book/src/app.js create mode 100644 phone-book/src/fetcher.js delete mode 100644 phone-book/user.html diff --git a/phone-book/add-user.html b/phone-book/add-user.html deleted file mode 100644 index 85318fb..0000000 --- a/phone-book/add-user.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - Add contact - - - - - - -
- - - - - \ No newline at end of file diff --git a/phone-book/edit-contact.html b/phone-book/edit-contact.html deleted file mode 100644 index 6b40b9c..0000000 --- a/phone-book/edit-contact.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Edit contact - - - - - - -
- - - - - - \ No newline at end of file diff --git a/phone-book/index.html b/phone-book/index.html index f73af15..0916e6e 100644 --- a/phone-book/index.html +++ b/phone-book/index.html @@ -11,9 +11,16 @@ -
+
+ + + + + + + diff --git a/phone-book/keypad.html b/phone-book/keypad.html deleted file mode 100644 index 2a79847..0000000 --- a/phone-book/keypad.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - Keypad - - - - - - - -
- - - - - \ No newline at end of file diff --git a/phone-book/node.js b/phone-book/node.js new file mode 100644 index 0000000..045ac87 --- /dev/null +++ b/phone-book/node.js @@ -0,0 +1,23 @@ +const http = require('http'); +const fs = require('fs'); +const port = 3000; + +http.createServer( (request, response) =>{ + let path = request.url; + if(path == '/'){ + path = '/index.html'; + } + let source = ''; + if (fs.existsSync('.' + path)) { + source = fs.readFileSync('.' + path); + }else{ + source = 'no such resource'; + response.statusCode = 404; + } + response.end(source); +}).listen(port, (err) => { + if (err) { + return console.log('something bad happened', err); + } + console.log(`server is listening on ${port}`) +}) diff --git a/phone-book/src/add-user.js b/phone-book/src/add-user.js index c9787ac..b392963 100644 --- a/phone-book/src/add-user.js +++ b/phone-book/src/add-user.js @@ -1,25 +1,16 @@ class AddUser { - constructor(containerSelector) { - this.container = document.body.querySelector(containerSelector); - this.pageName = 'Keypad'; - this.users = users; + constructor(appContainer) { + this.appContainer = appContainer; } - createHeaderSource(){ - return ` -
-
-

${this.pageName}

-
-
- `; + initEvents(){ + } - createMainSource(){ + render(){ return ` -
@@ -87,46 +78,6 @@ class AddUser {
-
- `; - } - - _createFooterIcon(iconData){ - return ` - - - ${iconData.title} - ` - } - - createFooterSource(){ - return ` - `; } - createPhoneSource(){ - return ` - ${this.createHeaderSource()} - ${this.createMainSource()} - ${this.createFooterSource()} - `; - } - - render(){ - const phoneSource = this.createPhoneSource(); - this.container.innerHTML = phoneSource; - } } - -const addUser = new AddUser('.container-holder'); -addUser.render(); \ No newline at end of file diff --git a/phone-book/src/app.js b/phone-book/src/app.js new file mode 100644 index 0000000..bed7d51 --- /dev/null +++ b/phone-book/src/app.js @@ -0,0 +1,142 @@ +class App { + constructor(appContainerId) { + this.pageName = 'Contacts'; + this.appContainer = document.getElementById(appContainerId); + this.pages = { + contacts : new Contacts(this.appContainer), + keypad : new Keypad(this.appContainer), + editContact : new EditContact(this.appContainer), + user : new User(this.appContainer), + addUser : new AddUser(this.appContainer), + } + this.activePage = "contacts"; + + const appHtml = this.renderAppContainer(); + this.appContainer.innerHTML = appHtml; + this.currentPage = this.pages.contacts; + this.initRouter(); + this.changePageTo(this.activePage); + + } + + changePageTo(newPageName){ + this.currentPage = this.pages[newPageName]; + this.insertCurrentPage(); + this.initPageEventListeners(); + } + + initPageEventListeners(){ + this.currentPage.initEvents(); + } + initRouter(){ + window.history.pushState({currentPage:this.activePage},'', '/index.html'); + const tabs = this.appContainer.querySelectorAll("a.tab"); + tabs.forEach( link => { + const href = link.href; + link.addEventListener('click', (event) =>{ + event.preventDefault(); + this.activePage = event.currentTarget.getAttribute("data-page"); + this.changePageTo(this.activePage); + window.history.pushState({currentPage:this.activePage},'', href); + }); + }); + window.addEventListener('popstate', event => { + this.changePageTo(event.state.currentPage); + }); + } + renderAppContainer(){ + return ` + ${this.renderAppHead()} + ${this.renderAppPage()} + ${this.renderAppFooter()} + `; + } + + renderAppHead(){ + return ` +
+
+

${this.pageName}

+
+
+ `; + } + + renderAppFooter(){ + return ` + + `; + } + renderAppPage(){ + return ` +
+
+ `; + // ${this.renderCurrentPage()} + } + + insertCurrentPage(){ + const placeForPage = this.appContainer.querySelector('main'); + placeForPage.innerHTML = this.renderCurrentPage(); + } + + renderCurrentPage(){ + return this.currentPage.render(); + } + + _createFooterIcon(iconData){ + return ` + + + ${iconData.title} + ` + } + + initializeRouter() { + /* + * 1) Если обновлять контент внутри тэга + * 2) + * + * */ + mountNode.innerHTML = ` +
+
+ +
+ `; + this.initializeRouterHandlers(); + this.appDOMNode = mountNode.getElementById('app'); + } + + renderNewPage() { + this.appDOMNode.innerHTML = this.pages[activePage].render(); + } + + updateView() { + this.pages[activePage].updateState(this.state); + } + + render() { + const { + activePage, + } = this.state; + + this.updateView(); + this.pages[activePage].render(); + } +} +const app = new App('app'); \ No newline at end of file diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index 2ff8c8c..1c28523 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -1,39 +1,54 @@ - - class Contacts { - constructor(containerSelector) { - this.container = document.body.querySelector(containerSelector); + constructor(appContainer) { this.pageName = 'Contacts'; - this.users = users; - this.usersOrderDirection = 'asc'; - this.container.addEventListener('click', (event) => { + this.users = []; + this.usersOrderDirection = 'asc'; + this.appContainer = appContainer; + } + + initEvents(){ + this.appContainer.querySelector("main > div.container").addEventListener('click', (event) => { if(event.target.nodeName === 'TH'){ let sortBy = event.target.getAttribute("data-name"); this.users = this.sortUsersBy(sortBy); this.usersOrderDirection = this.usersOrderDirection == 'asc' ? 'desc' : 'asc'; - this.insertListOfUsers(); + this.updateListOfUsers(); } - }); - - - + }); + this.initSearch(); + this.getListOfUsers(); } initSearch(){ document.getElementById('search').addEventListener('keyup', (event) => { - this.users = users; if(event.target.value !== ''){ this.users = this.findUser(event.target.value); } - this.insertListOfUsers(); + this.updateListOfUsers(); }); } + + getListOfUsers(){ + if(this.users.length != 0){ + return false; + } + let promisWithUsers = []; + const fetcher = new Fetcher(); + promisWithUsers.push(fetcher.getUsers()); + Promise.all(promisWithUsers).then( (users) => { + this.users = users[0]; + this.updateListOfUsers(); + }); + // return users; + } renderListOfUsers(){ return this.users.map( user => { + const name = user.fullName.split(' ')[0]; + const cname = user.fullName.split(' ')[1] || ''; return ` - ${user.name} - ${user.cname} + ${name} + ${cname} ${user.email} `; @@ -45,88 +60,49 @@ class Contacts { - - + + - + ${this.renderListOfUsers()}
NameLast nameNameLast name Email
`; } - insertListOfUsers(){ - const containerForList = this.container.querySelector('table > tbody'); + updateListOfUsers(){ + const containerForList = this.appContainer.querySelector('table > tbody'); containerForList.innerHTML = this.renderListOfUsers(); } - createHeaderSource(){ - return ` -
-
-

${this.pageName}

-
-
- `; - } - createMainSource(){ return ` -
-
-
-
- - -
-
- ${this.renderContactsList()} -
-
+
+
+
+ + +
+
+ ${this.renderContactsList()} +
`; } - _createFooterIcon(iconData){ - return ` - - - ${iconData.title} - ` - } - - createFooterSource(){ - return ` - - `; - } - createPhoneSource(){ - return ` - ${this.createHeaderSource()} - ${this.createMainSource()} - ${this.createFooterSource()} - `; - } - _cleanStringValue(name) { + + + cleanStringValue(name) { return name.toLowerCase().trim() } + sortUsersBy(prop) { const usersOrderDirection = this.usersOrderDirection == 'asc' ? 1 : -1; return this.users.sort((a, b) => { - const propA = this._cleanStringValue(a[prop]); - const propB = this._cleanStringValue(b[prop]); + const propA = this.cleanStringValue(a[prop]); + const propB = this.cleanStringValue(b[prop]); if (propA < propB) { return -1*usersOrderDirection; } @@ -137,12 +113,12 @@ class Contacts { }) } - findUser(value, prop) { const letFilterBy = user => { if(!prop){ - return user["name"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || - user["cname"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || + console.log(user); + return user["fullName"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || + user["fullName"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || user["email"].toLowerCase().indexOf(value.toLowerCase()) !== -1; } return user[prop].toLowerCase().indexOf(value.toLowerCase()) !== -1; @@ -151,12 +127,9 @@ class Contacts { } render(){ - const phoneSource = this.createPhoneSource(); - this.container.innerHTML = phoneSource; - this.insertListOfUsers(); - this.initSearch(); + return ` + ${this.createMainSource()} + ` } } -const contacts = new Contacts('.container-holder'); -contacts.render(); \ No newline at end of file diff --git a/phone-book/src/edit-contact.js b/phone-book/src/edit-contact.js index aee006f..797c560 100644 --- a/phone-book/src/edit-contact.js +++ b/phone-book/src/edit-contact.js @@ -1,36 +1,23 @@ - - class EditContact { - constructor(containerSelector) { - this.container = document.body.querySelector(containerSelector); - this.pageName = 'Edit Contact'; - this.users = users; - + constructor(appContainer) { + this.appContainer = appContainer; } - prepareEditableFields(){ - const editButtons = this.container.querySelectorAll('a.add-btn'); + + initEvents(){ + const editButtons = this.appContainer.querySelectorAll('a.add-btn'); editButtons.forEach(( value ) => { value.children[1].contentEditable = 'true'; }); - this.container.addEventListener('click', (event) => { + this.appContainer.addEventListener('click', (event) => { + event.preventDefault(); if( event.target.nodeName == 'A' && event.target.classList.contains('add-btn')){ event.target.children[1].backgroundColor = 'purple'; } }); } - createHeaderSource(){ - return ` -
-
-

${this.pageName}

-
-
- `; - } - createMainSource(){ + render(){ return ` -
#
@@ -96,47 +83,7 @@ class EditContact {
-
`; } - _createFooterIcon(iconData){ - return ` - - - ${iconData.title} - ` - } - - createFooterSource(){ - return ` - - `; - } - createPhoneSource(){ - return ` - ${this.createHeaderSource()} - ${this.createMainSource()} - ${this.createFooterSource()} - `; - } - - render(){ - const phoneSource = this.createPhoneSource(); - this.container.innerHTML = phoneSource; - this.prepareEditableFields(); - } } - -const editContact = new EditContact('.container-holder'); -editContact.render(); \ No newline at end of file diff --git a/phone-book/src/fetcher.js b/phone-book/src/fetcher.js new file mode 100644 index 0000000..76c6415 --- /dev/null +++ b/phone-book/src/fetcher.js @@ -0,0 +1,18 @@ +class Fetcher{ + constructor(){ + this.url = 'http://easycode-js.herokuapp.com/mamax' + } + getUsers(){ + return fetch(this.url) + .then( response => { + return response.json(); + }) + .then(parsedResponse => { + return parsedResponse.users; + }) + .catch( alert => { + // console.error(alert); + }); + + } +} diff --git a/phone-book/src/keypad.js b/phone-book/src/keypad.js index 9f7400b..a156eec 100644 --- a/phone-book/src/keypad.js +++ b/phone-book/src/keypad.js @@ -1,26 +1,27 @@ - - class Keypad { - constructor(containerSelector) { - this.container = document.body.querySelector(containerSelector); - this.pageName = 'Keypad'; - this.users = users; + constructor(appContainer) { this.currentNumber = ''; - this.container.addEventListener('click', (event) => { + this.appContainer = appContainer; + } + + initEvents(){ + this.appContainer.querySelector("main > div.container").addEventListener('click', (event) => { this.detectClickedNumber(event); - }); + }); - this.container.addEventListener('click', (event) => { + this.appContainer.querySelector("main > div.container").addEventListener('click', (event) => { if(event.target.nodeName === 'SPAN' && event.target.classList.contains('delete-number')){ this.deleteDigitFromNumber(); } }); - document.addEventListener('keyup', (event) => { + + document.addEventListener('keydown', (event) => { this.updateNumbersField(event.key); if(event.keyCode == 8 ){ this.deleteDigitFromNumber(); } - }); + }); + } deleteDigitFromNumber(){ @@ -40,7 +41,7 @@ class Keypad { this.currentNumber += number; } const formatedNumber = this.formatformNumber(this.currentNumber); - this.container.querySelector('main span.numbers').innerHTML = formatedNumber + this.appContainer.querySelector('main span.numbers').innerHTML = formatedNumber } formatformNumber(number) { @@ -66,35 +67,13 @@ class Keypad { } return res }); - /* - if(number.length > 0){ - if(number.length < 3){ - res = `(${number}`; - }else if (number.length < 6) { - res = number.replace(/(\d{3})(\d{0,2})/, '($1) $2'); - }else if (number.length < 8) { - res = number.replace(/(\d{3})(\d{0,2})(\d{0,2})/, '($1) $2-$3'); - }else{ - - } - - }*/ return formatedNumber; } - createHeaderSource(){ - return ` -
-
-

${this.pageName}

-
-
- `; - } + - createMainSource(){ + render(){ return ` -
@@ -117,46 +96,6 @@ class Keypad {
-
`; } - - _createFooterIcon(iconData){ - return ` - - - ${iconData.title} - ` - } - - createFooterSource(){ - return ` - - `; - } - createPhoneSource(){ - return ` - ${this.createHeaderSource()} - ${this.createMainSource()} - ${this.createFooterSource()} - `; - } - - render(){ - const phoneSource = this.createPhoneSource(); - this.container.innerHTML = phoneSource; - } } - -const keypad = new Keypad('.container-holder'); -keypad.render(); \ No newline at end of file diff --git a/phone-book/src/user.js b/phone-book/src/user.js index 782c2f5..35bbd6f 100644 --- a/phone-book/src/user.js +++ b/phone-book/src/user.js @@ -1,25 +1,16 @@ class User { - constructor(containerSelector) { - this.container = document.body.querySelector(containerSelector); - this.pageName = 'Keypad'; - this.users = users; + constructor(appContainer) { + this.appContainer = appContainer; } - createHeaderSource(){ - return ` -
-
-

${this.pageName}

-
-
- `; - } + initEvents(){ - createMainSource(){ + } + + render(){ return ` -
#
User Name
@@ -58,46 +49,6 @@ class User {
-
`; } - - _createFooterIcon(iconData){ - return ` - - - ${iconData.title} - ` - } - - createFooterSource(){ - return ` - - `; - } - createPhoneSource(){ - return ` - ${this.createHeaderSource()} - ${this.createMainSource()} - ${this.createFooterSource()} - `; - } - - render(){ - const phoneSource = this.createPhoneSource(); - this.container.innerHTML = phoneSource; - } } - -const user = new User('.container-holder'); -user.render(); \ No newline at end of file diff --git a/phone-book/user.html b/phone-book/user.html deleted file mode 100644 index 493a101..0000000 --- a/phone-book/user.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - User - - - - - - -
- - - - - \ No newline at end of file From c89689d4fa8f29d7182e310ec041a86eccb458e3 Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sat, 18 Aug 2018 12:56:29 +0300 Subject: [PATCH 02/10] http -> https --- phone-book/src/fetcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phone-book/src/fetcher.js b/phone-book/src/fetcher.js index 76c6415..751d1f2 100644 --- a/phone-book/src/fetcher.js +++ b/phone-book/src/fetcher.js @@ -1,6 +1,6 @@ class Fetcher{ constructor(){ - this.url = 'http://easycode-js.herokuapp.com/mamax' + this.url = 'https://easycode-js.herokuapp.com/mamax' } getUsers(){ return fetch(this.url) From 07609415bf0ac3f160f28f18b175c38e7407fe1c Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sat, 18 Aug 2018 22:11:48 +0300 Subject: [PATCH 03/10] router is separete class. But I think my variant is not very clever... --- phone-book/index.html | 1 + phone-book/src/app.js | 32 +++++++++++--------------------- phone-book/src/contacts.js | 28 +++++++++++++++++++++++++++- phone-book/src/fetcher.js | 18 ++++++++++++++++-- phone-book/src/main.css | 23 +---------------------- phone-book/src/router.js | 29 +++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 46 deletions(-) create mode 100644 phone-book/src/router.js diff --git a/phone-book/index.html b/phone-book/index.html index 0916e6e..d93b244 100644 --- a/phone-book/index.html +++ b/phone-book/index.html @@ -14,6 +14,7 @@
+ diff --git a/phone-book/src/app.js b/phone-book/src/app.js index bed7d51..c622eb8 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -1,6 +1,6 @@ class App { constructor(appContainerId) { - this.pageName = 'Contacts'; + this.state = {} this.appContainer = document.getElementById(appContainerId); this.pages = { contacts : new Contacts(this.appContainer), @@ -9,13 +9,18 @@ class App { user : new User(this.appContainer), addUser : new AddUser(this.appContainer), } - this.activePage = "contacts"; + + this.state.pageName = 'Contacts' + this.state.activePage = "contacts"; const appHtml = this.renderAppContainer(); this.appContainer.innerHTML = appHtml; - this.currentPage = this.pages.contacts; - this.initRouter(); - this.changePageTo(this.activePage); + + this.router = new Router(this); + + // this.currentPage = this.pages.contacts; + // this.initRouter(); + // this.changePageTo(this.activePage); } @@ -28,22 +33,7 @@ class App { initPageEventListeners(){ this.currentPage.initEvents(); } - initRouter(){ - window.history.pushState({currentPage:this.activePage},'', '/index.html'); - const tabs = this.appContainer.querySelectorAll("a.tab"); - tabs.forEach( link => { - const href = link.href; - link.addEventListener('click', (event) =>{ - event.preventDefault(); - this.activePage = event.currentTarget.getAttribute("data-page"); - this.changePageTo(this.activePage); - window.history.pushState({currentPage:this.activePage},'', href); - }); - }); - window.addEventListener('popstate', event => { - this.changePageTo(event.state.currentPage); - }); - } + renderAppContainer(){ return ` ${this.renderAppHead()} diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index 1c28523..a50cbdc 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -17,8 +17,33 @@ class Contacts { }); this.initSearch(); this.getListOfUsers(); + this.initClickOnUser() } + showUserPage(id){ + let promisWithUsers = []; + const fetcher = new Fetcher(); + promisWithUsers.push(fetcher.getUser(id)); + Promise.all(promisWithUsers).then( (user) => { + console.log(user); + }); + } + + initClickOnUser(){ + this.appContainer.querySelector("main > div.container").addEventListener('click', event => { + const container = event.currentTarget; + let target = event.target; + while (target != container) { + if (target.nodeName == 'TR') { + const id = target.getAttribute("data-user_id"); + this.showUserPage(id); + return; + } + target = target.parentNode; + } + }); + + } initSearch(){ document.getElementById('search').addEventListener('keyup', (event) => { if(event.target.value !== ''){ @@ -45,8 +70,9 @@ class Contacts { return this.users.map( user => { const name = user.fullName.split(' ')[0]; const cname = user.fullName.split(' ')[1] || ''; + const id = user._id; return ` - + ${name} ${cname} ${user.email} diff --git a/phone-book/src/fetcher.js b/phone-book/src/fetcher.js index 751d1f2..044a72d 100644 --- a/phone-book/src/fetcher.js +++ b/phone-book/src/fetcher.js @@ -3,16 +3,30 @@ class Fetcher{ this.url = 'https://easycode-js.herokuapp.com/mamax' } getUsers(){ - return fetch(this.url) + return fetch(this.url + '/users') .then( response => { return response.json(); }) .then(parsedResponse => { - return parsedResponse.users; + return parsedResponse; }) .catch( alert => { // console.error(alert); }); } + getUser(id){ + return fetch(this.url + '/users/' + id) + .then( response => { + return response.json(); + }) + .then(parsedResponse => { + console.log(parsedResponse); + return parsedResponse; + }) + .catch( alert => { + // console.error(alert); + }); + + } } diff --git a/phone-book/src/main.css b/phone-book/src/main.css index d599d48..472af3d 100644 --- a/phone-book/src/main.css +++ b/phone-book/src/main.css @@ -1,25 +1,3 @@ -/** - * Description: main styles - * Version: 1.0.0 - * Last update: 09.01.2017 - * Author: alex.maslennikova19@gmail.com - */ -/*$breakpoints: ( - 'screen-xs': 480px, - 'screen-sm': 768px, - 'screen-md': 992px, - 'screen-lg': 1200px -); -// keywords -$media-expressions: ( - 'screen': 'screen', - 'print': 'print', - 'handheld': 'handheld', - 'landscape': '(orientation: landscape)', - 'portrait': '(orientation: portrait)', - 'retina2x': '(-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi)', - 'retina3x': '(-webkit-min-device-pixel-ratio: 2.5), (min-resolution: 240dpi)' -);*/ .clearfix:after { content: ''; display: table; @@ -157,6 +135,7 @@ h3 { display: table; width: 100%; table-layout: fixed; + cursor: pointer; } .table > thead > tr > th { diff --git a/phone-book/src/router.js b/phone-book/src/router.js new file mode 100644 index 0000000..84768fd --- /dev/null +++ b/phone-book/src/router.js @@ -0,0 +1,29 @@ +class Router { + constructor(app){ + this.setHref(app,'/index.html'); + const tabs = app.appContainer.querySelector("nav.main-nav"); + tabs.addEventListener('click', (event) => { + event.preventDefault(); + const container = event.currentTarget; + let target = event.target; + while (target != container) { + if (target.nodeName == 'A' && target.classList.contains('tab') ) { + const href = target.href; + app.state.activePage = target.getAttribute("data-page"); + this.setHref(app,href); + return; + } + target = target.parentNode; + } + }); + window.addEventListener('popstate', event => { + app.changePageTo(event.state.currentPage); + }); + } + + setHref(app,href){ + window.history.pushState({currentPage:app.state.activePage},'', href); + app.changePageTo(app.state.activePage); + } + +} \ No newline at end of file From 23f8556043a36ad58aaf29e4b2dbaf9e615844a4 Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sat, 18 Aug 2018 23:00:00 +0300 Subject: [PATCH 04/10] router is two function. Just changing url and state --- phone-book/node.js | 4 +- phone-book/src/app.js | 83 ++++++++++++++------------------------ phone-book/src/contacts.js | 11 +++-- phone-book/src/router.js | 25 +++--------- 4 files changed, 46 insertions(+), 77 deletions(-) diff --git a/phone-book/node.js b/phone-book/node.js index 045ac87..b8d19d9 100644 --- a/phone-book/node.js +++ b/phone-book/node.js @@ -4,9 +4,11 @@ const port = 3000; http.createServer( (request, response) =>{ let path = request.url; - if(path == '/'){ + if(path.indexOf('html') != -1 || path == '/'){ path = '/index.html'; } + // path = '/index.html'; + let source = ''; if (fs.existsSync('.' + path)) { source = fs.readFileSync('.' + path); diff --git a/phone-book/src/app.js b/phone-book/src/app.js index c622eb8..d3f0645 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -1,37 +1,53 @@ class App { constructor(appContainerId) { - this.state = {} + this.state = {}; this.appContainer = document.getElementById(appContainerId); + this.router = new Router(this); this.pages = { - contacts : new Contacts(this.appContainer), + contacts : new Contacts(this), keypad : new Keypad(this.appContainer), editContact : new EditContact(this.appContainer), user : new User(this.appContainer), addUser : new AddUser(this.appContainer), } - - this.state.pageName = 'Contacts' - this.state.activePage = "contacts"; const appHtml = this.renderAppContainer(); this.appContainer.innerHTML = appHtml; + this.addRouterToFooter(); - this.router = new Router(this); - - // this.currentPage = this.pages.contacts; - // this.initRouter(); - // this.changePageTo(this.activePage); + this.state.pageName = 'Contacts'; + this.router.gotToPage('contacts','/index.html'); + this.changePageTo('contacts'); + } + addRouterToFooter(){ + const tabs = this.appContainer.querySelector("nav.main-nav"); + tabs.addEventListener('click', (event) => { + event.preventDefault(); + const container = event.currentTarget; + let target = event.target; + while (target != container) { + if (target.nodeName == 'A' && target.classList.contains('tab') ) { + const href = target.href; + const newPage = target.getAttribute("data-page"); + this.router.gotToPage(newPage,href); + this.changePageTo(newPage); + return; + } + target = target.parentNode; + } + }); } changePageTo(newPageName){ - this.currentPage = this.pages[newPageName]; + this.state.activePage = newPageName; + this.state.currentPage = this.pages[newPageName]; this.insertCurrentPage(); this.initPageEventListeners(); } initPageEventListeners(){ - this.currentPage.initEvents(); + this.state.currentPage.initEvents(); } renderAppContainer(){ @@ -72,7 +88,6 @@ class App {
`; - // ${this.renderCurrentPage()} } insertCurrentPage(){ @@ -80,8 +95,9 @@ class App { placeForPage.innerHTML = this.renderCurrentPage(); } - renderCurrentPage(){ - return this.currentPage.render(); + renderCurrentPage(){ + const currentPage = this.state.currentPage; + return currentPage.render(); } _createFooterIcon(iconData){ @@ -91,42 +107,5 @@ class App { ${iconData.title} ` } - - initializeRouter() { - /* - * 1) Если обновлять контент внутри тэга - * 2) - * - * */ - mountNode.innerHTML = ` -
-
- -
- `; - this.initializeRouterHandlers(); - this.appDOMNode = mountNode.getElementById('app'); - } - - renderNewPage() { - this.appDOMNode.innerHTML = this.pages[activePage].render(); - } - - updateView() { - this.pages[activePage].updateState(this.state); - } - - render() { - const { - activePage, - } = this.state; - - this.updateView(); - this.pages[activePage].render(); - } } const app = new App('app'); \ No newline at end of file diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index a50cbdc..e2f3ae8 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -1,9 +1,10 @@ class Contacts { - constructor(appContainer) { + constructor(app) { + this.app = app; + this.appContainer = app.appContainer; this.pageName = 'Contacts'; this.users = []; this.usersOrderDirection = 'asc'; - this.appContainer = appContainer; } initEvents(){ @@ -25,7 +26,7 @@ class Contacts { const fetcher = new Fetcher(); promisWithUsers.push(fetcher.getUser(id)); Promise.all(promisWithUsers).then( (user) => { - console.log(user); + }); } @@ -36,7 +37,9 @@ class Contacts { while (target != container) { if (target.nodeName == 'TR') { const id = target.getAttribute("data-user_id"); - this.showUserPage(id); + // this.showUserPage(id); + // this.app.router.setHref('user', '/user.html'); + console.log(id); return; } target = target.parentNode; diff --git a/phone-book/src/router.js b/phone-book/src/router.js index 84768fd..2c798b0 100644 --- a/phone-book/src/router.js +++ b/phone-book/src/router.js @@ -1,29 +1,14 @@ class Router { constructor(app){ - this.setHref(app,'/index.html'); - const tabs = app.appContainer.querySelector("nav.main-nav"); - tabs.addEventListener('click', (event) => { - event.preventDefault(); - const container = event.currentTarget; - let target = event.target; - while (target != container) { - if (target.nodeName == 'A' && target.classList.contains('tab') ) { - const href = target.href; - app.state.activePage = target.getAttribute("data-page"); - this.setHref(app,href); - return; - } - target = target.parentNode; - } - }); + window.addEventListener('popstate', event => { - app.changePageTo(event.state.currentPage); + // console.log(event.state); + app.changePageTo(event.state.activePage); }); } - setHref(app,href){ - window.history.pushState({currentPage:app.state.activePage},'', href); - app.changePageTo(app.state.activePage); + gotToPage(activePage,href){ + window.history.pushState({activePage:activePage},'', href); } } \ No newline at end of file From 62e735347b88a4b26d2163ca5be6b19d6ec56198 Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sat, 18 Aug 2018 23:50:41 +0300 Subject: [PATCH 05/10] fix: restored filter sorting after impleemtation of router --- phone-book/src/app.js | 24 +++++++++++++++--------- phone-book/src/contacts.js | 30 +++++++++++++++--------------- phone-book/src/router.js | 7 ++++--- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/phone-book/src/app.js b/phone-book/src/app.js index d3f0645..72fd055 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -16,10 +16,14 @@ class App { this.addRouterToFooter(); this.state.pageName = 'Contacts'; - this.router.gotToPage('contacts','/index.html'); - this.changePageTo('contacts'); + this.updateState({activePage : 'contacts'}); + this.router.gotToPage({activePage : 'contacts'},'/index.html'); + this.changePageToActive(); } + updateState(newState){ + Object.assign(this.state,newState); + } addRouterToFooter(){ const tabs = this.appContainer.querySelector("nav.main-nav"); tabs.addEventListener('click', (event) => { @@ -30,8 +34,9 @@ class App { if (target.nodeName == 'A' && target.classList.contains('tab') ) { const href = target.href; const newPage = target.getAttribute("data-page"); - this.router.gotToPage(newPage,href); - this.changePageTo(newPage); + this.updateState({activePage : newPage}); + this.router.gotToPage({activePage : newPage},href); + this.changePageToActive(); return; } target = target.parentNode; @@ -39,15 +44,15 @@ class App { }); } - changePageTo(newPageName){ - this.state.activePage = newPageName; - this.state.currentPage = this.pages[newPageName]; + changePageToActive(){ this.insertCurrentPage(); this.initPageEventListeners(); } initPageEventListeners(){ - this.state.currentPage.initEvents(); + const activePage = this.state.activePage; + const currentPage = this.pages[activePage]; + currentPage.initEvents(); } renderAppContainer(){ @@ -96,7 +101,8 @@ class App { } renderCurrentPage(){ - const currentPage = this.state.currentPage; + const activePage = this.state.activePage; + const currentPage = this.pages[activePage]; return currentPage.render(); } diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index e2f3ae8..5bbea60 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -13,11 +13,11 @@ class Contacts { let sortBy = event.target.getAttribute("data-name"); this.users = this.sortUsersBy(sortBy); this.usersOrderDirection = this.usersOrderDirection == 'asc' ? 'desc' : 'asc'; - this.updateListOfUsers(); + this.insertListOfUsersToApp(this.users); } }); - this.initSearch(); this.getListOfUsers(); + this.initSearch(); this.initClickOnUser() } @@ -35,11 +35,11 @@ class Contacts { const container = event.currentTarget; let target = event.target; while (target != container) { - if (target.nodeName == 'TR') { + if (target.nodeName == 'TR' && target.parentNode.nodeName == 'TBODY') { const id = target.getAttribute("data-user_id"); - // this.showUserPage(id); - // this.app.router.setHref('user', '/user.html'); - console.log(id); + this.app.updateState({activePage : 'user', userId : id }); + this.app.router.gotToPage({activePage : 'user', userId : id },'/user.html'); + this.app.changePageToActive(); return; } target = target.parentNode; @@ -49,10 +49,11 @@ class Contacts { } initSearch(){ document.getElementById('search').addEventListener('keyup', (event) => { + let filteredUsers = this.users; if(event.target.value !== ''){ - this.users = this.findUser(event.target.value); + filteredUsers = this.findUser(event.target.value); } - this.updateListOfUsers(); + this.insertListOfUsersToApp(filteredUsers); }); } @@ -65,12 +66,12 @@ class Contacts { promisWithUsers.push(fetcher.getUsers()); Promise.all(promisWithUsers).then( (users) => { this.users = users[0]; - this.updateListOfUsers(); + this.insertListOfUsersToApp(this.users); }); // return users; } - renderListOfUsers(){ - return this.users.map( user => { + renderListOfUsers(listOfUsers){ + return listOfUsers.map( user => { const name = user.fullName.split(' ')[0]; const cname = user.fullName.split(' ')[1] || ''; const id = user._id; @@ -95,16 +96,16 @@ class Contacts { - ${this.renderListOfUsers()} + ${this.renderListOfUsers(this.users)} `; } - updateListOfUsers(){ + insertListOfUsersToApp(listOfUsers){ const containerForList = this.appContainer.querySelector('table > tbody'); - containerForList.innerHTML = this.renderListOfUsers(); + containerForList.innerHTML = this.renderListOfUsers(listOfUsers); } createMainSource(){ @@ -145,7 +146,6 @@ class Contacts { findUser(value, prop) { const letFilterBy = user => { if(!prop){ - console.log(user); return user["fullName"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || user["fullName"].toLowerCase().indexOf(value.toLowerCase()) !== -1 || user["email"].toLowerCase().indexOf(value.toLowerCase()) !== -1; diff --git a/phone-book/src/router.js b/phone-book/src/router.js index 2c798b0..caccc80 100644 --- a/phone-book/src/router.js +++ b/phone-book/src/router.js @@ -3,12 +3,13 @@ class Router { window.addEventListener('popstate', event => { // console.log(event.state); - app.changePageTo(event.state.activePage); + app.updateState({activePage : event.state.activePage}); + app.changePageToActive(); }); } - gotToPage(activePage,href){ - window.history.pushState({activePage:activePage},'', href); + gotToPage(state,href){ + window.history.pushState(state,'', href); } } \ No newline at end of file From 3ab6d6ebb607d603621f51b799c615c2407d1af1 Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sun, 19 Aug 2018 00:07:06 +0300 Subject: [PATCH 06/10] title of page is property of class --- phone-book/src/add-user.js | 1 + phone-book/src/app.js | 22 +++++++++++++++++----- phone-book/src/contacts.js | 1 + phone-book/src/edit-contact.js | 1 + phone-book/src/keypad.js | 1 + phone-book/src/user.js | 1 + 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/phone-book/src/add-user.js b/phone-book/src/add-user.js index b392963..a61ff79 100644 --- a/phone-book/src/add-user.js +++ b/phone-book/src/add-user.js @@ -2,6 +2,7 @@ class AddUser { constructor(appContainer) { + this.title = 'Add User' this.appContainer = appContainer; } diff --git a/phone-book/src/app.js b/phone-book/src/app.js index 72fd055..b1f0420 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -22,8 +22,10 @@ class App { } updateState(newState){ + this.state = {}; Object.assign(this.state,newState); } + addRouterToFooter(){ const tabs = this.appContainer.querySelector("nav.main-nav"); tabs.addEventListener('click', (event) => { @@ -45,13 +47,24 @@ class App { } changePageToActive(){ + this.updateTitle(); this.insertCurrentPage(); this.initPageEventListeners(); } + updateTitle(){ + const currentPage = this.getCurrentPage(); + const title = this.appContainer.querySelector('header > div > h2'); + title.textContent = currentPage.title; + } - initPageEventListeners(){ + getCurrentPage(){ const activePage = this.state.activePage; - const currentPage = this.pages[activePage]; + const currentPage = this.pages[activePage]; + return currentPage; + } + + initPageEventListeners(){ + const currentPage = this.getCurrentPage(); currentPage.initEvents(); } @@ -67,7 +80,7 @@ class App { return `
-

${this.pageName}

+

`; @@ -101,8 +114,7 @@ class App { } renderCurrentPage(){ - const activePage = this.state.activePage; - const currentPage = this.pages[activePage]; + const currentPage = this.getCurrentPage(); return currentPage.render(); } diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index 5bbea60..b8c029d 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -1,6 +1,7 @@ class Contacts { constructor(app) { this.app = app; + this.title = "Contacts"; this.appContainer = app.appContainer; this.pageName = 'Contacts'; this.users = []; diff --git a/phone-book/src/edit-contact.js b/phone-book/src/edit-contact.js index 797c560..11359b2 100644 --- a/phone-book/src/edit-contact.js +++ b/phone-book/src/edit-contact.js @@ -1,5 +1,6 @@ class EditContact { constructor(appContainer) { + this.title = 'Edit Contact'; this.appContainer = appContainer; } diff --git a/phone-book/src/keypad.js b/phone-book/src/keypad.js index a156eec..b2daa6b 100644 --- a/phone-book/src/keypad.js +++ b/phone-book/src/keypad.js @@ -1,5 +1,6 @@ class Keypad { constructor(appContainer) { + this.title = "Keypad"; this.currentNumber = ''; this.appContainer = appContainer; } diff --git a/phone-book/src/user.js b/phone-book/src/user.js index 35bbd6f..8e804b9 100644 --- a/phone-book/src/user.js +++ b/phone-book/src/user.js @@ -2,6 +2,7 @@ class User { constructor(appContainer) { + this.title = "User"; this.appContainer = appContainer; } From d22bbbe1cfe88932721bae38b4dd8e9a88fd254b Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sun, 19 Aug 2018 12:00:15 +0300 Subject: [PATCH 07/10] serverAPI simplified to jast returning promise from fetch. User class render name and phone from data recieved from server --- phone-book/index.html | 2 +- phone-book/src/app.js | 3 ++- phone-book/src/contacts.js | 19 ++++++++------ phone-book/src/fetcher.js | 32 ----------------------- phone-book/src/server-api.js | 11 ++++++++ phone-book/src/user.js | 49 ++++++++++++++++++++++++++++++++++-- 6 files changed, 73 insertions(+), 43 deletions(-) delete mode 100644 phone-book/src/fetcher.js create mode 100644 phone-book/src/server-api.js diff --git a/phone-book/index.html b/phone-book/index.html index d93b244..e2ba574 100644 --- a/phone-book/index.html +++ b/phone-book/index.html @@ -15,7 +15,7 @@ - + diff --git a/phone-book/src/app.js b/phone-book/src/app.js index b1f0420..d065f18 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -3,11 +3,12 @@ class App { this.state = {}; this.appContainer = document.getElementById(appContainerId); this.router = new Router(this); + this.serverAPI = new ServerAPI(); this.pages = { contacts : new Contacts(this), keypad : new Keypad(this.appContainer), editContact : new EditContact(this.appContainer), - user : new User(this.appContainer), + user : new User(this), addUser : new AddUser(this.appContainer), } diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index b8c029d..f57ce9d 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -62,15 +62,20 @@ class Contacts { if(this.users.length != 0){ return false; } - let promisWithUsers = []; - const fetcher = new Fetcher(); - promisWithUsers.push(fetcher.getUsers()); - Promise.all(promisWithUsers).then( (users) => { - this.users = users[0]; - this.insertListOfUsersToApp(this.users); + const serverAPI = this.app.serverAPI; + const loadingUsers = serverAPI.getUsers(); + loadingUsers.then( response => { + return response.json(); + }) + .then(users => { + this.users = users + this.insertListOfUsersToApp(this.users); + }) + .catch( err => { + console.error(err.message); }); - // return users; } + renderListOfUsers(listOfUsers){ return listOfUsers.map( user => { const name = user.fullName.split(' ')[0]; diff --git a/phone-book/src/fetcher.js b/phone-book/src/fetcher.js deleted file mode 100644 index 044a72d..0000000 --- a/phone-book/src/fetcher.js +++ /dev/null @@ -1,32 +0,0 @@ -class Fetcher{ - constructor(){ - this.url = 'https://easycode-js.herokuapp.com/mamax' - } - getUsers(){ - return fetch(this.url + '/users') - .then( response => { - return response.json(); - }) - .then(parsedResponse => { - return parsedResponse; - }) - .catch( alert => { - // console.error(alert); - }); - - } - getUser(id){ - return fetch(this.url + '/users/' + id) - .then( response => { - return response.json(); - }) - .then(parsedResponse => { - console.log(parsedResponse); - return parsedResponse; - }) - .catch( alert => { - // console.error(alert); - }); - - } -} diff --git a/phone-book/src/server-api.js b/phone-book/src/server-api.js new file mode 100644 index 0000000..a31eaf2 --- /dev/null +++ b/phone-book/src/server-api.js @@ -0,0 +1,11 @@ +class ServerAPI{ + constructor(){ + this.url = 'https://easycode-js.herokuapp.com/mamax' + } + getUsers(){ + return fetch(this.url + '/users'); + } + getUser(id){ + return fetch(this.url + '/users/' + id); + } +} diff --git a/phone-book/src/user.js b/phone-book/src/user.js index 8e804b9..f8abd4b 100644 --- a/phone-book/src/user.js +++ b/phone-book/src/user.js @@ -1,15 +1,60 @@ class User { - constructor(appContainer) { + constructor(app) { this.title = "User"; - this.appContainer = appContainer; + this.appContainer = app.appContainer; + this.app = app; } initEvents(){ + this.getUser(); + } + getUser(){ + + if(this.user){ + return false; + } + const serverAPI = this.app.serverAPI; + const userId = this.app.state.userId; + const loadingUser = serverAPI.getUser(userId); + loadingUser.then( response => { + return response.json(); + }) + .then(user => { + this.user = user + this.fillPageWithUsersData(); + }) + .catch( err => { + console.error(err.message); + }); + + } + + fillPageWithUsersData(){ + this.updateName(); + this.updateEmail(); + this.updatePhone(); + } + + updateName(){ + const nameNode = this.app.appContainer.querySelector('div.user-name'); + nameNode.textContent = this.user.fullName + + } + + updatePhone(){ + const phoneNode = this.app.appContainer.querySelector('div.tel-number > div'); + phoneNode.textContent = this.user.phone; + } + + updateEmail(){ + + } + render(){ return `
From 73d31a3afdf5b0e09fc5648c4ce0d58aadb975b1 Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sun, 19 Aug 2018 16:33:14 +0300 Subject: [PATCH 08/10] router is set on main block instead initial in every modul. --- phone-book/src/add-user.js | 45 +++------------------- phone-book/src/app.js | 74 ++++++++++++++++++++++++++++-------- phone-book/src/contacts.js | 23 ++--------- phone-book/src/keypad.js | 33 +++------------- phone-book/src/main.css | 4 ++ phone-book/src/router.js | 13 +++++-- phone-book/src/server-api.js | 11 +++++- phone-book/src/user.js | 33 +++++++++------- 8 files changed, 117 insertions(+), 119 deletions(-) diff --git a/phone-book/src/add-user.js b/phone-book/src/add-user.js index a61ff79..74d066b 100644 --- a/phone-book/src/add-user.js +++ b/phone-book/src/add-user.js @@ -1,9 +1,10 @@ class AddUser { - constructor(appContainer) { + constructor(app) { this.title = 'Add User' - this.appContainer = appContainer; + this.app = app; + this.appContainer = app.appContainer; } initEvents(){ @@ -21,19 +22,10 @@ class AddUser {
-
-
- -
-
-
+
@@ -43,38 +35,13 @@ class AddUser { add mobile phone
-
- -
- -
-
- -
-
- -
-
- -
-
- +
diff --git a/phone-book/src/app.js b/phone-book/src/app.js index d065f18..d65f8ae 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -5,20 +5,35 @@ class App { this.router = new Router(this); this.serverAPI = new ServerAPI(); this.pages = { - contacts : new Contacts(this), - keypad : new Keypad(this.appContainer), - editContact : new EditContact(this.appContainer), - user : new User(this), - addUser : new AddUser(this.appContainer), + contacts : { + pageObject : new Contacts(this), + href : '/contacts.html' + }, + keypad : { + pageObject : new Keypad(this), + href : '/keypad.html' + }, + editContact : { + pageObject : new EditContact(this.appContainer), + href : '/edit-contact.html' + }, + user : { + pageObject : new User(this), + href : '/user.html' + }, + addUser : { + pageObject : new AddUser(this.appContainer), + href : '/add-user.html' + } } const appHtml = this.renderAppContainer(); this.appContainer.innerHTML = appHtml; - this.addRouterToFooter(); + this.addRouter(); this.state.pageName = 'Contacts'; this.updateState({activePage : 'contacts'}); - this.router.gotToPage({activePage : 'contacts'},'/index.html'); + this.router.gotToPage(this.state,'/index.html'); this.changePageToActive(); } @@ -27,18 +42,21 @@ class App { Object.assign(this.state,newState); } - addRouterToFooter(){ - const tabs = this.appContainer.querySelector("nav.main-nav"); - tabs.addEventListener('click', (event) => { + addRouter(){ + this.appContainer.addEventListener('click', (event) => { event.preventDefault(); const container = event.currentTarget; let target = event.target; while (target != container) { - if (target.nodeName == 'A' && target.classList.contains('tab') ) { - const href = target.href; + if (target.getAttribute("data-page") ) { const newPage = target.getAttribute("data-page"); - this.updateState({activePage : newPage}); - this.router.gotToPage({activePage : newPage},href); + const newUser = target.getAttribute("data-user-id"); + const newState = { activePage : newPage }; + if(newUser){ + newState.userId = newUser; + } + this.updateState(newState); + this.router.gotToPage(this.state); this.changePageToActive(); return; } @@ -60,7 +78,7 @@ class App { getCurrentPage(){ const activePage = this.state.activePage; - const currentPage = this.pages[activePage]; + const currentPage = this.pages[activePage].pageObject; return currentPage; } @@ -77,6 +95,32 @@ class App { `; } + formatformNumber(number) { + if(isNaN(number.charAt(0))){ + return number; + } + const formatedNumber = number.replace(/(\d{0,3})(\d{0,2})?(\d{0,2})?(\d{0,3})?/, (match,g1,g2,g3,g4) => { + let res = '' + if(g1){ + res = `(${g1}`; + } + if(g1.length === 3){ + res += `) `; + } + if(g2){ + res += `${g2}`; + } + if(g3){ + res += `-${g3}`; + } + if(g4){ + res += `-${g4}`; + } + return res + }); + return formatedNumber; + } + renderAppHead(){ return `
diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index f57ce9d..fbb23df 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -19,7 +19,6 @@ class Contacts { }); this.getListOfUsers(); this.initSearch(); - this.initClickOnUser() } showUserPage(id){ @@ -31,23 +30,7 @@ class Contacts { }); } - initClickOnUser(){ - this.appContainer.querySelector("main > div.container").addEventListener('click', event => { - const container = event.currentTarget; - let target = event.target; - while (target != container) { - if (target.nodeName == 'TR' && target.parentNode.nodeName == 'TBODY') { - const id = target.getAttribute("data-user_id"); - this.app.updateState({activePage : 'user', userId : id }); - this.app.router.gotToPage({activePage : 'user', userId : id },'/user.html'); - this.app.changePageToActive(); - return; - } - target = target.parentNode; - } - }); - - } + initSearch(){ document.getElementById('search').addEventListener('keyup', (event) => { let filteredUsers = this.users; @@ -75,14 +58,14 @@ class Contacts { console.error(err.message); }); } - + renderListOfUsers(listOfUsers){ return listOfUsers.map( user => { const name = user.fullName.split(' ')[0]; const cname = user.fullName.split(' ')[1] || ''; const id = user._id; return ` - + ${name} ${cname} ${user.email} diff --git a/phone-book/src/keypad.js b/phone-book/src/keypad.js index b2daa6b..afba6a5 100644 --- a/phone-book/src/keypad.js +++ b/phone-book/src/keypad.js @@ -1,8 +1,9 @@ class Keypad { - constructor(appContainer) { + constructor(app) { this.title = "Keypad"; this.currentNumber = ''; - this.appContainer = appContainer; + this.app = app; + this.appContainer = app.appContainer; } initEvents(){ @@ -41,35 +42,11 @@ class Keypad { if( number && /^[\d\*#]$/.test(number) && this.currentNumber.length < 10){ this.currentNumber += number; } - const formatedNumber = this.formatformNumber(this.currentNumber); + const formatedNumber = this.app.formatformNumber(this.currentNumber); this.appContainer.querySelector('main span.numbers').innerHTML = formatedNumber } - formatformNumber(number) { - if(isNaN(number.charAt(0))){ - return number; - } - const formatedNumber = number.replace(/(\d{0,3})(\d{0,2})?(\d{0,2})?(\d{0,3})?/, (match,g1,g2,g3,g4) => { - let res = '' - if(g1){ - res = `(${g1}`; - } - if(g1.length === 3){ - res += `) `; - } - if(g2){ - res += `${g2}`; - } - if(g3){ - res += `-${g3}`; - } - if(g4){ - res += `-${g4}`; - } - return res - }); - return formatedNumber; - } + diff --git a/phone-book/src/main.css b/phone-book/src/main.css index 472af3d..ce82345 100644 --- a/phone-book/src/main.css +++ b/phone-book/src/main.css @@ -214,6 +214,10 @@ h3 { font-size: 16px; } +.loading{ + color:gray; +} + .options-table { margin-bottom: 20px; font-size: 16px; diff --git a/phone-book/src/router.js b/phone-book/src/router.js index caccc80..a9ca4c1 100644 --- a/phone-book/src/router.js +++ b/phone-book/src/router.js @@ -1,14 +1,21 @@ class Router { constructor(app){ - + this.app = app; window.addEventListener('popstate', event => { // console.log(event.state); - app.updateState({activePage : event.state.activePage}); + const popState = { activePage : event.state.activePage }; + if(event.state.userId){ + popState.userId = event.state.userId; + } + + app.updateState(popState); app.changePageToActive(); }); } - gotToPage(state,href){ + gotToPage(state){ + const activePage = this.app.state.activePage; + const href = this.app.pages[activePage].href; window.history.pushState(state,'', href); } diff --git a/phone-book/src/server-api.js b/phone-book/src/server-api.js index a31eaf2..31c57ac 100644 --- a/phone-book/src/server-api.js +++ b/phone-book/src/server-api.js @@ -7,5 +7,14 @@ class ServerAPI{ } getUser(id){ return fetch(this.url + '/users/' + id); - } + } + addUser(data){ + fetch(this.url + '/users' , { + headers : { + 'Content-Type': 'application/json' + }, + method: "POST", + body: JSON.stringify(data) + }); + } } diff --git a/phone-book/src/user.js b/phone-book/src/user.js index f8abd4b..828a2ee 100644 --- a/phone-book/src/user.js +++ b/phone-book/src/user.js @@ -15,11 +15,12 @@ class User { getUser(){ - if(this.user){ + const userId = this.app.state.userId; + if(this.user && this.user._id == userId){ + this.fillPageWithUsersData(); return false; } const serverAPI = this.app.serverAPI; - const userId = this.app.state.userId; const loadingUser = serverAPI.getUser(userId); loadingUser.then( response => { return response.json(); @@ -38,19 +39,28 @@ class User { this.updateName(); this.updateEmail(); this.updatePhone(); + this.setUserIDtoAttribute(); } updateName(){ - const nameNode = this.app.appContainer.querySelector('div.user-name'); - nameNode.textContent = this.user.fullName + const nameNode = this.app.appContainer.querySelector('main div.user-name'); + nameNode.innerHTML = this.user.fullName } updatePhone(){ - const phoneNode = this.app.appContainer.querySelector('div.tel-number > div'); - phoneNode.textContent = this.user.phone; + const phoneNode = this.app.appContainer.querySelector('main div.tel-number > div'); + const formattedNumber = this.app.formatformNumber(this.user.phone); + phoneNode.innerHTML = formattedNumber; } + setUserIDtoAttribute(){ + const editLinks = this.app.appContainer.querySelectorAll("main [data-page='editContact']"); + editLinks.forEach( link => { + link.setAttribute('data-user-id', this.user._id); + }); + + } updateEmail(){ } @@ -59,7 +69,7 @@ class User { return `
# -
User Name
+
Loading name...
@@ -80,11 +90,7 @@ class User {

mobile

-
+38 (093) 989 89 89
-
-
-

home

-
+38 (093) 989 89 89
+
Loading phone number...
- `; + `; } } From d0d6f07cd96963830a36948858ece53fbc45037c Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sun, 19 Aug 2018 22:51:49 +0300 Subject: [PATCH 09/10] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=81=D0=BE=D1=85=D0=B0=D0=BD?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20(=D1=87=D0=B5=D1=81=D0=BD?= =?UTF-8?q?=D0=BE=20=D1=83=D0=B6=D0=B5=20=D0=BD=D0=B5=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=8F=D0=BB)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phone-book/src/add-user.js | 51 --------- phone-book/src/app.js | 11 +- phone-book/src/contacts.js | 4 +- phone-book/src/edit-contact.js | 90 --------------- phone-book/src/edit-user.js | 195 +++++++++++++++++++++++++++++++++ phone-book/src/main.css | 10 +- phone-book/src/server-api.js | 16 ++- phone-book/src/user.js | 11 +- 8 files changed, 229 insertions(+), 159 deletions(-) delete mode 100644 phone-book/src/add-user.js delete mode 100644 phone-book/src/edit-contact.js create mode 100644 phone-book/src/edit-user.js diff --git a/phone-book/src/add-user.js b/phone-book/src/add-user.js deleted file mode 100644 index 74d066b..0000000 --- a/phone-book/src/add-user.js +++ /dev/null @@ -1,51 +0,0 @@ - - -class AddUser { - constructor(app) { - this.title = 'Add User' - this.app = app; - this.appContainer = app.appContainer; - } - - initEvents(){ - - } - - render(){ - return ` -
-
-
- -
-
-
- -
- -
-
-
-
-
- -
-
- -
-
- -
-
-
-
- `; - } -} diff --git a/phone-book/src/app.js b/phone-book/src/app.js index d65f8ae..8a25bbc 100644 --- a/phone-book/src/app.js +++ b/phone-book/src/app.js @@ -4,6 +4,7 @@ class App { this.appContainer = document.getElementById(appContainerId); this.router = new Router(this); this.serverAPI = new ServerAPI(); + const userPage = new EditUser(this); this.pages = { contacts : { pageObject : new Contacts(this), @@ -13,8 +14,8 @@ class App { pageObject : new Keypad(this), href : '/keypad.html' }, - editContact : { - pageObject : new EditContact(this.appContainer), + editUser : { + pageObject : userPage, href : '/edit-contact.html' }, user : { @@ -22,7 +23,7 @@ class App { href : '/user.html' }, addUser : { - pageObject : new AddUser(this.appContainer), + pageObject : userPage, href : '/add-user.html' } } @@ -40,6 +41,8 @@ class App { updateState(newState){ this.state = {}; Object.assign(this.state,newState); + + } addRouter(){ @@ -138,7 +141,7 @@ class App { diff --git a/phone-book/src/contacts.js b/phone-book/src/contacts.js index fbb23df..60db4ac 100644 --- a/phone-book/src/contacts.js +++ b/phone-book/src/contacts.js @@ -1,7 +1,7 @@ class Contacts { constructor(app) { - this.app = app; this.title = "Contacts"; + this.app = app; this.appContainer = app.appContainer; this.pageName = 'Contacts'; this.users = []; @@ -42,7 +42,7 @@ class Contacts { } getListOfUsers(){ - if(this.users.length != 0){ + if(this.users.length != 0 ){ return false; } const serverAPI = this.app.serverAPI; diff --git a/phone-book/src/edit-contact.js b/phone-book/src/edit-contact.js deleted file mode 100644 index 11359b2..0000000 --- a/phone-book/src/edit-contact.js +++ /dev/null @@ -1,90 +0,0 @@ -class EditContact { - constructor(appContainer) { - this.title = 'Edit Contact'; - this.appContainer = appContainer; - } - - initEvents(){ - const editButtons = this.appContainer.querySelectorAll('a.add-btn'); - editButtons.forEach(( value ) => { - value.children[1].contentEditable = 'true'; - }); - this.appContainer.addEventListener('click', (event) => { - event.preventDefault(); - if( event.target.nodeName == 'A' && event.target.classList.contains('add-btn')){ - event.target.children[1].backgroundColor = 'purple'; - } - }); - } - - render(){ - return ` - - `; - } - -} diff --git a/phone-book/src/edit-user.js b/phone-book/src/edit-user.js new file mode 100644 index 0000000..2d08288 --- /dev/null +++ b/phone-book/src/edit-user.js @@ -0,0 +1,195 @@ + + +class EditUser { + constructor(app) { + this.title = 'Add User' + this.app = app; + this.appContainer = app.appContainer; + } + + initEvents(){ + // this.createPlaceholders(); + this.initSaveEvent(); + if(this.app.state.userId){ + this.initDeleteEvent(); + this.renderUserData(); + } + } + + setCaretToEnd(node) { + let range = document.createRange(); + let sel = window.getSelection(); + range.setStart(node, 1); + range.collapse(true); + sel.removeAllRanges(); + sel.addRange(range); + } + renderUserData(){ + const contactObj = this.app.pages.contacts.pageObject; + const userId = this.app.state.userId; + this.getUser(); + } + + getUser(){ + const userId = this.app.state.userId; + const serverAPI = this.app.serverAPI; + const loadingUser = serverAPI.getUser(userId); + loadingUser.then( response => { + return response.json(); + }) + .then(user => { + const fullNameField = this.appContainer.querySelector('span[data-name="fullName"]'); + fullNameField.textContent = user.fullName; + + const emailField = this.appContainer.querySelector('span[data-name="email"]'); + emailField.textContent = user.email; + + const phoneField = this.appContainer.querySelector('span[data-name="phone"]'); + phoneField.textContent = user.phone; + }) + .catch( err => { + console.error(err.message); + }); + + } + + updateUser(data){ + const serverAPI = this.app.serverAPI; + const updatingUser = serverAPI.updateUser(data); + updatingUser.then( response => { + this.app.pages.contacts.pageObject.users = []; + const newPage = 'contacts'; + const newState = { activePage : newPage }; + this.app.updateState(newState); + this.app.router.gotToPage(this.app.state); + this.app.changePageToActive(); + }) + .catch( err => { + console.error(err.message); + }); + } + + addUserToServer(data){ + const serverAPI = this.app.serverAPI; + const addingUser = serverAPI.addUser(data); + addingUser.then( response => { + return response.json(); + }) + .then(addedUser => { + this.app.pages.contacts.pageObject.users = []; + const newPage = 'user'; + const newUser = addedUser._id; + const newState = { activePage : newPage }; + if(newUser){ + newState.userId = newUser; + } + this.app.updateState(newState); + this.app.router.gotToPage(this.app.state); + this.app.changePageToActive(); + }) + .catch( err => { + console.error(err.message); + }); + } + deleteUser(id){ + const serverAPI = this.app.serverAPI; + const deletingUser = serverAPI.deleteUser(id); + deletingUser.then( response => { + this.app.pages.contacts.pageObject.users = []; + const newPage = 'contacts'; + const newState = { activePage : newPage }; + this.app.updateState(newState); + this.app.router.gotToPage(this.app.state); + this.app.changePageToActive(); + }) + .catch( err => { + console.error(err.message); + }); + } + + initDeleteEvent(){ + const saveButton = this.appContainer.querySelector('button.delete-contact'); + saveButton.style.display = 'inline-block'; + saveButton.addEventListener('click', (event) => { + this.deleteUser(this.app.state.userId); + }); + } + + initSaveEvent(){ + const saveButton = this.appContainer.querySelector('button.save-contact'); + saveButton.addEventListener('click', (event) => { + const newUserData = this.grabUserData(); + if(newUserData.phone && newUserData.email && newUserData.fullName){ + if(!this.app.state.userId){ + this.addUserToServer(newUserData); + }else{ + newUserData.userId = this.app.state.userId; + this.updateUser(newUserData); + } + } + }); + } + + grabUserData(){ + const editableFields = this.appContainer.querySelectorAll('span[data-name]'); + return [...editableFields].reduce( (acc,elem) => { + + if(this.validateField(elem)){ + acc[elem.getAttribute('data-name')] = elem.textContent.trim(); + } + return acc; + },{}); + } + + validateField(elem){ + const classes = elem.parentElement.classList; + if(elem.textContent.trim() != ''){ + classes.remove("delete-btn") + classes.add("add-btn"); + return true; + } + classes.remove("add-btn") + classes.add("delete-btn"); + return false; + } + + + render(){ + return ` +
+
+
+
+
+
+
+ + Full Name: +
+
+
+
+
+
+
+
+ + mobile phone: +
+
+
+
+ + email: +
+
+
+ + +
+
+
+
+ `; + } +} diff --git a/phone-book/src/main.css b/phone-book/src/main.css index ce82345..1830c91 100644 --- a/phone-book/src/main.css +++ b/phone-book/src/main.css @@ -162,6 +162,7 @@ h3 { width: 100px; height: 100px; margin-bottom: 10px; + float:left; } .user-name { @@ -304,9 +305,11 @@ h3 { margin-right: 10px; } -.add-btn span:last-child{ +.edit-field span:last-child{ display: inline-block; padding: 2px 3px; + width: 150px; + border: 1px solid black; } .add-btn:hover, .add-btn:focus, .add-btn:active { @@ -317,8 +320,11 @@ h3 { background-color: black; } -.delete-contact { +.edit-contact { color: #e32910; margin: 0 auto; font-weight: bold; +} +.delete-contact{ + display: none; } \ No newline at end of file diff --git a/phone-book/src/server-api.js b/phone-book/src/server-api.js index 31c57ac..f0d6d8a 100644 --- a/phone-book/src/server-api.js +++ b/phone-book/src/server-api.js @@ -9,7 +9,7 @@ class ServerAPI{ return fetch(this.url + '/users/' + id); } addUser(data){ - fetch(this.url + '/users' , { + return fetch(this.url + '/users' , { headers : { 'Content-Type': 'application/json' }, @@ -17,4 +17,18 @@ class ServerAPI{ body: JSON.stringify(data) }); } + deleteUser(id){ + return fetch(this.url + '/users/' + id , { + method: "DELETE", + }); + } + updateUser(data){ + return fetch(this.url + '/users/' + data.userId , { + headers : { + 'Content-Type': 'application/json' + }, + method: "PATCH", + body: JSON.stringify(data) + }); + } } diff --git a/phone-book/src/user.js b/phone-book/src/user.js index 828a2ee..57198bc 100644 --- a/phone-book/src/user.js +++ b/phone-book/src/user.js @@ -55,7 +55,7 @@ class User { } setUserIDtoAttribute(){ - const editLinks = this.app.appContainer.querySelectorAll("main [data-page='editContact']"); + const editLinks = this.app.appContainer.querySelectorAll("main a.editUser"); editLinks.forEach( link => { link.setAttribute('data-user-id', this.user._id); }); @@ -68,7 +68,6 @@ class User { render(){ return `
- #
Loading name...
@@ -93,13 +92,7 @@ class User {
Loading phone number...
`; From 7b18c4b2e5defebc737d92bf0bffbef3c4254e8b Mon Sep 17 00:00:00 2001 From: maxeasy18 Date: Sun, 19 Aug 2018 22:52:57 +0300 Subject: [PATCH 10/10] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=81=D0=BE=D1=85=D0=B0=D0=BD?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=D1=81=D1=8F=20(=D1=87=D0=B5=D1=81=D0=BD?= =?UTF-8?q?=D0=BE=20=D1=83=D0=B6=D0=B5=20=D0=BD=D0=B5=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B5=D1=80=D1=8F=D0=BB)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phone-book/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phone-book/index.html b/phone-book/index.html index e2ba574..25776d9 100644 --- a/phone-book/index.html +++ b/phone-book/index.html @@ -19,9 +19,9 @@ - + - +