Refactored message logic
This commit is contained in:
		
							parent
							
								
									24ddd4b294
								
							
						
					
					
						commit
						20f817506f
					
				| @ -2,8 +2,10 @@ import { app } from "../app.js"; | |||||||
| 
 | 
 | ||||||
| class ChatInputComponent extends HTMLElement { | class ChatInputComponent extends HTMLElement { | ||||||
|   autoCompletions = { |   autoCompletions = { | ||||||
|     "example 1": () => {}, |     "example 1": () => { | ||||||
|     "example 2": () => {}, |     }, | ||||||
|  |     "example 2": () => { | ||||||
|  |     }, | ||||||
|   } |   } | ||||||
|   hiddenCompletions = { |   hiddenCompletions = { | ||||||
|     "/starsRender": () => { |     "/starsRender": () => { | ||||||
| @ -17,6 +19,8 @@ class ChatInputComponent extends HTMLElement { | |||||||
|   previousValue = "" |   previousValue = "" | ||||||
|   lastChange = null |   lastChange = null | ||||||
|   changed = false |   changed = false | ||||||
|  |   expiryTimer = null; | ||||||
|  | 
 | ||||||
|   constructor() { |   constructor() { | ||||||
|     super(); |     super(); | ||||||
|     this.lastUpdateEvent = new Date(); |     this.lastUpdateEvent = new Date(); | ||||||
| @ -32,12 +36,14 @@ class ChatInputComponent extends HTMLElement { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   set value(value) { |   set value(value) { | ||||||
|     this._value = value || ""; |     this._value = value; | ||||||
|     this.textarea.value = this._value; |     this.textarea.value = this._value; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   get allAutoCompletions() { |   get allAutoCompletions() { | ||||||
|     return Object.assign({}, this.autoCompletions, this.hiddenCompletions) |     return Object.assign({}, this.autoCompletions, this.hiddenCompletions) | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   resolveAutoComplete() { |   resolveAutoComplete() { | ||||||
|     let count = 0; |     let count = 0; | ||||||
|     let value = null; |     let value = null; | ||||||
| @ -59,6 +65,7 @@ class ChatInputComponent extends HTMLElement { | |||||||
|   focus() { |   focus() { | ||||||
|     this.textarea.focus(); |     this.textarea.focus(); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   getAuthors() { |   getAuthors() { | ||||||
|     let authors = [] |     let authors = [] | ||||||
|     for (let i = 0; i < this.users.length; i++) { |     for (let i = 0; i < this.users.length; i++) { | ||||||
| @ -68,17 +75,11 @@ class ChatInputComponent extends HTMLElement { | |||||||
|     return authors |     return authors | ||||||
| 
 | 
 | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   extractMentions(text) { |   extractMentions(text) { | ||||||
|   const regex = /@([a-zA-Z0-9_-]+)/g; |     return Array.from(text.matchAll(/@([a-zA-Z0-9_-]+)/g), m => m[1]); | ||||||
|   const mentions = []; |  | ||||||
|   let match; |  | ||||||
| 
 |  | ||||||
|   while ((match = regex.exec(text)) !== null) { |  | ||||||
|     mentions.push(match[1]); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return mentions; |  | ||||||
| } |  | ||||||
|   matchMentionsToAuthors(mentions, authors) { |   matchMentionsToAuthors(mentions, authors) { | ||||||
|     return mentions.map(mention => { |     return mentions.map(mention => { | ||||||
|       let closestAuthor = null; |       let closestAuthor = null; | ||||||
| @ -105,6 +106,7 @@ class ChatInputComponent extends HTMLElement { | |||||||
|       return { mention, closestAuthor, distance: minDistance }; |       return { mention, closestAuthor, distance: minDistance }; | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   levenshteinDistance(a, b) { |   levenshteinDistance(a, b) { | ||||||
|     const matrix = []; |     const matrix = []; | ||||||
| 
 | 
 | ||||||
| @ -135,7 +137,6 @@ levenshteinDistance(a, b) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|   replaceMentionsWithAuthors(text) { |   replaceMentionsWithAuthors(text) { | ||||||
|     const authors = this.getAuthors(); |     const authors = this.getAuthors(); | ||||||
|     const mentions = this.extractMentions(text); |     const mentions = this.extractMentions(text); | ||||||
| @ -151,15 +152,12 @@ levenshteinDistance(a, b) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|   async connectedCallback() { |   async connectedCallback() { | ||||||
|     this.user = null |     this.user = null | ||||||
|     app.rpc.getUser(null).then((user) => { |     app.rpc.getUser(null).then((user) => { | ||||||
|       this.user = user |       this.user = user | ||||||
|     }) |     }) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|       const me = this; |  | ||||||
|     this.liveType = this.getAttribute("live-type") === "true"; |     this.liveType = this.getAttribute("live-type") === "true"; | ||||||
|     this.liveTypeInterval = |     this.liveTypeInterval = | ||||||
|       parseInt(this.getAttribute("live-type-interval")) || 6; |       parseInt(this.getAttribute("live-type-interval")) || 6; | ||||||
| @ -190,13 +188,29 @@ levenshteinDistance(a, b) { | |||||||
| 
 | 
 | ||||||
|     this.textarea.addEventListener("keyup", (e) => { |     this.textarea.addEventListener("keyup", (e) => { | ||||||
|       if (e.key === "Enter" && !e.shiftKey) { |       if (e.key === "Enter" && !e.shiftKey) { | ||||||
|         this.value = ""; | 
 | ||||||
|  |         const message = this.replaceMentionsWithAuthors(this.value); | ||||||
|         e.target.value = ""; |         e.target.value = ""; | ||||||
|  | 
 | ||||||
|  |         if (!message) { | ||||||
|           return; |           return; | ||||||
|         } |         } | ||||||
|       this.value = e.target.value; |         let autoCompletionHandler = this.allAutoCompletions[this.value.split(" ", 1)[0]]; | ||||||
|       this.changed = true; |         if (autoCompletionHandler) { | ||||||
|       this.update(); |           autoCompletionHandler(); | ||||||
|  |           this.value = ""; | ||||||
|  |           this.previousValue = ""; | ||||||
|  |           e.target.value = ""; | ||||||
|  | 
 | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.finalizeMessage() | ||||||
|  | 
 | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       this.updateFromInput(e.target.value); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     this.textarea.addEventListener("keydown", (e) => { |     this.textarea.addEventListener("keydown", (e) => { | ||||||
| @ -213,56 +227,16 @@ levenshteinDistance(a, b) { | |||||||
|       } |       } | ||||||
|       if (e.key === "Enter" && !e.shiftKey) { |       if (e.key === "Enter" && !e.shiftKey) { | ||||||
|         e.preventDefault(); |         e.preventDefault(); | ||||||
| 
 |  | ||||||
|         const message = me.replaceMentionsWithAuthors(this.value); |  | ||||||
|         e.target.value = ""; |  | ||||||
| 
 |  | ||||||
|         if (!message) { |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
|           let autoCompletionHandler = this.allAutoCompletions[this.value.split(" ")[0]]; |  | ||||||
|         if (autoCompletionHandler) { |  | ||||||
|           autoCompletionHandler(); |  | ||||||
|             this.value = ""; |  | ||||||
|           this.previousValue = ""; |  | ||||||
|           e.target.value = ""; |  | ||||||
| 
 |  | ||||||
|           return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         this.updateMessage() |  | ||||||
|         app.rpc.finalizeMessage(this.messageUid) |  | ||||||
|         this.value = ""; |  | ||||||
|         this.previousValue = ""; |  | ||||||
|         this.messageUid = null; |  | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     this.changeInterval = setInterval(() => { |  | ||||||
|       if (!this.liveType) { |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       if (this.value !== this.previousValue) { |  | ||||||
|         if ( |  | ||||||
|           this.trackSecondsBetweenEvents(this.lastChange, new Date()) >= |  | ||||||
|           this.liveTypeInterval |  | ||||||
|         ) { |  | ||||||
|           this.value = ""; |  | ||||||
|           this.previousValue = ""; |  | ||||||
|         } |  | ||||||
|         this.lastChange = new Date(); |  | ||||||
|       } |  | ||||||
|       this.update(); |  | ||||||
|     }, 300); |  | ||||||
| 
 |  | ||||||
|     this.addEventListener("upload", (e) => { |     this.addEventListener("upload", (e) => { | ||||||
|       this.focus(); |       this.focus(); | ||||||
|     }); |     }); | ||||||
|     this.addEventListener("uploaded", function (e) { |     this.addEventListener("uploaded", function (e) { | ||||||
|       let message = ""; |       let message = e.detail.files.reduce((message, file) => { | ||||||
|       e.detail.files.forEach((file) => { |         return `${message}[${file.name}](/channel/attachment/${file.relative_url})`; | ||||||
|         message += `[${file.name}](/channel/attachment/${file.relative_url})`; |       }, ''); | ||||||
|       }); |  | ||||||
|       app.rpc.sendMessage(this.channelUid, message, true); |       app.rpc.sendMessage(this.channelUid, message, true); | ||||||
|     }); |     }); | ||||||
|     setTimeout(() => { |     setTimeout(() => { | ||||||
| @ -274,6 +248,7 @@ levenshteinDistance(a, b) { | |||||||
|     const millisecondsDifference = event2Time.getTime() - event1Time.getTime(); |     const millisecondsDifference = event2Time.getTime() - event1Time.getTime(); | ||||||
|     return millisecondsDifference / 1000; |     return millisecondsDifference / 1000; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|   isSubsequence(s, t) { |   isSubsequence(s, t) { | ||||||
|     let i = 0, j = 0; |     let i = 0, j = 0; | ||||||
|     while (i < s.length && j < t.length) { |     while (i < s.length && j < t.length) { | ||||||
| @ -285,80 +260,54 @@ levenshteinDistance(a, b) { | |||||||
|     return i === s.length; |     return i === s.length; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 
 |   flagTyping() { | ||||||
|   newMessage() { |     if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) >= 1) { | ||||||
|     if (!this.messageUid) { |       this.lastUpdateEvent = new Date(); | ||||||
|       this.messageUid = "?"; |       app.rpc.set_typing(this.channelUid, this.user.color).catch(() => { | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|     this.value = this.replaceMentionsWithAuthors(this.value); |   finalizeMessage() { | ||||||
|     this.sendMessage(this.channelUid, this.value,!this.liveType).then((uid) => { |     if (!this.messageUid) { | ||||||
|  |       if (this.value.trim() === "") { | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       this.sendMessage(this.channelUid, this.replaceMentionsWithAuthors(this.value), !this.liveType); | ||||||
|  |     } else { | ||||||
|  |       app.rpc.finalizeMessage(this.messageUid) | ||||||
|  |     } | ||||||
|  |     this.value = ""; | ||||||
|  |     this.previousValue = ""; | ||||||
|  |     this.messageUid = null; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   updateFromInput(value) { | ||||||
|  |     if (this.expiryTimer) { | ||||||
|  |       clearTimeout(this.expiryTimer); | ||||||
|  |       this.expiryTimer = null; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.value = value; | ||||||
|  | 
 | ||||||
|  |     this.flagTyping() | ||||||
|  | 
 | ||||||
|  |     if (this.liveType && value[0] !== "/") { | ||||||
|  |       this.expiryTimer = setTimeout(() => { | ||||||
|  |         this.finalizeMessage() | ||||||
|  |       }, this.liveTypeInterval * 1000); | ||||||
|  | 
 | ||||||
|  |       if (this.messageUid === "?") { | ||||||
|  |       } else if (this.messageUid) { | ||||||
|  |         app.rpc.updateMessageText(this.messageUid, this.replaceMentionsWithAuthors(this.value)); | ||||||
|  |       } else { | ||||||
|  |         this.messageUid = "?"; // Indicate that a message is being sent
 | ||||||
|  |         this.sendMessage(this.channelUid, this.replaceMentionsWithAuthors(value), !this.liveType).then((uid) => { | ||||||
|           if (this.liveType) { |           if (this.liveType) { | ||||||
|             this.messageUid = uid; |             this.messageUid = uid; | ||||||
|           } |           } | ||||||
|         }); |         }); | ||||||
|       } |       } | ||||||
| 
 |  | ||||||
|   updateMessage() { |  | ||||||
|     if (this.value[0] == "/") { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     if (!this.messageUid) { |  | ||||||
|       this.newMessage(); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     if (this.messageUid === "?") { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     if ( |  | ||||||
|       typeof app !== "undefined" && |  | ||||||
|       app.rpc && |  | ||||||
|       typeof app.rpc.updateMessageText === "function" |  | ||||||
|     ) { |  | ||||||
|       app.rpc.updateMessageText(this.messageUid, this.replaceMentionsWithAuthors(this.value)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   updateStatus() { |  | ||||||
|     if (this.liveType) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) > 1) { |  | ||||||
|       this.lastUpdateEvent = new Date(); |  | ||||||
|       if ( |  | ||||||
|         typeof app !== "undefined" && |  | ||||||
|         app.rpc && |  | ||||||
|         typeof app.rpc.set_typing === "function" |  | ||||||
|       ) { |  | ||||||
|         app.rpc.set_typing(this.channelUid, this.user.color); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   update() { |  | ||||||
|     const expired = |  | ||||||
|       this.trackSecondsBetweenEvents(this.lastChange, new Date()) >= |  | ||||||
|       this.liveTypeInterval; |  | ||||||
|     const changed = this.value !== this.previousValue; |  | ||||||
| 
 |  | ||||||
|     if (changed || expired) { |  | ||||||
|       this.lastChange = new Date(); |  | ||||||
|       this.updateStatus(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     this.previousValue = this.value; |  | ||||||
| 
 |  | ||||||
|     if (this.liveType && expired) { |  | ||||||
|       this.value = ""; |  | ||||||
|       this.previousValue = ""; |  | ||||||
|       this.messageUid = null; |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (changed) { |  | ||||||
|       if (this.liveType) { |  | ||||||
|         this.updateMessage(); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 BordedDev
						BordedDev