1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

Mobile: Rich Text Editor: Enable syntax highlighting and auto-indent in the code block editor (#12909)

This commit is contained in:
Henry Heino
2025-08-19 23:29:30 -07:00
committed by GitHub
parent 8a811b9e78
commit af5c0135dc
20 changed files with 294 additions and 88 deletions

View File

@@ -7,6 +7,9 @@ import { OnMessageEvent, WebViewControl } from '../../components/ExtendedWebView
import { EditorEvent } from '@joplin/editor/events';
import Logger from '@joplin/utils/Logger';
import RNToWebViewMessenger from '../../utils/ipc/RNToWebViewMessenger';
import { _ } from '@joplin/lib/locale';
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
import useCodeMirrorPlugins from './utils/useCodeMirrorPlugins';
import Resource from '@joplin/lib/models/Resource';
import { parseResourceUrl } from '@joplin/lib/urlUtils';
const { isImageMimeType } = require('@joplin/lib/resourceUtils');
@@ -15,9 +18,10 @@ const logger = Logger.create('markdownEditor');
interface Props {
editorOptions: EditorOptions;
initialSelection: SelectionRange;
initialSelection: SelectionRange|null;
noteHash: string;
globalSearch: string;
pluginStates: PluginStates;
onEditorEvent: (event: EditorEvent)=> void;
onAttachFile: (mime: string, base64: string)=> void;
@@ -33,9 +37,11 @@ const defaultSearchState: SearchState = {
dialogVisible: false,
};
type Result = SetUpResult<EditorProcessApi> & { hasPlugins: boolean };
const useWebViewSetup = ({
editorOptions, initialSelection, noteHash, globalSearch, webviewRef, onEditorEvent, onAttachFile,
}: Props): SetUpResult<EditorProcessApi> => {
editorOptions, pluginStates, initialSelection, noteHash, globalSearch, webviewRef, onEditorEvent, onAttachFile,
}: Props): Result => {
const setInitialSelectionJs = initialSelection ? `
cm.select(${initialSelection.start}, ${initialSelection.end});
cm.execCommand('scrollSelectionIntoView');
@@ -51,20 +57,21 @@ const useWebViewSetup = ({
` : '';
const injectedJavaScript = useMemo(() => `
if (typeof markdownEditorBundle === 'undefined') {
${shim.injectedJs('markdownEditorBundle')};
window.markdownEditorBundle = markdownEditorBundle;
markdownEditorBundle.setUpLogger();
}
if (!window.cm) {
const parentClassName = ${JSON.stringify(editorOptions.parentElementClassName)};
const foundParent = document.getElementsByClassName(parentClassName).length > 0;
const parentClassName = ${JSON.stringify(editorOptions?.parentElementOrClassName)};
const foundParent = !!parentClassName && document.getElementsByClassName(parentClassName).length > 0;
// On Android, injectedJavaScript can be run multiple times, including once before the
// document has loaded. To avoid logging an error each time the editor starts, don't throw
// if the parent element can't be found:
if (foundParent) {
${shim.injectedJs('markdownEditorBundle')};
markdownEditorBundle.setUpLogger();
window.cm = markdownEditorBundle.initializeEditor(
${JSON.stringify(editorOptions)}
);
window.cm = markdownEditorBundle.createMainEditor(${JSON.stringify(editorOptions)});
${jumpToHashJs}
// Set the initial selection after jumping to the header -- the initial selection,
@@ -75,7 +82,7 @@ const useWebViewSetup = ({
window.onresize = () => {
cm.execCommand('scrollSelectionIntoView');
};
} else {
} else if (parentClassName) {
console.log('No parent element found with class name ', parentClassName);
}
}
@@ -101,6 +108,10 @@ const useWebViewSetup = ({
const onAttachRef = useRef(onAttachFile);
onAttachRef.current = onAttachFile;
const codeMirrorPlugins = useCodeMirrorPlugins(pluginStates);
const codeMirrorPluginsRef = useRef(codeMirrorPlugins);
codeMirrorPluginsRef.current = codeMirrorPlugins;
const editorMessenger = useMemo(() => {
const localApi: MainProcessApi = {
async onEditorEvent(event) {
@@ -112,6 +123,13 @@ const useWebViewSetup = ({
async onPasteFile(type, data) {
onAttachRef.current(type, data);
},
async onLocalize(text) {
const localizationFunction = _;
return localizationFunction(text);
},
async onEditorAdded() {
messenger.remoteApi.updatePlugins(codeMirrorPluginsRef.current);
},
async onResolveImageSrc(src) {
const url = parseResourceUrl(src);
if (!url.itemId) return null;
@@ -153,17 +171,22 @@ const useWebViewSetup = ({
const editorSettings = editorOptions.settings;
useEffect(() => {
api.editor.updateSettings(editorSettings);
api.updateSettings(editorSettings);
}, [api, editorSettings]);
useEffect(() => {
api.updatePlugins(codeMirrorPlugins);
}, [codeMirrorPlugins, api]);
return useMemo(() => ({
pageSetup: {
js: injectedJavaScript,
css: '',
},
hasPlugins: codeMirrorPlugins.length > 0,
api,
webViewEventHandlers,
}), [injectedJavaScript, api, webViewEventHandlers]);
}), [injectedJavaScript, api, webViewEventHandlers, codeMirrorPlugins]);
};
export default useWebViewSetup;