Skip to content

Commit 07db69b

Browse files
committed
Improved chat-message editing
1 parent 8594e50 commit 07db69b

File tree

2 files changed

+71
-33
lines changed

2 files changed

+71
-33
lines changed

src/component/chat-box/chat-message.css

+14-4
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ pre {
7878
.modify-buttons {
7979
display: flex;
8080
flex-direction: row;
81+
margin-top: 1px;
82+
}
83+
.modify-buttons sl-button::part(base) {
84+
border: 0;
85+
min-height: var(--sl-input-height-small);
86+
font-size: var(--sl-button-font-size-small);
87+
line-height: calc(var(--sl-input-height-small) - var(--sl-input-border-width) * 2);
8188
}
8289
.deleted-message-content {
8390
font-style: italic;
@@ -124,8 +131,11 @@ pre {
124131
display: flex;
125132
align-items: center;
126133
}
127-
128-
textarea {
129-
flex: 1;
130-
margin-right: 8px;
134+
135+
[contenteditable] {
136+
border-radius: 2px;
137+
outline: 1px dashed var(--sl-color-primary-800);
138+
outline-offset: 2px;
139+
position: relative;
140+
white-space: pre-wrap;
131141
}

src/component/chat-box/chat-message.ts

+57-29
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@ export class ChatBoxMessage extends Component {
4747
@query('#edit-tooltip')
4848
accessor editTooltip: SlTooltip;
4949

50+
@query('#message-editor')
51+
accessor messageEditor: HTMLElement;
52+
53+
@query('#message-submit')
54+
accessor messageSubmit: HTMLButtonElement;
55+
5056
@query(".chat-message-boxed")
5157
accessor chatMessageBoxed: HTMLElement;
5258

53-
editedText: string = "";
54-
5559
timestamp: string;
5660

5761
content: string;
@@ -88,14 +92,7 @@ export class ChatBoxMessage extends Component {
8892
<div class="chat-message-boxed">
8993
${when(this.editing, () => html`
9094
<div class="chat-message-edit">
91-
<textarea
92-
@input="${(e: InputEvent) => this.editedText = (e.target as HTMLTextAreaElement).value}"
93-
.value="${this.editedText}" id="edit-message-textarea">
94-
</textarea>
95-
<sl-button id="message-submit" slot="right-pane" @click="${this.postEditedMessage}"
96-
type="submit" form="course-message-form" size="medium" circle>
97-
<sl-icon name="send"></sl-icon>
98-
</sl-button>
95+
<div id="message-editor" contenteditable="true">${this.message.text}</div>
9996
</div>
10097
`)}
10198
${when(!this.editing, () => html`
@@ -112,6 +109,14 @@ export class ChatBoxMessage extends Component {
112109

113110
return html`
114111
<div class="modify-buttons">
112+
${when(this.editing, () => html`
113+
<sl-button id="message-submit" slot="right-pane" @click="${this.postEditedMessage}"
114+
type="submit" form="course-message-form" size="medium">
115+
<sl-icon slot="prefix" name="send"></sl-icon>
116+
${t("course.feature.message.send")}
117+
</sl-button>
118+
`)}
119+
115120
<sl-tooltip id="reply-tooltip" .content="${t("course.feature.message.reply.button")}" trigger="hover">
116121
<sl-icon-button name="chat-reply" @click="${this.replyToMessage}" form="course-message-form" size="small" ?disabled="${!this.canReply()}"></sl-icon-button>
117122
</sl-tooltip>
@@ -175,7 +180,7 @@ export class ChatBoxMessage extends Component {
175180

176181
}
177182

178-
private replyToMessage(event: Event) : void {
183+
private replyToMessage(_event: Event) : void {
179184
if (!this.chatForm) {
180185
throw new Error("Form is null");
181186
}
@@ -189,23 +194,36 @@ export class ChatBoxMessage extends Component {
189194
this.hideTooltips();
190195

191196
this.editing = true;
192-
this.editedText = this.message.text;
193197

194198
const clickListener = (e: MouseEvent) => this.cancelEditing(e);
195199
document.addEventListener('mousedown', clickListener);
196200

197-
this.globalClickListener = clickListener;
201+
this.globalClickListener = clickListener;
202+
203+
setTimeout(() => {
204+
this.messageEditor.focus();
205+
}, 0);
198206
}
199207

200-
private postEditedMessage(event: Event) : void{
208+
private postEditedMessage(event: Event): void {
209+
const editedText = this.messageEditor.innerText;
210+
211+
if (editedText == this.message.text) {
212+
this.editing = false;
213+
return;
214+
}
215+
201216
document.removeEventListener('mousedown', this.globalClickListener);
202217
const editButton = <HTMLButtonElement> event.target;
203218
editButton.disabled = true;
204219

205-
this.chatService.editMessage(this.editedText, this.message.messageId)
220+
this.chatService.editMessage(editedText, this.message.messageId)
206221
.then(() => {
222+
this.message.text = editedText;
207223
this.editing = false;
208-
if (this.editedText != this.message.text) Toaster.showSuccess(`${t("course.feature.message.edited")}`);
224+
225+
Toaster.showSuccess(`${t("course.feature.message.edited")}`);
226+
209227
editButton.disabled = false;
210228
})
211229
.catch(error => {
@@ -232,29 +250,39 @@ export class ChatBoxMessage extends Component {
232250
}
233251

234252
private canReply(): boolean {
235-
if(this.editing || this.message.deleted) return false;
236-
237-
if(!privilegeStore.canWriteMessages()) return false;
238-
if(ChatService.isPrivateMessage(this.message) && !privilegeStore.canWritePrivateMessages()) return false;
239-
if(ChatService.isMessageToOrganisers(this.message) && !privilegeStore.canWriteMessagesToOrganisators()) return false;
253+
if (this.editing || this.message.deleted) {
254+
return false;
255+
}
256+
if (!privilegeStore.canWriteMessages()) {
257+
return false;
258+
}
259+
if (ChatService.isPrivateMessage(this.message) && !privilegeStore.canWritePrivateMessages()) {
260+
return false;
261+
}
262+
if (ChatService.isMessageToOrganisers(this.message) && !privilegeStore.canWriteMessagesToOrganisators()) {
263+
return false;
264+
}
240265

241266
return privilegeStore.canWriteMessagesToAll();
242267
}
243268

244-
private cancelEditing(event: MouseEvent) : void {
245-
if(!this.chatMessageBoxed) return;
269+
private cancelEditing(event: MouseEvent): void {
270+
if (!this.chatMessageBoxed) {
271+
return;
272+
}
246273

247-
const clickWithinMessageBox: boolean = ChatBoxMessage.isWithinRect(
248-
event.clientX, event.clientY,
249-
this.chatMessageBoxed.getBoundingClientRect())
274+
const clickWithinMessageSubmit = ChatBoxMessage.isWithinRect(event.clientX, event.clientY,
275+
this.messageSubmit?.getBoundingClientRect() ?? new DOMRect());
276+
const clickWithinMessageBox = ChatBoxMessage.isWithinRect(event.clientX, event.clientY,
277+
this.chatMessageBoxed.getBoundingClientRect());
250278

251-
if(clickWithinMessageBox) {
279+
if (clickWithinMessageBox || clickWithinMessageSubmit) {
252280
return;
253281
}
254282

255-
this.editing = false;
283+
this.editing = false;
256284

257-
document.removeEventListener('mousedown', this.globalClickListener);
285+
document.removeEventListener('mousedown', this.globalClickListener);
258286
}
259287

260288
private static getMessageDate(message: ChatMessage) {

0 commit comments

Comments
 (0)