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

All: Extract note renderer to separate package (WIP) (#2206)

* Started updating to use external renderer package

* Added way to build renderer assets

* Done mobile compatilibty

* Upgrade joplin-renderer

* Added joplin-renderer package
This commit is contained in:
Laurent Cozic 2019-12-29 18:58:40 +01:00 committed by GitHub
parent 1d660d7141
commit 2a63ecef2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 1130 additions and 3672 deletions

View File

@ -50,3 +50,4 @@ ElectronClient/app/packageInfo.js
# Ignore files generated from TypeScript files # Ignore files generated from TypeScript files
ElectronClient/app/gui/ShareNoteDialog.js ElectronClient/app/gui/ShareNoteDialog.js
ReactNativeClient/lib/JoplinServerApi.js ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/pluginAssetsLoader.js

1
.gitignore vendored
View File

@ -49,3 +49,4 @@ Tools/commit_hook.txt
# Ignore files generated from TypeScript files # Ignore files generated from TypeScript files
ElectronClient/app/gui/ShareNoteDialog.js ElectronClient/app/gui/ShareNoteDialog.js
ReactNativeClient/lib/JoplinServerApi.js ReactNativeClient/lib/JoplinServerApi.js
ReactNativeClient/pluginAssetsLoader.js

View File

@ -806,6 +806,11 @@
"debug": "^2.6.9" "debug": "^2.6.9"
} }
}, },
"font-awesome-filetypes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/font-awesome-filetypes/-/font-awesome-filetypes-2.1.0.tgz",
"integrity": "sha512-U6hi14GRjfZFIWsTNyVmCBuHyPhiizWEKVbaQqHipKQv3rA1l1PNvmKulzpqxonFnQMToty5ZhfWbc/0IjLDGA=="
},
"for-each-property": { "for-each-property": {
"version": "0.0.4", "version": "0.0.4",
"resolved": "https://registry.npmjs.org/for-each-property/-/for-each-property-0.0.4.tgz", "resolved": "https://registry.npmjs.org/for-each-property/-/for-each-property-0.0.4.tgz",
@ -959,6 +964,24 @@
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
}, },
"handlebars": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -1533,6 +1556,75 @@
"integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==",
"dev": true "dev": true
}, },
"joplin-renderer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz",
"integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==",
"requires": {
"base-64": "^0.1.0",
"font-awesome-filetypes": "^2.1.0",
"fs-extra": "^8.1.0",
"highlight.js": "^9.17.1",
"html-entities": "^1.2.1",
"katex": "^0.11.1",
"markdown-it": "^10.0.0",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^5.2.5",
"markdown-it-deflist": "^2.0.3",
"markdown-it-emoji": "^1.4.0",
"markdown-it-footnote": "^3.0.2",
"markdown-it-ins": "^3.0.0",
"markdown-it-mark": "^3.0.0",
"markdown-it-multimd-table": "^4.0.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"uslug": "^1.0.4"
},
"dependencies": {
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
},
"highlight.js": {
"version": "9.17.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz",
"integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==",
"requires": {
"handlebars": "^4.5.3"
}
},
"markdown-it": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
"requires": {
"argparse": "^1.0.7",
"entities": "~2.0.0",
"linkify-it": "^2.0.0",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
}
}
},
"joplin-turndown": { "joplin-turndown": {
"version": "4.0.19", "version": "4.0.19",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz",
@ -1636,6 +1728,21 @@
"resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz", "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz",
"integrity": "sha1-FHshJTaQNcpLL30hDcU58Amz3po=" "integrity": "sha1-FHshJTaQNcpLL30hDcU58Amz3po="
}, },
"katex": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.11.1.tgz",
"integrity": "sha512-5oANDICCTX0NqYIyAiFCCwjQ7ERu3DQG2JFHLbYOf+fXaMoH8eg/zOq5WSYJsKMi/QebW+Eh3gSM+oss1H/bww==",
"requires": {
"commander": "^2.19.0"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
}
}
},
"klaw": { "klaw": {
"version": "1.3.1", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
@ -1755,6 +1862,64 @@
"uc.micro": "^1.0.5" "uc.micro": "^1.0.5"
} }
}, },
"markdown-it-abbr": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz",
"integrity": "sha1-1mtTZFIcuz3Yqlna37ovtoZcj9g="
},
"markdown-it-anchor": {
"version": "5.2.5",
"resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.5.tgz",
"integrity": "sha512-xLIjLQmtym3QpoY9llBgApknl7pxAcN3WDRc2d3rwpl+/YvDZHPmKscGs+L6E05xf2KrCXPBvosWt7MZukwSpQ=="
},
"markdown-it-deflist": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/markdown-it-deflist/-/markdown-it-deflist-2.0.3.tgz",
"integrity": "sha512-/BNZ8ksW42bflm1qQLnRI09oqU2847Z7MVavrR0MORyKLtiUYOMpwtlAfMSZAQU9UCvaUZMpgVAqoS3vpToJxw=="
},
"markdown-it-emoji": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz",
"integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw="
},
"markdown-it-footnote": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.2.tgz",
"integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A=="
},
"markdown-it-ins": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz",
"integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q=="
},
"markdown-it-mark": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz",
"integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw=="
},
"markdown-it-multimd-table": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz",
"integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==",
"requires": {
"markdown-it": "^8.4.2"
}
},
"markdown-it-sub": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz",
"integrity": "sha1-N1/WAm6ufdywEkl/ZBEZXqHjr+g="
},
"markdown-it-sup": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz",
"integrity": "sha1-y5yf+RpSVawI8/09YyhuFd8KH8M="
},
"markdown-it-toc-done-right": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz",
"integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw=="
},
"md5": { "md5": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
@ -1911,6 +2076,11 @@
} }
} }
}, },
"neo-async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
},
"nextgen-events": { "nextgen-events": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/nextgen-events/-/nextgen-events-1.3.0.tgz", "resolved": "https://registry.npmjs.org/nextgen-events/-/nextgen-events-1.3.0.tgz",
@ -2089,6 +2259,15 @@
"wrappy": "1" "wrappy": "1"
} }
}, },
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
}
},
"optionator": { "optionator": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
@ -3205,6 +3384,11 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc="
}, },
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"unpack-string": { "unpack-string": {
"version": "0.0.2", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz", "resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz",
@ -3244,6 +3428,14 @@
"requires-port": "^1.0.0" "requires-port": "^1.0.0"
} }
}, },
"uslug": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz",
"integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=",
"requires": {
"unorm": ">= 1.0.0"
}
},
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -3333,6 +3525,11 @@
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
}, },
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"wordwrapjs": { "wordwrapjs": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-3.0.0.tgz",

View File

@ -44,6 +44,7 @@
"html-minifier": "^3.5.15", "html-minifier": "^3.5.15",
"image-data-uri": "^2.0.0", "image-data-uri": "^2.0.0",
"image-type": "^3.0.0", "image-type": "^3.0.0",
"joplin-renderer": "^1.0.4",
"joplin-turndown": "^4.0.19", "joplin-turndown": "^4.0.19",
"joplin-turndown-plugin-gfm": "^1.0.11", "joplin-turndown-plugin-gfm": "^1.0.11",
"jssha": "^2.3.0", "jssha": "^2.3.0",

View File

@ -6,6 +6,7 @@ const Setting = require('lib/models/Setting.js');
const { shim } = require('lib/shim.js'); const { shim } = require('lib/shim.js');
const MasterKey = require('lib/models/MasterKey'); const MasterKey = require('lib/models/MasterKey');
const Note = require('lib/models/Note'); const Note = require('lib/models/Note');
const { MarkupToHtml } = require('joplin-renderer');
const { _, setLocale } = require('lib/locale.js'); const { _, setLocale } = require('lib/locale.js');
const { Logger } = require('lib/logger.js'); const { Logger } = require('lib/logger.js');
const fs = require('fs-extra'); const fs = require('fs-extra');
@ -1132,7 +1133,7 @@ class Application extends BaseApplication {
for (const itemId of ['copy', 'paste', 'cut', 'selectAll', 'bold', 'italic', 'link', 'code', 'insertDateTime', 'commandStartExternalEditing', 'setTags', 'showLocalSearch']) { for (const itemId of ['copy', 'paste', 'cut', 'selectAll', 'bold', 'italic', 'link', 'code', 'insertDateTime', 'commandStartExternalEditing', 'setTags', 'showLocalSearch']) {
const menuItem = Menu.getApplicationMenu().getMenuItemById(`edit:${itemId}`); const menuItem = Menu.getApplicationMenu().getMenuItemById(`edit:${itemId}`);
if (!menuItem) continue; if (!menuItem) continue;
menuItem.enabled = !!note && note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN; menuItem.enabled = !!note && note.markup_language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
} }
const menuItem = Menu.getApplicationMenu().getMenuItemById('help:toggleDevTools'); const menuItem = Menu.getApplicationMenu().getMenuItemById('help:toggleDevTools');

View File

@ -6,16 +6,16 @@ const NoteTextViewer = require('./NoteTextViewer.min');
const HelpButton = require('./HelpButton.min'); const HelpButton = require('./HelpButton.min');
const BaseModel = require('lib/BaseModel'); const BaseModel = require('lib/BaseModel');
const Revision = require('lib/models/Revision'); const Revision = require('lib/models/Revision');
const Note = require('lib/models/Note');
const urlUtils = require('lib/urlUtils'); const urlUtils = require('lib/urlUtils');
const Setting = require('lib/models/Setting'); const Setting = require('lib/models/Setting');
const RevisionService = require('lib/services/RevisionService'); const RevisionService = require('lib/services/RevisionService');
const shared = require('lib/components/shared/note-screen-shared.js'); const shared = require('lib/components/shared/note-screen-shared.js');
const MarkupToHtml = require('lib/renderers/MarkupToHtml'); const { MarkupToHtml } = require('joplin-renderer');
const { time } = require('lib/time-utils.js'); const { time } = require('lib/time-utils.js');
const ReactTooltip = require('react-tooltip'); const ReactTooltip = require('react-tooltip');
const { urlDecode, substrWithEllipsis } = require('lib/string-utils'); const { urlDecode, substrWithEllipsis } = require('lib/string-utils');
const { bridge } = require('electron').remote.require('./bridge'); const { bridge } = require('electron').remote.require('./bridge');
const markupLanguageUtils = require('lib/markupLanguageUtils');
class NoteRevisionViewerComponent extends React.PureComponent { class NoteRevisionViewerComponent extends React.PureComponent {
constructor() { constructor() {
@ -101,7 +101,7 @@ class NoteRevisionViewerComponent extends React.PureComponent {
async reloadNote() { async reloadNote() {
let noteBody = ''; let noteBody = '';
let markupLanguage = Note.MARKUP_LANGUAGE_MARKDOWN; let markupLanguage = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
if (!this.state.revisions.length || !this.state.currentRevId) { if (!this.state.revisions.length || !this.state.currentRevId) {
noteBody = _('This note has no history'); noteBody = _('This note has no history');
this.setState({ note: null }); this.setState({ note: null });
@ -116,18 +116,18 @@ class NoteRevisionViewerComponent extends React.PureComponent {
const theme = themeStyle(this.props.theme); const theme = themeStyle(this.props.theme);
const markupToHtml = new MarkupToHtml({ const markupToHtml = markupLanguageUtils.newMarkupToHtml({
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`, resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
}); });
const result = markupToHtml.render(markupLanguage, noteBody, theme, { const result = await markupToHtml.render(markupLanguage, noteBody, theme, {
codeTheme: theme.codeThemeCss, codeTheme: theme.codeThemeCss,
userCss: this.props.customCss ? this.props.customCss : '', userCss: this.props.customCss ? this.props.customCss : '',
resources: await shared.attachedResources(noteBody), resources: await shared.attachedResources(noteBody),
postMessageSyntax: 'ipcProxySendToHost', postMessageSyntax: 'ipcProxySendToHost',
}); });
this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles }); this.viewerRef_.current.wrappedInstance.send('setHtml', result.html, { cssFiles: result.cssFiles, pluginAssets: result.pluginAssets });
} }
async webview_ipcMessage(event) { async webview_ipcMessage(event) {

View File

@ -15,7 +15,7 @@ const TagList = require('./TagList.min.js');
const { connect } = require('react-redux'); const { connect } = require('react-redux');
const { _ } = require('lib/locale.js'); const { _ } = require('lib/locale.js');
const { reg } = require('lib/registry.js'); const { reg } = require('lib/registry.js');
const MarkupToHtml = require('lib/renderers/MarkupToHtml'); const { MarkupToHtml } = require('joplin-renderer');
const shared = require('lib/components/shared/note-screen-shared.js'); const shared = require('lib/components/shared/note-screen-shared.js');
const { bridge } = require('electron').remote.require('./bridge'); const { bridge } = require('electron').remote.require('./bridge');
const { themeStyle } = require('../theme.js'); const { themeStyle } = require('../theme.js');
@ -41,6 +41,7 @@ const SearchEngine = require('lib/services/SearchEngine');
const NoteTextViewer = require('./NoteTextViewer.min'); const NoteTextViewer = require('./NoteTextViewer.min');
const NoteRevisionViewer = require('./NoteRevisionViewer.min'); const NoteRevisionViewer = require('./NoteRevisionViewer.min');
const TemplateUtils = require('lib/TemplateUtils'); const TemplateUtils = require('lib/TemplateUtils');
const markupLanguageUtils = require('lib/markupLanguageUtils');
require('brace/mode/markdown'); require('brace/mode/markdown');
// https://ace.c9.io/build/kitchen-sink.html // https://ace.c9.io/build/kitchen-sink.html
@ -111,6 +112,7 @@ class NoteTextComponent extends React.Component {
newAndNoTitleChangeNoteId: null, newAndNoTitleChangeNoteId: null,
bodyHtml: '', bodyHtml: '',
lastRenderCssFiles: [], lastRenderCssFiles: [],
lastRenderPluginAssets: [],
lastKeys: [], lastKeys: [],
showLocalSearch: false, showLocalSearch: false,
localSearch: Object.assign({}, this.localSearchDefaultState), localSearch: Object.assign({}, this.localSearchDefaultState),
@ -401,9 +403,11 @@ class NoteTextComponent extends React.Component {
markupToHtml() { markupToHtml() {
if (this.markupToHtml_) return this.markupToHtml_; if (this.markupToHtml_) return this.markupToHtml_;
this.markupToHtml_ = new MarkupToHtml({
this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml({
resourceBaseUrl: `file://${Setting.value('resourceDir')}/`, resourceBaseUrl: `file://${Setting.value('resourceDir')}/`,
}); });
return this.markupToHtml_; return this.markupToHtml_;
} }
@ -1048,10 +1052,10 @@ class NoteTextComponent extends React.Component {
if (bodyToRender === null) { if (bodyToRender === null) {
bodyToRender = this.state.note && this.state.note.body ? this.state.note.body : ''; bodyToRender = this.state.note && this.state.note.body ? this.state.note.body : '';
markupLanguage = this.state.note ? this.state.note.markup_language : Note.MARKUP_LANGUAGE_MARKDOWN; markupLanguage = this.state.note ? this.state.note.markup_language : MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
} }
if (!markupLanguage) markupLanguage = Note.MARKUP_LANGUAGE_MARKDOWN; if (!markupLanguage) markupLanguage = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
const resources = await shared.attachedResources(bodyToRender); const resources = await shared.attachedResources(bodyToRender);
@ -1072,11 +1076,11 @@ class NoteTextComponent extends React.Component {
bodyToRender = `<i>${_('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout'))}</i>`; bodyToRender = `<i>${_('This note has no content. Click on "%s" to toggle the editor and edit the note.', _('Layout'))}</i>`;
} }
const result = this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions); const result = await this.markupToHtml().render(markupLanguage, bodyToRender, theme, mdOptions);
this.setState({ this.setState({
bodyHtml: result.html, bodyHtml: result.html,
lastRenderCssFiles: result.cssFiles, lastRenderPluginAssets: result.pluginAssets,
}); });
} }
@ -1630,7 +1634,7 @@ class NoteTextComponent extends React.Component {
}); });
} }
if (note.markup_language === Note.MARKUP_LANGUAGE_MARKDOWN && editorIsVisible) { if (note.markup_language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN && editorIsVisible) {
toolbarItems.push({ toolbarItems.push({
tooltip: _('Bold'), tooltip: _('Bold'),
iconName: 'fa-bold', iconName: 'fa-bold',
@ -1858,7 +1862,7 @@ class NoteTextComponent extends React.Component {
const style = this.props.style; const style = this.props.style;
const note = this.state.note; const note = this.state.note;
const body = note && note.body ? note.body : ''; const body = note && note.body ? note.body : '';
const markupLanguage = note ? note.markup_language : Note.MARKUP_LANGUAGE_MARKDOWN; const markupLanguage = note ? note.markup_language : MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
const theme = themeStyle(this.props.theme); const theme = themeStyle(this.props.theme);
const visiblePanes = this.props.visiblePanes || ['editor', 'viewer']; const visiblePanes = this.props.visiblePanes || ['editor', 'viewer'];
const isTodo = note && !!note.is_todo; const isTodo = note && !!note.is_todo;
@ -1999,7 +2003,7 @@ class NoteTextComponent extends React.Component {
const htmlHasChanged = this.lastSetHtml_ !== html; const htmlHasChanged = this.lastSetHtml_ !== html;
if (htmlHasChanged) { if (htmlHasChanged) {
let options = { let options = {
cssFiles: this.state.lastRenderCssFiles, pluginAssets: this.state.lastRenderPluginAssets,
downloadResources: Setting.value('sync.resourceDownloadMode'), downloadResources: Setting.value('sync.resourceDownloadMode'),
}; };
this.webviewRef_.current.wrappedInstance.send('setHtml', html, options); this.webviewRef_.current.wrappedInstance.send('setHtml', html, options);

View File

@ -66,15 +66,21 @@
} }
})); }));
const loadedCssFiles_ = {}; const loadedPluginAssets_ = {}
function loadCssFiles(cssFiles) { function loadPluginAssets(assets) {
for (let i = 0; i < cssFiles.length; i++) { if (!assets) return;
const f = cssFiles[i];
if (loadedCssFiles_[f]) continue; for (let i = 0; i < assets.length; i++) {
const link = document.createElement('link'); const asset = assets[i];
link.rel = 'stylesheet'; if (loadedPluginAssets_[asset.name]) continue;
link.href = f; loadedPluginAssets_[asset.name] = true;
document.getElementById('joplin-container-styleContainer').appendChild(link);
if (asset.mime === 'text/css') {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'pluginAssets/' + asset.name;
document.getElementById('joplin-container-styleContainer').appendChild(link);
}
} }
} }
@ -154,7 +160,9 @@
}, 1); }, 1);
} }
loadCssFiles(event.options.cssFiles); // loadCssFiles(event.options.cssFiles);
loadPluginAssets(event.options.pluginAssets);
if (event.options.downloadResources === 'manual') { if (event.options.downloadResources === 'manual') {
webviewLib.setupResourceManualDownload(); webviewLib.setupResourceManualDownload();

View File

@ -0,0 +1,75 @@
/*
Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage
Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #abb2bf;
background: #282c34;
}
.hljs-keyword, .hljs-operator {
color: #F92672;
}
.hljs-pattern-match {
color: #F92672;
}
.hljs-pattern-match .hljs-constructor {
color: #61aeee;
}
.hljs-function {
color: #61aeee;
}
.hljs-function .hljs-params {
color: #A6E22E;
}
.hljs-function .hljs-params .hljs-typing {
color: #FD971F;
}
.hljs-module-access .hljs-module {
color: #7e57c2;
}
.hljs-constructor {
color: #e2b93d;
}
.hljs-constructor .hljs-string {
color: #9CCC65;
}
.hljs-comment, .hljs-quote {
color: #b18eb1;
font-style: italic;
}
.hljs-doctag, .hljs-formula {
color: #c678dd;
}
.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst {
color: #e06c75;
}
.hljs-literal {
color: #56b6c2;
}
.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string {
color: #98c379;
}
.hljs-built_in, .hljs-class .hljs-title {
color: #e6c07b;
}
.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number {
color: #d19a66;
}
.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title {
color: #61aeee;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

View File

@ -0,0 +1,96 @@
/*
Atom One Light by Daniel Gamage
Original One Light Syntax theme from https://github.com/atom/one-light-syntax
base: #fafafa
mono-1: #383a42
mono-2: #686b77
mono-3: #a0a1a7
hue-1: #0184bb
hue-2: #4078f2
hue-3: #a626a4
hue-4: #50a14f
hue-5: #e45649
hue-5-2: #c91243
hue-6: #986801
hue-6-2: #c18401
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #383a42;
background: #fafafa;
}
.hljs-comment,
.hljs-quote {
color: #a0a1a7;
font-style: italic;
}
.hljs-doctag,
.hljs-keyword,
.hljs-formula {
color: #a626a4;
}
.hljs-section,
.hljs-name,
.hljs-selector-tag,
.hljs-deletion,
.hljs-subst {
color: #e45649;
}
.hljs-literal {
color: #0184bb;
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-attribute,
.hljs-meta-string {
color: #50a14f;
}
.hljs-built_in,
.hljs-class .hljs-title {
color: #c18401;
}
.hljs-attr,
.hljs-variable,
.hljs-template-variable,
.hljs-type,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo,
.hljs-number {
color: #986801;
}
.hljs-symbol,
.hljs-bullet,
.hljs-link,
.hljs-meta,
.hljs-selector-id,
.hljs-title {
color: #4078f2;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
.hljs-link {
text-decoration: underline;
}

File diff suppressed because one or more lines are too long

View File

@ -706,8 +706,7 @@
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -728,14 +727,12 @@
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -750,20 +747,17 @@
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -880,8 +874,7 @@
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -893,7 +886,6 @@
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -908,7 +900,6 @@
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
@ -916,14 +907,12 @@
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -942,7 +931,6 @@
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -1023,8 +1011,7 @@
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -1036,7 +1023,6 @@
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -1122,8 +1108,7 @@
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -1159,7 +1144,6 @@
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -1179,7 +1163,6 @@
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -1223,14 +1206,12 @@
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true,
"dev": true, "dev": true
"optional": true
} }
} }
}, },
@ -1248,15 +1229,13 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"dev": true, "dev": true
"optional": true
}, },
"is-glob": { "is-glob": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"is-extglob": "^1.0.0" "is-extglob": "^1.0.0"
} }
@ -1658,8 +1637,7 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz", "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.0.tgz",
"integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ==", "integrity": "sha512-OElxJ1lUSinuoUnkpOgLmxp0DC4ytEhODEL6QJU0NpxE/mI4rUSh8h1P1Wkvfi3xQEBcxXR2gBIPNYNuaFcAbQ==",
"dev": true, "dev": true
"optional": true
}, },
"boxen": { "boxen": {
"version": "3.2.0", "version": "3.2.0",
@ -3588,15 +3566,13 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"dev": true, "dev": true
"optional": true
}, },
"is-glob": { "is-glob": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"is-extglob": "^1.0.0" "is-extglob": "^1.0.0"
} }
@ -3721,6 +3697,24 @@
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
}, },
"handlebars": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"har-schema": { "har-schema": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@ -3785,9 +3779,12 @@
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
}, },
"highlight.js": { "highlight.js": {
"version": "9.15.6", "version": "9.17.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz",
"integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==" "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==",
"requires": {
"handlebars": "^4.5.3"
}
}, },
"hoist-non-react-statics": { "hoist-non-react-statics": {
"version": "2.5.0", "version": "2.5.0",
@ -4181,6 +4178,67 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
}, },
"joplin-renderer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz",
"integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==",
"requires": {
"base-64": "^0.1.0",
"font-awesome-filetypes": "^2.1.0",
"fs-extra": "^8.1.0",
"highlight.js": "^9.17.1",
"html-entities": "^1.2.1",
"katex": "^0.11.1",
"markdown-it": "^10.0.0",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^5.2.5",
"markdown-it-deflist": "^2.0.3",
"markdown-it-emoji": "^1.4.0",
"markdown-it-footnote": "^3.0.2",
"markdown-it-ins": "^3.0.0",
"markdown-it-mark": "^3.0.0",
"markdown-it-multimd-table": "^4.0.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"uslug": "^1.0.4"
},
"dependencies": {
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"graceful-fs": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
},
"markdown-it": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
"requires": {
"argparse": "^1.0.7",
"entities": "~2.0.0",
"linkify-it": "^2.0.0",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
}
}
},
"joplin-turndown": { "joplin-turndown": {
"version": "4.0.19", "version": "4.0.19",
"resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz",
@ -4547,37 +4605,19 @@
"integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A=="
}, },
"markdown-it-ins": { "markdown-it-ins": {
"version": "2.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz",
"integrity": "sha1-papqMPHi9x6Ul1Z8/f9A8f3mdIM=" "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q=="
},
"markdown-it-katex": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz",
"integrity": "sha1-17hqGuoLnWSW+rTnkZoY/e9YnDk=",
"requires": {
"katex": "^0.6.0"
},
"dependencies": {
"katex": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz",
"integrity": "sha1-EkGOCRIcBckgQbazuftrqyE8tvM=",
"requires": {
"match-at": "^0.1.0"
}
}
}
}, },
"markdown-it-mark": { "markdown-it-mark": {
"version": "2.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz",
"integrity": "sha1-RqGqlHEFrtgYiXjgoBYXnkBPQsc=" "integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw=="
}, },
"markdown-it-multimd-table": { "markdown-it-multimd-table": {
"version": "3.2.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-3.2.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz",
"integrity": "sha512-dBtYHVtyAnoWslzYLYDh0d9jX2/qroyMIsJ1BjFdIcLgZjzqBIBGwZ1j3AaaWh+IIfe3KVm5Irqn5Uzadm5kQA==", "integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==",
"requires": { "requires": {
"markdown-it": "^8.4.2" "markdown-it": "^8.4.2"
}, },
@ -4611,11 +4651,6 @@
"resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz",
"integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw==" "integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw=="
}, },
"match-at": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz",
"integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q=="
},
"matcher": { "matcher": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz", "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz",
@ -4826,6 +4861,11 @@
} }
} }
}, },
"neo-async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
},
"no-case": { "no-case": {
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
@ -5112,7 +5152,6 @@
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"dev": true, "dev": true,
"optional": true,
"requires": { "requires": {
"remove-trailing-separator": "^1.0.1" "remove-trailing-separator": "^1.0.1"
} }
@ -5231,6 +5270,15 @@
"mimic-fn": "^1.0.0" "mimic-fn": "^1.0.0"
} }
}, },
"optimist": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
"requires": {
"minimist": "~0.0.1",
"wordwrap": "~0.0.2"
}
},
"optionator": { "optionator": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
@ -5422,8 +5470,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
"dev": true, "dev": true
"optional": true
}, },
"is-glob": { "is-glob": {
"version": "2.0.1", "version": "2.0.1",
@ -5993,15 +6040,13 @@
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
"dev": true, "dev": true
"optional": true
}, },
"repeat-element": { "repeat-element": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
"dev": true, "dev": true
"optional": true
}, },
"repeat-string": { "repeat-string": {
"version": "1.6.1", "version": "1.6.1",
@ -7149,6 +7194,11 @@
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==" "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
}, },
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
"integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
},
"wrap-ansi": { "wrap-ansi": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",

View File

@ -99,34 +99,20 @@
"es6-promise-pool": "^2.5.0", "es6-promise-pool": "^2.5.0",
"file-uri-to-path": "^1.0.0", "file-uri-to-path": "^1.0.0",
"follow-redirects": "^1.5.0", "follow-redirects": "^1.5.0",
"font-awesome-filetypes": "^2.1.0",
"form-data": "^2.3.2", "form-data": "^2.3.2",
"formatcoords": "^1.1.3", "formatcoords": "^1.1.3",
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"highlight.js": "^9.15.6",
"html-entities": "^1.2.1", "html-entities": "^1.2.1",
"html-minifier": "^4.0.0", "html-minifier": "^4.0.0",
"image-type": "^3.0.0", "image-type": "^3.0.0",
"joplin-renderer": "^1.0.4",
"joplin-turndown": "^4.0.19", "joplin-turndown": "^4.0.19",
"joplin-turndown-plugin-gfm": "^1.0.11", "joplin-turndown-plugin-gfm": "^1.0.11",
"jssha": "^2.3.1", "jssha": "^2.3.1",
"katex": "^0.11.1",
"levenshtein": "^1.0.5", "levenshtein": "^1.0.5",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"mark.js": "^8.11.1", "mark.js": "^8.11.1",
"markdown-it": "^8.4.1", "markdown-it": "^8.4.1",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^5.2.5",
"markdown-it-deflist": "^2.0.3",
"markdown-it-emoji": "^1.4.0",
"markdown-it-footnote": "^3.0.2",
"markdown-it-ins": "^2.0.0",
"markdown-it-katex": "^2.0.3",
"markdown-it-mark": "^2.0.0",
"markdown-it-multimd-table": "^3.2.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1", "md5": "^2.2.1",
"moment": "^2.22.2", "moment": "^2.22.2",
"multiparty": "^4.2.1", "multiparty": "^4.2.1",
@ -157,7 +143,6 @@
"tcp-port-used": "^0.1.2", "tcp-port-used": "^0.1.2",
"uglifycss": "0.0.29", "uglifycss": "0.0.29",
"url-parse": "^1.4.3", "url-parse": "^1.4.3",
"uslug": "^1.0.4",
"uuid": "^3.2.1", "uuid": "^3.2.1",
"valid-url": "^1.0.9", "valid-url": "^1.0.9",
"xml2js": "^0.4.19" "xml2js": "^0.4.19"

View File

@ -5,5 +5,7 @@ set script_dir=%mypath:~0,-1%
call build.bat call build.bat
if %errorlevel% neq 0 exit /b %errorlevel% if %errorlevel% neq 0 exit /b %errorlevel%
rem xcopy /C /I /H /R /Y /S /Q D:\Docs\PROGS\Node\joplin-renderer %script_dir%\app\node_modules\joplin-renderer
cd %script_dir%\app cd %script_dir%\app
call .\node_modules\.bin\electron.cmd . --env dev --log-level debug --no-welcome --open-dev-tools "$@" call .\node_modules\.bin\electron.cmd . --env dev --log-level debug --no-welcome --open-dev-tools "$@"

View File

@ -0,0 +1,55 @@
const { dirname } = require('lib/path-utils.js');
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting');
const pluginAssets = require('./pluginAssets/index');
const KvStore = require('lib/services/KvStore.js');
export default class PluginAssetsLoader {
static instance_:PluginAssetsLoader = null;
logger_:any = null;
static instance() {
if (PluginAssetsLoader.instance_) return PluginAssetsLoader.instance_;
PluginAssetsLoader.instance_ = new PluginAssetsLoader();
return PluginAssetsLoader.instance_;
}
setLogger(logger:any) {
this.logger_ = logger;
}
logger() {
return this.logger_;
}
async importAssets() {
const destDir = `${Setting.value('resourceDir')}/pluginAssets`;
await shim.fsDriver().mkdir(destDir);
const hash = pluginAssets.hash;
if (hash === await KvStore.instance().value('PluginAssetsLoader.lastHash')) {
this.logger().info(`PluginAssetsLoader: Assets are up to date. Hash: ${hash}`);
return;
}
this.logger().info(`PluginAssetsLoader: Importing assets to ${destDir}`);
try {
for (let name in pluginAssets.files) {
const dataBase64 = pluginAssets.files[name].data;
const destPath = `${destDir}/${name}`;
await shim.fsDriver().mkdir(dirname(destPath));
await shim.fsDriver().unlink(destPath);
this.logger().info(`PluginAssetsLoader: Copying: ${name} => ${destPath}`);
await shim.fsDriver().writeFile(destPath, dataBase64);
}
} catch (error) {
this.logger().error(error);
}
KvStore.instance().setValue('PluginAssetsLoader.lastHash', hash);
}
}

View File

@ -0,0 +1,74 @@
require('app-module-path').addPath(`${__dirname}`);
const fs = require('fs-extra');
const { dirname, fileExtension } = require('lib/path-utils');
const md5 = require('md5');
const rootDir = __dirname;
const outputDir = `${rootDir}/pluginAssets`;
var walk = function(dir) {
var results = [];
var list = fs.readdirSync(dir);
list.forEach(function(file) {
file = `${dir}/${file}`;
var stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
results = results.concat(walk(file));
} else {
results.push(file);
}
});
return results;
};
async function encodeFile(sourcePath, destPath) {
const buffer = await fs.readFile(sourcePath);
const hash = md5(buffer.toString('base64'));
const js = `module.exports = \`${buffer.toString('base64')}\`;`;
const outputPath = `${outputDir}/${destPath}.base64.js`;
await fs.mkdirp(dirname(outputPath));
await fs.writeFile(outputPath, js);
const ext = fileExtension(sourcePath).toLowerCase();
let mime = 'application/octet-stream';
if (ext === 'js') mime = 'application/javascript';
if (ext === 'css') mime = 'text/css';
return {
encoding: 'base64',
name: destPath,
encodedName: `${destPath}.base64.js`,
mime: mime,
hash: hash,
};
}
async function main() {
await fs.mkdirp(outputDir);
const encodedFiles = [];
const sourceAssetDir = `${rootDir}/node_modules/joplin-renderer/assets`;
const files = walk(sourceAssetDir);
for (const file of files) {
const destFile = file.substr(sourceAssetDir.length + 1);
encodedFiles.push(await encodeFile(file, destFile));
}
const hashes = [];
const indexJs = [];
for (const file of encodedFiles) {
indexJs.push(`'${file.name}': { data: require('./${file.encodedName}'), mime: '${file.mime}', encoding: '${file.encoding}' },`);
hashes.push(file.hash);
}
const hash = md5(hashes.join(''));
await fs.writeFile(`${outputDir}/index.js`, `module.exports = {\nhash:"${hash}", files: {\n${indexJs.join('\n')}\n}\n};`);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -38,7 +38,7 @@ const globalStyle = {
htmlCodeBorderColor: 'rgb(220, 220, 220)', htmlCodeBorderColor: 'rgb(220, 220, 220)',
htmlCodeColor: 'rgb(0,0,0)', htmlCodeColor: 'rgb(0,0,0)',
codeThemeCss: 'hljs-atom-one-light.css', codeThemeCss: 'atom-one-light.css',
}; };
globalStyle.marginRight = globalStyle.margin; globalStyle.marginRight = globalStyle.margin;

View File

@ -1,13 +1,15 @@
const React = require('react'); const React = require('react');
const Component = React.Component; const Component = React.Component;
const { Platform, View } = require('react-native'); const { Platform, View, Text } = require('react-native');
const { WebView } = require('react-native-webview'); const { WebView } = require('react-native-webview');
const { themeStyle } = require('lib/components/global-style.js'); const { themeStyle } = require('lib/components/global-style.js');
const Setting = require('lib/models/Setting.js'); const Setting = require('lib/models/Setting.js');
const { reg } = require('lib/registry.js'); const { reg } = require('lib/registry.js');
const { shim } = require('lib/shim'); const { shim } = require('lib/shim');
const MdToHtml = require('lib/renderers/MdToHtml.js');
const shared = require('lib/components/shared/note-screen-shared.js'); const shared = require('lib/components/shared/note-screen-shared.js');
const markupLanguageUtils = require('lib/markupLanguageUtils');
import Async from 'react-async';
class NoteBodyViewer extends Component { class NoteBodyViewer extends Component {
constructor() { constructor() {
@ -15,21 +17,134 @@ class NoteBodyViewer extends Component {
this.state = { this.state = {
resources: {}, resources: {},
webViewLoaded: false, webViewLoaded: false,
bodyHtml: '',
}; };
this.isMounted_ = false; this.isMounted_ = false;
this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml();
this.reloadNote = this.reloadNote.bind(this);
} }
UNSAFE_componentWillMount() { componentDidMount() {
this.mdToHtml_ = new MdToHtml();
this.isMounted_ = true; this.isMounted_ = true;
} }
componentWillUnmount() { componentWillUnmount() {
this.mdToHtml_ = null; this.markupToHtml_ = null;
this.isMounted_ = false; this.isMounted_ = false;
} }
async reloadNote() {
const note = this.props.note;
const theme = themeStyle(this.props.theme);
const bodyToRender = note ? note.body : '';
const mdOptions = {
onResourceLoaded: () => {
if (this.resourceLoadedTimeoutId_) {
clearTimeout(this.resourceLoadedTimeoutId_);
this.resourceLoadedTimeoutId_ = null;
}
this.resourceLoadedTimeoutId_ = setTimeout(() => {
this.resourceLoadedTimeoutId_ = null;
this.forceUpdate();
}, 100);
},
paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
highlightedKeywords: this.props.highlightedKeywords,
resources: this.props.noteResources, // await shared.attachedResources(bodyToRender),
codeTheme: theme.codeThemeCss,
postMessageSyntax: 'window.ReactNativeWebView.postMessage',
};
let result = await this.markupToHtml_.render(note.markup_language, bodyToRender, this.props.webViewStyle, mdOptions);
let html = result.html;
const resourceDownloadMode = Setting.value('sync.resourceDownloadMode');
const injectedJs = [];
injectedJs.push(shim.injectedJs('webviewLib'));
injectedJs.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });');
injectedJs.push(`
const readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload();
const hash = "${this.props.noteHash}";
// Gives it a bit of time before scrolling to the anchor
// so that images are loaded.
if (hash) {
setTimeout(() => {
const e = document.getElementById(hash);
if (!e) {
console.warn('Cannot find hash', hash);
return;
}
e.scrollIntoView();
}, 500);
}
}
}, 10);
`);
const headers = [];
for (let i = 0; i < result.pluginAssets.length; i++) {
const asset = result.pluginAssets[i];
if (asset.mime === 'text/css') {
headers.push(`<link rel="stylesheet" href="pluginAssets/${asset.name}">`);
} else if (asset.mime === 'application/javascript') {
// NOT TESTED!!
headers.push(`<script type="application/javascript" src="pluginAssets/${asset.name}"></script>`);
}
}
html =
`
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
${headers.join('\n')}
</head>
<body>
${html}
</body>
</html>
`;
// On iOS scalesPageToFit work like this:
//
// Find the widest image, resize it *and everything else* by x% so that
// the image fits within the viewport. The problem is that it means if there's
// a large image, everything is going to be scaled to a very small size, making
// the text unreadable.
//
// On Android:
//
// Find the widest elements and scale them (and them only) to fit within the viewport
// It means it's going to scale large images, but the text will remain at the normal
// size.
//
// That means we can use scalesPageToFix on Android but not on iOS.
// The weird thing is that on iOS, scalesPageToFix=false along with a CSS
// rule "img { max-width: 100% }", works like scalesPageToFix=true on Android.
// So we use scalesPageToFix=false on iOS along with that CSS rule.
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
return {
source: {
html: html,
baseUrl: `file://${Setting.value('resourceDir')}/`,
},
injectedJs: injectedJs,
};
}
onLoadEnd() { onLoadEnd() {
setTimeout(() => { setTimeout(() => {
if (this.props.onLoadEnd) this.props.onLoadEnd(); if (this.props.onLoadEnd) this.props.onLoadEnd();
@ -70,80 +185,18 @@ class NoteBodyViewer extends Component {
} }
rebuildMd() { rebuildMd() {
// this.mdToHtml_.clearCache();
this.forceUpdate(); this.forceUpdate();
} }
render() { render() {
const note = this.props.note; // Note: useWebKit={false} is needed to go around this bug:
const style = this.props.style; // https://github.com/react-native-community/react-native-webview/issues/376
// However, if we add the <meta> tag as described there, it is no longer necessary and WebKit can be used!
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-501991406
//
// However, on iOS, due to the bug below, we cannot use WebKit:
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-503754654
const theme = themeStyle(this.props.theme);
const bodyToRender = note ? note.body : '';
const mdOptions = {
onResourceLoaded: () => {
if (this.resourceLoadedTimeoutId_) {
clearTimeout(this.resourceLoadedTimeoutId_);
this.resourceLoadedTimeoutId_ = null;
}
this.resourceLoadedTimeoutId_ = setTimeout(() => {
this.resourceLoadedTimeoutId_ = null;
this.forceUpdate();
}, 100);
},
paddingBottom: '3.8em', // Extra bottom padding to make it possible to scroll past the action button (so that it doesn't overlap the text)
highlightedKeywords: this.props.highlightedKeywords,
resources: this.props.noteResources, // await shared.attachedResources(bodyToRender),
codeTheme: theme.codeThemeCss,
postMessageSyntax: 'window.ReactNativeWebView.postMessage',
};
let result = this.mdToHtml_.render(bodyToRender, this.props.webViewStyle, mdOptions);
let html = result.html;
const resourceDownloadMode = Setting.value('sync.resourceDownloadMode');
const injectedJs = [this.mdToHtml_.injectedJavaScript()];
injectedJs.push(shim.injectedJs('webviewLib'));
injectedJs.push('webviewLib.initialize({ postMessage: msg => { return window.ReactNativeWebView.postMessage(msg); } });');
injectedJs.push(`
const readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
clearInterval(readyStateCheckInterval);
if ("${resourceDownloadMode}" === "manual") webviewLib.setupResourceManualDownload();
const hash = "${this.props.noteHash}";
// Gives it a bit of time before scrolling to the anchor
// so that images are loaded.
if (hash) {
setTimeout(() => {
const e = document.getElementById(hash);
if (!e) {
console.warn('Cannot find hash', hash);
return;
}
e.scrollIntoView();
}, 500);
}
}
}, 10);
`);
html =
`
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
${html}
</body>
</html>
`;
let webViewStyle = { backgroundColor: this.props.webViewStyle.backgroundColor }; let webViewStyle = { backgroundColor: this.props.webViewStyle.backgroundColor };
// On iOS, the onLoadEnd() event is never fired so always // On iOS, the onLoadEnd() event is never fired so always
@ -153,68 +206,49 @@ class NoteBodyViewer extends Component {
webViewStyle.opacity = this.state.webViewLoaded ? 1 : 0.01; webViewStyle.opacity = this.state.webViewLoaded ? 1 : 0.01;
} }
// On iOS scalesPageToFit work like this:
//
// Find the widest image, resize it *and everything else* by x% so that
// the image fits within the viewport. The problem is that it means if there's
// a large image, everything is going to be scaled to a very small size, making
// the text unreadable.
//
// On Android:
//
// Find the widest elements and scale them (and them only) to fit within the viewport
// It means it's going to scale large images, but the text will remain at the normal
// size.
//
// That means we can use scalesPageToFix on Android but not on iOS.
// The weird thing is that on iOS, scalesPageToFix=false along with a CSS
// rule "img { max-width: 100% }", works like scalesPageToFix=true on Android.
// So we use scalesPageToFix=false on iOS along with that CSS rule.
// `baseUrl` is where the images will be loaded from. So images must use a path relative to resourceDir.
const source = {
html: html,
baseUrl: `file://${Setting.value('resourceDir')}/`,
};
// Note: useWebKit={false} is needed to go around this bug:
// https://github.com/react-native-community/react-native-webview/issues/376
// However, if we add the <meta> tag as described there, it is no longer necessary and WebKit can be used!
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-501991406
//
// However, on iOS, due to the bug below, we cannot use WebKit:
// https://github.com/react-native-community/react-native-webview/issues/312#issuecomment-503754654
return ( return (
<View style={style}> <View style={this.props.style}>
<WebView <Async promiseFn={this.reloadNote}>
useWebKit={Platform.OS !== 'ios'} {({ data, error, isPending }) => {
style={webViewStyle} if (error) {
source={source} console.error(error);
injectedJavaScript={injectedJs.join('\n')} return <Text>{error.message}</Text>;
originWhitelist={['file://*', './*', 'http://*', 'https://*']}
mixedContentMode="always"
allowFileAccess={true}
onLoadEnd={() => this.onLoadEnd()}
onError={() => reg.logger().error('WebView error')}
onMessage={event => {
// Since RN 58 (or 59) messages are now escaped twice???
let msg = unescape(unescape(event.nativeEvent.data));
console.info('Got IPC message: ', msg);
if (msg.indexOf('checkboxclick:') === 0) {
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
} else if (msg.indexOf('markForDownload:') === 0) {
msg = msg.split(':');
const resourceId = msg[1];
if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId });
} else {
this.props.onJoplinLinkClick(msg);
} }
if (isPending) return null;
return (
<WebView
useWebKit={Platform.OS !== 'ios'}
style={webViewStyle}
source={data.source}
injectedJavaScript={data.injectedJs.join('\n')}
originWhitelist={['file://*', './*', 'http://*', 'https://*']}
mixedContentMode="always"
allowFileAccess={true}
onLoadEnd={() => this.onLoadEnd()}
onError={() => reg.logger().error('WebView error')}
onMessage={event => {
// Since RN 58 (or 59) messages are now escaped twice???
let msg = unescape(unescape(event.nativeEvent.data));
console.info('Got IPC message: ', msg);
if (msg.indexOf('checkboxclick:') === 0) {
const newBody = shared.toggleCheckbox(msg, this.props.note.body);
if (this.props.onCheckboxChange) this.props.onCheckboxChange(newBody);
} else if (msg.indexOf('markForDownload:') === 0) {
msg = msg.split(':');
const resourceId = msg[1];
if (this.props.onMarkForDownload) this.props.onMarkForDownload({ resourceId: resourceId });
} else {
this.props.onJoplinLinkClick(msg);
}
}}
/>
);
}} }}
/> </Async>
</View> </View>
); );
} }

View File

@ -38,7 +38,13 @@ class FsDriverRN extends FsDriverBase {
if (!options) options = {}; if (!options) options = {};
if (!('recursive' in options)) options.recursive = false; if (!('recursive' in options)) options.recursive = false;
let items = await RNFS.readDir(path); let items = [];
try {
items = await RNFS.readDir(path);
} catch (error) {
throw new Error(`Could not read directory: ${path}: ${error.message}`);
}
let output = []; let output = [];
for (let i = 0; i < items.length; i++) { for (let i = 0; i < items.length; i++) {
const item = items[i]; const item = items[i];

View File

@ -4,6 +4,7 @@ const BaseModel = require('lib/BaseModel.js');
const Note = require('lib/models/Note.js'); const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js'); const Tag = require('lib/models/Tag.js');
const Resource = require('lib/models/Resource.js'); const Resource = require('lib/models/Resource.js');
const { MarkupToHtml } = require('joplin-renderer');
const { enexXmlToMd } = require('./import-enex-md-gen.js'); const { enexXmlToMd } = require('./import-enex-md-gen.js');
const { enexXmlToHtml } = require('./import-enex-html-gen.js'); const { enexXmlToHtml } = require('./import-enex-html-gen.js');
const { time } = require('lib/time-utils.js'); const { time } = require('lib/time-utils.js');
@ -224,8 +225,8 @@ function importEnex(parentFolderId, filePath, importOptions = null) {
delete note.bodyXml; delete note.bodyXml;
note.markup_language = importOptions.outputFormat === 'html' ? note.markup_language = importOptions.outputFormat === 'html' ?
Note.MARKUP_LANGUAGE_HTML : MarkupToHtml.MARKUP_LANGUAGE_HTML :
Note.MARKUP_LANGUAGE_MARKDOWN; MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
// console.info('*************************************************************************'); // console.info('*************************************************************************');
// console.info(body); // console.info(body);

View File

@ -287,6 +287,11 @@ class JoplinDatabase extends Database {
}); });
} }
addMigrationFile(num) {
const timestamp = Date.now();
return { sql: 'INSERT INTO migrations (number, created_time, updated_time) VALUES (?, ?, ?)', params: [num, timestamp, timestamp] };
}
async upgradeDatabase(fromVersion) { async upgradeDatabase(fromVersion) {
// INSTRUCTIONS TO UPGRADE THE DATABASE: // INSTRUCTIONS TO UPGRADE THE DATABASE:
// //
@ -302,7 +307,7 @@ class JoplinDatabase extends Database {
// must be set in the synchronizer too. // must be set in the synchronizer too.
// Note: v16 and v17 don't do anything. They were used to debug an issue. // Note: v16 and v17 don't do anything. They were used to debug an issue.
const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]; const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27];
let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion); let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);
@ -596,9 +601,8 @@ class JoplinDatabase extends Database {
`; `;
queries.push(this.sqlStringToLines(newTableSql)[0]); queries.push(this.sqlStringToLines(newTableSql)[0]);
const timestamp = Date.now();
queries.push('ALTER TABLE resources ADD COLUMN `size` INT NOT NULL DEFAULT -1'); queries.push('ALTER TABLE resources ADD COLUMN `size` INT NOT NULL DEFAULT -1');
queries.push({ sql: 'INSERT INTO migrations (number, created_time, updated_time) VALUES (20, ?, ?)', params: [timestamp, timestamp] }); queries.push(this.addMigrationFile(20));
} }
if (targetVersion == 21) { if (targetVersion == 21) {
@ -657,6 +661,10 @@ class JoplinDatabase extends Database {
} }
} }
if (targetVersion == 27) {
queries.push(this.addMigrationFile(27));
}
queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] }); queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] });
try { try {

View File

@ -1,7 +1,7 @@
const stringPadding = require('string-padding'); const stringPadding = require('string-padding');
const urlUtils = require('lib/urlUtils'); const urlUtils = require('lib/urlUtils');
const MarkdownIt = require('markdown-it'); const MarkdownIt = require('markdown-it');
const setupLinkify = require('lib/renderers/MdToHtml/setupLinkify'); const { setupLinkify } = require('joplin-renderer');
const markdownUtils = { const markdownUtils = {
// Not really escaping because that's not supported by marked.js // Not really escaping because that's not supported by marked.js

View File

@ -1,17 +1,36 @@
const markdownUtils = require('lib/markdownUtils'); const markdownUtils = require('lib/markdownUtils');
const htmlUtils = require('lib/htmlUtils'); const htmlUtils = require('lib/htmlUtils');
const Note = require('lib/models/Note'); const Setting = require('lib/models/Setting');
const Resource = require('lib/models/Resource');
const { MarkupToHtml } = require('joplin-renderer');
class MarkupLanguageUtils { class MarkupLanguageUtils {
lib_(language) { lib_(language) {
if (language === Note.MARKUP_LANGUAGE_HTML) return htmlUtils; if (language === MarkupToHtml.MARKUP_LANGUAGE_HTML) return htmlUtils;
if (language === Note.MARKUP_LANGUAGE_MARKDOWN) return markdownUtils; if (language === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN) return markdownUtils;
throw new Error(`Unsupported markup language: ${language}`); throw new Error(`Unsupported markup language: ${language}`);
} }
extractImageUrls(language, text) { extractImageUrls(language, text) {
return this.lib_(language).extractImageUrls(text); return this.lib_(language).extractImageUrls(text);
} }
// Create a new MarkupToHtml instance while injecting options specific to Joplin
// desktop and mobile applications.
newMarkupToHtml(options = null) {
const subValues = Setting.subValues('markdown.plugin', Setting.toPlainObject());
const pluginOptions = {};
for (const n in subValues) {
pluginOptions[n] = { enabled: subValues[n] };
}
options = Object.assign({
ResourceModel: Resource,
pluginOptions: pluginOptions,
}, options);
return new MarkupToHtml(options);
}
} }
const markupLanguageUtils = new MarkupLanguageUtils(); const markupLanguageUtils = new MarkupLanguageUtils();

View File

@ -0,0 +1,10 @@
const Setting = require('lib/models/Setting');
const script = {};
script.exec = async function() {
Setting.setValue('markdown.plugin.softbreaks', Setting.value('markdown.softbreaks'));
Setting.setValue('markdown.plugin.typographer', Setting.value('markdown.typographer'));
};
module.exports = script;

View File

@ -2,6 +2,7 @@ const BaseModel = require('lib/BaseModel.js');
const migrationScripts = { const migrationScripts = {
20: require('lib/migrations/20.js'), 20: require('lib/migrations/20.js'),
27: require('lib/migrations/27.js'),
}; };
class Migration extends BaseModel { class Migration extends BaseModel {
@ -18,6 +19,7 @@ class Migration extends BaseModel {
} }
static script(number) { static script(number) {
if (!migrationScripts[number]) throw new Error('Migration script has not been added to "migrationScripts" array');
return migrationScripts[number]; return migrationScripts[number];
} }
} }

View File

@ -11,6 +11,7 @@ const { _ } = require('lib/locale.js');
const ArrayUtils = require('lib/ArrayUtils.js'); const ArrayUtils = require('lib/ArrayUtils.js');
const lodash = require('lodash'); const lodash = require('lodash');
const urlUtils = require('lib/urlUtils.js'); const urlUtils = require('lib/urlUtils.js');
const { MarkupToHtml } = require('joplin-renderer');
class Note extends BaseItem { class Note extends BaseItem {
static tableName() { static tableName() {
@ -624,8 +625,8 @@ class Note extends BaseItem {
} }
static markupLanguageToLabel(markupLanguageId) { static markupLanguageToLabel(markupLanguageId) {
if (markupLanguageId === Note.MARKUP_LANGUAGE_MARKDOWN) return 'Markdown'; if (markupLanguageId === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN) return 'Markdown';
if (markupLanguageId === Note.MARKUP_LANGUAGE_HTML) return 'HTML'; if (markupLanguageId === MarkupToHtml.MARKUP_LANGUAGE_HTML) return 'HTML';
throw new Error(`Invalid markup language ID: ${markupLanguageId}`); throw new Error(`Invalid markup language ID: ${markupLanguageId}`);
} }
} }
@ -633,7 +634,4 @@ class Note extends BaseItem {
Note.updateGeolocationEnabled_ = true; Note.updateGeolocationEnabled_ = true;
Note.geolocationUpdating_ = false; Note.geolocationUpdating_ = false;
Note.MARKUP_LANGUAGE_MARKDOWN = 1;
Note.MARKUP_LANGUAGE_HTML = 2;
module.exports = Note; module.exports = Note;

View File

@ -334,8 +334,14 @@ class Setting extends BaseModel {
}; };
}, },
}, },
'markdown.softbreaks': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable soft breaks') },
'markdown.typographer': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable typographer support') }, // Deprecated - use markdown.plugin.*
'markdown.softbreaks': { value: false, type: Setting.TYPE_BOOL, public: false, appTypes: ['mobile', 'desktop']},
'markdown.typographer': { value: false, type: Setting.TYPE_BOOL, public: false, appTypes: ['mobile', 'desktop']},
// Deprecated
'markdown.plugin.softbreaks': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable soft breaks') },
'markdown.plugin.typographer': { value: false, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable typographer support') },
'markdown.plugin.katex': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable math expressions') }, 'markdown.plugin.katex': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable math expressions') },
'markdown.plugin.mark': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable ==mark== syntax') }, 'markdown.plugin.mark': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable ==mark== syntax') },
'markdown.plugin.footnote': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable footnotes') }, 'markdown.plugin.footnote': { value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable footnotes') },
@ -848,12 +854,14 @@ class Setting extends BaseModel {
// { sync.5.path: 'http://example', sync.5.username: 'testing' } // { sync.5.path: 'http://example', sync.5.username: 'testing' }
// and baseKey is 'sync.5', the function will return // and baseKey is 'sync.5', the function will return
// { path: 'http://example', username: 'testing' } // { path: 'http://example', username: 'testing' }
static subValues(baseKey, settings) { static subValues(baseKey, settings, options = null) {
const includeBaseKeyInName = !!options && !!options.includeBaseKeyInName;
let output = {}; let output = {};
for (let key in settings) { for (let key in settings) {
if (!settings.hasOwnProperty(key)) continue; if (!settings.hasOwnProperty(key)) continue;
if (key.indexOf(baseKey) === 0) { if (key.indexOf(baseKey) === 0) {
const subKey = key.substr(baseKey.length + 1); const subKey = includeBaseKeyInName ? key : key.substr(baseKey.length + 1);
output[subKey] = settings[key]; output[subKey] = settings[key];
} }
} }

View File

@ -1,41 +0,0 @@
const htmlUtils = require('lib/htmlUtils');
const utils = require('./utils');
const noteStyle = require('./noteStyle');
class HtmlToHtml {
constructor(options) {
if (!options) options = {};
this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null;
}
render(markup, theme, options) {
const html = htmlUtils.processImageTags(markup, data => {
if (!data.src) return null;
const r = utils.imageReplacement(data.src, options.resources, this.resourceBaseUrl_);
if (!r) return null;
if (typeof r === 'string') {
return {
type: 'replaceElement',
html: r,
};
} else {
return {
type: 'setAttributes',
attrs: r,
};
}
});
const cssStrings = noteStyle(theme, options);
const styleHtml = `<style>${cssStrings.join('\n')}</style>`;
return {
html: styleHtml + html,
cssFiles: [],
};
}
}
module.exports = HtmlToHtml;

View File

@ -1,37 +0,0 @@
const MdToHtml = require('./MdToHtml');
const HtmlToHtml = require('./HtmlToHtml');
const Note = require('lib/models/Note');
class MarkupToHtml {
constructor(options) {
this.options_ = options;
this.renderers_ = {};
}
renderer(markupLanguage) {
if (this.renderers_[markupLanguage]) return this.renderers_[markupLanguage];
let RendererClass = null;
if (markupLanguage === Note.MARKUP_LANGUAGE_MARKDOWN) {
RendererClass = MdToHtml;
} else if (markupLanguage === Note.MARKUP_LANGUAGE_HTML) {
RendererClass = HtmlToHtml;
} else {
throw new Error(`Invalid markup language: ${markupLanguage}`);
}
this.renderers_[markupLanguage] = new RendererClass(this.options_);
return this.renderers_[markupLanguage];
}
injectedJavaScript() {
return '';
}
render(markupLanguage, markup, theme, options) {
return this.renderer(markupLanguage).render(markup, theme, options);
}
}
module.exports = MarkupToHtml;

View File

@ -1,199 +0,0 @@
const MarkdownIt = require('markdown-it');
const { shim } = require('lib/shim.js');
const md5 = require('md5');
const noteStyle = require('./noteStyle');
const Setting = require('lib/models/Setting.js');
const rules = {
image: require('./MdToHtml/rules/image'),
checkbox: require('./MdToHtml/rules/checkbox'),
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'),
fountain: require('./MdToHtml/rules/fountain'),
};
const setupLinkify = require('./MdToHtml/setupLinkify');
const hljs = require('highlight.js');
const uslug = require('uslug');
const markdownItAnchor = require('markdown-it-anchor');
// The keys must match the corresponding entry in Setting.js
const plugins = {
mark: { module: require('markdown-it-mark') },
footnote: { module: require('markdown-it-footnote') },
sub: { module: require('markdown-it-sub') },
sup: { module: require('markdown-it-sup') },
deflist: { module: require('markdown-it-deflist') },
abbr: { module: require('markdown-it-abbr') },
emoji: { module: require('markdown-it-emoji') },
insert: { module: require('markdown-it-ins') },
multitable: { module: require('markdown-it-multimd-table'), options: { enableMultilineRows: true, enableRowspan: true } },
toc: { module: require('markdown-it-toc-done-right'), options: { listType: 'ul', slugify: uslugify } },
};
function uslugify(s) {
return uslug(s);
}
class MdToHtml {
constructor(options = null) {
if (!options) options = {};
// Must include last "/"
this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null;
this.cachedOutputs_ = {};
this.lastCodeHighlightCacheKey_ = null;
this.cachedHighlightedCode_ = {};
}
render(body, style, options = null) {
if (!options) options = {};
if (!options.postMessageSyntax) options.postMessageSyntax = 'postMessage';
if (!options.paddingBottom) options.paddingBottom = '0';
if (!options.highlightedKeywords) options.highlightedKeywords = [];
// The "codeHighlightCacheKey" option indicates what set of cached object should be
// associated with this particular Markdown body. It is only used to allow us to
// clear the cache whenever switching to a different note.
// If "codeHighlightCacheKey" is not specified, code highlighting won't be cached.
if (options.codeHighlightCacheKey !== this.lastCodeHighlightCacheKey_ || !options.codeHighlightCacheKey) {
this.cachedHighlightedCode_ = {};
this.lastCodeHighlightCacheKey_ = options.codeHighlightCacheKey;
}
const breaks_ = Setting.value('markdown.softbreaks') ? false : true;
const typographer_ = Setting.value('markdown.typographer') ? true : false;
const cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(style)));
const cachedOutput = this.cachedOutputs_[cacheKey];
if (cachedOutput) return cachedOutput;
const context = {
css: {},
cssFiles: {},
assetLoaders: {},
};
const ruleOptions = Object.assign({}, options, { resourceBaseUrl: this.resourceBaseUrl_ });
const markdownIt = new MarkdownIt({
breaks: breaks_,
typographer: typographer_,
linkify: true,
html: true,
highlight: (str, lang) => {
try {
let hlCode = '';
const cacheKey = md5(`${str}_${lang}`);
if (options.codeHighlightCacheKey && this.cachedHighlightedCode_[cacheKey]) {
hlCode = this.cachedHighlightedCode_[cacheKey];
} else {
if (lang && hljs.getLanguage(lang)) {
hlCode = hljs.highlight(lang, str, true).value;
} else {
hlCode = hljs.highlightAuto(str).value;
}
this.cachedHighlightedCode_[cacheKey] = hlCode;
}
if (shim.isReactNative()) {
context.css['hljs'] = shim.loadCssFromJs(options.codeTheme);
} else {
context.cssFiles['hljs'] = `highlight/styles/${options.codeTheme}`;
}
return `<pre class="hljs"><code>${hlCode}</code></pre>`;
} catch (error) {
return `<pre class="hljs"><code>${markdownIt.utils.escapeHtml(str)}</code></pre>`;
}
},
});
// To add a plugin, there are three options:
//
// 1. If the plugin does not need any application specific data, use the standard way:
//
// const someMarkdownPlugin = require('someMarkdownPlugin');
// markdownIt.use(someMarkdownPlugin);
//
// 2. If the plugin does not need any application specific data, and you want the user
// to be able to toggle the plugin:
//
// Add the plugin to the plugins object
// const plugins = {
// plugin: require('someMarkdownPlugin'),
// }
//
// And add a corresponding entry into Setting.js
// 'markdown.plugin.mark': {value: true, type: Setting.TYPE_BOOL, section: 'plugins', public: true, appTypes: ['mobile', 'desktop'], label: () => _('Enable ==mark== syntax')},
//
// 3. If the plugin needs application data (in ruleOptions) or needs to pass data (CSS, files to load, etc.) back
// to the application (using the context object), use the application-specific way:
//
// const imagePlugin = require('./MdToHtml/rules/image');
// markdownIt.use(imagePlugin(context, ruleOptions));
//
// Using the `context` object, a plugin can send back either CSS strings (in .css) or CSS files that need
// to be loaded (in .cssFiles). In general, the desktop app will load the CSS files and the mobile app
// will load the CSS strings.
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 (Setting.value('markdown.plugin.katex')) markdownIt.use(rules.katex(context, ruleOptions));
if (Setting.value('markdown.plugin.fountain')) markdownIt.use(rules.fountain(context, ruleOptions));
markdownIt.use(rules.highlight_keywords(context, ruleOptions));
markdownIt.use(rules.code_inline(context, ruleOptions));
markdownIt.use(markdownItAnchor, { slugify: uslugify });
for (let key in plugins) {
if (Setting.value(`markdown.plugin.${key}`)) markdownIt.use(plugins[key].module, plugins[key].options);
}
setupLinkify(markdownIt);
const renderedBody = markdownIt.render(body);
const cssStrings = noteStyle(style, options);
for (let k in context.css) {
if (!context.css.hasOwnProperty(k)) continue;
cssStrings.push(context.css[k]);
}
for (let k in context.assetLoaders) {
if (!context.assetLoaders.hasOwnProperty(k)) continue;
context.assetLoaders[k]().catch(error => {
console.warn(`MdToHtml: Error loading assets for ${k}: `, error.message);
});
}
if (options.userCss) cssStrings.push(options.userCss);
const styleHtml = `<style>${cssStrings.join('\n')}</style>`;
const html = `${styleHtml}<div id="rendered-md">${renderedBody}</div>`;
const output = {
html: html,
cssFiles: Object.keys(context.cssFiles).map(k => context.cssFiles[k]),
};
// Fow now, we keep only the last entry in the cache
this.cachedOutputs_ = {};
this.cachedOutputs_[cacheKey] = output;
return output;
}
injectedJavaScript() {
return '';
}
}
module.exports = MdToHtml;

View File

@ -1,126 +0,0 @@
let checkboxIndex_ = -1;
const checkboxStyle = `
/* Remove the indentation from the checkboxes at the root of the document
(otherwise they are too far right), but keep it for their children to allow
nested lists. Make sure this value matches the UL margin. */
#rendered-md > ul > li.md-checkbox {
margin-left: -1.7em;
}
li.md-checkbox {
list-style-type: none;
}
li.md-checkbox input[type=checkbox] {
margin-right: 1em;
}
`;
function createPrefixTokens(Token, id, checked, label, postMessageSyntax, sourceToken) {
let token = null;
const tokens = [];
// A bit hard to handle errors here and it's unlikely that the token won't have a valid
// map parameter, but if it does set it to a very high value, which will be more easy to notice
// in calling code.
const lineIndex = sourceToken.map && sourceToken.map.length ? sourceToken.map[0] : 99999999;
const checkedString = checked ? 'checked' : 'unchecked';
const labelId = `cb-label-${id}`;
const js = `
${postMessageSyntax}('checkboxclick:${checkedString}:${lineIndex}');
const label = document.getElementById("${labelId}");
label.classList.remove(this.checked ? 'checkbox-label-unchecked' : 'checkbox-label-checked');
label.classList.add(this.checked ? 'checkbox-label-checked' : 'checkbox-label-unchecked');
return true;
`;
token = new Token('checkbox_input', 'input', 0);
token.attrs = [['type', 'checkbox'], ['id', id], ['onclick', js]];
if (checked) token.attrs.push(['checked', 'true']);
tokens.push(token);
token = new Token('label_open', 'label', 1);
token.attrs = [['id', labelId], ['for', id], ['class', `checkbox-label-${checkedString}`]];
tokens.push(token);
if (label) {
token = new Token('text', '', 0);
token.content = label;
tokens.push(token);
}
return tokens;
}
function createSuffixTokens(Token) {
return [new Token('label_close', 'label', -1)];
}
function installRule(markdownIt, mdOptions, ruleOptions, context) {
markdownIt.core.ruler.push('checkbox', state => {
const tokens = state.tokens;
const Token = state.Token;
const checkboxPattern = /^\[([x|X| ])\] (.*)$/;
let currentListItem = null;
let processedFirstInline = false;
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.type === 'list_item_open') {
currentListItem = token;
processedFirstInline = false;
continue;
}
if (token.type === 'list_item_close') {
currentListItem = null;
processedFirstInline = false;
continue;
}
// Note that we only support list items that start with "-" (not with "*")
if (currentListItem && currentListItem.markup === '-' && !processedFirstInline && token.type === 'inline') {
processedFirstInline = true;
const firstChild = token.children && token.children.length ? token.children[0] : null;
if (!firstChild) continue;
const matches = checkboxPattern.exec(firstChild.content);
if (!matches || matches.length < 2) continue;
checkboxIndex_++;
const checked = matches[1] !== ' ';
const id = `md-checkbox-${checkboxIndex_}`;
const label = matches.length >= 3 ? matches[2] : '';
// Prepend the text content with the checkbox markup and the opening <label> tag
// then append the </label> tag at the end of the text content.
const prefix = createPrefixTokens(Token, id, checked, label, ruleOptions.postMessageSyntax, token);
const suffix = createSuffixTokens(Token);
token.children = markdownIt.utils.arrayReplaceAt(token.children, 0, prefix);
token.children = token.children.concat(suffix);
// Add a class to the <li> container so that it can be targetted with CSS.
let itemClass = currentListItem.attrGet('class');
if (!itemClass) itemClass = '';
itemClass += ' md-checkbox';
currentListItem.attrSet('class', itemClass.trim());
context.css['checkbox'] = checkboxStyle;
}
}
});
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions, context);
};
};

View File

@ -1,22 +0,0 @@
function installRule(markdownIt) {
const defaultRender =
markdownIt.renderer.rules.code_inline ||
function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
markdownIt.renderer.rules.code_inline = (tokens, idx, options, env, self) => {
const token = tokens[idx];
let tokenClass = token.attrGet('class');
if (!tokenClass) tokenClass = '';
tokenClass += ' inline-code';
token.attrSet('class', tokenClass.trim());
return defaultRender(tokens, idx, options, env, self);
};
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions);
};
};

View File

@ -1,134 +0,0 @@
const fountain = require('lib/vendor/fountain.min.js');
const fountainCss = `
.fountain {
font-family: monospace;
line-height: 107%;
max-width: 1000px;
margin-left: auto;
margin-right: auto;
}
.fountain .title-page,
.fountain .page {
box-shadow: 0 0 5px rgba(0,0,0,0.1);
border: 1px solid #d2d2d2;
padding: 10%;
margin-bottom: 2em;
}
.fountain h1,
.fountain h2,
.fountain h3,
.fountain h4,
.fountain p {
font-weight: normal;
line-height: 107%;
margin: 1em 0;
border: none;
font-size: 1em;
}
.fountain .bold {
font-weight: bold;
}
.fountain .underline {
text-decoration: underline;
}
.fountain .centered {
text-align: center;
}
.fountain h2 {
text-align: right;
}
.fountain .dialogue p.parenthetical {
margin-left: 11%;
}
.fountain .title-page .credit,
.fountain .title-page .authors,
.fountain .title-page .source {
text-align: center;
}
.fountain .title-page h1 {
margin-bottom: 1.5em;
text-align: center;
}
.fountain .title-page .source {
margin-top: 1.5em;
}
.fountain .title-page .notes {
text-align: right;
margin: 3em 0;
}
.fountain .title-page h1 {
margin-bottom: 1.5em;
text-align: center;
}
.fountain .dialogue {
margin-left: 3em;
margin-right: 3em;
}
.fountain .dialogue p,
.fountain .dialogue h1,
.fountain .dialogue h2,
.fountain .dialogue h3,
.fountain .dialogue h4 {
margin: 0;
}
.fountain .dialogue h1,
.fountain .dialogue h2,
.fountain .dialogue h3,
.fountain .dialogue h4 {
text-align: center;
}
`;
function renderFountainScript(content) {
const result = fountain.parse(content);
return `
<div class="fountain">
<div class="title-page">
${result.html.title_page}
</div>
<div class="page">
${result.html.script}
</div>
</div>
`;
}
function addContextAssets(context) {
if ('fountain' in context.css) return;
context.css['fountain'] = fountainCss;
}
function installRule(markdownIt, mdOptions, ruleOptions, context) {
const defaultRender = markdownIt.renderer.rules.fence || function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
markdownIt.renderer.rules.fence = function(tokens, idx, options, env, self) {
const token = tokens[idx];
if (token.info !== 'fountain') return defaultRender(tokens, idx, options, env, self);
addContextAssets(context);
return renderFountainScript(token.content);
};
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions, context);
};
};

View File

@ -1,67 +0,0 @@
const StringUtils = require('lib/string-utils.js');
const md5 = require('md5');
function createHighlightedTokens(Token, splitted) {
let token;
const output = [];
for (let i = 0; i < splitted.length; i++) {
const text = splitted[i];
if (!text) continue;
if (i % 2 === 0) {
token = new Token('text', '', 0);
token.content = text;
output.push(token);
} else {
token = new Token('highlighted_keyword_open', 'span', 1);
token.attrs = [['class', 'highlighted-keyword']];
output.push(token);
token = new Token('text', '', 0);
token.content = text;
output.push(token);
token = new Token('highlighted_keyword_close', 'span', -1);
output.push(token);
}
}
return output;
}
function installRule(markdownIt, mdOptions, ruleOptions) {
const divider = md5(Date.now().toString() + Math.random().toString());
markdownIt.core.ruler.push('highlight_keywords', state => {
const keywords = ruleOptions.highlightedKeywords;
if (!keywords || !keywords.length) return;
const tokens = state.tokens;
const Token = state.Token;
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.type !== 'inline') continue;
for (let j = 0; j < token.children.length; j++) {
const child = token.children[j];
if (child.type !== 'text') continue;
const splitted = StringUtils.surroundKeywords(keywords, child.content, divider, divider).split(divider);
const splittedTokens = createHighlightedTokens(Token, splitted);
if (splittedTokens.length <= 1) continue;
token.children = markdownIt.utils.arrayReplaceAt(token.children, j, splittedTokens);
j += splittedTokens.length - 1;
}
}
});
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions);
};
};

View File

@ -1,51 +0,0 @@
const Resource = require('lib/models/Resource.js');
const htmlUtils = require('lib/htmlUtils.js');
const utils = require('../../utils');
function renderImageHtml(before, src, after, ruleOptions) {
const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl);
if (typeof r === 'string') return r;
if (r) return `<img ${before} ${htmlUtils.attributesHtml(r)} ${after}/>`;
return `[Image: ${src}]`;
}
function installRule(markdownIt, mdOptions, ruleOptions) {
const htmlBlockDefaultRender =
markdownIt.renderer.rules.html_block ||
function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
const htmlInlineDefaultRender =
markdownIt.renderer.rules.html_inline ||
function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
const imageRegex = /<img(.*?)src=["'](.*?)["'](.*?)>/gi;
const handleImageTags = function(defaultRender) {
return function(tokens, idx, options, env, self) {
const token = tokens[idx];
const content = token.content;
if (!content.match(imageRegex)) return defaultRender(tokens, idx, options, env, self);
return content.replace(imageRegex, (v, before, src, after) => {
if (!Resource.isResourceUrl(src)) return defaultRender(tokens, idx, options, env, self);
return renderImageHtml(before, src, after, ruleOptions);
});
};
};
// It seems images sometimes are inline, sometimes a block
// to make sure they both render correctly.
markdownIt.renderer.rules.html_block = handleImageTags(htmlBlockDefaultRender);
markdownIt.renderer.rules.html_inline = handleImageTags(htmlInlineDefaultRender);
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions);
};
};

View File

@ -1,27 +0,0 @@
const Resource = require('lib/models/Resource.js');
const utils = require('../../utils');
const htmlUtils = require('lib/htmlUtils.js');
function installRule(markdownIt, mdOptions, ruleOptions) {
const defaultRender = markdownIt.renderer.rules.image;
markdownIt.renderer.rules.image = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const src = utils.getAttr(token.attrs, 'src');
const title = utils.getAttr(token.attrs, 'title');
if (!Resource.isResourceUrl(src) || ruleOptions.plainResourceRendering) return defaultRender(tokens, idx, options, env, self);
const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl);
if (typeof r === 'string') return r;
if (r) return `<img data-from-md ${htmlUtils.attributesHtml(Object.assign({}, r, { title: title }))}/>`;
return defaultRender(tokens, idx, options, env, self);
};
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions);
};
};

View File

@ -1,295 +0,0 @@
// Based on https://github.com/waylonflinn/markdown-it-katex
'use strict';
const { shim } = require('lib/shim');
const Setting = require('lib/models/Setting');
var katex = require('katex');
const katexCss = require('lib/csstojs/katex.css.js');
const md5 = require('md5');
const mhchemModule = require('./katex_mhchem.js');
katex = mhchemModule(katex);
// const style = `
// /*
// This is to fix https://github.com/laurent22/joplin/issues/764
// Without this, the tag attached to an equation float at an absolute position of the page,
// instead of a position relative to the container.
// 2018-03-13: No longer needed??
// */
// /*
// .katex-display>.katex>.katex-html {
// position: relative;
// }
// */
// `
// Test if potential opening or closing delimieter
// Assumes that there is a "$" at state.src[pos]
function isValidDelim(state, pos) {
var prevChar,
nextChar,
max = state.posMax,
can_open = true,
can_close = true;
prevChar = pos > 0 ? state.src.charCodeAt(pos - 1) : -1;
nextChar = pos + 1 <= max ? state.src.charCodeAt(pos + 1) : -1;
// Check non-whitespace conditions for opening and closing, and
// check that closing delimeter isn't followed by a number
if (prevChar === 0x20 /* " " */ || prevChar === 0x09 /* \t */ || (nextChar >= 0x30 /* "0" */ && nextChar <= 0x39) /* "9" */) {
can_close = false;
}
if (nextChar === 0x20 /* " " */ || nextChar === 0x09 /* \t */) {
can_open = false;
}
return {
can_open: can_open,
can_close: can_close,
};
}
function math_inline(state, silent) {
var start, match, token, res, pos;
if (state.src[state.pos] !== '$') {
return false;
}
res = isValidDelim(state, state.pos);
if (!res.can_open) {
if (!silent) {
state.pending += '$';
}
state.pos += 1;
return true;
}
// First check for and bypass all properly escaped delimieters
// This loop will assume that the first leading backtick can not
// be the first character in state.src, which is known since
// we have found an opening delimieter already.
start = state.pos + 1;
match = start;
while ((match = state.src.indexOf('$', match)) !== -1) {
// Found potential $, look for escapes, pos will point to
// first non escape when complete
pos = match - 1;
while (state.src[pos] === '\\') {
pos -= 1;
}
// Even number of escapes, potential closing delimiter found
if ((match - pos) % 2 == 1) {
break;
}
match += 1;
}
// No closing delimter found. Consume $ and continue.
if (match === -1) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}
// Check if we have empty content, ie: $$. Do not parse.
if (match - start === 0) {
if (!silent) {
state.pending += '$$';
}
state.pos = start + 1;
return true;
}
// Check for valid closing delimiter
res = isValidDelim(state, match);
if (!res.can_close) {
if (!silent) {
state.pending += '$';
}
state.pos = start;
return true;
}
if (!silent) {
token = state.push('math_inline', 'math', 0);
token.markup = '$';
token.content = state.src.slice(start, match);
}
state.pos = match + 1;
return true;
}
function math_block(state, start, end, silent) {
var firstLine,
lastLine,
next,
lastPos,
found = false,
token,
pos = state.bMarks[start] + state.tShift[start],
max = state.eMarks[start];
if (pos + 2 > max) {
return false;
}
if (state.src.slice(pos, pos + 2) !== '$$') {
return false;
}
pos += 2;
firstLine = state.src.slice(pos, max);
if (silent) {
return true;
}
if (firstLine.trim().slice(-2) === '$$') {
// Single line expression
firstLine = firstLine.trim().slice(0, -2);
found = true;
}
for (next = start; !found;) {
next++;
if (next >= end) {
break;
}
pos = state.bMarks[next] + state.tShift[next];
max = state.eMarks[next];
if (pos < max && state.tShift[next] < state.blkIndent) {
// non-empty line with negative indent should stop the list:
break;
}
if (
state.src
.slice(pos, max)
.trim()
.slice(-2) === '$$'
) {
lastPos = state.src.slice(0, max).lastIndexOf('$$');
lastLine = state.src.slice(pos, lastPos);
found = true;
}
}
state.line = next + 1;
token = state.push('math_block', 'math', 0);
token.block = true;
token.content = (firstLine && firstLine.trim() ? `${firstLine}\n` : '') + state.getLines(start + 1, next, state.tShift[start], true) + (lastLine && lastLine.trim() ? lastLine : '');
token.map = [start, state.line];
token.markup = '$$';
return true;
}
let assetsLoaded_ = false;
let cache_ = {};
module.exports = function(context) {
// Keep macros that persist across Katex blocks to allow defining a macro
// in one block and re-using it later in other blocks.
// https://github.com/laurent22/joplin/issues/1105
context.__katex = { macros: {} };
const addContextAssets = () => {
context.css['katex'] = katexCss;
context.assetLoaders['katex'] = async () => {
if (assetsLoaded_) return;
// In node, the fonts are simply copied using copycss to where Katex expects to find them, which is under app/gui/note-viewer/fonts
// In React Native, it's more complicated and we need to download and copy them to the right directory. Ideally, we should embed
// them as an asset and copy them from there (or load them from there by modifying Katex CSS), but for now that will do.
if (shim.isReactNative()) {
// Fonts must go under the resourceDir directory because this is the baseUrl of NoteBodyViewer
const baseDir = Setting.value('resourceDir');
await shim.fsDriver().mkdir(`${baseDir}/fonts`);
await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Main-Regular.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Main-Regular.woff2` });
await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Math-Italic.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Math-Italic.woff2` });
await shim.fetchBlob('https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.9.0-beta1/fonts/KaTeX_Size1-Regular.woff2', { overwrite: false, path: `${baseDir}/fonts/KaTeX_Size1-Regular.woff2` });
}
// eslint-disable-next-line require-atomic-updates
assetsLoaded_ = true;
};
};
function renderToStringWithCache(latex, options) {
const cacheKey = md5(escape(latex) + escape(JSON.stringify(options)));
if (cacheKey in cache_) {
return cache_[cacheKey];
} else {
const beforeMacros = JSON.stringify(options.macros);
const output = katex.renderToString(latex, options);
const afterMacros = JSON.stringify(options.macros);
// Don't cache the formulas that add macros, otherwise
// they won't be added on second run.
if (beforeMacros === afterMacros) cache_[cacheKey] = output;
return output;
}
}
return function(md, options) {
// Default options
options = options || {};
options.macros = context.__katex.macros;
// set KaTeX as the renderer for markdown-it-simplemath
var katexInline = function(latex) {
options.displayMode = false;
try {
return renderToStringWithCache(latex, options);
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};
var inlineRenderer = function(tokens, idx) {
addContextAssets();
return katexInline(tokens[idx].content);
};
var katexBlock = function(latex) {
options.displayMode = true;
try {
return `<p>${renderToStringWithCache(latex, options)}</p>`;
} catch (error) {
if (options.throwOnError) {
console.log(error);
}
return latex;
}
};
var blockRenderer = function(tokens, idx) {
addContextAssets();
return `${katexBlock(tokens[idx].content)}\n`;
};
md.inline.ruler.after('escape', 'math_inline', math_inline);
md.block.ruler.after('blockquote', 'math_block', math_block, {
alt: ['paragraph', 'reference', 'blockquote', 'list'],
});
md.renderer.rules.math_inline = inlineRenderer;
md.renderer.rules.math_block = blockRenderer;
};
};

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = new Entities().encode;
const utils = require('../../utils');
const urlUtils = require('lib/urlUtils.js');
const { getClassNameForMimeType } = require('font-awesome-filetypes');
function installRule(markdownIt, mdOptions, ruleOptions) {
markdownIt.renderer.rules.link_open = function(tokens, idx) {
const token = tokens[idx];
let href = utils.getAttr(token.attrs, 'href');
const resourceHrefInfo = urlUtils.parseResourceUrl(href);
const isResourceUrl = !!resourceHrefInfo;
let title = utils.getAttr(token.attrs, 'title', isResourceUrl ? '' : href);
let resourceIdAttr = '';
let icon = '';
let hrefAttr = '#';
let mime = '';
if (isResourceUrl) {
const resourceId = resourceHrefInfo.itemId;
const result = ruleOptions.resources[resourceId];
const resourceStatus = utils.resourceStatus(result);
if (result && result.item) {
title = utils.getAttr(token.attrs, 'title', result.item.title);
mime = result.item.mime;
}
if (result && resourceStatus !== 'ready' && !ruleOptions.plainResourceRendering) {
const icon = utils.resourceStatusFile(resourceStatus);
return `<a class="not-loaded-resource resource-status-${resourceStatus}" data-resource-id="${resourceId}">` + `<img src="data:image/svg+xml;utf8,${htmlentities(icon)}"/>`;
} else {
href = `joplin://${resourceId}`;
if (resourceHrefInfo.hash) href += `#${resourceHrefInfo.hash}`;
resourceIdAttr = `data-resource-id='${resourceId}'`;
let iconType = getClassNameForMimeType(mime);
if (!mime) {
iconType = 'fa-joplin';
}
// Icons are defined in lib/renderers/noteStyle.js using inline svg
// The icons are taken from fork-awesome but use the font-awesome naming scheme in order
// to be more compatible with the getClass library
icon = `<span class="resource-icon ${iconType}"></span>`;
}
} else {
// If the link is a plain URL (as opposed to a resource link), set the href to the actual
// link. This allows the link to be exported too when exporting to PDF.
hrefAttr = href;
}
// A single quote is valid in a URL but we don't want any because the
// href is already enclosed in single quotes.
// https://github.com/laurent22/joplin/issues/2030
href = href.replace(/'/g, '%27');
let js = `${ruleOptions.postMessageSyntax}(${JSON.stringify(href)}); return false;`;
if (hrefAttr.indexOf('#') === 0 && href.indexOf('#') === 0) js = ''; // If it's an internal anchor, don't add any JS since the webview is going to handle navigating to the right place
if (ruleOptions.plainResourceRendering) {
return `<a data-from-md ${resourceIdAttr} title='${htmlentities(title)}' href='${hrefAttr}' type='${htmlentities(mime)}'>`;
} else {
return `<a data-from-md ${resourceIdAttr} title='${htmlentities(title)}' href='${hrefAttr}' onclick='${js}' type='${htmlentities(mime)}'>${icon}`;
}
};
}
module.exports = function(context, ruleOptions) {
return function(md, mdOptions) {
installRule(md, mdOptions, ruleOptions);
};
};

View File

@ -1,29 +0,0 @@
module.exports = function(markdownIt) {
// Add `file:` protocol in linkify to allow text in the format of "file://..." to translate into
// file-URL links in html view
markdownIt.linkify.add('file:', {
validate: function(text, pos, self) {
var tail = text.slice(pos);
if (!self.re.file) {
// matches all local file URI on Win/Unix/MacOS systems including reserved characters in some OS (i.e. no OS specific sanity check)
self.re.file = new RegExp('^[\\/]{2,3}[\\S]+');
}
if (self.re.file.test(tail)) {
return tail.match(self.re.file)[0].length;
}
return 0;
},
});
// enable file link URLs in MarkdownIt. Keeps other URL restrictions of MarkdownIt untouched.
// Format [link name](file://...)
markdownIt.validateLink = function(url) {
var BAD_PROTO_RE = /^(vbscript|javascript|data):/;
var GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/;
// url should be normalized at this point, and existing entities are decoded
var str = url.trim().toLowerCase();
return BAD_PROTO_RE.test(str) ? (GOOD_DATA_RE.test(str) ? true : false) : true;
};
};

View File

@ -1,291 +0,0 @@
module.exports = function(style, options) {
// https://necolas.github.io/normalize.css/
const normalizeCss = `
html{line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}
pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}
b,strong{font-weight:bolder}small{font-size:80%}img{border-style:none}
`;
const fontFamily = '\'Avenir\', \'Arial\', sans-serif';
const css =
`
body {
font-size: ${style.htmlFontSize};
color: ${style.htmlColor};
line-height: ${style.htmlLineHeight};
background-color: ${style.htmlBackgroundColor};
font-family: ${fontFamily};
padding-bottom: ${options.paddingBottom};
}
strong {
color: ${style.colorBright};
}
kbd {
border: 1px solid ${style.htmlCodeBorderColor};
box-shadow: inset 0 -1px 0 ${style.htmlCodeBorderColor};
padding: 2px 4px;
border-radius: 3px;
background-color: ${style.htmlCodeBackgroundColor};
}
::-webkit-scrollbar {
width: 7px;
height: 7px;
}
::-webkit-scrollbar-corner {
background: none;
}
::-webkit-scrollbar-track {
border: none;
}
::-webkit-scrollbar-thumb {
background: rgba(100, 100, 100, 0.3);
border-radius: 5px;
}
::-webkit-scrollbar-track:hover {
background: rgba(0, 0, 0, 0.1);
}
::-webkit-scrollbar-thumb:hover {
background: rgba(100, 100, 100, 0.7);
}
/* Remove top padding and margin from first child so that top of rendered text is aligned to top of text editor text */
#rendered-md h1:first-child,
#rendered-md h2:first-child,
#rendered-md h3:first-child,
#rendered-md h4:first-child,
#rendered-md ul:first-child,
#rendered-md ol:first-child,
#rendered-md table:first-child,
#rendered-md blockquote:first-child,
#rendered-md img:first-child,
#rendered-md p:first-child {
margin-top: 0;
padding-top: 0;
}
p, h1, h2, h3, h4, h5, h6, ul, table {
margin-top: .6em;
margin-bottom: .65em;
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.5em;
}
h1 {
font-size: 1.5em;
font-weight: bold;
border-bottom: 1px solid ${style.htmlDividerColor};
padding-bottom: .3em;
}
h2 {
font-size: 1.3em;
font-weight: bold;
padding-bottom: .1em; */
}
h3 {
font-size: 1.1em;
}
h4, h5, h6 {
font-size: 1em;
font-weight: bold;
}
a {
color: ${style.htmlLinkColor};
}
ul, ol {
padding-left: 0;
margin-left: 1.7em;
}
li {
margin-bottom: .4em;
}
li p {
margin-top: 0.2em;
margin-bottom: 0;
}
.resource-icon {
display: inline-block;
position: relative;
top: .5em;
text-decoration: none;
width: 1.2em;
height: 1.4em;
margin-right: 0.4em;
background-color: ${style.htmlLinkColor};
}
/* These icons are obtained from the wonderful ForkAwesome project by copying the src svgs
* into the css classes below.
* svgs are obtained from https://github.com/ForkAwesome/Fork-Awesome/tree/master/src/icons/svg
* instead of the svg width, height property you must use a viewbox here, 0 0 1536 1792 is typically the actual size of the icon
* each line begins with the pre-amble -webkit-mask: url("data:image/svg+xml;utf8,
* and of course finishes with ");
* to precvent artifacts it is also necessary to include -webkit-mask-repeat: no-repeat;
* on the following line
* */
.fa-joplin {
/* Awesome Font file */
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M373.834 128C168.227 128 0 296.223 0 501.834v788.336C0 1495.778 168.227 1664 373.834 1664h788.336c205.608 0 373.83-168.222 373.83-373.83V501.834C1536 296.224 1367.778 128 1162.17 128zm397.222 205.431h417.424a7.132 7.132 0 0 1 7.132 7.133v132.552c0 4.461-3.619 8.073-8.077 8.073h-57.23c-24.168 0-43.768 19.338-44.284 43.374v2.377h-.017v136.191h-.053l-.466 509.375c-5.02 77.667-39.222 149.056-96.324 201.046-60.28 54.834-141.948 85.017-229.962 85.017-12.45 0-25.208-.61-37.907-1.785-92.157-8.682-181.494-48.601-251.662-112.438-71.99-65.517-117.147-150.03-127.164-238-11.226-98.763 23.42-192.783 95.045-257.937 81.99-74.637 198.185-101.768 316.613-75.704 5.574 1.227 9.55 6.282 9.55 11.997v199.52c-.199 2.625-1.481 6.599-8.183 2.896-.663-.365-1.194-.511-1.653-.531-21.987-10.587-45.159-17.57-68.559-19.916-.38-.04-.757-.124-1.138-.163-.537-.048-1.034-.033-1.556-.075-4.13-.354-8.183-.517-12.203-.58-.87-.011-1.771-.127-2.641-.127-.486 0-.951.05-1.437.057-1.464.011-2.886.115-4.33.163-2.76.102-5.497.211-8.182.448-.273.024-.547.07-.835.097-25.509 2.4-47.864 11.104-65.012 25.47-.954.802-1.974 1.53-2.9 2.36a1.34 1.34 0 0 1-.168.146c-23.96 21.8-34.881 53.872-30.726 90.316 4.62 40.737 26.94 81.156 62.841 113.823 35.908 32.67 80.335 52.977 125.113 57.186 35.118 3.36 66.547-3.919 89.899-20.461a97.255 97.255 0 0 0 9.365-7.501c2.925-2.661 5.569-5.5 8.086-8.416.3-.348.672-.673.975-1.024 8.253-9.864 14.222-21.067 17.996-33.148.639-2.034 1.051-4.148 1.564-6.227.381-1.563.81-3.106 1.112-4.693.555-2.784.923-5.632 1.253-8.49.086-.709.183-1.414.237-2.128.492-4.893.693-9.858.55-14.91h.013V521.623c-2.01-22.626-20.78-40.434-43.928-40.434h-57.23a8.071 8.071 0 0 1-8.077-8.073V340.564a7.132 7.132 0 0 1 7.136-7.133z'/></svg>");
}
.fa-file-image {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zm-128-448v320H256v-192l192-192 128 128 384-384zm-832-192c-106 0-192-86-192-192s86-192 192-192 192 86 192 192-86 192-192 192z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-pdf {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zm-514-593c25 20 53 38 84 56 42-5 81-7 117-7 67 0 152 8 177 49 7 10 13 28 2 52-1 1-2 3-3 4v1c-3 18-18 38-71 38-64 0-161-29-245-73-139 15-285 46-392 83-103 176-182 262-242 262-10 0-19-2-28-7l-24-12c-3-1-4-3-6-5-5-5-9-16-6-36 10-46 64-123 188-188 8-5 18-2 23 6 1 1 2 3 2 4 31-51 67-116 107-197 45-90 80-178 104-262-32-109-42-221-24-287 7-25 22-40 42-40h22c15 0 27 5 35 15 12 14 15 36 9 68-1 3-2 6-4 8 1 3 1 5 1 8v30c-1 63-2 123-14 192 35 105 87 190 146 238zm-576 411c30-14 73-57 137-158-75 58-122 124-137 158zm398-920c-10 28-10 76-2 132 3-16 5-31 7-44 2-17 5-31 7-43 1-3 2-5 4-8-1-1-1-3-2-5-1-18-7-29-13-36 0 2-1 3-1 4zm-124 661c88-35 186-63 284-81-10-8-20-15-29-23-49-43-93-103-127-176-19 61-47 126-83 197-15 28-30 56-45 83zm646-16c-5-5-31-24-140-24 49 18 94 28 124 28 9 0 14 0 18-1 0-1-1-2-2-3z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-word {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zM233 768v107h70l164 661h159l128-485c5-15 8-30 10-46 1-8 2-16 2-24h4l3 24c3 14 4 30 9 46l128 485h159l164-661h70V768h-300v107h90l-99 438c-4 16-6 33-7 46l-2 21h-4c0-6-2-14-3-21-3-13-5-30-9-46L825 768H711l-144 545c-4 16-5 33-8 46l-4 21h-4l-2-21c-1-13-3-30-7-46l-99-438h90V768H233z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-powerpoint {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zm-992-234v106h327v-106h-93v-167h137c43 0 82-2 118-15 90-31 146-124 146-233s-54-193-137-228c-38-15-84-19-130-19H416v107h92v555h-92zm353-280H650V882h120c35 0 62 6 83 18 36 21 56 62 56 115 0 56-20 99-62 120-21 10-47 15-78 15z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-excel {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zm-979-234v106h281v-106h-75l103-161c12-19 18-34 21-34h2c1 4 3 7 5 10 4 8 10 14 17 24l107 161h-76v106h291v-106h-68l-192-273 195-282h67V768H828v107h74l-103 159c-12 19-21 34-21 33h-2c-1-4-3-7-5-10-4-7-9-14-17-23L648 875h76V768H434v107h68l189 272-194 283h-68z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-audio {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zM620 850c12 5 20 17 20 30v544c0 13-8 25-20 30-4 1-8 2-12 2-8 0-16-3-23-9l-166-167H288c-18 0-32-14-32-32v-192c0-18 14-32 32-32h131l166-167c10-9 23-12 35-7zm417 689c19 0 37-8 50-24 83-102 129-231 129-363s-46-261-129-363c-22-28-63-32-90-10-28 23-32 63-9 91 65 80 100 178 100 282s-35 202-100 282c-23 28-19 68 9 90 12 10 26 15 40 15zm-211-148c17 0 34-7 47-20 56-60 87-137 87-219s-31-159-87-219c-24-26-65-27-91-3-25 24-27 65-2 91 33 36 52 82 52 131s-19 95-52 131c-25 26-23 67 2 91 13 11 29 17 44 17z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-video {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zM768 768c70 0 128 58 128 128v384c0 70-58 128-128 128H384c-70 0-128-58-128-128V896c0-70 58-128 128-128h384zm492 2c12 5 20 17 20 30v576c0 13-8 25-20 30-4 1-8 2-12 2-8 0-17-3-23-9l-265-266v-90l265-266c6-6 15-9 23-9 4 0 8 1 12 2z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-archive {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M640 384V256H512v128h128zm128 128V384H640v128h128zM640 640V512H512v128h128zm128 128V640H640v128h128zm700-388c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H768v128H640V128H128v1536h1280zM781 943c85 287 107 349 107 349 5 17 8 34 8 52 0 111-108 192-256 192s-256-81-256-192c0-18 3-35 8-52 0 0 21-62 120-396V768h128v128h79c29 0 54 19 62 47zm-141 465c71 0 128-29 128-64s-57-64-128-64-128 29-128 64 57 64 128 64z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-code {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zM480 768c11-14 31-17 45-6l51 38c14 11 17 31 6 45l-182 243 182 243c11 14 8 34-6 45l-51 38c-14 11-34 8-45-6l-226-301c-8-11-8-27 0-38zm802 301c8 11 8 27 0 38l-226 301c-11 14-31 17-45 6l-51-38c-14-11-17-31-6-45l182-243-182-243c-11-14-8-34 6-45l51-38c14-11 34-8 45 6zm-620 461c-18-3-29-20-26-37l138-831c3-18 20-29 37-26l63 10c18 3 29 20 26 37l-138 831c-3 18-20 29-37 26z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file-alt, .fa-file-csv {
/* fork-awesome doesn't have csv so we use the text icon */
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280zM384 800c0-18 14-32 32-32h704c18 0 32 14 32 32v64c0 18-14 32-32 32H416c-18 0-32-14-32-32v-64zm736 224c18 0 32 14 32 32v64c0 18-14 32-32 32H416c-18 0-32-14-32-32v-64c0-18 14-32 32-32h704zm0 256c18 0 32 14 32 32v64c0 18-14 32-32 32H416c-18 0-32-14-32-32v-64c0-18 14-32 32-32h704z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
.fa-file {
-webkit-mask: url("data:image/svg+xml;utf8,<svg viewBox='0 0 1536 1792' xmlns='http://www.w3.org/2000/svg'><path d='M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280z'/></svg>");
-webkit-mask-repeat: no-repeat;
}
blockquote {
border-left: 4px solid ${style.htmlCodeBorderColor};
padding-left: 1.2em;
margin-left: 0;
opacity: .7;
}
table {
text-align: left-align;
border-collapse: collapse;
border: 1px solid ${style.htmlCodeBorderColor};
background-color: ${style.htmlBackgroundColor};
}
td, th {
padding: .5em 1em .5em 1em;
font-size: ${style.htmlFontSize};
color: ${style.htmlColor};
font-family: ${fontFamily};
}
td {
border: 1px solid ${style.htmlCodeBorderColor};
}
th {
border: 1px solid ${style.htmlCodeBorderColor};
border-bottom: 2px solid ${style.htmlCodeBorderColor};
background-color: ${style.htmlTableBackgroundColor};
}
tr:nth-child(even) {
background-color: ${style.htmlTableBackgroundColor};
}
tr:hover {
background-color: ${style.raisedBackgroundColor};
}
hr {
border: none;
border-bottom: 2px solid ${style.htmlDividerColor};
}
img {
max-width: 100%;
height: auto;
}
.inline-code {
border: 1px solid ${style.htmlCodeBorderColor};
background-color: ${style.htmlCodeBackgroundColor};
padding-right: .2em;
padding-left: .2em;
border-radius: .25em;
color: ${style.htmlCodeColor};
font-size: ${style.htmlCodeFontSize};
}
.highlighted-keyword {
background-color: #F3B717;
color: black;
}
.not-loaded-resource img {
width: 1.15em;
height: 1.15em;
background: white;
padding: 2px !important;
border-radius: 2px;
box-shadow: 0 1px 3px #000000aa;
}
a.not-loaded-resource img {
margin-right: .2em;
}
a.not-loaded-resource {
display: flex;
flex-direction: row;
align-items: center;
}
.md-checkbox input[type=checkbox]:checked {
opacity: 0.7;
}
.md-checkbox .checkbox-label-checked {
opacity: 0.5;
}
.exported-note-title {
font-size: 2.2em;
font-weight: bold;
margin-bottom: 1em;
}
.exported-note {
padding: 1em;
}
@media print {
body {
height: auto !important;
}
pre {
white-space: pre-wrap;
}
.code, .inline-code {
border: 1px solid #CBCBCB;
}
#joplin-container-content {
/* The height of the content is set dynamically by JavaScript (in updateBodyHeight) to go
around various issues related to scrolling. However when printing we don't want this
fixed size as that would crop the content. So we set it to auto here. "important" is
needed to override the style set by JavaScript at the element-level. */
height: auto !important;
}
}
`;
return [normalizeCss, css];
};

View File

@ -1,122 +0,0 @@
const Resource = require('lib/models/Resource.js');
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = new Entities().encode;
const utils = {};
utils.getAttr = function(attrs, name, defaultValue = null) {
for (let i = 0; i < attrs.length; i++) {
if (attrs[i][0] === name) return attrs[i].length > 1 ? attrs[i][1] : null;
}
return defaultValue;
};
utils.notDownloadedResource = function() {
return `
<svg width="1700" height="1536" xmlns="http://www.w3.org/2000/svg">
<path d="M1280 1344c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm256 0c0-35-29-64-64-64s-64 29-64 64 29 64 64 64 64-29 64-64zm128-224v320c0 53-43 96-96 96H96c-53 0-96-43-96-96v-320c0-53 43-96 96-96h465l135 136c37 36 85 56 136 56s99-20 136-56l136-136h464c53 0 96 43 96 96zm-325-569c10 24 5 52-14 70l-448 448c-12 13-29 19-45 19s-33-6-45-19L339 621c-19-18-24-46-14-70 10-23 33-39 59-39h256V64c0-35 29-64 64-64h256c35 0 64 29 64 64v448h256c26 0 49 16 59 39z"/>
</svg>
`;
};
utils.notDownloadedImage = function() {
// https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-image-o.svg
// Height changed to 1795
return `
<svg width="1925" height="1792" xmlns="http://www.w3.org/2000/svg">
<path d="M640 576c0 106-86 192-192 192s-192-86-192-192 86-192 192-192 192 86 192 192zm1024 384v448H256v-192l320-320 160 160 512-512zm96-704H160c-17 0-32 15-32 32v1216c0 17 15 32 32 32h1600c17 0 32-15 32-32V288c0-17-15-32-32-32zm160 32v1216c0 88-72 160-160 160H160c-88 0-160-72-160-160V288c0-88 72-160 160-160h1600c88 0 160 72 160 160z"/>
</svg>
`;
};
utils.notDownloadedFile = function() {
// https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-o.svg
return `
<svg width="1925" height="1792" xmlns="http://www.w3.org/2000/svg">
<path d="M1468 380c37 37 68 111 68 164v1152c0 53-43 96-96 96H96c-53 0-96-43-96-96V96C0 43 43 0 96 0h896c53 0 127 31 164 68zm-444-244v376h376c-6-17-15-34-22-41l-313-313c-7-7-24-16-41-22zm384 1528V640H992c-53 0-96-43-96-96V128H128v1536h1280z"/>
</svg>
`;
};
utils.errorImage = function() {
// https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/times-circle.svg
return `
<svg width="1795" height="1795" xmlns="http://www.w3.org/2000/svg">
<path d="M1149 1122c0-17-7-33-19-45L949 896l181-181c12-12 19-28 19-45s-7-34-19-46l-90-90c-12-12-29-19-46-19s-33 7-45 19L768 715 587 534c-12-12-28-19-45-19s-34 7-46 19l-90 90c-12 12-19 29-19 46s7 33 19 45l181 181-181 181c-12 12-19 28-19 45s7 34 19 46l90 90c12 12 29 19 46 19s33-7 45-19l181-181 181 181c12 12 28 19 45 19s34-7 46-19l90-90c12-12 19-29 19-46zm387-226c0 424-344 768-768 768S0 1320 0 896s344-768 768-768 768 344 768 768z"/>
</svg>
`;
};
utils.loaderImage = function() {
// https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/hourglass-half.svg
return `
<svg width="1536" height="1790" xmlns="http://www.w3.org/2000/svg">
<path d="M1408 128c0 370-177 638-373 768 196 130 373 398 373 768h96c18 0 32 14 32 32v64c0 18-14 32-32 32H32c-18 0-32-14-32-32v-64c0-18 14-32 32-32h96c0-370 177-638 373-768-196-130-373-398-373-768H32c-18 0-32-14-32-32V32C0 14 14 0 32 0h1472c18 0 32 14 32 32v64c0 18-14 32-32 32h-96zm-128 0H256c0 146 33 275 85 384h854c52-109 85-238 85-384zm-57 1216c-74-193-207-330-340-384H653c-133 54-266 191-340 384h910z"/>
</svg>
`;
};
utils.resourceStatusImage = function(state) {
if (state === 'notDownloaded') return utils.notDownloadedResource();
return utils.resourceStatusFile(state);
};
utils.resourceStatusFile = function(state) {
if (state === 'notDownloaded') return utils.notDownloadedResource();
if (state === 'downloading') return utils.loaderImage();
if (state === 'encrypted') return utils.loaderImage();
if (state === 'error') return utils.errorImage();
throw new Error(`Unknown state: ${state}`);
};
utils.resourceStatus = function(resourceInfo) {
let resourceStatus = 'ready';
if (resourceInfo) {
const resource = resourceInfo.item;
const localState = resourceInfo.localState;
if (localState.fetch_status === Resource.FETCH_STATUS_IDLE) {
resourceStatus = 'notDownloaded';
} else if (localState.fetch_status === Resource.FETCH_STATUS_STARTED) {
resourceStatus = 'downloading';
} else if (localState.fetch_status === Resource.FETCH_STATUS_DONE) {
if (resource.encryption_blob_encrypted || resource.encryption_applied) {
resourceStatus = 'encrypted';
}
}
} else {
resourceStatus = 'notDownloaded';
}
return resourceStatus;
};
utils.imageReplacement = function(src, resources, resourceBaseUrl) {
if (!Resource.isResourceUrl(src)) return null;
const resourceId = Resource.urlToId(src);
const result = resources[resourceId];
const resource = result ? result.item : null;
const resourceStatus = utils.resourceStatus(result);
if (resourceStatus !== 'ready') {
const icon = utils.resourceStatusImage(resourceStatus);
return `<div class="not-loaded-resource resource-status-${resourceStatus}" data-resource-id="${resourceId}">` + `<img src="data:image/svg+xml;utf8,${htmlentities(icon)}"/>` + '</div>';
}
const mime = resource.mime ? resource.mime.toLowerCase() : '';
if (Resource.isSupportedImageMimeType(mime)) {
let newSrc = `./${Resource.filename(resource)}`;
if (resourceBaseUrl) newSrc = resourceBaseUrl + newSrc;
return {
'data-resource-id': resource.id,
src: newSrc,
};
}
return null;
};
module.exports = utils;

View File

@ -6,11 +6,11 @@ const Note = require('lib/models/Note');
const Setting = require('lib/models/Setting'); const Setting = require('lib/models/Setting');
const Resource = require('lib/models/Resource'); const Resource = require('lib/models/Resource');
const { shim } = require('lib/shim'); const { shim } = require('lib/shim');
const MarkupToHtml = require('lib/renderers/MarkupToHtml.js');
const dataurl = require('dataurl'); const dataurl = require('dataurl');
const { themeStyle } = require('../../theme.js'); const { themeStyle } = require('../../theme.js');
const { dirname } = require('lib/path-utils.js'); const { dirname } = require('lib/path-utils.js');
const { escapeHtml } = require('lib/string-utils.js'); const { escapeHtml } = require('lib/string-utils.js');
const markupLanguageUtils = require('lib/markupLanguageUtils');
class InteropService_Exporter_Html extends InteropService_Exporter_Base { class InteropService_Exporter_Html extends InteropService_Exporter_Base {
@ -27,7 +27,7 @@ class InteropService_Exporter_Html extends InteropService_Exporter_Base {
this.resourceDir_ = this.destDir_ ? `${this.destDir_}/_resources` : null; this.resourceDir_ = this.destDir_ ? `${this.destDir_}/_resources` : null;
await shim.fsDriver().mkdir(this.destDir_); await shim.fsDriver().mkdir(this.destDir_);
this.markupToHtml_ = new MarkupToHtml(); this.markupToHtml_ = markupLanguageUtils.newMarkupToHtml();
this.resources_ = []; this.resources_ = [];
this.style_ = themeStyle(Setting.THEME_LIGHT); this.style_ = themeStyle(Setting.THEME_LIGHT);
} }
@ -103,7 +103,7 @@ class InteropService_Exporter_Html extends InteropService_Exporter_Base {
} }
const bodyMd = await this.processNoteResources_(item); const bodyMd = await this.processNoteResources_(item);
const result = this.markupToHtml_.render(item.markup_language, bodyMd, this.style_, { resources: this.resources_, plainResourceRendering: true }); const result = await this.markupToHtml_.render(item.markup_language, bodyMd, this.style_, { resources: this.resources_, plainResourceRendering: true });
const noteContent = []; const noteContent = [];
if (item.title) noteContent.push(`<div class="exported-note-title">${escapeHtml(item.title)}</div>`); if (item.title) noteContent.push(`<div class="exported-note-title">${escapeHtml(item.title)}</div>`);
if (result.html) noteContent.push(result.html); if (result.html) noteContent.push(result.html);

View File

@ -22,6 +22,7 @@ const ApiResponse = require('lib/services/rest/ApiResponse');
const SearchEngineUtils = require('lib/services/SearchEngineUtils'); const SearchEngineUtils = require('lib/services/SearchEngineUtils');
const { FoldersScreenUtils } = require('lib/folders-screen-utils.js'); const { FoldersScreenUtils } = require('lib/folders-screen-utils.js');
const uri2path = require('file-uri-to-path'); const uri2path = require('file-uri-to-path');
const { MarkupToHtml } = require('joplin-renderer');
class ApiError extends Error { class ApiError extends Error {
constructor(message, httpCode = 400) { constructor(message, httpCode = 400) {
@ -491,7 +492,7 @@ class Api {
} }
output.body = styleTag + minifiedHtml; output.body = styleTag + minifiedHtml;
output.body = htmlUtils.prependBaseUrl(output.body, baseUrl); output.body = htmlUtils.prependBaseUrl(output.body, baseUrl);
output.markup_language = Note.MARKUP_LANGUAGE_HTML; output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_HTML;
} else { } else {
// Convert to Markdown // Convert to Markdown
// Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed // Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed
@ -501,7 +502,7 @@ class Api {
baseUrl: baseUrl, baseUrl: baseUrl,
anchorNames: requestNote.anchor_names ? requestNote.anchor_names : [], anchorNames: requestNote.anchor_names ? requestNote.anchor_names : [],
}); });
output.markup_language = Note.MARKUP_LANGUAGE_MARKDOWN; output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
} }
} }
@ -520,7 +521,7 @@ class Api {
if ('is_todo' in requestNote) output.is_todo = Database.formatValue(Database.TYPE_INT, requestNote.is_todo); if ('is_todo' in requestNote) output.is_todo = Database.formatValue(Database.TYPE_INT, requestNote.is_todo);
if ('markup_language' in requestNote) output.markup_language = Database.formatValue(Database.TYPE_INT, requestNote.markup_language); if ('markup_language' in requestNote) output.markup_language = Database.formatValue(Database.TYPE_INT, requestNote.markup_language);
if (!output.markup_language) output.markup_language = Note.MARKUP_LANGUAGE_MARKDOWN; if (!output.markup_language) output.markup_language = MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN;
return output; return output;
} }
@ -664,7 +665,7 @@ class Api {
replaceImageUrlsByResources_(markupLanguage, md, urls, imageSizes) { replaceImageUrlsByResources_(markupLanguage, md, urls, imageSizes) {
const imageSizesIndexes = {}; const imageSizesIndexes = {};
if (markupLanguage === Note.MARKUP_LANGUAGE_HTML) { if (markupLanguage === MarkupToHtml.MARKUP_LANGUAGE_HTML) {
return htmlUtils.replaceImageUrls(md, imageUrl => { return htmlUtils.replaceImageUrls(md, imageUrl => {
const urlInfo = urls[imageUrl]; const urlInfo = urls[imageUrl];
if (!urlInfo || !urlInfo.resource) return imageUrl; if (!urlInfo || !urlInfo.resource) return imageUrl;

View File

@ -16,11 +16,6 @@ const injectedJs = {
webviewLib: require('lib/rnInjectedJs/webviewLib'), webviewLib: require('lib/rnInjectedJs/webviewLib'),
}; };
const cssToJs = {
'hljs-atom-one-dark-reasonable.css': require('lib/csstojs/hljs-atom-one-dark-reasonable.css.js'),
'hljs-atom-one-light.css': require('lib/csstojs/hljs-atom-one-light.css.js'),
};
function shimInit() { function shimInit() {
shim.Geolocation = GeolocationReact; shim.Geolocation = GeolocationReact;
shim.setInterval = PoorManIntervals.setInterval; shim.setInterval = PoorManIntervals.setInterval;
@ -187,11 +182,6 @@ function shimInit() {
if (!(name in injectedJs)) throw new Error(`Cannot find injectedJs file (add it to "injectedJs" object): ${name}`); if (!(name in injectedJs)) throw new Error(`Cannot find injectedJs file (add it to "injectedJs" object): ${name}`);
return injectedJs[name]; return injectedJs[name];
}; };
shim.loadCssFromJs = function(name) {
if (!(name in cssToJs)) throw new Error(`Cannot find csstojs file (add it to "cssToJs" object): ${name}`);
return cssToJs[name];
};
} }
module.exports = { shimInit }; module.exports = { shimInit };

View File

@ -199,10 +199,6 @@ shim.waitForFrame = () => {
shim.injectedJs = name => ''; shim.injectedJs = name => '';
shim.loadCssFromJs = name => {
throw new Error('Not implemented');
};
let isTestingEnv_ = false; let isTestingEnv_ = false;
shim.isTestingEnv = () => { shim.isTestingEnv = () => {

View File

@ -1466,6 +1466,12 @@
} }
} }
}, },
"app-module-path": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/app-module-path/-/app-module-path-2.2.0.tgz",
"integrity": "sha1-ZBqlXft9am8KgUHEucCqULbCTdU=",
"dev": true
},
"are-we-there-yet": { "are-we-there-yet": {
"version": "1.1.5", "version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
@ -2727,22 +2733,19 @@
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
}, },
"fs-extra": { "fs-extra": {
"version": "1.0.0", "version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": { "requires": {
"graceful-fs": "^4.1.2", "graceful-fs": "^4.2.0",
"jsonfile": "^2.1.0", "jsonfile": "^4.0.0",
"klaw": "^1.0.0" "universalify": "^0.1.0"
}, },
"dependencies": { "dependencies": {
"jsonfile": { "graceful-fs": {
"version": "2.4.0", "version": "4.2.3",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ=="
"requires": {
"graceful-fs": "^4.1.6"
}
} }
} }
}, },
@ -2768,8 +2771,7 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true, "bundled": true
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
@ -2787,13 +2789,11 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
@ -2806,18 +2806,15 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true, "bundled": true
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
@ -2920,8 +2917,7 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true, "bundled": true
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
@ -2931,7 +2927,6 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
@ -2944,20 +2939,17 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true, "bundled": true
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
@ -2974,7 +2966,6 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
@ -3047,8 +3038,7 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true, "bundled": true
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@ -3058,7 +3048,6 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
@ -3134,8 +3123,7 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true, "bundled": true
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
@ -3165,7 +3153,6 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
@ -3183,7 +3170,6 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
@ -3222,13 +3208,11 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true, "bundled": true
"optional": true
} }
} }
}, },
@ -3313,6 +3297,40 @@
"resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
}, },
"handlebars": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"requires": {
"neo-async": "^2.6.0",
"optimist": "^0.6.1",
"source-map": "^0.6.1",
"uglify-js": "^3.1.4"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"optional": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"uglify-js": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.3.tgz",
"integrity": "sha512-7tINm46/3puUA4hCkKYo4Xdts+JDaVC9ZPRcG8Xw9R4nhO/gZgUM3TENq8IF4Vatk8qCig4MzP/c8G4u2BkVQg==",
"optional": true,
"requires": {
"commander": "~2.20.3",
"source-map": "~0.6.1"
}
}
}
},
"has-ansi": { "has-ansi": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
@ -3386,9 +3404,12 @@
} }
}, },
"highlight.js": { "highlight.js": {
"version": "9.15.6", "version": "9.17.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.17.1.tgz",
"integrity": "sha512-zozTAWM1D6sozHo8kqhfYgsac+B+q0PmsjXeyDrYIHHcBN0zTVT66+s2GW1GZv7DbyaROdLXKdabwS/WqPyIdQ==" "integrity": "sha512-TA2/doAur5Ol8+iM3Ov7qy3jYcr/QiJ2eDTdRF4dfbjG7AaaB99J5G+zSl11ljbl6cIcahgPY6SKb3sC3EJ0fw==",
"requires": {
"handlebars": "^4.5.3"
}
}, },
"hoist-non-react-statics": { "hoist-non-react-statics": {
"version": "2.5.0", "version": "2.5.0",
@ -3774,6 +3795,57 @@
"integrity": "sha512-+f/4OLeqY8RAmXnonI1ffeY1DR8kMNJPhv5WMFehchf7U71cjMQVKkOz1n6asz6kfVoAqKNWJz1A/18i18AcXA==", "integrity": "sha512-+f/4OLeqY8RAmXnonI1ffeY1DR8kMNJPhv5WMFehchf7U71cjMQVKkOz1n6asz6kfVoAqKNWJz1A/18i18AcXA==",
"dev": true "dev": true
}, },
"joplin-renderer": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.4.tgz",
"integrity": "sha512-Q7GoEYA6hYtv8ZQgxccn/gSw25V8kQPyWdolK0PJhG7m2BJa0zunyagtaOhMkYuWl8beDYHwTsvsVx2ayKqMcQ==",
"requires": {
"base-64": "^0.1.0",
"font-awesome-filetypes": "^2.1.0",
"fs-extra": "^8.1.0",
"highlight.js": "^9.17.1",
"html-entities": "^1.2.1",
"katex": "^0.11.1",
"markdown-it": "^10.0.0",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^5.2.5",
"markdown-it-deflist": "^2.0.3",
"markdown-it-emoji": "^1.4.0",
"markdown-it-footnote": "^3.0.2",
"markdown-it-ins": "^3.0.0",
"markdown-it-mark": "^3.0.0",
"markdown-it-multimd-table": "^4.0.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1",
"uslug": "^1.0.4"
},
"dependencies": {
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"markdown-it": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
"integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
"requires": {
"argparse": "^1.0.7",
"entities": "~2.0.0",
"linkify-it": "^2.0.0",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
}
},
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
}
}
},
"js-tokens": { "js-tokens": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
@ -4028,37 +4100,19 @@
"integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A=="
}, },
"markdown-it-ins": { "markdown-it-ins": {
"version": "2.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz",
"integrity": "sha1-papqMPHi9x6Ul1Z8/f9A8f3mdIM=" "integrity": "sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q=="
},
"markdown-it-katex": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/markdown-it-katex/-/markdown-it-katex-2.0.3.tgz",
"integrity": "sha1-17hqGuoLnWSW+rTnkZoY/e9YnDk=",
"requires": {
"katex": "^0.6.0"
},
"dependencies": {
"katex": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/katex/-/katex-0.6.0.tgz",
"integrity": "sha1-EkGOCRIcBckgQbazuftrqyE8tvM=",
"requires": {
"match-at": "^0.1.0"
}
}
}
}, },
"markdown-it-mark": { "markdown-it-mark": {
"version": "2.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-3.0.0.tgz",
"integrity": "sha1-RqGqlHEFrtgYiXjgoBYXnkBPQsc=" "integrity": "sha512-HqMWeKfMMOu4zBO0emmxsoMWmbf2cPKZY1wP6FsTbKmicFfp5y4L3KXAsNeO1rM6NTJVOrNlLKMPjWzriBGspw=="
}, },
"markdown-it-multimd-table": { "markdown-it-multimd-table": {
"version": "3.2.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-3.2.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.0.tgz",
"integrity": "sha512-dBtYHVtyAnoWslzYLYDh0d9jX2/qroyMIsJ1BjFdIcLgZjzqBIBGwZ1j3AaaWh+IIfe3KVm5Irqn5Uzadm5kQA==", "integrity": "sha512-kdM3fH+/sRMfHQgD2CM1BcIpLNODUCuoiFr6TwS7mDJBYntVXDJxZbFwGDRflIc9ZzAfsUbr0lnHc6RbYafIsw==",
"requires": { "requires": {
"markdown-it": "^8.4.2" "markdown-it": "^8.4.2"
}, },
@ -4097,11 +4151,6 @@
"resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz", "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.1.0.tgz",
"integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw==" "integrity": "sha512-UhD2Oj6cZV3ycYPoelt4hTkwKIK3zbPP1wjjdpCq7UGtWQOFalDFDv1s2zBYV6aR2gMs/X8kpJcOYsQmUbiXDw=="
}, },
"match-at": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/match-at/-/match-at-0.1.1.tgz",
"integrity": "sha512-h4Yd392z9mST+dzc+yjuybOGFNOZjmXIPKWjxBd1Bb23r4SmDOsk2NYCU2BMUBGbSpZqwVsZYNq26QS3xfaT3Q=="
},
"math-random": { "math-random": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
@ -4239,6 +4288,16 @@
"ua-parser-js": "^0.7.18" "ua-parser-js": "^0.7.18"
} }
}, },
"fs-extra": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
"integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0"
}
},
"invariant": { "invariant": {
"version": "2.2.4", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@ -4247,6 +4306,14 @@
"loose-envify": "^1.0.0" "loose-envify": "^1.0.0"
} }
}, },
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"metro-react-native-babel-preset": { "metro-react-native-babel-preset": {
"version": "0.51.1", "version": "0.51.1",
"resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.51.1.tgz", "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.51.1.tgz",
@ -4731,6 +4798,11 @@
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
}, },
"neo-async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
"integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw=="
},
"nice-try": { "nice-try": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@ -5352,6 +5424,11 @@
} }
} }
}, },
"react-async": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/react-async/-/react-async-10.0.0.tgz",
"integrity": "sha512-Uk7yG49ftaJ1ShMfgTqsZUcEIRxdWHV2ABojw+dzFifCSMeqydCFhzj9x7okACClCzMDgkGqC5/bOtY95yQG1A=="
},
"react-clone-referenced-element": { "react-clone-referenced-element": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/react-clone-referenced-element/-/react-clone-referenced-element-1.1.0.tgz", "resolved": "https://registry.npmjs.org/react-clone-referenced-element/-/react-clone-referenced-element-1.1.0.tgz",
@ -5488,6 +5565,16 @@
"ua-parser-js": "^0.7.18" "ua-parser-js": "^0.7.18"
} }
}, },
"fs-extra": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz",
"integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=",
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^2.1.0",
"klaw": "^1.0.0"
}
},
"invariant": { "invariant": {
"version": "2.2.4", "version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
@ -5496,6 +5583,14 @@
"loose-envify": "^1.0.0" "loose-envify": "^1.0.0"
} }
}, },
"jsonfile": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
"integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"node-fetch": { "node-fetch": {
"version": "2.6.0", "version": "2.6.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",

