Files
nimg.neuroinf.jp/src/common/lib/XoopsCode.tsx
T
orrisroot 4e4a0c5de1 build: migrate from Create React App to Vite
- Replace CRA with Vite as the build tool
- Rename index.tsx to main.tsx (Vite convention)
- Add vite.config.ts, tsconfig.app.json, tsconfig.node.json
- Move index.html from public/ to project root
- Replace yarn.lock with package-lock.json
- Remove CRA-specific files (reportWebVitals,
  setupTests, react-app-env.d.ts)
- Update package.json, tsconfig.json, .gitignore, and README.md
- Adjust all source files for Vite compatibility
2026-05-25 00:16:32 +09:00

151 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import ReactHtmlParser, {
convertNodeToElement,
type DomElement,
type DomNode,
type Transform,
} from '@orrisroot/react-html-parser';
import type React from 'react';
import { HashLink } from 'react-router-hash-link';
import type { MultiLang } from '../../config';
import Functions from '../../functions';
interface Props {
lang: MultiLang;
text: string;
dohtml?: boolean;
dosmiley?: boolean;
doxcode?: boolean;
doimage?: boolean;
dobr?: boolean;
}
const preConvertXCode = (text: string, doxcode: boolean): string => {
if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (_m0, m1) => {
return '[code]' + Functions.base64Encode(m1) + '[/code]';
});
}
return text;
};
const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): string => {
if (doxcode) {
return text.replace(/\[code\](.*)\[\/code\]/gs, (_m0, m1) => {
const text = convertXCode(Functions.htmlspecialchars(Functions.base64Decode(m1)), doimage);
return '<div class="xoopsCode"><pre><code>' + text + '</code></pre></div>';
});
}
return text;
};
const convertClickable = (text: string) => {
text = text.replace(
/(^|[^\]_a-zA-Z0-9-="'/]+)((?:https?|ftp)(?::\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[a-zA-Z0-9=]))/g,
(...matches) => {
return (
matches[1] +
'<a href="' +
matches[2] +
'" target="_blank" rel="external noopener noreferrer">' +
matches[2] +
'</a>'
);
},
);
text = text.replace(
/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g,
(...matches) => {
return matches[1] + '<a href="mailto:' + matches[2] + '">' + matches[2] + '</a>';
},
);
return text;
};
const convertXCode = (text: string, _doimage: boolean): string => {
// TODO: implement
return text;
};
const convertSmiley = (text: string) => {
// TODO: implement
return text;
};
const convertBr = (text: string): string => {
return text.replace(/(\r?\n|\r)/g, '<br />');
};
const cssConvert = (text: string): object => {
const ret: any = {};
text.split(';').forEach((line) => {
const line_ = line.trim();
if (line.length === 0) {
return;
}
const kv = line_.split(':');
const key = Functions.camelCase(kv[0].trim());
const value = kv[1].trim();
ret[key] = value;
});
return ret;
};
const xoopsTransform: Transform = (node: DomNode, index: number | string, transform?: Transform): React.ReactNode => {
if (node.type === 'tag') {
const node_ = node as DomElement;
if (node_.name === 'a') {
const url = node_.attribs?.['href'] || '/';
const download = (node_.attribs && node_.attribs['download']) || '';
const rel = (node_.attribs && node_.attribs['rel']) || '';
const klass = (node_.attribs && node_.attribs['class']) || '';
const isFile = download !== '' || /\.(zip|pdf|png|gif|jpg)$/.test(url);
const isExternal = /external/.test(rel) || /external/.test(klass) || /^(mailto|https?:?\/\/)/.test(url);
if (!isFile && !isExternal) {
const style = node_.attribs?.['style'] || '';
const title = node_.attribs?.['title'];
return (
<HashLink key={index} to={url} style={cssConvert(style)} title={title}>
{node_.children.map((value: DomNode, index: number) => {
return convertNodeToElement(value, index, transform);
})}
</HashLink>
);
}
}
if (node_.name === 'img') {
const src = (node_.attribs && node_.attribs['src']) || '';
node_.attribs['src'] = src.replace('`XOOPS_URL`', '');
return convertNodeToElement(node_, index, transform);
}
}
};
const XoopsCode: React.FC<Props> = (props: Props) => {
const { lang } = props;
let text = props.text;
const dohtml = !!props.dohtml;
const dosmiley = !!props.dosmiley;
const doxcode = !!props.doxcode;
const doimage = !!props.doimage;
const dobr = !!props.dobr;
text = preConvertXCode(text, doxcode);
if (!dohtml) {
text = Functions.htmlspecialchars(text);
text = convertClickable(text);
}
if (dosmiley) {
text = convertSmiley(text);
}
if (doxcode) {
text = convertXCode(text, doimage);
}
if (dobr) {
text = convertBr(text);
}
text = postConvertXCode(text, doxcode, doimage);
text = Functions.mlang(text, lang);
return <div>{ReactHtmlParser(text, { transform: xoopsTransform })}</div>;
};
export default XoopsCode;