You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Moved the Joplin renderer back to the main repository to make development easier
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
							
								
								
									
										158
									
								
								CliClient/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										158
									
								
								CliClient/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
							
								
								
									
										172
									
								
								ElectronClient/app/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										172
									
								
								ElectronClient/app/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -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", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 "$@" | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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'); | ||||
|  | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
							
								
								
									
										3
									
								
								ReactNativeClient/lib/joplin-renderer/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								ReactNativeClient/lib/joplin-renderer/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| node_modules/ | ||||
| .vscode/ | ||||
| copyLib.bat | ||||
							
								
								
									
										42
									
								
								ReactNativeClient/lib/joplin-renderer/HtmlToHtml.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								ReactNativeClient/lib/joplin-renderer/HtmlToHtml.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 = `<style>${cssStrings.join('\n')}</style>`; | ||||
|  | ||||
| 		return { | ||||
| 			html: styleHtml + html, | ||||
| 			pluginAssets: [], | ||||
| 		}; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| module.exports = HtmlToHtml; | ||||
							
								
								
									
										44
									
								
								ReactNativeClient/lib/joplin-renderer/MarkupToHtml.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								ReactNativeClient/lib/joplin-renderer/MarkupToHtml.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
							
								
								
									
										243
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <script> or <style> tags. Everything, like fonts, etc. is loaded | ||||
| 					// via CSS or some other ways. | ||||
| 					mime = 'application/octet-stream'; | ||||
| 					if (ext === 'css') mime = 'text/css'; | ||||
| 					if (ext === 'js') mime = 'application/javascript'; | ||||
| 				} | ||||
|  | ||||
| 				if (asset.inline) { | ||||
| 					if (mime === 'text/css') { | ||||
| 						cssStrings.push(asset.text); | ||||
| 					} else { | ||||
| 						throw new Error(`Unsupported inline mime type: ${mime}`); | ||||
| 					} | ||||
| 				} else { | ||||
| 					files.push(Object.assign({}, asset, { | ||||
| 						name: `${pluginName}/${asset.name}`, | ||||
| 						mime: mime, | ||||
| 					})); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return { | ||||
| 			files: files, | ||||
| 			cssStrings: cssStrings, | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	async render(body, style = null, options = null) { | ||||
| 		if (!options) options = {}; | ||||
| 		if (!options.postMessageSyntax) options.postMessageSyntax = 'postMessage'; | ||||
| 		if (!options.paddingBottom) options.paddingBottom = '0'; | ||||
| 		if (!options.highlightedKeywords) options.highlightedKeywords = []; | ||||
| 		if (!options.codeTheme) options.codeTheme = 'atom-one-light.css'; | ||||
|  | ||||
| 		if (!style) style = Object.assign({}, defaultNoteStyle); | ||||
|  | ||||
| 		// 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 cacheKey = md5(escape(body + JSON.stringify(options) + JSON.stringify(style))); | ||||
| 		const cachedOutput = this.cachedOutputs_[cacheKey]; | ||||
| 		if (cachedOutput) return cachedOutput; | ||||
|  | ||||
| 		const context = { | ||||
| 			css: {}, | ||||
| 			pluginAssets: {}, | ||||
| 		}; | ||||
|  | ||||
| 		const ruleOptions = Object.assign({}, options, { | ||||
| 			resourceBaseUrl: this.resourceBaseUrl_, | ||||
| 			ResourceModel: this.ResourceModel_, | ||||
| 		}); | ||||
|  | ||||
| 		const markdownIt = new MarkdownIt({ | ||||
| 			breaks: !this.pluginEnabled('softbreaks'), | ||||
| 			typographer: this.pluginEnabled('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; | ||||
| 					} | ||||
|  | ||||
| 					context.pluginAssets['highlight.js'] = [ | ||||
| 						{ name: 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 define what additional assets they need (css, fonts, etc.) using context.pluginAssets. | ||||
| 		// The calling application will need to handle loading these assets. | ||||
|  | ||||
| 		markdownIt.use(rules.image(context, ruleOptions)); | ||||
| 		markdownIt.use(rules.checkbox(context, ruleOptions)); | ||||
| 		markdownIt.use(rules.link_open(context, ruleOptions)); | ||||
| 		markdownIt.use(rules.html_image(context, ruleOptions)); | ||||
| 		if (this.pluginEnabled('katex')) markdownIt.use(rules.katex(context, ruleOptions)); | ||||
| 		if (this.pluginEnabled('fountain')) markdownIt.use(rules.fountain(context, ruleOptions)); | ||||
| 		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 (this.pluginEnabled(key)) markdownIt.use(plugins[key].module, plugins[key].options); | ||||
| 		} | ||||
|  | ||||
| 		setupLinkify(markdownIt); | ||||
|  | ||||
| 		const renderedBody = markdownIt.render(body); | ||||
|  | ||||
| 		let cssStrings = noteStyle(style, options); | ||||
|  | ||||
| 		const pluginAssets = this.processPluginAssets(context.pluginAssets); | ||||
| 		cssStrings = cssStrings.concat(pluginAssets.cssStrings); | ||||
|  | ||||
| 		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, | ||||
| 			pluginAssets: pluginAssets.files, | ||||
| 		}; | ||||
|  | ||||
| 		// Fow now, we keep only the last entry in the cache | ||||
| 		this.cachedOutputs_ = {}; | ||||
| 		this.cachedOutputs_[cacheKey] = output; | ||||
|  | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	injectedJavaScript() { | ||||
| 		return ''; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| module.exports = MdToHtml; | ||||
							
								
								
									
										134
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/checkbox.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,134 @@ | ||||
| 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()); | ||||
|  | ||||
| 				if (!('checkbox' in context.pluginAssets)) { | ||||
| 					context.pluginAssets['checkbox'] = [ | ||||
| 						{ | ||||
| 							inline: true, | ||||
| 							text: checkboxStyle, | ||||
| 							mime: 'text/css', | ||||
| 						}, | ||||
| 					]; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}); | ||||
| } | ||||
|  | ||||
| module.exports = function(context, ruleOptions) { | ||||
| 	return function(md, mdOptions) { | ||||
| 		installRule(md, mdOptions, ruleOptions, context); | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,22 @@ | ||||
| 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); | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										141
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fountain.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/fountain.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| const fountain = require('../../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.pluginAssets) return; | ||||
|  | ||||
| 	context.pluginAssets['fountain'] = [ | ||||
| 		{ | ||||
| 			inline: true, | ||||
| 			text: fountainCss, | ||||
| 			mime: 'text/css', | ||||
| 		}, | ||||
| 	]; | ||||
| } | ||||
|  | ||||
| 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); | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,67 @@ | ||||
| const stringUtils = require('../../stringUtils.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); | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,53 @@ | ||||
| // const Resource = require('lib/models/Resource.js'); | ||||
| const htmlUtils = require('../../htmlUtils.js'); | ||||
| const utils = require('../../utils'); | ||||
|  | ||||
| function renderImageHtml(before, src, after, ruleOptions) { | ||||
| 	const r = utils.imageReplacement(ruleOptions.ResourceModel, 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 Resource = ruleOptions.ResourceModel; | ||||
|  | ||||
| 	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); | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,29 @@ | ||||
| // const Resource = require('lib/models/Resource.js'); | ||||
| const utils = require('../../utils'); | ||||
| const htmlUtils = require('../../htmlUtils.js'); | ||||
|  | ||||
| function installRule(markdownIt, mdOptions, ruleOptions) { | ||||
| 	const defaultRender = markdownIt.renderer.rules.image; | ||||
|  | ||||
| 	markdownIt.renderer.rules.image = (tokens, idx, options, env, self) => { | ||||
| 		const Resource = ruleOptions.ResourceModel; | ||||
|  | ||||
| 		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(ruleOptions.ResourceModel, 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); | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										262
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/katex.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/katex.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| // Based on https://github.com/waylonflinn/markdown-it-katex | ||||
|  | ||||
| 'use strict'; | ||||
|  | ||||
| let katex = require('katex'); | ||||
| const md5 = require('md5'); | ||||
| const mhchemModule = require('./katex_mhchem.js'); | ||||
|  | ||||
| // Katex macros include circular references so we need | ||||
| // to serialize them with json-stringify-safe | ||||
| const stringifySafe = require('json-stringify-safe'); | ||||
|  | ||||
| katex = mhchemModule(katex); | ||||
|  | ||||
| // 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 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.pluginAssets['katex'] = [ | ||||
| 			{ name: 'katex.css' }, | ||||
| 			{ name: 'fonts/KaTeX_Main-Regular.woff2' }, | ||||
| 			{ name: 'fonts/KaTeX_Math-Italic.woff2' }, | ||||
| 			{ name: 'fonts/KaTeX_Size1-Regular.woff2' }, | ||||
| 		]; | ||||
| 	}; | ||||
|  | ||||
| 	function renderToStringWithCache(latex, options) { | ||||
| 		console.info('OPTSON', stringifySafe(options)); | ||||
| 		const cacheKey = md5(escape(latex) + escape(stringifySafe(options))); | ||||
| 		if (cacheKey in cache_) { | ||||
| 			return cache_[cacheKey]; | ||||
| 		} else { | ||||
| 			const beforeMacros = stringifySafe(options.macros); | ||||
| 			const output = katex.renderToString(latex, options); | ||||
| 			const afterMacros = stringifySafe(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; | ||||
| 		options.trust = true; | ||||
|  | ||||
| 		// set KaTeX as the renderer for markdown-it-simplemath | ||||
| 		var katexInline = function(latex) { | ||||
| 			options.displayMode = false; | ||||
| 			try { | ||||
| 				return renderToStringWithCache(latex, options); | ||||
| 			} catch (error) { | ||||
| 				console.error('Katex error for:', latex, 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) { | ||||
| 				console.error('Katex error for:', latex, 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; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										1732
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/katex_mhchem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1732
									
								
								ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/katex_mhchem.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -0,0 +1,74 @@ | ||||
| const Entities = require('html-entities').AllHtmlEntities; | ||||
| const htmlentities = new Entities().encode; | ||||
| const utils = require('../../utils'); | ||||
| const urlUtils = require('../../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(ruleOptions.ResourceModel, 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); | ||||
| 	}; | ||||
| }; | ||||
| @@ -0,0 +1,29 @@ | ||||
| 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; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										52
									
								
								ReactNativeClient/lib/joplin-renderer/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								ReactNativeClient/lib/joplin-renderer/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| # Joplin Renderer | ||||
|  | ||||
| This is the renderer used by [Joplin](https://github.com/laurent22/joplin) to render notes in Markdown or HTML format. | ||||
|  | ||||
| ## Installation | ||||
|  | ||||
| 	npm i -s joplin-renderer | ||||
|  | ||||
| Certain plugins require additional assets like CSS, fonts, etc. These assets are in the `/assets` directory and should be copied to wherever the application can find them at runtime. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ```js | ||||
| const { MarkupToHtml } = require('joplin-renderer'); | ||||
|  | ||||
| const options = {}; | ||||
|  | ||||
| // The notes are rendered using the provided theme. The supported theme properties are in `defaultNoteStyle.js` | ||||
| // and this is what is used if no theme is provided. A `theme` object can be provided to override default theme | ||||
| // properties. | ||||
| const theme = {}; | ||||
|  | ||||
| const markdown = "Testing `MarkupToHtml` renderer"; | ||||
|  | ||||
| const markupToHtml = new MarkupToHtml(options); | ||||
| const result = await markupToHtml.render(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, markdown, theme, options); | ||||
|  | ||||
| console.info('HTML:', result.html); | ||||
| console.info('Plugin assets:', result.pluginAssets); | ||||
| ``` | ||||
|  | ||||
| When calling `render()`, an object with the following properties is returned: | ||||
|  | ||||
| - `html`: The rendered HTML code | ||||
| - `pluginAssets`: The assets required by the plugins | ||||
|  | ||||
| The assets need to be loaded by the calling application. For example this is how they are loaded in the Joplin desktop application: | ||||
|  | ||||
| ```js | ||||
| function loadPluginAssets(assets) { | ||||
| 	for (let i = 0; i < assets.length; i++) { | ||||
| 		const asset = assets[i]; | ||||
|  | ||||
| 		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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										30
									
								
								ReactNativeClient/lib/joplin-renderer/Tools/buildAssets.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								ReactNativeClient/lib/joplin-renderer/Tools/buildAssets.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| const fs = require('fs-extra'); | ||||
| const {dirname } = require('../pathUtils'); | ||||
|  | ||||
| const rootDir = dirname(__dirname); | ||||
| const assetsDir = `${rootDir}/assets`; | ||||
|  | ||||
| async function copyFile(source, dest) { | ||||
| 	const fullDest = `${assetsDir}/${dest}`; | ||||
| 	const dir = dirname(fullDest); | ||||
| 	await fs.mkdirp(dir); | ||||
| 	await fs.copy(source, fullDest); | ||||
| } | ||||
|  | ||||
| async function main() { | ||||
| 	await fs.remove(assetsDir); | ||||
|  | ||||
| 	await copyFile(`${rootDir}/node_modules/katex/dist/katex.min.css`, 'katex/katex.css'); | ||||
| 	await copyFile(`${rootDir}/node_modules/katex/dist/fonts/KaTeX_Main-Regular.woff2`, 'katex/fonts/KaTeX_Main-Regular.woff2'); | ||||
| 	await copyFile(`${rootDir}/node_modules/katex/dist/fonts/KaTeX_Math-Italic.woff2`, 'katex/fonts/KaTeX_Math-Italic.woff2'); | ||||
| 	await copyFile(`${rootDir}/node_modules/katex/dist/fonts/KaTeX_Size1-Regular.woff2`, 'katex/fonts/KaTeX_Size1-Regular.woff2'); | ||||
| 	await copyFile(`${rootDir}/node_modules/katex/dist/fonts/KaTeX_Size2-Regular.woff2`, 'katex/fonts/KaTeX_Size2-Regular.woff2'); | ||||
|  | ||||
| 	await copyFile(`${rootDir}/node_modules/highlight.js/styles/atom-one-light.css`, 'highlight.js/atom-one-light.css'); | ||||
| 	await copyFile(`${rootDir}/node_modules/highlight.js/styles/atom-one-dark-reasonable.css`, 'highlight.js/atom-one-dark-reasonable.css'); | ||||
| } | ||||
|  | ||||
| main().catch((error) => { | ||||
| 	console.error(error); | ||||
| 	process.exit(1); | ||||
| }); | ||||
| @@ -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; | ||||
| } | ||||
| @@ -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; | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										18
									
								
								ReactNativeClient/lib/joplin-renderer/assetsToHeaders.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								ReactNativeClient/lib/joplin-renderer/assetsToHeaders.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| // Utility function to convert the plugin assets to a list of LINK or SCRIPT tags | ||||
| // that can be included in the HEAD tag. | ||||
| function assetsToHeaders(pluginAssets) { | ||||
| 	const headers = []; | ||||
| 	for (let i = 0; i < pluginAssets.length; i++) { | ||||
| 		const asset = 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>`); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return headers.join('\n'); | ||||
| } | ||||
|  | ||||
| module.exports = assetsToHeaders; | ||||
							
								
								
									
										19
									
								
								ReactNativeClient/lib/joplin-renderer/defaultNoteStyle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								ReactNativeClient/lib/joplin-renderer/defaultNoteStyle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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', | ||||
| }; | ||||
							
								
								
									
										50
									
								
								ReactNativeClient/lib/joplin-renderer/htmlUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								ReactNativeClient/lib/joplin-renderer/htmlUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 = /<img([\s\S]*?)src=["']([\s\S]*?)["']([\s\S]*?)>/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 `<img${before}src="${src}"${after}>`; | ||||
|  | ||||
| 			if (action.type === 'replaceElement') { | ||||
| 				return action.html; | ||||
| 			} | ||||
|  | ||||
| 			if (action.type === 'replaceSource') { | ||||
| 				return `<img${before}src="${action.src}"${after}>`; | ||||
| 			} | ||||
|  | ||||
| 			if (action.type === 'setAttributes') { | ||||
| 				const attrHtml = this.attributesHtml(action.attrs); | ||||
| 				return `<img${before}${attrHtml}${after}>`; | ||||
| 			} | ||||
|  | ||||
| 			throw new Error(`Invalid action: ${action.type}`); | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| const htmlUtils = new HtmlUtils(); | ||||
|  | ||||
| module.exports = htmlUtils; | ||||
							
								
								
									
										7
									
								
								ReactNativeClient/lib/joplin-renderer/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								ReactNativeClient/lib/joplin-renderer/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| module.exports = { | ||||
| 	MarkupToHtml: require('./MarkupToHtml'), | ||||
| 	MdToHtml: require('./MdToHtml'), | ||||
| 	HtmlToHtml: require('./HtmlToHtml'), | ||||
| 	setupLinkify: require('./MdToHtml/setupLinkify'), | ||||
| 	assetsToHeaders: require('./assetsToHeaders'), | ||||
| }; | ||||
							
								
								
									
										291
									
								
								ReactNativeClient/lib/joplin-renderer/noteStyle.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										291
									
								
								ReactNativeClient/lib/joplin-renderer/noteStyle.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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,<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]; | ||||
| }; | ||||
							
								
								
									
										394
									
								
								ReactNativeClient/lib/joplin-renderer/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								ReactNativeClient/lib/joplin-renderer/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										39
									
								
								ReactNativeClient/lib/joplin-renderer/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								ReactNativeClient/lib/joplin-renderer/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -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" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										32
									
								
								ReactNativeClient/lib/joplin-renderer/pathUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ReactNativeClient/lib/joplin-renderer/pathUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 }; | ||||
							
								
								
									
										14
									
								
								ReactNativeClient/lib/joplin-renderer/publish.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ReactNativeClient/lib/joplin-renderer/publish.sh
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
							
								
								
									
										74
									
								
								ReactNativeClient/lib/joplin-renderer/stringUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								ReactNativeClient/lib/joplin-renderer/stringUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 }; | ||||
							
								
								
									
										24
									
								
								ReactNativeClient/lib/joplin-renderer/tests/MdToHtmlTest.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								ReactNativeClient/lib/joplin-renderer/tests/MdToHtmlTest.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
|  | ||||
| 		//  | ||||
| 	})); | ||||
|  | ||||
| }); | ||||
| @@ -0,0 +1,9 @@ | ||||
| { | ||||
|   "spec_dir": "tests", | ||||
|   "spec_files": [ | ||||
|     "*.js", | ||||
|     "!test-utils.js" | ||||
|   ], | ||||
|   "stopSpecOnExpectationFailure": true, | ||||
|   "random": true | ||||
| } | ||||
							
								
								
									
										16
									
								
								ReactNativeClient/lib/joplin-renderer/tests/test-utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								ReactNativeClient/lib/joplin-renderer/tests/test-utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 }; | ||||
							
								
								
									
										32
									
								
								ReactNativeClient/lib/joplin-renderer/urlUtils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								ReactNativeClient/lib/joplin-renderer/urlUtils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||
							
								
								
									
										133
									
								
								ReactNativeClient/lib/joplin-renderer/utils.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								ReactNativeClient/lib/joplin-renderer/utils.js
									
									
									
									
									
										Normal file
									
								
							| @@ -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 ` | ||||
| 		<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(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 `<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 (ResourceModel.isSupportedImageMimeType(mime)) { | ||||
| 		let newSrc = `./${ResourceModel.filename(resource)}`; | ||||
| 		if (resourceBaseUrl) newSrc = resourceBaseUrl + newSrc; | ||||
| 		return { | ||||
| 			'data-resource-id': resource.id, | ||||
| 			src: newSrc, | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	return null; | ||||
| }; | ||||
|  | ||||
| module.exports = utils; | ||||
							
								
								
									
										14
									
								
								ReactNativeClient/lib/joplin-renderer/vendor/fountain.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ReactNativeClient/lib/joplin-renderer/vendor/fountain.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| // https://github.com/mattdaly/Fountain.js/ | ||||
|  | ||||
| (function(){var d={title_page:/^((?:title|credit|author[s]?|source|notes|draft date|date|contact|copyright)\:)/gim,scene_heading:/^((?:\*{0,3}_?)?(?:(?:int|ext|est|i\/e)[. ]).+)|^(?:\.(?!\.+))(.+)/i,scene_number:/( *#(.+)# *)/,transition:/^((?:FADE (?:TO BLACK|OUT)|CUT TO BLACK)\.|.+ TO\:)|^(?:> *)(.+)/,dialogue:/^([A-Z*_]+[0-9A-Z (._\-')]*)(\^?)?(?:\n(?!\n+))([\s\S]+)/,parenthetical:/^(\(.+\))$/,action:/^(.+)/g,centered:/^(?:> *)(.+)(?: *<)(\n.+)*/g,section:/^(#+)(?: *)(.*)/,synopsis:/^(?:\=(?!\=+) *)(.*)/, | ||||
| note:/^(?:\[{2}(?!\[+))(.+)(?:\]{2}(?!\[+))$/,note_inline:/(?:\[{2}(?!\[+))([\s\S]+?)(?:\]{2}(?!\[+))/g,boneyard:/(^\/\*|^\*\/)$/g,page_break:/^\={3,}$/,line_break:/^ {2}$/,emphasis:/(_|\*{1,3}|_\*{1,3}|\*{1,3}_)(.+)(_|\*{1,3}|_\*{1,3}|\*{1,3}_)/g,bold_italic_underline:/(_{1}\*{3}(?=.+\*{3}_{1})|\*{3}_{1}(?=.+_{1}\*{3}))(.+?)(\*{3}_{1}|_{1}\*{3})/g,bold_underline:/(_{1}\*{2}(?=.+\*{2}_{1})|\*{2}_{1}(?=.+_{1}\*{2}))(.+?)(\*{2}_{1}|_{1}\*{2})/g,italic_underline:/(?:_{1}\*{1}(?=.+\*{1}_{1})|\*{1}_{1}(?=.+_{1}\*{1}))(.+?)(\*{1}_{1}|_{1}\*{1})/g, | ||||
| bold_italic:/(\*{3}(?=.+\*{3}))(.+?)(\*{3})/g,bold:/(\*{2}(?=.+\*{2}))(.+?)(\*{2})/g,italic:/(\*{1}(?=.+\*{1}))(.+?)(\*{1})/g,underline:/(_{1}(?=.+_{1}))(.+?)(_{1})/g,splitter:/\n{2,}/g,cleaner:/^\n+|\n+$/,standardizer:/\r\n|\r/g,whitespacer:/^\t+|^ {3,}/gm},n={note:"<\!-- $1 --\>",line_break:"<br />",bold_italic_underline:'<span class="bold italic underline">$2</span>',bold_underline:'<span class="bold underline">$2</span>',italic_underline:'<span class="italic underline">$2</span>',bold_italic:'<span class="bold italic">$2</span>', | ||||
| bold:'<span class="bold">$2</span>',italic:'<span class="italic">$2</span>',underline:'<span class="underline">$2</span>',lexer:function(c){if(c){for(var j="underline,italic,bold,bold_italic,italic_underline,bold_underline,bold_italic_underline".split(","),k=j.length,g,b,c=c.replace(d.note_inline,n.note).replace(/\\\*/g,"[star]").replace(/\\_/g,"[underline]").replace(/\n/g,n.line_break);k--;)g=j[k],b=d[g],b.test(c)&&(c=c.replace(b,n[g]));return c.replace(/\[star\]/g,"*").replace(/\[underline\]/g, | ||||
| "_").trim()}}},h=function(c,d){return h.parse(c,d)};h.parse=function(c,j,k){var g;void 0===k&&"function"===typeof j&&(k=j,j=void 0);for(var b=c.replace(d.boneyard,"\n$1\n").replace(d.standardizer,"\n").replace(d.cleaner,"").replace(d.whitespacer,"").split(d.splitter),f=b.length,e,a,l,i,h,m,c=[];f--;)if(e=b[f],d.title_page.test(e)){a=e.replace(d.title_page,"\n$1").split(d.splitter).reverse();i=0;for(h=a.length;i<h;i++)l=a[i].replace(d.cleaner,"").split(/\:\n*/),c.push({type:l[0].trim().toLowerCase().replace(" ", | ||||
| "_"),text:l[1].trim()})}else if(a=e.match(d.scene_heading)){if(e=a[1]||a[2],e.indexOf("  ")!==e.length-2){if(a=e.match(d.scene_number))a=a[2],e=e.replace(d.scene_number,"");c.push({type:"scene_heading",text:e,scene_number:a||void 0})}}else if(a=e.match(d.centered))c.push({type:"centered",text:a[0].replace(/>|</g,"")});else if(a=e.match(d.transition))c.push({type:"transition",text:a[1]||a[2]});else if((a=e.match(d.dialogue))&&a[1].indexOf("  ")!==a[1].length-2){a[2]&&c.push({type:"dual_dialogue_end"}); | ||||
| c.push({type:"dialogue_end"});l=a[3].split(/(\(.+\))(?:\n+)/).reverse();i=0;for(h=l.length;i<h;i++)e=l[i],0<e.length&&c.push({type:d.parenthetical.test(e)?"parenthetical":"dialogue",text:e});c.push({type:"character",text:a[1].trim()});c.push({type:"dialogue_begin",dual:a[2]?"right":m?"left":void 0});m&&c.push({type:"dual_dialogue_begin"});m=a[2]?!0:!1}else(a=e.match(d.section))?c.push({type:"section",text:a[2],depth:a[1].length}):(a=e.match(d.synopsis))?c.push({type:"synopsis",text:a[1]}):(a=e.match(d.note))? | ||||
| c.push({type:"note",text:a[1]}):(a=e.match(d.boneyard))?c.push({type:"/"===a[0][0]?"boneyard_begin":"boneyard_end"}):d.page_break.test(e)?c.push({type:"page_break"}):d.line_break.test(e)?c.push({type:"line_break"}):c.push({type:"action",text:e});m=c.length;f=[];for(a=[];m--;)switch(b=c[m],b.text=n.lexer(b.text),b.type){case "title":f.push("<h1>"+b.text+"</h1>");g=b.text.replace("<br />"," ").replace(/<(?:.|\n)*?>/g,"");break;case "credit":f.push('<p class="credit">'+b.text+"</p>");break;case "author":f.push('<p class="authors">'+ | ||||
| b.text+"</p>");break;case "authors":f.push('<p class="authors">'+b.text+"</p>");break;case "source":f.push('<p class="source">'+b.text+"</p>");break;case "notes":f.push('<p class="notes">'+b.text+"</p>");break;case "draft_date":f.push('<p class="draft-date">'+b.text+"</p>");break;case "date":f.push('<p class="date">'+b.text+"</p>");break;case "contact":f.push('<p class="contact">'+b.text+"</p>");break;case "copyright":f.push('<p class="copyright">'+b.text+"</p>");break;case "scene_heading":a.push("<h3"+ | ||||
| (b.scene_number?' id="'+b.scene_number+'">':">")+b.text+"</h3>");break;case "transition":a.push("<h2>"+b.text+"</h2>");break;case "dual_dialogue_begin":a.push('<div class="dual-dialogue">');break;case "dialogue_begin":a.push('<div class="dialogue'+(b.dual?" "+b.dual:"")+'">');break;case "character":a.push("<h4>"+b.text+"</h4>");break;case "parenthetical":a.push('<p class="parenthetical">'+b.text+"</p>");break;case "dialogue":a.push("<p>"+b.text+"</p>");break;case "dialogue_end":a.push("</div> "); | ||||
| break;case "dual_dialogue_end":a.push("</div> ");break;case "section":a.push('<p class="section" data-depth="'+b.depth+'">'+b.text+"</p>");break;case "synopsis":a.push('<p class="synopsis">'+b.text+"</p>");break;case "note":a.push("<\!-- "+b.text+"--\>");break;case "boneyard_begin":a.push("<\!-- ");break;case "boneyard_end":a.push(" --\>");break;case "action":a.push("<p>"+b.text+"</p>");break;case "centered":a.push('<p class="centered">'+b.text+"</p>");break;case "page_break":a.push("<hr />");break; | ||||
| case "line_break":a.push("<br />")}g={title:g,html:{title_page:f.join(""),script:a.join("")},tokens:j?c.reverse():void 0};g="function"===typeof k?k(g):g;return g};"undefined"!==typeof module?module.exports=h:this.fountain=h}).call(this); | ||||
							
								
								
									
										110
									
								
								ReactNativeClient/lib/joplin-renderer/webviewLib.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								ReactNativeClient/lib/joplin-renderer/webviewLib.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| const webviewLib = {}; | ||||
|  | ||||
| let manualDownloadResourceElements = []; | ||||
|  | ||||
| webviewLib.onUnloadedResourceClick = function(event) { | ||||
| 	const resourceId = event.currentTarget.getAttribute('data-resource-id'); | ||||
| 	webviewLib.options_.postMessage(`markForDownload:${resourceId}`); | ||||
| }; | ||||
|  | ||||
| webviewLib.setupResourceManualDownload = function() { | ||||
| 	for (const element of manualDownloadResourceElements) { | ||||
| 		element.style.cursor = 'default'; | ||||
| 		element.removeEventListener('click', webviewLib.onUnloadedResourceClick); | ||||
| 	} | ||||
|  | ||||
| 	manualDownloadResourceElements = []; | ||||
|  | ||||
| 	const elements = document.getElementsByClassName('resource-status-notDownloaded'); | ||||
|  | ||||
| 	for (const element of elements) { | ||||
| 		element.style.cursor = 'pointer'; | ||||
| 		element.addEventListener('click', webviewLib.onUnloadedResourceClick); | ||||
| 		manualDownloadResourceElements.push(element); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| webviewLib.handleInternalLink = function(event, anchorNode) { | ||||
| 	const href = anchorNode.getAttribute('href'); | ||||
| 	if (!href) return false; | ||||
|  | ||||
| 	if (href.indexOf('#') === 0) { | ||||
| 		event.preventDefault(); | ||||
| 		let old_hash = location.hash; | ||||
|  | ||||
| 		location.hash = href; | ||||
|  | ||||
| 		// HACK | ||||
| 		// For some reason anchors at the bottom cause the webview to move itself | ||||
| 		// so that the content is aligned with the top of the screen | ||||
| 		// This basically refreshes the scroll view so that is returns to a normal | ||||
| 		// position, the scroll positions stays correct though | ||||
| 		// Additionally an anchor could not be clicked twice because the location | ||||
| 		// would not change, this fixes that also | ||||
| 		setTimeout(function() { | ||||
| 			location.hash = old_hash; | ||||
| 		}, 10); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	return false; | ||||
| }; | ||||
|  | ||||
| webviewLib.getParentAnchorElement = function(element) { | ||||
| 	let counter = 0; | ||||
| 	while (true) { | ||||
| 		if (counter++ >= 10000) { | ||||
| 			console.warn('been looping for too long - exiting'); | ||||
| 			return null; | ||||
| 		} | ||||
|  | ||||
| 		if (!element) return null; | ||||
| 		if (element.nodeName === 'A') return element; | ||||
| 		element = element.parentElement; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| webviewLib.cloneError = function(error) { | ||||
| 	return { | ||||
| 		message: error.message, | ||||
| 		stack: error.stack, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| webviewLib.logEnabledEventHandler = function(fn) { | ||||
| 	return function(event) { | ||||
| 		try { | ||||
| 			return fn(event); | ||||
| 		} catch (error) { | ||||
| 			webviewLib.options_.postMessage(`error:${JSON.stringify(webviewLib.cloneError(error))}`); | ||||
| 			throw error; | ||||
| 		} | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| webviewLib.initialize = function(options) { | ||||
| 	webviewLib.options_ = options; | ||||
| }; | ||||
|  | ||||
| document.addEventListener('click', function(event) { | ||||
| 	const anchor = webviewLib.getParentAnchorElement(event.target); | ||||
| 	if (!anchor) return; | ||||
|  | ||||
| 	// Prevent URLs added via <a> tags from being opened within the application itself | ||||
| 	// otherwise it would open the whole website within the WebView. | ||||
|  | ||||
| 	// Note that we already handle some links in html_inline.js, however not all of them | ||||
| 	// go through this plugin, in particular links coming from third-party packages such | ||||
| 	// as Katex. | ||||
| 	if (!anchor.hasAttribute('data-from-md')) { | ||||
| 		if (webviewLib.handleInternalLink(event, anchor)) return; | ||||
| 		event.preventDefault(); | ||||
| 		if (anchor.getAttribute('href')) webviewLib.options_.postMessage(anchor.getAttribute('href')); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	// If this is an internal link, jump to the anchor directly | ||||
| 	if (anchor.hasAttribute('data-from-md')) { | ||||
| 		if (webviewLib.handleInternalLink(event, anchor)) return; | ||||
| 	} | ||||
| }); | ||||
| @@ -1,7 +1,7 @@ | ||||
| const stringPadding = require('string-padding'); | ||||
| const urlUtils = require('lib/urlUtils'); | ||||
| const MarkdownIt = require('markdown-it'); | ||||
| const { setupLinkify } = require('joplin-renderer'); | ||||
| const { setupLinkify } = require('lib/joplin-renderer'); | ||||
|  | ||||
| const markdownUtils = { | ||||
| 	// Not really escaping because that's not supported by marked.js | ||||
|   | ||||
| @@ -2,7 +2,7 @@ const markdownUtils = require('lib/markdownUtils'); | ||||
| const htmlUtils = require('lib/htmlUtils'); | ||||
| const Setting = require('lib/models/Setting'); | ||||
| const Resource = require('lib/models/Resource'); | ||||
| const { MarkupToHtml } = require('joplin-renderer'); | ||||
| const { MarkupToHtml } = require('lib/joplin-renderer'); | ||||
|  | ||||
| class MarkupLanguageUtils { | ||||
| 	lib_(language) { | ||||
|   | ||||
| @@ -11,7 +11,7 @@ const { _ } = require('lib/locale.js'); | ||||
| const ArrayUtils = require('lib/ArrayUtils.js'); | ||||
| const lodash = require('lodash'); | ||||
| const urlUtils = require('lib/urlUtils.js'); | ||||
| const { MarkupToHtml } = require('joplin-renderer'); | ||||
| const { MarkupToHtml } = require('lib/joplin-renderer'); | ||||
|  | ||||
| class Note extends BaseItem { | ||||
| 	static tableName() { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ const { themeStyle } = require('../../theme.js'); | ||||
| const { dirname } = require('lib/path-utils.js'); | ||||
| const { escapeHtml } = require('lib/string-utils.js'); | ||||
| const markupLanguageUtils = require('lib/markupLanguageUtils'); | ||||
| const { assetsToHeaders } = require('joplin-renderer'); | ||||
| const { assetsToHeaders } = require('lib/joplin-renderer'); | ||||
|  | ||||
| class InteropService_Exporter_Html extends InteropService_Exporter_Base { | ||||
|  | ||||
|   | ||||
| @@ -22,7 +22,7 @@ const ApiResponse = require('lib/services/rest/ApiResponse'); | ||||
| const SearchEngineUtils = require('lib/services/SearchEngineUtils'); | ||||
| const { FoldersScreenUtils } = require('lib/folders-screen-utils.js'); | ||||
| const uri2path = require('file-uri-to-path'); | ||||
| const { MarkupToHtml } = require('joplin-renderer'); | ||||
| const { MarkupToHtml } = require('lib/joplin-renderer'); | ||||
| const { uuid } = require('lib/uuid'); | ||||
|  | ||||
| class ApiError extends Error { | ||||
|   | ||||
							
								
								
									
										176
									
								
								ReactNativeClient/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										176
									
								
								ReactNativeClient/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -2691,11 +2691,6 @@ | ||||
|         "locate-path": "^2.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "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", | ||||
| @@ -2736,6 +2731,7 @@ | ||||
|       "version": "8.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", | ||||
|       "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", | ||||
|       "dev": true, | ||||
|       "requires": { | ||||
|         "graceful-fs": "^4.2.0", | ||||
|         "jsonfile": "^4.0.0", | ||||
| @@ -2745,7 +2741,8 @@ | ||||
|         "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==" | ||||
|           "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", | ||||
|           "dev": true | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
| @@ -3369,11 +3366,6 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "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", | ||||
| @@ -3758,58 +3750,6 @@ | ||||
|       "integrity": "sha512-+f/4OLeqY8RAmXnonI1ffeY1DR8kMNJPhv5WMFehchf7U71cjMQVKkOz1n6asz6kfVoAqKNWJz1A/18i18AcXA==", | ||||
|       "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==" | ||||
|         }, | ||||
|         "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": { | ||||
|       "version": "3.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", | ||||
| @@ -3847,11 +3787,6 @@ | ||||
|         "jsonify": "~0.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "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=" | ||||
|     }, | ||||
|     "json5": { | ||||
|       "version": "2.1.0", | ||||
|       "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", | ||||
| @@ -3873,21 +3808,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", | ||||
|       "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" | ||||
|     }, | ||||
|     "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==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "kind-of": { | ||||
|       "version": "3.2.2", | ||||
|       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", | ||||
| @@ -4043,83 +3963,6 @@ | ||||
|         "uc.micro": "^1.0.3" | ||||
|       } | ||||
|     }, | ||||
|     "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" | ||||
|           } | ||||
|         }, | ||||
|         "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==" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "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==" | ||||
|     }, | ||||
|     "math-random": { | ||||
|       "version": "1.0.4", | ||||
|       "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", | ||||
| @@ -7261,11 +7104,6 @@ | ||||
|       "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==" | ||||
|     }, | ||||
|     "unpipe": { | ||||
|       "version": "1.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", | ||||
| @@ -7347,14 +7185,6 @@ | ||||
|       "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", | ||||
|       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" | ||||
|     }, | ||||
|     "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": { | ||||
|       "version": "2.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.2.tgz", | ||||
|   | ||||
| @@ -19,7 +19,6 @@ | ||||
|     "events": "^1.1.1", | ||||
|     "form-data": "^2.1.4", | ||||
|     "html-entities": "^1.2.1", | ||||
|     "joplin-renderer": "^1.0.8", | ||||
|     "jsc-android": "241213.1.0", | ||||
|     "markdown-it": "^8.4.0", | ||||
|     "md5": "^2.2.1", | ||||
|   | ||||
| @@ -8,9 +8,6 @@ | ||||
| 			"name": "Joplin Nextcloud App", | ||||
| 			"path": "D:/Web/www/nextcloud/apps/joplin" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"path": "D:/Docs/PROGS/Node/joplin-renderer" | ||||
| 		} | ||||
| 	], | ||||
| 	"settings": { | ||||
| 		"files.exclude": { | ||||
|   | ||||
| @@ -7,7 +7,8 @@ | ||||
|     "linter-ci": "./node_modules/.bin/eslint --ext .js --ext .jsx --ext .ts --ext .tsx", | ||||
|     "tsc": "tsc", | ||||
|     "tsc-watch": "tsc --watch", | ||||
|     "copyLib": "rsync --delete -a ReactNativeClient/lib/ ElectronClient/app/lib/" | ||||
|     "copyLib": "rsync --delete -a ReactNativeClient/lib/ ElectronClient/app/lib/", | ||||
|     "postinstall": "cd ReactNativeClient && cd lib && cd joplin-renderer && npm i" | ||||
|   }, | ||||
|   "husky": { | ||||
|     "hooks": { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user