mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Plugins: Add support for getting plugin settings from a Markdown renderer
This commit is contained in:
parent
b097ab29ee
commit
8be22ed910
@ -206,7 +206,7 @@ describe('services_PluginService', () => {
|
|||||||
|
|
||||||
const mdToHtml = new MdToHtml();
|
const mdToHtml = new MdToHtml();
|
||||||
const module = require(contentScript.path).default;
|
const module = require(contentScript.path).default;
|
||||||
mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({}));
|
mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({}), '');
|
||||||
|
|
||||||
const result = await mdToHtml.render([
|
const result = await mdToHtml.render([
|
||||||
'```justtesting',
|
'```justtesting',
|
||||||
|
@ -48,6 +48,7 @@ import ItemChange from '@joplin/lib/models/ItemChange';
|
|||||||
import PlainEditor from './NoteBody/PlainEditor/PlainEditor';
|
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';
|
||||||
|
import { namespacedKey } from '@joplin/lib/services/plugins/api/JoplinSettings';
|
||||||
|
|
||||||
const commands = [
|
const commands = [
|
||||||
require('./commands/showRevisions'),
|
require('./commands/showRevisions'),
|
||||||
@ -159,10 +160,15 @@ function NoteEditor(props: NoteEditorProps) {
|
|||||||
return formNote.saveActionQueue.waitForAllDone();
|
return formNote.saveActionQueue.waitForAllDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const settingValue = useCallback((pluginId: string, key: string) => {
|
||||||
|
return Setting.value(namespacedKey(pluginId, key));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const markupToHtml = useMarkupToHtml({
|
const markupToHtml = useMarkupToHtml({
|
||||||
themeId: props.themeId,
|
themeId: props.themeId,
|
||||||
customCss: props.customCss,
|
customCss: props.customCss,
|
||||||
plugins: props.plugins,
|
plugins: props.plugins,
|
||||||
|
settingValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
const allAssets = useCallback(async (markupLanguage: number, options: AllAssetsOptions = null): Promise<any[]> => {
|
const allAssets = useCallback(async (markupLanguage: number, options: AllAssetsOptions = null): Promise<any[]> => {
|
||||||
|
@ -12,6 +12,7 @@ interface HookDependencies {
|
|||||||
themeId: number;
|
themeId: number;
|
||||||
customCss: string;
|
customCss: string;
|
||||||
plugins: PluginStates;
|
plugins: PluginStates;
|
||||||
|
settingValue: (pluginId: string, key: string)=> any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MarkupToHtmlOptions {
|
export interface MarkupToHtmlOptions {
|
||||||
@ -59,12 +60,16 @@ export default function useMarkupToHtml(deps: HookDependencies) {
|
|||||||
|
|
||||||
delete options.replaceResourceInternalToExternalLinks;
|
delete options.replaceResourceInternalToExternalLinks;
|
||||||
|
|
||||||
const result = await markupToHtml.render(markupLanguage, md, theme, { codeTheme: theme.codeThemeCss,
|
const result = await markupToHtml.render(markupLanguage, md, theme, {
|
||||||
|
codeTheme: theme.codeThemeCss,
|
||||||
resources: resources,
|
resources: resources,
|
||||||
postMessageSyntax: 'ipcProxySendToHost',
|
postMessageSyntax: 'ipcProxySendToHost',
|
||||||
splitted: true,
|
splitted: true,
|
||||||
externalAssetsOnly: true,
|
externalAssetsOnly: true,
|
||||||
codeHighlightCacheKey: 'useMarkupToHtml', ...options });
|
codeHighlightCacheKey: 'useMarkupToHtml',
|
||||||
|
settingValue: deps.settingValue,
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
TEMP_PATH=~/src/plugin-tests
|
TEMP_PATH=~/src/plugin-tests
|
||||||
NEED_COMPILING=0
|
NEED_COMPILING=1
|
||||||
PLUGIN_PATH=~/src/joplin/packages/app-cli/tests/support/plugins/simple
|
PLUGIN_PATH=~/src/plugin-abc
|
||||||
|
|
||||||
if [[ $NEED_COMPILING == 1 ]]; then
|
if [[ $NEED_COMPILING == 1 ]]; then
|
||||||
mkdir -p "$TEMP_PATH"
|
mkdir -p "$TEMP_PATH"
|
||||||
|
@ -7,6 +7,7 @@ export interface ChangeEvent {
|
|||||||
keys: string[];
|
keys: string[];
|
||||||
}
|
}
|
||||||
export type ChangeHandler = (event: ChangeEvent) => void;
|
export type ChangeHandler = (event: ChangeEvent) => void;
|
||||||
|
export declare const namespacedKey: (pluginId: string, key: string) => string;
|
||||||
/**
|
/**
|
||||||
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
|
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
|
||||||
*
|
*
|
||||||
@ -19,8 +20,6 @@ export type ChangeHandler = (event: ChangeEvent) => void;
|
|||||||
export default class JoplinSettings {
|
export default class JoplinSettings {
|
||||||
private plugin_;
|
private plugin_;
|
||||||
constructor(plugin: Plugin);
|
constructor(plugin: Plugin);
|
||||||
private get keyPrefix();
|
|
||||||
private namespacedKey;
|
|
||||||
/**
|
/**
|
||||||
* Registers new settings.
|
* Registers new settings.
|
||||||
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
|
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
|
||||||
|
@ -519,6 +519,20 @@ export interface ContentScriptContext {
|
|||||||
postMessage: PostMessageHandler;
|
postMessage: PostMessageHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ContentScriptModuleLoadedEvent {
|
||||||
|
userData?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContentScriptModule {
|
||||||
|
onLoaded?: (event:ContentScriptModuleLoadedEvent) => void;
|
||||||
|
plugin: () => any;
|
||||||
|
assets?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
|
||||||
|
plugin: (markdownIt:any, options:any) => any;
|
||||||
|
}
|
||||||
|
|
||||||
export enum ContentScriptType {
|
export enum ContentScriptType {
|
||||||
/**
|
/**
|
||||||
* Registers a new Markdown-It plugin, which should follow the template
|
* Registers a new Markdown-It plugin, which should follow the template
|
||||||
@ -528,7 +542,7 @@ export enum ContentScriptType {
|
|||||||
* module.exports = {
|
* module.exports = {
|
||||||
* default: function(context) {
|
* default: function(context) {
|
||||||
* return {
|
* return {
|
||||||
* plugin: function(markdownIt, options) {
|
* plugin: function(markdownIt, pluginOptions) {
|
||||||
* // ...
|
* // ...
|
||||||
* },
|
* },
|
||||||
* assets: {
|
* assets: {
|
||||||
@ -538,6 +552,7 @@ export enum ContentScriptType {
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
* See [the
|
* See [the
|
||||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
||||||
* for a simple Markdown-it plugin example.
|
* for a simple Markdown-it plugin example.
|
||||||
@ -550,10 +565,7 @@ export enum ContentScriptType {
|
|||||||
*
|
*
|
||||||
* - The **required** `plugin` key is the actual Markdown-It plugin - check
|
* - The **required** `plugin` key is the actual Markdown-It plugin - check
|
||||||
* the [official doc](https://github.com/markdown-it/markdown-it) for more
|
* the [official doc](https://github.com/markdown-it/markdown-it) for more
|
||||||
* information. The `options` parameter is of type
|
* information.
|
||||||
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
|
|
||||||
* which contains a number of options, mostly useful for Joplin's internal
|
|
||||||
* code.
|
|
||||||
*
|
*
|
||||||
* - Using the **optional** `assets` key you may specify assets such as JS
|
* - Using the **optional** `assets` key you may specify assets such as JS
|
||||||
* or CSS that should be loaded in the rendered HTML document. Check for
|
* or CSS that should be loaded in the rendered HTML document. Check for
|
||||||
@ -561,6 +573,11 @@ export enum ContentScriptType {
|
|||||||
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
||||||
* to see how the data should be structured.
|
* to see how the data should be structured.
|
||||||
*
|
*
|
||||||
|
* ## Getting the settings from the renderer
|
||||||
|
*
|
||||||
|
* You can access your plugin settings from the renderer by calling
|
||||||
|
* `pluginOptions.settingValue("your-setting-key')`.
|
||||||
|
*
|
||||||
* ## Posting messages from the content script to your plugin
|
* ## Posting messages from the content script to your plugin
|
||||||
*
|
*
|
||||||
* The application provides the following function to allow executing
|
* The application provides the following function to allow executing
|
||||||
|
@ -70,6 +70,17 @@ export interface ChangeEvent {
|
|||||||
|
|
||||||
export type ChangeHandler = (event: ChangeEvent)=> void;
|
export type ChangeHandler = (event: ChangeEvent)=> void;
|
||||||
|
|
||||||
|
const keyPrefix = (pluginId: string): string => {
|
||||||
|
return `plugin-${pluginId}.`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Ensures that the plugin settings and sections are within their own namespace,
|
||||||
|
// to prevent them from overwriting other plugin settings or the default
|
||||||
|
// settings.
|
||||||
|
export const namespacedKey = (pluginId: string, key: string): string => {
|
||||||
|
return `${keyPrefix(pluginId)}${key}`;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
|
* This API allows registering new settings and setting sections, as well as getting and setting settings. Once a setting has been registered it will appear in the config screen and be editable by the user.
|
||||||
*
|
*
|
||||||
@ -86,16 +97,6 @@ export default class JoplinSettings {
|
|||||||
this.plugin_ = plugin;
|
this.plugin_ = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private get keyPrefix(): string {
|
|
||||||
return `plugin-${this.plugin_.id}.`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures that the plugin settings and sections are within their own namespace, to prevent them from
|
|
||||||
// overwriting other plugin settings or the default settings.
|
|
||||||
private namespacedKey(key: string): string {
|
|
||||||
return `${this.keyPrefix}${key}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers new settings.
|
* Registers new settings.
|
||||||
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
|
* Note that registering a setting item is dynamic and will be gone next time Joplin starts.
|
||||||
@ -116,7 +117,7 @@ export default class JoplinSettings {
|
|||||||
|
|
||||||
if ('subType' in setting) internalSettingItem.subType = setting.subType;
|
if ('subType' in setting) internalSettingItem.subType = setting.subType;
|
||||||
if ('isEnum' in setting) internalSettingItem.isEnum = setting.isEnum;
|
if ('isEnum' in setting) internalSettingItem.isEnum = setting.isEnum;
|
||||||
if ('section' in setting) internalSettingItem.section = this.namespacedKey(setting.section);
|
if ('section' in setting) internalSettingItem.section = namespacedKey(this.plugin_.id, setting.section);
|
||||||
if ('options' in setting) internalSettingItem.options = () => setting.options;
|
if ('options' in setting) internalSettingItem.options = () => setting.options;
|
||||||
if ('appTypes' in setting) internalSettingItem.appTypes = setting.appTypes;
|
if ('appTypes' in setting) internalSettingItem.appTypes = setting.appTypes;
|
||||||
if ('secure' in setting) internalSettingItem.secure = setting.secure;
|
if ('secure' in setting) internalSettingItem.secure = setting.secure;
|
||||||
@ -126,7 +127,7 @@ export default class JoplinSettings {
|
|||||||
if ('step' in setting) internalSettingItem.step = setting.step;
|
if ('step' in setting) internalSettingItem.step = setting.step;
|
||||||
if ('storage' in setting) internalSettingItem.storage = setting.storage;
|
if ('storage' in setting) internalSettingItem.storage = setting.storage;
|
||||||
|
|
||||||
await Setting.registerSetting(this.namespacedKey(key), internalSettingItem);
|
await Setting.registerSetting(namespacedKey(this.plugin_.id, key), internalSettingItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,21 +151,21 @@ export default class JoplinSettings {
|
|||||||
* Registers a new setting section. Like for registerSetting, it is dynamic and needs to be done every time the plugin starts.
|
* Registers a new setting section. Like for registerSetting, it is dynamic and needs to be done every time the plugin starts.
|
||||||
*/
|
*/
|
||||||
public async registerSection(name: string, section: SettingSection) {
|
public async registerSection(name: string, section: SettingSection) {
|
||||||
return Setting.registerSection(this.namespacedKey(name), SettingSectionSource.Plugin, section);
|
return Setting.registerSection(namespacedKey(this.plugin_.id, name), SettingSectionSource.Plugin, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a setting value (only applies to setting you registered from your plugin)
|
* Gets a setting value (only applies to setting you registered from your plugin)
|
||||||
*/
|
*/
|
||||||
public async value(key: string): Promise<any> {
|
public async value(key: string): Promise<any> {
|
||||||
return Setting.value(this.namespacedKey(key));
|
return Setting.value(namespacedKey(this.plugin_.id, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a setting value (only applies to setting you registered from your plugin)
|
* Sets a setting value (only applies to setting you registered from your plugin)
|
||||||
*/
|
*/
|
||||||
public async setValue(key: string, value: any) {
|
public async setValue(key: string, value: any) {
|
||||||
return Setting.setValue(this.namespacedKey(key), value);
|
return Setting.setValue(namespacedKey(this.plugin_.id, key), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,8 +188,8 @@ export default class JoplinSettings {
|
|||||||
// Filter out keys that are not related to this plugin
|
// Filter out keys that are not related to this plugin
|
||||||
eventManager.on('settingsChange', (event: ChangeEvent) => {
|
eventManager.on('settingsChange', (event: ChangeEvent) => {
|
||||||
const keys = event.keys
|
const keys = event.keys
|
||||||
.filter(k => k.indexOf(this.keyPrefix) === 0)
|
.filter(k => k.indexOf(keyPrefix(this.plugin_.id)) === 0)
|
||||||
.map(k => k.substr(this.keyPrefix.length));
|
.map(k => k.substr(keyPrefix(this.plugin_.id).length));
|
||||||
if (!keys.length) return;
|
if (!keys.length) return;
|
||||||
handler({ keys });
|
handler({ keys });
|
||||||
});
|
});
|
||||||
|
@ -519,6 +519,20 @@ export interface ContentScriptContext {
|
|||||||
postMessage: PostMessageHandler;
|
postMessage: PostMessageHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ContentScriptModuleLoadedEvent {
|
||||||
|
userData?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ContentScriptModule {
|
||||||
|
onLoaded?: (event: ContentScriptModuleLoadedEvent)=> void;
|
||||||
|
plugin: ()=> any;
|
||||||
|
assets?: ()=> void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MarkdownItContentScriptModule extends Omit<ContentScriptModule, 'plugin'> {
|
||||||
|
plugin: (markdownIt: any, options: any)=> any;
|
||||||
|
}
|
||||||
|
|
||||||
export enum ContentScriptType {
|
export enum ContentScriptType {
|
||||||
/**
|
/**
|
||||||
* Registers a new Markdown-It plugin, which should follow the template
|
* Registers a new Markdown-It plugin, which should follow the template
|
||||||
@ -528,7 +542,7 @@ export enum ContentScriptType {
|
|||||||
* module.exports = {
|
* module.exports = {
|
||||||
* default: function(context) {
|
* default: function(context) {
|
||||||
* return {
|
* return {
|
||||||
* plugin: function(markdownIt, options) {
|
* plugin: function(markdownIt, pluginOptions) {
|
||||||
* // ...
|
* // ...
|
||||||
* },
|
* },
|
||||||
* assets: {
|
* assets: {
|
||||||
@ -538,6 +552,7 @@ export enum ContentScriptType {
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
|
*
|
||||||
* See [the
|
* See [the
|
||||||
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
* demo](https://github.com/laurent22/joplin/tree/dev/packages/app-cli/tests/support/plugins/content_script)
|
||||||
* for a simple Markdown-it plugin example.
|
* for a simple Markdown-it plugin example.
|
||||||
@ -550,10 +565,7 @@ export enum ContentScriptType {
|
|||||||
*
|
*
|
||||||
* - The **required** `plugin` key is the actual Markdown-It plugin - check
|
* - The **required** `plugin` key is the actual Markdown-It plugin - check
|
||||||
* the [official doc](https://github.com/markdown-it/markdown-it) for more
|
* the [official doc](https://github.com/markdown-it/markdown-it) for more
|
||||||
* information. The `options` parameter is of type
|
* information.
|
||||||
* [RuleOptions](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml.ts),
|
|
||||||
* which contains a number of options, mostly useful for Joplin's internal
|
|
||||||
* code.
|
|
||||||
*
|
*
|
||||||
* - Using the **optional** `assets` key you may specify assets such as JS
|
* - Using the **optional** `assets` key you may specify assets such as JS
|
||||||
* or CSS that should be loaded in the rendered HTML document. Check for
|
* or CSS that should be loaded in the rendered HTML document. Check for
|
||||||
@ -561,6 +573,11 @@ export enum ContentScriptType {
|
|||||||
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
* plugin](https://github.com/laurent22/joplin/blob/dev/packages/renderer/MdToHtml/rules/mermaid.ts)
|
||||||
* to see how the data should be structured.
|
* to see how the data should be structured.
|
||||||
*
|
*
|
||||||
|
* ## Getting the settings from the renderer
|
||||||
|
*
|
||||||
|
* You can access your plugin settings from the renderer by calling
|
||||||
|
* `pluginOptions.settingValue("your-setting-key')`.
|
||||||
|
*
|
||||||
* ## Posting messages from the content script to your plugin
|
* ## Posting messages from the content script to your plugin
|
||||||
*
|
*
|
||||||
* The application provides the following function to allow executing
|
* The application provides the following function to allow executing
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { PluginStates } from '../reducer';
|
import { PluginStates } from '../reducer';
|
||||||
import { ContentScriptType, ContentScriptContext, PostMessageHandler } from '../api/types';
|
import { ContentScriptType, ContentScriptContext, PostMessageHandler, ContentScriptModule } from '../api/types';
|
||||||
import { dirname } from '@joplin/renderer/pathUtils';
|
import { dirname } from '@joplin/renderer/pathUtils';
|
||||||
import shim from '../../../shim';
|
import shim from '../../../shim';
|
||||||
import Logger from '@joplin/utils/Logger';
|
import Logger from '@joplin/utils/Logger';
|
||||||
@ -11,6 +11,7 @@ export interface ExtraContentScript {
|
|||||||
id: string;
|
id: string;
|
||||||
module: any;
|
module: any;
|
||||||
assetPath: string;
|
assetPath: string;
|
||||||
|
pluginId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function postMessageHandler(pluginId: string, scriptType: ContentScriptType, contentScriptId: string): PostMessageHandler {
|
function postMessageHandler(pluginId: string, scriptType: ContentScriptType, contentScriptId: string): PostMessageHandler {
|
||||||
@ -53,14 +54,15 @@ function loadContentScripts(plugins: PluginStates, scriptType: ContentScriptType
|
|||||||
postMessage: postMessageHandler(pluginId, scriptType, contentScript.id),
|
postMessage: postMessageHandler(pluginId, scriptType, contentScript.id),
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadedModule = module.default(context);
|
const loadedModule = module.default(context) as ContentScriptModule;
|
||||||
|
|
||||||
if (!loadedModule.plugin && !loadedModule.codeMirrorResources && !loadedModule.codeMirrorOptions) throw new Error(`Content script must export a "plugin" key or a list of CodeMirror assets or define a CodeMirror option: Plugin: ${pluginId}: Script: ${contentScript.id}`);
|
if (!loadedModule.plugin && !(loadedModule as any).codeMirrorResources && !(loadedModule as any).codeMirrorOptions) throw new Error(`Content script must export a "plugin" key or a list of CodeMirror assets or define a CodeMirror option: Plugin: ${pluginId}: Script: ${contentScript.id}`);
|
||||||
|
|
||||||
output.push({
|
output.push({
|
||||||
id: contentScript.id,
|
id: contentScript.id,
|
||||||
module: loadedModule,
|
module: loadedModule,
|
||||||
assetPath: dirname(contentScript.path),
|
assetPath: dirname(contentScript.path),
|
||||||
|
pluginId,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// This function must not throw as doing so would crash the
|
// This function must not throw as doing so would crash the
|
||||||
|
@ -7,10 +7,10 @@ import { ItemIdToUrlHandler } from './utils';
|
|||||||
import { RenderResult, RenderResultPluginAsset } from './MarkupToHtml';
|
import { RenderResult, RenderResultPluginAsset } from './MarkupToHtml';
|
||||||
import { Options as NoteStyleOptions } from './noteStyle';
|
import { Options as NoteStyleOptions } from './noteStyle';
|
||||||
import hljs from './highlight';
|
import hljs from './highlight';
|
||||||
|
import * as MarkdownIt from 'markdown-it';
|
||||||
|
|
||||||
const Entities = require('html-entities').AllHtmlEntities;
|
const Entities = require('html-entities').AllHtmlEntities;
|
||||||
const htmlentities = new Entities().encode;
|
const htmlentities = new Entities().encode;
|
||||||
const MarkdownIt = require('markdown-it');
|
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
|
|
||||||
export interface RenderOptions {
|
export interface RenderOptions {
|
||||||
@ -32,6 +32,7 @@ export interface RenderOptions {
|
|||||||
useCustomPdfViewer?: boolean;
|
useCustomPdfViewer?: boolean;
|
||||||
noteId?: string;
|
noteId?: string;
|
||||||
vendorDir?: string;
|
vendorDir?: string;
|
||||||
|
settingValue?: (pluginId: string, key: string)=> any;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RendererRule {
|
interface RendererRule {
|
||||||
@ -40,6 +41,7 @@ interface RendererRule {
|
|||||||
plugin?: any;
|
plugin?: any;
|
||||||
assetPath?: string;
|
assetPath?: string;
|
||||||
assetPathIsAbsolute?: boolean;
|
assetPathIsAbsolute?: boolean;
|
||||||
|
pluginId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RendererRules {
|
interface RendererRules {
|
||||||
@ -102,6 +104,7 @@ export interface ExtraRendererRule {
|
|||||||
id: string;
|
id: string;
|
||||||
module: any;
|
module: any;
|
||||||
assetPath: string;
|
assetPath: string;
|
||||||
|
pluginId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Options {
|
export interface Options {
|
||||||
@ -233,7 +236,7 @@ export default class MdToHtml {
|
|||||||
|
|
||||||
if (options.extraRendererRules) {
|
if (options.extraRendererRules) {
|
||||||
for (const rule of options.extraRendererRules) {
|
for (const rule of options.extraRendererRules) {
|
||||||
this.loadExtraRendererRule(rule.id, rule.assetPath, rule.module);
|
this.loadExtraRendererRule(rule.id, rule.assetPath, rule.module, rule.pluginId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,11 +271,13 @@ export default class MdToHtml {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// `module` is a file that has already been `required()`
|
// `module` is a file that has already been `required()`
|
||||||
public loadExtraRendererRule(id: string, assetPath: string, module: any) {
|
public loadExtraRendererRule(id: string, assetPath: string, module: any, pluginId: string) {
|
||||||
if (this.extraRendererRules_[id]) throw new Error(`A renderer rule with this ID has already been loaded: ${id}`);
|
if (this.extraRendererRules_[id]) throw new Error(`A renderer rule with this ID has already been loaded: ${id}`);
|
||||||
|
|
||||||
this.extraRendererRules_[id] = {
|
this.extraRendererRules_[id] = {
|
||||||
...module,
|
...module,
|
||||||
assetPath,
|
assetPath,
|
||||||
|
pluginId: pluginId,
|
||||||
assetPathIsAbsolute: true,
|
assetPathIsAbsolute: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -451,6 +456,7 @@ export default class MdToHtml {
|
|||||||
pdfViewerEnabled: this.pluginEnabled('pdfViewer'),
|
pdfViewerEnabled: this.pluginEnabled('pdfViewer'),
|
||||||
|
|
||||||
contentMaxWidth: 0,
|
contentMaxWidth: 0,
|
||||||
|
settingValue: (_pluginId: string, _key: string) => { throw new Error('settingValue is not implemented'); },
|
||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -467,8 +473,11 @@ export default class MdToHtml {
|
|||||||
const cachedOutput = this.cachedOutputs_[cacheKey];
|
const cachedOutput = this.cachedOutputs_[cacheKey];
|
||||||
if (cachedOutput) return cachedOutput;
|
if (cachedOutput) return cachedOutput;
|
||||||
|
|
||||||
const ruleOptions = { ...options, resourceBaseUrl: this.resourceBaseUrl_,
|
const ruleOptions = {
|
||||||
ResourceModel: this.ResourceModel_ };
|
...options,
|
||||||
|
resourceBaseUrl: this.resourceBaseUrl_,
|
||||||
|
ResourceModel: this.ResourceModel_,
|
||||||
|
};
|
||||||
|
|
||||||
const context: PluginContext = {
|
const context: PluginContext = {
|
||||||
css: {},
|
css: {},
|
||||||
@ -478,12 +487,12 @@ export default class MdToHtml {
|
|||||||
currentLinks: [],
|
currentLinks: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const markdownIt = new MarkdownIt({
|
const markdownIt: MarkdownIt = new MarkdownIt({
|
||||||
breaks: !this.pluginEnabled('softbreaks'),
|
breaks: !this.pluginEnabled('softbreaks'),
|
||||||
typographer: this.pluginEnabled('typographer'),
|
typographer: this.pluginEnabled('typographer'),
|
||||||
linkify: this.pluginEnabled('linkify'),
|
linkify: this.pluginEnabled('linkify'),
|
||||||
html: true,
|
html: true,
|
||||||
highlight: (str: string, lang: string) => {
|
highlight: (str: string, lang: string, _attrs: any): any => {
|
||||||
let outputCodeHtml = '';
|
let outputCodeHtml = '';
|
||||||
|
|
||||||
// The strings includes the last \n that is part of the fence,
|
// The strings includes the last \n that is part of the fence,
|
||||||
@ -567,6 +576,9 @@ export default class MdToHtml {
|
|||||||
context: context,
|
context: context,
|
||||||
...ruleOptions,
|
...ruleOptions,
|
||||||
...(ruleOptions.plugins[key] ? ruleOptions.plugins[key] : {}),
|
...(ruleOptions.plugins[key] ? ruleOptions.plugins[key] : {}),
|
||||||
|
settingValue: (key: string) => {
|
||||||
|
return options.settingValue(rule.pluginId, key);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "29.5.5",
|
"@types/jest": "29.5.5",
|
||||||
|
"@types/markdown-it": "13.0.2",
|
||||||
"@types/node": "18.17.19",
|
"@types/node": "18.17.19",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-environment-jsdom": "29.7.0",
|
"jest-environment-jsdom": "29.7.0",
|
||||||
|
@ -6668,6 +6668,7 @@ __metadata:
|
|||||||
"@joplin/fork-uslug": ^1.0.11
|
"@joplin/fork-uslug": ^1.0.11
|
||||||
"@joplin/utils": ~2.13
|
"@joplin/utils": ~2.13
|
||||||
"@types/jest": 29.5.5
|
"@types/jest": 29.5.5
|
||||||
|
"@types/markdown-it": 13.0.2
|
||||||
"@types/node": 18.17.19
|
"@types/node": 18.17.19
|
||||||
font-awesome-filetypes: 2.1.0
|
font-awesome-filetypes: 2.1.0
|
||||||
fs-extra: 11.1.1
|
fs-extra: 11.1.1
|
||||||
|
Loading…
Reference in New Issue
Block a user