diff --git a/assets/HypertextPages/chat-members.nytl.html b/assets/HypertextPages/chat-members.nytl.html new file mode 100644 index 0000000..7a7b41c --- /dev/null +++ b/assets/HypertextPages/chat-members.nytl.html @@ -0,0 +1,61 @@ +{% ELDEF main JSON pres JSON userinfo JSON openedchat JSON initial_chatUpdResp %} + + + + + + + + + + {%w pres.chat-members.members-of %} {%w openedchat.name %} + + +{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %} + + + + + +
+ + +
+ New chat +
+ +
+
+
+ + + + + + +{% ENDELDEF %} diff --git a/assets/HypertextPages/chatSettings.nytl.html b/assets/HypertextPages/chatSettings.nytl.html deleted file mode 100644 index 71269c7..0000000 --- a/assets/HypertextPages/chatSettings.nytl.html +++ /dev/null @@ -1,46 +0,0 @@ -{% ELDEF main JSON pres JSON userinfo %} - - - - - - - Настройки комнаты - - -
-
- - -
-
- -
-
- -
-
- -
-
-
- × -

Добавить участников

-
-
- -
- -
-
- - - -{% ENDELDEF%} \ No newline at end of file diff --git a/assets/HypertextPages/edit-profile.nytl.html b/assets/HypertextPages/edit-profile.nytl.html new file mode 100644 index 0000000..ebac231 --- /dev/null +++ b/assets/HypertextPages/edit-profile.nytl.html @@ -0,0 +1,71 @@ +{% ELDEF main JSON pres JSON userinfo JSON alienprofile JSON errors %} + + + + + + + + + {%w pres.edit-profile.header-profile-of %} {%w alienprofile.name %} + + + +
+ + + {% FOR error IN errors %} +
+ {% W error.text %} +
+ {% ENDFOR %} + +
+

{% W alienprofile.name %}

+

{%w pres.edit-profile.directive-nickname %} {% W alienprofile.nickname %}

+

+ {% W alienprofile.bio %} +

+
+ +
+

{%w pres.edit-profile.change-user-attributes %}

+
+ + + + + + + + + +
+ + + +
+ + + +
+ +
+ + +
+
+
+ + + +{% ENDELDEF%} diff --git a/assets/HypertextPages/pass-pres-userinfo.nytl.html b/assets/HypertextPages/pass-pres-userinfo.nytl.html deleted file mode 100644 index 8331b75..0000000 --- a/assets/HypertextPages/pass-pres-userinfo.nytl.html +++ /dev/null @@ -1,6 +0,0 @@ -{% ELDEF main JSON pres JSON userinfo %} - -{% ENDELDEF %} diff --git a/assets/HypertextPages/profile.nytl.html b/assets/HypertextPages/profile.nytl.html deleted file mode 100644 index 5c9505a..0000000 --- a/assets/HypertextPages/profile.nytl.html +++ /dev/null @@ -1,39 +0,0 @@ -{% ELDEF main JSON pres JSON userinfo %} - - - - - - Профиль - - -
-
-

Профиль пользователя

- Назад -
-
-
-
-
- -
-
-
-
-
-
-
-

О себе

-
- -
- -
-
- - - - - -{% ENDELDEF%} diff --git a/assets/HypertextPages/registration.nytl.html b/assets/HypertextPages/registration.nytl.html deleted file mode 100644 index e9810ba..0000000 --- a/assets/HypertextPages/registration.nytl.html +++ /dev/null @@ -1,27 +0,0 @@ -{% ELDEF main JSON pres JSON userinfo %} - - - - - - Страница Регистрации - - - - - -
-

Вход

-
-
-
-
- -
-
-
- - - - -{% ENDELDEF %} diff --git a/assets/HypertextPages/view-profile.nytl.html b/assets/HypertextPages/view-profile.nytl.html new file mode 100644 index 0000000..af04f9c --- /dev/null +++ b/assets/HypertextPages/view-profile.nytl.html @@ -0,0 +1,36 @@ +{% ELDEF main JSON pres JSON userinfo JSON alienprofile %} + + + + + + + + + {%w pres.view-profile.header-profile-of %} {%w alienprofile.name %} + + + +
+ + +
+

