1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-21 09:38:01 +02:00

Desktop: Resolves #8749: Use plain text editor in safe mode (#8750)

This commit is contained in:
Henry Heino 2023-10-22 04:00:19 -07:00 committed by GitHub
parent c2bfc526e7
commit 03bd77c107
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 62 deletions

View File

@ -242,6 +242,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/PlainEditor/PlainEditor.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js

1
.gitignore vendored
View File

@ -224,6 +224,7 @@ packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/CodeMirror.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/Editor.js
packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v6/useEditorCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/PlainEditor/PlainEditor.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/TinyMCE.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js

View File

@ -740,7 +740,9 @@ class MainScreenComponent extends React.Component<Props, State> {
editor: () => { editor: () => {
let bodyEditor = this.props.settingEditorCodeView ? 'CodeMirror' : 'TinyMCE'; let bodyEditor = this.props.settingEditorCodeView ? 'CodeMirror' : 'TinyMCE';
if (this.props.settingEditorCodeView && this.props.enableBetaMarkdownEditor) { if (this.props.isSafeMode) {
bodyEditor = 'PlainText';
} else if (this.props.settingEditorCodeView && this.props.enableBetaMarkdownEditor) {
bodyEditor = 'CodeMirror6'; bodyEditor = 'CodeMirror6';
} }
return <NoteEditor key={key} bodyEditor={bodyEditor} />; return <NoteEditor key={key} bodyEditor={bodyEditor} />;

View File

@ -0,0 +1,56 @@
// Used in safe mode
import * as React from 'react';
import { ForwardedRef } from 'react';
import { useEffect, useCallback, useRef, forwardRef, useImperativeHandle } from 'react';
import { NoteBodyEditorProps, NoteBodyEditorRef } from '../../utils/types';
const PlainEditor = (props: NoteBodyEditorProps, ref: ForwardedRef<NoteBodyEditorRef>) => {
const editorRef = useRef<HTMLTextAreaElement>();
useImperativeHandle(ref, () => {
return {
content: () => editorRef.current?.value ?? '',
resetScroll: () => {
editorRef.current.scrollTop = 0;
},
scrollTo: () => {
// Not supported
},
supportsCommand: _name => {
return false;
},
execCommand: async _command => {
// Not supported
},
};
}, []);
useEffect(() => {
if (!editorRef.current) return;
if (editorRef.current.value !== props.content) {
editorRef.current.value = props.content;
}
}, [props.content]);
const onChange = useCallback((event: any) => {
props.onChange({ changeId: null, content: event.target.value });
}, [props.onChange]);
return (
<div style={props.style}>
<textarea
ref={editorRef}
style={{ width: '100%', height: '100%' }}
defaultValue={props.content}
onChange={onChange}
/>
</div>
);
};
export default forwardRef(PlainEditor);

View File

@ -1,50 +0,0 @@
// Kept only for reference
import * as React from 'react';
import { useEffect, useCallback, useRef, forwardRef, useImperativeHandle } from 'react';
export interface OnChangeEvent {
changeId: number,
content: any,
}
interface PlainEditorProps {
style: any,
onChange(event: OnChangeEvent): void,
onWillChange(event:any): void,
markupToHtml: Function,
disabled: boolean,
}
const PlainEditor = (props:PlainEditorProps, ref:any) => {
const editorRef = useRef<any>();
useImperativeHandle(ref, () => {
return {
content: () => '',
};
}, []);
useEffect(() => {
if (!editorRef.current) return;
editorRef.current.value = props.defaultEditorState.value;
}, [props.defaultEditorState]);
const onChange = useCallback((event:any) => {
props.onChange({ changeId: null, content: event.target.value });
}, [props.onWillChange, props.onChange]);
return (
<div style={props.style}>
<textarea
ref={editorRef}
style={{ width: '100%', height: '100%' }}
defaultValue={props.defaultEditorState.value}
onChange={onChange}
/>;
</div>
);
};
export default forwardRef(PlainEditor);

View File

@ -14,7 +14,7 @@ import useFormNote, { OnLoadEvent } from './utils/useFormNote';
import useEffectiveNoteId from './utils/useEffectiveNoteId'; import useEffectiveNoteId from './utils/useEffectiveNoteId';
import useFolder from './utils/useFolder'; import useFolder from './utils/useFolder';
import styles_ from './styles'; import styles_ from './styles';
import { NoteEditorProps, FormNote, ScrollOptions, ScrollOptionTypes, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions } from './utils/types'; import { NoteEditorProps, FormNote, ScrollOptions, ScrollOptionTypes, OnChangeEvent, NoteBodyEditorProps, AllAssetsOptions, NoteBodyEditorRef } from './utils/types';
import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index'; import ResourceEditWatcher from '@joplin/lib/services/ResourceEditWatcher/index';
import CommandService from '@joplin/lib/services/CommandService'; import CommandService from '@joplin/lib/services/CommandService';
import ToolbarButton from '../ToolbarButton/ToolbarButton'; import ToolbarButton from '../ToolbarButton/ToolbarButton';
@ -45,6 +45,7 @@ import { ModelType } from '@joplin/lib/BaseModel';
import BaseItem from '@joplin/lib/models/BaseItem'; import BaseItem from '@joplin/lib/models/BaseItem';
import { ErrorCode } from '@joplin/lib/errors'; import { ErrorCode } from '@joplin/lib/errors';
import ItemChange from '@joplin/lib/models/ItemChange'; import ItemChange from '@joplin/lib/models/ItemChange';
import PlainEditor from './NoteBody/PlainEditor/PlainEditor';
import CodeMirror6 from './NoteBody/CodeMirror/v6/CodeMirror'; import CodeMirror6 from './NoteBody/CodeMirror/v6/CodeMirror';
import CodeMirror5 from './NoteBody/CodeMirror/v5/CodeMirror'; import CodeMirror5 from './NoteBody/CodeMirror/v5/CodeMirror';
@ -60,7 +61,7 @@ function NoteEditor(props: NoteEditorProps) {
const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions>(null); const [scrollWhenReady, setScrollWhenReady] = useState<ScrollOptions>(null);
const [isReadOnly, setIsReadOnly] = useState<boolean>(false); const [isReadOnly, setIsReadOnly] = useState<boolean>(false);
const editorRef = useRef<any>(); const editorRef = useRef<NoteBodyEditorRef>();
const titleInputRef = useRef<any>(); const titleInputRef = useRef<any>();
const isMountedRef = useRef(true); const isMountedRef = useRef(true);
const noteSearchBarRef = useRef(null); const noteSearchBarRef = useRef(null);
@ -462,6 +463,8 @@ function NoteEditor(props: NoteEditorProps) {
if (props.bodyEditor === 'TinyMCE') { if (props.bodyEditor === 'TinyMCE') {
editor = <TinyMCE {...editorProps}/>; editor = <TinyMCE {...editorProps}/>;
} else if (props.bodyEditor === 'PlainText') {
editor = <PlainEditor {...editorProps}/>;
} else if (props.bodyEditor === 'CodeMirror') { } else if (props.bodyEditor === 'CodeMirror') {
editor = <CodeMirror5 {...editorProps}/>; editor = <CodeMirror5 {...editorProps}/>;
} else if (props.bodyEditor === 'CodeMirror6') { } else if (props.bodyEditor === 'CodeMirror6') {

View File

@ -1,5 +1,5 @@
import { useEffect } from 'react'; import { RefObject, useEffect } from 'react';
import { FormNote, ScrollOptionTypes } from './types'; import { FormNote, NoteBodyEditorRef, ScrollOptionTypes } from './types';
import editorCommandDeclarations, { enabledCondition } from '../editorCommandDeclarations'; import editorCommandDeclarations, { enabledCondition } from '../editorCommandDeclarations';
import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService'; import CommandService, { CommandDeclaration, CommandRuntime, CommandContext } from '@joplin/lib/services/CommandService';
import time from '@joplin/lib/time'; import time from '@joplin/lib/time';
@ -12,6 +12,8 @@ const commandsWithDependencies = [
require('../commands/pasteAsText'), require('../commands/pasteAsText'),
]; ];
type SetFormNoteCallback = (callback: (prev: FormNote)=> FormNote)=> void;
interface HookDependencies { interface HookDependencies {
formNote: FormNote; formNote: FormNote;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
@ -19,16 +21,18 @@ interface HookDependencies {
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
dispatch: Function; dispatch: Function;
noteSearchBarRef: any; noteSearchBarRef: any;
editorRef: any; editorRef: RefObject<NoteBodyEditorRef>;
titleInputRef: any; titleInputRef: any;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
saveNoteAndWait: Function; saveNoteAndWait: Function;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied setFormNote: SetFormNoteCallback;
setFormNote: Function;
} }
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied function editorCommandRuntime(
function editorCommandRuntime(declaration: CommandDeclaration, editorRef: any, setFormNote: Function): CommandRuntime { declaration: CommandDeclaration,
editorRef: RefObject<NoteBodyEditorRef>,
setFormNote: SetFormNoteCallback,
): CommandRuntime {
return { return {
execute: async (_context: CommandContext, ...args: any[]) => { execute: async (_context: CommandContext, ...args: any[]) => {
if (!editorRef.current) { if (!editorRef.current) {

View File

@ -12,8 +12,9 @@ export default function stateToWhenClauseContext(state: AppState, options: WhenC
...libStateToWhenClauseContext(state, options), ...libStateToWhenClauseContext(state, options),
// UI elements // UI elements
markdownEditorVisible: !!state.settings['editor.codeView'], markdownEditorVisible: !!state.settings['editor.codeView'] && !state.settings['isSafeMode'],
richTextEditorVisible: !state.settings['editor.codeView'], richTextEditorVisible: !state.settings['editor.codeView'] && !state.settings['isSafeMode'],
markdownEditorPaneVisible: state.settings['editor.codeView'] && state.noteVisiblePanes.includes('editor'), markdownEditorPaneVisible: state.settings['editor.codeView'] && state.noteVisiblePanes.includes('editor'),
markdownViewerPaneVisible: state.settings['editor.codeView'] && state.noteVisiblePanes.includes('viewer'), markdownViewerPaneVisible: state.settings['editor.codeView'] && state.noteVisiblePanes.includes('viewer'),
modalDialogVisible: !!Object.keys(state.visibleDialogs).length, modalDialogVisible: !!Object.keys(state.visibleDialogs).length,