master #6
| @ -17,8 +17,8 @@ | ||||
|         <h1 class="popup-window-msg">Nickname for summoned user</h1> | ||||
|         <input class="one-line-input" id="summoned-user-nickname"> | ||||
|         <input type="checkbox" id="summoned-user-is-read-only"> | ||||
|         <label>Make read only</label> | ||||
|         <button class="popup-window-btn-yes" id="user-summoning-yes">Summon</button> | ||||
|         <label>Make read only</label><br> | ||||
|         <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> | ||||
|     </div> | ||||
| 
 | ||||
| @ -29,7 +29,7 @@ | ||||
|         <button class="popup-window-btn-no" id="user-deletion-no">No, cancel</button> | ||||
|     </div> | ||||
| 
 | ||||
|     <div id="document-container"> | ||||
|     <div class="document-container resp-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"> | ||||
|  | ||||
| @ -14,32 +14,47 @@ | ||||
|     <meta charset="UTF-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <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-popup.css"> | ||||
|     <link rel="stylesheet" href="/assets/css/chat.css"> | ||||
|     <title>Chat </title> | ||||
|     <title>Chat</title> | ||||
| </head> | ||||
| <body> | ||||
| <!-- todo: 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> | ||||
|     {% PUT chat.pass pres userinfo openedchat initial_chatUpdResp %} | ||||
| 
 | ||||
|     <div id="msg-deletion-win" class="popup-window"> | ||||
|         <h1 class="popup-window-msg">Are you sure you want to delete this message?</h1> | ||||
|         <!-- message preview will be actually rewritten before each window activation--> | ||||
|         <p class="message-in-popup-preview" id="win-deletion-msg-preview">Lorem ipsum dolor</p> | ||||
|         <button class="popup-window-btn-yes" id="msg-deletion-yes">Yes, delete</button> | ||||
|         <button class="popup-window-btn-no" id="msg-deletion-no">No, cancel</button> | ||||
|     </div> | ||||
|     <div id="chat-widget"></div> | ||||
|     <div class="panel" id="input-panel"> | ||||
|         <div contentEditable id="message-input" class="panel-thing"></div> | ||||
| 
 | ||||
|     <div class="fullscreen-container resp-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 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> | ||||
|     <script src="/assets/js/chat.js"></script> | ||||
| </div> | ||||
| </body> | ||||
| </html> | ||||
| {% ENDELDEF %} | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
|     <div id="document-container"> | ||||
|     <div class="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"> | ||||
| @ -35,7 +35,7 @@ | ||||
|             </p> | ||||
|         </div> | ||||
| 
 | ||||
|         <div class="profile-container"> | ||||
|         <div class="profile-container resp-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"> | ||||
|  | ||||
| @ -49,7 +49,7 @@ | ||||
|     </div> | ||||
| 
 | ||||
| x | ||||
|     <div id="document-container"> | ||||
|     <div class="document-container resp-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"> | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| </head> | ||||
| <body> | ||||
| 
 | ||||
|     <div id="document-container"> | ||||
|     <div class="document-container resp-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"> | ||||
|  | ||||
| @ -10,16 +10,44 @@ body, html { | ||||
|     overflow: hidden; | ||||
| } | ||||
| 
 | ||||
