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

Plugins: Add support for content script asset files, for Markdown-it plugins

This commit is contained in:
Laurent Cozic 2020-12-10 16:09:31 +00:00
parent 5cafc8cea5
commit 3ed0083e94
5 changed files with 47 additions and 9 deletions

View File

@ -170,7 +170,9 @@ describe('services_PluginService', function() {
const tempDir = await createTempDir();
const contentScriptPath = `${tempDir}/markdownItTestPlugin.js`;
const contentScriptCssPath = `${tempDir}/markdownItTestPlugin.css`;
await shim.fsDriver().copy(`${testPluginDir}/content_script/src/markdownItTestPlugin.js`, contentScriptPath);
await shim.fsDriver().copy(`${testPluginDir}/content_script/src/markdownItTestPlugin.css`, contentScriptCssPath);
const service = newPluginService();
@ -205,7 +207,7 @@ describe('services_PluginService', function() {
const mdToHtml = new MdToHtml();
const module = require(contentScript.path).default;
mdToHtml.loadExtraRendererRule(contentScript.id, module({}));
mdToHtml.loadExtraRendererRule(contentScript.id, tempDir, module({}));
const result = await mdToHtml.render([
'```justtesting',
@ -213,6 +215,11 @@ describe('services_PluginService', function() {
'```',
].join('\n'));
const asset = result.pluginAssets.find(a => a.name === 'justtesting/markdownItTestPlugin.css');
const assetContent: string = await shim.fsDriver().readFile(asset.path, 'utf8');
expect(assetContent.includes('.just-testing')).toBe(true);
expect(assetContent.includes('background-color: red;')).toBe(true);
expect(result.html.includes('JUST TESTING: something')).toBe(true);
await shim.fsDriver().remove(tempDir);

View File

@ -20,4 +20,4 @@
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
}
}
}

View File

@ -0,0 +1,4 @@
.just-testing {
background-color: red;
color: yellow;
}

View File

@ -6,7 +6,7 @@ function plugin(markdownIt, _options) {
markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) {
const token = tokens[idx];
if (token.info !== 'justtesting') return defaultRender(tokens, idx, options, env, self);
return `JUST TESTING: ${token.content}`;
return `<div class="just-testing">JUST TESTING: ${token.content}</div>`;
};
}
@ -14,6 +14,11 @@ module.exports = {
default: function(_context) {
return {
plugin: plugin,
assets: function() {
return [
{ name: 'markdownItTestPlugin.css' }
];
},
}
},
}

View File

@ -9,6 +9,7 @@ interface RendererRule {
install(context: any, ruleOptions: any): any;
assets?(theme: any): any;
plugin?: any;
assetPath?: string;
}
interface RendererRules {
@ -197,7 +198,7 @@ export default class MdToHtml {
if (options.extraRendererRules) {
for (const rule of options.extraRendererRules) {
this.loadExtraRendererRule(rule.id, rule.module);
this.loadExtraRendererRule(rule.id, rule.assetPath, rule.module);
}
}
}
@ -232,15 +233,28 @@ export default class MdToHtml {
}
// `module` is a file that has already been `required()`
public loadExtraRendererRule(id: string, module: any) {
public loadExtraRendererRule(id: string, assetPath: string, module: any) {
if (this.extraRendererRules_[id]) throw new Error(`A renderer rule with this ID has already been loaded: ${id}`);
this.extraRendererRules_[id] = module;
this.extraRendererRules_[id] = {
...module,
assetPath,
};
}
private ruleByKey(key: string): RendererRule {
if (rules[key]) return rules[key];
if (this.extraRendererRules_[key]) return this.extraRendererRules_[key];
if (key === 'highlight.js') return null;
throw new Error(`No such rule: ${key}`);
}
private processPluginAssets(pluginAssets: PluginAssets): RenderResult {
const files: RenderResultPluginAsset[] = [];
const cssStrings = [];
for (const pluginName in pluginAssets) {
const rule = this.ruleByKey(pluginName);
for (const asset of pluginAssets[pluginName]) {
let mime = asset.mime;
@ -263,10 +277,18 @@ export default class MdToHtml {
throw new Error(`Unsupported inline mime type: ${mime}`);
}
} else {
// TODO: we should resolve the path using
// resolveRelativePathWithinDir() for increased
// security, but the shim is not accessible from the
// renderer, and React Native doesn't have this
// function, so for now use the provided path as-is.
const name = `${pluginName}/${asset.name}`;
const assetPath = rule?.assetPath ? `${rule.assetPath}/${asset.name}` : `pluginAssets/${name}`;
files.push(Object.assign({}, asset, {
name: name,
path: `pluginAssets/${name}`,
path: assetPath,
mime: mime,
}));
}
@ -282,7 +304,7 @@ export default class MdToHtml {
// This return all the assets for all the plugins. Since it is called
// on each render, the result is cached.
private allProcessedAssets(theme: any, codeTheme: string) {
private allProcessedAssets(rules: RendererRules, theme: any, codeTheme: string) {
const cacheKey: string = theme.cacheKey + codeTheme;
if (this.allProcessedAssets_[cacheKey]) return this.allProcessedAssets_[cacheKey];
@ -501,7 +523,7 @@ export default class MdToHtml {
let cssStrings = noteStyle(options.theme);
let output = { ...this.allProcessedAssets(options.theme, options.codeTheme) };
let output = { ...this.allProcessedAssets(allRules, options.theme, options.codeTheme) };
cssStrings = cssStrings.concat(output.cssStrings);
if (options.userCss) cssStrings.push(options.userCss);