master #6
| @ -17,8 +17,8 @@ | |||||||
|         <h1 class="popup-window-msg">Nickname for summoned user</h1> |         <h1 class="popup-window-msg">Nickname for summoned user</h1> | ||||||
|         <input class="one-line-input" id="summoned-user-nickname"> |         <input class="one-line-input" id="summoned-user-nickname"> | ||||||
|         <input type="checkbox" id="summoned-user-is-read-only"> |         <input type="checkbox" id="summoned-user-is-read-only"> | ||||||
|         <label>Make read only</label> |         <label>Make read only</label><br> | ||||||
|         <button class="popup-window-btn-yes" id="user-summoning-yes">Summon</button> |         <button class="popup-window-btn-yes" id="user-summoning-yes">Yes, summon</button> | ||||||
|         <button class="popup-window-btn-no" id="user-summoning-no">No, cancel</button> |         <button class="popup-window-btn-no" id="user-summoning-no">No, cancel</button> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
| @ -29,7 +29,7 @@ | |||||||
|         <button class="popup-window-btn-no" id="user-deletion-no">No, cancel</button> |         <button class="popup-window-btn-no" id="user-deletion-no">No, cancel</button> | ||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
|     <div id="document-container"> |     <div class="document-container resp-container"> | ||||||
|         <div id="navigation-panel" class="panel"> |         <div id="navigation-panel" class="panel"> | ||||||
|             <a href="/list-rooms" id="go-to-chat-list" class="panel-thing"> |             <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"> |                 <img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px"> | ||||||
|  | |||||||
| @ -14,32 +14,47 @@ | |||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|     <link rel="icon" type="image/png" href="/assets/img/favicon.png"> |     <link rel="icon" type="image/png" href="/assets/img/favicon.png"> | ||||||
|  |     <link rel="stylesheet" href="/assets/css/debug.css"> | ||||||
|     <link rel="stylesheet" href="/assets/css/common.css"> |     <link rel="stylesheet" href="/assets/css/common.css"> | ||||||
|  |     <link rel="stylesheet" href="/assets/css/common-popup.css"> | ||||||
|     <link rel="stylesheet" href="/assets/css/chat.css"> |     <link rel="stylesheet" href="/assets/css/chat.css"> | ||||||
|     <title>Chat </title> |     <title>Chat</title> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| <!-- todo: Write the actual chat script --> |     {% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %} | ||||||
| <!--% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %--> | 
 | ||||||
| <div id="fullscreen-container"> |     <div id="msg-deletion-win" class="popup-window"> | ||||||
|     <div class="panel" id="navigation-info-panel"> |         <h1 class="popup-window-msg">Are you sure you want to delete this message?</h1> | ||||||
|         <a href="/list-rooms" id="go-to-chat-list" class="panel-thing"> |         <!-- message preview will be actually rewritten before each window activation--> | ||||||
|             <img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px"> |         <p class="message-in-popup-preview" id="win-deletion-msg-preview">Lorem ipsum dolor</p> | ||||||
|         </a> |         <button class="popup-window-btn-yes" id="msg-deletion-yes">Yes, delete</button> | ||||||
|         <a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing"> |         <button class="popup-window-btn-no" id="msg-deletion-no">No, cancel</button> | ||||||
|             <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> | ||||||
|     <div id="chat-widget"></div> | 
 | ||||||
|     <div class="panel" id="input-panel"> |     <div class="fullscreen-container resp-container"> | ||||||
|         <div contentEditable id="message-input" class="panel-thing"></div> |         <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 class="chat-debug-rect chat-debug-rect-top" id="debug-line-highest"></div> | ||||||
|  |             <div class="chat-debug-rect" id="debug-line-lowest"></div> | ||||||
|  |         </div> | ||||||
|  |         <div class="panel" id="input-panel"> | ||||||
|  |             <div contentEditable id="message-input" class="panel-thing"></div> | ||||||
|  |         </div> | ||||||
|  |         <script src="/assets/js/common.js"></script> | ||||||
|  |         <script src="/assets/js/common-popup.js"></script> | ||||||
|  |         <script src="/assets/js/chat.js"></script> | ||||||
|     </div> |     </div> | ||||||
|     <script src="/assets/js/chat.js"></script> |  | ||||||
| </div> |  | ||||||
| </body> | </body> | ||||||
| </html> | </html> | ||||||
| {% ENDELDEF %} | {% ENDELDEF %} | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| 
 | 
 | ||||||
|     <div id="document-container"> |     <div class="document-container"> | ||||||
|         <div id="navigation-panel" class="panel"> |         <div id="navigation-panel" class="panel"> | ||||||
|             <a href="/list-rooms" id="go-to-chat-list" class="panel-thing"> |             <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"> |                 <img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px"> | ||||||
| @ -35,7 +35,7 @@ | |||||||
|             </p> |             </p> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div class="profile-container"> |         <div class="profile-container resp-container"> | ||||||
|             <h1 class="wide-centered-header">Change user attributes</h1> |             <h1 class="wide-centered-header">Change user attributes</h1> | ||||||
|             <form action = "/user/{% WRITE alienprofile.nickname %}" method="post" enctype="application/x-www-form-urlencoded"> |             <form action = "/user/{% WRITE alienprofile.nickname %}" method="post" enctype="application/x-www-form-urlencoded"> | ||||||
|                 <table class="logins-input-table"> |                 <table class="logins-input-table"> | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ | |||||||
|     </div> |     </div> | ||||||
| 
 | 
 | ||||||
| x | x | ||||||
|     <div id="document-container"> |     <div class="document-container resp-container"> | ||||||
|         <div id="navigation-panel" class="panel"> |         <div id="navigation-panel" class="panel"> | ||||||
|             <a href="/user/{% WRITE userinfo.nickname %}" id="go-to-my-profile" class="panel-thing"> |             <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"> |                 <img alt="Go to my profile" src="/assets/img/user.svg" width="32px"> | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ | |||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| 
 | 
 | ||||||
