diff --git a/assets/HypertextPages/chat.nytl.html b/assets/HypertextPages/chat.nytl.html
index 61b8e9b..fb5a2e1 100644
--- a/assets/HypertextPages/chat.nytl.html
+++ b/assets/HypertextPages/chat.nytl.html
@@ -45,8 +45,16 @@
diff --git a/assets/css/chat.css b/assets/css/chat.css
index 3e9990c..448e434 100644
--- a/assets/css/chat.css
+++ b/assets/css/chat.css
@@ -6,46 +6,66 @@ body, html {
position: relative;
flex: 1;
background-color: #f1f1f1;
- color: black;
overflow: hidden;
}
-.message-box-mine {
+.message-supercontainer{
position: absolute;
- right: 5px;
+ width: 100%;
+ left: 0;
+ background-color: rgba(150, 0, 100, 50);
+ /*display: flex;*/
+ /*flex-direction: row;*/
+ /*justify-content: center;*/
+}
+
+.message-box{
+ /*display: inline-block;*/
+ padding: 5px;
+}
+
+.message-box-mine {
+ margin-right: 5px;
+ margin-left: auto;
max-width: 400px;
border: 2px solid #82a173;
padding: 5px;
background-color: #cdff9b;
color: black;
+ /*justify-self: flex-end;*/
}
.message-box-alien {
- position: absolute;
- left: 5px;
+ margin-left: 5px;
+ margin-right: auto;
max-width: 400px;
border: 2px solid dimgrey;
padding: 5px;
background-color: white;
color: black;
+ /*justify-self: flex-start;*/
}
/* 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-deleted .message-box-msg{
+ font-weight: bold;
+}
+
.message-box-system {
- position: absolute;
- left: 15px;
+ margin-left: auto;
+ margin-right: auto;
max-width: 500px;
padding: 4px;
background-color: #2d2d2d;
color: white;
font-weight: bold;
+ justify-self: center;
}
/* in #chat-widget .message-box */
@@ -80,6 +100,7 @@ body, html {
width: 20px;
padding: 2px;
cursor: pointer;
+ display: inline;
}
.message-box-msg{
@@ -110,4 +131,12 @@ body, html {
margin-right: auto;
max-height: 20%;
word-wrap: break-word;
+}
+
+.loading-spinner{
+ margin-left: auto;
+ margin-right: auto;
+ background-color: rgba(0, 0, 0, 0);
+ width: 25px;
+ display: block;
}
\ No newline at end of file
diff --git a/assets/css/debug.css b/assets/css/debug.css
index cb5f5b1..017070f 100644
--- a/assets/css/debug.css
+++ b/assets/css/debug.css
@@ -2,11 +2,7 @@
width: 100%;
position: absolute;
left: 0;
- background-color: rgba(255, 50, 50, 160);
- height: 4px;
+ opacity: 0.3;
+ height: 3px;
z-index: 2;
-}
-
-.chat-debug-rect-top{
- background-color: rgba(148, 0, 211, 160);
}
\ No newline at end of file
diff --git a/assets/gif/loading.gif b/assets/gif/loading.gif
new file mode 100644
index 0000000..05e1f57
Binary files /dev/null and b/assets/gif/loading.gif differ
diff --git a/assets/js/chat.js b/assets/js/chat.js
index 003b223..929764e 100644
--- a/assets/js/chat.js
+++ b/assets/js/chat.js
@@ -3,6 +3,8 @@ let LocalHistoryId = 0;
let members = new Map();
let loadedMessages = new Map(); // messageSt objects
+/*
+container: EL, box: EL, offset: number (msgPres) */
let visibleMessages = new Map(); // HTMLElement objects
let anchoredMsg = -1;
@@ -41,15 +43,37 @@ function genSentBaseGMN(){
return Sent;
}
+function getChatWgSz(){
+ let chatWg = document.getElementById("chat-widget");
+ return [chatWg.offsetWidth, chatWg.offsetHeight];
+}
+
+function elSetOffsetInChat(el, offset){
+ el.style.bottom = String(offset) + "px";
+}
+
+function isMissingPrimaryMsgHeap(){
+ return lastMsgId >= 0 && anchoredMsg < 0;
+}
+
+function isMissingTopMsgHeap(){
+ let [W, H] = getChatWgSz();
+ return anchoredMsg >= 0 && (highestPoint < H + softZoneSz && visibleMsgSegStart > 0);
+}
+
+function isMissingBottomMsgHeap(){
+ return anchoredMsg >= 0 && (lowestPoint > - softZoneSz && visibleMsgSegEnd < lastMsgId);
+}
+
function updateOffsetOfVisibleMsg(msgId, offset){
- visibleMessages.get(msgId).style.bottom = String(offset) + "px";
+ visibleMessages.get(msgId).container.style.bottom = String(offset) + "px";
}
function updateOffsetsUpToTop(){
let offset = offsetOfAnchor;
for (let curMsg = anchoredMsg; curMsg >= visibleMsgSegStart; curMsg--){
updateOffsetOfVisibleMsg(curMsg, offset);
- let height = visibleMessages.get(curMsg).offsetHeight;
+ let height = visibleMessages.get(curMsg).container.offsetHeight;
offset += height + 5;
}
return offset;
@@ -58,7 +82,7 @@ function updateOffsetsUpToTop(){
function updateOffsetsDown(){
let offset = offsetOfAnchor;
for (let curMsg = anchoredMsg + 1; curMsg <= visibleMsgSegEnd; curMsg++){
- let height = visibleMessages.get(curMsg).offsetHeight;
+ let height = visibleMessages.get(curMsg).container.offsetHeight;
offset -= (height + 5);
updateOffsetOfVisibleMsg(curMsg, offset);
}
@@ -72,28 +96,47 @@ function updateOffsetsSane(){
lowestPoint = updateOffsetsDown();
}
+function heightOfPreloadGhost(){
+ let [W, H] = getChatWgSz();
+ return Math.min(H * 0.9, Math.max(H * 0.69, 30));
+}
+
function updateOffsets(){
- if (anchoredMsg < 0)
- return;
- updateOffsetsSane()
- let winTop = document.getElementById("chat-widget").offsetHeight;
- if (lowestPoint > chatPadding || (highestPoint - lowestPoint) <= winTop){
- bumpedAtTheBottom = true;
- anchoredMsg = visibleMsgSegEnd;
- offsetOfAnchor = chatPadding;
- updateOffsetsSane();
- } else if (highestPoint < winTop - chatPadding) {
- console.log("Advancing by " + (winTop - chatPadding - highestPoint))
- offsetOfAnchor += (winTop - chatPadding - highestPoint);
+ let spinnerTop = document.getElementById("top-loading");
+ let spinnerBottom = document.getElementById("bottom-loading");
+ let SbH = spinnerBottom.offsetHeight;
+ if (anchoredMsg < 0){
+ hideHTMLElement(spinnerBottom);
+ elSetOffsetInChat(spinnerTop, chatPadding);
+ setElementVisibility(spinnerTop, isMissingPrimaryMsgHeap());
+ } else {
updateOffsetsSane();
+ let [W, H] = getChatWgSz();
+ let lowestLowestPoint = isMissingBottomMsgHeap() ? lowestPoint - heightOfPreloadGhost(): lowestPoint;
+ let highestHighestPoint = isMissingTopMsgHeap() ? highestPoint + heightOfPreloadGhost() : highestPoint;
+ if (lowestLowestPoint > chatPadding || (highestHighestPoint - lowestLowestPoint) <= H - chatPadding * 2) {
+ bumpedAtTheBottom = true;
+ offsetOfAnchor += (-lowestLowestPoint + chatPadding);
+ updateOffsetsSane();
+ } else if (highestHighestPoint < H - chatPadding) {
+ offsetOfAnchor += (-highestHighestPoint + (H - chatPadding));
+ updateOffsetsSane();
+ }
+ /* Messages weere updated (and only them). They were talking with ghosts.
+ Now we are trying to show spinners of ghosts */
+ elSetOffsetInChat(spinnerTop, highestPoint);
+ setElementVisibility(spinnerTop, isMissingTopMsgHeap());
+ elSetOffsetInChat(spinnerBottom, lowestPoint - SbH);
+ setElementVisibility(spinnerBottom, isMissingBottomMsgHeap());
}
}
function shouldShowDeleteMesgBtn(messageSt){
- return !messageSt.isSystem && messageSt.exists && (
+ return !messageSt.isSystem && messageSt.exists && (messageSt.myRoleHere !== userChatRoleReadOnly) &&(
messageSt.myRoleHere === userChatRoleAdmin || messageSt.senderUserId === userinfo.uid);
}
+// todo: fix messageboxes
function getMsgTypeClassSenderBased(messageSt){
if (messageSt.isSystem)
return "message-box-system"
@@ -106,12 +149,13 @@ 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";
+/* Two things can be updated: messages existance and delete button visibility
+* Supercontainer.container is persistent, Supercontainer.box can change it's class */
+function updateMessageSupercontainer(supercontainer, messageSt){
+ let box = supercontainer.box;
+ setElementVisibility(box.querySelector(".message-box-button-delete"), shouldShowDeleteMesgBtn(messageSt), "inline");
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
+ // Notice, that no check of previous state is performed. Double loading is a rare event, I can afford to be slow
if (!messageSt.exists)
box.querySelector(".message-box-msg").innerText = msgErased;
}
@@ -136,8 +180,12 @@ function decodeSystemMessage(text){
return "... Bad log ...";
}
-function convertMessageStToBox(messageSt){
+function convertMessageStToSupercontainer(messageSt){
+ let container = document.createElement("div");
+ container.className = "message-supercontainer";
+
let box = document.createElement("div");
+ container.appendChild(box);
box.className = getMsgFullTypeClassName(messageSt);
let ID = messageSt.id;
@@ -178,6 +226,7 @@ function convertMessageStToBox(messageSt){
storeHiddenMsgIdForDeletionWin = ID;
activatePopupWindowById("msg-deletion-win");
};
+ setElementVisibility(inTopPartButtonDelete, shouldShowDeleteMesgBtn(messageSt), "inline");
let inTopPartButtonGetLink = document.createElement("img");
topPart.appendChild(inTopPartButtonGetLink);
@@ -202,14 +251,15 @@ function convertMessageStToBox(messageSt){
msgPart.innerText = messageSt.text;
} else
msgPart.innerText = msgErased;
- return box;
+
+ return {'container': container, 'box': box, 'offset': 0};
}
function makeVisible(msgId){
- let box = convertMessageStToBox(loadedMessages.get(msgId));
+ let supercontainer = convertMessageStToSupercontainer(loadedMessages.get(msgId));
const chatWin = document.getElementById("chat-widget");
- chatWin.appendChild(box);
- visibleMessages.set(msgId, box);
+ chatWin.appendChild(supercontainer.container);
+ visibleMessages.set(msgId, supercontainer);
}
function opaNewMessageSt(messageSt){
@@ -217,7 +267,7 @@ function opaNewMessageSt(messageSt){
if (loadedMessages.has(msgId)){
loadedMessages.set(msgId, messageSt);
if (visibleMessages.has(msgId)){
- updateMessageBox(msgId, visibleMessages.get(msgId), messageSt);
+ updateMessageSupercontainer(visibleMessages.get(msgId), messageSt);
}
} else {
loadedMessages.set(msgId, messageSt);
@@ -249,15 +299,16 @@ function canISendMessages(){
}
function updateLocalStateFromChatUpdRespBlind(chatUpdResp){
+ console.log(anchoredMsg, offsetOfAnchor, 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);
+ for (let [msgId, sc] of visibleMessages){
+ updateMessageSupercontainer(sc, loadedMessages.get(msgId));
}
- document.getElementById("message-input").style.display = (canISendMessages() ? "block" : "none");
+ setElementVisibility(document.getElementById("message-input"), canISendMessages());
}
}
for (let memberSt of chatUpdResp.members){
@@ -284,31 +335,16 @@ async function requestMessageNeighbours(fromMsg, direction){
}
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;
+ return isMissingPrimaryMsgHeap() || isMissingTopMsgHeap() || isMissingBottomMsgHeap();
}
-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){
+async function tryLoadWhitespaceSingle(){
+ console.log('tryLoadWhitespaceSingle');
+ if (isMissingPrimaryMsgHeap()){
+ await requestMessageNeighbours(-1, "backward");
+ } else if (isMissingTopMsgHeap()){
await requestMessageNeighbours(visibleMsgSegStart, "backward");
- } else if (lowestPoint > 0 - softZoneSz && visibleMsgSegEnd < lastMsgId){
+ } else if (isMissingBottomMsgHeap()){
await requestMessageNeighbours(visibleMsgSegEnd, "forward");
}
}
@@ -317,10 +353,8 @@ async function loadWhitespaceMultitry(){
if (needToLoadWhitespace()){
cancelMainloopTimeout();
do {
- console.trace();
- console.log("Normalnie ludi ne spyat");
try {
- await tryLoadWhitespace();
+ await tryLoadWhitespaceSingle();
await sleep(100);
} catch (e) {
console.error(e);
@@ -368,7 +402,7 @@ async function UPDATE(){
let Recv = await apiRequest("chatPollEvents", genSentBase());
await updateLocalStateFromRecv(Recv);
}
-// __guestMainloopPollerAction = UPDATE();
+__guestMainloopPollerAction = UPDATE;
window.onload = function (){
console.log("Page was loaded");
@@ -397,8 +431,10 @@ window.onload = function (){
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";
+ elSetOffsetInChat(document.getElementById("debug-line-lowest"), -softZoneSz);
+ elSetOffsetInChat(document.getElementById("debug-line-highest"), H + softZoneSz);
+ elSetOffsetInChat(document.getElementById("debug-line-top-padding"), H - chatPadding);
+ elSetOffsetInChat(document.getElementById("debug-line-bottom-padding"), chatPadding)
};
window.addEventListener("resize", chatWgDebugLinesFnc);
chatWgDebugLinesFnc();
diff --git a/assets/js/common.js b/assets/js/common.js
index ea33eed..3b48ded 100644
--- a/assets/js/common.js
+++ b/assets/js/common.js
@@ -59,3 +59,15 @@ function roleToColor(role) {
// todo: replace it with translation
const msgErased = "[ ERASED ]";
+
+function hideHTMLElement(el){
+ el.style.display = "none";
+}
+
+function showHTMLElement(el){
+ el.style.display = "block";
+}
+
+function setElementVisibility(el, isVisible, howVisible = "block"){
+ el.style.display = isVisible ? howVisible : "none";
+}
\ No newline at end of file
diff --git a/src/web_chat/iu9_ca_web_chat_lib/run.cpp b/src/web_chat/iu9_ca_web_chat_lib/run.cpp
index ad05db5..2fe2b29 100644
--- a/src/web_chat/iu9_ca_web_chat_lib/run.cpp
+++ b/src/web_chat/iu9_ca_web_chat_lib/run.cpp
@@ -41,6 +41,7 @@ namespace iu9cawebchat {
samI.update({
een9::StaticAssetManagerRule{assets_dir + "/css", "/assets/css", {{".css", "text/css"}} },
een9::StaticAssetManagerRule{assets_dir + "/js", "/assets/js", {{".js", "text/javascript"}} },
+ een9::StaticAssetManagerRule{assets_dir + "/gif", "/assets/gif", {{".gif", "image/gif"}} },
een9::StaticAssetManagerRule{assets_dir + "/img", "/assets/img", {
{".jpg", "image/jpg"}, {".png", "image/png"}, {".svg", "image/svg+xml"}
} },