diff --git a/.eslintignore b/.eslintignore index 7b8331990..e5d7d9409 100644 --- a/.eslintignore +++ b/.eslintignore @@ -47,6 +47,7 @@ Server/bin/ Server/node_modules/ ElectronClient/app/packageInfo.js ReactNativeClient/pluginAssets/ +ReactNativeClient/lib/joplin-renderer/vendor/fountain.min.js # Ignore files generated from TypeScript files ElectronClient/app/gui/ShareNoteDialog.js diff --git a/CliClient/package-lock.json b/CliClient/package-lock.json index 61b99a4d9..ee85920be 100644 --- a/CliClient/package-lock.json +++ b/CliClient/package-lock.json @@ -806,11 +806,6 @@ "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": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/for-each-property/-/for-each-property-0.0.4.tgz", @@ -1538,73 +1533,6 @@ "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "dev": true }, - "joplin-renderer": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.8.tgz", - "integrity": "sha512-Q4SSYXl9ErcnUDTz7N4FjWcOOgfPEf5yyNRjU2J1fuxZ/1VbYt6MnfBB7OeiRW+XF+4Arhihk+/XVK++of4hEA==", - "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", - "json-stringify-safe": "^5.0.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.1", - "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.18.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.0.tgz", - "integrity": "sha512-A97kI1KAUzKoAiEoaGcf2O9YPS8nbDTCRFokaaeBhnqjQTvbAuAJrQMm21zw8s8xzaMtCQBtgbyGXLGxdxQyqQ==" - }, - "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": { "version": "4.0.19", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", @@ -1708,21 +1636,6 @@ "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz", "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": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -1842,64 +1755,6 @@ "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.1", - "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.1.tgz", - "integrity": "sha512-ZgRV8LlGz6JXTZ5zd82yCL8IVG5MRastMWxxrc6hQC8aC8kq/7zpp+ksBqVqcdTmTdabnkuSo/7h3SyKM31YCA==", - "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": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", @@ -3234,11 +3089,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "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": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz", @@ -3278,14 +3128,6 @@ "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": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/CliClient/package.json b/CliClient/package.json index 281141a74..f3b8d84d4 100644 --- a/CliClient/package.json +++ b/CliClient/package.json @@ -44,7 +44,6 @@ "html-minifier": "^3.5.15", "image-data-uri": "^2.0.0", "image-type": "^3.0.0", - "joplin-renderer": "^1.0.8", "joplin-turndown": "^4.0.19", "joplin-turndown-plugin-gfm": "^1.0.12", "jssha": "^2.3.0", diff --git a/ElectronClient/app/app.js b/ElectronClient/app/app.js index 7c14ebbd8..16698fcbe 100644 --- a/ElectronClient/app/app.js +++ b/ElectronClient/app/app.js @@ -6,7 +6,7 @@ const Setting = require('lib/models/Setting.js'); const { shim } = require('lib/shim.js'); const MasterKey = require('lib/models/MasterKey'); const Note = require('lib/models/Note'); -const { MarkupToHtml } = require('joplin-renderer'); +const { MarkupToHtml } = require('lib/joplin-renderer'); const { _, setLocale } = require('lib/locale.js'); const { Logger } = require('lib/logger.js'); const fs = require('fs-extra'); diff --git a/ElectronClient/app/gui/NoteRevisionViewer.jsx b/ElectronClient/app/gui/NoteRevisionViewer.jsx index 7346a99f5..245e87033 100644 --- a/ElectronClient/app/gui/NoteRevisionViewer.jsx +++ b/ElectronClient/app/gui/NoteRevisionViewer.jsx @@ -12,7 +12,7 @@ const urlUtils = require('lib/urlUtils'); const Setting = require('lib/models/Setting'); const RevisionService = require('lib/services/RevisionService'); const shared = require('lib/components/shared/note-screen-shared.js'); -const { MarkupToHtml, assetsToHeaders } = require('joplin-renderer'); +const { MarkupToHtml, assetsToHeaders } = require('lib/joplin-renderer'); const { time } = require('lib/time-utils.js'); const ReactTooltip = require('react-tooltip'); const { urlDecode, substrWithEllipsis } = require('lib/string-utils'); diff --git a/ElectronClient/app/gui/NoteText.jsx b/ElectronClient/app/gui/NoteText.jsx index 8258139ae..33fbe53a6 100644 --- a/ElectronClient/app/gui/NoteText.jsx +++ b/ElectronClient/app/gui/NoteText.jsx @@ -16,7 +16,7 @@ const TagList = require('./TagList.min.js'); const { connect } = require('react-redux'); const { _ } = require('lib/locale.js'); const { reg } = require('lib/registry.js'); -const { MarkupToHtml, assetsToHeaders } = require('joplin-renderer'); +const { MarkupToHtml, assetsToHeaders } = require('lib/joplin-renderer'); const shared = require('lib/components/shared/note-screen-shared.js'); const { bridge } = require('electron').remote.require('./bridge'); const { themeStyle } = require('../theme.js'); diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json index 951986334..cb94852c7 100644 --- a/ElectronClient/app/package-lock.json +++ b/ElectronClient/app/package-lock.json @@ -3353,11 +3353,6 @@ } } }, - "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-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -3703,11 +3698,6 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, - "highlight.js": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.0.tgz", - "integrity": "sha512-A97kI1KAUzKoAiEoaGcf2O9YPS8nbDTCRFokaaeBhnqjQTvbAuAJrQMm21zw8s8xzaMtCQBtgbyGXLGxdxQyqQ==" - }, "hoist-non-react-statics": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz", @@ -4100,68 +4090,6 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "joplin-renderer": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/joplin-renderer/-/joplin-renderer-1.0.8.tgz", - "integrity": "sha512-Q4SSYXl9ErcnUDTz7N4FjWcOOgfPEf5yyNRjU2J1fuxZ/1VbYt6MnfBB7OeiRW+XF+4Arhihk+/XVK++of4hEA==", - "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", - "json-stringify-safe": "^5.0.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.1", - "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": { "version": "4.0.19", "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.19.tgz", @@ -4293,21 +4221,6 @@ "resolved": "https://registry.npmjs.org/jssha/-/jssha-2.3.1.tgz", "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==" - } - } - }, "keyv": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", @@ -4502,78 +4415,6 @@ "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.1", - "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.1.tgz", - "integrity": "sha512-ZgRV8LlGz6JXTZ5zd82yCL8IVG5MRastMWxxrc6hQC8aC8kq/7zpp+ksBqVqcdTmTdabnkuSo/7h3SyKM31YCA==", - "requires": { - "markdown-it": "^8.4.2" - }, - "dependencies": { - "markdown-it": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", - "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", - "requires": { - "argparse": "^1.0.7", - "entities": "~1.1.1", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - } - } - } - }, - "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==" - }, "matcher": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-2.1.0.tgz", @@ -6808,11 +6649,6 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "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==" - }, "unused-filename": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-1.0.0.tgz", @@ -6916,14 +6752,6 @@ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", "dev": true }, - "uslug": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz", - "integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=", - "requires": { - "unorm": ">= 1.0.0" - } - }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 41eaf0359..3c307c6c7 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -104,7 +104,6 @@ "html-entities": "^1.2.1", "html-minifier": "^4.0.0", "image-type": "^3.0.0", - "joplin-renderer": "^1.0.8", "joplin-turndown": "^4.0.19", "joplin-turndown-plugin-gfm": "^1.0.12", "jssha": "^2.3.1", diff --git a/ElectronClient/run.bat b/ElectronClient/run.bat index 4640da608..c7ad48273 100644 --- a/ElectronClient/run.bat +++ b/ElectronClient/run.bat @@ -5,7 +5,5 @@ set script_dir=%mypath:~0,-1% call build.bat 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 call .\node_modules\.bin\electron.cmd . --env dev --log-level debug --no-welcome --open-dev-tools "$@" diff --git a/ReactNativeClient/encodeAssets.js b/ReactNativeClient/encodeAssets.js index 86d986b0c..b0781790a 100644 --- a/ReactNativeClient/encodeAssets.js +++ b/ReactNativeClient/encodeAssets.js @@ -48,7 +48,7 @@ async function main() { await fs.mkdirp(outputDir); const encodedFiles = []; - const sourceAssetDir = `${rootDir}/node_modules/joplin-renderer/assets`; + const sourceAssetDir = `${rootDir}/lib/joplin-renderer/assets`; const files = walk(sourceAssetDir); for (const file of files) { diff --git a/ReactNativeClient/lib/components/note-body-viewer.js b/ReactNativeClient/lib/components/note-body-viewer.js index 321059e8b..077904bca 100644 --- a/ReactNativeClient/lib/components/note-body-viewer.js +++ b/ReactNativeClient/lib/components/note-body-viewer.js @@ -8,7 +8,7 @@ const { themeStyle } = require('lib/components/global-style.js'); const Setting = require('lib/models/Setting.js'); const { reg } = require('lib/registry.js'); const { shim } = require('lib/shim'); -const { assetsToHeaders } = require('joplin-renderer'); +const { assetsToHeaders } = require('lib/joplin-renderer'); const shared = require('lib/components/shared/note-screen-shared.js'); const markupLanguageUtils = require('lib/markupLanguageUtils'); diff --git a/ReactNativeClient/lib/import-enex.js b/ReactNativeClient/lib/import-enex.js index a25155fc1..0f9aa54b0 100644 --- a/ReactNativeClient/lib/import-enex.js +++ b/ReactNativeClient/lib/import-enex.js @@ -4,7 +4,7 @@ const BaseModel = require('lib/BaseModel.js'); const Note = require('lib/models/Note.js'); const Tag = require('lib/models/Tag.js'); const Resource = require('lib/models/Resource.js'); -const { MarkupToHtml } = require('joplin-renderer'); +const { MarkupToHtml } = require('lib/joplin-renderer'); const { enexXmlToMd } = require('./import-enex-md-gen.js'); const { enexXmlToHtml } = require('./import-enex-html-gen.js'); const { time } = require('lib/time-utils.js'); diff --git a/ReactNativeClient/lib/joplin-renderer/.gitignore b/ReactNativeClient/lib/joplin-renderer/.gitignore new file mode 100644 index 000000000..95a012309 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +.vscode/ +copyLib.bat diff --git a/ReactNativeClient/lib/joplin-renderer/HtmlToHtml.js b/ReactNativeClient/lib/joplin-renderer/HtmlToHtml.js new file mode 100644 index 000000000..0a929c4ec --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/HtmlToHtml.js @@ -0,0 +1,42 @@ +const htmlUtils = require('./htmlUtils'); +const utils = require('./utils'); +const noteStyle = require('./noteStyle'); + +class HtmlToHtml { + constructor(options) { + if (!options) options = {}; + this.resourceBaseUrl_ = 'resourceBaseUrl' in options ? options.resourceBaseUrl : null; + this.ResourceModel_ = options.ResourceModel; + } + + render(markup, theme, options) { + const html = htmlUtils.processImageTags(markup, data => { + if (!data.src) return null; + + const r = utils.imageReplacement(this.ResourceModel_, 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 = ``; + + return { + html: styleHtml + html, + pluginAssets: [], + }; + } +} + +module.exports = HtmlToHtml; diff --git a/ReactNativeClient/lib/joplin-renderer/MarkupToHtml.js b/ReactNativeClient/lib/joplin-renderer/MarkupToHtml.js new file mode 100644 index 000000000..9b1f68c0c --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/MarkupToHtml.js @@ -0,0 +1,44 @@ +const MdToHtml = require('./MdToHtml'); +const HtmlToHtml = require('./HtmlToHtml'); + +class MarkupToHtml { + constructor(options) { + this.options_ = Object.assign({}, { + ResourceModel: { + isResourceUrl: () => false, + }, + }, options); + + this.renderers_ = {}; + } + + renderer(markupLanguage) { + if (this.renderers_[markupLanguage]) return this.renderers_[markupLanguage]; + + let RendererClass = null; + + if (markupLanguage === MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN) { + RendererClass = MdToHtml; + } else if (markupLanguage === MarkupToHtml.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); + } +} + +MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN = 1; +MarkupToHtml.MARKUP_LANGUAGE_HTML = 2; + +module.exports = MarkupToHtml; diff --git a/ReactNativeClient/lib/joplin-renderer/MdToHtml.js b/ReactNativeClient/lib/joplin-renderer/MdToHtml.js new file mode 100644 index 000000000..964b2771d --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/MdToHtml.js @@ -0,0 +1,243 @@ +const MarkdownIt = require('markdown-it'); +const md5 = require('md5'); +const noteStyle = require('./noteStyle'); +const { fileExtension } = require('./pathUtils'); +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: { multiline: true, rowspan: true, headerless: true } }, + toc: { module: require('markdown-it-toc-done-right'), options: { listType: 'ul', slugify: uslugify } }, +}; +const defaultNoteStyle = require('./defaultNoteStyle'); + +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_ = {}; + this.ResourceModel_ = options.ResourceModel; + this.pluginOptions_ = options.pluginOptions ? options.pluginOptions : {}; + } + + pluginOptions(name) { + let o = this.pluginOptions_[name] ? this.pluginOptions_[name] : {}; + o = Object.assign({ + enabled: true, + }, o); + return o; + } + + pluginEnabled(name) { + return this.pluginOptions(name).enabled; + } + + processPluginAssets(pluginAssets) { + const files = []; + const cssStrings = []; + for (const pluginName in pluginAssets) { + for (const asset of pluginAssets[pluginName]) { + let mime = asset.mime; + + if (!mime && asset.inline) throw new Error('Mime type is required for inline assets'); + + if (!mime) { + const ext = fileExtension(asset.name).toLowerCase(); + // For now it's only useful to support CSS and JS because that's what needs to be added + // by the caller with `); + } + } + + return headers.join('\n'); +} + +module.exports = assetsToHeaders; diff --git a/ReactNativeClient/lib/joplin-renderer/defaultNoteStyle.js b/ReactNativeClient/lib/joplin-renderer/defaultNoteStyle.js new file mode 100644 index 000000000..bfb5b48de --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/defaultNoteStyle.js @@ -0,0 +1,19 @@ +module.exports = { + htmlFontSize: '15px', + htmlColor: '#222222', + htmlLineHeight: '1.6em', + htmlBackgroundColor: 'white', + paddingBottom: 3, + colorBright: '#000000', // For important text + htmlCodeBorderColor: 'rgb(220, 220, 220)', + htmlCodeBackgroundColor: 'rgb(243, 243, 243)', + htmlDividerColor: 'rgb(230,230,230)', + htmlLinkColor: 'rgb(80,130,190)', + htmlTableBackgroundColor: 'rgb(247, 247, 247)', + raisedBackgroundColor: '#e5e5e5', + htmlCodeColor: 'rgb(0,0,0)', + htmlCodeFontSize: '.9em', + + editorTheme: 'chrome', + codeThemeCss: 'atom-one-light.css', +}; diff --git a/ReactNativeClient/lib/joplin-renderer/htmlUtils.js b/ReactNativeClient/lib/joplin-renderer/htmlUtils.js new file mode 100644 index 000000000..2b775f819 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/htmlUtils.js @@ -0,0 +1,50 @@ +const Entities = require('html-entities').AllHtmlEntities; +const htmlentities = new Entities().encode; + +// [\s\S] instead of . for multiline matching +// https://stackoverflow.com/a/16119722/561309 +const imageRegex = //gi; + +class HtmlUtils { + + attributesHtml(attr) { + const output = []; + + for (const n in attr) { + if (!attr.hasOwnProperty(n)) continue; + output.push(`${n}="${htmlentities(attr[n])}"`); + } + + return output.join(' '); + } + + processImageTags(html, callback) { + if (!html) return ''; + + return html.replace(imageRegex, (v, before, src, after) => { + const action = callback({ src: src }); + + if (!action) return ``; + + if (action.type === 'replaceElement') { + return action.html; + } + + if (action.type === 'replaceSource') { + return ``; + } + + if (action.type === 'setAttributes') { + const attrHtml = this.attributesHtml(action.attrs); + return ``; + } + + throw new Error(`Invalid action: ${action.type}`); + }); + } + +} + +const htmlUtils = new HtmlUtils(); + +module.exports = htmlUtils; diff --git a/ReactNativeClient/lib/joplin-renderer/index.js b/ReactNativeClient/lib/joplin-renderer/index.js new file mode 100644 index 000000000..036a2a5b9 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/index.js @@ -0,0 +1,7 @@ +module.exports = { + MarkupToHtml: require('./MarkupToHtml'), + MdToHtml: require('./MdToHtml'), + HtmlToHtml: require('./HtmlToHtml'), + setupLinkify: require('./MdToHtml/setupLinkify'), + assetsToHeaders: require('./assetsToHeaders'), +}; diff --git a/ReactNativeClient/lib/joplin-renderer/noteStyle.js b/ReactNativeClient/lib/joplin-renderer/noteStyle.js new file mode 100644 index 000000000..64d4d5764 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/noteStyle.js @@ -0,0 +1,291 @@ +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,"); + } + .fa-file-image { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-pdf { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-word { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-powerpoint { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-excel { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-audio { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-video { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-archive { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file-code { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -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,"); + -webkit-mask-repeat: no-repeat; + } + .fa-file { + -webkit-mask: url("data:image/svg+xml;utf8,"); + -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]; +}; diff --git a/ReactNativeClient/lib/joplin-renderer/package-lock.json b/ReactNativeClient/lib/joplin-renderer/package-lock.json new file mode 100644 index 000000000..72776ab97 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/package-lock.json @@ -0,0 +1,394 @@ +{ + "name": "joplin-renderer", + "version": "1.0.8", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "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==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==" + }, + "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==" + }, + "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" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.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==" + }, + "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" + } + }, + "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" + } + }, + "html-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", + "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "jasmine": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.5.0.tgz", + "integrity": "sha512-DYypSryORqzsGoMazemIHUfMkXM7I7easFaxAvNM3Mr6Xz3Fy36TupTrAOxZWN8MVKEU5xECv22J4tUQf3uBzQ==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "jasmine-core": "~3.5.0" + } + }, + "jasmine-core": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.5.0.tgz", + "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "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" + } + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "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" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/markdown-it-multimd-table/-/markdown-it-multimd-table-4.0.1.tgz", + "integrity": "sha512-ZgRV8LlGz6JXTZ5zd82yCL8IVG5MRastMWxxrc6hQC8aC8kq/7zpp+ksBqVqcdTmTdabnkuSo/7h3SyKM31YCA==", + "requires": { + "markdown-it": "^8.4.2" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "markdown-it": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", + "integrity": "sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + } + } + }, + "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": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", + "requires": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", + "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "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" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "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==" + }, + "uglify-js": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.7.2.tgz", + "integrity": "sha512-uhRwZcANNWVLrxLfNFEdltoPNhECUR3lc+UdJoG9CBpMcSnKyWA94tc3eAujB1GcMY5Uwq8ZMp4qWpxWYDQmaA==", + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, + "uslug": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/uslug/-/uslug-1.0.4.tgz", + "integrity": "sha1-uaIvCRTgqGFAYz2swwLl9PpFBnc=", + "requires": { + "unorm": ">= 1.0.0" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/ReactNativeClient/lib/joplin-renderer/package.json b/ReactNativeClient/lib/joplin-renderer/package.json new file mode 100644 index 000000000..9835a9ccd --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/package.json @@ -0,0 +1,39 @@ +{ + "name": "joplin-renderer", + "version": "1.0.8", + "description": "The Joplin note renderer, used the mobile and desktop application", + "repository": "https://github.com/laurent22/joplin/tree/master/ReactNativeClient/lib/joplin-renderer", + "main": "index.js", + "scripts": { + "test": "jasmine --config=tests/support/jasmine.json", + "buildAssets": "node Tools/buildAssets.js" + }, + "author": "", + "license": "MIT", + "devDependencies": { + "jasmine": "^3.5.0" + }, + "dependencies": { + "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", + "json-stringify-safe": "^5.0.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.1", + "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" + } +} diff --git a/ReactNativeClient/lib/joplin-renderer/pathUtils.js b/ReactNativeClient/lib/joplin-renderer/pathUtils.js new file mode 100644 index 000000000..ed085e296 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/pathUtils.js @@ -0,0 +1,32 @@ +function dirname(path) { + if (!path) throw new Error('Path is empty'); + let s = path.split(/\/|\\/); + s.pop(); + return s.join('/'); +} + +function basename(path) { + if (!path) throw new Error('Path is empty'); + let s = path.split(/\/|\\/); + return s[s.length - 1]; +} + +function filename(path, includeDir = false) { + if (!path) throw new Error('Path is empty'); + let output = includeDir ? path : basename(path); + if (output.indexOf('.') < 0) return output; + + output = output.split('.'); + output.pop(); + return output.join('.'); +} + +function fileExtension(path) { + if (!path) throw new Error('Path is empty'); + + let output = path.split('.'); + if (output.length <= 1) return ''; + return output[output.length - 1]; +} + +module.exports = { basename, dirname, filename, fileExtension }; diff --git a/ReactNativeClient/lib/joplin-renderer/publish.sh b/ReactNativeClient/lib/joplin-renderer/publish.sh new file mode 100644 index 000000000..fc7e8dd30 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/publish.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" +npm run buildAssets +npm version patch +npm publish + +NEW_VERSION=$(cat package.json | jq -r .version) +git add -A +git commit -m "v$NEW_VERSION" +git tag "v$NEW_VERSION" +git push && git push --tags \ No newline at end of file diff --git a/ReactNativeClient/lib/joplin-renderer/stringUtils.js b/ReactNativeClient/lib/joplin-renderer/stringUtils.js new file mode 100644 index 000000000..1ca72f030 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/stringUtils.js @@ -0,0 +1,74 @@ +function pregQuote(str, delimiter = '') { + return (`${str}`).replace(new RegExp(`[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\${delimiter || ''}-]`, 'g'), '\\$&'); +} + +function replaceRegexDiacritics(regexString) { + if (!regexString) return ''; + + const diacriticReplacements = { + a: '[aàáâãäåāą]', + A: '[AÀÁÂÃÄÅĀĄ]', + c: '[cçćč]', + C: '[CÇĆČ]', + d: '[dđď]', + D: '[DĐĎ]', + e: '[eèéêëěēę]', + E: '[EÈÉÊËĚĒĘ]', + i: '[iìíîïī]', + I: '[IÌÍÎÏĪ]', + l: '[lł]', + L: '[LŁ]', + n: '[nñňń]', + N: '[NÑŇŃ]', + o: '[oòóôõöøō]', + O: '[OÒÓÔÕÖØŌ]', + r: '[rř]', + R: '[RŘ]', + s: '[sšś]', + S: '[SŠŚ]', + t: '[tť]', + T: '[TŤ]', + u: '[uùúûüůū]', + U: '[UÙÚÛÜŮŪ]', + y: '[yÿý]', + Y: '[YŸÝ]', + z: '[zžżź]', + Z: '[ZŽŻŹ]', + }; + + let output = ''; + for (let i = 0; i < regexString.length; i++) { + let c = regexString[i]; + const r = diacriticReplacements[c]; + if (r) { + output += r; + } else { + output += c; + } + } + + return output; +} + +// keywords can either be a list of strings, or a list of objects with the format: +// { value: 'actualkeyword', type: 'regex/string' } +// The function surrounds the keywords wherever they are, even within other words. +function surroundKeywords(keywords, text, prefix, suffix) { + if (!keywords.length) return text; + + let regexString = keywords + .map(k => { + if (k.type === 'regex') { + return replaceRegexDiacritics(k.valueRegex); + } else { + const value = typeof k === 'string' ? k : k.value; + return replaceRegexDiacritics(pregQuote(value)); + } + }) + .join('|'); + regexString = `(${regexString})`; + const re = new RegExp(regexString, 'gi'); + return text.replace(re, `${prefix}$1${suffix}`); +} + +module.exports = { surroundKeywords }; diff --git a/ReactNativeClient/lib/joplin-renderer/tests/MdToHtmlTest.js b/ReactNativeClient/lib/joplin-renderer/tests/MdToHtmlTest.js new file mode 100644 index 000000000..a1457c35d --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/tests/MdToHtmlTest.js @@ -0,0 +1,24 @@ +const { asyncTest } = require('./test-utils'); +const MdToHtml = require('../MdToHtml'); + +describe('MdToHtml', function() { + + beforeEach(async (done) => { + done(); + }); + + it('should convert Markdown to HTML', asyncTest(async () => { + const mdToHtml = new MdToHtml({ + ResourceModel: null, + }); + + const md = 'Testing: **Testing**'; + + const html = mdToHtml.render(md); + + console.info(html); + + // ![test.jpg](:/b08c25f72bea437ebef5f6470944c3b9) + })); + +}); diff --git a/ReactNativeClient/lib/joplin-renderer/tests/support/jasmine.json b/ReactNativeClient/lib/joplin-renderer/tests/support/jasmine.json new file mode 100644 index 000000000..37c83f757 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/tests/support/jasmine.json @@ -0,0 +1,9 @@ +{ + "spec_dir": "tests", + "spec_files": [ + "*.js", + "!test-utils.js" + ], + "stopSpecOnExpectationFailure": true, + "random": true +} diff --git a/ReactNativeClient/lib/joplin-renderer/tests/test-utils.js b/ReactNativeClient/lib/joplin-renderer/tests/test-utils.js new file mode 100644 index 000000000..10daba779 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/tests/test-utils.js @@ -0,0 +1,16 @@ +// Wrap an async test in a try/catch block so that done() is always called +// and display a proper error message instead of "unhandled promise error" +function asyncTest(callback) { + return async function(done) { + try { + await callback(); + } catch (error) { + console.error(error); + expect('good').toBe('not good', 'Test has thrown an exception - see above error'); + } finally { + done(); + } + }; +} + +module.exports = { asyncTest }; diff --git a/ReactNativeClient/lib/joplin-renderer/urlUtils.js b/ReactNativeClient/lib/joplin-renderer/urlUtils.js new file mode 100644 index 000000000..37118d8d9 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/urlUtils.js @@ -0,0 +1,32 @@ +const urlUtils = {}; + +const resourceRegex = /^(joplin:\/\/|:\/)([0-9a-zA-Z]{32})(|#[^\s]*)(|\s".*?")$/; + +urlUtils.urlDecode = function(string) { + return decodeURIComponent((`${string}`).replace(/\+/g, '%20')); +}; + +urlUtils.isResourceUrl = function(url) { + return !!url.match(resourceRegex); +}; + +urlUtils.parseResourceUrl = function(url) { + if (!urlUtils.isResourceUrl(url)) return null; + + const match = url.match(resourceRegex); + + const itemId = match[2]; + let hash = match[3].trim(); + + // In general we want the hash to be decoded so that non-alphabetical languages + // appear as-is without being encoded with %. + // Fixes https://github.com/laurent22/joplin/issues/1870 + if (hash) hash = urlUtils.urlDecode(hash.substr(1)); // Remove the first # + + return { + itemId: itemId, + hash: hash, + }; +}; + +module.exports = urlUtils; diff --git a/ReactNativeClient/lib/joplin-renderer/utils.js b/ReactNativeClient/lib/joplin-renderer/utils.js new file mode 100644 index 000000000..69eba9ac2 --- /dev/null +++ b/ReactNativeClient/lib/joplin-renderer/utils.js @@ -0,0 +1,133 @@ +const Entities = require('html-entities').AllHtmlEntities; +const htmlentities = new Entities().encode; + +// Imported from models/Resource.js +const FetchStatuses = { + FETCH_STATUS_IDLE: 0, + FETCH_STATUS_STARTED: 1, + FETCH_STATUS_DONE: 2, + FETCH_STATUS_ERROR: 3, +}; + +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 ` + + `; +}; + +utils.notDownloadedImage = function() { + // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-image-o.svg + // Height changed to 1795 + return ` + + `; +}; + +utils.notDownloadedFile = function() { + // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/file-o.svg + return ` + + `; +}; + +utils.errorImage = function() { + // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/times-circle.svg + return ` + + `; +}; + +utils.loaderImage = function() { + // https://github.com/ForkAwesome/Fork-Awesome/blob/master/src/icons/svg/hourglass-half.svg + return ` + + `; +}; + +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(ResourceModel, resourceInfo) { + if (!ResourceModel) return 'ready'; + + let resourceStatus = 'ready'; + + if (resourceInfo) { + const resource = resourceInfo.item; + const localState = resourceInfo.localState; + + if (localState.fetch_status === FetchStatuses.FETCH_STATUS_IDLE) { + resourceStatus = 'notDownloaded'; + } else if (localState.fetch_status === FetchStatuses.FETCH_STATUS_STARTED) { + resourceStatus = 'downloading'; + } else if (localState.fetch_status === FetchStatuses.FETCH_STATUS_DONE) { + if (resource.encryption_blob_encrypted || resource.encryption_applied) { + resourceStatus = 'encrypted'; + } + } + } else { + resourceStatus = 'notDownloaded'; + } + + return resourceStatus; +}; + +utils.imageReplacement = function(ResourceModel, src, resources, resourceBaseUrl) { + if (!ResourceModel) return null; + + if (!ResourceModel.isResourceUrl(src)) return null; + + const resourceId = ResourceModel.urlToId(src); + const result = resources[resourceId]; + const resource = result ? result.item : null; + const resourceStatus = utils.resourceStatus(ResourceModel, result); + + if (resourceStatus !== 'ready') { + const icon = utils.resourceStatusImage(resourceStatus); + return `
'+b.text+"
");break;case "author":f.push(' ");break;case "authors":f.push(' ");break;case "source":f.push(''+b.text+"
");break;case "notes":f.push(''+b.text+"
");break;case "draft_date":f.push(''+b.text+"
");break;case "date":f.push(''+b.text+"
");break;case "contact":f.push(''+b.text+"
");break;case "copyright":f.push(''+b.text+"
");break;case "scene_heading":a.push("'+b.text+"
");break;case "dialogue":a.push(""+b.text+"
");break;case "dialogue_end":a.push("'+b.text+"
");break;case "synopsis":a.push(''+b.text+"
");break;case "note":a.push("<\!-- "+b.text+"--\>");break;case "boneyard_begin":a.push("<\!-- ");break;case "boneyard_end":a.push(" --\>");break;case "action":a.push(""+b.text+"
");break;case "centered":a.push(''+b.text+"
");break;case "page_break":a.push("