diff --git a/main.js b/main.js index 7bd9a9a..fdad1ef 100644 --- a/main.js +++ b/main.js @@ -2,6 +2,8 @@ const { app,Menu, BrowserWindow } = require('electron') const path = require('path') const {menuRebuild} = require('./src/comment/TopMenu.js') +// const {SAVE} = require("./src/utils/HotkeyConst"); +// const {PUSH_HOTKEY} = require("./src/utils/MainContentsChannel"); const createWindow = () => { // Create the browser window. const win = new BrowserWindow({ @@ -20,15 +22,23 @@ const createWindow = () => { // 打开开发工具 win.webContents.openDevTools() win.webContents.on('before-input-event', (event, input) => { - // if (input.control && input.key.toLowerCase() === 's') { - // console.log('Pressed Control+s') - // event.preventDefault() - // } + if (input.control && input.key.toLowerCase() === 's') { + console.log("win.webContents.send(\"pushHotkeys\",\"CTRL+S\")") + win.webContents.send("pushHotkeys","CTRL+S") + // event.preventDefault() + } console.log('Pressed ',input.key) - if (input.key==='f5'){ - console.log('Pressed f5') + if (input.key.toUpperCase()==='F5'){ win.reload() } + if (input.key.toUpperCase()==='F12'){ + if (win.webContents.isDevToolsOpened()){ + win.webContents.closeDevTools() + }else { + win.webContents.openDevTools() + } + } + }) Menu.setApplicationMenu(Menu.buildFromTemplate(menuRebuild(win))) } diff --git a/package-lock.json b/package-lock.json index f391663..07d0214 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "electron-squirrel-startup": "^1.0.0", "electron-store": "^8.1.0", + "md5": "^2.3.0", "mousetrap": "^1.6.5", "node-sass": "^7.0.3" }, @@ -8490,6 +8491,14 @@ "node": ">=10" } }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "engines": { + "node": "*" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmmirror.com/check-types/-/check-types-11.2.3.tgz", @@ -9667,6 +9676,14 @@ "node": ">=12.10" } }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "engines": { + "node": "*" + } + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -14346,6 +14363,11 @@ "node": ">= 0.4" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", @@ -17928,6 +17950,16 @@ "node": ">=10" } }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, "node_modules/mdn-data": { "version": "2.0.4", "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.4.tgz", diff --git a/package.json b/package.json index 99adaf1..199a392 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "dependencies": { "electron-squirrel-startup": "^1.0.0", "electron-store": "^8.1.0", + "md5": "^2.3.0", "mousetrap": "^1.6.5", "node-sass": "^7.0.3" }, diff --git a/src/App.js b/src/App.js index ca9c79f..3bf7043 100644 --- a/src/App.js +++ b/src/App.js @@ -3,7 +3,7 @@ import routes from './routes' import {Outlet, useNavigate, useRoutes} from 'react-router-dom' import useIpcRenderer from '../src/utils/useIpcRenderer' import {dirAdd} from "./redux/dirMessage_reducer"; -import {openFile} from "./redux/clickFile_reducer" +import {pushHotkeys} from "./redux/pushHotkeys_reducer"; import {store} from "./redux/store"; function App() { @@ -17,11 +17,16 @@ function App() { const addNewDir =(event,args)=> { store.dispatch(dirAdd(args)) } + const pushHotkeysAction =(event,args)=> { + console.log("store.dispatch(pushHotkeys(args))",args) + store.dispatch(pushHotkeys(args)) + } console.log("routes",routes) const element = useRoutes(routes) useIpcRenderer({'redirectUrl':redirectUrl}) useIpcRenderer({'openDirectory':addNewDir}) + useIpcRenderer({'pushHotkeys':pushHotkeysAction}) return ( <> {/* 注册路由 */} diff --git a/src/pages/Note/Hlexical/index.jsx b/src/pages/Note/Hlexical/index.jsx index 9db27f5..2079e01 100644 --- a/src/pages/Note/Hlexical/index.jsx +++ b/src/pages/Note/Hlexical/index.jsx @@ -1,84 +1,109 @@ 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 {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 {Button} from "antd"; -import { HeadingNode, QuoteNode } from "@lexical/rich-text"; -import { TableCellNode, TableNode, TableRowNode } from "@lexical/table"; -import { ListItemNode, ListNode } from "@lexical/list"; -import { CodeHighlightNode, CodeNode } from "@lexical/code"; -import { AutoLinkNode, LinkNode } from "@lexical/link"; -import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin"; -import { ListPlugin } from "@lexical/react/LexicalListPlugin"; -import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin"; -import { TRANSFORMERS } from "@lexical/markdown"; +import {HeadingNode, QuoteNode} from "@lexical/rich-text"; +import {TableCellNode, TableNode, TableRowNode} from "@lexical/table"; +import {ListItemNode, ListNode} from "@lexical/list"; +import {CodeHighlightNode, CodeNode} from "@lexical/code"; +import {AutoLinkNode, LinkNode} from "@lexical/link"; +import {LinkPlugin} from "@lexical/react/LexicalLinkPlugin"; +import {ListPlugin} from "@lexical/react/LexicalListPlugin"; +import {MarkdownShortcutPlugin} from "@lexical/react/LexicalMarkdownShortcutPlugin"; +import {TRANSFORMERS} from "@lexical/markdown"; import "./index.less" import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin"; import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin"; import AutoLinkPlugin from "./plugins/AutoLinkPlugin"; -import {useEffect,useState} from 'react'; +import {useEffect, useState} from 'react'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; -import {importFile} from "../../../utils/File" +import {importFile, overWriteFile} from "../../../utils/File" import {CLEAR_HISTORY_COMMAND} from "lexical"; import ActionPlugin from "../../../components/ActionPlug" import {func} from "prop-types"; - +import store from "../../../redux/store"; +import {useSelector} from 'react-redux' +import {SAVE} from "../../../utils/HotkeyConst"; +import md5 from "md5" function Placeholder() { - return
Enter some rich text...
; + return
Enter some rich text...
; } 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 - ] + // 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 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(()=>{ - importFile(props.filePath).then(value=>{ - console.log('value.toString()',value.toString()) - 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) - ) - },[]) + const [editor] = useLexicalComposerContext(); + useEffect(() => { + importFile(props.filePath).then(value => { + 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) + ) + }, []) +} + +function SaveFilePlugin(props) { + const [editor] = useLexicalComposerContext(); + useEffect(() => { + store.subscribe(() => { + let data = store.getState().pushHotkeys.data; + const editorState = {"editorState":editor.getEditorState()}; + let resultSave = JSON.stringify(editorState); + if (data === SAVE) { + importFile(props.filePath).then(value => { + if (md5(resultSave)!==md5(JSON.stringify(JSON.parse(value.toString())))){ + console.log("保存重写") + overWriteFile(props.filePath, resultSave) + } + }).catch(error => + console.error(error) + ) + + } + }) + }, editor) } // 从字符串化 JSON 设置编辑器状态 @@ -86,41 +111,44 @@ function ImportFilePlugin(props) { // editor.setEditorState(editorState); export default function Hlexical(props) { - console.log("this.props.filePath:",props.filePath) - const [editorState, setEditorState] = useState(); - function onChange(editorState) { - // Call toJSON on the EditorState object, which produces a serialization safe string - const editorStateJSON = editorState.toJSON(); - console.log('editorStateJSON',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)); - } - return ( - -
- {/* 富文本插件 */} - -
- } - placeholder={} - ErrorBoundary={LexicalErrorBoundary} - /> - - {/*黑窗口动态记录当前操作*/} - - - {/**/} - {/**/} - {/**/} - {/**/} - {/**/} - - - - {/**/} -
-
-
- ); + console.log("this.props.filePath:", props.filePath) + const [editorState, setEditorState] = useState(); + + function onChange(editorState) { + // Call toJSON on the EditorState object, which produces a serialization safe string + const editorStateJSON = editorState.toJSON(); + console.log('editorStateJSON', 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)); + } + + return ( + +
+ {/* 富文本插件 */} + +
+ } + placeholder={} + ErrorBoundary={LexicalErrorBoundary} + /> + + {/*黑窗口动态记录当前操作*/} + + + {/**/} + {/**/} + {/**/} + {/**/} + {/**/} + + + + + {/**/} +
+
+
+ ); } diff --git a/src/redux/pushHotkeys_reducer.js b/src/redux/pushHotkeys_reducer.js new file mode 100644 index 0000000..65e40cf --- /dev/null +++ b/src/redux/pushHotkeys_reducer.js @@ -0,0 +1,19 @@ +import { createSlice } from '@reduxjs/toolkit' + +export const pushHotkeysSlice = createSlice({ + name: 'pushHotkeys', + initialState: { + data: "" + }, + reducers: { + pushHotkeys: (state, action) => { + console.log("pushHotkeys:pushHotkeys", state, action) + if(action.payload){ + state.data = action.payload; + } + } + } +}) +export const { pushHotkeys } = pushHotkeysSlice.actions + +export default pushHotkeysSlice.reducer diff --git a/src/redux/store.js b/src/redux/store.js index 04a04e9..f426531 100644 --- a/src/redux/store.js +++ b/src/redux/store.js @@ -3,12 +3,14 @@ import historyReducer from './historyRecord_reducer' import redirectReducer from './redirectUrl_reducer' import dirMessageReducer from './dirMessage_reducer' import clickFileReducer from './clickFile_reducer' +import pushHotkeysReducer from "./pushHotkeys_reducer"; // 用于支持异步函数 export const store = configureStore({ reducer: { historyRecord:historyReducer, redirectUrl:redirectReducer, dirMessage:dirMessageReducer, + pushHotkeys:pushHotkeysReducer, clickFileMessage:clickFileReducer } }) diff --git a/src/utils/File/index.jsx b/src/utils/File/index.jsx index 9fc53ec..f820397 100644 --- a/src/utils/File/index.jsx +++ b/src/utils/File/index.jsx @@ -7,6 +7,6 @@ export async function importFile(pathName) { return await fs.readFile(pathName) } -export function overWriteFile(filePath) { - fs.writeFile(filePath,) +export async function overWriteFile(filePath,jsonText) { + await fs.writeFile(filePath,jsonText,{"encoding":"utf-8"}) } \ No newline at end of file diff --git a/src/utils/HotkeyConst.js b/src/utils/HotkeyConst.js new file mode 100644 index 0000000..0c42881 --- /dev/null +++ b/src/utils/HotkeyConst.js @@ -0,0 +1 @@ +export const SAVE = 'CTRL+S' \ No newline at end of file diff --git a/src/utils/MainContentsChannel.js b/src/utils/MainContentsChannel.js new file mode 100644 index 0000000..6eb626d --- /dev/null +++ b/src/utils/MainContentsChannel.js @@ -0,0 +1 @@ +export const PUSH_HOTKEY = 'pushHotkeys' \ No newline at end of file diff --git a/src/utils/useIpcRenderer.js b/src/utils/useIpcRenderer.js index 294461b..4e137b6 100644 --- a/src/utils/useIpcRenderer.js +++ b/src/utils/useIpcRenderer.js @@ -5,6 +5,7 @@ const { ipcRenderer } = window.require('electron') const useIpcRenderer = (keyCallbackMap) => { useEffect(() => { Object.keys(keyCallbackMap).forEach(key => { + console.log("ipcRenderer.on(key, keyCallbackMap[key])",key) ipcRenderer.on(key, keyCallbackMap[key]) }) return () => {