diff options
author | Anton L. Šijanec <sijanecantonluka@gmail.com> | 2020-04-05 20:23:30 +0200 |
---|---|---|
committer | Anton L. Šijanec <sijanecantonluka@gmail.com> | 2020-04-05 20:23:30 +0200 |
commit | 3fd55d3389e5d1d496a62bbb7ee95234c304ca8e (patch) | |
tree | 2cd45b711b6f7c12291bf6eff6afb042494dacc0 /js/chats.js | |
parent | teachers.js, absences.js: uporabljajo gsec.js; gsec.js: spremembe apija (diff) | |
download | beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar.gz beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar.bz2 beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar.lz beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar.xz beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.tar.zst beziapp-3fd55d3389e5d1d496a62bbb7ee95234c304ca8e.zip |
Diffstat (limited to 'js/chats.js')
-rw-r--r-- | js/chats.js | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/js/chats.js b/js/chats.js new file mode 100644 index 0000000..73dc791 --- /dev/null +++ b/js/chats.js @@ -0,0 +1,373 @@ +const API_ENDPOINT = "https://gimb.tk/test.php"; +const DIRECTORY_URL = "/directory.json"; +// "Global" object for name directory +var directory = null; +var currentlyChattingWith = null; // msgid +var sogovornik = null; // name +var firstPageOfMessages = null; // so we can test if new messages ever arrive + +async function checkLogin() { + localforage.getItem("logged_in").then(function (value) { + // This code runs once the value has been loaded + // from the offline store. + if (value !== true) { + window.location.replace("/index.html"); + } + }).catch(function (err) { + // This code runs if there were any errors + console.log(err); + }); +} +function getKeyByValue(object, value) { + return Object.keys(object).find(key => object[key] === value); +} +// -----------HTML HELPERS----------- +function htmlEncode(value) { + // Create a in-memory element, set its inner text (which is automatically encoded) + // Then grab the encoded contents back out. The element never exists on the DOM. + return $("<textarea/>").text(value).html(); +} + +function htmlDecode(value) { + return $("<textarea/>").html(value).text(); +} +// --------------------------------- + +// Try to fetch name:id directory +function loadDirectory() { + $.ajax({ + url: DIRECTORY_URL, + crossDomain: true, + + dataType: "json", + cache: false, + type: "GET", + + success: (data) => { + // If we were able to retrieve it, update the saved directory + localforage.setItem("directory", data); + directory = data; + // Populate autocomplete + populateAutocomplete(); + }, + + error: () => { + // Otherwise, try to retrieve stored directory + localforage.getItem("directory").then((stored_directory) => { + if (stored_directory === null) { + // If unable, set directory to null (so other functions know that we don't have it) + UIAlert( D("nameDirectoryNotSet"), "loadDirectory(): stored_directory === null" ); + directory = null; + // Disable send button + document.getElementById("msg-send").disabled = true; + } else { + directory = stored_directory; + // Populate autocomplete + populateAutocomplete(); + } + }); + } + }); +} + +function populateAutocomplete() { + let elems = document.querySelectorAll('.autocomplete-fullname'); + // če se uporablja globalna var directory, ki je shranjena kot objekt (vedno shranjen kot reference), bo pri let x=y x le pointer na object y + // in se bo spremenil z spremembo "originala". spodnja stvar itak ni preveč efficent, loop čez vseh 7000 ljudi bi lahko delal težave... + // kakšen Object.keys bi bila boljša varianta ampak raje napišem tale komentar... idk, to se mi je zdelo uporabno ampak sedaj obžalujem + // samo guglal sem "copying an object js" + let autocomplete_entries = Object.assign({}, directory); + for (let variableKey in autocomplete_entries) { + autocomplete_entries[variableKey] = null; + } + M.Autocomplete.init(elems, { + data: autocomplete_entries, + onAutocomplete: validateName, + minLength: 0 + }); + if(window.location.hash.length > 1) { + document.getElementById("full-name").value = decodeURIComponent(window.location.hash.substring(1)); + } else { + document.getElementById("full-name").value = getUrlParameter("m"); + } + M.updateTextFields(); + validateName(); +} + +// Function to toggle loading bar +function setLoading(state) { + if (state) { + $("#loading-bar").removeClass("hidden"); + } else { + $("#loading-bar").addClass("hidden"); + } +} +async function sendMessage(recipient_number = null, body = null) { + if(recipient_number == null || recipient_number == undefined) { + recipient_number = directory[sogovornik]; + } + if(body == null || body == undefined) { + body = document.getElementById("msg-body").value; + } + if(body.length > 180) { + throw new RangeError("sendMessage(): message is longer than 180 characters."); + } + let promises_to_run = [ + localforage.getItem("username").then((value) => { + username = value; + }), + localforage.getItem("password").then((value) => { + password = value; + }), + ]; + setLoading(true); + Promise.all(promises_to_run).then(() => { + try { + let gsecInstance = new gsec(); + gsecInstance.login(username, password).then( () => { + gsecInstance.sendMessage(recipient_number, "beziapp-ctlmsg-chat-"+body, "BežiApp chat: "+body).then( (value) => { + addMessage(0, body); + setLoading(false); + }).catch( (err) => { + gsecErrorHandlerUI(err); + setLoading(false); + }); + }); + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } + }); +} +function addMessage(whom, body, datePlacement = 0, messageDate = null) { // datePlacement: 0=append bubble to end, 1=append bubble to start. + if(whom == 0) { + var whos = "mine"; + } else { + var whos = "yours"; + } + var timestamp = Date.now(); + if(messageDate instanceof Date) { timestamp = messageDate.getTime(); } + if(typeof messageDate == "number") { timestamp = messageDate; } + var chatarea = document.getElementsByClassName("chat")[0]; + var alreadyMessages = chatarea.querySelectorAll(".message"); + var textnode = document.createTextNode(body); + var bubblenode = document.createElement("div"); + bubblenode.setAttribute("data-date", timestamp); + bubblenode.appendChild(textnode); + if(chatarea.childElementCount == 0) { + bubblenode.className = "message last"; + var messagesnest = document.createElement("div"); + var istaoseba = false; + } else { + if(datePlacement == 0 || timestamp > Number(alreadyMessages[alreadyMessages.length - 1].getAttribute("data-date"))) { + datePlacement = 0; + console.log(alreadyMessages[0].getAttribute("data-date")); + bubblenode.className = "message last"; + if(chatarea.children.item(chatarea.children.length - 1).classList.contains(whos)) { // ista oseba + var istaoseba = true; + var messagesnest = chatarea.children.item(chatarea.children.length - 1); + messagesnest.children.item(messagesnest.children.length - 1).classList.remove("last"); + } else { + var istaoseba = false; + var messagesnest = document.createElement("div"); + } + } else if (datePlacement == 1 || timestamp < Number(alreadyMessages[0].getAttribute("data-date"))) { + datePlacement = 1; + console.log(alreadyMessages[0].getAttribute("data-date")); + if(chatarea.children.item(0).classList.contains(whos)) { // ista oseba + bubblenode.className = "message"; + var istaoseba = true; + var messagesnest = chatarea.children.item(0); + } else { + bubblenode.className = "message last"; + var istaoseba = false; + var messagesnest = document.createElement("div"); + } + } else { // auto place (slower, so 0 or 1 are options + console.log("if3"); + for(var iter = 0; iter < alreadyMessages.length - 2; iter++) { // (-2 zato, ker potem iter+1 ne obstaja pri zadnjem elementu) + if ( + Number(alreadyMessages[iter].getAttribute("data-date")) < timstamp + && Number(alreadyMessages[iter+1].getAttribute("data-date")) > timestamp + ) { + var zgornjiIsti = alreadyMessages[iter].parentElement.classList.contains(whos); + var spodnjiIsti = alreadyMessages[iter+1].parentElement.classList.contains(whos); + console.log([zgornjiIsti, spodnjiIsti]); + if(zgornjiIsti && spodnjiIsti) { + var messagesnest = alreadyMessages[iter].parentElement; + bubblenode.className = "message"; + messagesnest.insertBefore(bubblenode, alreadyMessages[iter+1]); + return; + } + if(zgornjiIsti && !spodnjiIsti) { + var messagesnest = alreadyMessages[iter].parentElement; + bubblenode.className = "message last"; + messagesnest.children.item(messagesnest.childElementCount - 1).classList.remove("last"); + messagesnest.appendChild(bubblenode); + return; + } + if(!zgornjiIsti && spodnjiIsti) { + var messagesnest = alreadyMessages[iter+1].parentElement; + bubblenode.className = "message"; + messagesnest.insertBefore(bubblenode, alreadyMessages[iter+1]); + return; + } + throw new RangeError("This should not happen!"); + } + } + throw new RangeError("This should not happen!1"); + } + } + // autodetect date is not present here anymore + messagesnest.className = whos+" messages"; + if(datePlacement == 0) { + messagesnest.appendChild(bubblenode); + } else { + messagesnest.prepend(bubblenode); + } + if(!istaoseba) { + if(datePlacement == 0) { + chatarea.appendChild(messagesnest); + } else{ + chatarea.prepend(messagesnest); + } + } +} +async function validateName() { + if (directory !== null) { + document.getElementById("full-name").disabled = false; + if ($("#full-name").val() in directory) { + $("#full-name").addClass("valid"); + $("#full-name").removeClass("invalid"); + document.getElementById("chat-recipient-select-btn").disabled = false; + document.getElementById("msg-body").disabled = false; + } else { + $("#full-name").addClass("invalid"); + $("#full-name").removeClass("valid"); + document.getElementById("chat-recipient-select-btn").disabled = true; + document.getElementById("msg-body").disabled = true; + document.getElementById("msg-body").value = ""; + } + } else { + document.getElementById("chat-recipient-select-btn").disabled = true; + document.getElementById("full-name").value = D("nameDirectoryNotSet"); + document.getElementById("full-name").disabled = true; + document.getElementById("msg-body").value = ""; + } +} + +async function clearMessages() { + var chatarea = document.getElementsByClassName("chat")[0]; + chatarea.innerHTML = ""; +} + +function getUrlParameter(sParam) { + const url_params = new URLSearchParams(window.location.search); + const found_param = url_params.get(sParam); + return found_param; +} + +document.addEventListener("DOMContentLoaded", () => { + checkLogin(); + loadDirectory(); + updateSendButton(); + var receivedmessages = null; + M.updateTextFields(); + // Setup side menu + const menus = document.querySelectorAll(".side-menu"); + M.Sidenav.init(menus, { edge: "right", draggable: true }); + let elems = document.querySelectorAll('.modal'); + let instances = M.Modal.init(elems, {}); + // Setup side modal + const modals = document.querySelectorAll('.side-modal'); + M.Sidenav.init(modals, { edge: 'left', draggable: false }); + prepareAndStartFetchingMessages(); // just opens modal, as there is no recipient selected + +}); + +async function updateSendButton() { + if(document.getElementById("msg-body").value.length == 0) { + document.getElementById("msg-send").disabled = true; + } else { + document.getElementById("msg-send").disabled = false; + } +} + +async function setRecipient(name = null) { + if(name == null || name == false || name == undefined) { + name = document.getElementById("full-name").value; + } else if (typeof name != "number") { + throw new TypeError('Hello from setRecipient(): name can only be string or null!'); + } + + if(Object.keys(directory).includes(name)) {} else { + UIAlert(D("recipientNotInDirectory")); + throw new RangeError("Hello from setRecipient(): name is not in directory"); + } + var modal = document.querySelectorAll('#directory-side-menu')[0]; + var modalInstance = M.Sidenav.getInstance(modal); + modalInstance.close(); + document.getElementsByClassName("msg-chattingWith")[0].innerHTML = name; + sogovornik = name; + currentlyChattingWith = directory[name]; + document.getElementById("chat-mustSelectRecipient").hidden=true; + updateSendButton(); + clearMessages(); // <-- do when recipient selected + prepareAndStartFetchingMessages(); // <-- same +} + +async function prepareAndStartFetchingMessages() { + if(currentlyChattingWith === 0 || (currentlyChattingWith >= 1 && currentlyChattingWith < 69420)) { + document.getElementById("msg-body").disabled = false; + await clearMessages(); + startFetchingMessages(); + } else { + var modal = document.querySelectorAll('#directory-side-menu')[0]; + var modalInstance = M.Sidenav.getInstance(modal); + modalInstance.open(); + } +} + +async function startFetchingMessages() { + let promises_to_run = [ + localforage.getItem("username").then((value) => { + username = value; + }), + localforage.getItem("password").then((value) => { + password = value; + }), + ]; + setLoading(true); + await Promise.all(promises_to_run); + try { + let gsecInstance = new gsec(); + await gsecInstance.login(username, password); + for (var category = 0; category <= 1; category++) { + let lastpage = await gsecInstance.fetchMessagesLastPageNumber(category); + startLoadingMessagesForCategory(gsecInstance, category, lastpage); + } + } catch (err) { + gsecErrorHandlerUI(err); + setLoading(false); + } +} + +async function startLoadingMessagesForCategory(gsecInstance, category, lastpage) { + for(var page = 1; page <= lastpage; page++) { + var gsecMsgList = await gsecInstance.fetchMessagesList(category, page); + if(category == 0) { + whom = 1; + } else { + whom = 0; + } + renderMessages(gsecMsgList, whom, 1); + } +} + +async function renderMessages(gsecMsgList, whom, order = 1) { // order: 1=newest>olest 0=oldest>newest 2=autodetect (todo-not implemented) + for(const message of gsecMsgList) { // whom: 0=me 1=you + if(message.subject.substring(0, 20) == "beziapp-ctlmsg-chat-") { + addMessage(whom, message.subject.substring(20), 2, message.date.getTime); + } + } +} |