master #6

Open
karimov-adel wants to merge 39 commits from master into adel_branch_2.0
26 changed files with 881 additions and 830 deletions
Showing only changes of commit 07711a93b0 - Show all commits

View File

@ -5,25 +5,12 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Веб-Чат Members</title>
<link rel="stylesheet" href="/assets/css/chat.css">
</head>
<body>
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
<!--TODO: ADD SOMETHING WRITE SOMETHING AAAAAA -->
<div class="overlay" id="overlay">
<div class="members-list" id="members-list">
<div class="members-list-header">
<span class="close" onclick="closeMembersList()">&times;</span>
<h2 class="all-members">Все участники</h2>
</div>
<div class="members-list-body">
<ul id="members-list-body">
<!-- Список участников будет добавлен динамически -->
</ul>
</div>
</div>
</div>
<script src="/assets/js/chat-members.js"></script>
<h1> Chat member list page for {% WRITE openedchat.nickname%}, not ready yet</h1>
<!--<script src="/assets/js/chat-members.js"></script>-->
</body>
</html>
{% ENDELDEF %}

View File

@ -9,17 +9,36 @@
{% ELDEF main JSON pres JSON userinfo JSON openedchat JSON initial_chatUpdResp %}
<!DOCTYPE html>
<html lang="ru">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Веб-Чат</title>
<link rel="stylesheet" href="/assets/css/common.css">
<link rel="stylesheet" href="/assets/css/chat.css">
<title>Chat </title>
</head>
<body>
{% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %}
<!-- TODO AAAAA-->
<script src="/assets/js/chat.js"></script>
<!-- Write the actual chat script -->
<!--% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %-->
<div id="fullscreen-container">
<div class="panel" id="navigation-info-panel">
<a href="/list-rooms" id="go-to-chat-list" class="panel-thing">
<img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px">
</a>
<a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
</a>
<p class="panel-thing panel-header-txt"> {% WRITE openedchat.name %} ({% WRITE openedchat.nickname %})</p>
<a href="/chat-members/{% WRITE openedchat.nickname %}" id="go-to-chat-settings" class="panel-thing">
<img alt="Settings of chat. List of members" src="/assets/img/settings-iron.svg" width="32px">
</a>
</div>
<div id="chat-widget"></div>
<div class="panel" id="input-panel">
<div contentEditable id="message-input" class="panel-thing"></div>
</div>
<script src="/assets/js/chat.js"></script>
</div>
</body>
</html>
{% ENDELDEF %}

View File

