Browse Source

HW 13,15,17 done

ostapenkonataliia 1 year ago
parent
commit
672f3e3903

+ 28 - 2
.idea/workspace.xml

@@ -2,9 +2,24 @@
 <project version="4">
   <component name="ChangeListManager">
     <list default="true" id="c45bf7d2-992f-400a-8194-6f236ee5f805" name="Changes" comment="">
+      <change afterPath="$PROJECT_DIR$/JS_17_rest, graphQL/index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/JS_17_rest, graphQL/js.js" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/JS_17_rest, graphQL/style.css" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_13_foop/Index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_13_foop/css.css" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_13_foop/js.js" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_15/index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_15/js.js" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_16_async_chat/index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_16_async_chat/js.js" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/Js_16_async_chat/style.css" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/MODULE/index.html" afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/MODULE/js.js" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/Js_12/js.js" beforeDir="false" afterPath="$PROJECT_DIR$/Js_12/js.js" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/Js_12/style.css" beforeDir="false" afterPath="$PROJECT_DIR$/Js_12/style.css" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/js.js" beforeDir="false" />
+      <change beforePath="$PROJECT_DIR$/rgb.js" beforeDir="false" afterPath="$PROJECT_DIR$/rgb.js" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -14,9 +29,9 @@
   <component name="FileTemplateManagerImpl">
     <option name="RECENT_TEMPLATES">
       <list>
-        <option value="JavaScript File" />
-        <option value="HTML File" />
         <option value="CSS File" />
+        <option value="HTML File" />
+        <option value="JavaScript File" />
       </list>
     </option>
   </component>
@@ -88,6 +103,17 @@
       <workItem from="1670585530619" duration="66786000" />
       <workItem from="1670959529015" duration="10774000" />
       <workItem from="1671047485199" duration="1057000" />
+      <workItem from="1671053770231" duration="45439000" />
+      <workItem from="1671438653562" duration="125185000" />
+      <workItem from="1672733045005" duration="21066000" />
+      <workItem from="1673014908083" duration="6454000" />
+      <workItem from="1673032789352" duration="6725000" />
+      <workItem from="1673087477277" duration="1809000" />
+      <workItem from="1673277859260" duration="1188000" />
+      <workItem from="1673279136550" duration="15941000" />
+      <workItem from="1673512789885" duration="17176000" />
+      <workItem from="1673679696247" duration="643000" />
+      <workItem from="1673856577763" duration="1291000" />
     </task>
     <servers />
   </component>

+ 25 - 0
JS_17_rest, graphQL/index.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+    <link rel="stylesheet" href="style.css">
+
+</head>
+<body>
+
+<div class="container">
+    <div class="light" id="red"> </div>
+    <div class="light" id="yellow"> </div>
+    <div class="light" id="green"> </div>
+</div>
+
+<div id="pedastrian_container">
+    <div class="light" id="red-light"> </div>
+    <div class="light" id="green-light"> </div>
+    <button id="button">switch</button>
+</div>
+
+<script src="js.js"></script>
+</body>
+</html>

+ 197 - 0
JS_17_rest, graphQL/js.js

