summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2022-09-10 18:09:14 +0200
committermetamuffin <metamuffin@disroot.org>2022-09-10 18:09:14 +0200
commitd889e1b572952c5777fc2bb147f04ad8baf7f497 (patch)
treec61a68864314290c85532311bb1cc3f5181f72cc
parente45770adfcc46fe5f0350767801204efdb14313b (diff)
downloadkeks-meet-d889e1b572952c5777fc2bb147f04ad8baf7f497.tar
keks-meet-d889e1b572952c5777fc2bb147f04ad8baf7f497.tar.bz2
keks-meet-d889e1b572952c5777fc2bb147f04ad8baf7f497.tar.zst
images in chat
-rw-r--r--client-web/public/assets/style/chat.css6
-rw-r--r--client-web/source/chat.ts52
-rw-r--r--client-web/source/helper.ts16
-rw-r--r--client-web/source/user/local.ts5
-rw-r--r--client-web/source/user/remote.ts2
-rw-r--r--common/packets.d.ts3
-rw-r--r--readme.md3
7 files changed, 64 insertions, 23 deletions
diff --git a/client-web/public/assets/style/chat.css b/client-web/public/assets/style/chat.css
index 26c1ad5..34e7d63 100644
--- a/client-web/public/assets/style/chat.css
+++ b/client-web/public/assets/style/chat.css
@@ -19,9 +19,13 @@
.chat .author {
font-weight: bold;
}
-.chat .content {
+.chat .text {
color: white;
}
+.chat .image {
+ width: min(20em, 30vw);
+}
+
.chat .messages {
height: calc(100% - 3em);
width: 100%;
diff --git a/client-web/source/chat.ts b/client-web/source/chat.ts
index dfef73f..792a620 100644
--- a/client-web/source/chat.ts
+++ b/client-web/source/chat.ts
@@ -1,4 +1,6 @@
-import { ediv, espan, OverlayUi } from "./helper.ts";
+import { ChatMessage } from "../../common/packets.d.ts";
+import { ediv, espan, image_view, OverlayUi } from "./helper.ts";
+import { log } from "./logger.ts";
import { Room } from "./room.ts";
import { User } from "./user/mod.ts";
@@ -9,13 +11,7 @@ export class Chat extends OverlayUi {
constructor(public room: Room) {
const send = document.createElement("input")
send.type = "text"
- send.onkeydown = (ev) => {
- if (ev.code == "Enter") {
- room.local_user.chat(send.value)
- this.send_message(room.local_user, send.value)
- send.value = ""
- }
- }
+
const messages = ediv({ class: "messages" })
const controls = ediv({ class: "controls" })
controls.append(send)
@@ -23,13 +19,45 @@ export class Chat extends OverlayUi {
super(ediv({ class: "chat" }, messages, controls))
this.messages = messages
this.controls = controls
+
+ send.onkeydown = (ev) => {
+ if (ev.code == "Enter") {
+ if (send.value.trim().length == 0) return // no!
+ this.send({ text: send.value })
+ send.value = ""
+ }
+ }
+ document.onpaste = (pasteEvent) => {
+ // TODO will only work when pasting a single image
+ const item = pasteEvent.clipboardData?.items[0];
+ if (!item) return
+ if (item.type.indexOf("image") === 0) {
+ log("*", "image pasted")
+ const blob = item.getAsFile()
+ if (!blob) return
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ if (!event.target) return
+ if (typeof event.target.result != "string") return
+ this.send({ image: event.target.result })
+ };
+ reader.readAsDataURL(blob);
+ }
+ }
+ }
+
+ send(msg: ChatMessage) {
+ this.room.local_user.chat(msg)
+ this.add_message(this.room.local_user, msg)
}
- send_message(sender: User, message: string) {
+ add_message(sender: User, message: ChatMessage) {
+ const els = []
+ if (message.text) els.push(espan(message.text, { class: "text" }))
+ if (message.image) els.push(image_view(message.image, { class: "image" }))
+
this.messages.append(ediv({ class: "message" },
- espan(sender.display_name, { class: "author" }),
- ": ",
- espan(message, { class: "content" })
+ espan(sender.display_name, { class: "author" }), ": ", ...els
))
}
}
diff --git a/client-web/source/helper.ts b/client-web/source/helper.ts
index 1d75b60..3c5d0ff 100644
--- a/client-web/source/helper.ts
+++ b/client-web/source/helper.ts
@@ -1,14 +1,13 @@
/// <reference lib="dom" />
-
-
const elem = (s: string) => document.createElement(s)
-interface Opts { class?: string[] | string, id?: string }
+interface Opts { class?: string[] | string, id?: string, src?: string, onclick?: () => void }
function apply_opts(e: HTMLElement, o: Opts | undefined) {
if (!o) return
if (o.id) e.id = o.id
+ if (o.onclick) e.onclick = o.onclick
if (typeof o?.class == "string") e.classList.add(o.class)
if (typeof o?.class == "object") e.classList.add(...o.class)
}
@@ -40,7 +39,6 @@ export const elabel = elem_with_content("label")
export const OVERLAYS = ediv({ class: "overlays" })
-
export class OverlayUi {
_shown = false
constructor(public el: HTMLElement, initial = false) {
@@ -54,3 +52,13 @@ export class OverlayUi {
}
}
+export function image_view(url: string, opts?: Opts): HTMLElement {
+ const img = document.createElement("img")
+ apply_opts(img, opts)
+ img.src = url
+ img.alt = `Image (click to open)`
+ img.addEventListener("click", () => {
+ window.open(url, "_blank", "noreferrer=true,noopener=true,popup=true")
+ })
+ return img
+}
diff --git a/client-web/source/user/local.ts b/client-web/source/user/local.ts
index 72d18a4..3fb52ce 100644
--- a/client-web/source/user/local.ts
+++ b/client-web/source/user/local.ts
@@ -9,6 +9,7 @@ import { TrackHandle } from "../track_handle.ts";
import { User } from "./mod.ts";
import { ROOM_CONTAINER } from "../index.ts";
import { ediv } from "../helper.ts";
+import { ChatMessage } from "../../../common/packets.d.ts";
export class LocalUser extends User {
mic_gain?: GainNode
@@ -47,8 +48,8 @@ export class LocalUser extends User {
})
}
- chat(content: string) {
- this.room.signaling.send_relay({ chat: { content } })
+ chat(message: ChatMessage) {
+ this.room.signaling.send_relay({ chat: message })
}
add_initial_to_remote(u: RemoteUser) {
diff --git a/client-web/source/user/remote.ts b/client-web/source/user/remote.ts
index 68dd08f..2ddf2e6 100644
--- a/client-web/source/user/remote.ts
+++ b/client-web/source/user/remote.ts
@@ -43,7 +43,7 @@ export class RemoteUser extends User {
}
on_relay(message: RelayMessage) {
- if (message.chat) this.room.chat.send_message(this, message.chat.content)
+ if (message.chat) this.room.chat.add_message(this, message.chat)
if (message.ice_candidate) this.add_ice_candidate(message.ice_candidate)
if (message.offer) this.on_offer(message.offer)
if (message.answer) this.on_answer(message.answer)
diff --git a/common/packets.d.ts b/common/packets.d.ts
index d7fe5b1..4c4f8b2 100644
--- a/common/packets.d.ts
+++ b/common/packets.d.ts
@@ -22,9 +22,10 @@ export interface RelayMessageWrapper {
}
export interface RelayMessage {
- chat?: { content: string },
+ chat?: ChatMessage,
identify?: { username: string }
offer?: F_RTCSessionDescriptionInit,
answer?: F_RTCSessionDescriptionInit,
ice_candidate?: F_RTCIceCandidateInit,
}
+export interface ChatMessage { text?: string, image?: string } \ No newline at end of file
diff --git a/readme.md b/readme.md
index 4b34a00..e3c6ce7 100644
--- a/readme.md
+++ b/readme.md
@@ -12,7 +12,7 @@ a web conferencing application
- Multiple streams
- Noise suppression (rnnoise)
- End-to-end-encryption
-- Chat
+- Chat (text and images)
## Licence
@@ -78,7 +78,6 @@ Booleans can be either `1`, `true`, `yes` or their opposites.
- Built-in storage for known keys
- Relay RTC when there are a lot of clients
- Mitigate security issues caused by `*_enabled` params
-- Images in chat
## Protocol