Browse Source

HW 13 done

suslov-dmytro 1 year ago
parent
commit
6ccefe60e9
5 changed files with 352 additions and 0 deletions
  1. BIN
      13/images/favicon.ico
  2. BIN
      13/images/logo.png
  3. 40 0
      13/index.html
  4. 207 0
      13/script.js
  5. 105 0
      13/styles.css

BIN
13/images/favicon.ico


BIN
13/images/logo.png


+ 40 - 0
13/index.html

@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<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" />
+    <link rel="icon" type="image/x-icon" href="images/favicon.ico">
+    <link rel="stylesheet" href="styles.css">
+    <title>ChatterBox</title>
+</head>
+
+<body>
+
+    <div class="wrapper">
+        <div class="logo">
+            <img src="images/logo.png" alt="" id="logo-img">
+            <h1>ASMER-CHAT</h1>
+        </div>
+
+        <div class="chatBlock">
+            <div id="container"></div>
+            <div class="inputBlock">
+                <input type="text" name="nickname" id="nick" placeholder="Enter nickname..." />
+                <br>
+                <input type="text" name="" id="message" placeholder="Enter message..." />
+                <br />
+                <button id="button">
+                    <p class="buttonText">Send ></p>
+                </button>
+            </div>
+        </div>
+
+    </div>
+
+    <script src="script.js"></script>
+</body>
+
+</html>

+ 207 - 0
13/script.js

@@ -0,0 +1,207 @@
+// Chat Homework
+
+// Этапы.
+
+// Используя функцию jsonPost на адрес http://students.a-level.com.ua:10012 напишите чат-клиент, который:
+
+// Stage 0
+
+// Для поиграться скопируйте в консоль функцию jsonPost (или запустите её с этой страницы) и вызовите её с теми или иными 
+// объектами в качестве второго параметра. см. RPC.
+
+// jsonPost('http://students.a-level.com.ua:10012', {func: 'addMessage', nick: 'Anon', message: 'Я не умею копипастить в консоль, зато умею жать красную кнопку.'})
+
+// Если после объявления функции jsonPost запустить пример выше, то вы напишите в чат.
+
+// Stage 1
+
+// Отправляет сообщения в чат. Для проверки отслеживайте приходящий с сервера nextMessageId, который должен увеличиваться. 
+// Интерфейс: поле ввода ника, поле ввода сообщения, кнопка отправки.
+
+// Stage 2
+
+// Читает все сообщения из чата и выводит их в отдельном контейнере. 
+// Интерфейс: некий div-контейнер, в котором на каждое сообщение создается div (или иной блочный контейнерный тэг) 
+// и в него помещается ник и сообщение. Также там есть timestamp который может показывать время отправки сообщения.
+
+// Stage 3
+
+// Читает только новые сообщения из чата. Для этого надо после каждого получения запоминать nextMessageId и отправлять его 
+// при следующем запросе новых сообщений. Изначально nextMessageId равен нулю, что бы вычитать всю историю сообщений с сервера.
+
+// Stage 4
+
+// Делаем Stage 3 в setInterval для периодической проверки сообщений (раз в 2 -5 секунд).
+
+// Stage 5
+
+// Напишите асинхронную функцию отправки, которая внутри себя будет делать два запроса: на отправку и на проверку, для того 
+// что бы минимизировать задержку между отправкой сообщения пользователя и его появлением в окне чата. 
+// Оформите отдельно функции отправки и проверки новых сообщений как асинхронные (async, возвращает Promise):
+
+// async function sendMessage(nick, message) отсылает сообщение.
+// async function getMessages() получает сообщения и отрисовывает их в DOM
+// async function sendAndCheck() использует две предыдущие для минимизации задержки между отправкой сообщения и приходом их. 
+// Именно эта функция должна запускаться по кнопке.
+// async function checkLoop() использует delay и бесконечный цикл для периодического запуска getMessages().
+
+// Stage 6
+
+// Прогуглить и разобраться с fetch и заменить внутренности jsonPost на код, использующий fetch вместо XMLHttpRequest.
+
+// Информация
+
+// jsonPost
+
+// Данная промисифицированная функция (кстати, сделайте из неё асинхронную) умеет общаться с моим чат-сервером отправляя 
+// RPC запросы используя JSON. Remote Procedure Call - вызов функций удаленно, имя функции и параметры передаются AJAX-ом 
+// в формате (например) JSON.
+
+// function jsonPost(url, data)
+// {
+//     return new Promise((resolve, reject) => {
+//         var x = new XMLHttpRequest();   
+//         x.onerror = () => reject(new Error('jsonPost failed'))
+//         //x.setRequestHeader('Content-Type', 'application/json');
+//         x.open('POST', url, true);
+//         x.send(JSON.stringify(data))
+
+//         x.onreadystatechange = () => {
+//             if (x.readyState == XMLHttpRequest.DONE && x.status == 200){
+//                 resolve(JSON.parse(x.responseText))
+//             }
+//             else if (x.status != 200){
+//                 reject(new Error('status is not 200'))
+//             }
+//         }
+//     })
+// }
+
+// Первым параметром указывается URL (см. выше) на который отправляется методом POST с JSON, вторым - готовый к JSONификации 
+// объект, который вы хотите отправить на сервер.
+
+// RPC
+
+// addMessage
+
+// Если вы отправите подобный JSON на сервер (см jsonPost), то сервер запишет ваше сообщение во внутренний массив и отдаст 
+// новую длину массива. После этого другие могут прочесть это сообщение, используя метод getMessages.
+
+// {func: 'addMessage', nick: 'msg', message: 'msg'}
+
+// Поле func является обязательным и содержит имя функции, которая должна быть вызвана на сервере. Функция на сервере получает 
+// параметром остальной объект (поля nick и message) В ответ вы получите так же объект:
+
+// {nextMessageId: 100500} 
+// где 100500: новая длина массива сообщений на сервере после добавления вашего сообщения.
+
+// getMessages
+
+// Позволяет прочесть часть массива сообщений от отпределенного индекса и до конца. 
+// Используется для последовательной дочитки новых сообщений. Для этого надо передать в jsonPost подобный объект:
+
+// {func: 'getMessages', messageId: 0}
+
+// При значении 0 в messageId сервер отдаст сообщения от 0 до конца, т. е. весь массив:
+
+// {
+// 	'data': [
+// 		{
+// 			'nick': 'test',
+// 			'message': 'test',
+// 			'timestamp': 1524225450317
+// 		},
+// 		{
+// 			'nick': 'test',
+// 			'message': 'test2',
+// 			'timestamp': 1524225460973
+// 		},
+// 		{
+// 			'nick': 'test',
+// 			'message': 'test3',
+// 			'timestamp': 1524225504849
+// 		},
+// 		{
+// 			'nick': 'SirkoSobaka',
+// 			'message': 'Hello!',
+// 			'timestamp': 1524226323310
+// 		},
+// 		{
+// 			'nick': 'SirkoSobaka',
+// 			'message': 'Hello!',
+// 			'timestamp': 1524226326628
+// 		},
+// 	],
+// 	'nextMessageId': 5
+// }
+
+// После чего вы итерируете по data и выводите каждый отдельный объект как DOM-элемент с текстом, и, возможно, вложенной 
+// версткой (время в отдельном элементе и т.п.)
+// nextMessageId вы запоминаете для того, что бы отправить следующий запрос начиная с него (т. е. с 68 в примере выше). 
+// Тогда сервер отдаст вам только сообщения новее последнего запроса.
+
+// Chat Server
+
+// Если у вас не чрезмерно свежий хром, то это можно делать даже на локалхосте и открывать файл из браузера с диска. 
+// Сервер позволяет соединятся с собой с любого домена.
+
+// Удачи :-)
+
+const url = 'http://students.a-level.com.ua:10012';
+const nick = document.getElementById('nick');
+const message = document.getElementById('message');
+const btnSendMessage = document.getElementById('button');
+const container = document.getElementById('container');
+let nextMessageId = 1;
+let delay = 1000;
+setInterval(getMessages, delay);
+
+function getMessages() {
+    jsonPost(url, { func: 'getMessages', messageId: nextMessageId })
+        .then((response) => response.json())
+        .then((data) => {
+            nextMessageId = data.nextMessageId;
+            updateMessages(data.data);
+        });
+}
+
+function jsonPost(url, data) {
+    return fetch(url, {
+        method: 'POST',
+        body: JSON.stringify(data),
+    });
+}
+
+function updateMessages(messageList) {
+    messageList.forEach((msg) => {
+        newGotMessage(msg);
+    });
+}
+
+function newGotMessage({ nick, message, timestamp }) {
+    const newBlock = document.createElement('div');
+    newBlock.classList.add('block');
+    const time = new Date(timestamp);
+    let html = '';
+    html += `<p>${nick}<p>`;
+    html += `<p class='message'>'${message}'</p>`;
+    html += `<p>${time.toString()}</p>`;
+    newBlock.innerHTML = html;
+    container.prepend(newBlock);
+}
+
+btnSendMessage.addEventListener('click', sendAndCheck);
+
+async function sendAndCheck() {
+    await sendMessage();
+    getMessages();
+    message.value = '';
+}
+
+async function sendMessage() {
+    jsonPost(url, {
+        func: 'addMessage',
+        nick: nick.value,
+        message: message.value,
+    });
+}