@@ -0,0 +1,197 @@
+//1. Светофор Используя асинхронную функцию и бесконечный цикл, просимулируйте светофор:
+// {
+//     const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));
+//
+//     let red = document.getElementById('red')
+//     let yellow = document.getElementById('yellow')
+//     let green = document.getElementById('green')
+//
+//     async function trafficLight(greenEl, yellowEl, redEl, greenTime, yellowTime, redTime) {
+//         while (true) {
+//
+//             greenEl.classList.add('green')
+//             await delay(greenTime)
+//             greenEl.classList.remove('green');
+//
+//             yellowEl.classList.add('yellow');
+//             await delay(yellowTime);
+//             yellowEl.classList.remove('yellow');
+//
+//             redEl.classList.add('red');
+//             await delay(redTime);
+//             redEl.classList.remove('red');
+//         }
+//     }
+//
+//     trafficLight(green, yellow, red, 4000, 1000, 4000);
+// }
+
+// PedestrianTrafficLight
+// Напишите упрощенный светофор для пешеходов
+// Stage 2
+// Используя Promise.race, domEventPromise и кнопку в DOM сделайте пешеходный светофор с кнопкой, который так
+// же переключается по времени периодически.
+// Stage 3
+// Не давайте возможности пешеходам сильно наглеть - предусмотрите задержку, после которой будет работать
+// кнопка.
+// {
+//     const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));
+//
+//     let container = document.getElementById('pedastrian-container')
+//     let red = document.getElementById('red-light');
+//     let green = document.getElementById('green-light');
+//     let button = document.getElementById('button');
+//
+//     function domEventPromise(element, eventName) {
+//         function executor(resolve) {
+//             function myEvent(event) {
+//                 element.disabled = true;
+//                 element.removeEventListener(eventName, myEvent);
+//                 setTimeout(() => resolve(event), 2000);
+//             }
+//             element.disabled = false;
+//             element.addEventListener(eventName, myEvent)
+//         }
+//         return new Promise(executor);
+//     }
+//
+//     async function pedestrianTrafficLight(ms) {
+//         while (true) {
+//             red.classList.add('red');
+//             await Promise.race([
+//                 delay(ms),
+//                 domEventPromise(button, 'click')
+//             ]);
+//             red.classList.remove('red');
+//             green.classList.add('green');
+//             await delay(ms);
+//             green.classList.remove('green');
+//         }
+//     }
+//     pedestrianTrafficLight(10000);
+// }
+
+//3. speedtest
+// Написать асинхронную функцию
+//
+// const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));
+//
+// function makeProfileTimer() {
+//     let t0 = performance.now();
+//     return function () {
+//         let t1 = performance.now();
+//         return t1 - t0;
+//     }
+// }
+//
+// async function speedtest(getPromise, count, parallel = 1) {
+//     let timer = makeProfileTimer();
+//     for (let i = 0; i < count; i++) {
+//         let promises = [];
+//         for (let j = 0; j < parallel; j++) {
+//             promises.push(getPromise());
+//         }
+//         console.log(await Promise.all(promises));
+//     }
+//
+//     let duration = timer();
+//     let parallelDuration = duration / (count * parallel);
+//     let parallelSpeed = 1 / parallelDuration;
+//     let queryDuration = duration / count;
+//     let querySpeed = 1 / queryDuration;
+//
+//     return {
+//         duration,
+//         querySpeed, //средняя скорость одного запроса
+//         queryDuration, //
+//         parallelSpeed,
+//         parallelDuration
+//     }
+// }
+//
+// speedtest(() => delay(1000), 10, 10)
+//     .then(result => console.log(result));
+// // {duration: 10000,
+// // querySpeed: 0.001, //1 тысячная запроса за миллисекунду
+// // queryDuration: 1000, //1000 миллисекунд на один реальный запрос в среднем
+// // parallelSpeed: 0.01  // 100 запросов за 10000 миллисекунд
+// // parallelDuration: 100 // 100 запросов за 10000 миллисекунд
+// speedtest(() => fetch('http://swapi.dev/api/people/1')
+//     .then(res => res.json()), 10, 5)
+//     .then(result => console.log(result));
+
+//4.gql
+// Напишите функцию gql, которая осуществляет GraphQL запрос. Функция принимает три параметра:
+//
+//     Эндпоинт - адрес сервера. Например "http://shop-roles.node.ed.asmer.org.ua/graphql"
+//     Текст запроса (query). Например:
+
+ function gql (endpoint, query, variables){
+    return fetch(endpoint,{
+        method: "POST",
+        headers: {
+            "Content-type": "application/Json",
+            'Accept': 'application/json'
+        },
+        body: JSON.stringify({
+            query,
+            variables
+        })
+    }).then(response => response.json())
+}
+
+(async () => {
+    const catQuery = `query cats($q: String){
+                                        CategoryFind(query: $q){
+                                            _id name
+                                        }
+                                    }`
+
+    const cats = await gql("http://shop-roles.node.ed.asmer.org.ua/graphql", catQuery, { q: "[{}]" })
+    console.log(cats) //список категорий с _id name и всем таким прочим
+
+    const loginQuery = `query login($login:String, $password:String){
+                            	login(login:$login, password:$password)
+                        }`
+
+    const token = await gql("http://shop-roles.node.ed.asmer.org.ua/graphql", loginQuery, { login: "test457", password: "123123" })
+    console.log(token)
+})()
+
+//5. jwtDecode
+// Напишете функцию jwtDecode, которая принимает единственный параметр token и возвращает информацию из переданного JWT токена.
+// Алгоритм раскодирования:
+//     Разбить токен на три части. Разделитель - . (точка)
+//     Выделить среднюю часть.
+//     Используя функцию atob раскодировать среднюю часть из кодировки Base64, получив JSON
+//     Раскодировать JSON
+//     Вернуть раскодированные данные из JSON
+//
+// Учтите, что в качестве токена может быть передана какая-то дичь. В таком случае раскодировка не получится, и функция:
+//
+//     Не должна сыпать красными матюками (ошибками) в консоль
+//     Должна просто вернуть undefined
+
+function jwtDecode(token) {
+    let result;
+    try {
+        let secondPartToken = token.split('.')[1];
+        result = JSON.parse(atob(secondPartToken));
+    } catch (e) {
+    }
+
+    return result;
+}
+
+try {
+    console.log(jwtDecode())         //undefined
+    console.log(jwtDecode("дичь"))   //undefined
+    console.log(jwtDecode("ey.ey.ey"))   //undefined
+
+    console.log('до сюда доработало, а значит jwtDecode не матерился в консоль красным цветом')
+}
+finally{
+    console.log('ДЗ, видимо, окончено')
+}
+
+

