2022-07-01 10:26:50 +05:00
|
|
|
import { Editor } from "notesnook-editor";
|
2022-07-04 16:14:26 +05:00
|
|
|
import {
|
|
|
|
|
MutableRefObject,
|
|
|
|
|
useCallback,
|
|
|
|
|
useEffect,
|
|
|
|
|
useRef,
|
|
|
|
|
useState,
|
|
|
|
|
} from "react";
|
2022-06-23 19:14:55 +05:00
|
|
|
import { useEditorThemeStore } from "../state/theme";
|
|
|
|
|
import { EventTypes, isReactNative, post, timerFn } from "../utils";
|
|
|
|
|
|
2022-07-04 16:14:26 +05:00
|
|
|
type Attachment = {
|
|
|
|
|
hash: string;
|
|
|
|
|
filename: string;
|
|
|
|
|
type: string;
|
|
|
|
|
size: number;
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-23 19:14:55 +05:00
|
|
|
export type Selection = {
|
|
|
|
|
[name: string]: {
|
|
|
|
|
text?: string;
|
|
|
|
|
length?: number;
|
|
|
|
|
attributes?: Record<string, any>;
|
|
|
|
|
type?: "mark" | "node";
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type Timers = {
|
|
|
|
|
selectionChange: NodeJS.Timeout | null;
|
|
|
|
|
change: NodeJS.Timeout | null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type EditorController = {
|
|
|
|
|
selectionChange: (editor: Editor) => void;
|
|
|
|
|
titleChange: (title: string) => void;
|
|
|
|
|
contentChange: (editor: Editor) => void;
|
|
|
|
|
scroll: (event: React.UIEvent<HTMLDivElement, UIEvent>) => void;
|
|
|
|
|
title: string;
|
|
|
|
|
setTitle: React.Dispatch<React.SetStateAction<string>>;
|
2022-06-27 18:39:59 +05:00
|
|
|
openFilePicker: (type: "image" | "file" | "camera") => void;
|
2022-06-23 19:14:55 +05:00
|
|
|
downloadAttachment: (attachment: Attachment) => void;
|
2022-07-04 16:14:26 +05:00
|
|
|
content: MutableRefObject<string | null>;
|
2022-06-23 19:14:55 +05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export function useEditorController(editor: Editor | null): EditorController {
|
|
|
|
|
const [title, setTitle] = useState("");
|
2022-07-04 16:14:26 +05:00
|
|
|
const htmlContentRef = useRef<string | null>(null);
|
2022-06-23 19:14:55 +05:00
|
|
|
const timers = useRef<Timers>({
|
|
|
|
|
selectionChange: null,
|
|
|
|
|
change: null,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const selectionChange = useCallback((editor: Editor) => {
|
|
|
|
|
// if (!editor) return;
|
|
|
|
|
// timers.current.selectionChange = timerFn(
|
|
|
|
|
// () => {
|
|
|
|
|
// let selection: Selection = {};
|
|
|
|
|
// let { view, state, schema } = editor;
|
|
|
|
|
// let { to, from } = view.state.selection;
|
|
|
|
|
// selection.attributes = {
|
|
|
|
|
// text: state.doc.textBetween(from, to, ""),
|
|
|
|
|
// length: to - from,
|
|
|
|
|
// };
|
|
|
|
|
// let marks = Object.keys(schema.marks);
|
|
|
|
|
// let nodes = Object.keys(schema.nodes);
|
|
|
|
|
// for (let mark of marks) {
|
|
|
|
|
// if (!editor.isActive(mark)) continue;
|
|
|
|
|
// selection[mark] = {
|
|
|
|
|
// attributes: editor.getAttributes(mark),
|
|
|
|
|
// type: "mark",
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
// for (let node of nodes) {
|
|
|
|
|
// if (!editor.isActive(node)) continue;
|
|
|
|
|
// selection[node] = {
|
|
|
|
|
// attributes: editor.getAttributes(node),
|
|
|
|
|
// type: "node",
|
|
|
|
|
// };
|
|
|
|
|
// }
|
|
|
|
|
// post(EventTypes.selection, selection);
|
|
|
|
|
// },
|
|
|
|
|
// 500,
|
|
|
|
|
// timers.current?.selectionChange
|
|
|
|
|
// );
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const titleChange = (title: string) => {
|
|
|
|
|
post(EventTypes.title, title);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const contentChange = useCallback(
|
|
|
|
|
(editor: Editor) => {
|
|
|
|
|
if (!editor) return;
|
|
|
|
|
selectionChange(editor);
|
|
|
|
|
timers.current.change = timerFn(
|
|
|
|
|
() => {
|
2022-07-04 16:14:26 +05:00
|
|
|
htmlContentRef.current = editor.getHTML();
|
|
|
|
|
post(EventTypes.content, htmlContentRef.current);
|
2022-06-23 19:14:55 +05:00
|
|
|
},
|
|
|
|
|
300,
|
|
|
|
|
timers.current?.change
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
[selectionChange]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const scroll = useCallback(
|
|
|
|
|
(event: React.UIEvent<HTMLDivElement, UIEvent>) => {
|
|
|
|
|
//@ts-ignore
|
2022-06-27 18:39:59 +05:00
|
|
|
//post(EventTypes.scroll, event.target.scrollTop);
|
2022-06-23 19:14:55 +05:00
|
|
|
},
|
|
|
|
|
[]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const onMessage = useCallback(
|
|
|
|
|
(data: Event) => {
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
let message = JSON.parse(data.data);
|
|
|
|
|
let type = message.type;
|
|
|
|
|
let value = message.value;
|
|
|
|
|
global.sessionId = message.sessionId;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case "native:html":
|
2022-07-04 16:14:26 +05:00
|
|
|
htmlContentRef.current = value;
|
|
|
|
|
editor?.commands.setContent(htmlContentRef.current, false, {
|
2022-06-23 19:14:55 +05:00
|
|
|
preserveWhitespace: true,
|
|
|
|
|
});
|
|
|
|
|
break;
|
|
|
|
|
case "native:theme":
|
|
|
|
|
useEditorThemeStore.getState().setColors(message.value);
|
|
|
|
|
break;
|
|
|
|
|
case "native:title":
|
|
|
|
|
setTitle(value);
|
|
|
|
|
break;
|
|
|
|
|
case "native:titleplaceholder":
|
|
|
|
|
break;
|
|
|
|
|
case "native:status":
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
post(type); // Notify that message was delivered successfully.
|
|
|
|
|
},
|
|
|
|
|
[editor]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// useEffect(() => {
|
|
|
|
|
// post(EventTypes.history, {
|
|
|
|
|
// undo: false, // editor?.can().undo(),
|
|
|
|
|
// redo: false, // editor?.can().redo(),
|
|
|
|
|
// });
|
|
|
|
|
// }, [editor]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (!isReactNative()) return; // Subscribe only in react native webview.
|
|
|
|
|
let isSafari = navigator.vendor.match(/apple/i);
|
|
|
|
|
let root = document;
|
|
|
|
|
if (isSafari) {
|
|
|
|
|
//@ts-ignore
|
|
|
|
|
root = window;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
root.addEventListener("message", onMessage);
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
root.removeEventListener("message", onMessage);
|
|
|
|
|
};
|
|
|
|
|
}, [onMessage]);
|
|
|
|
|
|
|
|
|
|
const openFilePicker = useCallback((type) => {
|
|
|
|
|
post(EventTypes.filepicker, type);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const downloadAttachment = useCallback((attachment: Attachment) => {
|
|
|
|
|
alert("downloadAttachment" + attachment.hash);
|
|
|
|
|
post(EventTypes.download, attachment);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
contentChange,
|
|
|
|
|
selectionChange,
|
|
|
|
|
titleChange,
|
|
|
|
|
scroll,
|
|
|
|
|
title,
|
|
|
|
|
setTitle,
|
|
|
|
|
openFilePicker,
|
|
|
|
|
downloadAttachment,
|
2022-07-04 16:14:26 +05:00
|
|
|
content: htmlContentRef,
|
2022-06-23 19:14:55 +05:00
|
|
|
};
|
|
|
|
|
}
|