diff options
-rw-r--r-- | index.html | 65 | ||||
-rw-r--r-- | main.js | 213 |
2 files changed, 278 insertions, 0 deletions
diff --git a/index.html b/index.html new file mode 100644 index 0000000..aae55ba --- /dev/null +++ b/index.html @@ -0,0 +1,65 @@ +<html> + <head> + <script src="main.js"></script> + <style> + .UI { + background-color: blue; + } + #chatwindow { + display: flex; + flex-flow: column; + overflow-y: scroll; + word-break: break-word; + scroll-snap-align: end; + flex-basis: 100vh; + flex-grow: 1; + } + #chatwindow > span:hover { + background-color: #DDD; + } + #chatwindow > span { + white-space: pre-line; + } + #navbar { + border-bottom: 2px solid black; + width: 100%; + display: inline-block; + flex-grow: 0; + } + #inputbox { + border-top: 2px solid black; + display: flex; + } + #inputbox > button { + padding: 0 5px 0 5px; + } + #input { + resize: none; + flex-grow: 1; + } + + * { + margin: 0; + padding: 0; + border: 0; + } + + body { + display: flex; + flex-direction: column; + max-height: 100vh; + } + </style> + </head> + <body onload="onload()"> + <span id="navbar"> + <span>Localhost</span> + <span id = "info" class="UI">Server Information: </span> + </span> + <div id="chatwindow"></div> + <span id="inputbox" onkeyup="inputkey(event)"> + <textarea id="input" autofocus rows="2"></textarea> + <button onclick="send()">Send</button> + </span> + </body> +</html> @@ -0,0 +1,213 @@ +const messages = new Map(); +const users = new Map(); + + +function xhttp_request(location) { + var xhttp = new XMLHttpRequest(); + var return_string; + + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + // Typical action to be performed when the document is ready: + return_string = xhttp.responseText; + } + }; + xhttp.open("GET", "http://localhost/api/" + location, false); + xhttp.send(); + + return JSON.parse(return_string); +} + +function xhttp_post(location, json) { + var xhttp = new XMLHttpRequest(); + xhttp.open("POST", "http://localhost/api/" + location, false); + xhttp.setRequestHeader("Content-Type", "application/json") + + + var return_string; + + xhttp.onreadystatechange = function() { + if (this.readyState == 4 && this.status == 200) { + return_string = xhttp.responseText; + } + }; + + xhttp.send(json); + + return JSON.parse(return_string); +} + +function format_message(m) { + var s; + var sender = get_user_name(m.sender); + + if (m.deleted) { + s = `<span>${m.id}|${sender}: deleted</span>` + // s = "<span>" + m.id + "|" + m.sender + ": /deleted/" + "</span>" + } else { + s = `<span>${m.id}|${sender}: ${m.message}</span>` + // s = "<span>" + m.id + "|" + m.sender + ": " + m.message + "</span>" + } + + return s +} + +function send() { + var input = document.getElementById("input").value; + let message = JSON.stringify({"sender": 0, "message": input}) + + var id = xhttp_post("send_message", message) + + get_message(id.Ok); + + document.getElementById("input").value = '' +} + +function get_newest_cache_id() { + let last = -1; + for (k of messages.keys()) { + if (k > last) { + last = k + } + } + + return last +} + +// Returns message list +function get_newest_messages() { + let newest_id = xhttp_request("get_message_id_newest").Ok; + let newest_cache_id = get_newest_cache_id(); + + + let final_array = []; + + if (newest_id == newest_cache_id) { + return + } + + if (newest_cache_id == -1) { + get_message(0) + return get_newest_messages() + } + + if (newest_id > newest_cache_id) { + let delta = newest_id - newest_cache_id ; + if (delta > 25) { + let oldest = newest_id - 25; + let newest = delta; + + + let list = get_message_list(oldest, newest); + for (x of list.values()) { + final_array.push(x) + } + + newest_id = oldest; + if (oldest - 25 < 0) { + newest_cache_id = 0 + } else { + newest_cache_id = oldest - 25 + } + } + } + + let list = get_message_list(newest_cache_id, newest_id) + for (x of list.values()) { + final_array.push(x) + } + + // Insert all values into the message map + for (x of final_array.values()) { + messages.set(x.id, x) + } + + chatwindow() +} + +function get_message_list(oldest, newest) { + let req = xhttp_request(`get_message_list/${oldest}/${newest}`).Ok + return req +} + +// Returns dom +function get_message(id) { + let cached = messages.get(id) + if (cached != undefined) { + return to_dom(cached) + } + + // Get message + let msg = xhttp_request("get_message/" + id).Ok; + messages.set(msg.id, msg) + + let dom = to_dom(msg); + + chatwindow() + + return dom +} + +function get_user_name(id) { + let cached = users.get(id) + if (cached != undefined) { + return cached.username + } + + + let user = xhttp_request("get_user/" + id).Ok; + users.set(user.id, user) + + return user.username +} + +// Returns dom +function to_dom(x) { + let dom = new DOMParser().parseFromString(format_message(x), "text/xml").firstChild; + return dom +} + +function chatwindow() { + let window = document.getElementById("chatwindow"); + window.innerHTML = ""; + + let array = []; + + for (v of messages.values()) { + array.push(v); + } + + array.sort( + function(a, b) { + return a.id - b.id + } + ); + + for (v of array) { + let dom = to_dom(v); + + window.append(dom) + } + + window.scrollTop = window.scrollHeight +} + +function inputkey(event) { + let key = event.key + let shift = event.shiftKey; + if (key == "Enter" && shift) { + send() + } else if (key == "Enter" && !shift) { + this.value += "\n" + } +} + +function onload() { + let server_info = xhttp_request(""); + document.getElementById("info").innerHTML += server_info.version + ", " + server_info.name + ", users: " + server_info.users; + + // Get all messages on startup + // get_newest_messages(); + + const interval = setInterval(get_newest_messages, 1000); +}
\ No newline at end of file |