@ -1,42 +1,68 @@
{% ELDEF main JSON pres JSON userprofile JSON errors %}
{% ELDEF main JSON pres JSON userinfo JSON alienprofile JSON errors %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/assets/css/profile.css">
<title>Профиль</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/css/common.css">
<link rel="stylesheet" href="/assets/css/edit-profile.css">
<title>Edit user Profile</title>
</head>
<body>
<div class="main-container">
<div id="document-container">
<div id="navigation-panel" class="panel">
<a href="/list-rooms" id="go-to-chat-list" class="panel-thing">
<img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px">
</a>
<a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
</a>
</div>
{% FOR error IN errors %}
<div>
<p>{% WRITE error.text %}</p>
<div class="server-notif-error-msg-box">
{% WRITE error.text %}
</div>
{% ENDFOR %}
<div class="profile-header">
<h1>Редактирование профиля</h1>
<div class="profile-container">
<h2 class="profile-name-text">{% WRITE alienprofile.name %}</h2>
<h3 class="profile-nickname-text">Nickname: {% WRITE alienprofile.nickname %}</h3>
<p class="profile-bio-text">
{% WRITE alienprofile.bio %}
</p>
</div>
<div class="profile-container">
<h1 class="wide-centered-header">Change user attributes</h1>
<form action = "/user/{% WRITE alienprofile.nickname %}" method="post" enctype="application/x-www-form-urlencoded">
<table class="logins-input-table">
<tr>
<td class="logins-input-td1">
<label for="new-name-input">Enter new name:</label>
</td>
<td class="logins-input-td2">
<input name="name" id="new-name-input" type="text" placeholder="New name" class="one-line-input">
</td>
</tr>
<tr>
<td class="logins-input-td1">
<label for="new-password-input">Enter new password: </label>
</td>
<td class="logins-input-td2">
<input name="password" id="new-password-input" type="password" placeholder="New password" class="one-line-input">
</td>
</tr>
</table>
<label for="input-change-bio">Change description:</label>
<br>
<textarea name="bio" id="input-change-bio" class="multiline-input"></textarea>
<button class="action-button centered-block-el" type="submit">Submit changes</button>
</form>
</div>
<form method="post" action="/user/{% WRITE userprofile.nickname %}">
<div class="columns">
<div class="column">
<p>{% WRITE userprofile.name %} ( {% WRITE userprofile.nickname %} )</p>
<label for="name"> Изменить имя </label>
<input type="text" name="name" id="name">
<br>
<label for="password"> Изменить пароль </label>
<input type="password" name="password" id="password">
<br>
</div>
</div>
<div class="additional-info">
<p>О себе</p>
<p>{% WRITE userprofile.bio %}</p><br>
<label for="bio">Изменить</label>
<textarea name="bio" id="bio"></textarea>
</div>
<button class="save" type="submit">Сохранить изменения</button>
</form>
</div>
</body>
</html>
{% ENDELDEF%}

View File

@ -4,69 +4,48 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Список Чат-Комнат</title>
<title>List of chat rooms</title>
<link rel="stylesheet" href="/assets/css/common.css">
<link rel="stylesheet" href="/assets/css/common-popup.css">
<link rel="stylesheet" href="/assets/css/list-rooms.css">
</head>
<body>
<script>
let pres = {% PUT jsinsert pres %};
let userinfo = {% PUT jsinsert userinfo %};
let initial_chatListUpdResp = {% PUT jsinsert initial_chatListUpdResp %};
</script>
<div class="container">
<h1 style="color: white;">Выберите Чат-Комнату</h1>
<ul class="room-list">
<!-- Здесь будет список комнат -->
</ul>
<button class="create-room-button" onclick="openCreateRoomModal()">Создать Комнату</button>
</div>
<script>
let pres = {% PUT jsinsert pres %};
let userinfo = {% PUT jsinsert userinfo %};
let initial_chatListUpdResp = {% PUT jsinsert initial_chatListUpdResp %};
</script>
<div id="popup-overlay-veil"></div>
<div id="chat-creation-win" class="popup-window">
<h1>Input identifying information for your new chat</h1>
</div>
<!-- Модальное окно для создания комнаты -->
<!--<div id="createRoomModal" class="modal">-->
<!-- <div class="modal-content">-->
<!-- <div class="modal-header">-->
<!-- <span class="close" onclick="closeCreateRoomModal()">&times;</span>-->
<!-- <h2>Создать Комнату</h2>-->
<!-- </div>-->
<!-- <div class="modal-body">-->
<!-- <input type="text" id="newRoomName" placeholder="Название комнаты">-->
<!-- <input type="password" id="newRoomNickname" placeholder="Никнейм комнаты">-->
<!-- </div>-->
<!-- <div id="error"></div>-->
<!-- <div class="modal-footer">-->
<!-- <button class="join-button" onclick="createRoom()">Создать</button>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
<div id="chat-renunciation-win" class="popup-window">
<!-- header will actually be rewritten before showing the window to include chat nickname -->
<h1 id="chat-renunciation-win-title">Are you sure you want to leave chat?</h1>
<button class="chat-renunciation-win-yes">Yes, leave</button>
<button class="chat-renunciation-win-no">No, cancel</button>
</div>
<!--&lt;!&ndash; Модальное окно для добавления участников &ndash;&gt;-->
<!--<div class="overlay" id="add_members">-->
<!-- <div class="add-members">-->
<!-- <div class="add-members-header">-->
<!-- <span class="close" onclick="closeAdd()">&times;</span>-->
<!-- <h2>Добавить участников</h2>-->
<!-- </div>-->
<!-- <div class="add-members-body">-->
<!-- <input type="text" id="newMemberLogin" placeholder="Логин пользователя">-->
<!-- </div>-->
<!-- <div class="add-members-footer">-->
<!-- <button class="add-member-button" onclick="addMember()">Добавить</button>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
<!--<div class="overlay" id="delete-chat">-->
<!-- <div class="delete-chat">-->
<!-- <div class="delete-chat-header">-->
<!-- <span class="delete-close" onclick="closeConfirm()">&times;</span>-->
<!-- <h2>Вы уверены, что хотите удалить чат?</h2>-->
<!-- </div>-->
<!-- <div class="delete-chat-body">-->
<!-- <button class="confirm" onclick="deleteChat()">Да</button>-->
<!-- <button class="cancel" onclick="closeConfirm()">Нет</button>-->
<!-- </div>-->
<!-- </div>-->
<!--</div>-->
<script src="/assets/js/list-rooms.js"></script>
x
<div id="document-container">
<div id="navigation-panel" class="panel">
<a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
</a>
<p class="panel-thing panel-header-txt">
List of available rooms
</p>
</div>
<div class="dynamic-block-list">
<img id="CL-bacbe" class="button-add centered-block-el" alt="New chat" src="/assets/img/add.svg">
<div class="dynamic-block-list-el-container" id="CL-dblec">
</div>
</div>
</div>
<script src="/assets/js/list-rooms.js"></script>
</body>
</html>
{% ENDELDEF %}

View File

@ -1,29 +1,40 @@
{% ELDEF main JSON pres JSON userinfo JSON errors %}
<!DOCTYPE html>
<html lang="{% WRITE pres.lang %}">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% WRITE pres.phr.decl.page-login %}</title>
<link rel="stylesheet" href="/assets/css/common.css">
<link rel="stylesheet" href="/assets/css/login.css">
<title>Login Page</title>
</head>
<body>
{% FOR msg IN errors %}
<div class="error-msg">
{% WRITE msg.text %}
{% FOR error IN errors %}
<div class="server-notif-error-msg-box">
{% WRITE error.text %}
</div>
{% ENDFOR %}
<div class="form-container">
<h1 class="wide-centered-header">Login</h1>
<form action="/login" method="post" enctype="application/x-www-form-urlencoded">
<table class="logins-input-table">
<tr>
<td class="logins-input-td1"><label for="input-nickname">Enter user nickname:</label></td>
<td class="logins-input-td2">
<input name="nickname" id="input-nickname" type="text" placeholder="Nickname" class="one-line-input" required>
</td>
</tr>
<tr>
<td class="logins-input-td1"><label for="input-password">Enter password:</label></td>
<td class="logins-input-td2">
<input name="password" id="input-password" type="password" placeholder="Password" class="one-line-input" required>
</td>
</tr>
</table>
<button class="action-button centered-block-el" type="submit">Login</button>
</form>
</div>
{% ENDFOR %}
<div class="form-container">
<h1 class="hide-cursor no-select">{% WRITE pres.phr.decl.enter %}</h1>
<form action="/login" method="post" enctype="application/x-www-form-urlencoded">
<label for="nickname">{% WRITE pres.phr.decl.nickname %}</label>
<input type="text" name="nickname" id="nickname"><br>
<label for="password">{% WRITE pres.phr.decl.password %}</label>
<input type="password" name="password" id="password"><br>
<button type="submit" class="hide-cursor no-select">{% WRITE pres.phr.act.enter %}</button>
</form>
</div>
</body>
</html>

View File