{%w alienprofile.name %}

+

{%w pres.view-profile.directive-nickname%} {%w alienprofile.nickname %}

+

+ {%w alienprofile.bio %} +

+
+
+ + + + +{% ENDELDEF%} diff --git a/assets/css/chat-members.css b/assets/css/chat-members.css new file mode 100644 index 0000000..af0d1c6 --- /dev/null +++ b/assets/css/chat-members.css @@ -0,0 +1,33 @@ +#CM-btn-add { + margin-top: 6px; + margin-bottom: 4px; + display: none; +} + +.CM-member-box { + display: flex; + flex-direction: row; +} + +.CL-member-box-nickname { + margin-left: 8px; + justify-self: flex-start; +} + +.CM-member-box-name { + margin-left: 14px; + justify-self: flex-start; +} + +.CM-member-box-role { + margin-left: auto; + justify-self: flex-end; +} + +.CM-member-box-leave-btn { + margin-left: 10px; + margin-right: 8px; + justify-self: flex-end; + width: 16px; + cursor: pointer; +} diff --git a/assets/css/chatSettings.css b/assets/css/chatSettings.css deleted file mode 100644 index ab8da39..0000000 --- a/assets/css/chatSettings.css +++ /dev/null @@ -1,163 +0,0 @@ -body { - font-family: Arial, sans-serif; - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - margin: 0; - background-color: #e5e5e5; -} - -.chat-settings-container { - width: 100%; - max-width: 800px; - background-color: white; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - display: flex; - flex-direction: column; - border-radius: 8px; - overflow: hidden; -} - -.chat-settings-container-header { - background-color: #007bb5; - color: white; - padding: 25px; - display: flex; - justify-content: center; - align-items: center; -} - -.room-name { - font-size: 24px; - width: 80%; - text-align: center; - border-radius: 10px; - border: none; -} -.changeName { - padding: 8px 10px; - background-color: #28a745; - color: white; - border-radius: 20px; - border: none; - cursor: pointer; -} -.changeName:hover { - background-color: #005f8c; -} -.chat-settings-container-body { - padding: 15px; - background-color: #f7f7f7; - flex: 1; -} - -#chat-settings-container-body { - list-style-type: none; - padding: 0; -} - -#chat-settings-container-body li { - margin-bottom: 10px; - background-color: white; - padding: 10px; - border-radius: 8px; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -} -.remove-member-button { - background-color: red; - color: white; - border: none; - padding: 5px 10px; - cursor: pointer; - margin-left: 10px; - border-radius: 4px; -} -.remove-member-button:hover { - background-color: darkred; -} -.chat-settings-container-invite { - padding: 15px; - background-color: white; - text-align: center; -} - -.invite-member { - padding: 10px 20px; - border: none; - background-color: #28a745; - color: white; - border-radius: 20px; - cursor: pointer; - transition: background-color 0.3s ease; -} - -.invite-member:hover { - background-color: #218838; -} - -.overlay { - display: none; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.5); - justify-content: center; - align-items: center; - z-index: 1000; -} - -.add-members { - background-color: white; - padding: 30px; - border-radius: 8px; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); - width: 100%; - max-width: 400px; - text-align: center; -} - -.add-members-header { - position: relative; - margin-bottom: 20px; -} - -.add-members-header h2 { - margin: 0; -} - -.close { - position: absolute; - right: 10px; - top: 0; - font-size: 24px; - font-weight: bold; - cursor: pointer; -} - -.add-members-body input { - width: 95%; - padding: 10px; - margin-bottom: 20px; - border: 1px solid #ddd; - border-radius: 4px; - margin-right: 15%; - outline: none; -} - -.add-member-button { - padding: 10px 20px; - border: none; - background-color: #007bb5; - color: white; - border-radius: 20px; - cursor: pointer; - outline: none; - transition: background-color 0.3s ease; -} - -.add-member-button:hover { - background-color: #005f8c; -} \ No newline at end of file diff --git a/assets/css/common-popup.css b/assets/css/common-popup.css new file mode 100644 index 0000000..c9dec24 --- /dev/null +++ b/assets/css/common-popup.css @@ -0,0 +1,50 @@ +.popup-overlay-veil { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.6); + + z-index: 99; + display: none; /* Hidden by default */ +} + +.popup-window { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + padding: 20px; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); + + z-index: 100; + display: none; +} + +.popup-btn { + display: inline; + padding: 5px; + border-bottom: 3px; +} + +.popup-window-btn-yes { + background-color: #0c7f0e; + border-radius: 5px; + padding: 12px; + color: white; +} + +.popup-window-btn-no { + background-color: #ff0005; + border-radius: 5px; + padding: 12px; + color: white; +} + +.popup-window-msg { + padding-left: 20px; + font-weight: bold; + font-size: 1.3em; +} \ No newline at end of file diff --git a/assets/css/common.css b/assets/css/common.css new file mode 100644 index 0000000..b5f7406 --- /dev/null +++ b/assets/css/common.css @@ -0,0 +1,206 @@ +/* Profile view elements */ +.profile-container { + background: white; + border-radius: 5px; + padding: 20px; + margin-top: 60px; /* Space below the fixed panel */ + box-shadow: 0 10px 15px rgba(0, 0, 0, 0.3); +} + +.profile-name-text { + color: black; +} + +.profile-nickname-text{ + color: #444; + text-align: left; +} + +.profile-bio-text { + padding-top: 40px; + text-align: left; + line-height: 1.6; + color: black; +} + +/* Panels */ +.panel { + width: 100%; + border: 2px solid blue; + background-color: #54b3ff; + display: flex; + flex-direction: row; + align-items: center; +} + +.panel-thing { + padding: 6px; +} + +.panel-header-txt{ + color: white; + font-size: 1.9em; + flex: 1; + text-align: center; +} + + +/* Containers for the whole document */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + font-family: Arial, sans-serif; +} + +.document-container { + width: 80%; /* Full width of the viewport */ + margin: 0 auto; /* Center the container horizontally */ +} + +.fullscreen-container { + width: 80%; /* Full width of the viewport */ + height: 100vh; /* Full height of the viewport */ + display: flex; + flex-direction: column; /* Stack children vertically */ + margin: 0 auto; /* Center the container horizontally */ +} + +@media (orientation: landscape) { + .resp-container{ + width: 80%; + } +} + +@media (orientation: portrait){ + .resp-container{ + width: 100%; + } +} + +body { + background-color: #f000f0; + background-image: url("/assets/img/clavicle-transparent.png"), url("/assets/img/broken-clavicle.png"); + background-repeat: revert; + background-size: 10%, 25%; +} + +/* Notifications, returned from server and embedded into html page at render-time */ + +.server-notif-error-msg-box{ + font-size: 1.3em; + text-align: center; + padding: 10px; + border: 2px solid red; + border-radius: 30px; + background-color: #ff5050; + max-width: 40%; + margin: 15px auto; +} + +/* Centered headers */ + +.wide-centered-header { + width: 100%; + text-align: center; + font-size: 1.4em; +} +/* Cool buttons with text */ + +.action-button { + padding: 10px 15px; + background-color: #007bff; + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s; +} + + +.action-button:hover { + background-color: #0056b3; /* Darker blue on hover */ +} + +/* This is for centering non-100%wide block */ + +.centered-block-el { + display: block; + margin-left: auto; + margin-right: auto; +} + +/* Beautiful text input */ + +.one-line-input { + width: 100%; + padding: 8px; + margin: 8px 0; + border: 1px solid #ccc; + border-radius: 4px; +} + +.multiline-input { + width: 100%; + /*max-width: 600px;*/ + height: 200px; + padding: 10px; + font-size: 1.15em; + border: 2px solid #ccc; + border-radius: 5px; + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1); /* Subtle shadow */ + outline: none; /* Remove default outline on focus */ + resize: vertical; /* Allow resizing vertically */ + transition: border-color 0.15s, box-shadow 0.15s; /* Smooth transition for border color and shadow */ +} + +.multiline-input:focus { + border-color: #007bff; /* Change border color on focus */ + box-shadow: 0 0 5px rgba(0, 123, 255, 0.5); /* Shadow on focus */ +} + +/* Handles the case of list of elements with dickanme, name, role and delete button + For list of chats and list of users in chat */ +.dynamic-block-list { + margin-top:12px; + display: flex; + flex-direction: column; + background-color: white; + border: 1px solid #c7c7c7; + align-items: stretch; + padding-left: 8px; + padding-right: 8px; + padding-bottom: 8px; +} + +.dynamic-block-list-el { + margin-top: 8px; + background-color: white; + border: 1px solid #c7c7c7; + color: black; + padding: 5px; +} + +.button-add{ + width: 50px; + cursor: pointer; +} + +.dynamic-block-list-el-container{ + width: 100%; +} + +.entity-nickname-txt { + font-weight: bold; + color: black; + text-decoration: none; + font-size: 1.5em; +} + +.entity-reg-field-txt { + /* For name and role */ + color: #242424; + text-decoration: none; + font-size: 1.5em; +} diff --git a/assets/css/edit-profile.css b/assets/css/edit-profile.css new file mode 100644 index 0000000..ae0932d --- /dev/null +++ b/assets/css/edit-profile.css @@ -0,0 +1,23 @@ +/* The morbid thing */ +table.logins-input-table { + width: 100%; + border-collapse: collapse; /* Combine borders */ +} +.logins-input-td1, .logins-input-td2 { + border: none; +} +.logins-input-td1 { + text-align: left; + padding-right: 5px; + white-space: nowrap; /* Prevent text wrap, keeping it in one line */ + overflow: hidden; /* Hide overflow content */ + text-overflow: ellipsis; /* Show ellipsis for overflowing text */ +} +.logins-input-td2 { + width: 100%; +} + +#input-change-bio{ + margin-top: 5px; + margin-bottom: 5px; +} diff --git a/assets/css/profile.css b/assets/css/profile.css deleted file mode 100644 index c60dbf5..0000000 --- a/assets/css/profile.css +++ /dev/null @@ -1,129 +0,0 @@ -body { - display: flex; - justify-content: center; - align-items: center; - height: 90vh; - background-color: #e5e5e5; - font-family: Arial, sans-serif; -} -.main-container { - width: 700px; - height: 700px; - border-color: antiquewhite; - background-color: white; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - border-radius: 10px; -} -.profile-header { - width: 700px; - height: 160px; - border-color: antiquewhite; - background-color: #0088cc; - border-radius: 10px; - position: relative; -} -.return { - background-color: #f0f0f0; - cursor: pointer; - width: 100px; - text-decoration: none; - color: black; - display: flex; - justify-content: center; - align-items: center; - height: 30px; - border-radius: 10px; - position: absolute; - left: 20px; - top: 25px; - border: none; -} -.return:hover{ - text-decoration: underline; - color: #0088cc; -} -form { - display: flex; - flex-direction: column; - align-items: center; -} - -.columns { - display: flex; - justify-content: center; - align-items: flex-start; - gap: 20px; - margin-bottom: 20px; -} - -.column { - display: flex; - flex-direction: column; - align-items: center; -} -.add { - width: 100px; - height: 40px; - border-width: 2px; - cursor: pointer; - font-size: 16px; - border-radius: 10px; -} -.add:hover { - background-color: #007bb5; -} -.image-button:hover { - opacity: 0.8; -} - -.image-button:active { - transform: scale(0.95); -} -#login { - font-family: Arial, sans-serif; - font-size:16px; - width: 150px; - height: 20px; - border-radius: 10px; - border-color: #2F4F4F; -} -#username { - font-family: Arial, sans-serif; - font-size:16px; - width: 150px; - height: 20px; - margin-bottom: 1px; - margin-top: 50px; - border-radius: 10px; - border-color: #2F4F4F; -} -#bio { - height: 150px; - width: 500px; - padding: 10px; - box-sizing: border-box; - font-family: Arial, sans-serif; - font-size:14px; - text-align: left; - vertical-align: top; - margin-bottom: 5px; -} -.save { - cursor:pointer; - font-size: 16px; - border-radius: 15px; - border-color: #2F4F4F; - height: 40px; - width: 150px; -} -.save:hover { - background-color: #007bb5; -} -.avatar { - border-radius: 50%; - object-fit: cover; -} \ No newline at end of file diff --git a/assets/css/registration.css b/assets/css/registration.css deleted file mode 100644 index b42c992..0000000 --- a/assets/css/registration.css +++ /dev/null @@ -1,77 +0,0 @@ -dy { - font-family: Arial, sans-serif; - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - margin: 0; - background-color: #e5e5e5; -} - -.form-container { - width: 100%; - max-width: 400px; - background-color: white; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); - display: flex; - flex-direction: column; - border-radius: 8px; - padding: 40px; - text-align: center; -} - -h1 { - margin-bottom: 20px; - color: #2F4F4F; -} - -input { - width: 100%; - background: #f7f7f7; - font-size: 16px; - padding: 10px; - border: 1px solid #ddd; - border-radius: 20px; - margin-bottom: 15px; - outline: none; -} - -button { - width: 100%; - padding: 15px; - border: none; - background-color: #0088cc; - color: white; - border-radius: 20px; - cursor: pointer; - outline: none; - font-size: 16px; - font-weight: bold; - transition: background-color 0.3s; -} - -button:hover, -button:focus-visible { - background-color: #007bb5; -} - -.hide-cursor::placeholder { - color: #000; -} - -.hide-cursor { - caret-color: transparent; -} - -.no-select { - -webkit-user-select: none; /* Для Safari */ - -moz-user-select: none; /* Для Firefox */ - user-select: none; /* Для всех остальных браузеров */ -} - -div { - color: red; - font-size: 15px; - margin-top: 10px; - display: none; -} diff --git a/assets/img/add.svg b/assets/img/add.svg new file mode 100644 index 0000000..e65c886 --- /dev/null +++ b/assets/img/add.svg @@ -0,0 +1,20 @@ + + + + + diff --git a/assets/img/empty_avatar.png b/assets/img/empty_avatar.png deleted file mode 100644 index c1aa714..0000000 Binary files a/assets/img/empty_avatar.png and /dev/null differ diff --git a/assets/img/favicon.png b/assets/img/favicon.png new file mode 100644 index 0000000..614d564 Binary files /dev/null and b/assets/img/favicon.png differ diff --git a/assets/img/list-rooms.svg b/assets/img/list-rooms.svg new file mode 100644 index 0000000..7499b7f --- /dev/null +++ b/assets/img/list-rooms.svg @@ -0,0 +1,28 @@ + + + + + + + + + + diff --git a/assets/img/return.svg b/assets/img/return.svg new file mode 100644 index 0000000..f3a18d4 --- /dev/null +++ b/assets/img/return.svg @@ -0,0 +1,20 @@ + + + + + + + + diff --git a/assets/img/user.svg b/assets/img/user.svg new file mode 100644 index 0000000..228c197 --- /dev/null +++ b/assets/img/user.svg @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/assets/js/chat-members.js b/assets/js/chat-members.js new file mode 100644 index 0000000..cf9f42a --- /dev/null +++ b/assets/js/chat-members.js @@ -0,0 +1,188 @@ +let LocalHistoryId = 0; + +function genSentBase(){ + return { + 'chatUpdReq': { + 'LocalHistoryId': LocalHistoryId, + 'chatId': openedchat.id + } + }; +} + +let members = new Map(); +let memberBoxes = new Map(); +let myRoleHere = null; // Dung local state updates should be updated first + +let userDeletionWinStoredUId = -1; + +function shouldShowDeleteButton(memberSt){ + return userinfo.uid !== memberSt.userId && myRoleHere === userChatRoleAdmin && memberSt.roleHere !== userChatRoleDeleted; +} + +function updateBoxWithSt(box, memberSt){ + let ID = memberSt.userId; + let roleP = box.querySelector(".CM-member-box-role"); + roleP.innerText = memberSt.roleHere; + box.style.backgroundColor = roleToColor(memberSt.roleHere); + box.querySelector(".CM-member-box-leave-btn").style.display = + (shouldShowDeleteButton(memberSt) ? "block" : "none"); +} + +function convertMemberStToBox(memberSt){ + let ID = memberSt.userId; + let userProfileURI = "/user/" + memberSt.nickname; + + let box = document.createElement("div"); + box.className = "dynamic-block-list-el CM-member-box"; + box.style.backgroundColor = roleToColor(memberSt.roleHere); + + let inBoxNickname = document.createElement("a"); + box.appendChild(inBoxNickname); + inBoxNickname.className = "entity-nickname-txt CM-member-box-nickname"; + inBoxNickname.innerText = memberSt.nickname; + inBoxNickname.href = userProfileURI; + + let inBoxName = document.createElement("a"); + box.appendChild(inBoxName); + inBoxName.className = "entity-reg-field-txt CM-member-box-name"; + inBoxName.innerText = memberSt.name; + inBoxName.href = userProfileURI; + + let inBoxUserRoleHere = document.createElement("p"); + box.appendChild(inBoxUserRoleHere); + inBoxUserRoleHere.className = "entity-reg-field-txt CM-member-box-role"; + inBoxUserRoleHere.innerText = memberSt.roleHere; + + let inBoxLeaveBtn = document.createElement("img"); + box.appendChild(inBoxLeaveBtn); + inBoxLeaveBtn.className = "CM-member-box-leave-btn"; + inBoxLeaveBtn.src = "/assets/img/delete.svg"; + inBoxLeaveBtn.onclick = function (ev) { + if (ev.button !== 0) + return; + userDeletionWinStoredUId = ID; + document.getElementById("user-deletion-win-title").innerText = + pres['chat-members']['reask-kick-user-X'] + " " + memberSt.nickname + "?"; + activatePopupWindowById("user-deletion-win"); + }; + box.querySelector(".CM-member-box-leave-btn").style.display = + (shouldShowDeleteButton(memberSt) ? "block" : "none"); + + return box; +} + +function updateLocalStateFromChatUpdResp(chatUpdResp){ + LocalHistoryId = chatUpdResp.HistoryId; + // If my role is updated, we need to update all the boes of already set users (kick button can appear and disappear) + let literalMemberList = document.getElementById("CM-list"); + // We ignore messages and everything related to them. Dang, I really should add an argument to disable message lookup here + for (let memberSt of chatUpdResp.members){ + console.log([memberSt, userinfo.uid, myRoleHere]); + if (memberSt.userId === userinfo.uid && myRoleHere !== memberSt.roleHere){ + myRoleHere = memberSt.roleHere; + for (let [id, memberSt] of members){ + let box = memberBoxes.get(id); + updateBoxWithSt(box, memberSt); + } + document.getElementById("CM-btn-add").style.display = + (memberSt.roleHere === userChatRoleAdmin ? "block" : "none"); + console.log("DEBUG " + (memberSt.roleHere === userChatRoleAdmin ? "block" : "none")); + break; + } + } + for (let memberSt of chatUpdResp.members){ + let id = memberSt.userId; + if (members.has(id)){ + updateBoxWithSt(memberBoxes.get(id), memberSt); + } else { + if (memberSt.roleHere !== userChatRoleDeleted){ + members.set(id, memberSt); + let box = convertMemberStToBox(memberSt); + memberBoxes.set(id, box); + literalMemberList.appendChild(box); + } + } + } +} + +function updateLocalStateFromRecv(Recv){ + updateLocalStateFromChatUpdResp(Recv.chatUpdResp); +} + +function configureSummonUserInterface(){ + document.getElementById("user-summoning-yes").onclick = function(ev ){ + if (ev.button !==0) + return; + let nickname = String(document.getElementById("summoned-user-nickname").value); + let isReadOnly = document.getElementById("summoned-user-is-read-only").checked; + deactivateActivePopup(); + let Sent = genSentBase(); + Sent.nickname = nickname; + Sent.makeReadOnly = Boolean(isReadOnly); + apiRequest("addMemberToChat", Sent). + then((Recv) => { + updateLocalStateFromRecv(Recv); + }).catch((e) => { + console.log(e); + alert(pres['chat-members']["failed-summon-member"]); + }); + }; + + document.getElementById("user-summoning-no").onclick = function (ev) { + if (ev.button !== 0) + return; + deactivateActivePopup(); + }; + + document.getElementById("CM-btn-add").onclick = function(ev) { + if (ev.button !== 0) + return; + document.getElementById("summoned-user-nickname").value = ""; + // read-only flag persists throughout user summoning sessions, and IT IS NOT A BUG + activatePopupWindowById("user-summoning-win"); + }; +} + +/* Popup activation button is configured for each box separately */ +function configureKickUserInterfaceWinPart(){ + document.getElementById("user-deletion-yes").onclick = function (ev){ + if (ev.button !== 0) + return; + deactivateActivePopup(); + if (userDeletionWinStoredUId < 0) + throw new Error("Karaul"); + let Sent = genSentBase(); + Sent.userId = userDeletionWinStoredUId; + apiRequest("removeMemberFromChat", Sent). + then((Recv) => { + updateLocalStateFromRecv(Recv); + }).catch((e) => { + console.log(e); + alert(pres['chat-members']["failed-kick-member"]); + }); + } + + document.getElementById("user-deletion-no").onclick = function (ev) { + if (ev.button !== 0) + return; + deactivateActivePopup(); + }; +} + +__mainloopDelayMS = 5000; +__guestMainloopPollerAction = function (){ + console.log("Hello, world"); + apiRequest("chatPollEvents", genSentBase()). + then((Recv) => { + console.log(Recv); + updateLocalStateFromRecv(Recv); + }); +} + +window.onload = function(){ + console.log("Page loaded"); + configureSummonUserInterface(); + configureKickUserInterfaceWinPart(); + updateLocalStateFromChatUpdResp(initial_chatUpdResp); + mainloopPoller(); +} diff --git a/assets/js/chatSettings.js b/assets/js/chatSettings.js deleted file mode 100644 index 337bc00..0000000 --- a/assets/js/chatSettings.js +++ /dev/null @@ -1,146 +0,0 @@ -const chatId = 123; -let localHistoryId = 0; - -function handleChangeName() { - const newName = document.getElementById('room-name').value; - changeChatName(chatId, localHistoryId, newName).then(() => { - }); -} -function handleAddMember() { - const login = document.getElementById('newMemberLogin').value; - if (login) { - addMemberToChat(chatId, localHistoryId, login).then(() => { - const list = document.getElementById("chat-settings-container-body"); - const listItem = document.createElement("li"); - listItem.textContent = login; - list.appendChild(listItem); - closeAdd(); - }); - } -} -function handleRemoveMember(userId) { - removeMemberFromChat(chatId, localHistoryId, userId).then(() => { - const listItem = document.getElementById(`member-${userId}`); - if (listItem) { - listItem.remove(); - } - }); -} -function openInvite() { - document.getElementById("add_members").style.display = "flex"; -} - -function closeAdd() { - document.getElementById("add_members").style.display = "none"; -} - -function updateChat() { - pollChatEvents(chatId, localHistoryId).then(() => { - }); -} -document.addEventListener('DOMContentLoaded', () => { - updateChat(); -}); -async function changeChatName(chatId, localHistoryId, newName) { - try { - const response = await fetch('/api/changeChatName', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chatUpdReq: { - chatId: chatId, - LocalHistoryId: localHistoryId - }, - content: { - name: newName - } - }) - }); - const data = await response.json(); - if (data.status === 0) { - console.log('Название комнаты успешно изменено'); - } else { - console.error('Ошибка при изменении названия комнаты:', data.error); - } - } catch (error) { - console.error('Ошибка сети при изменении названия комнаты:', error); - } -} -async function addMemberToChat(chatId, localHistoryId, nickname) { - try { - const response = await fetch('/api/addMemberToChat', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chatUpdReq: { - chatId: chatId, - LocalHistoryId: localHistoryId - }, - nickname: nickname - }) - }); - const data = await response.json(); - if (data.status === 0) { - console.log('Участник успешно добавлен'); - } else { - console.error('Ошибка при добавлении участника:', data.error); - } - } catch (error) { - console.error('Ошибка сети при добавлении участника:', error); - } -} - -async function removeMemberFromChat(chatId, localHistoryId, userId) { - try { - const response = await fetch('/api/removeMemberFromChat', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chatUpdReq: { - chatId: chatId, - LocalHistoryId: localHistoryId - }, - userId: userId - }) - }); - const data = await response.json(); - if (data.status === 0) { - console.log('Участник успешно удален'); - } else { - console.error('Ошибка при удалении участника:', data.error); - } - } catch (error) { - console.error('Ошибка сети при удалении участника:', error); - } -} - -async function pollChatEvents(chatId, localHistoryId) { - try { - const response = await fetch('/api/chatPollEvents', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - chatUpdReq: { - chatId: chatId, - LocalHistoryId: localHistoryId - } - }) - }); - const data = await response.json(); - if (data.status === 0) { - console.log('События чата успешно обновлены'); - } else { - console.error('Ошибка при обновлении событий чата:', data.error); - } - } catch (error) { - console.error('Ошибка сети при обновлении событий чата:', error); - } -} \ No newline at end of file diff --git a/assets/js/common-popup.js b/assets/js/common-popup.js new file mode 100644 index 0000000..1148577 --- /dev/null +++ b/assets/js/common-popup.js @@ -0,0 +1,26 @@ +let activePopupWinId = ""; + +function activatePopupWindow__(el){ + let veil = document.createElement("div"); + veil.id = "popup-overlay-veil-OBJ" + veil.className = "popup-overlay-veil"; + veil.style.display = "block"; + document.body.appendChild(veil); + el.style.display = "block"; +} + +function activatePopupWindowById(id){ + if (activePopupWinId !== "") + return; + /* Lmao, this thing is just... SO unsafe */ + activePopupWinId = id; + activatePopupWindow__(document.getElementById(id)) +} + +function deactivateActivePopup(){ + if (activePopupWinId === "") + return + document.getElementById("popup-overlay-veil-OBJ").remove(); + document.getElementById(activePopupWinId).style.display = "none"; + activePopupWinId = ""; +} diff --git a/assets/js/common.js b/assets/js/common.js new file mode 100644 index 0000000..637b0b6 --- /dev/null +++ b/assets/js/common.js @@ -0,0 +1,77 @@ +let dopDopYesYes = (ign) => {}; + +function sleep(ms){ + return new Promise(res => setTimeout(res, ms)); +} + +async function apiRequest(type, req){ + let A = await fetch("/api/" + type, + {method: 'POST', body: JSON.stringify(req)}); + let B = await A.json(); + if (B.status !== 0) + throw Error("Server returned non-zero status"); + return B; +} + +/* Framework for pages with mainloop (it can be npt only polling, but also literally anything else */ +let __mainloopDelayMs = 3000; +let mainloopTimeout = null; +let __guestMainloopPollerAction = null; +function setMainloopTimeout(){ + if (mainloopTimeout !== null) + return; + mainloopTimeout = setTimeout(mainloopPoller, __mainloopDelayMs); +} +function cancelMainloopTimeout(){ + if (mainloopTimeout === null){ + console.log("cancelling nothing") + return; + } + clearTimeout(mainloopTimeout); + mainloopTimeout = null; +} +function mainloopPoller(){ + mainloopTimeout = null; + try { + if (__guestMainloopPollerAction) + __guestMainloopPollerAction(); + } catch (error){ + console.log(error) + } + setMainloopTimeout(); +} + +// 1 +const userChatRoleAdmin = "admin"; +// 2 +const userChatRoleRegular = "regular"; +// 3 +const userChatRoleReadOnly = "read-only"; +// 4 +const userChatRoleDeleted = "not-a-member"; + +function roleToColor(role) { + if (role === userChatRoleAdmin) { + return "#aafff3"; + } else if (role === userChatRoleRegular){ + return "#ffffff"; + + } else if (role === userChatRoleReadOnly){ + return "#bfb2b2"; + } else if (role === userChatRoleDeleted) { + return "#fb4a4a"; + } + return "#286500" // Bug +} + +function hideHTMLElement(el){ + el.style.display = "none"; +} + +function showHTMLElement(el){ + el.style.display = "block"; +} + +function setElementVisibility(el, isVisible, howVisible = "block"){ + el.style.display = isVisible ? howVisible : "none"; +} \ No newline at end of file diff --git a/assets/js/profile.js b/assets/js/profile.js deleted file mode 100644 index fc92988..0000000 --- a/assets/js/profile.js +++ /dev/null @@ -1,10 +0,0 @@ -document.getElementById('fileInput').addEventListener('change', function(event) { - const file = event.target.files[0]; - if (file) { - const reader = new FileReader(); - reader.onload = function(e) { - document.getElementById('avatar').src = e.target.result; - }; - reader.readAsDataURL(file); - } -}); \ No newline at end of file