| @@ -17,21 +17,8 @@ export default ({ title, body }: Props) => { | |||||
| const [realBody, setRealBody] = useState<string> ('') | const [realBody, setRealBody] = useState<string> ('') | ||||
| useEffect (() => { | useEffect (() => { | ||||
| const matchIndices = (target: string, keyword: string) => { | |||||
| const indices: number[] = [] | |||||
| let pos = 0 | |||||
| while (true) | |||||
| { | |||||
| const idx = target.indexOf (keyword, pos) | |||||
| if (idx < 0) | |||||
| break | |||||
| indices.push (idx) | |||||
| pos = idx + keyword.length | |||||
| } | |||||
| return indices | |||||
| } | |||||
| if (!(body)) | |||||
| return | |||||
| void (async () => { | void (async () => { | ||||
| try | try | ||||
| @@ -45,19 +32,47 @@ export default ({ title, body }: Props) => { | |||||
| setPageNames ([]) | setPageNames ([]) | ||||
| } | } | ||||
| }) () | }) () | ||||
| }, []) | |||||
| useEffect (() => { | |||||
| if (!(body)) | |||||
| return | |||||
| const matchIndices = (target: string, keyword: string) => { | |||||
| const indices: number[] = [] | |||||
| let pos = 0 | |||||
| let idx | |||||
| while ((idx = target.indexOf (keyword, pos)) >= 0) | |||||
| { | |||||
| indices.push (idx) | |||||
| pos = idx + keyword.length | |||||
| } | |||||
| const linkIndices: [string, [number, number]][] = [] | |||||
| pageNames.forEach (name => { | |||||
| matchIndices (body ?? '', name).map (idx => [idx, idx + name.length]).forEach (([start, end]) => { | |||||
| if (linkIndices.every (([, [st, ed]]) => (start < st || ed <= start) && (end < st || ed <= end))) | |||||
| linkIndices.push ([name, [start, end]]) | |||||
| return indices | |||||
| } | |||||
| const linkIndices = (text: string, names: string[]): [string, [number, number]][] => { | |||||
| const result: [string, [number, number]][] = [] | |||||
| names.forEach (name => { | |||||
| matchIndices (text, name).forEach (idx => { | |||||
| const start = idx | |||||
| const end = idx + name.length | |||||
| const overlaps = result.some (([, [st, ed]]) => start < ed && end > st) | |||||
| if (!(overlaps)) | |||||
| result.push ([name, [start, end]]) | |||||
| }) | |||||
| }) | }) | ||||
| }) | |||||
| linkIndices.sort (([, [a]], [, [b]]) => b - a) | |||||
| linkIndices.forEach (([name, [start, end]]) => { | |||||
| setRealBody (prev => `${ prev.slice (0, start) }[${ name }](/wiki/${ encodeURIComponent (name) })${ prev.slice (end) }`) | |||||
| }) | |||||
| }, []) | |||||
| return result.sort (([, [a]], [, [b]]) => b - a) | |||||
| } | |||||
| setRealBody ( | |||||
| linkIndices (body, pageNames).reduce ((acc, [name, [start, end]]) => ( | |||||
| acc.slice (0, start) | |||||
| + `[${ name }](/wiki/${ encodeURIComponent (name) })` | |||||
| + acc.slice (end)), body)) | |||||
| }, [pageNames]) | |||||
| return ( | return ( | ||||
| <ReactMarkdown components={{ a: ( | <ReactMarkdown components={{ a: ( | ||||