@ -1,26 +1,35 @@
{% ELDEF main JSON pres JSON userprofile %}
{% ELDEF main JSON pres JSON userinfo JSON alienprofile %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/assets/css/profile.css">
<title>Профиль</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/assets/css/common.css">
<!-- This page is so simple, that it does not even have it's separate css file -->
<title>User Profile</title>
</head>
<body>
<div class="main-container">
<div class="profile-header">
<h1>Профиль пользователя</h1>
<div id="document-container">
<div id="navigation-panel" class="panel">
<a href="/list-rooms" id="go-to-chat-list" class="panel-thing">
<img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px">
</a>
<a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing">
<img alt="Go to my profile" src="/assets/img/user.svg" width="32px">
</a>
</div>
<div class="columns">
<div class="column">
<p>{% WRITE userprofile.name %} ( {% WRITE userprofile.nickname %} )</p>
</div>
</div>
<div class="additional-info">
<p>О себе</p>
<p>{% WRITE userprofile.bio %}</p><br>
<div class="profile-container">
<h2 class="profile-name-text">{% WRITE alienprofile.name %}</h2>
<h3 class="profile-nickname-text">Nickname: {% WRITE alienprofile.nickname %}</h3>
<p class="profile-bio-text">
{% WRITE alienprofile.bio %}
</p>
</div>
</div>
</body>
</html>
{% ENDELDEF%}

View File

@ -0,0 +1,72 @@
body, html {
height: 100%;
}
#navigation-info-panel {
align-items: center;
}
#chat-widget {
position: relative;
flex: 1;
background-color: #f1f1f1;
color: black;
overflow: hidden;
}
#chat-widget .message-box {
position: absolute;
right: 5px;
max-width: 300px;
border: 2px solid dimgrey;
padding: 5px;
background-color: white;
color: black;
}
/* in #chat-widget .message-box */
.message-box-top{
/* You see, each message contains a 20+2+2 px high icon that HAS TO BE LOADED FIRST.
This happens after window.onload, so I added a crutch: loading won't update height in
unpredictable moment. cause it will be already high enough. BUGA-GA-GA!! */
min-height: 30px;
display: block;
}
.message-box-sender-name{
font-weight: bold;
color: black;
text-decoration: none;
padding: 2px;
display: inline;
}
.message-box-sender-name:hover{
color: #1060ff
}
.message-box-button{
width: 20px;
padding: 2px;
cursor: pointer;
}
.message-box-msg{
word-wrap: break-word;
}
#input-panel {
}
#input-panel #message-input{
padding: 15px;
height: auto;
width: 100%;
display: inline-block;
background-color: white;
border: 1px solid #1000d0;
border-radius : 7px;
font-size: .9rem;
margin: 10px;
}

View File

@ -0,0 +1,30 @@
#popup-overlay-veil {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
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;
}

193
assets/css/common.css Normal file
View File

@ -0,0 +1,193 @@
/* 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;
}
.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 */
}
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;
}

View File

@ -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;
}

View File