|     <div id="document-container"> |     <div class="document-container resp-container"> | ||||||
|         <div id="navigation-panel" class="panel"> |         <div id="navigation-panel" class="panel"> | ||||||
|             <a href="/list-rooms" id="go-to-chat-list" class="panel-thing"> |             <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"> |                 <img alt="Go to list of chats" src="/assets/img/list-rooms.svg" width="32px"> | ||||||
|  | |||||||
| @ -10,16 +10,44 @@ body, html { | |||||||
|     overflow: hidden; |     overflow: hidden; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #chat-widget .message-box { | .message-box-mine { | ||||||
|     position: absolute; |     position: absolute; | ||||||
|     right: 5px; |     right: 5px; | ||||||
|     max-width: 300px; |     max-width: 400px; | ||||||
|  |     border: 2px solid #82a173; | ||||||
|  |     padding: 5px; | ||||||
|  |     background-color: #cdff9b; | ||||||
|  |     color: black; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .message-box-alien { | ||||||
|  |     position: absolute; | ||||||
|  |     left: 5px; | ||||||
|  |     max-width: 400px; | ||||||
|     border: 2px solid dimgrey; |     border: 2px solid dimgrey; | ||||||
|     padding: 5px; |     padding: 5px; | ||||||
|     background-color: white; |     background-color: white; | ||||||
|     color: black; |     color: black; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* Only non-system messages can be deleted. Deleted messages do not have delete button | ||||||
|  |  This class should be used with (and, ofcourse, after) class message-box-my/message-box-alien */ | ||||||
|  | .message-box-deleted { | ||||||
|  |     font-weight: bold; | ||||||
|  |     border: 2px solid #cb0005; | ||||||
|  |     background-color: #ffc1bc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .message-box-system { | ||||||
|  |     position: absolute; | ||||||
|  |     left: 15px; | ||||||
|  |     max-width: 500px; | ||||||
|  |     padding: 4px; | ||||||
|  |     background-color: #2d2d2d; | ||||||
|  |     color: white; | ||||||
|  |     font-weight: bold; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* in #chat-widget .message-box */ | /* in #chat-widget .message-box */ | ||||||
| .message-box-top{ | .message-box-top{ | ||||||
|     /* You see, each message contains a 20+2+2 px high icon that HAS TO BE LOADED FIRST. |     /* You see, each message contains a 20+2+2 px high icon that HAS TO BE LOADED FIRST. | ||||||
| @ -30,11 +58,18 @@ body, html { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .message-box-sender-name{ | .message-box-sender-name{ | ||||||
|     font-weight: bold; |  | ||||||
|     color: black; |     color: black; | ||||||
|     text-decoration: none; |     text-decoration: none; | ||||||
|     padding: 2px; |     padding: 2px; | ||||||
|     display: inline; |     display: inline; | ||||||
|  |     font-size: 0.8em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Additional to message-box-sender-name */ | ||||||
|  | .message-box-sender-shortname { | ||||||
|  |     font-weight: bold; | ||||||
|  |     padding-left: 3px; | ||||||
|  |     font-size: 0.94em; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .message-box-sender-name:hover{ | .message-box-sender-name:hover{ | ||||||
| @ -51,7 +86,11 @@ body, html { | |||||||
|     word-wrap: break-word; |     word-wrap: break-word; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #input-panel #message-input{ | #input-panel { | ||||||
|  |     min-height: 20px; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #message-input { | ||||||
|     padding: 15px; |     padding: 15px; | ||||||
|     height: auto; |     height: auto; | ||||||
|     width: 100%; |     width: 100%; | ||||||
| @ -62,3 +101,13 @@ body, html { | |||||||
|     font-size: .9rem; |     font-size: .9rem; | ||||||
|     margin: 10px; |     margin: 10px; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | .message-in-popup-preview{ | ||||||
|  |     border: 4px solid red; | ||||||
|  |     width: 80%; | ||||||
|  |     max-width: 200px; | ||||||
|  |     margin-left: auto; | ||||||
|  |     margin-right: auto; | ||||||
|  |     max-height: 20%; | ||||||
|  |     word-wrap: break-word; | ||||||
|  | } | ||||||
| @ -54,12 +54,12 @@ | |||||||
|     font-family: Arial, sans-serif; |     font-family: Arial, sans-serif; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #document-container { | .document-container { | ||||||
|     width: 80%; /* Full width of the viewport */ |     width: 80%; /* Full width of the viewport */ | ||||||
|     margin: 0 auto; /* Center the container horizontally */ |     margin: 0 auto; /* Center the container horizontally */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #fullscreen-container { | .fullscreen-container { | ||||||
|     width: 80%; /* Full width of the viewport */ |     width: 80%; /* Full width of the viewport */ | ||||||
|     height: 100vh; /* Full height of the viewport */ |     height: 100vh; /* Full height of the viewport */ | ||||||
|     display: flex; |     display: flex; | ||||||
| @ -67,6 +67,18 @@ | |||||||
|     margin: 0 auto; /* Center the container horizontally */ |     margin: 0 auto; /* Center the container horizontally */ | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @media (orientation: landscape) { | ||||||
|  |     .resp-container{ | ||||||
|  |         width: 80%; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (orientation: portrait){ | ||||||
|  |     .resp-container{ | ||||||
|  |         width: 100%; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| body { | body { | ||||||
|     background-color: #f000f0; |     background-color: #f000f0; | ||||||
|     background-image: url("/assets/img/clavicle-transparent.png"), url("/assets/img/broken-clavicle.png"); |     background-image: url("/assets/img/clavicle-transparent.png"), url("/assets/img/broken-clavicle.png"); | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								assets/css/debug.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								assets/css/debug.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | .chat-debug-rect{ | ||||||
|  |     width: 100%; | ||||||
|  |     position: absolute; | ||||||
|  |     left: 0; | ||||||
|  |     background-color: rgba(255, 50, 50, 160); | ||||||
|  |     height: 4px; | ||||||
|  |     z-index: 2; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .chat-debug-rect-top{ | ||||||
|  |     background-color: rgba(148, 0, 211, 160); | ||||||
|  | } | ||||||
| @ -76,12 +76,10 @@ function updateLocalStateFromChatUpdResp(chatUpdResp){ | |||||||
|     // If my role is updated, we need to update all the boes of already set users (kick button can appear and disappear)
 |     // If my role is updated, we need to update all the boes of already set users (kick button can appear and disappear)
 | ||||||
|     let literalMemberList = document.getElementById("CM-list"); |     let literalMemberList = document.getElementById("CM-list"); | ||||||
|     // We ignore messages and everything related to them. Dang, I really should add an argument to disable message lookup here
 |     // We ignore messages and everything related to them. Dang, I really should add an argument to disable message lookup here
 | ||||||
|     // let haveToUpdateAllBoxes = false;
 |  | ||||||
|     for (let memberSt of chatUpdResp.members){ |     for (let memberSt of chatUpdResp.members){ | ||||||
|         console.log([memberSt, userinfo.uid, myRoleHere]); |         console.log([memberSt, userinfo.uid, myRoleHere]); | ||||||
|         if (memberSt.userId === userinfo.uid && myRoleHere !== memberSt.roleHere){ |         if (memberSt.userId === userinfo.uid && myRoleHere !== memberSt.roleHere){ | ||||||
|             myRoleHere = memberSt.roleHere; |             myRoleHere = memberSt.roleHere; | ||||||
|             // haveToUpdateAllBoxes = true;
 |  | ||||||
|             for (let [id, memberSt] of members){ |             for (let [id, memberSt] of members){ | ||||||
|                 let box = memberBoxes.get(id); |                 let box = memberBoxes.get(id); | ||||||
|                 updateBoxWithSt(box, memberSt); |                 updateBoxWithSt(box, memberSt); | ||||||
| @ -115,7 +113,7 @@ function configureSummonUserInterface(){ | |||||||
|     document.getElementById("user-summoning-yes").onclick = function(ev ){ |     document.getElementById("user-summoning-yes").onclick = function(ev ){ | ||||||
|         if (ev.button !==0) |         if (ev.button !==0) | ||||||
|             return; |             return; | ||||||
|         let nickname = document.getElementById("summoned-user-nickname").value; |         let nickname = String(document.getElementById("summoned-user-nickname").value); | ||||||
|         let isReadOnly = document.getElementById("summoned-user-is-read-only").checked; |         let isReadOnly = document.getElementById("summoned-user-is-read-only").checked; | ||||||
|         deactivateActivePopup(); |         deactivateActivePopup(); | ||||||
|         let Sent = genSentBase(); |         let Sent = genSentBase(); | ||||||
| @ -174,8 +172,7 @@ function configureKickUserInterfaceWinPart(){ | |||||||
| __mainloopDelayMS = 5000; | __mainloopDelayMS = 5000; | ||||||
| __guestMainloopPollerAction = function (){ | __guestMainloopPollerAction = function (){ | ||||||
|     console.log("Hello, world"); |     console.log("Hello, world"); | ||||||
|     let Sent = genSentBase(); |     apiRequest("chatPollEvents", genSentBase()). | ||||||
|     apiRequest("chatPollEvents", Sent). |  | ||||||
|     then((Recv) => { |     then((Recv) => { | ||||||
|         console.log(Recv); |         console.log(Recv); | ||||||
|         updateLocalStateFromRecv(Recv); |         updateLocalStateFromRecv(Recv); | ||||||
|  | |||||||
| @ -1,17 +1,6 @@ | |||||||
| // In real world, I would get this variables from server through nytl
 | let LocalHistoryId = 0; | ||||||
| let pres = {lang: ''} | 
 | ||||||
| let userinfo = {id: 2, nickname: 'pv', name: 'Pavlov Vladimir'}; | let members = new Map(); | ||||||
| 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 loadedMessages = new Map();  // messageSt objects
 | ||||||
| let visibleMessages = new Map();  // HTMLElement objects
 | let visibleMessages = new Map();  // HTMLElement objects
 | ||||||
| @ -19,14 +8,37 @@ let visibleMessages = new Map();  // HTMLElement objects | |||||||
| let anchoredMsg = -1; | let anchoredMsg = -1; | ||||||
| let visibleMsgSegStart = -1; | let visibleMsgSegStart = -1; | ||||||
| let visibleMsgSegEnd = -2; | let visibleMsgSegEnd = -2; | ||||||
| let offsetOfAnchor = 100; | let offsetOfAnchor = 500; | ||||||
|  | let highestPoint = null; | ||||||
|  | let lowestPoint = null; | ||||||
|  | 
 | ||||||
|  | let lastMsgId = -1; | ||||||
|  | let myRoleHere = null;  // Dung local state updates should be updated first
 | ||||||
| 
 | 
 | ||||||
| // Would start with true if opened `/chat/<>`
 | // Would start with true if opened `/chat/<>`
 | ||||||
| let bumpedAtTheBottom = false; | let bumpedAtTheBottom = false; | ||||||
| 
 | 
 | ||||||
| let members = new Map(); | // Hidden variable. When deletion window popup is active
 | ||||||
| for (let memberSt of initial_chatUpdResp.members){ | // Persists from popup activation until popup deactivation
 | ||||||
|     members.set(memberSt.id, memberSt); | let storeHiddenMsgIdForDeletionWin = -1; | ||||||
|  | 
 | ||||||
|  | // Positive in production, negative for debug
 | ||||||
|  | let softZoneSz = -150; | ||||||
|  | let chatPadding = 300; | ||||||
|  | 
 | ||||||
|  | function genSentBase(){ | ||||||
|  |     return { | ||||||
|  |         'chatUpdReq': { | ||||||
|  |             'LocalHistoryId': LocalHistoryId, | ||||||
|  |             'chatId': openedchat.id | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function genSentBaseGMN(){ | ||||||
|  |     let Sent = genSentBase(); | ||||||
|  |     Sent.amount = 1; | ||||||
|  |     return Sent; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function updateOffsetOfVisibleMsg(msgId, offset){ | function updateOffsetOfVisibleMsg(msgId, offset){ | ||||||
| @ -54,59 +66,117 @@ function updateOffsetsDown(){ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function updateOffsetsSane(){ | function updateOffsetsSane(){ | ||||||
|     let highest_point = updateOffsetsUpToTop(); |     if (anchoredMsg < 0) | ||||||
|     let lowest_point = updateOffsetsDown(); |         return; | ||||||
|     return [highest_point, lowest_point]; |     highestPoint = updateOffsetsUpToTop(); | ||||||
|  |     lowestPoint = updateOffsetsDown(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function updateOffsets(){ | function updateOffsets(){ | ||||||
|     if (anchoredMsg < 0) |     if (anchoredMsg < 0) | ||||||
|         return; |         return; | ||||||
|     let [highest_point, lowest_point] = updateOffsetsSane(); |     updateOffsetsSane() | ||||||
|     let winTop = document.getElementById("chat-widget").offsetHeight; |     let winTop = document.getElementById("chat-widget").offsetHeight; | ||||||
|     if (lowest_point > 5 || (highest_point - lowest_point) <= winTop){ |     if (lowestPoint > chatPadding || (highestPoint - lowestPoint) <= winTop){ | ||||||
|         bumpedAtTheBottom = true; |         bumpedAtTheBottom = true; | ||||||
|         anchoredMsg = visibleMsgSegEnd; |         anchoredMsg = visibleMsgSegEnd; | ||||||
|         offsetOfAnchor = 5; |         offsetOfAnchor = chatPadding; | ||||||
|         updateOffsetsSane(); |         updateOffsetsSane(); | ||||||
|     } else if (highest_point < winTop - 5){ |     } else if (highestPoint < winTop - chatPadding) { | ||||||
|         console.log("Adancing by " + (winTop - 5 - highest_point)) |         console.log("Advancing by " + (winTop - chatPadding - highestPoint)) | ||||||
|         offsetOfAnchor += (winTop - 5 - highest_point); |         offsetOfAnchor += (winTop - chatPadding - highestPoint); | ||||||
|         updateOffsetsSane(); |         updateOffsetsSane(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function makeMessageBox(messageSt){ | function shouldShowDeleteMesgBtn(messageSt){ | ||||||
|     if (!messageSt.exists || messageSt.isSystem) |     return !messageSt.isSystem && messageSt.exists && ( | ||||||
|         throw new Error("Not ready for this"); |         messageSt.myRoleHere === userChatRoleAdmin || messageSt.senderUserId === userinfo.uid); | ||||||
|     const parentDiv = document.getElementById("chat-widget"); | } | ||||||
|  | 
 | ||||||
|  | function getMsgTypeClassSenderBased(messageSt){ | ||||||
|  |     if (messageSt.isSystem) | ||||||
|  |         return "message-box-system" | ||||||
|  |     if (messageSt.senderUserId === userinfo.uid) | ||||||
|  |         return "message-box-mine" | ||||||
|  |     return "message-box-alien"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function getMsgFullTypeClassName(messageSt){ | ||||||
|  |     return getMsgTypeClassSenderBased(messageSt) + (messageSt.exists ? "" : " message-box-deleted"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Two things can be updated: messages existance and delete button visibility */ | ||||||
|  | function updateMessageBox(id, box, messageSt){ | ||||||
|  |     box.querySelector(".message-box-button-delete").style.display = shouldShowDeleteMesgBtn(messageSt) ? "block" : "none"; | ||||||
|  |     box.className = getMsgFullTypeClassName(messageSt); | ||||||
|  |     // Notice, that no check of previous state is performed. Double loading is a rare event,
 | ||||||
|  |     // and I can afford to be slow
 | ||||||
|  |     if (!messageSt.exists) | ||||||
|  |         box.querySelector(".message-box-msg").innerText = msgErased; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function decodeSystemMessage(text){ | ||||||
|  |     let [subject, verb, object] = text.split(','); | ||||||
|  |     let subjectId = Number(subject); | ||||||
|  |     let objectId = Number(object); | ||||||
|  |     let subjectRef = members.has(subjectId) ? members.get(subjectId).nickname : "???"; | ||||||
|  |     let objectRef = members.has(objectId) ? members.get(objectId).nickname : "???"; | ||||||
|  |     if (verb === "kicked"){ | ||||||
|  |         return subjectRef + " kicked " + objectRef; | ||||||
|  |     } else if (verb === "summoned"){ | ||||||
|  |         return subjectRef + " summoned " + objectId; | ||||||
|  |     } else if (verb === "left"){ | ||||||
|  |         return subjectRef + " left chat"; | ||||||
|  |     } else if (verb === "joined"){ | ||||||
|  |         return subjectId + " joined chat"; | ||||||
|  |     } else if (verb === "created"){ | ||||||
|  |         return subjectId + " created this chat"; | ||||||
|  |     } | ||||||
|  |     return "... Bad log ..."; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function convertMessageStToBox(messageSt){ | ||||||
|     let box = document.createElement("div"); |     let box = document.createElement("div"); | ||||||
|     parentDiv.appendChild(box); |     box.className = getMsgFullTypeClassName(messageSt); | ||||||
|     box.className = "message-box"; | 
 | ||||||
|  |     let ID = messageSt.id; | ||||||
| 
 | 
 | ||||||
|     let topPart = document.createElement("div"); |     let topPart = document.createElement("div"); | ||||||
|     box.appendChild(topPart); |     box.appendChild(topPart); | ||||||
|     topPart.className = "message-box-top"; |     topPart.className = "message-box-top"; | ||||||
| 
 | 
 | ||||||
|  |     if (!members.has(messageSt.senderUserId)) | ||||||
|  |         throw new Error("First - update members"); | ||||||
|  |     let senderMemberSt = members.get(messageSt.senderUserId); | ||||||
|  |     let senderProfileURI = "/user/" + senderMemberSt.nickname; | ||||||
|  | 
 | ||||||
|     let inTopPartSenderName = document.createElement("a"); |     let inTopPartSenderName = document.createElement("a"); | ||||||
|     topPart.appendChild(inTopPartSenderName); |     topPart.appendChild(inTopPartSenderName); | ||||||
|     inTopPartSenderName.className = "message-box-sender-name"; |     inTopPartSenderName.className = "message-box-sender-name"; | ||||||
|     if (!members.has(messageSt.senderUserId)) |     inTopPartSenderName.innerText = senderMemberSt.name; | ||||||
|         throw new Error("MMMHMMMMGMHMMMM. First - update members. Then messages"); |     inTopPartSenderName.href = senderProfileURI; | ||||||
|     let memberSt = members.get(messageSt.senderUserId); |  | ||||||
|     inTopPartSenderName.innerText = memberSt.name + " (" + memberSt.nickname + ")"; |  | ||||||
|     inTopPartSenderName.href = "/user/" + memberSt.nickname; |  | ||||||
| 
 | 
 | ||||||
|     let ID = messageSt.id; |     let inTopPartSenderNickname = document.createElement("a"); | ||||||
|  |     topPart.appendChild(inTopPartSenderNickname); | ||||||
|  |     inTopPartSenderNickname.className = "message-box-sender-name message-box-sender-shortname" | ||||||
|  |     inTopPartSenderNickname.innerText = senderMemberSt.nickname; | ||||||
|  |     inTopPartSenderNickname.href = senderProfileURI; | ||||||
| 
 | 
 | ||||||
|     let inTopPartButtonDelete = document.createElement("img"); |     let inTopPartButtonDelete = document.createElement("img"); | ||||||
|     topPart.appendChild(inTopPartButtonDelete); |     topPart.appendChild(inTopPartButtonDelete); | ||||||
|     inTopPartButtonDelete.className = "message-box-button"; |     inTopPartButtonDelete.className = "message-box-button message-box-button-delete"; | ||||||
|     inTopPartButtonDelete.src = "/assets/img/delete.svg"; |     inTopPartButtonDelete.src = "/assets/img/delete.svg"; | ||||||
|     inTopPartButtonDelete.onclick = (ev) => { |     inTopPartButtonDelete.onclick = (ev) => { | ||||||
|         if (ev.button === 0){ |         if (ev.button !== 0) | ||||||
|             console.log("Tried to delete message " + ID); |             return; | ||||||
|         } |         let msgText = box.querySelector(".message-box-msg").innerText; | ||||||
|  |         let previewText = senderMemberSt.nickname + ":\n" + msgText; | ||||||
|  |         if (previewText.length > 1000) | ||||||
|  |             previewText = previewText.substring(0, 1000 - 3); | ||||||
|  |         document.getElementById("win-deletion-msg-preview").innerText = previewText; | ||||||
|  |         storeHiddenMsgIdForDeletionWin = ID; | ||||||
|  |         activatePopupWindowById("msg-deletion-win"); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let inTopPartButtonGetLink = document.createElement("img"); |     let inTopPartButtonGetLink = document.createElement("img"); | ||||||
| @ -114,34 +184,41 @@ function makeMessageBox(messageSt){ | |||||||
|     inTopPartButtonGetLink.className = "message-box-button"; |     inTopPartButtonGetLink.className = "message-box-button"; | ||||||
|     inTopPartButtonGetLink.src = "/assets/img/link.svg"; |     inTopPartButtonGetLink.src = "/assets/img/link.svg"; | ||||||
|     inTopPartButtonGetLink.onclick = (ev) => { |     inTopPartButtonGetLink.onclick = (ev) => { | ||||||
|         if (ev.button === 0){ |         if (ev.button !== 0) | ||||||
|             console.log("Tried to get link on message " + ID); |             return; | ||||||
|         } |         let URI = window.location.host + "/chat/" + openedchat.nickname + "/m/" + String(ID); | ||||||
|  |         document.getElementById("message-input").innerText += (" " + URI + ""); | ||||||
|  |         console.log("Tried to get link on message " + ID); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|     let msgPart = document.createElement("p"); |     let msgPart = document.createElement("p"); | ||||||
|     box.appendChild(msgPart); |     box.appendChild(msgPart); | ||||||
|     msgPart.className = "message-box-msg"; |     msgPart.className = "message-box-msg"; | ||||||
|     msgPart.innerText = messageSt.text; |     if (messageSt.exists){ | ||||||
|  |         if (messageSt.isSystem) | ||||||
|  |             msgPart.innerText = decodeSystemMessage(messageSt.text); | ||||||
|  |         else | ||||||
|  |             msgPart.innerText = messageSt.text; | ||||||
|  |     } else | ||||||
|  |         msgPart.innerText = msgErased; | ||||||
|     return box; |     return box; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function makeVisible(msgId){ | function makeVisible(msgId){ | ||||||
|     visibleMessages.set(msgId, makeMessageBox(loadedMessages.get(msgId))) |     let box = convertMessageStToBox(loadedMessages.get(msgId)); | ||||||
|  |     const chatWin = document.getElementById("chat-widget"); | ||||||
|  |     chatWin.appendChild(box); | ||||||
|  |     visibleMessages.set(msgId, box); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function opaNewMessage(messageSt){ | function opaNewMessageSt(messageSt){ | ||||||
|     let msgId = messageSt.id; |     let msgId = messageSt.id; | ||||||
|     let text = messageSt.text; |  | ||||||
|     const chatWin = document.getElementById("chat-widget"); |  | ||||||
|     if (loadedMessages.has(msgId)){ |     if (loadedMessages.has(msgId)){ | ||||||
|         throw new Error("Not ready yet"); |         loadedMessages.set(msgId, messageSt); | ||||||
|         // loadedMessages.get(msgId).text = text;
 |         if (visibleMessages.has(msgId)){ | ||||||
|         // if (visibleMessages.has(msgId)){
 |             updateMessageBox(msgId, visibleMessages.get(msgId), messageSt); | ||||||
|         //     visibleMessages.get(msgId).textContent = text;
 |         } | ||||||
|         //     updateOffsets();
 |  | ||||||
|         // }
 |  | ||||||
|     } else { |     } else { | ||||||
|         loadedMessages.set(msgId, messageSt); |         loadedMessages.set(msgId, messageSt); | ||||||
|         if (anchoredMsg < 0){ |         if (anchoredMsg < 0){ | ||||||
| @ -149,7 +226,6 @@ function opaNewMessage(messageSt){ | |||||||
|             visibleMsgSegStart = msgId; |             visibleMsgSegStart = msgId; | ||||||
|             visibleMsgSegEnd = msgId; |             visibleMsgSegEnd = msgId; | ||||||
|             makeVisible(msgId); |             makeVisible(msgId); | ||||||
|             updateOffsets(); |  | ||||||
|         } else if (msgId + 1 === visibleMsgSegStart) { |         } else if (msgId + 1 === visibleMsgSegStart) { | ||||||
|             visibleMsgSegStart--; |             visibleMsgSegStart--; | ||||||
|             makeVisible(msgId); |             makeVisible(msgId); | ||||||
| @ -157,7 +233,6 @@ function opaNewMessage(messageSt){ | |||||||
|                 visibleMsgSegStart--; |                 visibleMsgSegStart--; | ||||||
|                 makeVisible(visibleMsgSegStart); |                 makeVisible(visibleMsgSegStart); | ||||||
|             } |             } | ||||||
|             updateOffsets(); |  | ||||||
|         } else if (msgId - 1 === visibleMsgSegEnd){ |         } else if (msgId - 1 === visibleMsgSegEnd){ | ||||||
|             visibleMsgSegEnd++; |             visibleMsgSegEnd++; | ||||||
|             makeVisible(msgId); |             makeVisible(msgId); | ||||||
| @ -165,57 +240,174 @@ function opaNewMessage(messageSt){ | |||||||
|                 visibleMsgSegEnd++; |                 visibleMsgSegEnd++; | ||||||
|                 makeVisible(visibleMsgSegEnd); |                 makeVisible(visibleMsgSegEnd); | ||||||
|             } |             } | ||||||
|             updateOffsets(); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function test(id, uid){ | function canISendMessages(){ | ||||||
|     opaNewMessage({ |     return myRoleHere === userChatRoleRegular || myRoleHere === userChatRoleAdmin; | ||||||
|         id: id, text: "Message number " + String(id), senderUserId: uid, exists: true, isSystem: false} |  | ||||||
|     ); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| let mainloopTimeout = null; | function updateLocalStateFromChatUpdRespBlind(chatUpdResp){ | ||||||
| let mainloopPoller = null; |     LocalHistoryId = chatUpdResp.HistoryId; | ||||||
| function setMainloopTimeout(){ |     for (let memberSt of chatUpdResp.members){ | ||||||
|     mainloopTimeout = setTimeout(mainloopPoller, 1000); |         let id = memberSt.userId; | ||||||
|  |         if (id === userinfo.uid && myRoleHere !== memberSt.roleHere) { | ||||||
|  |             myRoleHere = memberSt.roleHere; | ||||||
|  |             for (let [msgId, box] of visibleMessages){ | ||||||
|  |                 updateMessageBox(msgId, loadedMessages.get(msgId), box); | ||||||
|  |             } | ||||||
|  |             document.getElementById("message-input").style.display = (canISendMessages() ? "block" : "none"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     for (let memberSt of chatUpdResp.members){ | ||||||
|  |         let id = memberSt.userId; | ||||||
|  |         members.set(id, memberSt); | ||||||
|  |     } | ||||||
|  |     lastMsgId = chatUpdResp.lastMsgId; | ||||||
|  |     for (let messageSt of chatUpdResp.messages){ | ||||||
|  |         opaNewMessageSt(messageSt); | ||||||
|  |     } | ||||||
|  |     updateOffsets(); | ||||||
| } | } | ||||||
| mainloopPoller = function(){ | 
 | ||||||
|  | function updateLocalStateFromRecvBlind(Recv){ | ||||||
|  |     updateLocalStateFromChatUpdRespBlind(Recv.chatUpdResp); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function requestMessageNeighbours(fromMsg, direction){ | ||||||
|  |     let Sent = genSentBaseGMN(); | ||||||
|  |     Sent.msgId = fromMsg; | ||||||
|  |     Sent.direction = direction; | ||||||
|  |     let Recv = await apiRequest("getMessageNeighbours", Sent); | ||||||
|  |     updateLocalStateFromRecvBlind(Recv);  // Blind to non-loaded whitespaces
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function needToLoadWhitespace(){ | ||||||
|  |     let winTop = document.getElementById("chat-widget").offsetHeight; | ||||||
|  |     if (anchoredMsg === -1){ | ||||||
|  |         if (lastMsgId >= 0) | ||||||
|  |             console.log("NEEDED 1", anchoredMsg, lastMsgId); | ||||||
|  |         return lastMsgId >= 0; | ||||||
|  |     } else if (highestPoint < winTop + softZoneSz && visibleMsgSegStart > 0){ | ||||||
|  |         console.log("NEEDED 2", visibleMsgSegStart); | ||||||
|  |         return true; | ||||||
|  |     } else if (lowestPoint > 0 - softZoneSz && visibleMsgSegEnd < lastMsgId){ | ||||||
|  |         console.log("NEEDED 3"); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function tryLoadWhitespace(){ | ||||||
|  |     let winTop = document.getElementById("chat-widget").offsetHeight; | ||||||
|  |     console.log(anchoredMsg, lastMsgId); | ||||||
|  |     if (anchoredMsg === -1){ | ||||||
|  |         if (lastMsgId !== -1){ | ||||||
|  |             await requestMessageNeighbours(-1, "backward"); | ||||||
|  |         } | ||||||
|  |     } else if (highestPoint < winTop + softZoneSz && visibleMsgSegStart > 0){ | ||||||
|  |         await requestMessageNeighbours(visibleMsgSegStart, "backward"); | ||||||
|  |     } else if (lowestPoint > 0 - softZoneSz && visibleMsgSegEnd < lastMsgId){ | ||||||
|  |         await requestMessageNeighbours(visibleMsgSegEnd, "forward"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function loadWhitespaceMultitry(){ | ||||||
|  |     if (needToLoadWhitespace()){ | ||||||
|  |         cancelMainloopTimeout(); | ||||||
|  |         do { | ||||||
|  |             console.trace(); | ||||||
|  |             console.log("Normalnie ludi ne spyat"); | ||||||
|  |             try { | ||||||
|  |                 await tryLoadWhitespace(); | ||||||
|  |                 await sleep(100); | ||||||
|  |             } catch (e) { | ||||||
|  |                 console.error(e); | ||||||
|  |                 await sleep(1500); | ||||||
|  |             } | ||||||
|  |         } while (needToLoadWhitespace()); | ||||||
|  |         setMainloopTimeout(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function updateLocalStateFromRecv(Recv){ | ||||||
|  |     updateLocalStateFromRecvBlind(Recv); | ||||||
|  |     await loadWhitespaceMultitry(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function safeApiRequestWithLocalStUpdate(type, Sent, errMsg){ | ||||||
|     try { |     try { | ||||||
|         console.log("Hello, World!"); |         let Recv = await apiRequest(type, Sent) | ||||||
|     } catch (error){} |         await updateLocalStateFromRecv(Recv); | ||||||
|     setMainloopTimeout(); |     } catch(e) { | ||||||
|  |         console.error(e); | ||||||
|  |         alert(errMsg); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function configureMsgDeletionPopupButtons(){ | ||||||
|  |     document.getElementById("msg-deletion-yes").onclick = function(ev){ | ||||||
|  |         if (ev.button !== 0) | ||||||
|  |             return; | ||||||
|  |         deactivateActivePopup(); | ||||||
|  |         let Sent = genSentBase(); | ||||||
|  |         Sent.id = storeHiddenMsgIdForDeletionWin; | ||||||
|  |         safeApiRequestWithLocalStUpdate("deleteMessage", Sent, "Failed to delete message"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     document.getElementById("msg-deletion-no").onclick = function (ev){ | ||||||
|  |         if (ev.button !== 0) | ||||||
|  |             return; | ||||||
|  |         deactivateActivePopup(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | __mainloopDelayMs = 1000; | ||||||
|  | async function UPDATE(){ | ||||||
|  |     let Recv = await apiRequest("chatPollEvents", genSentBase()); | ||||||
|  |     await updateLocalStateFromRecv(Recv); | ||||||
|  | } | ||||||
|  | // __guestMainloopPollerAction = UPDATE();
 | ||||||
| 
 | 
 | ||||||
| window.onload = function (){ | window.onload = function (){ | ||||||
|     console.log("Everything was loaded"); |     console.log("Page was loaded"); | ||||||
|     test(6, 1); | 
 | ||||||
|     test(1, 2); |     document.body.addEventListener("wheel", function (event) { | ||||||
|     test(3, 3); |         // event.preventDefault();
 | ||||||
|     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; |         bumpedAtTheBottom = false; | ||||||
|         console.log("Scroll of " + String(event.deltaY)); |         offsetOfAnchor += event.deltaY / 3; | ||||||
|         offsetOfAnchor += event.deltaY / 5; |  | ||||||
|         updateOffsets(); |         updateOffsets(); | ||||||
|  |         loadWhitespaceMultitry().then(dopDopYesYes); | ||||||
|     }); |     }); | ||||||
|     mainloopPoller(); | 
 | ||||||
|     document.getElementById("message-input").addEventListener("keyup", (event) => { |     document.getElementById("message-input").addEventListener("keyup", function (event) { | ||||||
|         if (event.ctrlKey && event.key === 'Enter'){ |         if (event.ctrlKey && event.key === 'Enter'){ | ||||||
|             let textarea = document.getElementById("message-input"); |             let textarea = document.getElementById("message-input"); | ||||||
|             console.log(textarea.value); |             let text = String(textarea.innerText); | ||||||
|  |             console.log(text); | ||||||
|  |             textarea.innerText = ""; | ||||||
|  |             let Sent = genSentBase(); | ||||||
|  |             Sent.content = {}; | ||||||
|  |             Sent.content.text = text; | ||||||
|  |             safeApiRequestWithLocalStUpdate("sendMessage", Sent, "Failed to send message"); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     let chatWg = document.getElementById("chat-widget"); | ||||||
|  |     let chatWgDebugLinesFnc = function (){ | ||||||
|  |         let H = chatWg.offsetHeight; | ||||||
|  |         document.getElementById("debug-line-lowest").style.bottom = String(-softZoneSz) + "px"; | ||||||
|  |         document.getElementById("debug-line-highest").style.bottom = String(H + softZoneSz) + "px"; | ||||||
|  |     }; | ||||||
|  |     window.addEventListener("resize", chatWgDebugLinesFnc); | ||||||
|  |     chatWgDebugLinesFnc(); | ||||||
|  | 
 | ||||||
|  |     configureMsgDeletionPopupButtons(); | ||||||
|  | 
 | ||||||
|  |     updateLocalStateFromChatUpdRespBlind(initial_chatUpdResp); | ||||||
|  | 
 | ||||||
|  |     setMainloopTimeout(); | ||||||
|  | 
 | ||||||
|  |     loadWhitespaceMultitry(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,9 @@ | |||||||
|  | let dopDopYesYes = (ign) => {}; | ||||||
|  | 
 | ||||||
|  | function sleep(ms){ | ||||||
|  |     return new Promise(res => setTimeout(res, ms)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| async function apiRequest(type, req){ | async function apiRequest(type, req){ | ||||||
|     let A = await fetch("/api/" + type, |     let A = await fetch("/api/" + type, | ||||||
|         {method: 'POST', body: JSON.stringify(req)}); |         {method: 'POST', body: JSON.stringify(req)}); | ||||||
| @ -10,18 +16,18 @@ async function apiRequest(type, req){ | |||||||
| /* Framework for pages with mainloop (it can be npt only polling, but also literally anything else */ | /* Framework for pages with mainloop (it can be npt only polling, but also literally anything else */ | ||||||
| let __mainloopDelayMs = 3000; | let __mainloopDelayMs = 3000; | ||||||
| let mainloopTimeout = null; | let mainloopTimeout = null; | ||||||
| let mainloopPoller = null; |  | ||||||
| let __guestMainloopPollerAction = null; | let __guestMainloopPollerAction = null; | ||||||
| function setMainloopTimeout(){ | function setMainloopTimeout(){ | ||||||
|     mainloopTimeout = setTimeout(mainloopPoller, __mainloopDelayMs); |     mainloopTimeout = setTimeout(mainloopPoller, __mainloopDelayMs); | ||||||
| } | } | ||||||
| function cancelMainloopTimeout(){ | function cancelMainloopTimeout(){ | ||||||
|     clearTimeout(mainloopTimeout); |     clearTimeout(mainloopTimeout); | ||||||
|  |     mainloopTimeout = null; | ||||||
| } | } | ||||||
| mainloopPoller = function(){ | function mainloopPoller(){ | ||||||
|     try { |     try { | ||||||
|         console.log("Hello, World!"); |         if (__guestMainloopPollerAction) | ||||||
|         __guestMainloopPollerAction(); |             __guestMainloopPollerAction(); | ||||||
|     } catch (error){ |     } catch (error){ | ||||||
|         console.log(error) |         console.log(error) | ||||||
|     } |     } | ||||||
| @ -50,3 +56,6 @@ function roleToColor(role) { | |||||||
|     } |     } | ||||||
|     return "#286500"  // Bug
 |     return "#286500"  // Bug
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // todo: replace it with translation
 | ||||||
|  | const msgErased = "[ ERASED ]"; | ||||||
|  | |||||||
| @ -108,8 +108,8 @@ function configureChatCreationInterface(){ | |||||||
|             return; |             return; | ||||||
|         let chatNicknameInput = document.getElementById("chat-nickname-input"); |         let chatNicknameInput = document.getElementById("chat-nickname-input"); | ||||||
|         let chatNameInput = document.getElementById("chat-name-input"); |         let chatNameInput = document.getElementById("chat-name-input"); | ||||||
|         let nickname = chatNicknameInput.value; |         let nickname = String(chatNicknameInput.value); | ||||||
|         let name = chatNameInput.value; |         let name = String(chatNameInput.value); | ||||||
|         deactivateActivePopup(); |         deactivateActivePopup(); | ||||||
|         let Sent = genSentBase(); |         let Sent = genSentBase(); | ||||||
|         Sent.content = {}; |         Sent.content = {}; | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| #include "server_data_interact.h" | #include "server_data_interact.h" | ||||||
| #include <engine_engine_number_9/baza_throw.h> | #include <engine_engine_number_9/baza_throw.h> | ||||||
|  | #include "../debug.h" | ||||||
| 
 | 
 | ||||||
| namespace iu9cawebchat { | namespace iu9cawebchat { | ||||||
|     json::JSON internalapi_deleteMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { |     json::JSON internalapi_deleteMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { | ||||||
|         int64_t chatId = Sent["chatUpdReq"].asInteger().get_int(); |         // debug_print_json(Sent);
 | ||||||
|  |         int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int(); | ||||||
|         int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId); |         int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId); | ||||||
|         if (my_role_here == user_chat_role_deleted) |         if (my_role_here == user_chat_role_deleted) | ||||||
|             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); |             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "server_data_interact.h" | #include "server_data_interact.h" | ||||||
| #include <engine_engine_number_9/baza_throw.h> | #include <engine_engine_number_9/baza_throw.h> | ||||||
| #include "../str_fields.h" | #include "../str_fields.h" | ||||||
|  | #include "../debug.h" | ||||||
| 
 | 
 | ||||||
| namespace iu9cawebchat { | namespace iu9cawebchat { | ||||||
|     /* No authorization check is performed
 |     /* No authorization check is performed
 | ||||||
| @ -13,16 +14,19 @@ namespace iu9cawebchat { | |||||||
|         int64_t chat_lastMsgId = get_lastMsgId_of_chat(conn, chatId); |         int64_t chat_lastMsgId = get_lastMsgId_of_chat(conn, chatId); | ||||||
|         SqliteStatement req(conn, |         SqliteStatement req(conn, | ||||||
|             "INSERT INTO `message` (`chatId`, `id`, `senderUserId`, `exists`, `isSystem`, `chat_IncHistoryId`, " |             "INSERT INTO `message` (`chatId`, `id`, `senderUserId`, `exists`, `isSystem`, `chat_IncHistoryId`, " | ||||||
|             "`text`) VALUES (?1, ?2, ?3 1, ?4, ?5, ?6)", |             "`text`) VALUES (?1, ?2, ?3, 1, ?4, ?5, ?6)", | ||||||
|             {{1, chatId}, {2, chat_lastMsgId + 1}, {4, (int64_t)isSystem}, {5, chat_HistoryId_BEFORE_MSG + 1}}, {{6, text}}); |             {{1, chatId}, {2, chat_lastMsgId + 1}, {4, (int64_t)isSystem}, {5, chat_HistoryId_BEFORE_MSG + 1}}, {{6, text}}); | ||||||
|         if (!isSystem) |         if (!isSystem) | ||||||
|             sqlite_stmt_bind_int64(req, 3, uid); |             sqlite_stmt_bind_int64(req, 3, uid); | ||||||
|  |         if (sqlite_stmt_step(req, {}, {}) != SQLITE_DONE) | ||||||
|  |             een9_THROW("There must be something wrong"); | ||||||
|         sqlite_nooutput(conn, "UPDATE `chat` SET `lastMsgId` = ?1, `it_HistoryId` = ?2 WHERE `id` = ?3", |         sqlite_nooutput(conn, "UPDATE `chat` SET `lastMsgId` = ?1, `it_HistoryId` = ?2 WHERE `id` = ?3", | ||||||
|             {{1, chat_lastMsgId + 1}, {2, chat_HistoryId_BEFORE_MSG + 1}, {3, chatId}}, {}); |             {{1, chat_lastMsgId + 1}, {2, chat_HistoryId_BEFORE_MSG + 1}, {3, chatId}}, {}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     json::JSON internalapi_sendMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { |     json::JSON internalapi_sendMessage(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { | ||||||
|         int64_t chatId = Sent["chatUpdReq"].asInteger().get_int(); |         debug_print_json(Sent); | ||||||
|  |         int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int(); | ||||||
|         int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId); |         int64_t my_role_here = get_role_of_user_in_chat(conn, uid, chatId); | ||||||
|         if (my_role_here == user_chat_role_deleted) |         if (my_role_here == user_chat_role_deleted) | ||||||
|             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); |             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); | ||||||
| @ -36,6 +40,7 @@ namespace iu9cawebchat { | |||||||
| 
 | 
 | ||||||
|         json::JSON Recv; |         json::JSON Recv; | ||||||
|         poll_update_chat(conn, Sent, Recv); |         poll_update_chat(conn, Sent, Recv); | ||||||
|  |         debug_print_json(Recv); | ||||||
|         return Recv; |         return Recv; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| #include "server_data_interact.h" | #include "server_data_interact.h" | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| #include <engine_engine_number_9/baza_throw.h> | #include <engine_engine_number_9/baza_throw.h> | ||||||
|  | #include "../debug.h" | ||||||
| 
 | 
 | ||||||
| namespace iu9cawebchat { | namespace iu9cawebchat { | ||||||
|     json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId) { |     json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId) { | ||||||
| @ -102,7 +103,7 @@ namespace iu9cawebchat { | |||||||
|         chatUpdResp["members"].asArray() = poll_update_chat_resp_members(conn, chatId, 0); |         chatUpdResp["members"].asArray() = poll_update_chat_resp_members(conn, chatId, 0); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         json::jarr messages = chatUpdResp["messages"].asArray(); |         json::jarr& messages = chatUpdResp["messages"].asArray(); | ||||||
|         if (selectedMsg >= 0) { |         if (selectedMsg >= 0) { | ||||||
|             RowMessage_Content msg = lookup_message_content(conn, chatId, selectedMsg); |             RowMessage_Content msg = lookup_message_content(conn, chatId, selectedMsg); | ||||||
|             messages.push_back(make_messageSt_obj(msg.id, msg.senderUserId, msg.exists, msg.isSystem, msg.text)); |             messages.push_back(make_messageSt_obj(msg.id, msg.senderUserId, msg.exists, msg.isSystem, msg.text)); | ||||||
| @ -165,7 +166,8 @@ namespace iu9cawebchat { | |||||||
| 
 | 
 | ||||||
|     /* Reznya */ |     /* Reznya */ | ||||||
|     json::JSON internalapi_getMessageNeighbours(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { |     json::JSON internalapi_getMessageNeighbours(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) { | ||||||
|         int64_t chatId = Sent["chatId"].asInteger().get_int(); |         debug_print_json(Sent); | ||||||
|  |         int64_t chatId = Sent["chatUpdReq"]["chatId"].asInteger().get_int(); | ||||||
|         if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted) |         if (get_role_of_user_in_chat(conn, uid, chatId) == user_chat_role_deleted) | ||||||
|             een9_THROW("Authentication failure"); |             een9_THROW("Authentication failure"); | ||||||
|         int64_t lastMsgId = get_lastMsgId_of_chat(conn, chatId); |         int64_t lastMsgId = get_lastMsgId_of_chat(conn, chatId); | ||||||
| @ -192,6 +194,7 @@ namespace iu9cawebchat { | |||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         poll_update_chat_important_segment(conn, Sent, Recv, qBeg, qEnd); |         poll_update_chat_important_segment(conn, Sent, Recv, qBeg, qEnd); | ||||||
|  |         debug_print_json(Recv); | ||||||
|         return Recv; |         return Recv; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -113,8 +113,6 @@ namespace iu9cawebchat { | |||||||
|         int status = sqlite_stmt_step(req, {{0, &senderUserId}, {1, &exists}, {2, &isSystem}}, |         int status = sqlite_stmt_step(req, {{0, &senderUserId}, {1, &exists}, {2, &isSystem}}, | ||||||
|             {{3, &msg_text}}); |             {{3, &msg_text}}); | ||||||
|         if (status == SQLITE_ROW) { |         if (status == SQLITE_ROW) { | ||||||
|             if (!(bool)exists.value) |  | ||||||
|                 een9_THROW("Message existed, but now it does not"); |  | ||||||
|             return {msgId, senderUserId.exist ? senderUserId.value : -1, (bool)exists.value, |             return {msgId, senderUserId.exist ? senderUserId.value : -1, (bool)exists.value, | ||||||
|                 (bool)isSystem.value, msg_text.value}; |                 (bool)isSystem.value, msg_text.value}; | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -25,15 +25,14 @@ namespace iu9cawebchat { | |||||||
|         } |         } | ||||||
|         if (!check_nickname(chat_nickname)) |         if (!check_nickname(chat_nickname)) | ||||||
|             return page_E404(wgd); |             return page_E404(wgd); | ||||||
|         if (path_segs.size() == 2) { |         bool show_chat_members = (path_segs[0] == "chat-members"); | ||||||
|         } else if (path_segs.size() == 4) { |         if (path_segs.size() == 4 && !show_chat_members) { | ||||||
|             if (path_segs[2] != "m") |             if (path_segs[2] != "m") | ||||||
|                 return page_E404(wgd); |                 return page_E404(wgd); | ||||||
|             selected_message_id = std::stoll(path_segs[3]); |             selected_message_id = std::stoll(path_segs[3]); | ||||||
|  |         } else if (path_segs.size() != 2) { | ||||||
|             return page_E404(wgd); |             return page_E404(wgd); | ||||||
|         } else |         } | ||||||
|             return page_E404(wgd); |  | ||||||
|         bool chat_members = (path_segs[0] == "chat-members"); |  | ||||||
| 
 | 
 | ||||||
|         if (userinfo.isNull()) |         if (userinfo.isNull()) | ||||||
|             return een9::form_http_server_response_303("/"); |             return een9::form_http_server_response_303("/"); | ||||||
| @ -55,7 +54,7 @@ namespace iu9cawebchat { | |||||||
|         // -1 means that nothing was selected
 |         // -1 means that nothing was selected
 | ||||||
|         openedchat["selectedMessageId"].asInteger() = json::Integer(selected_message_id); |         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); |         json::JSON initial_chatUpdResp = poll_update_chat_ONE_MSG_resp(*wgd.db, chatInfo.id, selected_message_id); | ||||||
|         if (chat_members) |         if (show_chat_members) | ||||||
|             return http_R200("chat-members", 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}); |         return http_R200("chat", wgd, {&config_presentation, &userinfo, &openedchat, &initial_chatUpdResp}); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										0
									
								
								src/web_chat/iu9_ca_web_chat_lib/debug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/web_chat/iu9_ca_web_chat_lib/debug.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								src/web_chat/iu9_ca_web_chat_lib/debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/web_chat/iu9_ca_web_chat_lib/debug.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #ifndef IU9_CA_WEB_CHAT_LIB_DEBUG_H | ||||||
|  | #define IU9_CA_WEB_CHAT_LIB_DEBUG_H | ||||||
|  | 
 | ||||||
|  | #define debug_print_json(x) printf("%s\n", json::generate_str(x, json::print_pretty).c_str()) | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
| @ -75,6 +75,9 @@ namespace iu9cawebchat { | |||||||
|                                              "`chat_IncHistoryId` INTEGER NOT NULL," |                                              "`chat_IncHistoryId` INTEGER NOT NULL," | ||||||
|                                              "PRIMARY KEY (`chatId`, `id`)" |                                              "PRIMARY KEY (`chatId`, `id`)" | ||||||
|                                              ")"); |                                              ")"); | ||||||
|  |             std::vector<std::string> sus = {"unknown", "undefined", "null", "none", "None", "NaN"}; | ||||||
|  |             for (auto& s: sus) | ||||||
|  |                 reserve_nickname(conn, s); | ||||||
|             add_user(conn, "root", "Rootov Root Rootovich", root_pw, "One admin to rule them all", 0); |             add_user(conn, "root", "Rootov Root Rootovich", root_pw, "One admin to rule them all", 0); | ||||||
|             sqlite_nooutput(conn, "END"); |             sqlite_nooutput(conn, "END"); | ||||||
|         } catch (const std::exception& e) { |         } catch (const std::exception& e) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user