aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile12
-rw-r--r--TODO1
-rw-r--r--src/index.html (renamed from index.html)2
-rw-r--r--src/main.css (renamed from main.css)31
-rw-r--r--src/main.ts (renamed from main.js)170
-rw-r--r--tsconfig.json17
7 files changed, 171 insertions, 63 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c795b05
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+build \ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a93bc93
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,12 @@
+.PHONY: build
+
+build: copy
+ mkdir -p build
+ tsc --outDir build/
+
+copy:
+ cp src/index.html build/
+ cp src/main.css build/
+
+clean:
+ rm -r build \ No newline at end of file
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..5551f7d
--- /dev/null
+++ b/TODO
@@ -0,0 +1 @@
+Reply to messages
diff --git a/index.html b/src/index.html
index a3fb0ab..38bbbc8 100644
--- a/index.html
+++ b/src/index.html
@@ -5,7 +5,7 @@
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/fork-awesome@1.2.0/css/fork-awesome.min.css" integrity="sha256-XoaMnoYC5TH6/+ihMEnospgm0J1PM/nioxbOUdnM8HY=" crossorigin="anonymous">
</head>
- <body onload="onload()">
+ <body onload="load()">
<span id="navbar">
<span>Localhost</span>
<span id = "info" class="UI">Server Information: </span>
diff --git a/main.css b/src/main.css
index 96a2d60..6c6218d 100644
--- a/main.css
+++ b/src/main.css
@@ -5,6 +5,7 @@
display: flex;
flex-flow: column;
overflow-y: scroll;
+ overflow-x: clip;
word-break: break-word;
scroll-snap-align: end;
flex-basis: 100vh;
@@ -15,12 +16,12 @@
}
.message {
display: flex;
- height: 1.6em;
+ flex-basis: 1.6em;
padding-left: 2px;
padding-right: 2px;
- align-items: center;
+ flex-shrink: 0;
}
-.message:hover > :last-child {
+.message:hover > :last-child > :first-child {
display: flex;
}
.messagetext {
@@ -29,13 +30,34 @@
}
.messagedate {
font-size: 12px;
+ align-self: start;
+ margin-top: 4px;
+ word-break: keep-all;
+
}
.message:not(.deleted) > .messagedate {
color: #666;
}
+.message_buttons_anchor {
+ position: relative;
+}
.message_buttons {
display: none;
+ position: absolute;
+ /* calc (((button height + anchor padding) / 2) * -1) */
+ top: calc(((1.6em + 4px) / 2) * -1);
+ /* calc ((buttons amount(button size + button padding) + anchor padding) * -1) */
+ left: calc((3(1.6em + 4px) + 4px) * -1);
+ right: 0;
+ bottom: 0;
+
+ margin-right: 8px;
+ padding: 2px;
+ height: min-content;
+ background-color: white;
+ border: 1px solid black;
+ border-radius: 2px;
}
.message_buttons > button {
height: 1.6em;
@@ -55,7 +77,8 @@
display: flex;
}
#inputbox > button {
- padding: 0 5px 0 5px;
+ /* padding: 0 10px 0 10px; */
+ width: 4em;
}
#input {
resize: none;
diff --git a/main.js b/src/main.ts
index c51bd0c..cec62d8 100644
--- a/main.js
+++ b/src/main.ts
@@ -1,16 +1,31 @@
-const messages = new Map();
-const users = new Map();
+interface User {
+ id: number,
+ username: string,
+ deleted: boolean,
+}
+interface Message {
+ id: number,
+ sender: number,
+ message: string,
+ reply_to: number,
+ date: number,
+ deleted: boolean,
+}
+
+
+const messages = new Map<number, Message>();
+const users = new Map<number, User>();
let sent = false;
const host = location.protocol + "//" + location.host;
-function xhttp_request(location) {
+function xhttp_request(location: string): Promise<any> {
let f = fetch(`${host}/api/${location}`);
return f.then((response) => response.json());
}
-function xhttp_send(method, location, json) {
+function xhttp_send(method: string, location: string, json: string) {
let f = fetch(`${host}/api/${location}`, {
method: method,
headers: {"Content-Type": "application/json"},
@@ -21,8 +36,7 @@ function xhttp_send(method, location, json) {
}
-async function format_message(m) {
- var s;
+async function format_message(m: Message): Promise<string> {
var sender = await get_user_name(m.sender);
var sclass = "";
@@ -30,17 +44,22 @@ async function format_message(m) {
m.message = "*deleted*"
sclass = "deleted"
}
- s = `<span id="${m.id}" class="message ${sclass}"><p class="messagedate">${format_date(m.date)}</p><p class="messagetext"> ${sender}: ${m.message}</p>
- <span class="message_buttons">
- <button title="${m.id}"><i class="fa fa-info" aria-hidden="true"></i></button>
- <button title="reply"><i class="fa fa-reply" aria-hidden="true"></i></button>
- <button title="delete" onclick="delete_message(${m.id})"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
+
+ let s = `<span id="${m.id}" class="message ${sclass}">
+ <p class="messagedate">${format_date(m.date)}</p>
+ <p class="messagetext"> ${sender}: ${m.message}</p>
+ <span class="message_buttons_anchor">
+ <span class="message_buttons">
+ <button title="information" onclick="message_info(${m.id})"><i class="fa fa-info" aria-hidden="true"></i></button>
+ <button title="reply"><i class="fa fa-reply" aria-hidden="true"></i></button>
+ <button title="delete" onclick="delete_message(${m.id})"><i class="fa fa-trash-o" aria-hidden="true"></i></button>
+ </span>
</span></span>`
return s
}
-function format_time(t) {
+function format_time(t: number) {
let as_str = `${t}`;
if (as_str.length < 2) {
return `0${t}`
@@ -49,7 +68,7 @@ function format_time(t) {
}
}
-function format_date(d) {
+function format_date(d: number) {
let date = new Date(d * 1000);
let hours = format_time(date.getHours());
let minutes = format_time(date.getMinutes());
@@ -57,36 +76,50 @@ function format_date(d) {
return `${hours}:${minutes}:${seconds}`;
}
-function delete_message(id) {
+function delete_message(id: number) {
xhttp_send("DELETE", "delete_message", JSON.stringify(id)).then((response) => {
if (response.Ok == undefined) {
alert("Could not delete message")
} else {
let old_msg = messages.get(id);
- old_msg.message = "*deleted*";
- old_msg.deleted = true;
- messages.set(id, old_msg);
-
- chatwindow(null).then();
+ if (old_msg != undefined) {
+ old_msg.message = "*deleted*";
+ old_msg.deleted = true;
+ messages.set(id, old_msg);
+
+ chatwindow(null).then();
+ } else {
+ throw new Error("Could not find message")
+ }
}
})
}
+function message_info(id: number): void {
+ let msg = messages.get(id);
+
+ if (msg != undefined) {
+ let final = `id: ${msg.id}\nsender: ${msg.sender}\nmessage: ${msg.message}\ndate: ${msg.date}\nreply_to: ${msg.reply_to}\ndelted: ${msg.deleted}`;
+ alert(final)
+ }
+}
+
function send() {
- var input = document.getElementById("input").value;
- let user_id = get_user_from_name().then((user_id) => {
+ var input = getelementbyid("input");
+
+ get_user_from_name().then((user_id) => {
if (user_id == undefined) {
alert("User not found")
return undefined
}
- let message = JSON.stringify({"sender": user_id, "message": input})
+ let message = JSON.stringify({"sender": user_id, "message": input.value})
- var id = xhttp_send("POST", "send_message", message).then((id) => {
+ xhttp_send("POST", "send_message", message).then((id) => {
if (id.Ok != undefined) {
get_message(id.Ok);
- document.getElementById("input").value = ""
+ input.value = "";
sent = true
} else {
alert(id.Err)
@@ -98,7 +131,7 @@ function send() {
function get_newest_cache_id() {
let last = -1;
- for (k of messages.keys()) {
+ for (let k of messages.keys()) {
if (k > last) {
last = k
}
@@ -122,7 +155,7 @@ function get_newest_messages() {
}
- let final_array = [];
+ let final_array: Message[] = [];
if (newest_id == newest_cache_id) {
return
@@ -145,8 +178,8 @@ function get_newest_messages() {
let newest = delta;
- let list = get_message_list(oldest, newest);
- for (x of list.values()) {
+ let list = await get_message_list(oldest, newest);
+ for (let x of list.values()) {
final_array.push(x)
}
@@ -160,12 +193,12 @@ function get_newest_messages() {
}
let list = await get_message_list(newest_cache_id, newest_id)
- for (x of list.values()) {
+ for (let x of list.values()) {
final_array.push(x)
}
// Insert all values into the message map
- for (x of final_array.values()) {
+ for (let x of final_array.values()) {
messages.set(x.id, x)
}
@@ -173,17 +206,17 @@ function get_newest_messages() {
});
}
-async function get_message_list(oldest, newest) {
+async function get_message_list(oldest, newest): Promise<Message[]> {
let data = await xhttp_request(`get_message_list/${oldest}/${newest}`).then();
let req = data.Ok;
return req
}
-function get_message(id) {
+function get_message(id: number): void {
let cached = messages.get(id)
if (cached != undefined) {
- return to_dom(format_message(cached))
- }
+ chatwindow(id)
+ }
// Get message
xhttp_request("get_message/" + id).then((data) => {
@@ -197,9 +230,9 @@ function get_message(id) {
}
async function get_user_from_name() {
- let v = document.getElementById("username").value;
+ let v = getelementbyid("username").value;
- for (x of users.values()) {
+ for (let x of users.values()) {
if (x.username == v) {
return x.id
}
@@ -242,20 +275,32 @@ async function get_user_name(id) {
return user.username
}
-function to_dom(x) {
- // Pretty hacky if I do say so myself
- let dom = new DOMParser().parseFromString(x, "text/html").firstChild.lastChild.firstChild;
- return dom
+// Pretty hacky if I do say so myself
+function to_dom(x: string): Node {
+ let dom = new DOMParser().parseFromString(x, "text/html");
+
+ if (dom != null) {
+ if (dom.firstChild) {
+ if (dom.firstChild.lastChild) {
+ if (dom.firstChild.lastChild.firstChild) {
+ return dom.firstChild.lastChild.firstChild
+ }
+ }
+ }
+ }
+
+ throw new Error("Could not convert to dom")
}
-async function chatwindow(hash) {
- let window = document.getElementById("chatwindow");
+async function chatwindow(hash: any = undefined) {
+ let window: HTMLDivElement = getelementbyid("chatwindow");
+ let new_messages: HTMLSpanElement = getelementbyid("new_messages")
let pre_scroll = window.scrollHeight - window.clientHeight;
window.innerHTML = "";
- let array = [];
+ let array: Message[] = [];
- for (v of messages.values()) {
+ for (let v of messages.values()) {
array.push(v);
}
@@ -267,7 +312,7 @@ async function chatwindow(hash) {
let old_date = new Date(0);
let latest_v;
- for (v of array) {
+ for (let v of array) {
latest_v = v;
let date = new Date(v.date * 1000);
if (date.getDate() > old_date.getDate() || date.getFullYear() > old_date.getFullYear() || date.getMonth() > date.getMonth()) {
@@ -276,10 +321,9 @@ async function chatwindow(hash) {
}
let data = await format_message(v).then()
- let dom = to_dom(data);
+ let dom: Node = to_dom(data);
window.appendChild(dom);
-
}
if (hash == null) {
@@ -288,28 +332,29 @@ async function chatwindow(hash) {
if (window.scrollTop == pre_scroll) {
if (latest_v != undefined && hash == undefined) {
- document.getElementById(v.id).scrollIntoView();
+ getelementbyid(latest_v.id).scrollIntoView();
}
} else {
- document.getElementById("new_messages").style.display = "unset"
+ new_messages.style.display = "unset"
}
if (hash != undefined) {
- document.getElementById(hash).scrollIntoView();
+ getelementbyid(hash.toString()).scrollIntoView();
}
}
function onscrollchat() {
- let window = document.getElementById("chatwindow");
+ let window: HTMLDivElement = getelementbyid("chatwindow");
+ let new_messages: HTMLSpanElement = getelementbyid("new_messages")
let pre_scroll = window.scrollHeight - window.clientHeight;
if (window.scrollTop == pre_scroll) {
- document.getElementById("new_messages").style.display = "";
+ new_messages.style.display = "";
}
}
-function inputkey(event) {
- let window = document.getElementById("input");
+function inputkey(event: KeyboardEvent) {
+ let window: HTMLTextAreaElement = getelementbyid("input");
// If the cursor pos is at the end of the textarea
let comp = window.selectionEnd - window.value.length
@@ -321,8 +366,8 @@ function inputkey(event) {
}
}
-function clearnewlineinput() {
- let window = document.getElementById("input");
+function clearnewlineinput(): void {
+ let window: HTMLTextAreaElement = getelementbyid("input");
if (window.value == "\n" && sent == true) {
window.value = ""
@@ -330,10 +375,19 @@ function clearnewlineinput() {
}
}
-function onload() {
+function getelementbyid(s: string): any {
+ let x = document.getElementById(s);
+ if (x == null) {
+ throw new Error("Could not find element")
+ } else {
+ return x
+ }
+}
+
+function load(): void {
xhttp_request("").then((server_info) => {
- document.getElementById("info").innerHTML += server_info.version + ", " + server_info.name + ", users: " + server_info.users;
+ getelementbyid("info").innerHTML += server_info.version + ", " + server_info.name + ", users: " + server_info.users;
// Get ready for websockets implementation in rocket_test 0.3
if (server_info.version[2] < 3 ) {
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..9443036
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "node",
+ "target": "ES2020",
+ "jsx": "preserve",
+ "strictNullChecks": true,
+ "strictFunctionTypes": true
+ },
+ "include": [
+ "src/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "**/node_modules/*"
+ ]
+} \ No newline at end of file