mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-29 19:13:59 +02:00
Chore: Desktop: Fix eslint issues and strengthen types in NoteEditor.tsx (#10449)
This commit is contained in:
parent
c632ea5c48
commit
652add9af2
@ -322,6 +322,8 @@ packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/usePluginServiceRegistration.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useScheduleSaveCallbacks.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useScrollWhenReadyOptions.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useSearchMarkers.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
|
||||
packages/app-desktop/gui/NoteList/NoteList2.js
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -301,6 +301,8 @@ packages/app-desktop/gui/NoteEditor/utils/useMarkupToHtml.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useMessageHandler.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useNoteSearchBar.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/usePluginServiceRegistration.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useScheduleSaveCallbacks.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useScrollWhenReadyOptions.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useSearchMarkers.js
|
||||
packages/app-desktop/gui/NoteEditor/utils/useWindowCommandHandler.js
|
||||
packages/app-desktop/gui/NoteList/NoteList2.js
|
||||
|
@ -26,6 +26,10 @@ export interface AppStateDialog {
|
||||
props: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface EditorScrollPercents {
|
||||
[noteId: string]: number;
|
||||
}
|
||||
|
||||
export interface AppState extends State {
|
||||
route: AppStateRoute;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
@ -34,8 +38,7 @@ export interface AppState extends State {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
windowContentSize: any;
|
||||
watchedNoteFiles: string[];
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
lastEditorScrollPercents: any;
|
||||
lastEditorScrollPercents: EditorScrollPercents;
|
||||
devToolsVisible: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
visibleDialogs: any; // empty object if no dialog is visible. Otherwise contains the list of visible dialogs.
|
||||
|
@ -3,19 +3,18 @@ import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import TinyMCE from './NoteBody/TinyMCE/TinyMCE';
|
||||
import { connect } from 'react-redux';
|
||||
import MultiNoteActions from '../MultiNoteActions';
|
||||
import { htmlToMarkdown, formNoteToNote } from './utils';
|
||||
import { htmlToMarkdown } from './utils';
|
||||
import useSearchMarkers from './utils/useSearchMarkers';
|
||||
import useNoteSearchBar from './utils/useNoteSearchBar';
|
||||
import useMessageHandler from './utils/useMessageHandler';
|
||||
import useWindowCommandHandler from './utils/useWindowCommandHandler';
|
||||
import useDropHandler from './utils/useDropHandler';
|
||||
import useMarkupToHtml from './utils/useMarkupToHtml';
|
||||
import useFormNote, { OnLoadEvent } from './utils/useFormNote';
|
||||
import useFormNote, { OnLoadEvent, SetFormNote } from './utils/useFormNote';
|
||||
import useEffectiveNoteId from './utils/useEffectiveNoteId';
|
||||
import useFolder from './utils/useFolder';
|
||||
import styles_ from './styles';
|
||||
import { NoteEditorProps, FormNote, ScrollOptions, ScrollOptionTypes, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions, NoteBodyEditorRef } from './utils/types';
|
||||
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
|
||||
import { NoteEditorProps, FormNote, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions, NoteBodyEditorRef } from './utils/types';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
import ToolbarButton from '../ToolbarButton/ToolbarButton';
|
||||
import Button, { ButtonLevel } from '../Button/Button';
|
||||
@ -26,7 +25,6 @@ import { _, _n } from '@joplin/lib/locale';
|
||||
import TagList from '../TagList';
|
||||
import NoteTitleBar from './NoteTitle/NoteTitleBar';
|
||||
import markupLanguageUtils from '../../utils/markupLanguageUtils';
|
||||
import usePrevious from '../hooks/usePrevious';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import stateToWhenClauseContext from '../../services/commands/stateToWhenClauseContext';
|
||||
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
|
||||
@ -37,7 +35,7 @@ import NoteSearchBar from '../NoteSearchBar';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
const bridge = require('@electron/remote').require('./bridge').default;
|
||||
import bridge from '../../services/bridge';
|
||||
import NoteRevisionViewer from '../NoteRevisionViewer';
|
||||
import { parseShareCache } from '@joplin/lib/services/share/reducer';
|
||||
import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
|
||||
@ -51,6 +49,8 @@ import CodeMirror5 from './NoteBody/CodeMirror/v5/CodeMirror';
|
||||
import { openItemById } from './utils/contextMenu';
|
||||
import getPluginSettingValue from '@joplin/lib/services/plugins/utils/getPluginSettingValue';
|
||||
import { MarkupLanguage } from '@joplin/renderer';
|
||||
import useScrollWhenReadyOptions from './utils/useScrollWhenReadyOptions';
|
||||
import useScheduleSaveCallbacks from './utils/useScheduleSaveCallbacks';
|
||||
|
||||
const commands = [
|
||||
require('./commands/showRevisions'),
|
||||
@ -61,20 +61,21 @@ const toolbarButtonUtils = new ToolbarButtonUtils(CommandService.instance());
|
||||
function NoteEditor(props: NoteEditorProps) {
|
||||
const [showRevisions, setShowRevisions] = useState(false);
|
||||
const [titleHasBeenManuallyChanged, setTitleHasBeenManuallyChanged] = useState(false);
|
||||
const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions>(null);
|
||||
const [isReadOnly, setIsReadOnly] = useState<boolean>(false);
|
||||
|
||||
const editorRef = useRef<NoteBodyEditorRef>();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const titleInputRef = useRef<any>();
|
||||
const titleInputRef = useRef<HTMLInputElement>();
|
||||
const isMountedRef = useRef(true);
|
||||
const noteSearchBarRef = useRef(null);
|
||||
|
||||
const setFormNoteRef = useRef<SetFormNote>();
|
||||
const { saveNoteIfWillChange, scheduleSaveNote } = useScheduleSaveCallbacks({
|
||||
setFormNote: setFormNoteRef, dispatch: props.dispatch, editorRef,
|
||||
});
|
||||
const formNote_beforeLoad = useCallback(async (event: OnLoadEvent) => {
|
||||
await saveNoteIfWillChange(event.formNote);
|
||||
setShowRevisions(false);
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, []);
|
||||
}, [saveNoteIfWillChange]);
|
||||
|
||||
const formNote_afterLoad = useCallback(async () => {
|
||||
setTitleHasBeenManuallyChanged(false);
|
||||
@ -92,6 +93,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
onBeforeLoad: formNote_beforeLoad,
|
||||
onAfterLoad: formNote_afterLoad,
|
||||
});
|
||||
setFormNoteRef.current = setFormNote;
|
||||
|
||||
const formNoteRef = useRef<FormNote>();
|
||||
formNoteRef.current = { ...formNote };
|
||||
@ -116,53 +118,6 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
|
||||
const styles = styles_(props);
|
||||
|
||||
function scheduleSaveNote(formNote: FormNote) {
|
||||
if (!formNote.saveActionQueue) throw new Error('saveActionQueue is not set!!'); // Sanity check
|
||||
|
||||
// reg.logger().debug('Scheduling...', formNote);
|
||||
|
||||
const makeAction = (formNote: FormNote) => {
|
||||
return async function() {
|
||||
const note = await formNoteToNote(formNote);
|
||||
reg.logger().debug('Saving note...', note);
|
||||
const savedNote = await Note.save(note);
|
||||
|
||||
setFormNote((prev: FormNote) => {
|
||||
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
|
||||
});
|
||||
|
||||
void ExternalEditWatcher.instance().updateNoteFile(savedNote);
|
||||
|
||||
props.dispatch({
|
||||
type: 'EDITOR_NOTE_STATUS_REMOVE',
|
||||
id: formNote.id,
|
||||
});
|
||||
|
||||
eventManager.emit(EventName.NoteContentChange, { note: savedNote });
|
||||
};
|
||||
};
|
||||
|
||||
formNote.saveActionQueue.push(makeAction(formNote));
|
||||
}
|
||||
|
||||
async function saveNoteIfWillChange(formNote: FormNote) {
|
||||
if (!formNote.id || !formNote.bodyWillChangeId) return;
|
||||
|
||||
const body = await editorRef.current.content();
|
||||
|
||||
scheduleSaveNote({
|
||||
...formNote,
|
||||
body: body,
|
||||
bodyWillChangeId: 0,
|
||||
bodyChangeId: 0,
|
||||
});
|
||||
}
|
||||
|
||||
async function saveNoteAndWait(formNote: FormNote) {
|
||||
await saveNoteIfWillChange(formNote);
|
||||
return formNote.saveActionQueue.waitForAllDone();
|
||||
}
|
||||
|
||||
const whiteBackgroundNoteRendering = formNote.markup_language === MarkupLanguage.Html;
|
||||
|
||||
const markupToHtml = useMarkupToHtml({
|
||||
@ -201,26 +156,8 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
id: formNote.id,
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [props.isProvisional, formNote.id]);
|
||||
}, [props.isProvisional, formNote.id, props.dispatch]);
|
||||
|
||||
const previousNoteId = usePrevious(formNote.id);
|
||||
|
||||
useEffect(() => {
|
||||
if (formNote.id === previousNoteId) return;
|
||||
|
||||
if (editorRef.current) {
|
||||
editorRef.current.resetScroll();
|
||||
}
|
||||
|
||||
setScrollWhenReady({
|
||||
type: props.selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
|
||||
value: props.selectedNoteHash ? props.selectedNoteHash : props.lastEditorScrollPercents[formNote.id] || 0,
|
||||
});
|
||||
|
||||
void ResourceEditWatcher.instance().stopWatchingAll();
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [formNote.id, previousNoteId]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onFieldChange = useCallback((field: string, value: any, changeId = 0) => {
|
||||
@ -263,19 +200,16 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
// The previously loaded note, that was modified, will be saved via saveNoteIfWillChange()
|
||||
} else {
|
||||
setFormNote(newNote);
|
||||
scheduleSaveNote(newNote);
|
||||
void scheduleSaveNote(newNote);
|
||||
}
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [handleProvisionalFlag, formNote, isNewNote, titleHasBeenManuallyChanged]);
|
||||
}, [handleProvisionalFlag, formNote, setFormNote, isNewNote, titleHasBeenManuallyChanged, scheduleSaveNote]);
|
||||
|
||||
useWindowCommandHandler({
|
||||
dispatch: props.dispatch,
|
||||
formNote,
|
||||
setShowLocalSearch,
|
||||
noteSearchBarRef,
|
||||
editorRef,
|
||||
titleInputRef,
|
||||
saveNoteAndWait,
|
||||
setFormNote,
|
||||
});
|
||||
|
||||
@ -339,10 +273,15 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
id: formNote.id,
|
||||
status: 'saving',
|
||||
});
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [formNote, handleProvisionalFlag]);
|
||||
}, [formNote, setFormNote, handleProvisionalFlag, props.dispatch]);
|
||||
|
||||
const onMessage = useMessageHandler(scrollWhenReady, setScrollWhenReady, editorRef, setLocalSearchResultCount, props.dispatch, formNote, htmlToMarkdown, markupToHtml);
|
||||
const { scrollWhenReady, clearScrollWhenReady } = useScrollWhenReadyOptions({
|
||||
noteId: formNote.id,
|
||||
selectedNoteHash: props.selectedNoteHash,
|
||||
lastEditorScrollPercents: props.lastEditorScrollPercents,
|
||||
editorRef,
|
||||
});
|
||||
const onMessage = useMessageHandler(scrollWhenReady, clearScrollWhenReady, editorRef, setLocalSearchResultCount, props.dispatch, formNote, htmlToMarkdown, markupToHtml);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const externalEditWatcher_noteChange = useCallback((event: any) => {
|
||||
@ -355,8 +294,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
|
||||
setFormNote(newFormNote);
|
||||
}
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [formNote]);
|
||||
}, [formNote, setFormNote]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const onNotePropertyChange = useCallback((event: any) => {
|
||||
@ -373,8 +311,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
|
||||
return newFormNote;
|
||||
});
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, []);
|
||||
}, [setFormNote]);
|
||||
|
||||
useEffect(() => {
|
||||
eventManager.on(EventName.AlarmChange, onNotePropertyChange);
|
||||
@ -409,8 +346,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
});
|
||||
}, [props.dispatch]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
function renderNoNotes(rootStyle: any) {
|
||||
function renderNoNotes(rootStyle: React.CSSProperties) {
|
||||
const emptyDivStyle = {
|
||||
backgroundColor: 'black',
|
||||
opacity: 0.1,
|
||||
@ -493,7 +429,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
}
|
||||
|
||||
const onRichTextReadMoreLinkClick = useCallback(() => {
|
||||
bridge().openExternal('https://joplinapp.org/help/apps/rich_text_editor');
|
||||
void bridge().openExternal('https://joplinapp.org/help/apps/rich_text_editor');
|
||||
}, []);
|
||||
|
||||
const onRichTextDismissLinkClick = useCallback(() => {
|
||||
@ -521,8 +457,7 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
if (showRevisions) {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const revStyle: any = {
|
||||
const revStyle: React.CSSProperties = {
|
||||
// ...props.style,
|
||||
display: 'inline-flex',
|
||||
padding: theme.margin,
|
||||
|
@ -36,8 +36,7 @@ interface Props {
|
||||
noteTitle: string;
|
||||
noteIsTodo: number;
|
||||
isProvisional: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
titleInputRef: any;
|
||||
titleInputRef: React.RefObject<HTMLInputElement>;
|
||||
onTitleChange(event: ChangeEvent<HTMLInputElement>): void;
|
||||
disabled: boolean;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect, useCallback, RefObject } from 'react';
|
||||
import { FormNote, defaultFormNote, ResourceInfos } from './types';
|
||||
import { clearResourceCache, attachedResources } from './resourceHandling';
|
||||
import AsyncActionQueue from '@joplin/lib/AsyncActionQueue';
|
||||
@ -25,14 +25,15 @@ export interface HookDependencies {
|
||||
decryptionStarted: boolean;
|
||||
noteId: string;
|
||||
isProvisional: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
titleInputRef: any;
|
||||
titleInputRef: RefObject<HTMLInputElement>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
editorRef: any;
|
||||
onBeforeLoad(event: OnLoadEvent): void;
|
||||
onAfterLoad(event: OnLoadEvent): void;
|
||||
}
|
||||
|
||||
export type SetFormNote = ReturnType<typeof useState<FormNote>>[1];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
function installResourceChangeHandler(onResourceChangeHandler: Function) {
|
||||
ResourceFetcher.instance().on('downloadComplete', onResourceChangeHandler);
|
||||
|
@ -25,7 +25,6 @@ export default function useMarkupToHtml(deps: HookDependencies) {
|
||||
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
|
||||
customCss: customCss || '',
|
||||
});
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [plugins, customCss]);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
@ -63,6 +62,5 @@ export default function useMarkupToHtml(deps: HookDependencies) {
|
||||
});
|
||||
|
||||
return result;
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [themeId, customCss, markupToHtml, whiteBackgroundNoteRendering]);
|
||||
}, [themeId, markupToHtml, whiteBackgroundNoteRendering, deps.settingValue]);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useCallback } from 'react';
|
||||
import { FormNote, HtmlToMarkdownHandler, MarkupToHtmlHandler } from './types';
|
||||
import { FormNote, HtmlToMarkdownHandler, MarkupToHtmlHandler, ScrollOptions } from './types';
|
||||
import contextMenu from './contextMenu';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
import PostMessageService from '@joplin/lib/services/PostMessageService';
|
||||
@ -8,7 +8,7 @@ import { reg } from '@joplin/lib/registry';
|
||||
const bridge = require('@electron/remote').require('./bridge').default;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
|
||||
export default function useMessageHandler(scrollWhenReady: any, setScrollWhenReady: Function, editorRef: any, setLocalSearchResultCount: Function, dispatch: Function, formNote: FormNote, htmlToMd: HtmlToMarkdownHandler, mdToHtml: MarkupToHtmlHandler) {
|
||||
export default function useMessageHandler(scrollWhenReady: ScrollOptions|null, clearScrollWhenReady: ()=> void, editorRef: any, setLocalSearchResultCount: Function, dispatch: Function, formNote: FormNote, htmlToMd: HtmlToMarkdownHandler, mdToHtml: MarkupToHtmlHandler) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
return useCallback(async (event: any) => {
|
||||
const msg = event.channel ? event.channel : '';
|
||||
@ -25,7 +25,7 @@ export default function useMessageHandler(scrollWhenReady: any, setScrollWhenRea
|
||||
} else if (msg === 'noteRenderComplete') {
|
||||
if (scrollWhenReady) {
|
||||
const options = { ...scrollWhenReady };
|
||||
setScrollWhenReady(null);
|
||||
clearScrollWhenReady();
|
||||
editorRef.current.scrollTo(options);
|
||||
}
|
||||
} else if (msg === 'setMarkerCount') {
|
||||
|
@ -0,0 +1,65 @@
|
||||
import Logger from '@joplin/utils/Logger';
|
||||
import { RefObject, useCallback } from 'react';
|
||||
import { FormNote, NoteBodyEditorRef } from './types';
|
||||
import { formNoteToNote } from '.';
|
||||
import ExternalEditWatcher from '@joplin/lib/services/ExternalEditWatcher';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import type { Dispatch } from 'redux';
|
||||
import eventManager, { EventName } from '@joplin/lib/eventManager';
|
||||
import type { SetFormNote } from './useFormNote';
|
||||
|
||||
const logger = Logger.create('useScheduleSaveCallbacks');
|
||||
|
||||
interface Props {
|
||||
setFormNote: RefObject<SetFormNote>;
|
||||
dispatch: Dispatch;
|
||||
editorRef: RefObject<NoteBodyEditorRef>;
|
||||
}
|
||||
|
||||
const useScheduleSaveCallbacks = (props: Props) => {
|
||||
const scheduleSaveNote = useCallback(async (formNote: FormNote) => {
|
||||
if (!formNote.saveActionQueue) throw new Error('saveActionQueue is not set!!'); // Sanity check
|
||||
|
||||
// reg.logger().debug('Scheduling...', formNote);
|
||||
|
||||
const makeAction = (formNote: FormNote) => {
|
||||
return async function() {
|
||||
const note = await formNoteToNote(formNote);
|
||||
logger.debug('Saving note...', note);
|
||||
const savedNote = await Note.save(note);
|
||||
|
||||
props.setFormNote.current((prev: FormNote) => {
|
||||
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
|
||||
});
|
||||
|
||||
void ExternalEditWatcher.instance().updateNoteFile(savedNote);
|
||||
|
||||
props.dispatch({
|
||||
type: 'EDITOR_NOTE_STATUS_REMOVE',
|
||||
id: formNote.id,
|
||||
});
|
||||
|
||||
eventManager.emit(EventName.NoteContentChange, { note: savedNote });
|
||||
};
|
||||
};
|
||||
|
||||
formNote.saveActionQueue.push(makeAction(formNote));
|
||||
}, [props.dispatch, props.setFormNote]);
|
||||
|
||||
const saveNoteIfWillChange = useCallback(async (formNote: FormNote) => {
|
||||
if (!formNote.id || !formNote.bodyWillChangeId) return;
|
||||
|
||||
const body = await props.editorRef.current.content();
|
||||
|
||||
void scheduleSaveNote({
|
||||
...formNote,
|
||||
body: body,
|
||||
bodyWillChangeId: 0,
|
||||
bodyChangeId: 0,
|
||||
});
|
||||
}, [scheduleSaveNote, props.editorRef]);
|
||||
|
||||
return { saveNoteIfWillChange, scheduleSaveNote };
|
||||
};
|
||||
|
||||
export default useScheduleSaveCallbacks;
|
@ -0,0 +1,44 @@
|
||||
import { RefObject, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { NoteBodyEditorRef, ScrollOptions, ScrollOptionTypes } from './types';
|
||||
import usePrevious from '@joplin/lib/hooks/usePrevious';
|
||||
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher';
|
||||
import type { EditorScrollPercents } from '../../../app.reducer';
|
||||
|
||||
interface Props {
|
||||
noteId: string;
|
||||
selectedNoteHash: string;
|
||||
lastEditorScrollPercents: EditorScrollPercents;
|
||||
editorRef: RefObject<NoteBodyEditorRef>;
|
||||
}
|
||||
|
||||
const useScrollWhenReadyOptions = ({ noteId, selectedNoteHash, lastEditorScrollPercents, editorRef }: Props) => {
|
||||
const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions|null>(null);
|
||||
|
||||
const previousNoteId = usePrevious(noteId);
|
||||
const lastScrollPercentsRef = useRef<EditorScrollPercents>();
|
||||
lastScrollPercentsRef.current = lastEditorScrollPercents;
|
||||
|
||||
useEffect(() => {
|
||||
if (noteId === previousNoteId) return;
|
||||
|
||||
if (editorRef.current) {
|
||||
editorRef.current.resetScroll();
|
||||
}
|
||||
|
||||
const lastScrollPercent = lastScrollPercentsRef.current[noteId] || 0;
|
||||
setScrollWhenReady({
|
||||
type: selectedNoteHash ? ScrollOptionTypes.Hash : ScrollOptionTypes.Percent,
|
||||
value: selectedNoteHash ? selectedNoteHash : lastScrollPercent,
|
||||
});
|
||||
|
||||
void ResourceEditWatcher.instance().stopWatchingAll();
|
||||
}, [noteId, previousNoteId, selectedNoteHash, editorRef]);
|
||||
|
||||
const clearScrollWhenReady = useCallback(() => {
|
||||
setScrollWhenReady(null);
|
||||
}, []);
|
||||
|
||||
return { scrollWhenReady, clearScrollWhenReady };
|
||||
};
|
||||
|
||||
export default useScrollWhenReadyOptions;
|
@ -15,7 +15,6 @@ const commandsWithDependencies = [
|
||||
type SetFormNoteCallback = (callback: (prev: FormNote)=> FormNote)=> void;
|
||||
|
||||
interface HookDependencies {
|
||||
formNote: FormNote;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
setShowLocalSearch: Function;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
@ -23,10 +22,7 @@ interface HookDependencies {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
noteSearchBarRef: any;
|
||||
editorRef: RefObject<NoteBodyEditorRef>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
titleInputRef: any;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
saveNoteAndWait: Function;
|
||||
titleInputRef: RefObject<HTMLInputElement>;
|
||||
setFormNote: SetFormNoteCallback;
|
||||
}
|
||||
|
||||
@ -109,6 +105,5 @@ export default function useWindowCommandHandler(dependencies: HookDependencies)
|
||||
CommandService.instance().unregisterRuntime(command.declaration.name);
|
||||
}
|
||||
};
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef]);
|
||||
}, [editorRef, setShowLocalSearch, noteSearchBarRef, titleInputRef, setFormNote]);
|
||||
}
|
||||
|
@ -83,7 +83,8 @@ const useRerenderHandler = (props: Props) => {
|
||||
return accum;
|
||||
}, {});
|
||||
const onlyNoteBodyHasChanged = Object.keys(changedDeps).length === 1 && changedDeps[0];
|
||||
const onlyCheckboxesHaveChanged = previousDeps[0] && changedDeps[0] && onlyCheckboxHasChangedHack(previousDeps[0], props.noteBody);
|
||||
const previousBody = previousDeps[0] as string;
|
||||
const onlyCheckboxesHaveChanged = previousDeps[0] && changedDeps[0] && onlyCheckboxHasChangedHack(previousBody, props.noteBody);
|
||||
const previousHash = usePrevious(props.noteHash, '');
|
||||
const hashChanged = previousHash !== props.noteHash;
|
||||
|
||||
|
@ -2,9 +2,8 @@ import shim from '../shim';
|
||||
|
||||
const { useRef, useEffect } = shim.react();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const usePrevious = (value: any, initialValue: any = null) => {
|
||||
const ref = useRef(initialValue);
|
||||
const usePrevious = <T> (value: T, initialValue: T = null) => {
|
||||
const ref = useRef<T>(initialValue);
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user