+ 43 - 0
JS_17_rest, graphQL/style.css

@@ -0,0 +1,43 @@
+.container {
+   width: 100px;
+   height: 230px;
+   background-color: rgba(154, 154, 154, 0.99);
+    border-radius: 50px;
+    padding: 10px;
+}
+
+.light {
+    background-color: rgba(0, 0, 0, 0.18);
+    width: 60px;
+    height: 60px;
+    border: 1px solid;
+    border-radius: 50%;
+    margin: 10px auto;
+
+}
+.red {
+    background-color: red;
+    box-shadow: 0 0 20px red;
+}
+
+.yellow {
+    background-color: yellow;
+    box-shadow: 0 0 20px yellow;
+}
+
+.green {
+    background-color: green;
+    box-shadow: 0 0 20px green;
+}
+
+#pedastrian_container {
+    width: 100px;
+    height: 200px;
+    background-color: rgba(154, 154, 154, 0.99);
+    border-radius: 50px;
+    padding: 10px;
+}
+
+#button {
+
+}

+ 1 - 2
Js_12/js.js

@@ -41,8 +41,7 @@ function reducer(state, {type, productName, productAmount, sum}){
     }
     if (type === 'Купить' && productAmount <= state[productName].amount && sum >= state[productName].price * productAmount){ //если тип action - КУПИТЬ, то:
         return {
-            ...state, //берем все что было из ассортимента
-            [productName]: {
+            ...state,[productName]: {
                 amount: state[productName].amount - productAmount,
                 price: state[productName].price
             },

+ 1 - 1
Js_12/style.css

@@ -13,7 +13,7 @@ body {
 
 .showCase {
     display: flex;
-}
+
 
 .productCard{
     padding: 10px;

+ 20 - 0
Js_13_foop/Index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+    <link rel="stylesheet" href="css.css">
+</head>
+<body>
+<!--<div class="inputs">-->
+<!--    <input type="password" class="password">-->
+<!--    <label>-->
+<!--        <input type="checkbox" class="showPassword"> Показать пароль-->
+<!--    </label>-->
+<!--</div>-->
+
+
+
+<script src="js.js"></script>
+</body>
+</html>

+ 45 - 0
Js_13_foop/css.css

@@ -0,0 +1,45 @@
+*,
+*:before,
+*:after {
+    box-sizing: border-box;
+}
+
+body {
+    margin: 0;
+    height: 100vh;
+    background-color: lavender;
+    padding: 20px;
+}
+
+.showCase {
+    display: flex;
+}
+
+.productCard{
+    padding: 10px;
+    margin: 10px 10px 10px 0;
+    width: 150px;
+    height: 150px;
+    background-color: #c083ef;
+    border-radius: 5px;
+}
+
+.productName{
+    text-align: center;
+    background-color: gold;
+    padding: 5px;
+    color: black;
+    margin-top: 0px;
+}
+
+.productPrice{
+    text-align: center;
+    padding: 10px;
+    color: black;
+}
+
+.productQuantity{
+    padding: 10px 0px 10px;
+    text-align: center;
+}
+

File diff suppressed because it is too large
+ 435 - 0
Js_13_foop/js.js


+ 12 - 0
Js_15/index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+
+</head>
+<body>
+<script src="js.js"></script>
+
+</body>
+</html>

+ 247 - 0
Js_15/js.js

@@ -0,0 +1,247 @@
+//1. fetch basic
+// Исследуйте сайт swapi.dev, рассмотрите JSON-ы, которые предоставляются этим сервисом
+// (например: https://swapi.dev/api/people/1/, https://swapi.dev/api/people/2/, https://swapi.dev/api/starships/12/
+// С помощью следующего кода считать и вывести информацию о Люке Скайвокере:
+// Напишите функцию для отображения любого JSON в форме таблицы. Функция должна принимать два параметра:
+//     DOM - элемент, в котором строится таблица
+//     JSON, который нужно отобразить.
+// {
+//     const person1 = 'https://swapi.dev/api/people/1/';
+//     const person2 = 'https://swapi.dev/api/people/2/';
+//     const person3 = 'https://swapi.dev/api/starships/12/';
+//
+//     let table = document.createElement('table')
+//     table.border = 1
+//     document.body.append(table)
+//
+//     function fetchBbasic (dom, source) {
+//
+//         fetch(source).then(res => res.json())
+//             .then(luke => {
+//                 for (let [key, value] of Object.entries(luke)) {
+//                     let tr = document.createElement("tr")
+//                     table.append(tr)
+//
+//                     let row = document.createElement('td')
+//                     row.innerText = key
+//                     tr.append(row)
+//
+//                     let rowValue = document.createElement('td')
+//                     rowValue.innerText = value
+//                     tr.append(rowValue)
+//
+//                 }
+//                 console.log(luke)
+//             })
+//     }
+//     fetchBbasic(table, person1)
+// }
+
+// 2. Расширить функцию отображения:
+//     Если одно из полей строка или массив.
+//     Если строки или строка содержат в себе https://swapi.dev/api/
+//     То выводить вместо текста строки кнопку, при нажатии на которую:
+//         делается fetch данных по этой ссылке
+//         функция отображения запускает сама себя(рекурсивно) для отображения новых данных в том же элементе.
+
+// {
+//     fetch('https://swapi.dev/api/people/1/')
+//         .then(res => res.json())
+//         .then(luke => {
+//             personTable(document.body, luke);
+//      })
+//
+//     function personTable(domElement, jsonElement, elemForRemoval) {
+//         let table = document.createElement('table');
+//         table.border = 1
+//         //elemForRemoval?.remove();
+//         domElement.append(table);
+//
+//         for (let [key, value] of Object.entries(jsonElement)) {
+//             let tr = document.createElement("tr")
+//                     table.append(tr)
+//             let row = document.createElement('td')
+//             row.innerText = key
+//             tr.append(row)
+//
+//             let rowValue = document.createElement('td')
+//             rowValue.innerText = value
+//             tr.append(rowValue)
+//
+//             if (typeof key === 'string' && value.includes('https://swapi.dev/api/')) {
+//                 linkButton(value, rowValue)
+//             }
+//             else if (Array.isArray(value)) {
+//                 value.forEach(element => {
+//                     linkButton(element,rowValue)
+//                 })
+//             }
+//         }
+//     }
+//
+//     function linkButton(value, rowValue) {
+//         let button = document.createElement('button');
+//         button.innerText = 'OPEN LINK';
+//         button.onclick = () => {
+//             fetch(value)
+//                 .then(res => res.json())
+//                 .then(data => {
+//                     personTable(rowValue, data, button);
+//                 })
+//         };
+//         rowValue.append(button);
+//     }
+// }
+
+//3. race
+// Используя Promise.race запустите запрос на API (swapi.dev) параллельно с delay. По результату определите, что было
+// быстрее, запрос по сети, или определенный интервал времени. Подберите параметр delay так, что бы результат был
+// неизвестен изначально, и при многократных запусках быстрее был то delay, то myfetch.
+// {
+//     let myFetch = new Promise(resolve => fetch('https://swapi.dev/api/people/1/').then(res => res.json())
+//         .then(luke => {
+//             console.log(luke)
+//         }) )
+//
+//     function delay(ms){
+//         function executor(fulfill, reject) {
+//             setTimeout(() => fulfill(ms), ms) }
+//         return new Promise(executor)
+//     }
+//     Promise.race([myFetch, delay(80)]).then((value) => {
+//         console.log(value);
+//      });
+//
+// }
+
+//4. Promisify: confirm
+// Промисифицируйте confirm. Напишите функцию, которая возвращает промис, который переходит в состояние fulfilled при
+// нажатии "OK" и реджектится при нажатии "Cancel". Функция должна принимать строку для confirm:
+// {
+//     function confirmPromise(text){
+//         function executor(fulfill, reject){
+//             if (confirm(text) === true) {
+//                 fulfill()
+//             } else {
+//                 reject()
+//             }
+//         }
+//         return new Promise(executor)
+//     }
+//
+//     confirmPromise('Промисы это сложно?').then(() => console.log('не так уже и сложно'),
+//         () => console.log('respect за усидчивость и внимательность'))
+// }
+
+//5. Promisify: prompt
+// Аналогично предыдующему заданию промисифицируйте prompt. В случае нажатия "ОК" промис резолвится и его результатом
+// становится текст, введенный пользователем в окне prompt. В случае нажатия "Отмены" - промис реджектится. Параметром
+// функции будет текст сообщения в prompt
+// {
+//     function promptPromise(text) {
+//         function executor(fulfill, reject) {
+//             let answer = prompt(text);
+//             if (answer) {
+//                 fulfill(answer);
+//             } else {
+//                 reject();
+//             }
+//         }
+//         return new Promise(executor);
+//     }
+//
+//     promptPromise("Как тебя зовут?").then(name => console.log(`Тебя зовут ${name}`),
+//         () => console.log('Ну зачем морозиться, нормально же общались'))
+// }
+
+//6. Promisify: LoginForm
+// Промисифицируйте конструктор LoginForm. В промисифицированную функцию передается DOM-элемент - родитель для формы,
+// В колбэке, предназначенном для получения логина и пароля в момент нажатия кнопки "Login...", который вы назначаете в
+// объекте LoginForm, зарезолвите промис. Результатом промиса должен быть объект с ключами login и password, ключи
+// должны содержать значения полей ввода.
+// {
+//     function loginPromise (parent) {
+//         function executor (resolve, reject) {
+//         const form = new LoginForm(parent, false)
+//         form.inputButtonOnclick = function () {
+//             resolve ({login: this.getLogin(), password: this.getPass()})
+//             }
+//         }
+//         return new Promise(executor)
+//     }
+//
+//     loginPromise(document.body).then(({login, password}) => console.log(`Вы ввели ${login} и ${password}`))
+//
+//
+//     function LoginForm(parent, passOpenDefault){
+//         function Password(parent, open) {
+//
+//             const inputPass = document.createElement('input')
+//             parent.append(inputPass)
+//             const checkboxPass = document.createElement('input')
+//             checkboxPass.type = 'checkbox'
+//             parent.append(checkboxPass)
+//
+//             this.setValue = (value) => {
+//                 inputPass.value = value
+//                 if (typeof this.onChange === 'function') this.onChange(this.getValue()) // запускается по событию oninput в поле ввода, передает текст в колбэк
+//             }      //задает значение
+//             this.getValue = () => inputPass.value                   //читает значение
+//             this.setOpen = (open) => {
+//                 if (open) {
+//                     checkboxPass.checked = true
+//                     inputPass.type = "text"
+//                 }
+//                 if (!open) {
+//                     checkboxPass.checked = false
+//                     inputPass.type = "password"
+//                 }
+//                 if (typeof this.onOpenChange === 'function') this.onOpenChange(this.getOpen()) // запускается по изменению состояния открытости пароля
+//             } //задает открытость текста в поле ввода
+//             this.getOpen = () => checkboxPass.checked //читает открытость текста в поле ввода
+//
+//             this.setOpen(open)
+//             inputPass.oninput = () => this.setValue(this.getValue())
+//             checkboxPass.oninput = () => this.setOpen(this.getOpen())
+//
+//         }
+//
+//         const LoginForm = document.createElement('div')
+//         parent.append(LoginForm)
+//
+//         const inputLogin = document.createElement('input')
+//         LoginForm.append(inputLogin)
+//
+//         let p = new Password(LoginForm, passOpenDefault)
+//
+//         const inputButton = document.createElement('input')
+//         inputButton.type = 'button'
+//         inputButton.value = 'войти'
+//         LoginForm.append(inputButton)
+//         inputButton.disabled = true
+//
+//         p.onChange = () => checkButtonDisabled()
+//         inputLogin.oninput = () => checkButtonDisabled()
+//
+//         function checkButtonDisabled () {
+//             if (p.getValue() && inputLogin.value) inputButton.disabled = false
+//             else inputButton.disabled = true
+//         }
+//
+//         this.getLogin = () => inputLogin.value
+//         this.setLogin = (value) => {
+//             inputLogin.value = value
+//             checkButtonDisabled()
+//
+//         }
+//         this.getPass = () => p.getValue()
+//         this.setPass = (value) => {
+//             p.setValue(value)
+//             checkButtonDisabled()
+//         }
+//
+//         inputButton.onclick = () => {
+//             if (typeof this.inputButtonOnclick === 'function') this.inputButtonOnclick() //функция при нажатии на кнопку войти
+//         }
+//     }
+// }

+ 22 - 0
Js_16_async_chat/index.html

@@ -0,0 +1,22 @@
+<html>
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>Document</title>
+    <link rel="stylesheet" href="style.css">
+
+</head>
+<body>
+
+<input id="userName" class="base_elem" placeholder="Name"><br>
+<input id="userMessage" class="base_elem" placeholder="Message"> <br>
+<button id="send" class="base_elem">Send</button>
+<div id="chat"></div>
+
+<script src="js.js"></script>
+
+</body>
+</html>
+

+ 165 - 0
Js_16_async_chat/js.js

@@ -0,0 +1,165 @@
+//1. Chat
+
+async function jsonPost(url, data){
+    try {
+        let response = await fetch(url, {
+            method: 'POST',
+            body: JSON.stringify(data)
+        })
+        if (response.ok) {
+            let json = await response.json()
+            return json}
+    } catch (error) {
+        console.log('ошибка: ' + error) //ловим ошибки
+    }
+}
+
+send.onclick = sendAndCheck
+
+async function sendAndCheck() {
+    await sendMessage(userName.value, userMessage.value)
+    getMessages (nextMessageId)
+}
+
+async function sendMessage(nick, message) {
+    if (nick && message) {
+        jsonPost("http://students.a-level.com.ua:10012", { func: 'addMessage', nick, message })
+    }
+}
+
+async function getMessages (id) {
+    const res = await jsonPost("http://students.a-level.com.ua:10012", { func: "getMessages", messageId: id}).then(res => res)
+
+    nextMessageId = res.nextMessageId
+
+    for(const msg of res.data){
+
+        const chatBox = document.createElement('div')
+        chat.prepend(chatBox)
+
+        const chatName = document.createElement('div')
+        chatBox.append(chatName)
+        chatName.innerText = msg.nick + ': '
+        chatName.classList.add('name')
+
+        const chatMessage = document.createElement('div')
+        chatBox.append(chatMessage)
+        chatMessage.innerText = msg.message
+        chatMessage.classList.add('text')
+
+        const time = document.createElement('div');
+        time.classList.add('time')
+        const data = new Date(msg.timestamp)
+        time.innerText = data.toLocaleDateString() + ' ' + data.toLocaleTimeString();
+        chatBox.append(time)
+    }
+}
+
+let nextMessageId = 0
+
+function delay(ms){
+    function executor(fulfill, reject){
+        setTimeout(() => fulfill(ms), ms)
+    }
+    return new Promise(executor)
+}
+
+async function checkLoop() {
+    while(true) {
+        getMessages (nextMessageId)
+        await delay(2000)
+    }
+}
+
+checkLoop()
+
+//2. SWAPI Links
+// Напишите промисифицированную функцию, которая принимать параметром ссылку на swapi.dev
+// (например, https://swapi.dev/api/people/20) и скачивать всю информацию по ссылке, включая вложенные ссылки. Все
+// ссылки внутри скачанного объекта должны заменяться на скачанные объекты. Полученный общий объект должен стать
+// результатом промиса, который возвращает функция.
+// Например, ссылка, приведенная выше позволяет информацию о Йода Мастере скачать:
+
+
+function fetchGet (url) {
+    return fetch(url)
+        .then((response) => {
+            if (response.ok) {
+                return response.json()
+            } else {
+                return Promise.reject(new Error(response.statusText))
+            }
+        } )
+}
+
+function swapiLinks (url) {
+    let obj;
+    return fetchGet(url)
+        .then((response) => {
+            console.log(response);
+            obj = response;
+            const linkPromises = [];
+            Object.values(obj).forEach(value => {
+                if (typeof value == 'string' && value.includes('https://swapi.dev/api/')) {
+                    linkPromises.push(fetchGet(value));
+                } else if (Array.isArray(value)) {
+                    value.forEach((el) => {
+                        if (typeof el == 'string' && el.includes('https://swapi.dev/api/')) {
+                            linkPromises.push(fetchGet(el));
+                        }
+                    })
+                }
+            })
+            return Promise.all(linkPromises)
+        }).then(linkResponses => {
+            Object.keys(obj).forEach(key => {
+                if (typeof obj[key] == 'string' && obj[key].includes('https://swapi.dev/api/')) {
+                    obj[key] = linkResponses.shift();
+                } else if (Array.isArray(obj[key])) {
+                    obj[key].forEach((el, i) => {
+                        if (typeof el == 'string' && el.includes('https://swapi.dev/api/')) {
+                            obj[key][i] = linkResponses.shift();
+                        }
+                    });
+                }
+            });
+            return Promise.resolve(obj);
+        })
+        .catch((error) => {
+            return Promise.reject(error);
+        });
+}
+
+swapiLinks("https://swapi.dev/api/people/20/")
+    .then(yodaWithLinks => {
+        console.log(JSON.stringify(yodaWithLinks, null, 4));
+    })
+    .catch((error) => {
+        console.log(error);
+    });
+
+//domEventPromise +
+// Реализуйте промисифицированную функцию, которая резолвит промис по событию в DOM:
+// Функция должна:
+//
+//     используя addEventListener повесить свой обработчик события на DOM element событие eventName
+// по событию зарезолвить промис отдав в качестве результата объект события
+// убрать обработчик с DOM-элемента, используя removeEventListener.
+//
+//     Убедитесь, что действительно убираете обработчик после резолва промиса. Он больше не нужен.
+
+function domEventPromise(element, eventName) {
+    function executor (resolve) {
+        let myEvent = event => {
+            resolve(event);
+            element.removeEventListener(eventName, myEvent)
+        }
+        element.addEventListener(eventName, myEvent)
+    }
+    return new Promise(executor)
+}
+let button = document.createElement('button')
+document.body.append(button)
+button.innerText = "Click"
+domEventPromise(button, 'click').then( e => console.log('event click happens', e))
+

+ 31 - 0
Js_16_async_chat/style.css

@@ -0,0 +1,31 @@
+* {
+    box-sizing: border-box;
+}
+
+.base_elem {
+    width: 100%;
+    height: 40px;
+    font-size: 23px;
+}
+
+#chat {
+    width: 100%;
+    overflow-y: scroll;
+    overflow-x: hidden;
+    padding: 10px;
+}
+
+.name {
+    font-size: 14px;
+    font-weight: bold;
+}
+
+.text {
+    font-size: 20px;
+}
+
+.time {
+    font-size: 10px;
+    color: #7a7979;
+    margin-bottom: 15px;
+}

+ 12 - 0
MODULE/index.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Title</title>
+</head>
+<body>
+
+
+<script src="js.js"></script>
+</body>
+</html>

+ 111 - 0
MODULE/js.js

@@ -0,0 +1,111 @@
+function createStore(reducer){
+    let state       = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
+    let cbs         = []                     //массив подписчиков
+
+    const getState  = () => state            //функция, возвращающая переменную из замыкания
+    const subscribe = cb => (cbs.push(cb),   //запоминаем подписчиков в массиве
+        () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
+
+    const dispatch  = action => {
+        if (typeof action === 'function'){ //если action - не объект, а функция
+            return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
+        }
+        const newState = reducer(state, action) //пробуем запустить редьюсер
+        if (newState !== state){ //проверяем, смог ли редьюсер обработать action
+            state = newState //если смог, то обновляем state
+            for (let cb of cbs)  cb() //и запускаем подписчиков
+        }
+    }
+    return {
+        getState, //добавление функции getState в результирующий объект
+        dispatch,
+        subscribe //добавление subscribe в объект
+    }
+}
+
+    function promiseReducer(state = {}, {promiseName, type, status, payload, error}) {
+        if (type === 'PROMISE') {
+            return {...state, [promiseName]: {status, payload, error}}
+        }
+        return state
+    }
+
+    const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));
+
+    const actionPending = promiseName => ({promiseName, type: 'PROMISE', status: 'PENDING'})
+    const actionFulfilled = (promiseName, payload) => ({promiseName, type: 'PROMISE', status: 'FULFILLED', payload})
+    const actionRejected = (promiseName, error) => ({promiseName, type: 'PROMISE', status: 'REJECTED', error})
+
+    const actionPromise = (promiseName, promise) =>
+        async dispatch => {
+            dispatch(actionPending(promiseName)) //сигнализируем redux, что промис начался
+            try {
+                const payload = await promise //ожидаем промиса
+                dispatch(actionFulfilled(promiseName, payload)) //сигнализируем redux, что промис успешно выполнен
+                return payload //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
+            } catch (error) {
+                dispatch(actionRejected(promiseName, error)) //в случае ошибки - сигнализируем redux, что промис несложился
+            }
+        }
+
+    const store = createStore(promiseReducer)
+
+    store.subscribe(() => console.log(store.getState())) //должен запускаться 6 раз
+
+    store.dispatch(actionPromise('delay', delay(1000)))
+    store.dispatch(actionPromise('luke', fetch("https://swapi.dev/api/people/1").then(res => res.json())))
+    store.dispatch(actionPromise('tatooine', fetch("https://swapi.dev/api/planets/1").then(res => res.json())))
+
+/////////////////////////////////////////////////////////////////////
+function authReducer (state={}, {token, type}){
+    if (type === 'AUTH_LOGIN') {
+        try {
+            let str = token.split('.')[1];
+            let result = JSON.parse(atob(str))
+            return {...state, 'token': token, 'playload':result}
+        } catch (e) {
+            return {}
+        }
+    }
+    else if (type === 'AUTH_LOGOUT') {
+        return {}
+    }
+    return state
+}
+
+const actionAuthLogin  = token => ({type: 'AUTH_LOGIN', token})
+const actionAuthLogout = ()    => ({type: 'AUTH_LOGOUT'})
+
+const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsiaWQiOiI2Mzc3ZTEzM2I3NGUxZjVmMmVjMWMxMjUiLCJsb2dpbiI6InRlc3Q1IiwiYWNsIjpbIjYzNzdlMTMzYjc0ZTFmNWYyZWMxYzEyNSIsInVzZXIiXX0sImlhdCI6MTY2ODgxMjQ1OH0.t1eQlRwkcP7v9JxUPMo3dcGKprH-uy8ujukNI7xE3A0"
+
+const storeAuth = createStore(authReducer)
+storeAuth.subscribe(() => console.log(storeAuth.getState()))
+
+storeAuth.dispatch(actionAuthLogin(token))
+
+// ///////////////////////////////////////////////////////////////////////
+function cartReducer (state = {}, {type, good, count}) {
+    let goodKey, oldCount, goodValue;
+    if (good) {
+        goodKey = good['_id'];
+        oldCount = state[goodKey]?.count || 0;
+        goodValue = {good, count: oldCount}
+    }
+    if (type === 'CARD_ADD') {
+        goodValue.count += count;
+        return {...state, [goodKey]: goodValue}
+    }
+    else if (type === 'CART_DEL') {
+        delete state[goodKey];
+
+    }
+}
+
+const actionCartAdd = (good, count=1) => ({type: 'CART_ADD', count, good})
+const actionCartSub = (good, count=1) => ({type: 'CART_SUB', count, good})
+const actionCartDel = (good) => ({type: 'CART_DEL', good})
+const actionCartSet = (good, count=1) => ({type: 'CART_SET', count, good})
+const actionCartClear = () => ({type: 'CART_CLEAR'})
+
+/////////////////////////////////////////////////////////////////
+

+ 0 - 130
js.js

@@ -1,130 +0,0 @@
-
-function createStore(reducer) {
-    let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
-    let cbs = []                     //массив подписчиков
-
-    const getState = () => state            //функция, возвращающая переменную из замыкания
-    const subscribe = cb => (cbs.push(cb),   //запоминаем подписчиков в массиве
-        () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
-
-    const dispatch = action => {
-        const newState = reducer(state, action) //пробуем запустить редьюсер
-        if (newState !== state) { //проверяем, смог ли редьюсер обработать action
-            state = newState //если смог, то обновляем state
-            for (let cb of cbs) cb() //и запускаем подписчиков
-        }
-    }
-
-    return {
-        getState, //добавление функции getState в результирующий объект
-        dispatch,
-        subscribe //добавление subscribe в объект
-    }
-}
-
-function reducer(state, {type, ШО, СКОКА, Цена}){ //объект action деструктуризируется на три переменных
-    if (!state){ //начальная уборка в ларьке:
-        return {
-                пиво: {
-                    количество: 100,
-                    цена: 38,
-                },
-                чипсы: {
-                    количество: 100,
-                    цена: 21,
-                },
-                сиги: {
-                    количество: 100,
-                    цена: 55,
-                }
-        }
-    }
-    if (type === 'КУПИТЬ'){ //если тип action - КУПИТЬ, то:
-        return {
-            ...state, //берем все что было из ассортимента
-            [ШО]: state[ШО] - СКОКА //и уменьшаем то, что покупается на количество
-        }
-    }
-    return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
-}
-
-// return {
-//
-// }
-
-let store = createStore(reducer);
-
-const actionByeBeer = СКОКА => ({type: 'КУПИТЬ', ШО: 'пиво', СКОКА})
-const actionByeСrisps = СКОКА => ({type: 'КУПИТЬ', ШО: 'чипсы', СКОКА})
-const actionByeSigarets = СКОКА => ({type: 'КУПИТЬ', ШО: 'сиги', СКОКА})
-
-console.log(store.getState().пиво)
-console.log(store.getState().сиги)
-
-document.body.append(productCard)
-
-for (let elementProduct in store.getState()) {
-    const productCard = document.getElementById('card')
-
-
-    const product = document.getElementById('product')
-    product.innerText = card
-
-    const amount = document.getElementById('amount')
-    amount.innerText = store.getState()[card].количество + `шт`
-
-    const price = document.getElementById('price')
-    price.innerText = store.getState()[card].цена + `грн`
-
-    productCard.append(product)
-    productCard.append(amount)
-    productCard.append(price)
-
-    console.log(card)
-}
-
-
-
-const list = document.createElement("select")
-document.body.append(list)
-
-const choicePrice = document.createElement('div')
-document.body.append(choicePrice)
-
-for (let name of Object.keys(store.getState())) {
-    let product = document.createElement("option")
-    product.innerText = name
-    list.append(product)
-}
-
-const inputAmount = document.createElement('input')
-inputAmount.id = "amount"
-inputAmount.type = 'number'
-inputAmount.min = "0"
-document.body.append(inputAmount)
-
-let total = document.createElement('div');
-
-inputAmount.oninput = list.onchange =  () => {
-    total.innerText = 15 * inputAmount.value;
-}
-document.body.append(total)
-
-const buttonBuy = document.createElement('button')
-buttonBuy.innerText = 'Купить'
-document.body.append(buttonBuy)
-
-// buttonBuy.onclick = () => {
-//     const actionByeBeer = СКОКА => ({type: 'КУПИТЬ', ШО: 'пиво', СКОКА})
-// }
-
-
-
-const person = {
-    name: 'Иван',
-    fatherName: 'Иванович',
-    surname: "Иванов"
-}
-
-const {["name"]:nameOrSurname} = person //деструктуризация с использованием ключа, вычисленного с помощью выражения
-console.log(nameOrSurname)

+ 40 - 1
rgb.js

@@ -121,4 +121,43 @@
     store.dispatch(actionColorRed(0))
     store.dispatch(actionColorGreen(0))
     store.dispatch(actionColorBlue(0))
-} */
+} */
+
+
+function Password(parent, open){
+    this.parent = parent,
+        this.open = open;
+
+    Password.prototype.setValue = () => {
+
+    }
+
+    let passwordInput = document.createElement('input')
+    passwordInput.type = "password"
+    passwordInput.placeholder = 'Введите пароль '
+    parent.append(passwordInput)
+
+    let checkboxButton = document.createElement('input')
+    checkboxButton.type = 'checkbox'
+    checkboxButton.checked = open
+    parent.append(checkboxButton)
+
+
+
+// function Store(reducer) {
+//     let state = reducer(undefined, {})
+//     let cbs = []
+//
+//     this.getState = () => state
+//     this.subscribe = cb => (cbs.push(cb),   //запоминаем подписчиков в массиве
+//         () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
+//
+//     this.dispatch = action => {
+//         const newState = reducer(state, action) //пробуем запустить редьюсер
+//         if (newState !== state) { //проверяем, смог ли редьюсер обработать action
+//             state = newState //если смог, то обновляем state
+//             for (let cb of cbs) cb() //и запускаем подписчиков
+//         }
+//     }
+// }
+//