mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 15:09:33 +01:00
perf: remove wordcount from state
This commit is contained in:
@@ -142,6 +142,7 @@ export async function verifyAccount() {
|
||||
export const AppEventManager = new EventManager();
|
||||
export const AppEvents = {
|
||||
UPDATE_ATTACHMENT_PROGRESS: "updateAttachmentProgress",
|
||||
UPDATE_WORD_COUNT: "updateWordCount",
|
||||
};
|
||||
|
||||
export function totalSubscriptionConsumed(user) {
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Flex, Text } from "rebass";
|
||||
import { AppEventManager, AppEvents } from "../../common";
|
||||
import { useStore } from "../../stores/editor-store";
|
||||
import { timeConverter } from "../../utils/time";
|
||||
|
||||
function EditorFooter() {
|
||||
const [totalWords, setTotalWords] = useState(0);
|
||||
const dateEdited = useStore((store) => store.session.dateEdited);
|
||||
const id = useStore((store) => store.session.id);
|
||||
const totalWords = useStore((store) => store.session.totalWords);
|
||||
const isSaving = useStore((store) => store.session.isSaving);
|
||||
|
||||
useEffect(() => {
|
||||
const updateWordCountEvent = AppEventManager.subscribe(
|
||||
AppEvents.UPDATE_WORD_COUNT,
|
||||
(count) => setTotalWords(count)
|
||||
);
|
||||
return () => {
|
||||
updateWordCountEvent.unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!id) return null;
|
||||
return (
|
||||
<Flex alignItems="center">
|
||||
|
||||
@@ -21,15 +21,22 @@ import useTablet from "../../utils/use-tablet";
|
||||
import Toolbar from "./toolbar";
|
||||
import EditorLoading from "./loading";
|
||||
import { db } from "../../common/db";
|
||||
import { AppEventManager, AppEvents } from "../../common";
|
||||
import debounce from "just-debounce-it";
|
||||
|
||||
const ReactMCE = React.lazy(() => import("./tinymce"));
|
||||
|
||||
function updateWordCount(editor) {
|
||||
if (!editor.countWords) return;
|
||||
AppEventManager.publish(AppEvents.UPDATE_WORD_COUNT, editor.countWords());
|
||||
}
|
||||
const debouncedUpdateWordCount = debounce(updateWordCount, 1000);
|
||||
|
||||
function Editor({ noteId, nonce }) {
|
||||
const editorRef = useRef();
|
||||
const [isEditorLoading, setIsEditorLoading] = useState(true);
|
||||
const sessionId = useStore((store) => store.session.id);
|
||||
const contentType = useStore((store) => store.session.content?.type);
|
||||
const setSession = useStore((store) => store.setSession);
|
||||
const saveSession = useStore((store) => store.saveSession);
|
||||
const newSession = useStore((store) => store.newSession);
|
||||
const openSession = useStore((store) => store.openSession);
|
||||
@@ -50,7 +57,6 @@ function Editor({ noteId, nonce }) {
|
||||
|
||||
const startSession = useCallback(
|
||||
async function startSession(noteId) {
|
||||
console.log("starting session", nonce, noteId);
|
||||
if (noteId === 0) newSession(nonce);
|
||||
else if (noteId) {
|
||||
await openSession(noteId);
|
||||
@@ -117,7 +123,6 @@ function Editor({ noteId, nonce }) {
|
||||
})();
|
||||
}, [startSession, noteId, nonce]);
|
||||
|
||||
// if (!isSessionReady) return <EditorLoading />;
|
||||
return (
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
@@ -200,8 +205,7 @@ function Editor({ noteId, nonce }) {
|
||||
onFocus={() => toggleProperties(false)}
|
||||
onSave={saveSession}
|
||||
sessionId={sessionId}
|
||||
initialValue={editorstore.get()?.session?.content?.data}
|
||||
onChange={(content) => {
|
||||
onChange={(content, editor) => {
|
||||
if (!content || content === "<p><br></pr>") return;
|
||||
|
||||
setSession((state) => {
|
||||
@@ -210,9 +214,10 @@ function Editor({ noteId, nonce }) {
|
||||
data: content,
|
||||
};
|
||||
});
|
||||
|
||||
debouncedUpdateWordCount(editor);
|
||||
}}
|
||||
changeInterval={100}
|
||||
onWordCountChanged={updateWordCount}
|
||||
onInit={(editor) => {
|
||||
editor.focus();
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
||||
import "./editor.css";
|
||||
import "@streetwritersco/tinymce-plugins/codeblock/styles.css";
|
||||
import "@streetwritersco/tinymce-plugins/collapsibleheaders/styles.css";
|
||||
import "tinymce/tinymce";
|
||||
import "tinymce/tinymce.js";
|
||||
// eslint-disable-next-line import/no-webpack-loader-syntax
|
||||
import "file-loader?name=static/js/icons/default/icons.js&esModule=false!tinymce/icons/default/icons.min.js";
|
||||
// eslint-disable-next-line import/no-webpack-loader-syntax
|
||||
@@ -45,7 +45,7 @@ import { useIsUserPremium } from "../../hooks/use-is-user-premium";
|
||||
import { AppEventManager, AppEvents } from "../../common";
|
||||
import { EV, EVENTS } from "notes-core/common";
|
||||
import { downloadAttachment } from "../../common/attachments";
|
||||
import debounce from "just-debounce";
|
||||
import debounce from "just-debounce-it";
|
||||
|
||||
const markdownPatterns = [
|
||||
{ start: "```", replacement: "<pre></pre>" },
|
||||
@@ -124,17 +124,15 @@ const plugins = {
|
||||
pro: "textpattern picker",
|
||||
};
|
||||
|
||||
const changeEvents = "change input compositionend paste";
|
||||
const changeEvents = "change keyup input compositionend paste";
|
||||
|
||||
function TinyMCE(props) {
|
||||
const {
|
||||
changeInterval,
|
||||
onChange,
|
||||
onWordCountChanged,
|
||||
onSave,
|
||||
placeholder,
|
||||
simple,
|
||||
initialValue,
|
||||
onFocus,
|
||||
editorRef,
|
||||
onInit,
|
||||
@@ -142,6 +140,7 @@ function TinyMCE(props) {
|
||||
} = props;
|
||||
const [oldSkin, newSkin] = useSkin();
|
||||
const isUserPremium = useIsUserPremium();
|
||||
|
||||
const tinymceRef = editorRef;
|
||||
useEffect(() => {
|
||||
if (!tinymceRef.current.editor.dom) return;
|
||||
@@ -188,7 +187,6 @@ function TinyMCE(props) {
|
||||
id={sessionId}
|
||||
ref={tinymceRef}
|
||||
onFocus={onFocus}
|
||||
initialValue={initialValue}
|
||||
init={{
|
||||
//experimental
|
||||
keep_styles: false,
|
||||
@@ -225,40 +223,46 @@ function TinyMCE(props) {
|
||||
imagetools_toolbar:
|
||||
"rotateleft rotateright | flipv fliph | alignleft aligncenter alignright",
|
||||
init_instance_callback: (editor) => {
|
||||
editor.serializer.addTempAttr("data-progress");
|
||||
clearTimeout(editor.changeTimeout);
|
||||
onInit && onInit(editor);
|
||||
console.log("init");
|
||||
},
|
||||
setup: (editor) => {
|
||||
editor.on("tap", (e) => {
|
||||
function onTap(e) {
|
||||
if (
|
||||
e.target.classList.contains("mce-content-body") &&
|
||||
!e.target.innerText.length > 0
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editor.on("ScrollIntoView", (e) => {
|
||||
e.preventDefault();
|
||||
e.elm.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
});
|
||||
});
|
||||
|
||||
const onEditorChange = debounce(() => {
|
||||
if (onWordCountChanged) onWordCountChanged(editor.countWords());
|
||||
const onEditorChange = debounce((e) => {
|
||||
if (editor.isLoading) {
|
||||
editor.isLoading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!editor.getHTML) return;
|
||||
|
||||
editor.getHTML().then((html) => {
|
||||
onChange(html, editor);
|
||||
});
|
||||
}, changeInterval);
|
||||
|
||||
function onScrollIntoView(e) {
|
||||
e.preventDefault();
|
||||
e.elm.scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block: "nearest",
|
||||
});
|
||||
}
|
||||
|
||||
editor.on("ScrollIntoView", onScrollIntoView);
|
||||
editor.on("tap", onTap);
|
||||
editor.on(changeEvents, onEditorChange);
|
||||
editor.on("remove", () => {
|
||||
editor.off("ScrollIntoView", onScrollIntoView);
|
||||
editor.off("tap", onTap);
|
||||
editor.off(changeEvents, onEditorChange);
|
||||
});
|
||||
},
|
||||
toolbar_persist: true,
|
||||
toolbar_sticky: false,
|
||||
|
||||
@@ -29,7 +29,6 @@ const getDefaultSession = () => {
|
||||
context: undefined,
|
||||
color: undefined,
|
||||
dateEdited: 0,
|
||||
totalWords: 0,
|
||||
attachments: [],
|
||||
content: {
|
||||
type: "tiny",
|
||||
@@ -65,7 +64,6 @@ class EditorStore extends BaseStore {
|
||||
...note,
|
||||
id: undefined, // NOTE: we give a session id only after the note is opened.
|
||||
content: note.content,
|
||||
totalWords: state.session.totalWords,
|
||||
state: SESSION_STATES.unlocked,
|
||||
};
|
||||
});
|
||||
@@ -108,7 +106,6 @@ class EditorStore extends BaseStore {
|
||||
...defaultSession,
|
||||
...note,
|
||||
content: content || defaultSession.content,
|
||||
totalWords: state.session.totalWords,
|
||||
state: SESSION_STATES.new,
|
||||
attachments: db.attachments.ofNote(note.id, "files") || [],
|
||||
};
|
||||
@@ -234,12 +231,6 @@ class EditorStore extends BaseStore {
|
||||
);
|
||||
};
|
||||
|
||||
updateWordCount = (count) => {
|
||||
this.set((state) => {
|
||||
state.session.totalWords = count;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @private internal
|
||||
* @param {Boolean} isLocked
|
||||
|
||||
Reference in New Issue
Block a user