| #chat-widget .message-box { | ||||
| .message-box-mine { | ||||
|     position: absolute; | ||||
|     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; | ||||
|     padding: 5px; | ||||
|     background-color: white; | ||||
|     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 */ | ||||
| .message-box-top{ | ||||
|     /* 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{ | ||||
|     font-weight: bold; | ||||
|     color: black; | ||||
|     text-decoration: none; | ||||
|     padding: 2px; | ||||
|     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{ | ||||
| @ -51,7 +86,11 @@ body, html { | ||||
|     word-wrap: break-word; | ||||
| } | ||||
| 
 | ||||
| #input-panel #message-input{ | ||||
| #input-panel { | ||||
|     min-height: 20px; | ||||
| } | ||||
| 
 | ||||
| #message-input { | ||||
|     padding: 15px; | ||||
|     height: auto; | ||||
|     width: 100%; | ||||
| @ -62,3 +101,13 @@ body, html { | ||||
|     font-size: .9rem; | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| #document-container { | ||||
| .document-container { | ||||
|     width: 80%; /* Full width of the viewport */ | ||||
|     margin: 0 auto; /* Center the container horizontally */ | ||||
| } | ||||
| 
 | ||||
| #fullscreen-container { | ||||
| .fullscreen-container { | ||||
|     width: 80%; /* Full width of the viewport */ | ||||
|     height: 100vh; /* Full height of the viewport */ | ||||
|     display: flex; | ||||
| @ -67,6 +67,18 @@ | ||||
|     margin: 0 auto; /* Center the container horizontally */ | ||||
| } | ||||
| 
 | ||||
| @media (orientation: landscape) { | ||||
|     .resp-container{ | ||||
|         width: 80%; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| @media (orientation: portrait){ | ||||
|     .resp-container{ | ||||
|         width: 100%; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|     background-color: #f000f0; | ||||
|     background-image: url("/assets/img/clavicle-transparent.png"), url("/assets/img/broken-clavicle.png"); | ||||
|  | ||||
							
								
								
									
										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)
 | ||||
|     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
 | ||||
|     // let haveToUpdateAllBoxes = false;
 | ||||
|     for (let memberSt of chatUpdResp.members){ | ||||
|         console.log([memberSt, userinfo.uid, myRoleHere]); | ||||
|         if (memberSt.userId === userinfo.uid && myRoleHere !== memberSt.roleHere){ | ||||
|             myRoleHere = memberSt.roleHere; | ||||
|             // haveToUpdateAllBoxes = true;
 | ||||
|             for (let [id, memberSt] of members){ | ||||
|                 let box = memberBoxes.get(id); | ||||
|                 updateBoxWithSt(box, memberSt); | ||||
| @ -115,7 +113,7 @@ function configureSummonUserInterface(){ | ||||
|     document.getElementById("user-summoning-yes").onclick = function(ev ){ | ||||
|         if (ev.button !==0) | ||||
|             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; | ||||
|         deactivateActivePopup(); | ||||
|         let Sent = genSentBase(); | ||||
| @ -174,8 +172,7 @@ function configureKickUserInterfaceWinPart(){ | ||||
| __mainloopDelayMS = 5000; | ||||
| __guestMainloopPollerAction = function (){ | ||||
|     console.log("Hello, world"); | ||||
|     let Sent = genSentBase(); | ||||
|     apiRequest("chatPollEvents", Sent). | ||||
|     apiRequest("chatPollEvents", genSentBase()). | ||||
|     then((Recv) => { | ||||
|         console.log(Recv); | ||||
|         updateLocalStateFromRecv(Recv); | ||||
|  | ||||
| @ -1,17 +1,6 @@ | ||||
| // 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 LocalHistoryId = 0; | ||||
| 
 | ||||
| let members = new Map(); | ||||
| 
 | ||||
| let loadedMessages = new Map();  // messageSt objects
 | ||||
| let visibleMessages = new Map();  // HTMLElement objects
 | ||||
| @ -19,14 +8,37 @@ let visibleMessages = new Map();  // HTMLElement objects | ||||
| let anchoredMsg = -1; | ||||
| let visibleMsgSegStart = -1; | ||||
| 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/<>`
 | ||||
| let bumpedAtTheBottom = false; | ||||
| 
 | ||||
| let members = new Map(); | ||||
| for (let memberSt of initial_chatUpdResp.members){ | ||||
|     members.set(memberSt.id, memberSt); | ||||
| // Hidden variable. When deletion window popup is active
 | ||||
| // Persists from popup activation until popup deactivation
 | ||||
| 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){ | ||||
| @ -54,59 +66,117 @@ function updateOffsetsDown(){ | ||||
| } | ||||
| 
 | ||||
| function updateOffsetsSane(){ | ||||
|     let highest_point = updateOffsetsUpToTop(); | ||||
|     let lowest_point = updateOffsetsDown(); | ||||
|     return [highest_point, lowest_point]; | ||||
|     if (anchoredMsg < 0) | ||||
|         return; | ||||
|     highestPoint = updateOffsetsUpToTop(); | ||||
|     lowestPoint = updateOffsetsDown(); | ||||
| } | ||||
| 
 | ||||
| function updateOffsets(){ | ||||
|     if (anchoredMsg < 0) | ||||
|         return; | ||||
|     let [highest_point, lowest_point] = updateOffsetsSane(); | ||||
|     updateOffsetsSane() | ||||
|     let winTop = document.getElementById("chat-widget").offsetHeight; | ||||
|     if (lowest_point > 5 || (highest_point - lowest_point) <= winTop){ | ||||
|     if (lowestPoint > chatPadding || (highestPoint - lowestPoint) <= winTop){ | ||||
|         bumpedAtTheBottom = true; | ||||
|         anchoredMsg = visibleMsgSegEnd; | ||||
|         offsetOfAnchor = 5; | ||||
|         offsetOfAnchor = chatPadding; | ||||
|         updateOffsetsSane(); | ||||
|     } else if (highest_point < winTop - 5){ | ||||
|         console.log("Adancing by " + (winTop - 5 - highest_point)) | ||||
|         offsetOfAnchor += (winTop - 5 - highest_point); | ||||
|     } else if (highestPoint < winTop - chatPadding) { | ||||
|         console.log("Advancing by " + (winTop - chatPadding - highestPoint)) | ||||
|         offsetOfAnchor += (winTop - chatPadding - highestPoint); | ||||
|         updateOffsetsSane(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function makeMessageBox(messageSt){ | ||||
|     if (!messageSt.exists || messageSt.isSystem) | ||||
|         throw new Error("Not ready for this"); | ||||
|     const parentDiv = document.getElementById("chat-widget"); | ||||
| function shouldShowDeleteMesgBtn(messageSt){ | ||||
|     return !messageSt.isSystem && messageSt.exists && ( | ||||
|         messageSt.myRoleHere === userChatRoleAdmin || messageSt.senderUserId === userinfo.uid); | ||||
| } | ||||
| 
 | ||||
| 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"); | ||||
|     parentDiv.appendChild(box); | ||||
|     box.className = "message-box"; | ||||
|     box.className = getMsgFullTypeClassName(messageSt); | ||||
| 
 | ||||
|     let ID = messageSt.id; | ||||
| 
 | ||||
|     let topPart = document.createElement("div"); | ||||
|     box.appendChild(topPart); | ||||
|     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"); | ||||
|     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; | ||||
|     inTopPartSenderName.innerText = senderMemberSt.name; | ||||
|     inTopPartSenderName.href = senderProfileURI; | ||||
| 
 | ||||
|     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"); | ||||
|     topPart.appendChild(inTopPartButtonDelete); | ||||
|     inTopPartButtonDelete.className = "message-box-button"; | ||||
|     inTopPartButtonDelete.className = "message-box-button message-box-button-delete"; | ||||
|     inTopPartButtonDelete.src = "/assets/img/delete.svg"; | ||||
|     inTopPartButtonDelete.onclick = (ev) => { | ||||
|         if (ev.button === 0){ | ||||
|             console.log("Tried to delete message " + ID); | ||||
|         } | ||||
|         if (ev.button !== 0) | ||||
|             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"); | ||||
| @ -114,34 +184,41 @@ function makeMessageBox(messageSt){ | ||||
|     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); | ||||
|         } | ||||
|         if (ev.button !== 0) | ||||
|             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"); | ||||
|     box.appendChild(msgPart); | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| 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 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();
 | ||||
|         // }
 | ||||
|         loadedMessages.set(msgId, messageSt); | ||||
|         if (visibleMessages.has(msgId)){ | ||||
|             updateMessageBox(msgId, visibleMessages.get(msgId), messageSt); | ||||
|         } | ||||
|     } else { | ||||
|         loadedMessages.set(msgId, messageSt); | ||||
|         if (anchoredMsg < 0){ | ||||
| @ -149,7 +226,6 @@ function opaNewMessage(messageSt){ | ||||
|             visibleMsgSegStart = msgId; | ||||
|             visibleMsgSegEnd = msgId; | ||||
|             makeVisible(msgId); | ||||
|             updateOffsets(); | ||||
|         } else if (msgId + 1 === visibleMsgSegStart) { | ||||
|             visibleMsgSegStart--; | ||||
|             makeVisible(msgId); | ||||
| @ -157,7 +233,6 @@ function opaNewMessage(messageSt){ | ||||
|                 visibleMsgSegStart--; | ||||
|                 makeVisible(visibleMsgSegStart); | ||||
|             } | ||||
|             updateOffsets(); | ||||
|         } else if (msgId - 1 === visibleMsgSegEnd){ | ||||
|             visibleMsgSegEnd++; | ||||
|             makeVisible(msgId); | ||||
| @ -165,57 +240,174 @@ function opaNewMessage(messageSt){ | ||||
|                 visibleMsgSegEnd++; | ||||
|                 makeVisible(visibleMsgSegEnd); | ||||
|             } | ||||
|             updateOffsets(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| function test(id, uid){ | ||||
|     opaNewMessage({ | ||||
|         id: id, text: "Message number " + String(id), senderUserId: uid, exists: true, isSystem: false} | ||||
|     ); | ||||
| function canISendMessages(){ | ||||
|     return myRoleHere === userChatRoleRegular || myRoleHere === userChatRoleAdmin; | ||||
| } | ||||
| 
 | ||||
| let mainloopTimeout = null; | ||||
| let mainloopPoller = null; | ||||
| function setMainloopTimeout(){ | ||||
|     mainloopTimeout = setTimeout(mainloopPoller, 1000); | ||||
| function updateLocalStateFromChatUpdRespBlind(chatUpdResp){ | ||||
|     LocalHistoryId = chatUpdResp.HistoryId; | ||||
|     for (let memberSt of chatUpdResp.members){ | ||||
|         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 { | ||||
|         console.log("Hello, World!"); | ||||
|     } catch (error){} | ||||
|     setMainloopTimeout(); | ||||
|         let Recv = await apiRequest(type, Sent) | ||||
|         await updateLocalStateFromRecv(Recv); | ||||
|     } 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 (){ | ||||
|     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(); | ||||
|     console.log("Page was loaded"); | ||||
| 
 | ||||
|     document.body.addEventListener("wheel", function (event) { | ||||
|         // event.preventDefault();
 | ||||
|         bumpedAtTheBottom = false; | ||||
|         console.log("Scroll of " + String(event.deltaY)); | ||||
|         offsetOfAnchor += event.deltaY / 5; | ||||
|         offsetOfAnchor += event.deltaY / 3; | ||||
|         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'){ | ||||
|             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){ | ||||
|     let A = await fetch("/api/" + type, | ||||
|         {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 */ | ||||
| let __mainloopDelayMs = 3000; | ||||
| let mainloopTimeout = null; | ||||
| let mainloopPoller = null; | ||||
| let __guestMainloopPollerAction = null; | ||||
| function setMainloopTimeout(){ | ||||
|     mainloopTimeout = setTimeout(mainloopPoller, __mainloopDelayMs); | ||||
| } | ||||
| function cancelMainloopTimeout(){ | ||||
|     clearTimeout(mainloopTimeout); | ||||
|     mainloopTimeout = null; | ||||
| } | ||||
| mainloopPoller = function(){ | ||||
| function mainloopPoller(){ | ||||
|     try { | ||||
|         console.log("Hello, World!"); | ||||
|         __guestMainloopPollerAction(); | ||||
|         if (__guestMainloopPollerAction) | ||||
|             __guestMainloopPollerAction(); | ||||
|     } catch (error){ | ||||
|         console.log(error) | ||||
|     } | ||||
| @ -50,3 +56,6 @@ function roleToColor(role) { | ||||
|     } | ||||
|     return "#286500"  // Bug
 | ||||
| } | ||||
| 
 | ||||
| // todo: replace it with translation
 | ||||
| const msgErased = "[ ERASED ]"; | ||||
|  | ||||
| @ -108,8 +108,8 @@ function configureChatCreationInterface(){ | ||||
|             return; | ||||
|         let chatNicknameInput = document.getElementById("chat-nickname-input"); | ||||
|         let chatNameInput = document.getElementById("chat-name-input"); | ||||
|         let nickname = chatNicknameInput.value; | ||||
|         let name = chatNameInput.value; | ||||
|         let nickname = String(chatNicknameInput.value); | ||||
|         let name = String(chatNameInput.value); | ||||
|         deactivateActivePopup(); | ||||
|         let Sent = genSentBase(); | ||||
|         Sent.content = {}; | ||||
|  | ||||
| @ -1,9 +1,11 @@ | ||||
| #include "server_data_interact.h" | ||||
| #include <engine_engine_number_9/baza_throw.h> | ||||
| #include "../debug.h" | ||||
| 
 | ||||
| namespace iu9cawebchat { | ||||
|     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); | ||||
|         if (my_role_here == user_chat_role_deleted) | ||||
|             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "server_data_interact.h" | ||||
| #include <engine_engine_number_9/baza_throw.h> | ||||
| #include "../str_fields.h" | ||||
| #include "../debug.h" | ||||
| 
 | ||||
| namespace iu9cawebchat { | ||||
|     /* No authorization check is performed
 | ||||
| @ -13,16 +14,19 @@ namespace iu9cawebchat { | ||||
|         int64_t chat_lastMsgId = get_lastMsgId_of_chat(conn, chatId); | ||||
|         SqliteStatement req(conn, | ||||
|             "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}}); | ||||
|         if (!isSystem) | ||||
|             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", | ||||
|             {{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) { | ||||
|         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); | ||||
|         if (my_role_here == user_chat_role_deleted) | ||||
|             een9_THROW("Unauthorized user tries to access internalapi_getChatInfo"); | ||||
| @ -36,6 +40,7 @@ namespace iu9cawebchat { | ||||
| 
 | ||||
|         json::JSON Recv; | ||||
|         poll_update_chat(conn, Sent, Recv); | ||||
|         debug_print_json(Recv); | ||||
|         return Recv; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "server_data_interact.h" | ||||
| #include <assert.h> | ||||
| #include <engine_engine_number_9/baza_throw.h> | ||||
| #include "../debug.h" | ||||
| 
 | ||||
| namespace iu9cawebchat { | ||||
|     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); | ||||
| 
 | ||||
| 
 | ||||
|         json::jarr messages = chatUpdResp["messages"].asArray(); | ||||
|         json::jarr& messages = chatUpdResp["messages"].asArray(); | ||||
|         if (selectedMsg >= 0) { | ||||
|             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)); | ||||
| @ -165,7 +166,8 @@ namespace iu9cawebchat { | ||||
| 
 | ||||
|     /* Reznya */ | ||||
|     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) | ||||
|             een9_THROW("Authentication failure"); | ||||
|         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); | ||||
|         debug_print_json(Recv); | ||||
|         return Recv; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -113,8 +113,6 @@ namespace iu9cawebchat { | ||||
|         int status = sqlite_stmt_step(req, {{0, &senderUserId}, {1, &exists}, {2, &isSystem}}, | ||||
|             {{3, &msg_text}}); | ||||
|         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, | ||||
|                 (bool)isSystem.value, msg_text.value}; | ||||
|         } | ||||
|  | ||||
| @ -25,15 +25,14 @@ namespace iu9cawebchat { | ||||
|         } | ||||
|         if (!check_nickname(chat_nickname)) | ||||
|             return page_E404(wgd); | ||||
|         if (path_segs.size() == 2) { | ||||
|         } else if (path_segs.size() == 4) { | ||||
|         bool show_chat_members = (path_segs[0] == "chat-members"); | ||||
|         if (path_segs.size() == 4 && !show_chat_members) { | ||||
|             if (path_segs[2] != "m") | ||||
|                 return page_E404(wgd); | ||||
|             selected_message_id = std::stoll(path_segs[3]); | ||||
|         } else if (path_segs.size() != 2) { | ||||
|             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("/"); | ||||
| @ -55,7 +54,7 @@ namespace iu9cawebchat { | ||||
|         // -1 means that nothing was selected
 | ||||
|         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) | ||||
|         if (show_chat_members) | ||||
|             return http_R200("chat-members", 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," | ||||
|                                              "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); | ||||
|             sqlite_nooutput(conn, "END"); | ||||
|         } catch (const std::exception& e) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user