master #6
| @ -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()">×</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 %} | ||||
|  | ||||
| @ -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 %} | ||||
|  | ||||
| @ -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> | ||||
|         <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"> | ||||
| 
 | ||||
|         <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> | ||||
|                     <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> | ||||
|                 <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> | ||||
|     </div> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
| {% ENDELDEF%} | ||||
|  | ||||
| @ -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> | ||||
|     <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> | ||||
|     <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()">×</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> | ||||
| 
 | ||||
| <!--<!– Модальное окно для добавления участников –>--> | ||||
| <!--<div class="overlay" id="add_members">--> | ||||
| <!--    <div class="add-members">--> | ||||
| <!--        <div class="add-members-header">--> | ||||
| <!--            <span class="close" onclick="closeAdd()">×</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()">×</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 %} | ||||
| @ -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="hide-cursor no-select">{% WRITE pres.phr.decl.enter %}</h1> | ||||
|     {% ENDFOR %} | ||||
| 
 | ||||
|     <div class="form-container"> | ||||
|         <h1 class="wide-centered-header">Login</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> | ||||
|             <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> | ||||
|     </div> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | ||||
| @ -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%} | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
							
								
								
									
										30
									
								
								assets/css/common-popup.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								assets/css/common-popup.css
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										193
									
								
								assets/css/common.css
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										23
									
								
								assets/css/edit-profile.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								assets/css/edit-profile.css
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
| @ -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; | ||||
|     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; | ||||
| .CL-my-chat-box-leave-btn { | ||||
|     margin-left: 10px; | ||||
|     margin-right: 8px; | ||||
|     justify-self: flex-end; | ||||
|     width: 16px; | ||||
|     cursor: pointer; | ||||
| } | ||||
| @ -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%; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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; | ||||
| } | ||||
| @ -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); | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| @ -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.getElementById("CL-bacbe").onclick = function (ev){ | ||||
|         if (ev.button === 0){ | ||||
| 
 | ||||
|         } | ||||
| }); | ||||
| document.addEventListener('DOMContentLoaded', initializeRoomList); | ||||
|     }; | ||||
| }; | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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; | ||||
|                 } | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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}); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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){} | ||||
|  | ||||
| @ -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"); | ||||
|     } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user