View File

@ -6,7 +6,8 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start", "start": "node node_modules/react-native/local-cli/cli.js start",
"postinstall": "node ../Tools/copycss.js && node ../Tools/buildReactNativeInjectedJs.js && npx jetify" "postinstall": "node ../Tools/buildReactNativeInjectedJs.js && npx jetify && npm run encodeAssets",
"encodeAssets": "node encodeAssets.js"
}, },
"dependencies": { "dependencies": {
"@react-native-community/slider": "^1.1.3", "@react-native-community/slider": "^1.1.3",
@ -16,31 +17,18 @@
"diacritics": "^1.3.0", "diacritics": "^1.3.0",
"diff-match-patch": "^1.0.4", "diff-match-patch": "^1.0.4",
"events": "^1.1.1", "events": "^1.1.1",
"font-awesome-filetypes": "^2.1.0",
"form-data": "^2.1.4", "form-data": "^2.1.4",
"highlight.js": "^9.15.6",
"html-entities": "^1.2.1", "html-entities": "^1.2.1",
"joplin-renderer": "^1.0.4",
"jsc-android": "241213.1.0", "jsc-android": "241213.1.0",
"katex": "^0.11.1",
"markdown-it": "^8.4.0", "markdown-it": "^8.4.0",
"markdown-it-abbr": "^1.0.4",
"markdown-it-anchor": "^5.2.5",
"markdown-it-deflist": "^2.0.3",
"markdown-it-emoji": "^1.4.0",
"markdown-it-footnote": "^3.0.2",
"markdown-it-ins": "^2.0.0",
"markdown-it-katex": "^2.0.3",
"markdown-it-mark": "^2.0.0",
"markdown-it-multimd-table": "^3.2.0",
"markdown-it-sub": "^1.0.0",
"markdown-it-sup": "^1.0.0",
"markdown-it-toc-done-right": "^4.1.0",
"md5": "^2.2.1", "md5": "^2.2.1",
"moment": "^2.24.0", "moment": "^2.24.0",
"prop-types": "^15.6.0", "prop-types": "^15.6.0",
"punycode": "^2.1.1", "punycode": "^2.1.1",
"query-string": "4.3.4", "query-string": "4.3.4",
"react": "^16.8.3", "react": "^16.8.3",
"react-async": "^10.0.0",
"react-native": "0.59.10", "react-native": "0.59.10",
"react-native-action-button": "^2.6.9", "react-native-action-button": "^2.6.9",
"react-native-camera": "^2.10.2", "react-native-camera": "^2.10.2",
@ -74,7 +62,6 @@
"timers": "^0.1.1", "timers": "^0.1.1",
"url": "^0.11.0", "url": "^0.11.0",
"url-parse": "^1.4.7", "url-parse": "^1.4.7",
"uslug": "^1.0.4",
"uuid": "^3.0.1", "uuid": "^3.0.1",
"valid-url": "^1.0.9", "valid-url": "^1.0.9",
"word-wrap": "^1.2.3", "word-wrap": "^1.2.3",
@ -83,6 +70,8 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.4.5", "@babel/core": "^7.4.5",
"@babel/runtime": "^7.4.5", "@babel/runtime": "^7.4.5",
"app-module-path": "^2.2.0",
"fs-extra": "^8.1.0",
"jetifier": "^1.6.4", "jetifier": "^1.6.4",
"metro-react-native-babel-preset": "^0.54.1", "metro-react-native-babel-preset": "^0.54.1",
"react-test-renderer": "^16.8.3" "react-test-renderer": "^16.8.3"

View File

@ -0,0 +1 @@
module.exports = `LyoKCkF0b20gT25lIERhcmsgV2l0aCBzdXBwb3J0IGZvciBSZWFzb25NTCBieSBHaWRpIE1vcnJpcywgYmFzZWQgb2ZmIHdvcmsgYnkgRGFuaWVsIEdhbWFnZQoKT3JpZ2luYWwgT25lIERhcmsgU3ludGF4IHRoZW1lIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2F0b20vb25lLWRhcmstc3ludGF4CgoqLwouaGxqcyB7CiAgZGlzcGxheTogYmxvY2s7CiAgb3ZlcmZsb3cteDogYXV0bzsKICBwYWRkaW5nOiAwLjVlbTsKICBjb2xvcjogI2FiYjJiZjsKICBiYWNrZ3JvdW5kOiAjMjgyYzM0Owp9Ci5obGpzLWtleXdvcmQsIC5obGpzLW9wZXJhdG9yIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIHsKICBjb2xvcjogI0Y5MjY3MjsKfQouaGxqcy1wYXR0ZXJuLW1hdGNoIC5obGpzLWNvbnN0cnVjdG9yIHsKICBjb2xvcjogIzYxYWVlZTsKfQouaGxqcy1mdW5jdGlvbiB7CiAgY29sb3I6ICM2MWFlZWU7Cn0KLmhsanMtZnVuY3Rpb24gLmhsanMtcGFyYW1zIHsKICBjb2xvcjogI0E2RTIyRTsKfQouaGxqcy1mdW5jdGlvbiAuaGxqcy1wYXJhbXMgLmhsanMtdHlwaW5nIHsKICBjb2xvcjogI0ZEOTcxRjsKfQouaGxqcy1tb2R1bGUtYWNjZXNzIC5obGpzLW1vZHVsZSB7CiAgY29sb3I6ICM3ZTU3YzI7Cn0KLmhsanMtY29uc3RydWN0b3IgewogIGNvbG9yOiAjZTJiOTNkOwp9Ci5obGpzLWNvbnN0cnVjdG9yIC5obGpzLXN0cmluZyB7CiAgY29sb3I6ICM5Q0NDNjU7Cn0KLmhsanMtY29tbWVudCwgLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYjE4ZWIxOwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQouaGxqcy1kb2N0YWcsIC5obGpzLWZvcm11bGEgewogIGNvbG9yOiAjYzY3OGRkOwp9Ci5obGpzLXNlY3Rpb24sIC5obGpzLW5hbWUsIC5obGpzLXNlbGVjdG9yLXRhZywgLmhsanMtZGVsZXRpb24sIC5obGpzLXN1YnN0IHsKICBjb2xvcjogI2UwNmM3NTsKfQouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzU2YjZjMjsKfQouaGxqcy1zdHJpbmcsIC5obGpzLXJlZ2V4cCwgLmhsanMtYWRkaXRpb24sIC5obGpzLWF0dHJpYnV0ZSwgLmhsanMtbWV0YS1zdHJpbmcgewogIGNvbG9yOiAjOThjMzc5Owp9Ci5obGpzLWJ1aWx0X2luLCAuaGxqcy1jbGFzcyAuaGxqcy10aXRsZSB7CiAgY29sb3I6ICNlNmMwN2I7Cn0KLmhsanMtYXR0ciwgLmhsanMtdmFyaWFibGUsIC5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLCAuaGxqcy10eXBlLCAuaGxqcy1zZWxlY3Rvci1jbGFzcywgLmhsanMtc2VsZWN0b3ItYXR0ciwgLmhsanMtc2VsZWN0b3ItcHNldWRvLCAuaGxqcy1udW1iZXIgewogIGNvbG9yOiAjZDE5YTY2Owp9Ci5obGpzLXN5bWJvbCwgLmhsanMtYnVsbGV0LCAuaGxqcy1saW5rLCAuaGxqcy1tZXRhLCAuaGxqcy1zZWxlY3Rvci1pZCwgLmhsanMtdGl0bGUgewogIGNvbG9yOiAjNjFhZWVlOwp9Ci5obGpzLWVtcGhhc2lzIHsKICBmb250LXN0eWxlOiBpdGFsaWM7Cn0KLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQouaGxqcy1saW5rIHsKICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsKfQo=`;

View File

@ -0,0 +1 @@
module.exports = `LyoKCkF0b20gT25lIExpZ2h0IGJ5IERhbmllbCBHYW1hZ2UKT3JpZ2luYWwgT25lIExpZ2h0IFN5bnRheCB0aGVtZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9hdG9tL29uZS1saWdodC1zeW50YXgKCmJhc2U6ICAgICNmYWZhZmEKbW9uby0xOiAgIzM4M2E0Mgptb25vLTI6ICAjNjg2Yjc3Cm1vbm8tMzogICNhMGExYTcKaHVlLTE6ICAgIzAxODRiYgpodWUtMjogICAjNDA3OGYyCmh1ZS0zOiAgICNhNjI2YTQKaHVlLTQ6ICAgIzUwYTE0ZgpodWUtNTogICAjZTQ1NjQ5Cmh1ZS01LTI6ICNjOTEyNDMKaHVlLTY6ICAgIzk4NjgwMQpodWUtNi0yOiAjYzE4NDAxCgoqLwoKLmhsanMgewogIGRpc3BsYXk6IGJsb2NrOwogIG92ZXJmbG93LXg6IGF1dG87CiAgcGFkZGluZzogMC41ZW07CiAgY29sb3I6ICMzODNhNDI7CiAgYmFja2dyb3VuZDogI2ZhZmFmYTsKfQoKLmhsanMtY29tbWVudCwKLmhsanMtcXVvdGUgewogIGNvbG9yOiAjYTBhMWE3OwogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtZG9jdGFnLAouaGxqcy1rZXl3b3JkLAouaGxqcy1mb3JtdWxhIHsKICBjb2xvcjogI2E2MjZhNDsKfQoKLmhsanMtc2VjdGlvbiwKLmhsanMtbmFtZSwKLmhsanMtc2VsZWN0b3ItdGFnLAouaGxqcy1kZWxldGlvbiwKLmhsanMtc3Vic3QgewogIGNvbG9yOiAjZTQ1NjQ5Owp9CgouaGxqcy1saXRlcmFsIHsKICBjb2xvcjogIzAxODRiYjsKfQoKLmhsanMtc3RyaW5nLAouaGxqcy1yZWdleHAsCi5obGpzLWFkZGl0aW9uLAouaGxqcy1hdHRyaWJ1dGUsCi5obGpzLW1ldGEtc3RyaW5nIHsKICBjb2xvcjogIzUwYTE0ZjsKfQoKLmhsanMtYnVpbHRfaW4sCi5obGpzLWNsYXNzIC5obGpzLXRpdGxlIHsKICBjb2xvcjogI2MxODQwMTsKfQoKLmhsanMtYXR0ciwKLmhsanMtdmFyaWFibGUsCi5obGpzLXRlbXBsYXRlLXZhcmlhYmxlLAouaGxqcy10eXBlLAouaGxqcy1zZWxlY3Rvci1jbGFzcywKLmhsanMtc2VsZWN0b3ItYXR0ciwKLmhsanMtc2VsZWN0b3ItcHNldWRvLAouaGxqcy1udW1iZXIgewogIGNvbG9yOiAjOTg2ODAxOwp9CgouaGxqcy1zeW1ib2wsCi5obGpzLWJ1bGxldCwKLmhsanMtbGluaywKLmhsanMtbWV0YSwKLmhsanMtc2VsZWN0b3ItaWQsCi5obGpzLXRpdGxlIHsKICBjb2xvcjogIzQwNzhmMjsKfQoKLmhsanMtZW1waGFzaXMgewogIGZvbnQtc3R5bGU6IGl0YWxpYzsKfQoKLmhsanMtc3Ryb25nIHsKICBmb250LXdlaWdodDogYm9sZDsKfQoKLmhsanMtbGluayB7CiAgdGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7Cn0K`;

View File

@ -0,0 +1,11 @@
module.exports = {
hash: '964177e31d959b03bc63f11216c61e3e', files: {
'highlight.js/atom-one-dark-reasonable.css': { data: require('./highlight.js/atom-one-dark-reasonable.css.base64.js'), mime: 'text/css', encoding: 'base64' },
'highlight.js/atom-one-light.css': { data: require('./highlight.js/atom-one-light.css.base64.js'), mime: 'text/css', encoding: 'base64' },
'katex/fonts/KaTeX_Main-Regular.woff2': { data: require('./katex/fonts/KaTeX_Main-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
'katex/fonts/KaTeX_Math-Italic.woff2': { data: require('./katex/fonts/KaTeX_Math-Italic.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
'katex/fonts/KaTeX_Size1-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size1-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
'katex/fonts/KaTeX_Size2-Regular.woff2': { data: require('./katex/fonts/KaTeX_Size2-Regular.woff2.base64.js'), mime: 'application/octet-stream', encoding: 'base64' },
'katex/katex.css': { data: require('./katex/katex.css.base64.js'), mime: 'text/css', encoding: 'base64' },
},
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -80,6 +80,8 @@ const DecryptionWorker = require('lib/services/DecryptionWorker');
const EncryptionService = require('lib/services/EncryptionService'); const EncryptionService = require('lib/services/EncryptionService');
const MigrationService = require('lib/services/MigrationService'); const MigrationService = require('lib/services/MigrationService');
import PluginAssetsLoader from './PluginAssetsLoader';
let storeDispatch = function() {}; let storeDispatch = function() {};
const logReducerAction = function(action) { const logReducerAction = function(action) {
@ -461,6 +463,9 @@ async function initialize(dispatch) {
Setting.setValue('welcome.enabled', false); Setting.setValue('welcome.enabled', false);
} }
PluginAssetsLoader.instance().setLogger(mainLogger);
await PluginAssetsLoader.instance().importAssets();
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
BaseItem.revisionService_ = RevisionService.instance(); BaseItem.revisionService_ = RevisionService.instance();

View File

@ -1,30 +0,0 @@
const fs = require('fs-extra');
const cwd = process.cwd();
const outputDir = `${cwd}/lib/csstojs`;
async function createJsFromCss(name, filePath) {
let css = await fs.readFile(filePath, 'utf-8');
// eslint-disable-next-line no-useless-escape
css = css.replace(/\`/g, '\\`');
const js = `module.exports = \`${css}\`;`;
const outputPath = `${outputDir}/${name}.css.js`;
await fs.writeFile(outputPath, js);
}
async function main(argv) {
await fs.mkdirp(outputDir);
await createJsFromCss('katex', `${cwd}/node_modules/katex/dist/katex.min.css`);
await createJsFromCss('hljs-atom-one-light', `${cwd}/node_modules/highlight.js/styles/atom-one-light.css`);
await createJsFromCss('hljs-atom-one-dark-reasonable', `${cwd}/node_modules/highlight.js/styles/atom-one-dark-reasonable.css`);
if (argv.indexOf('--copy-fonts') >= 0) {
await fs.copy(`${cwd}/node_modules/katex/dist/fonts`, `${cwd}/gui/note-viewer/fonts`);
}
}
main(process.argv).catch((error) => {
console.error(error);
process.exit(1);
});

View File

@ -2,11 +2,15 @@
"folders": [ "folders": [
{ {
"name": "Joplin", "name": "Joplin",
"path": ".", "path": "."
}, {
"name": "Joplin Nextcloud App",
"path": "D:/Web/www/nextcloud/apps/joplin",
}, },
{
"name": "Joplin Nextcloud App",
"path": "D:/Web/www/nextcloud/apps/joplin"
},
{
"path": "D:/Docs/PROGS/Node/joplin-renderer"
}
], ],
"settings": { "settings": {
"files.exclude": { "files.exclude": {