mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-07-05 11:00:50 +00:00
improved emoji suggestions open method
This commit is contained in:
parent
7ba62da699
commit
41ce5ae36a
5 changed files with 206 additions and 101 deletions
|
|
@ -3,33 +3,34 @@
|
||||||
<div class="change-log">
|
<div class="change-log">
|
||||||
<span class="news-title">Changes in this release</span>
|
<span class="news-title">Changes in this release</span>
|
||||||
|
|
||||||
<div class="change">
|
<div class="change" v-for="(change, index) in changelog" :key="change.title">
|
||||||
<div class="date">{{changelog.date}}</div>
|
<div :class="`heading ${index === 0 ? 'latest': ''}`">
|
||||||
<div class="changes-title">{{changelog.title}}</div>
|
<div class="date">{{change.date}}</div>
|
||||||
|
<div class="changes-title">{{change.title}}</div>
|
||||||
|
</div>
|
||||||
<div class="information">
|
<div class="information">
|
||||||
|
<div v-if="change.new">
|
||||||
<div v-if="changelog.new">
|
<strong>What's new?</strong>
|
||||||
<strong>What's new?</strong><br>
|
<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(wnew, index) in changelog.new" :key="index">{{wnew}}</li>
|
<li v-for="(wnew, index) in change.new" :key="index">{{wnew}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="changelog.fix">
|
<div v-if="change.fix">
|
||||||
<strong>Issues fixed</strong><br>
|
<strong>Issues fixed</strong>
|
||||||
|
<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(wfix, index) in changelog.fix" :key="index">{{wfix}}</li>
|
<li v-for="(wfix, index) in change.fix" :key="index">{{wfix}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="changelog.next">
|
<div v-if="change.next">
|
||||||
<strong>Up next</strong><br>
|
<strong>Up next</strong>
|
||||||
|
<br>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="(wnext, index) in changelog.next" :key="index">{{wnext}}</li>
|
<li v-for="(wnext, index) in change.next" :key="index">{{wnext}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="changelog.msg">
|
<div v-if="change.msg">{{change.msg}}</div>
|
||||||
{{changelog.msg}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -38,39 +39,36 @@
|
||||||
<span class="news-title">Planned Features</span>
|
<span class="news-title">Planned Features</span>
|
||||||
<p>Features that are coming soon:</p>
|
<p>Features that are coming soon:</p>
|
||||||
<ul class="plan-list">
|
<ul class="plan-list">
|
||||||
<li>Online, Offline status (Done)</li>
|
<li>Online, Offline status(Done)</li>
|
||||||
<li>Profile picture</li>
|
<li>Profile picture (done)</li>
|
||||||
<li>Typing indicator</li>
|
<li>Typing indicator (done)</li>
|
||||||
<li>Sending files</li>
|
<li>Sending files (done)</li>
|
||||||
<li>Custom emojis</li>
|
<li>Custom emojis</li>
|
||||||
<li>Guilds</li>
|
<li>Guilds</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Spinner from '@/components/Spinner.vue'
|
import Spinner from "@/components/Spinner.vue";
|
||||||
import ChangeLog from '@/components/ChangeLog.vue'
|
import changelog from "@/utils/changelog.js";
|
||||||
import changelog from '@/utils/changelog.js'
|
|
||||||
export default {
|
export default {
|
||||||
components: {},
|
components: {},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
changelog: changelog[0]
|
changelog: changelog
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
||||||
.news {
|
.news {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin:20px;
|
margin: 20px;
|
||||||
color: white;
|
color: white;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
@ -83,21 +81,35 @@ export default {
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
border-bottom: solid 1px white;
|
border-bottom: solid 1px white;
|
||||||
}
|
}
|
||||||
.todo-list{
|
.todo-list {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
background: rgba(0, 0, 0, 0.137);
|
background: rgba(0, 0, 0, 0.137);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
.change-log{
|
.change {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: solid 1px white;
|
||||||
|
}
|
||||||
|
.heading{
|
||||||
|
padding: 10px;
|
||||||
|
background: rgba(0, 0, 0, 0.555);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.heading.latest {
|
||||||
|
background: rgba(38, 139, 255, 0.87);
|
||||||
|
}
|
||||||
|
.change-log {
|
||||||
background: rgba(0, 0, 0, 0.137);
|
background: rgba(0, 0, 0, 0.137);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.plan-list{
|
.plan-list {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
.date{
|
.date {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin-right: 50px;
|
margin-right: 50px;
|
||||||
color: rgba(255, 255, 255, 0.692);
|
color: rgba(255, 255, 255, 0.692);
|
||||||
|
|
@ -114,12 +126,11 @@ export default {
|
||||||
.news {
|
.news {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
.todo-list{
|
.todo-list {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
.change-log {
|
.change-log {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
<span v-else>{{channelName}}</span>
|
<span v-else>{{channelName}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="loading" v-if="selectedChannelID && !messages[selectedChannelID]">
|
<div class="loading" v-if="selectedChannelID && !selectedChannelMessages">
|
||||||
<spinner/>
|
<spinner/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="selectedChannelID" class="message-logs" @wheel="invertScroll">
|
<div v-else-if="selectedChannelID" class="message-logs" @wheel="invertScroll">
|
||||||
<div class="scroll">
|
<div class="scroll">
|
||||||
<message
|
<message
|
||||||
v-for="(msg, index) in messages[selectedChannelID]"
|
v-for="(msg, index) in selectedChannelMessages"
|
||||||
:key="index"
|
:key="index"
|
||||||
:date="msg.created"
|
:date="msg.created"
|
||||||
:admin="msg.creator.admin"
|
:admin="msg.creator.admin"
|
||||||
|
|
@ -29,11 +29,12 @@
|
||||||
<uploadsQueue v-if="uploadQueue !== undefined" :queue="uploadQueue"/>
|
<uploadsQueue v-if="uploadQueue !== undefined" :queue="uploadQueue"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<news v-if="!selectedChannelID && !messages[selectedChannelID]"/>
|
<news v-if="!selectedChannelID "/>
|
||||||
<div class="chat-input-area" v-if="selectedChannelID">
|
<div class="chat-input-area" v-if="selectedChannelID">
|
||||||
<div class="emoji-suggestion-outer" v-if="showEmojiSuggestions">
|
<div class="emoji-suggestion-outer" v-if="showEmojiSuggestions">
|
||||||
<emoji-suggestions :emojiArray="emojiSuggestionsArray"/>
|
<emoji-suggestions :emojiArray="emojiSuggestionsArray"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="message-area">
|
<div class="message-area">
|
||||||
<input type="file" ref="sendFileBrowse" @change="attachmentChange" class="hidden">
|
<input type="file" ref="sendFileBrowse" @change="attachmentChange" class="hidden">
|
||||||
<div class="attachment-button" @click="attachmentButton">
|
<div class="attachment-button" @click="attachmentButton">
|
||||||
|
|
@ -44,8 +45,8 @@
|
||||||
rows="1"
|
rows="1"
|
||||||
ref="input-box"
|
ref="input-box"
|
||||||
placeholder="Message"
|
placeholder="Message"
|
||||||
@keydown="chatInput"
|
@keydown="keyDown"
|
||||||
@keyup="delayedResize"
|
@keyup="keyUp"
|
||||||
@change="resize"
|
@change="resize"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
v-model="message"
|
v-model="message"
|
||||||
|
|
@ -131,6 +132,7 @@ export default {
|
||||||
|
|
||||||
if (this.message == "") return;
|
if (this.message == "") return;
|
||||||
if (this.message.length > 5000) return;
|
if (this.message.length > 5000) return;
|
||||||
|
this.showEmojiSuggestions = false;
|
||||||
clearInterval(this.postTimerID);
|
clearInterval(this.postTimerID);
|
||||||
this.postTimerID = null;
|
this.postTimerID = null;
|
||||||
this.messageLength = 0;
|
this.messageLength = 0;
|
||||||
|
|
@ -150,6 +152,10 @@ export default {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.message = "";
|
this.message = "";
|
||||||
|
|
||||||
|
let input = this.$refs["input-box"];
|
||||||
|
input.style.height = "1em";
|
||||||
|
|
||||||
this.$store.dispatch("updateChannelLastMessage", this.selectedChannelID);
|
this.$store.dispatch("updateChannelLastMessage", this.selectedChannelID);
|
||||||
const { ok, error, result } = await messagesService.post(
|
const { ok, error, result } = await messagesService.post(
|
||||||
this.selectedChannelID,
|
this.selectedChannelID,
|
||||||
|
|
@ -191,21 +197,52 @@ export default {
|
||||||
input.style.height = `calc(${input.scrollHeight}px - 1em)`;
|
input.style.height = `calc(${input.scrollHeight}px - 1em)`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
delayedResize(event) {
|
emojiSwitchKey(event) {
|
||||||
this.resize(event);
|
if (!this.showEmojiSuggestions) return;
|
||||||
|
|
||||||
|
const keyCode = event.keyCode;
|
||||||
|
|
||||||
|
if (keyCode == 38) {
|
||||||
|
//up
|
||||||
|
bus.$emit("emojiSuggestions:up");
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (keyCode == 40) {
|
||||||
|
//down
|
||||||
|
bus.$emit("emojiSuggestions:down");
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
showEmojiPopout() {
|
GetWordByPos(str, pos) {
|
||||||
const shortcode = this.message.split(" ").pop();
|
let left = str.substr(0, pos);
|
||||||
if (!shortcode || !shortcode.startsWith(":") || shortcode.endsWith(":") || shortcode.length < 3)
|
let right = str.substr(pos);
|
||||||
return (this.showEmojiSuggestions = false);
|
|
||||||
const searchArr = emojiParser.searchEmoji(shortcode.slice(1, -1));
|
left = left.replace(/^.+ /g, "");
|
||||||
|
right = right.replace(/ .+$/g, "");
|
||||||
|
|
||||||
|
return left + right;
|
||||||
|
},
|
||||||
|
showEmojiPopout(event) {
|
||||||
|
if (event.keyCode == 38 || event.keyCode == 40) return; // up/down
|
||||||
|
|
||||||
|
const cursorPosition = event.target.selectionStart;
|
||||||
|
const cursorWord = this.GetWordByPos(this.message, cursorPosition)
|
||||||
|
const cursorLetter = this.message.substring(cursorPosition - 1, cursorPosition)
|
||||||
|
|
||||||
|
if (cursorLetter.trim() == "" || cursorWord.endsWith(":"))
|
||||||
|
return this.showEmojiSuggestions = false;
|
||||||
|
|
||||||
|
if (cursorWord.startsWith(":") && cursorWord.length >= 3) {
|
||||||
|
const searchArr = emojiParser.searchEmoji(cursorWord.slice(1, -1));
|
||||||
if (searchArr.length <= 0) return (this.showEmojiSuggestions = false);
|
if (searchArr.length <= 0) return (this.showEmojiSuggestions = false);
|
||||||
this.showEmojiSuggestions = true;
|
|
||||||
this.emojiSuggestionsArray = searchArr;
|
this.emojiSuggestionsArray = searchArr;
|
||||||
|
this.showEmojiSuggestions = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async onInput(event) {
|
async onInput(event) {
|
||||||
this.showEmojiPopout();
|
this.resize(event);
|
||||||
this.delayedResize(event);
|
|
||||||
this.messageLength = this.message.length;
|
this.messageLength = this.message.length;
|
||||||
const value = event.target.value.trim();
|
const value = event.target.value.trim();
|
||||||
if (value && this.postTimerID == null) {
|
if (value && this.postTimerID == null) {
|
||||||
|
|
@ -213,9 +250,13 @@ export default {
|
||||||
await typingService.post(this.selectedChannelID);
|
await typingService.post(this.selectedChannelID);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
chatInput(event) {
|
keyUp(event) {
|
||||||
this.delayedResize(event);
|
this.resize(event);
|
||||||
|
this.showEmojiPopout(event);
|
||||||
|
},
|
||||||
|
keyDown(event) {
|
||||||
|
this.resize(event);
|
||||||
|
this.emojiSwitchKey(event);
|
||||||
// when enter is press
|
// when enter is press
|
||||||
if (event.keyCode == 13) {
|
if (event.keyCode == 13) {
|
||||||
// and the shift key is not held
|
// and the shift key is not held
|
||||||
|
|
@ -331,8 +372,9 @@ export default {
|
||||||
channel() {
|
channel() {
|
||||||
return this.$store.getters.channels[this.selectedChannelID];
|
return this.$store.getters.channels[this.selectedChannelID];
|
||||||
},
|
},
|
||||||
messages() {
|
selectedChannelMessages() {
|
||||||
return this.$store.getters.messages;
|
const selectedChannel = this.$store.getters.selectedChannelID;
|
||||||
|
return this.$store.getters.messages[selectedChannel];
|
||||||
},
|
},
|
||||||
selectedChannelID() {
|
selectedChannelID() {
|
||||||
return this.$store.getters.selectedChannelID;
|
return this.$store.getters.selectedChannelID;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,75 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="emoji-suggetions-list">
|
<div class="emoji-suggetions-list">
|
||||||
<div class="emoji" v-for="emoji in $props.emojiArray" :key="emoji.hexcode">
|
<div
|
||||||
<div class="preview">{{emoji.unicode}}</div>
|
v-for="(emoji, index) in $props.emojiArray.slice(0,10)"
|
||||||
|
:class="{emoji: true, selected: index === selectedIndex}"
|
||||||
|
@mouseover="hoverEvent"
|
||||||
|
:key="emoji.hexcode"
|
||||||
|
>
|
||||||
|
<div class="preview" v-html="emojiParser(emoji.unicode)"></div>
|
||||||
<div class="short-code">:{{emoji.shortcodes[0]}}:</div>
|
<div class="short-code">:{{emoji.shortcodes[0]}}:</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { bus } from "@/main";
|
||||||
|
import emojiParser from "@/utils/emojiParser.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: ['emojiArray'],
|
props: ["emojiArray"],
|
||||||
methods: {},
|
data() {
|
||||||
computed: {}
|
return {
|
||||||
|
selectedIndex: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
emojiParser(emoji) {
|
||||||
|
return emojiParser.replaceEmojis(emoji);
|
||||||
|
},
|
||||||
|
hoverEvent(event) {
|
||||||
|
const emoji = event.target.closest(".emoji");
|
||||||
|
const parent = event.target.parentElement.children;
|
||||||
|
if (!emoji || !emoji) return;
|
||||||
|
const index = [...parent].findIndex(el => el === emoji);
|
||||||
|
if (index >= 0) this.selectedIndex = index;
|
||||||
|
},
|
||||||
|
KeySwitch(key) {
|
||||||
|
if (key == "up") {
|
||||||
|
if (this.selectedIndex == 0)
|
||||||
|
return (this.selectedIndex =
|
||||||
|
this.$props.emojiArray.slice(0, 10).length - 1);
|
||||||
|
|
||||||
|
this.selectedIndex--;
|
||||||
|
}
|
||||||
|
if (key == "down") {
|
||||||
|
if (
|
||||||
|
this.selectedIndex ==
|
||||||
|
this.$props.emojiArray.slice(0, 10).length - 1
|
||||||
|
)
|
||||||
|
return (this.selectedIndex = 0);
|
||||||
|
|
||||||
|
this.selectedIndex++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
bus.$on("emojiSuggestions:up", () => this.KeySwitch("up"));
|
||||||
|
bus.$on("emojiSuggestions:down", () => this.KeySwitch("down"));
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
emojiArray() {
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.emoji-suggetions-list{
|
.selected {
|
||||||
|
background: rgba(66, 66, 66, 0.89);
|
||||||
|
}
|
||||||
|
.emoji-suggetions-list {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 70px;
|
left: 70px;
|
||||||
|
|
@ -36,24 +84,27 @@ export default {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.emoji-suggetions-list:hover{
|
.emoji-suggetions-list:hover {
|
||||||
background: rgba(32, 32, 32, 0.966);
|
background: rgba(32, 32, 32, 0.966);
|
||||||
}
|
}
|
||||||
.preview{
|
.preview {
|
||||||
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
.name{
|
.name {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
.short-code {
|
.short-code {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
.emoji{
|
.emoji {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
.emoji.selected {
|
@media (max-height: 441px) {
|
||||||
|
.emoji-suggetions-list {
|
||||||
|
max-height: 150px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import twemoji from "twemoji";
|
||||||
import emojis from "emojibase-data/en/compact.json";
|
import emojis from "emojibase-data/en/compact.json";
|
||||||
import matchSorter from "match-sorter";
|
import matchSorter from "match-sorter";
|
||||||
import {
|
import {
|
||||||
|
|
@ -15,17 +16,15 @@ export default {
|
||||||
return x
|
return x
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
replaceEmojis: (string) => {
|
||||||
|
return twemoji.parse(string,
|
||||||
|
function (icon, options, variant) {
|
||||||
|
if (!icon) return string;
|
||||||
|
return require("twemoji/2/svg/" + icon + ".svg")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
searchEmoji: (shortCode) => {
|
searchEmoji: (shortCode) => {
|
||||||
let array = []
|
|
||||||
for (let index = 0; index < emojis.length; index++) {
|
|
||||||
const element = emojis[index];
|
|
||||||
for (let i = 0; i < element.shortcodes.length; i++) {
|
|
||||||
const el2 = element.shortcodes[i];
|
|
||||||
if (el2.includes(shortCode)) array.push(element);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return matchSorter(emojis, shortCode, {keys: ['shortcodes']});
|
return matchSorter(emojis, shortCode, {keys: ['shortcodes']});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
import futoji from 'futoji'
|
import futoji from 'futoji'
|
||||||
import twemoji from 'twemoji'
|
import twemoji from 'twemoji'
|
||||||
|
import emojiParser from '@/utils/emojiParser';
|
||||||
|
|
||||||
|
|
||||||
export default (message) => {
|
export default (message) => {
|
||||||
|
|
||||||
|
|
||||||
message = twemoji.parse(escapeHtml(message),
|
|
||||||
function (icon, options, variant) {
|
|
||||||
if (!icon) return message;
|
|
||||||
return require("twemoji/2/svg/" + icon + ".svg")
|
|
||||||
})
|
|
||||||
|
|
||||||
futoji.addTransformer({
|
futoji.addTransformer({
|
||||||
name: 'bold-and-italic',
|
name: 'bold-and-italic',
|
||||||
|
|
@ -58,7 +54,13 @@ export default (message) => {
|
||||||
recursive: false,
|
recursive: false,
|
||||||
transformer: text => `<code>${text}</code>`,
|
transformer: text => `<code>${text}</code>`,
|
||||||
})
|
})
|
||||||
return futoji.format(message);
|
|
||||||
|
|
||||||
|
message = futoji.format(escapeHtml(message));
|
||||||
|
|
||||||
|
message = emojiParser.replaceEmojis(message);
|
||||||
|
|
||||||
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue