This is an automated email from the ASF dual-hosted git repository. robin0716 pushed a commit to branch refactor/editor in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
commit f60d25618bfa5ebb054e796abc19eba77c9c5f54 Author: robin <[email protected]> AuthorDate: Mon Apr 15 17:54:01 2024 +0800 refactor(ui): Migrate extension methods to extension.ts --- .../Editor/utils/{index.ts => extension.ts} | 139 +------------ ui/src/components/Editor/utils/index.ts | 227 +-------------------- 2 files changed, 9 insertions(+), 357 deletions(-) diff --git a/ui/src/components/Editor/utils/index.ts b/ui/src/components/Editor/utils/extension.ts similarity index 67% copy from ui/src/components/Editor/utils/index.ts copy to ui/src/components/Editor/utils/extension.ts index 92fcbae3..84687e84 100644 --- a/ui/src/components/Editor/utils/index.ts +++ b/ui/src/components/Editor/utils/extension.ts @@ -17,56 +17,11 @@ * under the License. */ -import { useEffect, useState } from 'react'; - -import { minimalSetup } from 'codemirror'; -import { EditorSelection, EditorState, StateEffect } from '@codemirror/state'; -import { EditorView, keymap, KeyBinding, placeholder } from '@codemirror/view'; -import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; -import { languages } from '@codemirror/language-data'; +import { EditorSelection, StateEffect } from '@codemirror/state'; +import { EditorView, keymap, KeyBinding } from '@codemirror/view'; import { Editor, Position } from '../types'; -export function htmlRender(el: HTMLElement | null) { - if (!el) return; - // Replace all br tags with newlines - // Fixed an issue where the BR tag in the editor block formula HTML caused rendering errors. - el.querySelectorAll('p').forEach((p) => { - if (p.innerHTML.startsWith('$$') && p.innerHTML.endsWith('$$')) { - const str = p.innerHTML.replace(/<br>/g, '\n'); - p.innerHTML = str; - } - }); - - // change table style - - el.querySelectorAll('table').forEach((table) => { - if ( - (table.parentNode as HTMLDivElement)?.classList.contains( - 'table-responsive', - ) - ) { - return; - } - - table.classList.add('table', 'table-bordered'); - const div = document.createElement('div'); - div.className = 'table-responsive'; - table.parentNode?.replaceChild(div, table); - div.appendChild(table); - }); - - // add rel nofollow for link not inlcludes domain - el.querySelectorAll('a').forEach((a) => { - const base = window.location.origin; - const targetUrl = new URL(a.href, base); - - if (targetUrl.origin !== base) { - a.rel = 'nofollow'; - } - }); -} - const createEditorUtils = (editor: Editor) => { editor.focus = () => { editor.contentDOM.focus(); @@ -210,6 +165,7 @@ const createEditorUtils = (editor: Editor) => { editor.replaceSelection(`${before}${defaultText}${after}`); } }; + editor.replaceLines = ( replace: Parameters<Array<string>['map']>[0], symbolLen = 0, @@ -286,91 +242,4 @@ const createEditorUtils = (editor: Editor) => { return editor; }; -export const useEditor = ({ - editorRef, - placeholder: placeholderText, - autoFocus, - onChange, - onFocus, - onBlur, -}) => { - const [editor, setEditor] = useState<Editor | null>(null); - const [value, setValue] = useState<string>(''); - const init = async () => { - const theme = EditorView.theme( - { - '&': { - width: '100%', - height: '100%', - }, - '&.cm-focused': { - outline: 'none', - }, - '.cm-content': { - width: '100%', - padding: '1rem', - }, - '.cm-line': { - whiteSpace: 'pre-wrap', - wordWrap: 'break-word', - wordBreak: 'break-all', - }, - }, - { dark: false }, - ); - - const startState = EditorState.create({ - extensions: [ - minimalSetup, - markdown({ - codeLanguages: languages, - base: markdownLanguage, - }), - theme, - placeholder(placeholderText), - ], - }); - - const view = new EditorView({ - parent: editorRef.current, - state: startState, - }); - - const cm = createEditorUtils(view as Editor); - - if (autoFocus) { - setTimeout(() => { - cm.focus(); - }, 10); - } - - cm.on('change', () => { - const newValue = cm.getValue(); - setValue(newValue); - }); - - cm.on('focus', () => { - onFocus?.(); - }); - - cm.on('blur', () => { - onBlur?.(); - }); - - setEditor(cm); - - return cm; - }; - - useEffect(() => { - onChange?.(value); - }, [value]); - - useEffect(() => { - if (!(editorRef.current instanceof HTMLElement) || editor) { - return; - } - init(); - }, [editor]); - return editor; -}; +export default createEditorUtils; diff --git a/ui/src/components/Editor/utils/index.ts b/ui/src/components/Editor/utils/index.ts index 92fcbae3..bf273dd4 100644 --- a/ui/src/components/Editor/utils/index.ts +++ b/ui/src/components/Editor/utils/index.ts @@ -20,12 +20,14 @@ import { useEffect, useState } from 'react'; import { minimalSetup } from 'codemirror'; -import { EditorSelection, EditorState, StateEffect } from '@codemirror/state'; -import { EditorView, keymap, KeyBinding, placeholder } from '@codemirror/view'; +import { EditorState } from '@codemirror/state'; +import { EditorView, placeholder } from '@codemirror/view'; import { markdown, markdownLanguage } from '@codemirror/lang-markdown'; import { languages } from '@codemirror/language-data'; -import { Editor, Position } from '../types'; +import { Editor } from '../types'; + +import createEditorUtils from './extension'; export function htmlRender(el: HTMLElement | null) { if (!el) return; @@ -67,225 +69,6 @@ export function htmlRender(el: HTMLElement | null) { }); } -const createEditorUtils = (editor: Editor) => { - editor.focus = () => { - editor.contentDOM.focus(); - }; - - editor.getCursor = () => { - const range = editor.state.selection.ranges[0]; - const line = editor.state.doc.lineAt(range.from).number; - const { from, to } = editor.state.doc.line(line); - return { from, to, ch: range.from - from, line }; - }; - - editor.addKeyMap = (keyMap) => { - const array = Object.entries(keyMap).map(([key, value]) => { - const keyBinding: KeyBinding = { - key, - preventDefault: true, - run: value, - }; - return keyBinding; - }); - - editor.dispatch({ - effects: StateEffect.appendConfig.of(keymap.of(array)), - }); - }; - - editor.getSelection = () => { - return editor.state.sliceDoc( - editor.state.selection.main.from, - editor.state.selection.main.to, - ); - }; - - editor.replaceSelection = (value: string) => { - editor.dispatch({ - changes: [ - { - from: editor.state.selection.main.from, - to: editor.state.selection.main.to, - insert: value, - }, - ], - selection: EditorSelection.cursor( - editor.state.selection.main.from + value.length, - ), - }); - }; - - editor.setSelection = (anchor: Position, head?: Position) => { - editor.dispatch({ - selection: EditorSelection.create([ - EditorSelection.range( - editor.state.doc.line(anchor.line).from + anchor.ch, - head - ? editor.state.doc.line(head.line).from + head.ch - : editor.state.doc.line(anchor.line).from + anchor.ch, - ), - ]), - }); - }; - - editor.on = (event, callback) => { - if (event === 'change') { - const change = EditorView.updateListener.of((update) => { - if (update.docChanged) { - callback(); - } - }); - - editor.dispatch({ - effects: StateEffect.appendConfig.of(change), - }); - } - if (event === 'focus') { - editor.contentDOM.addEventListener('focus', callback); - } - if (event === 'blur') { - editor.contentDOM.addEventListener('blur', callback); - } - - if (event === 'dragenter') { - editor.contentDOM.addEventListener('dragenter', callback); - } - - if (event === 'dragover') { - editor.contentDOM.addEventListener('dragover', callback); - } - - if (event === 'drop') { - editor.contentDOM.addEventListener('drop', callback); - } - - if (event === 'paste') { - editor.contentDOM.addEventListener('paste', callback); - } - }; - - editor.off = (event, callback) => { - if (event === 'focus') { - editor.contentDOM.removeEventListener('focus', callback); - } - - if (event === 'blur') { - editor.contentDOM.removeEventListener('blur', callback); - } - - if (event === 'dragenter') { - editor.contentDOM.removeEventListener('dragenter', callback); - } - - if (event === 'dragover') { - editor.contentDOM.removeEventListener('dragover', callback); - } - - if (event === 'drop') { - editor.contentDOM.removeEventListener('drop', callback); - } - - if (event === 'paste') { - editor.contentDOM.removeEventListener('paste', callback); - } - }; - - editor.getValue = () => { - return editor.state.doc.toString(); - }; - - editor.setValue = (value: string) => { - editor.dispatch({ - changes: { from: 0, to: editor.state.doc.length, insert: value }, - }); - }; - - editor.wrapText = (before: string, after = before, defaultText) => { - const range = editor.state.selection.ranges[0]; - const selection = editor.state.sliceDoc(range.from, range.to); - if (selection) { - editor.replaceSelection(`${before}${selection}${after}`); - } else { - editor.replaceSelection(`${before}${defaultText}${after}`); - } - }; - editor.replaceLines = ( - replace: Parameters<Array<string>['map']>[0], - symbolLen = 0, - ) => { - const range = editor.state.selection.ranges[0]; - const line = editor.state.doc.lineAt(range.from).number; - const { from, to } = editor.state.doc.line(line); - const lines = editor.state.sliceDoc(from, to).split('\n'); - - const insert = lines.map(replace).join('\n'); - const selectionStart = from; - const selectionEnd = from + insert.length; - - editor.dispatch({ - changes: [ - { - from, - to, - insert, - }, - ], - selection: EditorSelection.create([ - EditorSelection.range(selectionStart + symbolLen, selectionEnd), - ]), - }); - }; - - editor.appendBlock = (content: string) => { - const range = editor.state.selection.ranges[0]; - const line = editor.state.doc.lineAt(range.from).number; - const { from, to } = editor.state.doc.line(line); - - let insert = `\n\n${content}`; - - let selection = EditorSelection.single(to, to + content.length); - if (from === to) { - insert = `${content}\n`; - selection = EditorSelection.create([ - EditorSelection.cursor(to + content.length), - ]); - } - - editor.dispatch({ - changes: [ - { - from: to, - insert, - }, - ], - selection, - }); - }; - - editor.replaceRange = ( - value: string, - selectionStart: Position, - selectionEnd: Position, - ) => { - const from = - editor.state.doc.line(selectionStart.line).from + selectionStart.ch; - const to = editor.state.doc.line(selectionEnd.line).from + selectionEnd.ch; - editor.dispatch({ - changes: [ - { - from, - to, - insert: value, - }, - ], - selection: EditorSelection.cursor(from + value.length), - }); - }; - - return editor; -}; - export const useEditor = ({ editorRef, placeholder: placeholderText,
