mirror of https://github.com/msgbyte/tailchat
refactor(web): bbcode 消息渲染插件
parent
f59a3fa685
commit
1bfd1c76d6
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"externalDeps": ["react"]
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "@plugins/com.msgbyte.bbcode",
|
||||||
|
"main": "src/index.tsx",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@bbob/parser": "^2.7.0",
|
||||||
|
"url-regex": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import bbcodeParser from './parser';
|
||||||
|
import urlRegex from 'url-regex';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 客户端预处理文本
|
||||||
|
* @param plainText 服务端文本
|
||||||
|
*/
|
||||||
|
export function preProcessLinkText(plainText: string): string {
|
||||||
|
const text = plainText.replace(
|
||||||
|
urlRegex({ exact: false, strict: true }),
|
||||||
|
'[url]$&[/url]'
|
||||||
|
); // 将聊天记录中的url提取成bbcode 需要过滤掉被bbcode包住的部分
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理所有的预处理文本
|
||||||
|
export function preProcessText(plainText: string): string {
|
||||||
|
return bbcodeParser.preProcessText(plainText, preProcessLinkText);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BBCodeProps {
|
||||||
|
plainText: string;
|
||||||
|
}
|
||||||
|
export const BBCode: React.FC<BBCodeProps> = React.memo(({ plainText }) => {
|
||||||
|
const bbcodeComponent = bbcodeParser.render(preProcessText(plainText));
|
||||||
|
|
||||||
|
return <Fragment>{bbcodeComponent}</Fragment>;
|
||||||
|
});
|
||||||
|
BBCode.displayName = 'BBCode';
|
@ -0,0 +1,30 @@
|
|||||||
|
import bbcodeParser from './parser';
|
||||||
|
import type { AstNode } from './type';
|
||||||
|
import _isNil from 'lodash/isNil';
|
||||||
|
|
||||||
|
function bbcodeNodeToPlainText(node: AstNode): string {
|
||||||
|
if (_isNil(node)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof node === 'string') {
|
||||||
|
return String(node);
|
||||||
|
} else {
|
||||||
|
if (node.tag === 'img') {
|
||||||
|
return '[图片]';
|
||||||
|
} else {
|
||||||
|
return (node.content ?? [])
|
||||||
|
.map((sub) => bbcodeNodeToPlainText(sub))
|
||||||
|
.join('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 BBCode 转化为普通的字符串
|
||||||
|
*/
|
||||||
|
export function bbcodeToPlainText(bbcode: string): string {
|
||||||
|
const ast = bbcodeParser.parse(bbcode);
|
||||||
|
|
||||||
|
return ast.map(bbcodeNodeToPlainText).join('');
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
export type AstNode = AstNodeObj | AstNodeStr;
|
||||||
|
|
||||||
|
export type AstNodeObj = {
|
||||||
|
tag: string;
|
||||||
|
attrs: Record<string, string>;
|
||||||
|
content: AstNode[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AstNodeStr = string;
|
||||||
|
|
||||||
|
export interface TagProps {
|
||||||
|
node: AstNodeObj;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import type { AstNodeObj } from './type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 url 节点的url地址
|
||||||
|
* @param urlTag url节点
|
||||||
|
*/
|
||||||
|
export function getUrlTagRealUrl(urlTag: AstNodeObj): string {
|
||||||
|
return urlTag.attrs.url ?? urlTag.content.join('');
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { regMessageRender } from '@capital/common';
|
||||||
|
import { BBCode } from './bbcode';
|
||||||
|
import './tags/__all__';
|
||||||
|
|
||||||
|
regMessageRender((message) => {
|
||||||
|
return <BBCode plainText={message} />;
|
||||||
|
});
|
@ -0,0 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { TagProps } from '../bbcode/type';
|
||||||
|
|
||||||
|
export const PlainText: React.FC<TagProps> = React.memo((props) => (
|
||||||
|
<pre style={{ display: 'inline' }}>{props.children}</pre>
|
||||||
|
));
|
||||||
|
PlainText.displayName = 'PlainText';
|
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import type { TagProps } from '../bbcode/type';
|
||||||
|
|
||||||
|
export const UrlTag: React.FC<TagProps> = React.memo((props) => {
|
||||||
|
const { node } = props;
|
||||||
|
const text = node.content.join('');
|
||||||
|
const url = node.attrs.url ?? text;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a href={url} title={text} target="_blank" rel="noopener noreferrer">
|
||||||
|
{text}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
UrlTag.displayName = 'UrlTag';
|
@ -0,0 +1,6 @@
|
|||||||
|
import { registerBBCodeTag } from '../bbcode/parser';
|
||||||
|
import { PlainText } from './PlainText';
|
||||||
|
import { UrlTag } from './UrlTag';
|
||||||
|
|
||||||
|
registerBBCodeTag('_text', PlainText);
|
||||||
|
registerBBCodeTag('url', UrlTag);
|
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": "./src",
|
||||||
|
"baseUrl": "./src",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"paths": {
|
||||||
|
"@capital/*": ["../../../src/plugin/*"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||||
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@bbob/parser@^2.7.0":
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.nlark.com/@bbob/parser/download/@bbob/parser-2.7.0.tgz#ed56a1169d9f69e6defe4512ca65cd004a9a6dcc"
|
||||||
|
integrity sha1-7VahFp2faebe/kUSymXNAEqabcw=
|
||||||
|
dependencies:
|
||||||
|
"@bbob/plugin-helper" "^2.7.0"
|
||||||
|
|
||||||
|
"@bbob/plugin-helper@^2.7.0":
|
||||||
|
version "2.7.0"
|
||||||
|
resolved "https://registry.nlark.com/@bbob/plugin-helper/download/@bbob/plugin-helper-2.7.0.tgz#e24f4a103a2b4daa71674d751af766c791d1d570"
|
||||||
|
integrity sha1-4k9KEDorTapxZ011Gvdmx5HR1XA=
|
||||||
|
|
||||||
|
ip-regex@^4.1.0:
|
||||||
|
version "4.3.0"
|
||||||
|
resolved "https://registry.nlark.com/ip-regex/download/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
|
||||||
|
integrity sha1-aHJ1qw9X+naXj/j03dyKI9WZDbU=
|
||||||
|
|
||||||
|
tlds@^1.203.0:
|
||||||
|
version "1.221.1"
|
||||||
|
resolved "https://registry.nlark.com/tlds/download/tlds-1.221.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftlds%2Fdownload%2Ftlds-1.221.1.tgz#6cf6bff5eaf30c5618c5801c3f425a6dc61ca0ad"
|
||||||
|
integrity sha1-bPa/9erzDFYYxYAcP0JabcYcoK0=
|
||||||
|
|
||||||
|
url-regex@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.npm.taobao.org/url-regex/download/url-regex-5.0.0.tgz#8f5456ab83d898d18b2f91753a702649b873273a"
|
||||||
|
integrity sha1-j1RWq4PYmNGLL5F1OnAmSbhzJzo=
|
||||||
|
dependencies:
|
||||||
|
ip-regex "^4.1.0"
|
||||||
|
tlds "^1.203.0"
|
Loading…
Reference in New Issue