1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Desktop: Resolves #9747: CodeMirror 6 plugin API: Support non-inline CSS assets (#9748)

This commit is contained in:
Henry Heino 2024-01-22 07:27:42 -08:00 committed by GitHub
parent d4d400217b
commit f3518cddbe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 62 additions and 7 deletions

View File

@ -0,0 +1,5 @@
.cm-gutter {
background-color: var(--joplin-background-color3);
color: var(--joplin-color3);
}

View File

@ -4,7 +4,7 @@
// This is necessary. Having multiple copies of the CodeMirror libraries loaded can cause
// the editor to not work properly.
//
import { lineNumbers } from '@codemirror/view';
import { lineNumbers, highlightActiveLineGutter, } from '@codemirror/view';
//
// For the above import to work, you may also need to add @codemirror/view as a dev dependency
// to package.json. (For the type information only).
@ -22,10 +22,37 @@ export default (_context: { contentScriptId: string }) => {
// We add the extension to CodeMirror using a helper method:
codeMirrorWrapper.addExtension([
lineNumbers(),
// We can include multiple extensions here:
highlightActiveLineGutter(),
]);
// See https://codemirror.net/ for more built-in extensions and configuration
// options.
},
// There are two main ways to style the CodeMirror editor:
// 1. With a CodeMirror6 theme extension (see https://codemirror.net/examples/styling/#themes)
// 2. With CSS assets
//
// CSS assets can be added by exporting an `assets` function:
assets: () => [
// We can include styles by either referencing a file
{ name: './assets/style.css' },
// or including the style sheet inline
{
inline: true,
mime: 'text/css',
text: `
/* This CSS class is added by the highlightActiveLineGutter extension: */
.cm-gutter .cm-activeLineGutter {
text-decoration: underline;
color: var(--joplin-color2);
background-color: var(--joplin-background-color2);
}
`,
},
],
};
};

View File

@ -9,6 +9,7 @@ import { ContentScriptType } from '@joplin/lib/services/plugins/api/types';
import shim from '@joplin/lib/shim';
import PluginService from '@joplin/lib/services/plugins/PluginService';
import setupVim from '@joplin/editor/CodeMirror/util/setupVim';
import { dirname } from 'path';
interface Props extends EditorProps {
style: React.CSSProperties;
@ -66,6 +67,11 @@ const Editor = (props: Props, ref: ForwardedRef<CodeMirrorControl>) => {
pluginId,
contentScriptId: contentScript.id,
contentScriptJs: () => shim.fsDriver().readFile(contentScript.path),
loadCssAsset: (name: string) => {
const assetPath = dirname(contentScript.path);
const path = shim.fsDriver().resolveRelativePathWithinDir(assetPath, name);
return shim.fsDriver().readFile(path, 'utf8');
},
postMessageHandler: (message: any) => {
const plugin = PluginService.instance().pluginById(pluginId);
return plugin.emitContentScriptMessage(contentScript.id, message);

View File

@ -76,12 +76,14 @@ describe('createEditor', () => {
const testPlugin1 = {
pluginId: 'a.plugin.id',
contentScriptId: 'a.plugin.id.contentScript',
loadCssAsset: async (_name: string) => '* { color: red; }',
contentScriptJs: getContentScriptJs,
postMessageHandler,
};
const testPlugin2 = {
pluginId: 'another.plugin.id',
contentScriptId: 'another.plugin.id.contentScript',
loadCssAsset: async (_name: string) => '...',
contentScriptJs: getContentScriptJs,
postMessageHandler,
};

View File

@ -119,7 +119,7 @@ export default class PluginLoader {
});
};
addScript(exports => {
addScript(async exports => {
if (!exports?.default || !(typeof exports.default === 'function')) {
throw new Error('All plugins must have a function default export');
}
@ -143,16 +143,30 @@ export default class PluginLoader {
const cssStrings = [];
for (const asset of loadedPlugin.assets()) {
let assetText: string = asset.text;
let assetMime: string = asset.mime;
if (!asset.inline) {
this.logMessage('Warning: The CM6 plugin API currently only supports inline CSS.');
continue;
if (!asset.name) {
throw new Error('Non-inline asset missing required property "name"');
}
if (assetMime !== 'text/css' && !asset.name.endsWith('.css')) {
throw new Error(
`Non-css assets are not supported by the CodeMirror 6 editor. (Asset path: ${asset.name})`,
);
}
assetText = await plugin.loadCssAsset(asset.name);
assetMime = 'text/css';
}
if (asset.mime !== 'text/css') {
throw new Error('Inline assets must have property "mime" set to "text/css"');
if (assetMime !== 'text/css') {
throw new Error(
'Plugin assets must have property "mime" set to "text/css" or have a filename ending with ".css"',
);
}
cssStrings.push(asset.text);
cssStrings.push(assetText);
}
addStyles(cssStrings);

View File

@ -68,6 +68,7 @@ export interface PluginData {
pluginId: string;
contentScriptId: string;
contentScriptJs: ()=> Promise<string>;
loadCssAsset: (name: string)=> Promise<string>;
postMessageHandler: (message: any)=> any;
}