diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.tsx b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.tsx index 92c32343d7..ff04015cbc 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.tsx +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/Editor.tsx @@ -67,6 +67,11 @@ import 'codemirror/mode/diff/diff'; import 'codemirror/mode/erlang/erlang'; import 'codemirror/mode/sql/sql'; +interface ExtendedWindow { + CodeMirror?: unknown; +} +declare const window: ExtendedWindow; + export interface EditorProps { value: string; @@ -100,6 +105,14 @@ function Editor(props: EditorProps, ref: any) { const editorParent = useRef(null); const lastEditTime = useRef(NaN); + useEffect(() => { + window.CodeMirror = CodeMirror; + + return () => { + window.CodeMirror = undefined; + }; + }, []); + // Codemirror plugins add new commands to codemirror (or change it's behavior) // This command adds the smartListIndent function which will be bound to tab useListIdent(CodeMirror); diff --git a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/utils/useExternalPlugins.ts b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/utils/useExternalPlugins.ts index 4ea72ec809..0ae8babbc0 100644 --- a/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/utils/useExternalPlugins.ts +++ b/packages/app-desktop/gui/NoteEditor/NoteBody/CodeMirror/v5/utils/useExternalPlugins.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; import { PluginStates } from '@joplin/lib/services/plugins/reducer'; +import bridge from '../../../../../../services/bridge'; import { contentScriptsToCodeMirrorPlugin } from '@joplin/lib/services/plugins/utils/loadContentScripts'; import { extname } from 'path'; import shim from '@joplin/lib/shim'; @@ -7,6 +8,18 @@ import uuid from '@joplin/lib/uuid'; import { reg } from '@joplin/lib/registry'; +const addPluginDependency = (path: string) => { + const id = `content-script-${encodeURIComponent(path)}`; + if (document.getElementById(id)) { + return; + } + + const element = document.createElement('script'); + element.setAttribute('id', id); + element.setAttribute('src', path); + document.head.appendChild(element); +}; + // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied export default function useExternalPlugins(CodeMirror: any, plugins: PluginStates) { const [options, setOptions] = useState({}); @@ -23,7 +36,14 @@ export default function useExternalPlugins(CodeMirror: any, plugins: PluginState if (mod.codeMirrorResources) { for (const asset of mod.codeMirrorResources) { try { - require(`codemirror/${asset}`); + let assetPath = shim.fsDriver().resolveRelativePathWithinDir(`${bridge().vendorDir()}/lib/codemirror/`, asset); + + // Compatibility with old versions of Joplin, where the file extension was automatically added by require(). + if (extname(assetPath) === '') { + assetPath += '.js'; + } + + addPluginDependency(assetPath); } catch (error) { error.message = `${asset} is not a valid CodeMirror asset, keymap or mode. You can find a list of valid assets here: https://codemirror.net/doc/manual.html#addons`; throw error; diff --git a/packages/app-desktop/tools/copyApplicationAssets.js b/packages/app-desktop/tools/copyApplicationAssets.js index 25cfa0acf9..6e47f1fff6 100644 --- a/packages/app-desktop/tools/copyApplicationAssets.js +++ b/packages/app-desktop/tools/copyApplicationAssets.js @@ -82,7 +82,7 @@ async function main() { const files = [ '@fortawesome/fontawesome-free/css/all.min.css', '@joeattardi/emoji-button/dist/index.js', - 'codemirror/addon/dialog/dialog.css', + 'codemirror/addon/', 'codemirror/lib/codemirror.css', 'mark.js/dist/mark.min.js', 'roboto-fontface/css/roboto/roboto-fontface.css',