mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-07-04 18:40:39 +00:00
increase emoji-parsing performance
This commit is contained in:
parent
5db33c4e7c
commit
4393095af4
1 changed files with 41 additions and 21 deletions
|
|
@ -3,39 +3,52 @@ import config from "@/config.js";
|
||||||
/* 58: ':' */
|
/* 58: ':' */
|
||||||
/* 60: '<' */
|
/* 60: '<' */
|
||||||
/* 62: '>' */
|
/* 62: '>' */
|
||||||
|
/* example: '<:cat_1:1hvDmIdozFp2vTTkEIsO-wBHPaYRkGmlP>' */
|
||||||
|
|
||||||
function render_custom_emoji(tokens, idx) {
|
function skipUntil(state, pos, code) {
|
||||||
return ':3'
|
for (let max = state.src.length; pos < max; pos++) {
|
||||||
|
if (state.src.charCodeAt(pos) === code) { break; }
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseUntil(state, fromPos, until) {
|
// old
|
||||||
|
function parseUntil(state, fromPos, until, maxLength = 16) {
|
||||||
let max = state.posMax
|
let max = state.posMax
|
||||||
let found = false
|
let found = false
|
||||||
|
let pos = state.pos + fromPos
|
||||||
let oldPos = state.pos
|
let oldPos = state.pos
|
||||||
// let start = nameStart + 1
|
|
||||||
state.pos = fromPos
|
|
||||||
let end = -1
|
let end = -1
|
||||||
|
|
||||||
while(state.pos++ < max) {
|
|
||||||
let marker = state.src.charCodeAt(state.pos)
|
while(pos < max && pos - oldPos < maxLength) {
|
||||||
|
let marker = state.src.charCodeAt(pos)
|
||||||
if(marker === until) {
|
if(marker === until) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// state.md.inline.skipToken(state);
|
||||||
|
|
||||||
|
pos += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if(found) {
|
if(found) {
|
||||||
end = state.pos
|
end = pos
|
||||||
}
|
}
|
||||||
|
|
||||||
state.pos = oldPos
|
|
||||||
|
|
||||||
return end
|
return end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function render_custom_emoji(tokens, idx) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function parseEmojiName(state, nameStart) {
|
function parseEmojiName(state, nameStart) {
|
||||||
return parseUntil(state, nameStart, 58)
|
// return parseUntil(state, nameStart, 58)
|
||||||
|
|
||||||
|
return skipUntil(state, nameStart, 58)
|
||||||
}
|
}
|
||||||
|
|
||||||
function replace_custom_emoji(state, silent) {
|
function replace_custom_emoji(state, silent) {
|
||||||
|
|
@ -53,8 +66,10 @@ function replace_custom_emoji(state, silent) {
|
||||||
let nameStart = pos + 1
|
let nameStart = pos + 1
|
||||||
let nameEnd = parseEmojiName(state, nameStart)
|
let nameEnd = parseEmojiName(state, nameStart)
|
||||||
|
|
||||||
|
// console.log(nameEnd, parseUntil(state,nameStart,58))
|
||||||
|
|
||||||
// parser failed to find another ':', so it's not a valid emoji
|
// parser failed to find another ':', so it's not a valid emoji
|
||||||
if(nameEnd < 0 || nameEnd - nameStart <= 1) { return false; }
|
if(nameEnd > max || nameEnd < 0 || nameEnd - nameStart <= 1) { return false; }
|
||||||
|
|
||||||
let emojiName = state.src.slice(nameStart, nameEnd)
|
let emojiName = state.src.slice(nameStart, nameEnd)
|
||||||
|
|
||||||
|
|
@ -62,9 +77,9 @@ function replace_custom_emoji(state, silent) {
|
||||||
|
|
||||||
// parse until '>'
|
// parse until '>'
|
||||||
let idStart = pos
|
let idStart = pos
|
||||||
let idEnd = parseUntil(state, idStart, 62)
|
let idEnd = skipUntil(state, pos, 62);
|
||||||
|
|
||||||
if(idEnd < 0 || idEnd - idStart <= 1) { return false; }
|
if(idEnd > max || idEnd < 0 || idEnd - idStart <= 1) { return false; }
|
||||||
|
|
||||||
let emojiID = state.src.slice(idStart, idEnd)
|
let emojiID = state.src.slice(idStart, idEnd)
|
||||||
|
|
||||||
|
|
@ -72,20 +87,25 @@ function replace_custom_emoji(state, silent) {
|
||||||
state.pos = idStart
|
state.pos = idStart
|
||||||
state.posMax = idEnd
|
state.posMax = idEnd
|
||||||
|
|
||||||
let token = state.push('custom_emoji_open', 'img', 1);
|
let token = state.push('custom_emoji', 'img', 0);
|
||||||
token.attrs = [[ 'src', `${config.domain}/files/${emojiID}` ]]
|
token.attrs = [[ 'src', `${config.domain}/files/${emojiID}` ], [ 'alt', emojiName ]]
|
||||||
|
|
||||||
// state.md.inline.tokenize(state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.pos = idEnd + 1
|
state.pos = idEnd + 1
|
||||||
state.posMax = max
|
state.posMax = max
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function custom_emoji_plugin(md, opts) {
|
export default function custom_emoji_plugin(md, opts) {
|
||||||
md.renderer.rules.custom_emoji_open = (tokens, idx) => {
|
md.renderer.rules.custom_emoji = (tokens, idx) => {
|
||||||
let token = tokens[idx]
|
let token = tokens[idx]
|
||||||
return `<${md.utils.escapeHtml(token.tag)} class="emoji" src=${md.utils.escapeHtml(token.attrs.find(([name]) => name === 'src')[1])} />`
|
|
||||||
|
// todo: better escaping method,
|
||||||
|
// even if this is good and covers most cases, there may be edge cases where DOMPurify may be better
|
||||||
|
let src = md.utils.escapeHtml(token.attrs.find(([name]) => name === 'src')[1])
|
||||||
|
let alt = md.utils.escapeHtml(token.attrs.find(([name]) => name === 'alt')[1])
|
||||||
|
|
||||||
|
return `<${md.utils.escapeHtml(token.tag)} class="emoji" title=${alt} alt=${alt} src=${src} />`
|
||||||
}
|
}
|
||||||
|
|
||||||
md.inline.ruler.push('custom_emoji', replace_custom_emoji)
|
md.inline.ruler.push('custom_emoji', replace_custom_emoji)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue