assistant-note/src/pages/Note/Hlexical/index.jsx

223 lines
8.6 KiB
JavaScript

import ExampleTheme from "./themes/ExampleTheme";
import {LexicalComposer} from "@lexical/react/LexicalComposer";
import {RichTextPlugin} from "@lexical/react/LexicalRichTextPlugin";
import {ContentEditable} from "@lexical/react/LexicalContentEditable";
import {HistoryPlugin} from "@lexical/react/LexicalHistoryPlugin";
import {AutoFocusPlugin} from "@lexical/react/LexicalAutoFocusPlugin";
import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
import TreeViewPlugin from "./plugins/TreeViewPlugin";
import ToolbarPlugin from "./plugins/ToolbarPlugin";
import {HeadingNode, QuoteNode} from "@lexical/rich-text";
import {TableCellNode, TableNode, TableRowNode} from "@lexical/table";
import {ListItemNode, ListNode} from "@lexical/list";
import {CodeHighlightNode, CodeNode, $createCodeNode, $isCodeNode} from "@lexical/code";
import {AutoLinkNode, LinkNode} from "@lexical/link";
import {MarkdownShortcutPlugin} from "@lexical/react/LexicalMarkdownShortcutPlugin";
import {
TRANSFORMERS, $convertFromMarkdownString,
$convertToMarkdownString,
} from "@lexical/markdown";
import "./index.less"
import {useEffect, useId, useState} from 'react';
import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
import {importFile, overWriteFile, saveFileWithName} from "../../../utils/File"
import {$getRoot, CLEAR_HISTORY_COMMAND, $createTextNode,} from "lexical";
import md5 from "md5"
import {isEmpty} from "../../../utils/ObjectUtils";
import {useDispatch, useSelector} from "react-redux";
import {updatedSavedFile} from "../../../redux/tableBarItem_reducer";
import {ListPlugin} from "@lexical/react/LexicalListPlugin";
import {LinkPlugin} from "@lexical/react/LexicalLinkPlugin";
import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
import {getFileNameByPath} from "../../../utils/PathOperate";
const {ipcRenderer} = window.require('electron')
function Placeholder() {
return <div className="editor-placeholder">Enter some rich text...</div>;
}
const editorConfig = {
// The editor theme
theme: ExampleTheme,
// Handling of errors during update
onError(error) {
throw error;
},
// Any custom nodes go here
nodes: [
HeadingNode,
ListNode,
ListItemNode,
QuoteNode,
CodeNode,
CodeHighlightNode,
TableNode,
TableCellNode,
TableRowNode,
AutoLinkNode,
LinkNode
]
};
function OnChangePlugin({onChange}) {
const [editor] = useLexicalComposerContext();
console.log('editor', editor)
useEffect(() => {
return editor.registerUpdateListener(({editorState}) => {
onChange(editorState);
});
}, [editor, onChange]);
}
function ImportFilePlugin(props) {
const [editor] = useLexicalComposerContext();
useEffect(() => {
if (props.filePath) {
importFile(props.filePath).then(value => {
if (isEmpty(value)) {
return
}
if (props.filePath.endsWith(".md")) {
const root = $getRoot();
const firstChild = root.getFirstChild();
if ($isCodeNode(firstChild) && firstChild.getLanguage() === 'markdown') {
$convertFromMarkdownString(
firstChild.getTextContent(),
PLAYGROUND_TRANSFORMERS,
);
} else {
const markdown = $convertToMarkdownString(PLAYGROUND_TRANSFORMERS);
root
.clear()
.append(
$createCodeNode('markdown').append($createTextNode(markdown)),
);
}
root.selectEnd();
} else {
const editorState = editor.parseEditorState(
JSON.stringify(JSON.parse(value.toString()).editorState)
);
editor.setEditorState(editorState);
editor.dispatchCommand(CLEAR_HISTORY_COMMAND, undefined);
}
}).catch(error =>
console.error(error)
)
}
}, [])
}
// 从字符串化 JSON 设置编辑器状态
// const editorState = editor.parseEditorState(editorStateJSONString);
// editor.setEditorState(editorState);
export default function Hlexical(props) {
console.log("Hlexical(props):this.props.filePath:", props.filePath)
const [editorState, setEditorState] = useState();
const dispatch = useDispatch();
function onChange(editorState) {
// Call toJSON on the EditorState object, which produces a serialization safe string
const editorStateJSON = editorState.toJSON();
console.log('onChange-editorStateJSON')
// However, we still have a JavaScript object, so we need to convert it to an actual string with JSON.stringify
setEditorState(JSON.stringify(editorStateJSON));
}
let pushHotKey = useSelector(state => state.pushHotkeys.data);
let activeKey = useSelector(state => state.tableBarItem.activeKey);
const saveFile = (event, args) => {
console.log("event,args:", event, args)
console.log("触发保存pushHotKey:", pushHotKey)
if (pushHotKey !== "CTRL+S") {
return
}
let filePath = props.filePath;
if (filePath !== activeKey) {
console.log("文件不同", filePath, activeKey)
return;
}
console.log("触发保存filePath:", filePath)
if (isEmpty(editorState)) {
return
}
const editorStateSave = {"editorState": JSON.parse(editorState)};
let resultSave = JSON.stringify(editorStateSave);
// 如果文件地址为空需要用户选择目录并设置文件。
if (!filePath) {
let saveDialogReturnValuePromise = saveFileWithName();
console.log("saveDialogReturnValuePromise", saveDialogReturnValuePromise)
saveDialogReturnValuePromise.then(result => {
if (!result.canceled) {
let fileKey = getFileNameByPath(result.filePath)
if (isEmpty(fileKey)){
fileKey = fileKey+".lexical"
}
overWriteFile(fileKey, resultSave)
// 修改当前文件名
dispatch(updatedSavedFile({filePath: result.filePath}))
// 文件目录更新
dispatch()
}
})
return
}
importFile(filePath).then(value => {
let save = (isEmpty(value)) || md5(resultSave) !== md5(JSON.stringify(JSON.parse(value.toString())));
if (save) {
console.log("保存重写" + filePath)
overWriteFile(filePath, resultSave)
}
}).catch(error =>
console.error(error)
)
}
useEffect(() => {
ipcRenderer.on("pushHotkeys", saveFile);
return () => {
console.log("销毁取消监听");
ipcRenderer.removeListener("pushHotkeys", saveFile)
};
}
)
return (
<LexicalComposer initialConfig={editorConfig}>
<div className="editor-container">
{/* 富文本插件 */}
<ToolbarPlugin/>
<div className="editor-inner">
<RichTextPlugin
contentEditable={<ContentEditable className="editor-input"/>}
placeholder={<Placeholder/>}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin/>
{/*黑窗口动态记录当前操作*/}
{/*<TreeViewPlugin/>*/}
<AutoFocusPlugin/>
<CodeHighlightPlugin/>
<ListPlugin/>
<LinkPlugin/>
<AutoLinkPlugin/>
<ListMaxIndentLevelPlugin maxDepth={7}/>
{/*markdown 快捷键*/}
<MarkdownShortcutPlugin transformers={TRANSFORMERS}/>
<OnChangePlugin onChange={onChange}/>
<ImportFilePlugin filePath={props.filePath}/>
{/*文件操作导入文件*/}
{/*<ActionPlugin/>*/}
</div>
</div>
</LexicalComposer>
);
}