+ 105 - 0
13/styles.css

@@ -0,0 +1,105 @@
+body {
+    background-color: #FBFBD4;
+    margin: 0;
+    box-sizing: border-box;
+    overflow-x: hidden;
+}
+
+.logo {
+    background-color: #adad6b;
+    height: 150px;
+    padding: 10px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-direction: column;
+}
+
+#logo-img {
+    display: block;
+    height: 100px;
+}
+
+h1 {
+    text-align: center;
+    color: #000;
+    height: 100px;
+    margin: 0;
+}
+
+input {
+    padding-left: 10px;
+    font-size: 20px;
+    width: 500px;
+    height: 50px;
+}
+
+#chat {
+    padding-left: 20px;
+    font-size: 25px;
+    width: 1250px;
+    height: 600px;
+}
+
+.chatBlock{
+    display: flex;
+    align-items: center;
+    flex-direction: column;
+    padding: 10px;
+}
+
+.inputBlock {
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    justify-content: space-evenly;
+    width: 80%;
+    padding: 20px;
+    background-color: #727229;
+    position: fixed;
+    margin-top: 55vh;
+    height: 200px;
+    border-radius: 30px;
+}
+
+#button {
+    height: 50px;
+    width: 120px;
+    background-color: #f5f5dc;
+}
+
+#button:hover {
+    opacity: 0.8;
+}
+
+.buttonText {
+    margin: 0;
+    font-size: 20px;
+    color: #000;
+}
+
+.chat {
+    max-width: 100%;
+    margin: 0 auto;
+    display: flex;
+    justify-content: center;
+}
+
+.block {
+    max-width: 1200px;
+    border-radius: 30px 30px 30px 0px;
+    padding: 0 30px;
+    margin: 7px 20px;
+    color: #000;
+    background-color: #D0C698;
+}
+
+#container {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    padding-top: 15px;
+    background-color: #fff;
+    max-width: 80%;
+    border-radius: 30px;
+}