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,

Reply via email to