@ -1,253 +1,35 @@
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 0;
#navigation-panel {
align-items: center;
}
.container {
max-width: 800px;
margin: 30px auto;
padding: 20px;
background-color: #007bff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 8px;
#CL-bacbe {
margin: 6px;
}
h1 {
text-align: center;
color: #fff;
}
.room-list {
list-style-type: none;
padding: 0;
}
.room-item {
.CL-my-chat-box {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
margin: 10px 0;
background-color: #fafafa;
border: 1px solid #ddd;
border-radius: 5px;
transition: background-color 0.3s ease;
flex-direction: row;
}
.room-item:hover {
background-color: #eaeaea;
.CL-my-chat-box-nickname {
margin-left: 8px;
justify-self: flex-start;
}
.room-name {
font-size: 18px;
color: #555;
.CL-my-chat-box-name {
margin-left: 14px;
justify-self: flex-start;
}
.join-button {
padding: 10px 15px;
font-size: 16px;
color: white;
background-color: #007bff;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.add-members-header {
text-align: center;
}
.add-members-footer {
text-align: right;
margin-top: 5px;
}
.add-members-button {
background-color: #218838;
padding: 10px 15px;
font-size: 16px;
color: white;
border: none;
border-radius: 5px;
position: absolute;
margin-left: 502px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.add-members-button:hover {
background-color: #006509
}
.delete-chat-button {
background-color: #dc2e45;
border: none;
color: white;
font-size: 16px;
border-radius: 5px;
position: absolute;
cursor: pointer;
transition: background-color 0.3s ease;
padding: 10px 15px;
margin-left: 380px;
}
.delete-chat-button:hover {
background-color: #881527;
}
#newMemberLogin {
width: 93.5%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 5px;
}
.add-member-button {
background-color: #218838;
padding: 10px 15px;
font-size: 16px;
color: white;
border: none;
border-radius: 5px;
position: absolute;
margin-left: -105px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.join-button:hover {
background-color: #0056b3;
.CL-my-chat-box-my-role {
margin-left: auto;
justify-self: flex-end;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.4);
}
.modal-content {
background-color: #fff;
margin: 10% auto;
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 400px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}
.modal-header, .modal-footer {
padding: 10px;
color: #333;
}
.modal-header {
text-align: center;
}
.modal-footer {
text-align: right;
}
.modal input {
width: 93.5%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 5px;
}
.create-room-button {
display: block;
width: 100%;
padding: 10px;
font-size: 16px;
color: white;
background-color: #1609ab;
border: none;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-top: 20px;
}
.create-room-button: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;
}
.overlay .add-members {
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
max-width: 400px;
width: 100%;
height: 18%;
position: fixed;
}
.overlay .delete-chat {
background-color: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
max-width: 400px;
width: 100%;
height: 18%;
position: fixed;
}
.delete-close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
.CL-my-chat-box-leave-btn {
margin-left: 10px;
margin-right: 8px;
justify-self: flex-end;
width: 16px;
cursor: pointer;
}
.delete-chat-header {
text-align: center;
}
.confirm {
background-color: #1609ab;
padding: 20px 70px;
font-size: 16px;
color: white;
border: none;
border-radius: 5px;
position: absolute;
margin-left: 20px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.cancel {
background-color: #1609ab;
padding: 20px 70px;
font-size: 16px;
color: white;
border: none;
border-radius: 5px;
position: absolute;
margin-left: 220px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}

View File

@ -1,59 +1,34 @@
/* I have no idea what is going on here */
body {
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
height: 100vh; /* Full viewport height */
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;
background-color: #ffffff; /* Brighter box color */
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
width: 50%; /* Set width of the form */
}
h1 {
margin-bottom: 20px;
color: #2F4F4F;
}
input {
/* The morbid thing */
table.logins-input-table {
width: 100%;
background: #f7f7f7;
font-size: 16px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 20px;
margin-bottom: 15px;
outline: none;
border-collapse: collapse; /* Combine borders */
}
button {
width: 100%;
padding: 15px;
.logins-input-td1, .logins-input-td2 {
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;
}
.error-msg {
color: red;
background-color: #ffc0c0;
border-color: red;
border-radius: 5px;
}
.logins-input-td1 {
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%;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,227 @@
// In real world, I would get this variables from server through nytl
let pres = {lang: ''}
let userinfo = {id: 2, nickname: 'pv', name: 'Pavlov Vladimir'};
let openedchat = {id: 100, name: "Some chat", nickname: 'chat'};
let initial_chatUpdResp = {
LocalHistoryId: 0,
lastMsgId: -1,
messages: [],
members: [
{id: 1, name: 'grisha', nickname: 'gri', role: 'admin'},
{id: 2, name: 'Pavlov Vladimir', nickname: 'pv', role: 'regular'},
{id: 3, name: 'Ivan', nickname: 'ivan', role: 'read-only'}
]
};
let loadedMessages = new Map(); // messageSt objects
let visibleMessages = new Map(); // HTMLElement objects
let anchoredMsg = -1;
let visibleMsgSegStart = -1;
let visibleMsgSegEnd = -2;
let offsetOfAnchor = 100;
// Would start with true if opened `/chat/<>`
let bumpedAtTheBottom = false;
let members = new Map();
for (let memberSt of initial_chatUpdResp.members){
members.set(memberSt.id, memberSt);
}
// members.set(1, {id: 1, name: 'grisha', nickname: 'gri', role: 'admin'});
// members.set(2, {id: 2, name: 'Pavlov Vladimir', nickname: 'pv', role: 'regular'});
// members.set(3, {id: 3, name: 'Ivan', nickname: 'ivan', role: 'read-only'});
function updateOffsetOfVisibleMsg(msgId, offset){
visibleMessages.get(msgId).style.bottom = String(offset) + "px";
}
function updateOffsetsUpToTop(){
let offset = offsetOfAnchor;
for (let curMsg = anchoredMsg; curMsg >= visibleMsgSegStart; curMsg--){
updateOffsetOfVisibleMsg(curMsg, offset);
let height = visibleMessages.get(curMsg).offsetHeight;
offset += height + 5;
}
return offset;
}
function updateOffsetsDown(){
let offset = offsetOfAnchor;
for (let curMsg = anchoredMsg + 1; curMsg <= visibleMsgSegEnd; curMsg++){
let height = visibleMessages.get(curMsg).offsetHeight;
offset -= (height + 5);
updateOffsetOfVisibleMsg(curMsg, offset);
}
return offset;
}
function updateOffsetsSane(){
let highest_point = updateOffsetsUpToTop();
let lowest_point = updateOffsetsDown();
return [highest_point, lowest_point];
}
function updateOffsets(){
if (anchoredMsg < 0)
return;
let [highest_point, lowest_point] = updateOffsetsSane();
let winTop = document.getElementById("chat-widget").offsetHeight;
if (lowest_point > 5 || (highest_point - lowest_point) <= winTop){
bumpedAtTheBottom = true;
anchoredMsg = visibleMsgSegEnd;
offsetOfAnchor = 5;
updateOffsetsSane();
} else if (highest_point < winTop - 5){
console.log("Adancing by " + (winTop - 5 - highest_point))
offsetOfAnchor += (winTop - 5 - highest_point);
updateOffsetsSane();
}
}
function makeMessageBox(messageSt){
if (!messageSt.exists || messageSt.isSystem)
throw new Error("Not ready for this");
const parentDiv = document.getElementById("chat-widget");
let box = document.createElement("div");
parentDiv.appendChild(box);
box.className = "message-box";
let topPart = document.createElement("div");
box.appendChild(topPart);
topPart.className = "message-box-top";
let inTopPartSenderName = document.createElement("a");
topPart.appendChild(inTopPartSenderName);
inTopPartSenderName.className = "message-box-sender-name";
if (!members.has(messageSt.senderUserId))
throw new Error("MMMHMMMMGMHMMMM. First - update members. Then messages");
let memberSt = members.get(messageSt.senderUserId);
inTopPartSenderName.innerText = memberSt.name + " (" + memberSt.nickname + ")";
inTopPartSenderName.href = "/user/" + memberSt.nickname;
let ID = messageSt.id;
let inTopPartButtonDelete = document.createElement("img");
topPart.appendChild(inTopPartButtonDelete);
inTopPartButtonDelete.className = "message-box-button";
inTopPartButtonDelete.src = "/assets/img/delete.svg";
inTopPartButtonDelete.onclick = (ev) => {
if (ev.button === 0){
console.log("Tried to delete message " + ID);
}
};
let inTopPartButtonGetLink = document.createElement("img");
topPart.appendChild(inTopPartButtonGetLink);
inTopPartButtonGetLink.className = "message-box-button";
inTopPartButtonGetLink.src = "/assets/img/link.svg";
inTopPartButtonGetLink.onclick = (ev) => {
if (ev.button === 0){
console.log("Tried to get link on message " + ID);
}
};
let msgPart = document.createElement("p");
box.appendChild(msgPart);
msgPart.className = "message-box-msg";
msgPart.innerText = messageSt.text;
return box;
}
function makeVisible(msgId){
visibleMessages.set(msgId, makeMessageBox(loadedMessages.get(msgId)))
}
function opaNewMessage(messageSt){
let msgId = messageSt.id;
let text = messageSt.text;
const chatWin = document.getElementById("chat-widget");
if (loadedMessages.has(msgId)){
throw new Error("Not ready yet");
// loadedMessages.get(msgId).text = text;
// if (visibleMessages.has(msgId)){
// visibleMessages.get(msgId).textContent = text;
// updateOffsets();
// }
} else {
loadedMessages.set(msgId, messageSt);
if (anchoredMsg < 0){
anchoredMsg = msgId;
visibleMsgSegStart = msgId;
visibleMsgSegEnd = msgId;
makeVisible(msgId);
updateOffsets();
} else if (msgId + 1 === visibleMsgSegStart) {
visibleMsgSegStart--;
makeVisible(msgId);
while (loadedMessages.has(visibleMsgSegStart - 1)){
visibleMsgSegStart--;
makeVisible(visibleMsgSegStart);
}
updateOffsets();
} else if (msgId - 1 === visibleMsgSegEnd){
visibleMsgSegEnd++;
makeVisible(msgId);
while (loadedMessages.has(visibleMsgSegEnd + 1)){
visibleMsgSegEnd++;
makeVisible(visibleMsgSegEnd);
}
updateOffsets();
}
}
}
function test(id, uid){
opaNewMessage({
id: id, text: "Message number " + String(id), senderUserId: uid, exists: true, isSystem: false}
);
}
let mainloopTimeout = null;
let mainloopPoller = null;
function setMainloopTimeout(){
mainloopTimeout = setTimeout(mainloopPoller, 1000);
}
mainloopPoller = function(){
try {
console.log("Hello, World!");
} catch (error){}
setMainloopTimeout();
}
window.onload = function (){
console.log("Everything was loaded");
test(6, 1);
test(1, 2);
test(3, 3);
test(2, 1);
test(4, 2);
test(0, 3);
test(5, 2);
test(8, 1);
test(9, 2);
test(7, 3);
for (let i = 10; i < 30; i++){
test(i, 2);
}
document.body.addEventListener("wheel", (event) => {
event.preventDefault();
bumpedAtTheBottom = false;
console.log("Scroll of " + String(event.deltaY));
offsetOfAnchor += event.deltaY / 5;
updateOffsets();
});
mainloopPoller();
document.getElementById("message-input").addEventListener("keyup", (event) => {
if (event.ctrlKey && event.key === 'Enter'){
let textarea = document.getElementById("message-input");
console.log(textarea.value);
}
});
}

View File

@ -1,186 +1,72 @@
let rooms = {};
let roomToDelete = null;
let currentRoom = null;
let currentHistoryId = 0;
let LocalHistoryId = 0;
function openRoom(currentRoom) {
alert('Вы вошли в комнату: ' + currentRoom);
}
let myChats = new Map();
let chatBoxes = new Map();
function closeAdd() {
document.getElementById('add_members').style.display = 'none';
}
const roleDeleted = "not-a-member";
function openAdd() {
document.getElementById('add_members').style.display = 'flex';
}
function convertStToBox(myMembershipSt){
let chatURI = "/user/" + myMembershipSt.chatNickname;
function openConfirm(roomNickname) {
roomToDelete = roomNickname;
document.getElementById("delete-chat").style.display = "flex";
}
let box = document.createElement("div");
chatBoxes.set(myMembershipSt.chatId, box);
box.className = "dynamic-block-list-el CL-my-chat-box";
function closeConfirm() {
roomToDelete = null;
document.getElementById("delete-chat").style.display = "none";
}
let inBoxNickname = document.createElement("a");
box.appendChild(inBoxNickname);
inBoxNickname.className = "entity-nickname-txt CL-my-chat-box-nickname";
console.log(myMembershipSt);
console.log(myMembershipSt.chatNickname);
inBoxNickname.innerText = myMembershipSt.chatNickname;
inBoxNickname.href = chatURI;
function deleteChat() {
if (roomToDelete && rooms[roomToDelete]) {
delete rooms[roomToDelete];
removeRoomFromList(roomToDelete);
closeConfirm();
} else {
alert("Не удалось найти выбранную комнату.");
}
}
let inBoxName = document.createElement("a");
box.appendChild(inBoxName);
inBoxName.className = "entity-reg-field-txt CL-my-chat-box-name";
inBoxName.innerText = myMembershipSt.chatName;
inBoxName.href = chatURI;
function addMember() {
const login = document.getElementById('newMemberLogin').value;
if (login) {
alert(`Участник с никнеймом '${login}' добавлен`);
closeAdd();
} else {
alert('Пожалуйста, введите логин участника');
}
}
let inBoxMyRoleHere = document.createElement("p");
box.appendChild(inBoxMyRoleHere);
inBoxMyRoleHere.className = "entity-reg-field-txt CL-my-chat-box-my-role";
inBoxMyRoleHere.innerText = "You are " + myMembershipSt.myRoleHere + " here";
function openCreateRoomModal() {
document.getElementById('createRoomModal').style.display = 'block';
}
let ID = myMembershipSt.chatId;
function closeCreateRoomModal() {
document.getElementById('createRoomModal').style.display = 'none';
}
async function createRoom() {
const errorElement = document.getElementById('error');
const roomName = document.getElementById('newRoomName').value.trim();
const roomNickname = document.getElementById('newRoomNickname').value.trim();
errorElement.style.display = 'none';
errorElement.textContent = '';
if (roomName === '' || roomNickname === '') {
errorElement.textContent = 'Пожалуйста, заполните все поля';
errorElement.style.display = 'block';
return;
}
const request = {
LocalHistoryId: currentHistoryId,
content: {
name: roomName,
nickname: roomNickname
let inBoxLeaveBtn = document.createElement("img");
box.appendChild(inBoxLeaveBtn);
inBoxLeaveBtn.className = "CL-my-chat-box-leave-btn";
inBoxLeaveBtn.src = "/assets/img/delete.svg";
inBoxLeaveBtn.onclick = function (ev) {
if (ev.button === 0){
console.log("Tried to leave chat" + ID);
}
};
try {
const response = await fetch('/internalapi/createChat', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(request)
});
const res = await response.json();
if (res.status === 0) {
addRoomToList(roomName, roomNickname);
rooms[roomNickname] = true;
closeCreateRoomModal();
currentHistoryId = res.update.LocalHistoryId;
window.location.href = '/chat/' + roomNickname;
} else {
throw new Error(res.error || 'Ошибка');
}
} catch (error) {
alert('Ошибка создания чата: ' + error.message);
}
return box;
}
function addRoomToList(roomName) {
const roomList = document.querySelector('.room-list');
const existingRoomItem = Array.from(roomList.children).find(item => item.querySelector('.room-name').textContent === roomName);
if (existingRoomItem) {
existingRoomItem.remove();
}
window.onload = function () {
console.log("Loading complete");
LocalHistoryId = initial_chatListUpdResp.HistoryId;
const roomItem = document.createElement('li');
roomItem.classList.add('room-item');
console.log(initial_chatListUpdResp);
roomItem.innerHTML = `
<span class="room-name">${roomName}</span>
<button class="delete-chat-button" onclick="openConfirm('${roomNickname}')">Удалить чат</button>
<button class="add-members-button" onclick="openAdd()">Добавить участников</button>
<button class="join-button" onclick="window.location.href = '/chat/${roomNickname}'">Войти</button>
`;
let literalChatList = document.getElementById("CL-dblec");
roomList.appendChild(roomItem);
}
function removeRoomFromList(roomName, roomNickname) {
const roomList = document.querySelector('.room-list');
const roomItem = Array.from(roomList.children).find(item => item.querySelector('.room-name').textContent === roomName);
if (roomItem) {
roomList.removeChild(roomItem);
}
}
async function initializeRoomList() {
try {
const response = await fetch('/internalapi/getChatList', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({})
});
const res = await response.json();
if (res.status === 0) {
res.chats.forEach(chat => {
addRoomToList(chat.content.name, chat.content.nickname);
});
} else {
throw new Error(res.error || 'Неизвестная ошибка');
}
} catch (error) {
alert('Ошибка загрузки списка чатов: ' + error.message);
}
}
async function getChatID() {
const chatNickname = window.location.pathname.split('/').pop();
const response = await fetch('/internalapi/getChatList', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({})
});
const res = await response.json();
for (const chat of res.chats) {
if (chat.content.nickname === chatNickname) {
return chat.id;
for (let myMembershipSt of initial_chatListUpdResp.myChats){
console.log(myMembershipSt);
if (myMembershipSt.myRoleHere !== roleDeleted){
myChats.set(myMembershipSt.chatId, myMembershipSt);
let box = convertStToBox(myMembershipSt)
chatBoxes.set(myMembershipSt.chatId, box);
literalChatList.appendChild(box);
}
}
return -1;
}
window.onclick = function(event) {
if (event.target === document.getElementById('createRoomModal')) {
closeCreateRoomModal();
}
}
document.getElementById('newRoomName').addEventListener('keydown', function(event) {
if (event.key === 'Enter') {
createRoom();
}
});
document.addEventListener('DOMContentLoaded', initializeRoomList);
document.getElementById("CL-bacbe").onclick = function (ev){
if (ev.button === 0){
}
};
};

View File

@ -112,6 +112,10 @@ namespace een9 {
return status;
}
res.body.reserve(std::min(100000ul, body_size));
if (body_size == 0) {
status = 1;
}
break;
}
}
if (!res.has_body) {

View File

@ -55,13 +55,16 @@ namespace nytl {
}
char skip(ParsingContext& ctx) {
ASSERT(ctx.pos < ctx.text.size(), "Unexpected EOF");
if (ctx.pos >= ctx.text.size())
THROW("Unexpected EOF");
return advance(ctx);
}
void skip(ParsingContext& ctx, char ch) {
ASSERT(ctx.pos < ctx.text.size(), "Unexpected EOF");
ASSERT(ctx.text[ctx.pos] == ch, "Unexpected character");
if (ctx.pos >= ctx.text.size())
THROW("Unexpected EOF");
if (ctx.text[ctx.pos] != ch)
THROW("Unexpected character");
advance(ctx);
}
@ -150,7 +153,8 @@ namespace nytl {
void parse_bare_file(const std::string& filename, const std::string& content,
global_elem_set_t& result)
{
ASSERT(result.count(filename) == 0, "Repeated element " + filename);
if (result.count(filename) != 0)
THROW("Repeated element " + filename);
std::string txt = clement_lstrip(content);
rstrip(txt);
size_t cut = 9999999999999;
@ -170,13 +174,15 @@ namespace nytl {
uptr<TPFrame> toMe(bool returned, ParsingContext& ctx) {
if (!returned) {
std::string nm = readName(ctx);
ASSERT(!nm.empty(), "Type specification expected");
if (nm.empty())
THROW("Type specification expected");
nm = make_uppercase(nm);
if (nm == "JSON") {
result = json::JSON(true);
return NULL;
}
ASSERT(nm == "EL", "Type of argument variable is either JSON or EL(...signature)")
if (nm != "EL")
THROW("Type of argument variable is either JSON or EL(...signature)");
skip(ctx, '(');
result.asArray();
assert(result.isArray());
@ -217,8 +223,10 @@ namespace nytl {
uptr<EPFrame> toMe(bool returned, ParsingContext& ctx, const arg_name_list_t& local_var_names) {
if (!returned) {
std::string first = readName(ctx);
ASSERT(!first.empty(), "Expression should start with 'root' name of global package or local variable");
ASSERT(first != "_", "_ ??? ARE YOU KIDDING???");
if (first.empty())
THROW("Expression should start with 'root' name of global package or local variable");
if (first == "_")
THROW("Expression root can't be _");
if (local_var_names.count(first) == 1) {
result["V"].asInteger() = json::Integer((int64_t)local_var_names.at(first));
} else {
@ -243,7 +251,8 @@ namespace nytl {
t = readUint(ctx);
if (!t.empty()) {
size_t v = std::stoul(t);
ASSERT(v < INT64_MAX, "Index is too big");
if (v >= INT64_MAX)
THROW("Index is too big");
chain.back() = json::JSON((int64_t)v);
continue;
}
@ -352,7 +361,8 @@ namespace nytl {
ElementPart::when_for_put_S& P = result.parts.back().when_for_put;
skipWhitespace(ctx);
std::string V1 = readName(ctx);
ASSERT(!V1.empty(), "Expected variable name");
if (V1.empty())
THROW("Expected variable name");
skipWhitespace(ctx);
bool have_colon_and_2 = false;
std::string V2;
@ -364,7 +374,8 @@ namespace nytl {
skipWhitespace(ctx);
}
op = make_uppercase(readName(ctx));
ASSERT(op == "IN", "Expected IN");
if (op != "IN")
THROW("Expected IN");
skipWhitespace(ctx);
P.ref_over = parse_expression(ctx, local_var_names);
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
@ -372,13 +383,15 @@ namespace nytl {
newborn.is_hidden = true;
arg_name_list_t local_var_names_of_nxt = local_var_names;
if (V1 != "_") {
ASSERT(local_var_names_of_nxt.count(V1) == 0, "Repeated local variable");
if (local_var_names_of_nxt.count(V1) != 0)
THROW("Repeated local variable");
size_t k = local_var_names_of_nxt.size();
local_var_names_of_nxt.emplace(V1, k);
(have_colon_and_2 ? P.where_key_var : P.where_value_var) = (ssize_t)k;
}
if (have_colon_and_2 && V2 != "_") {
ASSERT(local_var_names_of_nxt.count(V2) == 0, "Repeated local variable");
if (local_var_names_of_nxt.count(V2) != 0)
THROW("Repeated local variable");
size_t k = local_var_names_of_nxt.size();
local_var_names_of_nxt.emplace(V2, k);
P.where_value_var = (ssize_t)k;
@ -395,11 +408,12 @@ namespace nytl {
ElementPart::when_ref_put_S& P = result.parts.back().when_ref_put;
skipWhitespace(ctx);
std::string Vn = readName(ctx);
ASSERT(!Vn.empty(), "Expected variable name");
ASSERT(Vn != "_", "Are you kidding???");
if (Vn.empty() || Vn == "_")
THROW("REF: expected variable name");
skipWhitespace(ctx);
op = make_uppercase(readName(ctx));
ASSERT(op == "AS", "Expected AS");
if (op != "AS")
THROW("Expected AS");
skipWhitespace(ctx);
P.ref_over = parse_expression(ctx, local_var_names);
P.internal_element = el_name + ".~" + std::to_string(free_hidden++);
@ -467,13 +481,15 @@ namespace nytl {
}
};
if (op == "ENDELDEF") {
ASSERT(myself == gone_for_nothing, "Unexpected end of element");
if (myself != gone_for_nothing)
THROW("Unexpected ENDELDEF");
skip_magic_block_end(ctx, syntax);
prepare_to_depart_parts();
return NULL;
}
if (op == "ENDFOR") {
ASSERT(myself == gone_for_for, "Unexpected end of for cycle");
if (myself != gone_for_for)
THROW("Unexpected ENDFOR");
skipWhitespace(ctx);
/* Here I am using ret_data_int to return info about NOLF(1)/LF(2) decision */
ret_data_int = 2; // Default is to do LF
@ -491,7 +507,8 @@ namespace nytl {
return NULL;
}
if (op == "ENDREF") {
assert(myself == gone_for_ref);
if (myself != gone_for_ref)
THROW("Unexpected ENDREF");
skip_magic_block_end(ctx, syntax);
prepare_to_depart_parts();
return NULL;
@ -525,12 +542,15 @@ namespace nytl {
if (peep(ctx) == EOFVAL)
break;
skip_magic_block_start(ctx, syntax);
ASSERT(make_uppercase(readName(ctx)) == "ELDEF", "Expected ELDEF");
if (make_uppercase(readName(ctx)) != "ELDEF")
THROW("Expected ELDEF");
skipWhitespace(ctx);
std::string elname_postfix = readName(ctx);
ASSERT(elname_postfix != "_", "please don't");
if (elname_postfix == "_")
THROW("Can't use _ as element name");
std::string fullname = elname_postfix == "main" ? filename : filename + "." + elname_postfix;
ASSERT(result.count(fullname) == 0, "Element " + fullname + " has been already defined");
if (result.count(fullname) != 0)
THROW("Element " + fullname + " has been already defined");
Element& newborn = result[fullname];
arg_name_list_t arglist;
while (true) {
@ -540,9 +560,11 @@ namespace nytl {
newborn.arguments.push_back(parse_type(ctx));
skipWhitespace(ctx);
std::string argname = readName(ctx);
ASSERT(!argname.empty(), "Expected argument name");
if (argname.empty())
THROW("Expected argument name");
if (argname != "_") {
ASSERT(arglist.count(argname) == 0, "Repeated argument (" + argname + ")");
if (arglist.count(argname) != 0)
THROW("Repeated argument (" + argname + ")");
size_t k = arglist.size();
arglist[argname] = k;
}

View File

@ -212,7 +212,7 @@ namespace nytl {
const std::function<std::string(std::string)> &escape) {
if (!returned)
if (elem_ns.count(name) != 1)
THROW("No such element");
THROW("No such element (" + name + ")");
const Element& el = elem_ns.at(name);
if (!returned) {
/* Continue to do checks */
@ -227,7 +227,9 @@ namespace nytl {
// If not json is expected, element must be expected
assert(el.arguments[i].isArray());
ASSERT(!passed_args[i].is_json, "Expected element element arguemnt, got json");
ASSERT(elem_ns.count(passed_args[i].EL_name), "No such element, can't compare signatures of argument value");
const std::string& passed_el_as_arg = passed_args[i].EL_name;
if (elem_ns.count(passed_el_as_arg) != 1)
THROW("No such element, can't compare signatures of argument value (" + passed_el_as_arg + ")");
const Element& arg_element = elem_ns.at(passed_args[i].EL_name);
// ASSERT(passed_args);
if(el.arguments[i].asArray() != arg_element.arguments)

View File

@ -8,7 +8,7 @@ namespace iu9cawebchat {
SqliteStatement my_membership_changes(conn,
"SELECT `chatId`, `role` FROM `user_chat_membership` WHERE `userId` = ?1 "
"AND `user_chatList_IncHistoryId` > ?2", {{1, userId}, {2, LocalHistoryId}});
json::jarr myChats = chatListUpdResp["myChats"].asArray();
json::jarr& myChats = chatListUpdResp["myChats"].asArray();
while (true) {
fsql_integer_or_null ev_chatId, usersRoleHere;
int status = sqlite_stmt_step(my_membership_changes, {{0, &ev_chatId}, {1, &usersRoleHere}}, {});
@ -73,7 +73,7 @@ namespace iu9cawebchat {
json::jarr members;
SqliteStatement membership_changes(conn,
"SELECT `userId`, `role`, FROM `user_chat_membership` WHERE `chatId` = ?1 "
"SELECT `userId`, `role` FROM `user_chat_membership` WHERE `chatId` = ?1 "
"AND `chat_IncHistoryId` > ?2", {{1, chatId}, {2, LocalHistoryId}}, {});
while (true) {
fsql_integer_or_null alienUserId;

View File

@ -7,8 +7,10 @@ namespace iu9cawebchat {
std::string when_page_chat(WorkerGuestData& wgd, const json::JSON& config_presentation,
const een9::ClientRequest& req, const json::JSON& userinfo) {
std::vector<std::string> path_segs = {""};
std::vector<std::string> path_segs = {};
path_segs.reserve(4);
if (req.uri_path.empty() || req.uri_path[0] != '/')
return page_E404(wgd);
for (char ch: req.uri_path) {
if (ch == '/')
path_segs.emplace_back();
@ -31,16 +33,18 @@ namespace iu9cawebchat {
return page_E404(wgd);
} else
return page_E404(wgd);
bool chat_members = (path_segs[0] == "chat-members");
if (userinfo.isNull())
return een9::form_http_server_response_303("/");
RowChat_Content chatInfo;
try {
chatInfo = lookup_chat_content_by_nickname(*wgd.db, chat_nickname);
} catch (const std::exception& e) {
return page_E404(wgd);
}
if (get_role_of_user_in_chat(*wgd.db, userinfo["id"].asInteger().get_int(), chatInfo.id) == user_chat_role_deleted) {
if (get_role_of_user_in_chat(*wgd.db, userinfo["uid"].asInteger().get_int(), chatInfo.id) == user_chat_role_deleted) {
return page_E404(wgd);
}
@ -52,7 +56,7 @@ namespace iu9cawebchat {
openedchat["selectedMessageId"].asInteger() = json::Integer(selected_message_id);
json::JSON initial_chatUpdResp = poll_update_chat_ONE_MSG_resp(*wgd.db, chatInfo.id, selected_message_id);
if (chat_members)
return http_R200("chat", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp});
return http_R200("chat-members", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp});
return http_R200("chat", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp});
}
}

View File

@ -8,6 +8,7 @@ namespace iu9cawebchat {
}
json::JSON initial_chatListUpdResp = poll_update_chat_list_resp(*wgd.db,
userinfo["uid"].asInteger().get_int(), 0);
printf("%s\n", json::generate_str(initial_chatListUpdResp, json::print_pretty).c_str());
return http_R200("list-rooms", wgd, {&config_presentation, &userinfo, &initial_chatListUpdResp});
}
}

View File

@ -18,8 +18,10 @@ namespace iu9cawebchat {
if (cmp.first == "password")
password = cmp.second;
}
een9_ASSERT(check_nickname(nickname), "/login/accpet-data rejected impossible nickname");
een9_ASSERT(check_password(password), "/login/accpet-data rejected impossible password");
if (!check_nickname(nickname))
een9_THROW("/login/accpet-data rejected impossible nickname");
if (!check_password(password))
een9_THROW("/login/accpet-data rejected impossible password");
uid = find_user_by_credentials(*wgd.db, nickname, password);
} catch(const std::exception& e){}

View File

@ -39,6 +39,8 @@ namespace iu9cawebchat {
std::string when_page_user(WorkerGuestData& wgd, const json::JSON& config_presentation,
const een9::ClientRequest& req, const std::vector<LoginCookie>& login_cookies, const json::JSON& userinfo) {
if (userinfo.isNull())
return een9::form_http_server_response_303("/");
SqliteConnection& conn = *wgd.db;
if (!is_page_of_certain_user(req.uri_path))
return page_E404(wgd);
@ -104,7 +106,7 @@ namespace iu9cawebchat {
json::JSON msg_list = jsonify_html_message_list({{"",
config_presentation["phr"]["decl"]["incorrect-profile-data"].asString()}});
json::JSON alien_userprofile = user_row_to_userprofile_obj(conn, alien);
return http_R200("edit-profile", wgd, {&config_presentation, &alien_userprofile, &msg_list});
return http_R200("edit-profile", wgd, {&config_presentation, &userinfo, &alien_userprofile, &msg_list});
}
return een9::form_http_server_response_303_spec_head("/user/" + alien_nickname, response_hlines);
}
@ -112,9 +114,9 @@ namespace iu9cawebchat {
json::JSON alien_userprofile = user_row_to_userprofile_obj(conn, alien);
if (can_edit) {
json::JSON empty_msg_list = jsonify_html_message_list({});
return http_R200("edit-profile", wgd, {&config_presentation, &alien_userprofile, &empty_msg_list});
return http_R200("edit-profile", wgd, {&config_presentation, &userinfo, &alien_userprofile, &empty_msg_list});
}
return http_R200("view-profile", wgd, {&config_presentation, &alien_userprofile});
return http_R200("view-profile", wgd, {&config_presentation, &userinfo, &alien_userprofile});
}
een9_THROW("Bad method");
}

View File

@ -36,7 +36,8 @@ int main(int argc, char** argv){
iu9cawebchat::run_website(config);
} else
een9_THROW("unknown action (known are 'run', 'initialize')");
} catch (std::exception& e) {
// todo: put back execption after debug
} catch (std::bad_weak_ptr& e) {
printf("System failure\n%s\n", e.what());
}
return 0;