mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-05-20 12:48:50 +00:00
replace the main futoji message formatter with markdown-it plugins
This commit is contained in:
parent
8904a9254b
commit
5db33c4e7c
5 changed files with 178 additions and 112 deletions
|
|
@ -13,6 +13,8 @@
|
|||
"futoji": "^0.5.0",
|
||||
"highlight.js": "^9.15.8",
|
||||
"jquery": "^3.4.0",
|
||||
"markdown-it": "^9.0.1",
|
||||
"markdown-it-chat-formatter": "^0.1.1",
|
||||
"match-sorter": "^2.3.0",
|
||||
"particles.js": "^2.0.0",
|
||||
"socket.io": "^2.2.0",
|
||||
|
|
|
|||
|
|
@ -452,11 +452,18 @@ export default {
|
|||
.msg-link {
|
||||
color: rgb(86, 159, 253);
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.codeblock {
|
||||
background-color: rgba(0, 0, 0, 0.397);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
img.emoji {
|
||||
height: 1.7em;
|
||||
width: auto;
|
||||
|
|
|
|||
92
src/utils/markdown-it-plugins/replaceCustomEmoji.js
Normal file
92
src/utils/markdown-it-plugins/replaceCustomEmoji.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import config from "@/config.js";
|
||||
|
||||
/* 58: ':' */
|
||||
/* 60: '<' */
|
||||
/* 62: '>' */
|
||||
|
||||
function render_custom_emoji(tokens, idx) {
|
||||
return ':3'
|
||||
}
|
||||
|
||||
function parseUntil(state, fromPos, until) {
|
||||
let max = state.posMax
|
||||
let found = false
|
||||
|
||||
let oldPos = state.pos
|
||||
// let start = nameStart + 1
|
||||
state.pos = fromPos
|
||||
let end = -1
|
||||
|
||||
while(state.pos++ < max) {
|
||||
let marker = state.src.charCodeAt(state.pos)
|
||||
if(marker === until) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(found) {
|
||||
end = state.pos
|
||||
}
|
||||
|
||||
state.pos = oldPos
|
||||
|
||||
return end
|
||||
}
|
||||
|
||||
function parseEmojiName(state, nameStart) {
|
||||
return parseUntil(state, nameStart, 58)
|
||||
}
|
||||
|
||||
function replace_custom_emoji(state, silent) {
|
||||
let pos = state.pos
|
||||
let max = state.posMax
|
||||
|
||||
// if begins with <
|
||||
if (state.src.charCodeAt(pos) !== 60) { return false; }
|
||||
pos += 1
|
||||
|
||||
// if the next character is not ':' then it's not a custom emoji
|
||||
if(state.src.charCodeAt(pos) !== 58) { return false; }
|
||||
|
||||
// parse the emoji name
|
||||
let nameStart = pos + 1
|
||||
let nameEnd = parseEmojiName(state, nameStart)
|
||||
|
||||
// parser failed to find another ':', so it's not a valid emoji
|
||||
if(nameEnd < 0 || nameEnd - nameStart <= 1) { return false; }
|
||||
|
||||
let emojiName = state.src.slice(nameStart, nameEnd)
|
||||
|
||||
pos = nameEnd + 1
|
||||
|
||||
// parse until '>'
|
||||
let idStart = pos
|
||||
let idEnd = parseUntil(state, idStart, 62)
|
||||
|
||||
if(idEnd < 0 || idEnd - idStart <= 1) { return false; }
|
||||
|
||||
let emojiID = state.src.slice(idStart, idEnd)
|
||||
|
||||
if(!silent) {
|
||||
state.pos = idStart
|
||||
state.posMax = idEnd
|
||||
|
||||
let token = state.push('custom_emoji_open', 'img', 1);
|
||||
token.attrs = [[ 'src', `${config.domain}/files/${emojiID}` ]]
|
||||
|
||||
// state.md.inline.tokenize(state)
|
||||
}
|
||||
|
||||
state.pos = idEnd + 1
|
||||
state.posMax = max
|
||||
return true
|
||||
}
|
||||
export default function custom_emoji_plugin(md, opts) {
|
||||
md.renderer.rules.custom_emoji_open = (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])} />`
|
||||
}
|
||||
|
||||
md.inline.ruler.push('custom_emoji', replace_custom_emoji)
|
||||
}
|
||||
|
|
@ -3,7 +3,30 @@ import twemoji from 'twemoji'
|
|||
import emojiParser from '@/utils/emojiParser';
|
||||
import config from "@/config.js";
|
||||
|
||||
const futoji = new Formatter();
|
||||
import customEmoji from './markdown-it-plugins/replaceCustomEmoji'
|
||||
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
import MarkdownIt from 'markdown-it'
|
||||
import chatPlugin from 'markdown-it-chat-formatter/dist-src/plugin'
|
||||
|
||||
const markdown = new MarkdownIt({
|
||||
highlight: function (str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return '<div class="codeblock"><code>' +
|
||||
hljs.highlight(lang, str, true).value +
|
||||
'</code></div>';
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return '<div class="codeblock"><code>' + markdown.utils.escapeHtml(str) + '</code></div>';
|
||||
}
|
||||
}).use(chatPlugin)
|
||||
.use(customEmoji);
|
||||
|
||||
const emojiFormatter = new Formatter();
|
||||
|
||||
emojiFormatter.addTransformer({
|
||||
|
|
@ -23,116 +46,11 @@ function owo (text) {
|
|||
}
|
||||
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'custom emoji',
|
||||
symbol: ':',
|
||||
padding: false,
|
||||
recursive: false,
|
||||
validate: text => /.+?&(.+?)/.test(text),
|
||||
transformer: text => {
|
||||
const formattedInner = emojiFormatter.format(text);
|
||||
return owo(formattedInner);
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'url',
|
||||
open: 'http',
|
||||
close: ' ',
|
||||
recursive: false,
|
||||
validate: text => /(https?:\/\/[^\s]+)/g.test('http' + text),
|
||||
transformer: text => '<a class="msg-link" target="_blank" href="http' + text + '">http' + text + '</a> '
|
||||
})
|
||||
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold-and-italic',
|
||||
symbol: '***',
|
||||
transformer: text => `<strong><em>${text}</em></strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold',
|
||||
symbol: '**',
|
||||
transformer: text => `<strong>${text}</strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '*',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'underline',
|
||||
symbol: '__',
|
||||
transformer: text => `<u>${text}</u>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '_',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'srike',
|
||||
symbol: '~~',
|
||||
transformer: text => `<s>${text.trim()}</s>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code-block',
|
||||
symbol: '```',
|
||||
recursive: false,
|
||||
transformer: text => `<div class="codeblock"><code>${formatCode(text).trim()}</code></div>`,
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code',
|
||||
symbol: '`',
|
||||
recursive: false,
|
||||
transformer: text => `<code>${text}</code>`,
|
||||
})
|
||||
|
||||
export default (message) => {
|
||||
|
||||
message = futoji.format(escapeHtml(message + ' ')).trim();
|
||||
message = markdown.render(message).trim();
|
||||
|
||||
message = emojiParser.replaceEmojis(message);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* format code to add syntax highlighting
|
||||
*/
|
||||
function formatCode(text) {
|
||||
// matches if word until newline
|
||||
// if spaces then it won't match
|
||||
let nameRegex = new RegExp('^(\\w+)\\s')
|
||||
|
||||
if (nameRegex.test(text)) {
|
||||
let language = nameRegex.exec(text)[1]
|
||||
let newText = text.replace(nameRegex, '')
|
||||
|
||||
// TODO: format newText with language
|
||||
|
||||
return newText
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
function escapeHtml(unsafe) {
|
||||
return unsafe
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
57
yarn.lock
57
yarn.lock
|
|
@ -1552,10 +1552,10 @@ aws4@^1.8.0:
|
|||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
||||
|
||||
axios@^0.18.0:
|
||||
version "0.18.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
|
||||
integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
|
||||
axios@^0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
|
||||
integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
is-buffer "^2.0.2"
|
||||
|
|
@ -3171,7 +3171,7 @@ enhanced-resolve@^4.1.0:
|
|||
memory-fs "^0.4.0"
|
||||
tapable "^1.0.0"
|
||||
|
||||
entities@^1.1.1:
|
||||
entities@^1.1.1, entities@~1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
|
||||
integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
|
||||
|
|
@ -4990,6 +4990,13 @@ levn@^0.3.0, levn@~0.3.0:
|
|||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
linkify-it@^2.0.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
|
||||
integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
|
||||
dependencies:
|
||||
uc.micro "^1.0.1"
|
||||
|
||||
load-json-file@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
|
||||
|
|
@ -5180,6 +5187,36 @@ map-visit@^1.0.0:
|
|||
dependencies:
|
||||
object-visit "^1.0.0"
|
||||
|
||||
markdown-it-chat-formatter@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-chat-formatter/-/markdown-it-chat-formatter-0.1.1.tgz#76a24a6599925ae22cdbf179301c6152867b1848"
|
||||
integrity sha512-RIGKubGe3wjvizsTqeeU+RIVS7b1bqAwZE0Xv7H15uxZxf3pdLQjpX+ATcInPkf1L2SY4Vl2do8nSliLBCutag==
|
||||
dependencies:
|
||||
markdown-it "^9.0.1"
|
||||
markdown-it-underline "^1.0.1"
|
||||
marked "^0.7.0"
|
||||
|
||||
markdown-it-underline@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it-underline/-/markdown-it-underline-1.0.1.tgz#43a54a541d95d739b43157701f1da306d7c300b2"
|
||||
integrity sha1-Q6VKVB2V1zm0MVdwHx2jBtfDALI=
|
||||
|
||||
markdown-it@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.0.1.tgz#aafe363c43718720b6575fd10625cde6e4ff2d47"
|
||||
integrity sha512-XC9dMBHg28Xi7y5dPuLjM61upIGPJG8AiHNHYqIaXER2KNnn7eKnM5/sF0ImNnyoV224Ogn9b1Pck8VH4k0bxw==
|
||||
dependencies:
|
||||
argparse "^1.0.7"
|
||||
entities "~1.1.1"
|
||||
linkify-it "^2.0.0"
|
||||
mdurl "^1.0.1"
|
||||
uc.micro "^1.0.5"
|
||||
|
||||
marked@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
|
||||
integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==
|
||||
|
||||
match-sorter@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-2.3.0.tgz#99eaf386689f75bf976f6bbf7f49afb9a7ffecc8"
|
||||
|
|
@ -5201,6 +5238,11 @@ mdn-data@~1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-1.1.4.tgz#50b5d4ffc4575276573c4eedb8780812a8419f01"
|
||||
integrity sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==
|
||||
|
||||
mdurl@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||
integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=
|
||||
|
||||
media-typer@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
|
|
@ -8151,6 +8193,11 @@ typedarray@^0.0.6:
|
|||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
uc.micro@^1.0.1, uc.micro@^1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
|
||||
integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
|
||||
|
||||
uglify-js@3.4.x:
|
||||
version "3.4.10"
|
||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
|
||||
|
|
|
|||
Loading…
Reference in a new issue