Compare commits
2 Commits
07711a93b0
...
9283590122
Author | SHA1 | Date | |
---|---|---|---|
9283590122 | |||
21a23be96e |
@ -15,16 +15,36 @@
|
||||
let userinfo = {% PUT jsinsert userinfo %};
|
||||
let initial_chatListUpdResp = {% PUT jsinsert initial_chatListUpdResp %};
|
||||
</script>
|
||||
<div id="popup-overlay-veil"></div>
|
||||
<div id="chat-creation-win" class="popup-window">
|
||||
<h1>Input identifying information for your new chat</h1>
|
||||
<h1 class="popup-window-msg">Input identifying information for your new chat</h1>
|
||||
<table class="id-str-input-table">
|
||||
<tr>
|
||||
<td class="id-str-input-td1">
|
||||
<label for="chat-nickname-input">Enter nickname for new chat:</label>
|
||||
</td>
|
||||
<td class="id-str-input-td2">
|
||||
<input name="name" id="chat-nickname-input" type="text" placeholder="Take a nickname" class="one-line-input" required>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="id-str-input-td1">
|
||||
<label for="chat-name-input">Enter name for new chat:</label>
|
||||
</td>
|
||||
<td class="id-str-input-td2">
|
||||
<input name="password" id="chat-name-input" type="text" placeholder="Come up with name" class="one-line-input" required>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h1 class="popup-window-msg">Create new chat?</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-creation-win-yes">Yes, create</button>
|
||||
<button class="popup-window-btn-no" id="chat-creation-win-no">No, cancel</button>
|
||||
</div>
|
||||
|
||||
<div id="chat-renunciation-win" class="popup-window">
|
||||
<!-- header will actually be rewritten before showing the window to include chat nickname -->
|
||||
<h1 id="chat-renunciation-win-title">Are you sure you want to leave chat?</h1>
|
||||
<button class="chat-renunciation-win-yes">Yes, leave</button>
|
||||
<button class="chat-renunciation-win-no">No, cancel</button>
|
||||
<h1 id="chat-renunciation-win-title" class="popup-window-msg">Are you sure you want to leave chat?</h1>
|
||||
<button class="popup-window-btn-yes" id="chat-renunciation-win-yes">Yes, leave</button>
|
||||
<button class="popup-window-btn-no" id="chat-renunciation-win-no">No, cancel</button>
|
||||
</div>
|
||||
|
||||
x
|
||||
@ -45,7 +65,9 @@ x
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/assets/js/common.js"></script>
|
||||
<script src="/assets/js/common-popup.js"></script>
|
||||
<script src="/assets/js/list-rooms.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
{% ENDELDEF %}
|
||||
{% ENDELDEF %}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#popup-overlay-veil {
|
||||
.popup-overlay-veil {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
|
||||
z-index: 99;
|
||||
display: none; /* Hidden by default */
|
||||
@ -27,4 +27,24 @@
|
||||
display: inline;
|
||||
padding: 5px;
|
||||
border-bottom: 3px;
|
||||
}
|
||||
|
||||
.popup-window-btn-yes {
|
||||
background-color: #0c7f0e;
|
||||
border-radius: 5px;
|
||||
padding: 12px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.popup-window-btn-no {
|
||||
background-color: #ff0005;
|
||||
border-radius: 5px;
|
||||
padding: 12px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.popup-window-msg {
|
||||
padding-left: 20px;
|
||||
font-weight: bold;
|
||||
font-size: 1.3em;
|
||||
}
|
@ -3,7 +3,8 @@
|
||||
}
|
||||
|
||||
#CL-bacbe {
|
||||
margin: 6px;
|
||||
margin-top: 6px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.CL-my-chat-box {
|
||||
@ -33,3 +34,22 @@
|
||||
width: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* The morbid thing */
|
||||
table.id-str-input-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse; /* Combine borders */
|
||||
}
|
||||
.id-str-input-td1, .id-str-input-td2 {
|
||||
border: none;
|
||||
}
|
||||
.id-str-input-td1 {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
white-space: nowrap; /* Prevent text wrap, keeping it in one line */
|
||||
overflow: hidden; /* Hide overflow content */
|
||||
text-overflow: ellipsis; /* Show ellipsis for overflowing text */
|
||||
}
|
||||
.id-str-input-td2 {
|
||||
width: 100%;
|
||||
}
|
@ -28,9 +28,6 @@ let members = new Map();
|
||||
for (let memberSt of initial_chatUpdResp.members){
|
||||
members.set(memberSt.id, memberSt);
|
||||
}
|
||||
// members.set(1, {id: 1, name: 'grisha', nickname: 'gri', role: 'admin'});
|
||||
// members.set(2, {id: 2, name: 'Pavlov Vladimir', nickname: 'pv', role: 'regular'});
|
||||
// members.set(3, {id: 3, name: 'Ivan', nickname: 'ivan', role: 'read-only'});
|
||||
|
||||
function updateOffsetOfVisibleMsg(msgId, offset){
|
||||
visibleMessages.get(msgId).style.bottom = String(offset) + "px";
|
||||
@ -180,13 +177,10 @@ function test(id, uid){
|
||||
}
|
||||
|
||||
let mainloopTimeout = null;
|
||||
|
||||
let mainloopPoller = null;
|
||||
|
||||
function setMainloopTimeout(){
|
||||
mainloopTimeout = setTimeout(mainloopPoller, 1000);
|
||||
}
|
||||
|
||||
mainloopPoller = function(){
|
||||
try {
|
||||
console.log("Hello, World!");
|
||||
|
@ -0,0 +1,26 @@
|
||||
let activePopupWinId = "";
|
||||
|
||||
function activatePopupWindow__(el){
|
||||
let veil = document.createElement("div");
|
||||
veil.id = "popup-overlay-veil-OBJ"
|
||||
veil.className = "popup-overlay-veil";
|
||||
veil.style.display = "block";
|
||||
document.body.appendChild(veil);
|
||||
el.style.display = "block";
|
||||
}
|
||||
|
||||
function activatePopupWindowById(id){
|
||||
if (activePopupWinId !== "")
|
||||
return;
|
||||
/* Lmao, this thing is just... SO unsafe */
|
||||
activePopupWinId = id;
|
||||
activatePopupWindow__(document.getElementById(id))
|
||||
}
|
||||
|
||||
function deactivateActivePopup(){
|
||||
if (activePopupWinId === "")
|
||||
return
|
||||
document.getElementById("popup-overlay-veil-OBJ").remove();
|
||||
document.getElementById(activePopupWinId).style.display = "none";
|
||||
activePopupWinId = "";
|
||||
}
|
52
assets/js/common.js
Normal file
52
assets/js/common.js
Normal file
@ -0,0 +1,52 @@
|
||||
async function apiRequest(type, req){
|
||||
let A = await fetch("/api/" + type,
|
||||
{method: 'POST', body: JSON.stringify(req)});
|
||||
let B = await A.json();
|
||||
if (B.status !== 0)
|
||||
throw Error("Server returned non-zero status");
|
||||
return B;
|
||||
}
|
||||
|
||||
/* Framework for pages with mainloop (it can be npt only polling, but also literally anything else */
|
||||
let __mainloopDelayMs = 3000;
|
||||
let mainloopTimeout = null;
|
||||
let mainloopPoller = null;
|
||||
let __guestMainloopPollerAction = null;
|
||||
function setMainloopTimeout(){
|
||||
mainloopTimeout = setTimeout(mainloopPoller, __mainloopDelayMs);
|
||||
}
|
||||
function cancelMainloopTimeout(){
|
||||
clearTimeout(mainloopTimeout);
|
||||
}
|
||||
mainloopPoller = function(){
|
||||
try {
|
||||
console.log("Hello, World!");
|
||||
__guestMainloopPollerAction();
|
||||
} catch (error){
|
||||
console.log(error)
|
||||
}
|
||||
setMainloopTimeout();
|
||||
}
|
||||
|
||||
// 1
|
||||
const userChatRoleAdmin = "admin";
|
||||
// 2
|
||||
const userChatRoleRegular = "regular";
|
||||
// 3
|
||||
const userChatRoleReadOnly = "read-only";
|
||||
// 4
|
||||
const userChatRoleDeleted = "not-a-member";
|
||||
|
||||
function roleToColor(role) {
|
||||
if (role === userChatRoleAdmin) {
|
||||
return "#aafff3";
|
||||
} else if (role === userChatRoleRegular){
|
||||
return "#ffffff";
|
||||
|
||||
} else if (role === userChatRoleReadOnly){
|
||||
return "#bfb2b2";
|
||||
} else if (role === userChatRoleDeleted) {
|
||||
return "#fb4a4a";
|
||||
}
|
||||
return "#286500" // Bug
|
||||
}
|
@ -1,12 +1,35 @@
|
||||
let LocalHistoryId = 0;
|
||||
|
||||
function genSentBase(){
|
||||
return {
|
||||
'chatListUpdReq': {
|
||||
'LocalHistoryId': LocalHistoryId
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let myChats = new Map();
|
||||
let chatBoxes = new Map();
|
||||
|
||||
const roleDeleted = "not-a-member";
|
||||
/* Generate text that is displayed on the right side of chat intro box */
|
||||
function youAreXHere(myRoleHere){
|
||||
return "You are " + myRoleHere + " here";
|
||||
}
|
||||
|
||||
|
||||
let chatRenunciationWinStoredId = -1;
|
||||
|
||||
/* Updating chat html box after myMembershipSt in it was updated */
|
||||
function updateBoxWithNewSt(box, myMembershipSt){
|
||||
let ID = myMembershipSt.chatId;
|
||||
let roleP = box.querySelector(".CL-my-chat-box-my-role");
|
||||
roleP.innerText = youAreXHere(myMembershipSt.myRoleHere);
|
||||
box.style.backgroundColor = roleToColor(myMembershipSt.myRoleHere);
|
||||
}
|
||||
|
||||
function convertStToBox(myMembershipSt){
|
||||
let chatURI = "/user/" + myMembershipSt.chatNickname;
|
||||
let ID = myMembershipSt.chatId;
|
||||
|
||||
let box = document.createElement("div");
|
||||
chatBoxes.set(myMembershipSt.chatId, box);
|
||||
@ -15,10 +38,9 @@ function convertStToBox(myMembershipSt){
|
||||
let inBoxNickname = document.createElement("a");
|
||||
box.appendChild(inBoxNickname);
|
||||
inBoxNickname.className = "entity-nickname-txt CL-my-chat-box-nickname";
|
||||
console.log(myMembershipSt);
|
||||
console.log(myMembershipSt.chatNickname);
|
||||
inBoxNickname.innerText = myMembershipSt.chatNickname;
|
||||
inBoxNickname.href = chatURI;
|
||||
box.style.backgroundColor = roleToColor(myMembershipSt.myRoleHere);
|
||||
|
||||
let inBoxName = document.createElement("a");
|
||||
box.appendChild(inBoxName);
|
||||
@ -29,44 +51,132 @@ function convertStToBox(myMembershipSt){
|
||||
let inBoxMyRoleHere = document.createElement("p");
|
||||
box.appendChild(inBoxMyRoleHere);
|
||||
inBoxMyRoleHere.className = "entity-reg-field-txt CL-my-chat-box-my-role";
|
||||
inBoxMyRoleHere.innerText = "You are " + myMembershipSt.myRoleHere + " here";
|
||||
|
||||
let ID = myMembershipSt.chatId;
|
||||
inBoxMyRoleHere.innerText = youAreXHere(myMembershipSt.myRoleHere);
|
||||
|
||||
let inBoxLeaveBtn = document.createElement("img");
|
||||
box.appendChild(inBoxLeaveBtn);
|
||||
inBoxLeaveBtn.className = "CL-my-chat-box-leave-btn";
|
||||
inBoxLeaveBtn.src = "/assets/img/delete.svg";
|
||||
inBoxLeaveBtn.onclick = function (ev) {
|
||||
if (ev.button === 0){
|
||||
console.log("Tried to leave chat" + ID);
|
||||
}
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
chatRenunciationWinStoredId = ID;
|
||||
activatePopupWindowById("chat-renunciation-win");
|
||||
document.getElementById("chat-renunciation-win-title").innerText =
|
||||
"Do you really want to leave chat " + myMembershipSt.chatNickname + "?";
|
||||
};
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
console.log("Loading complete");
|
||||
LocalHistoryId = initial_chatListUpdResp.HistoryId;
|
||||
|
||||
console.log(initial_chatListUpdResp);
|
||||
function updateLocalStateFromChatListUpdResp(chatListUpdResp){
|
||||
LocalHistoryId = chatListUpdResp.HistoryId;
|
||||
|
||||
let literalChatList = document.getElementById("CL-dblec");
|
||||
|
||||
for (let myMembershipSt of initial_chatListUpdResp.myChats){
|
||||
for (let myMembershipSt of chatListUpdResp.myChats){
|
||||
let chatId = myMembershipSt.chatId;
|
||||
console.log(myMembershipSt);
|
||||
if (myMembershipSt.myRoleHere !== roleDeleted){
|
||||
myChats.set(myMembershipSt.chatId, myMembershipSt);
|
||||
if (myChats.has(chatId)){
|
||||
myChats.set(chatId, myMembershipSt);
|
||||
updateBoxWithNewSt(chatBoxes.get(chatId), myMembershipSt);
|
||||
} else {
|
||||
if (myMembershipSt.myRoleHere === userChatRoleDeleted)
|
||||
continue;
|
||||
myChats.set(chatId, myMembershipSt);
|
||||
let box = convertStToBox(myMembershipSt)
|
||||
chatBoxes.set(myMembershipSt.chatId, box);
|
||||
chatBoxes.set(chatId, box);
|
||||
literalChatList.appendChild(box);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Use it ONLY if `Recv` reported success */
|
||||
function updateLocalStateFromRecv(Recv){
|
||||
updateLocalStateFromChatListUpdResp(Recv.chatListUpdResp);
|
||||
}
|
||||
|
||||
function configureChatCreationInterface(){
|
||||
document.getElementById("chat-creation-win-yes").onclick = function (ev) {
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
let chatNicknameInput = document.getElementById("chat-nickname-input");
|
||||
let chatNameInput = document.getElementById("chat-name-input");
|
||||
let nickname = chatNicknameInput.value;
|
||||
let name = chatNameInput.value;
|
||||
deactivateActivePopup();
|
||||
let Sent = genSentBase();
|
||||
Sent.content = {};
|
||||
Sent.content.nickname = nickname;
|
||||
Sent.content.name = name;
|
||||
apiRequest("createChat", Sent
|
||||
).then((Recv) => {
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
alert("Failed to create chat");
|
||||
console.log(e);
|
||||
});
|
||||
};
|
||||
|
||||
document.getElementById("chat-creation-win-no").onclick = function (ev) {
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
deactivateActivePopup();
|
||||
}
|
||||
|
||||
document.getElementById("CL-bacbe").onclick = function (ev){
|
||||
if (ev.button === 0){
|
||||
|
||||
}
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
let chatNicknameInput = document.getElementById("chat-nickname-input");
|
||||
let chatNameInput = document.getElementById("chat-name-input");
|
||||
chatNicknameInput.value = "";
|
||||
chatNameInput.value = "";
|
||||
activatePopupWindowById("chat-creation-win");
|
||||
console.log("Tried to show chat creation window");
|
||||
};
|
||||
}
|
||||
|
||||
function configureChatRenunciationInterfaceWinPart(){
|
||||
document.getElementById("chat-renunciation-win-yes").onclick = function (ev){
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
deactivateActivePopup();
|
||||
if (chatRenunciationWinStoredId < 0)
|
||||
throw new Error("chatRenunciationWinStoredId < 0");
|
||||
let chatId = chatRenunciationWinStoredId;
|
||||
let Sent = genSentBase();
|
||||
Sent.chatId = chatId;
|
||||
apiRequest("leaveChat", Sent
|
||||
).then((Recv) => {
|
||||
updateLocalStateFromRecv(Recv);
|
||||
}).catch((e) => {
|
||||
alert("Failed to leave chat");
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("chat-renunciation-win-no").onclick = function(ev) {
|
||||
if (ev.button !== 0)
|
||||
return;
|
||||
deactivateActivePopup();
|
||||
}
|
||||
}
|
||||
|
||||
__mainloopDelayMs = 3000;
|
||||
__guestMainloopPollerAction = function(){
|
||||
let Sent = genSentBase();
|
||||
apiRequest("chatListPollEvents", Sent
|
||||
).then((Recv) => {
|
||||
console.log("Got a response");
|
||||
console.log(Recv);
|
||||
updateLocalStateFromRecv(Recv);
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
console.log("Loading complete");
|
||||
updateLocalStateFromChatListUpdResp(initial_chatListUpdResp);
|
||||
configureChatCreationInterface();
|
||||
configureChatRenunciationInterfaceWinPart();
|
||||
mainloopPoller();
|
||||
};
|
||||
|
@ -10,10 +10,13 @@ namespace iu9cawebchat {
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-1l)}});
|
||||
if (is_nickname_taken(conn, new_chat_nickname))
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-2l)}});
|
||||
if (is_nickname_taken(conn, new_chat_nickname))
|
||||
return json::JSON(json::jdict{{"status", json::JSON(-3l)}});
|
||||
reserve_nickname(conn, new_chat_nickname);
|
||||
|
||||
sqlite_nooutput(conn,
|
||||
"INSERT INTO `chat` (`nickname`, `name`, `it_HistoryId`, `lastMsgId`) VALUES (?1, ?2, 0, -1)");
|
||||
"INSERT INTO `chat` (`nickname`, `name`, `it_HistoryId`, `lastMsgId`) VALUES (?1, ?2, 0, -1)",
|
||||
{}, {{1, new_chat_nickname}, {2, new_chat_name}});
|
||||
|
||||
int64_t CHAT_ID = sqlite_trsess_last_insert_rowid(conn);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
namespace iu9cawebchat {
|
||||
json::JSON poll_update_chat_list_resp(SqliteConnection& conn, int64_t userId, int64_t LocalHistoryId) {
|
||||
printf("Userid: %ld\n", userId);
|
||||
json::JSON chatListUpdResp;
|
||||
SqliteStatement my_membership_changes(conn,
|
||||
"SELECT `chatId`, `role` FROM `user_chat_membership` WHERE `userId` = ?1 "
|
||||
@ -32,7 +33,8 @@ namespace iu9cawebchat {
|
||||
void poll_update_chat_list(SqliteConnection& conn, int64_t userId, const json::JSON& Sent, json::JSON& Recv) {
|
||||
Recv["status"].asInteger() = json::Integer(0l);
|
||||
// todo: in libjsonincpp: get rid of Integer
|
||||
poll_update_chat_list_resp(conn, userId, Sent["chatListUpdReq"]["LocalHistoryId"].asInteger().get_int());
|
||||
printf("%s\n", json::generate_str(Sent, json::print_pretty).c_str());
|
||||
Recv["chatListUpdResp"] = poll_update_chat_list_resp(conn, userId, Sent["chatListUpdReq"]["LocalHistoryId"].asInteger().get_int());
|
||||
}
|
||||
|
||||
json::JSON make_messageSt_obj(int64_t id, int64_t senderUserId, bool exists, bool isSystem, const std::string& text) {
|
||||
@ -158,6 +160,7 @@ namespace iu9cawebchat {
|
||||
json::JSON internalapi_chatListPollEvents(SqliteConnection& conn, int64_t uid, const json::JSON& Sent) {
|
||||
json::JSON Recv;
|
||||
poll_update_chat_list(conn, uid, Sent, Recv);
|
||||
printf("%s\n", json::generate_str(Recv, json::print_pretty).c_str());
|
||||
return Recv;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,6 @@ namespace iu9cawebchat {
|
||||
/* All the api calls processing is done in dedicated files.
|
||||
* All functions related to polling are defined in api_pollevents.cpp */
|
||||
|
||||
// todo: move everything to dedicated files
|
||||
int64_t get_current_history_id_of_chat(SqliteConnection& conn, int64_t chatId) {
|
||||
SqliteStatement req(conn, "SELECT `it_HistoryId` FROM `chat` WHERE `id` = ?1", {{1, chatId}}, {});
|
||||
fsql_integer_or_null HistoryId;
|
||||
|
@ -36,8 +36,7 @@ int main(int argc, char** argv){
|
||||
iu9cawebchat::run_website(config);
|
||||
} else
|
||||
een9_THROW("unknown action (known are 'run', 'initialize')");
|
||||
// todo: put back execption after debug
|
||||
} catch (std::bad_weak_ptr& e) {
|
||||
} catch (std::exception& e) {
|
||||
printf("System failure\n%s\n", e.what());
|
||||
}
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user