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 %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% 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 %}
-
-
-
-
-
-
- Настройки комнаты
-
-
-
-
-
-
-
- - Участник 1
- - Участник 2
- - Участник 3
-
-
-
-
-
-
-
-
-
-
-
-{% 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 %}
+
+
+
+
+
+
+
+
+{% 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