2021-07-13 20:13:13 +02:00
|
|
|
/* eslint-disable import/prefer-default-export */
|
|
|
|
|
|
|
|
// This contains the CodeMirror instance, which needs to be built into a bundle
|
2024-01-26 22:19:28 +02:00
|
|
|
// using `yarn buildInjectedJs`. This bundle is then loaded from
|
2021-07-13 20:13:13 +02:00
|
|
|
// NoteEditor.tsx into the webview.
|
|
|
|
//
|
|
|
|
// In general, since this file is harder to debug due to the intermediate built
|
2024-02-26 12:16:23 +02:00
|
|
|
// step, it's better to keep it as light as possible - it should just be a light
|
2021-07-13 20:13:13 +02:00
|
|
|
// wrapper to access CodeMirror functionalities. Anything else should be done
|
|
|
|
// from NoteEditor.tsx.
|
|
|
|
|
2023-09-21 10:12:40 +02:00
|
|
|
import { EditorSettings } from '@joplin/editor/types';
|
|
|
|
import createEditor from '@joplin/editor/CodeMirror/createEditor';
|
|
|
|
import CodeMirrorControl from '@joplin/editor/CodeMirror/CodeMirrorControl';
|
2024-03-11 17:02:15 +02:00
|
|
|
import WebViewToRNMessenger from '../../../utils/ipc/WebViewToRNMessenger';
|
|
|
|
import { WebViewToEditorApi } from '../types';
|
2024-06-21 18:16:12 +02:00
|
|
|
import { focus } from '@joplin/lib/utils/focusHandler';
|
2022-12-08 01:19:55 +02:00
|
|
|
|
2024-03-11 17:02:15 +02:00
|
|
|
export const initCodeMirror = (
|
|
|
|
parentElement: HTMLElement,
|
|
|
|
initialText: string,
|
|
|
|
settings: EditorSettings,
|
|
|
|
): CodeMirrorControl => {
|
|
|
|
const messenger = new WebViewToRNMessenger<CodeMirrorControl, WebViewToEditorApi>('editor', null);
|
|
|
|
|
|
|
|
const control = createEditor(parentElement, {
|
2023-09-21 10:12:40 +02:00
|
|
|
initialText,
|
|
|
|
settings,
|
|
|
|
|
2024-07-16 20:28:05 +02:00
|
|
|
onPasteFile: async (data) => {
|
|
|
|
const reader = new FileReader();
|
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
|
|
reader.onload = async () => {
|
|
|
|
const dataUrl = reader.result as string;
|
|
|
|
const base64 = dataUrl.replace(/^data:.*;base64,/, '');
|
|
|
|
await messenger.remoteApi.onPasteFile(data.type, base64);
|
|
|
|
resolve();
|
|
|
|
};
|
|
|
|
reader.onerror = () => reject(new Error('Failed to load file.'));
|
|
|
|
|
|
|
|
reader.readAsDataURL(data);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2023-09-21 10:12:40 +02:00
|
|
|
onLogMessage: message => {
|
2024-03-11 17:02:15 +02:00
|
|
|
void messenger.remoteApi.logMessage(message);
|
2022-06-26 19:21:38 +02:00
|
|
|
},
|
2023-09-21 10:12:40 +02:00
|
|
|
onEvent: (event): void => {
|
2024-03-11 17:02:15 +02:00
|
|
|
void messenger.remoteApi.onEditorEvent(event);
|
2022-04-11 12:56:45 +02:00
|
|
|
},
|
2023-09-21 10:12:40 +02:00
|
|
|
});
|
2022-08-08 17:00:14 +02:00
|
|
|
|
2024-03-05 18:57:18 +02:00
|
|
|
// Works around https://github.com/laurent22/joplin/issues/10047 by handling
|
|
|
|
// the text/uri-list MIME type when pasting, rather than sending the paste event
|
|
|
|
// to CodeMirror.
|
|
|
|
//
|
|
|
|
// TODO: Remove this workaround when the issue has been fixed upstream.
|
2024-03-18 12:17:39 +02:00
|
|
|
control.on('paste', (_editor, event: ClipboardEvent) => {
|
2024-03-05 18:57:18 +02:00
|
|
|
const clipboardData = event.clipboardData;
|
|
|
|
if (clipboardData.types.length === 1 && clipboardData.types[0] === 'text/uri-list') {
|
|
|
|
event.preventDefault();
|
2024-03-18 12:17:39 +02:00
|
|
|
control.insertText(clipboardData.getData('text/uri-list'));
|
2024-03-05 18:57:18 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-06-21 18:16:12 +02:00
|
|
|
// Note: Just adding an onclick listener seems sufficient to focus the editor when its background
|
|
|
|
// is tapped.
|
|
|
|
parentElement.addEventListener('click', (event) => {
|
|
|
|
const activeElement = document.querySelector(':focus');
|
|
|
|
if (!parentElement.contains(activeElement) && event.target === parentElement) {
|
|
|
|
focus('initial editor focus', control);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-03-11 17:02:15 +02:00
|
|
|
messenger.setLocalInterface(control);
|
|
|
|
return control;
|
|
|
|
};
|