You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-06-15 23:00:36 +02:00
Desktop: Added support for checkboxes and fixed various issues with WYSIWYG editor
This commit is contained in:
@ -3,19 +3,22 @@ const md5 = require('md5');
|
||||
const noteStyle = require('./noteStyle');
|
||||
const { fileExtension } = require('./pathUtils');
|
||||
const memoryCache = require('memory-cache');
|
||||
|
||||
// /!\/!\ Note: the order of rules is important!! /!\/!\
|
||||
const rules = {
|
||||
fence: require('./MdToHtml/rules/fence').default,
|
||||
sanitize_html: require('./MdToHtml/rules/sanitize_html').default,
|
||||
image: require('./MdToHtml/rules/image'),
|
||||
checkbox: require('./MdToHtml/rules/checkbox'),
|
||||
checkbox: require('./MdToHtml/rules/checkbox').default,
|
||||
katex: require('./MdToHtml/rules/katex'),
|
||||
link_open: require('./MdToHtml/rules/link_open'),
|
||||
html_image: require('./MdToHtml/rules/html_image'),
|
||||
highlight_keywords: require('./MdToHtml/rules/highlight_keywords'),
|
||||
code_inline: require('./MdToHtml/rules/code_inline'),
|
||||
fence: require('./MdToHtml/rules/fence').default,
|
||||
fountain: require('./MdToHtml/rules/fountain'),
|
||||
mermaid: require('./MdToHtml/rules/mermaid').default,
|
||||
sanitize_html: require('./MdToHtml/rules/sanitize_html').default,
|
||||
};
|
||||
|
||||
const setupLinkify = require('./MdToHtml/setupLinkify');
|
||||
const hljs = require('highlight.js');
|
||||
const uslug = require('uslug');
|
||||
@ -77,6 +80,13 @@ class MdToHtml {
|
||||
return this.tempDir_;
|
||||
}
|
||||
|
||||
static pluginNames() {
|
||||
const output = [];
|
||||
for (const n in rules) output.push(n);
|
||||
for (const n in plugins) output.push(n);
|
||||
return output;
|
||||
}
|
||||
|
||||
pluginOptions(name) {
|
||||
let o = this.pluginOptions_[name] ? this.pluginOptions_[name] : {};
|
||||
o = Object.assign({
|
||||
@ -115,8 +125,10 @@ class MdToHtml {
|
||||
throw new Error(`Unsupported inline mime type: ${mime}`);
|
||||
}
|
||||
} else {
|
||||
const name = `${pluginName}/${asset.name}`;
|
||||
files.push(Object.assign({}, asset, {
|
||||
name: `${pluginName}/${asset.name}`,
|
||||
name: name,
|
||||
path: `pluginAssets/${name}`,
|
||||
mime: mime,
|
||||
}));
|
||||
}
|
||||
@ -124,21 +136,52 @@ class MdToHtml {
|
||||
}
|
||||
|
||||
return {
|
||||
files: files,
|
||||
pluginAssets: files,
|
||||
cssStrings: cssStrings,
|
||||
};
|
||||
}
|
||||
|
||||
async render(body, style = null, options = null) {
|
||||
async allAssets(theme) {
|
||||
const assets = {};
|
||||
for (const key in rules) {
|
||||
if (!this.pluginEnabled(key)) continue;
|
||||
const rule = rules[key];
|
||||
|
||||
if (rule.style) {
|
||||
assets[key] = rule.style(theme);
|
||||
}
|
||||
}
|
||||
|
||||
const processedAssets = this.processPluginAssets(assets);
|
||||
processedAssets.cssStrings.splice(0, 0, noteStyle(theme));
|
||||
const output = await this.outputAssetsToExternalAssets_(processedAssets);
|
||||
return output.pluginAssets;
|
||||
}
|
||||
|
||||
async outputAssetsToExternalAssets_(output) {
|
||||
for (const cssString of output.cssStrings) {
|
||||
output.pluginAssets.push(await this.fsDriver().cacheCssToFile(cssString));
|
||||
}
|
||||
delete output.cssStrings;
|
||||
return output;
|
||||
}
|
||||
|
||||
// "style" here is really the theme, as returned by themeStyle()
|
||||
async render(body, theme = null, options = null) {
|
||||
options = Object.assign({}, {
|
||||
// In bodyOnly mode, the rendered Markdown is returned without the wrapper DIV
|
||||
bodyOnly: false,
|
||||
// In splitted mode, the CSS and HTML will be returned in separate properties.
|
||||
// In non-splitted mode, CSS and HTML will be merged in the same document.
|
||||
splitted: false,
|
||||
// When this is true, all assets such as CSS or JS are returned as external
|
||||
// files. Otherwise some of them might be in the cssStrings property.
|
||||
externalAssetsOnly: false,
|
||||
postMessageSyntax: 'postMessage',
|
||||
paddingBottom: '0',
|
||||
highlightedKeywords: [],
|
||||
codeTheme: 'atom-one-light.css',
|
||||
style: Object.assign({}, defaultNoteStyle),
|
||||
theme: Object.assign({}, defaultNoteStyle, theme),
|
||||
plugins: {},
|
||||
}, options);
|
||||
|
||||
// The "codeHighlightCacheKey" option indicates what set of cached object should be
|
||||
@ -150,7 +193,7 @@ class MdToHtml {
|
||||
this.lastCodeHighlightCacheKey_ = options.codeHighlightCacheKey;
|
||||
}
|
||||
|
||||
const cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(style)));
|
||||
const cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(options.theme)));
|
||||
const cachedOutput = this.cachedOutputs_[cacheKey];
|
||||
if (cachedOutput) return cachedOutput;
|
||||
|
||||
@ -237,19 +280,13 @@ class MdToHtml {
|
||||
// Using the `context` object, a plugin can define what additional assets they need (css, fonts, etc.) using context.pluginAssets.
|
||||
// The calling application will need to handle loading these assets.
|
||||
|
||||
// /!\/!\ Note: the order of rules is important!! /!\/!\
|
||||
for (const key in rules) {
|
||||
if (!this.pluginEnabled(key)) continue;
|
||||
const rule = rules[key];
|
||||
const ruleInstall = rule.install ? rule.install : rule;
|
||||
markdownIt.use(ruleInstall(context, { ...ruleOptions }));
|
||||
}
|
||||
|
||||
markdownIt.use(rules.fence(context, ruleOptions));
|
||||
markdownIt.use(rules.sanitize_html(context, ruleOptions));
|
||||
markdownIt.use(rules.image(context, ruleOptions));
|
||||
markdownIt.use(rules.checkbox(context, ruleOptions));
|
||||
markdownIt.use(rules.link_open(context, ruleOptions));
|
||||
markdownIt.use(rules.html_image(context, ruleOptions));
|
||||
if (this.pluginEnabled('katex')) markdownIt.use(rules.katex(context, ruleOptions));
|
||||
if (this.pluginEnabled('fountain')) markdownIt.use(rules.fountain(context, ruleOptions));
|
||||
if (this.pluginEnabled('mermaid')) markdownIt.use(rules.mermaid(context, ruleOptions));
|
||||
markdownIt.use(rules.highlight_keywords(context, ruleOptions));
|
||||
markdownIt.use(rules.code_inline(context, ruleOptions));
|
||||
markdownIt.use(markdownItAnchor, { slugify: uslugify });
|
||||
|
||||
for (const key in plugins) {
|
||||
@ -260,41 +297,28 @@ class MdToHtml {
|
||||
|
||||
const renderedBody = markdownIt.render(body);
|
||||
|
||||
let cssStrings = noteStyle(style, options);
|
||||
let cssStrings = noteStyle(options.theme);
|
||||
|
||||
const pluginAssets = this.processPluginAssets(context.pluginAssets);
|
||||
cssStrings = cssStrings.concat(pluginAssets.cssStrings);
|
||||
|
||||
const output = {
|
||||
pluginAssets: pluginAssets.files.map(f => {
|
||||
return Object.assign({}, f, {
|
||||
path: `pluginAssets/${f.name}`,
|
||||
});
|
||||
}),
|
||||
};
|
||||
|
||||
if (options.bodyOnly) {
|
||||
output.html = renderedBody;
|
||||
return output;
|
||||
}
|
||||
let output = this.processPluginAssets(context.pluginAssets);
|
||||
cssStrings = cssStrings.concat(output.cssStrings);
|
||||
|
||||
if (options.userCss) cssStrings.push(options.userCss);
|
||||
|
||||
const styleHtml = `<style>${cssStrings.join('\n')}</style>`;
|
||||
|
||||
const html = `${styleHtml}<div id="rendered-md">${renderedBody}</div>`;
|
||||
|
||||
output.html = html;
|
||||
|
||||
if (options.splitted) {
|
||||
if (options.bodyOnly) {
|
||||
output.html = renderedBody;
|
||||
output.cssStrings = cssStrings;
|
||||
output.html = `<div id="rendered-md">${renderedBody}</div>`;
|
||||
} else {
|
||||
const styleHtml = `<style>${cssStrings.join('\n')}</style>`;
|
||||
output.html = `${styleHtml}<div id="rendered-md">${renderedBody}</div>`;
|
||||
|
||||
if (options.externalAssetsOnly) {
|
||||
output.pluginAssets.push(await this.fsDriver().cacheCssToFile(cssStrings));
|
||||
if (options.splitted) {
|
||||
output.cssStrings = cssStrings;
|
||||
output.html = `<div id="rendered-md">${renderedBody}</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
if (options.externalAssetsOnly) output = await this.outputAssetsToExternalAssets_(output);
|
||||
|
||||
// Fow now, we keep only the last entry in the cache
|
||||
this.cachedOutputs_ = {};
|
||||
this.cachedOutputs_[cacheKey] = output;
|
||||
|
Reference in New Issue
Block a user