Merge pull request 'Refactored message logic to fix issues where they desync' (#51) from BordedDev/snek:bugfix/typing-desync into main
Reviewed-on: retoor/snek#51
This commit is contained in:
		
						commit
						31d08ec973
					
				@ -2,29 +2,27 @@ import { app } from "../app.js";
 | 
			
		||||
 | 
			
		||||
class ChatInputComponent extends HTMLElement {
 | 
			
		||||
  autoCompletions = {
 | 
			
		||||
    "example 1": () => {},
 | 
			
		||||
    "example 2": () => {},
 | 
			
		||||
    "example 1": () => {
 | 
			
		||||
    },
 | 
			
		||||
    "example 2": () => {
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
  hiddenCompletions = {
 | 
			
		||||
    "/starsRender": () => {
 | 
			
		||||
        app.rpc.starsRender(this.channelUid,this.value.replace("/starsRender ",""))
 | 
			
		||||
      app.rpc.starsRender(this.channelUid, this.value.replace("/starsRender ", ""))
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  users = []
 | 
			
		||||
  textarea = null
 | 
			
		||||
  _value = ""
 | 
			
		||||
  lastUpdateEvent = null
 | 
			
		||||
  previousValue = "" 
 | 
			
		||||
  lastChange = null 
 | 
			
		||||
  changed = false 
 | 
			
		||||
  expiryTimer = null;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super();
 | 
			
		||||
    this.lastUpdateEvent = new Date();
 | 
			
		||||
    this.textarea = document.createElement("textarea");
 | 
			
		||||
    this.value = this.getAttribute("value") || "";
 | 
			
		||||
    this.previousValue = this.value;
 | 
			
		||||
    this.lastChange = new Date();
 | 
			
		||||
    this.changed = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get value() {
 | 
			
		||||
@ -32,24 +30,27 @@ class ChatInputComponent extends HTMLElement {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set value(value) {
 | 
			
		||||
    this._value = value || "";
 | 
			
		||||
    this._value = value;
 | 
			
		||||
    this.textarea.value = this._value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get allAutoCompletions() {
 | 
			
		||||
     return Object.assign({},this.autoCompletions,this.hiddenCompletions) 
 | 
			
		||||
    return Object.assign({}, this.autoCompletions, this.hiddenCompletions)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resolveAutoComplete() {
 | 
			
		||||
    let count = 0;
 | 
			
		||||
    let value = null;
 | 
			
		||||
 | 
			
		||||
    Object.keys(this.allAutoCompletions).forEach((key) => {
 | 
			
		||||
        if (key.startsWith(this.value.split(" ")[0])) {
 | 
			
		||||
        count++;
 | 
			
		||||
    for (const key of Object.keys(this.allAutoCompletions)) {
 | 
			
		||||
      if (key.startsWith(this.value.split(" ", 1)[0])) {
 | 
			
		||||
        if (value) {
 | 
			
		||||
          return null;
 | 
			
		||||
        }
 | 
			
		||||
        value = key;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    if (count == 1) return value;
 | 
			
		||||
    return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isActive() {
 | 
			
		||||
@ -59,116 +60,102 @@ class ChatInputComponent extends HTMLElement {
 | 
			
		||||
  focus() {
 | 
			
		||||
    this.textarea.focus();
 | 
			
		||||
  }
 | 
			
		||||
    getAuthors(){
 | 
			
		||||
        let authors = []
 | 
			
		||||
        for (let i = 0; i < this.users.length; i++) {
 | 
			
		||||
            authors.push(this.users[i].username)
 | 
			
		||||
            authors.push(this.users[i].nick)
 | 
			
		||||
        }
 | 
			
		||||
        return authors
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 extractMentions(text) {
 | 
			
		||||
  const regex = /@([a-zA-Z0-9_-]+)/g;
 | 
			
		||||
  const mentions = [];
 | 
			
		||||
  let match;
 | 
			
		||||
 | 
			
		||||
  while ((match = regex.exec(text)) !== null) {
 | 
			
		||||
    mentions.push(match[1]);
 | 
			
		||||
  getAuthors() {
 | 
			
		||||
    return this.users.flatMap((user) => [user.username, user.nick])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return mentions;
 | 
			
		||||
}
 | 
			
		||||
    matchMentionsToAuthors(mentions, authors) {
 | 
			
		||||
  return mentions.map(mention => {
 | 
			
		||||
    let closestAuthor = null;
 | 
			
		||||
    let minDistance = Infinity;
 | 
			
		||||
     const lowerMention = mention.toLowerCase();
 | 
			
		||||
  extractMentions(text) {
 | 
			
		||||
    return Array.from(text.matchAll(/@([a-zA-Z0-9_-]+)/g), m => m[1]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
    authors.forEach(author => {
 | 
			
		||||
    const lowerAuthor = author.toLowerCase();
 | 
			
		||||
      let distance = this.levenshteinDistance(lowerMention, lowerAuthor);
 | 
			
		||||
  matchMentionsToAuthors(mentions, authors) {
 | 
			
		||||
    return mentions.map(mention => {
 | 
			
		||||
      let closestAuthor = null;
 | 
			
		||||
      let minDistance = Infinity;
 | 
			
		||||
      const lowerMention = mention.toLowerCase();
 | 
			
		||||
 | 
			
		||||
      authors.forEach(author => {
 | 
			
		||||
        const lowerAuthor = author.toLowerCase();
 | 
			
		||||
        let distance = this.levenshteinDistance(lowerMention, lowerAuthor);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if(!this.isSubsequence(lowerMention,lowerAuthor)) {
 | 
			
		||||
            distance += 10        
 | 
			
		||||
        if (!this.isSubsequence(lowerMention, lowerAuthor)) {
 | 
			
		||||
          distance += 10
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      if (distance < minDistance) {
 | 
			
		||||
        minDistance = distance;
 | 
			
		||||
        closestAuthor = author;
 | 
			
		||||
        if (distance < minDistance) {
 | 
			
		||||
          minDistance = distance;
 | 
			
		||||
          closestAuthor = author;
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      return { mention, closestAuthor, distance: minDistance };
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  levenshteinDistance(a, b) {
 | 
			
		||||
    const matrix = [];
 | 
			
		||||
 | 
			
		||||
    // Initialize the first row and column
 | 
			
		||||
    for (let i = 0; i <= b.length; i++) {
 | 
			
		||||
      matrix[i] = [i];
 | 
			
		||||
    }
 | 
			
		||||
    for (let j = 0; j <= a.length; j++) {
 | 
			
		||||
      matrix[0][j] = j;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Fill in the matrix
 | 
			
		||||
    for (let i = 1; i <= b.length; i++) {
 | 
			
		||||
      for (let j = 1; j <= a.length; j++) {
 | 
			
		||||
        if (b.charAt(i - 1) === a.charAt(j - 1)) {
 | 
			
		||||
          matrix[i][j] = matrix[i - 1][j - 1];
 | 
			
		||||
        } else {
 | 
			
		||||
          matrix[i][j] = Math.min(
 | 
			
		||||
            matrix[i - 1][j] + 1,    // Deletion
 | 
			
		||||
            matrix[i][j - 1] + 1,    // Insertion
 | 
			
		||||
            matrix[i - 1][j - 1] + 1 // Substitution
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return matrix[b.length][a.length];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  replaceMentionsWithAuthors(text) {
 | 
			
		||||
    const authors = this.getAuthors();
 | 
			
		||||
    const mentions = this.extractMentions(text);
 | 
			
		||||
 | 
			
		||||
    const matches = this.matchMentionsToAuthors(mentions, authors);
 | 
			
		||||
    let updatedText = text;
 | 
			
		||||
    matches.forEach(({ mention, closestAuthor }) => {
 | 
			
		||||
      const mentionRegex = new RegExp(`@${mention}`, 'g');
 | 
			
		||||
      updatedText = updatedText.replace(mentionRegex, `@${closestAuthor}`);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return { mention, closestAuthor, distance: minDistance };
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
levenshteinDistance(a, b) {
 | 
			
		||||
  const matrix = [];
 | 
			
		||||
 | 
			
		||||
  // Initialize the first row and column
 | 
			
		||||
  for (let i = 0; i <= b.length; i++) {
 | 
			
		||||
    matrix[i] = [i];
 | 
			
		||||
    return updatedText;
 | 
			
		||||
  }
 | 
			
		||||
  for (let j = 0; j <= a.length; j++) {
 | 
			
		||||
    matrix[0][j] = j;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Fill in the matrix
 | 
			
		||||
  for (let i = 1; i <= b.length; i++) {
 | 
			
		||||
    for (let j = 1; j <= a.length; j++) {
 | 
			
		||||
      if (b.charAt(i - 1) === a.charAt(j - 1)) {
 | 
			
		||||
        matrix[i][j] = matrix[i - 1][j - 1];
 | 
			
		||||
      } else {
 | 
			
		||||
        matrix[i][j] = Math.min(
 | 
			
		||||
          matrix[i - 1][j] + 1,    // Deletion
 | 
			
		||||
          matrix[i][j - 1] + 1,    // Insertion
 | 
			
		||||
          matrix[i - 1][j - 1] + 1 // Substitution
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return matrix[b.length][a.length];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      replaceMentionsWithAuthors(text) {
 | 
			
		||||
    const authors = this.getAuthors();
 | 
			
		||||
  const mentions = this.extractMentions(text);
 | 
			
		||||
  
 | 
			
		||||
  const matches = this.matchMentionsToAuthors(mentions, authors);
 | 
			
		||||
  let updatedText = text;
 | 
			
		||||
  matches.forEach(({ mention, closestAuthor }) => {
 | 
			
		||||
    const mentionRegex = new RegExp(`@${mention}`, 'g');
 | 
			
		||||
      updatedText = updatedText.replace(mentionRegex, `@${closestAuthor}`);
 | 
			
		||||
  });
 | 
			
		||||
  
 | 
			
		||||
  return updatedText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  async connectedCallback() {
 | 
			
		||||
    this.user = null
 | 
			
		||||
    app.rpc.getUser(null).then((user) => {
 | 
			
		||||
        this.user=user
 | 
			
		||||
      this.user = user
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
      const me = this;
 | 
			
		||||
    this.liveType = this.getAttribute("live-type") === "true";
 | 
			
		||||
    this.liveTypeInterval =
 | 
			
		||||
      parseInt(this.getAttribute("live-type-interval")) || 6;
 | 
			
		||||
    this.channelUid = this.getAttribute("channel");
 | 
			
		||||
 | 
			
		||||
    app.rpc.getRecentUsers(this.channelUid).then(users=>{
 | 
			
		||||
        this.users = users    
 | 
			
		||||
    app.rpc.getRecentUsers(this.channelUid).then(users => {
 | 
			
		||||
      this.users = users
 | 
			
		||||
    })
 | 
			
		||||
      this.messageUid = null;
 | 
			
		||||
    this.messageUid = null;
 | 
			
		||||
 | 
			
		||||
    this.classList.add("chat-input");
 | 
			
		||||
 | 
			
		||||
@ -190,13 +177,28 @@ levenshteinDistance(a, b) {
 | 
			
		||||
 | 
			
		||||
    this.textarea.addEventListener("keyup", (e) => {
 | 
			
		||||
      if (e.key === "Enter" && !e.shiftKey) {
 | 
			
		||||
        this.value = "";
 | 
			
		||||
 | 
			
		||||
        const message = this.replaceMentionsWithAuthors(this.value);
 | 
			
		||||
        e.target.value = "";
 | 
			
		||||
 | 
			
		||||
        if (!message) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        let autoCompletionHandler = this.allAutoCompletions[this.value.split(" ", 1)[0]];
 | 
			
		||||
        if (autoCompletionHandler) {
 | 
			
		||||
          autoCompletionHandler();
 | 
			
		||||
          this.value = "";
 | 
			
		||||
          e.target.value = "";
 | 
			
		||||
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.finalizeMessage()
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      this.value = e.target.value;
 | 
			
		||||
      this.changed = true;
 | 
			
		||||
      this.update();
 | 
			
		||||
 | 
			
		||||
      this.updateFromInput(e.target.value);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.textarea.addEventListener("keydown", (e) => {
 | 
			
		||||
@ -213,160 +215,94 @@ levenshteinDistance(a, b) {
 | 
			
		||||
      }
 | 
			
		||||
      if (e.key === "Enter" && !e.shiftKey) {
 | 
			
		||||
        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.focus();
 | 
			
		||||
    });
 | 
			
		||||
    this.addEventListener("uploaded", function (e) {
 | 
			
		||||
      let message = "";
 | 
			
		||||
      e.detail.files.forEach((file) => {
 | 
			
		||||
        message += `[${file.name}](/channel/attachment/${file.relative_url})`;
 | 
			
		||||
      });
 | 
			
		||||
      app.rpc.sendMessage(this.channelUid, message,true);
 | 
			
		||||
      let message = e.detail.files.reduce((message, file) => {
 | 
			
		||||
        return `${message}[${file.name}](/channel/attachment/${file.relative_url})`;
 | 
			
		||||
      }, '');
 | 
			
		||||
      app.rpc.sendMessage(this.channelUid, message, true);
 | 
			
		||||
    });
 | 
			
		||||
    setTimeout(()=>{
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      this.focus();
 | 
			
		||||
    },1000)
 | 
			
		||||
    }, 1000)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackSecondsBetweenEvents(event1Time, event2Time) {
 | 
			
		||||
    const millisecondsDifference = event2Time.getTime() - event1Time.getTime();
 | 
			
		||||
    return millisecondsDifference / 1000;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isSubsequence(s, t) {
 | 
			
		||||
      let i = 0, j = 0;
 | 
			
		||||
      while (i < s.length && j < t.length) {
 | 
			
		||||
        if (s[i] === t[j]) {
 | 
			
		||||
          i++;
 | 
			
		||||
        }
 | 
			
		||||
        j++;
 | 
			
		||||
    let i = 0, j = 0;
 | 
			
		||||
    while (i < s.length && j < t.length) {
 | 
			
		||||
      if (s[i] === t[j]) {
 | 
			
		||||
        i++;
 | 
			
		||||
      }
 | 
			
		||||
      return i === s.length; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  newMessage() {
 | 
			
		||||
    if (!this.messageUid) {
 | 
			
		||||
      this.messageUid = "?";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.value = this.replaceMentionsWithAuthors(this.value);
 | 
			
		||||
    this.sendMessage(this.channelUid, this.value,!this.liveType).then((uid) => {
 | 
			
		||||
        if (this.liveType) {
 | 
			
		||||
            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));
 | 
			
		||||
      j++;
 | 
			
		||||
    }
 | 
			
		||||
    return i === s.length;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  updateStatus() {
 | 
			
		||||
    if (this.liveType) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.trackSecondsBetweenEvents(this.lastUpdateEvent, new Date()) > 1) {
 | 
			
		||||
  flagTyping() {
 | 
			
		||||
    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);
 | 
			
		||||
      app.rpc.set_typing(this.channelUid, this.user.color).catch(() => {
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  finalizeMessage() {
 | 
			
		||||
    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.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) {
 | 
			
		||||
            this.messageUid = uid;
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendMessage(channelUid, value,is_final) {
 | 
			
		||||
  async sendMessage(channelUid, value, is_final) {
 | 
			
		||||
    if (!value.trim()) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
    return await app.rpc.sendMessage(channelUid, value,is_final);
 | 
			
		||||
    return await app.rpc.sendMessage(channelUid, value, is_final);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user