diff --git a/CliClient/package-lock.json b/CliClient/package-lock.json
index 6d3718096..62dc0c167 100644
--- a/CliClient/package-lock.json
+++ b/CliClient/package-lock.json
@@ -15,9 +15,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
- "version": "5.7.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
- "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
+ "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
},
"acorn-globals": {
"version": "4.3.2",
@@ -26,13 +26,6 @@
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
- },
- "dependencies": {
- "acorn": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
- "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
- }
}
},
"acorn-walk": {
@@ -518,18 +511,6 @@
"abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
- },
- "dependencies": {
- "whatwg-url": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
- "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
- "requires": {
- "lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
- }
- }
}
},
"debug": {
@@ -1374,6 +1355,11 @@
"resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz",
"integrity": "sha1-ge9X/l0FgUzVjCSDYyqZwwoOgIc="
},
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
"is-absolute": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz",
@@ -1472,6 +1458,193 @@
"css": "^2.2.4",
"html-entities": "^1.2.1",
"jsdom": "^11.9.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+ },
+ "ajv": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz",
+ "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "jsdom": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
+ "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "requires": {
+ "abab": "^2.0.0",
+ "acorn": "^5.5.3",
+ "acorn-globals": "^4.1.0",
+ "array-equal": "^1.0.0",
+ "cssom": ">= 0.3.2 < 0.4.0",
+ "cssstyle": "^1.0.0",
+ "data-urls": "^1.0.0",
+ "domexception": "^1.0.1",
+ "escodegen": "^1.9.1",
+ "html-encoding-sniffer": "^1.0.2",
+ "left-pad": "^1.3.0",
+ "nwsapi": "^2.0.7",
+ "parse5": "4.0.0",
+ "pn": "^1.1.0",
+ "request": "^2.87.0",
+ "request-promise-native": "^1.0.5",
+ "sax": "^1.2.4",
+ "symbol-tree": "^3.2.2",
+ "tough-cookie": "^2.3.4",
+ "w3c-hr-time": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "whatwg-encoding": "^1.0.3",
+ "whatwg-mimetype": "^2.1.0",
+ "whatwg-url": "^6.4.1",
+ "ws": "^5.2.0",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "parse5": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
+ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ },
+ "whatwg-url": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
+ "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "ws": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
}
},
"joplin-turndown-plugin-gfm": {
@@ -1496,35 +1669,35 @@
"optional": true
},
"jsdom": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
- "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz",
+ "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==",
"requires": {
"abab": "^2.0.0",
- "acorn": "^5.5.3",
- "acorn-globals": "^4.1.0",
+ "acorn": "^6.1.1",
+ "acorn-globals": "^4.3.2",
"array-equal": "^1.0.0",
- "cssom": ">= 0.3.2 < 0.4.0",
- "cssstyle": "^1.0.0",
- "data-urls": "^1.0.0",
+ "cssom": "^0.3.6",
+ "cssstyle": "^1.2.2",
+ "data-urls": "^1.1.0",
"domexception": "^1.0.1",
- "escodegen": "^1.9.1",
+ "escodegen": "^1.11.1",
"html-encoding-sniffer": "^1.0.2",
- "left-pad": "^1.3.0",
- "nwsapi": "^2.0.7",
- "parse5": "4.0.0",
+ "nwsapi": "^2.1.4",
+ "parse5": "5.1.0",
"pn": "^1.1.0",
- "request": "^2.87.0",
- "request-promise-native": "^1.0.5",
- "sax": "^1.2.4",
+ "request": "^2.88.0",
+ "request-promise-native": "^1.0.7",
+ "saxes": "^3.1.9",
"symbol-tree": "^3.2.2",
- "tough-cookie": "^2.3.4",
+ "tough-cookie": "^3.0.1",
"w3c-hr-time": "^1.0.1",
+ "w3c-xmlserializer": "^1.1.2",
"webidl-conversions": "^4.0.2",
- "whatwg-encoding": "^1.0.3",
- "whatwg-mimetype": "^2.1.0",
- "whatwg-url": "^6.4.1",
- "ws": "^5.2.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^7.0.0",
+ "ws": "^7.0.0",
"xml-name-validator": "^3.0.0"
},
"dependencies": {
@@ -1647,6 +1820,23 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
+ "tough-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
+ "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
+ "requires": {
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ }
+ }
+ },
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
@@ -2200,9 +2390,9 @@
}
},
"parse5": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
- "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+ "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ=="
},
"path-exists": {
"version": "3.0.0",
@@ -2503,6 +2693,14 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
+ "saxes": {
+ "version": "3.1.11",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
+ "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
+ "requires": {
+ "xmlchars": "^2.1.1"
+ }
+ },
"semver": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
@@ -3212,6 +3410,16 @@
"browser-process-hrtime": "^0.1.2"
}
},
+ "w3c-xmlserializer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
+ "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+ "requires": {
+ "domexception": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
@@ -3241,9 +3449,9 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
- "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@@ -3297,11 +3505,11 @@
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"ws": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
- "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.0.tgz",
+ "integrity": "sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g==",
"requires": {
- "async-limiter": "~1.0.0"
+ "async-limiter": "^1.0.0"
}
},
"xml-name-validator": {
@@ -3323,6 +3531,11 @@
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz",
"integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8="
},
+ "xmlchars": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz",
+ "integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w=="
+ },
"xregexp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-3.2.0.tgz",
diff --git a/CliClient/package.json b/CliClient/package.json
index 99e2311c8..1918b607c 100644
--- a/CliClient/package.json
+++ b/CliClient/package.json
@@ -45,6 +45,7 @@
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.17",
"joplin-turndown-plugin-gfm": "^1.0.8",
+ "jsdom": "^15.1.1",
"jssha": "^2.3.0",
"levenshtein": "^1.0.5",
"lodash": "^4.17.4",
diff --git a/CliClient/tests/htmlUtils.js b/CliClient/tests/htmlUtils.js
new file mode 100644
index 000000000..0181025f3
--- /dev/null
+++ b/CliClient/tests/htmlUtils.js
@@ -0,0 +1,33 @@
+require('app-module-path').addPath(__dirname);
+
+const { time } = require('lib/time-utils.js');
+const { fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
+const htmlUtils = require('lib/htmlUtils.js');
+
+process.on('unhandledRejection', (reason, p) => {
+ console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
+});
+
+describe('htmlUtils', function() {
+
+ beforeEach(async (done) => {
+ done();
+ });
+
+ it('should extract image URLs', async (done) => {
+ const testCases = [
+ ['', ['http://test.com/img.png']],
+ [' ', ['http://test.com/img.png', 'http://test.com/img2.png']],
+ ];
+
+ for (let i = 0; i < testCases.length; i++) {
+ const md = testCases[i][0];
+ const expected = testCases[i][1];
+
+ expect(htmlUtils.extractImageUrls(md).join(' ')).toBe(expected.join(' '));
+ }
+
+ done();
+ });
+
+});
\ No newline at end of file
diff --git a/Clipper/joplin-webclipper/content_scripts/index.js b/Clipper/joplin-webclipper/content_scripts/index.js
index 5b5324802..943530de8 100644
--- a/Clipper/joplin-webclipper/content_scripts/index.js
+++ b/Clipper/joplin-webclipper/content_scripts/index.js
@@ -61,7 +61,7 @@
const output = {};
for (let i = 0; i < images.length; i++) {
const img = images[i];
- const src = forceAbsoluteUrls ? absoluteUrl(img.src) : img.src;
+ const src = forceAbsoluteUrls ? absoluteUrl(img.currentSrc) : img.currentSrc;
output[src] = {
width: img.width,
height: img.height,
@@ -112,7 +112,7 @@
}
if (nodeName === 'img') {
- node.src = absoluteUrl(node.src);
+ node.src = absoluteUrl(node.currentSrc);
const imageSize = imageSizes[node.src];
if (imageSize) {
node.width = imageSize.width;
@@ -135,6 +135,8 @@
for (let i = 0; i < childNodes.length; i++) {
const node = childNodes[i];
const nodeName = node.nodeName.toLowerCase();
+ const nodeParent = node.parentNode;
+ const nodeParentName = nodeParent ? nodeParent.nodeName.toLowerCase() : '';
let isVisible = node.nodeType === 1 ? window.getComputedStyle(node).display !== 'none' : true;
if (isVisible && ['script', 'noscript', 'style', 'select', 'option', 'button'].indexOf(nodeName) >= 0) isVisible = false;
@@ -153,6 +155,10 @@
if (a && a.toLowerCase().indexOf('math/tex') >= 0) isVisible = true;
}
+ if (nodeName === 'source' && nodeParentName === 'picture') {
+ isVisible = false
+ }
+
if (!isVisible) {
node.classList.add('joplin-clipper-hidden');
} else {
@@ -179,19 +185,25 @@
// Given a document, return a ';
+ return output;
}
function documentForReadability() {
@@ -223,7 +235,7 @@
async function prepareCommandResponse(command) {
console.info('Got command: ' + command.name);
- const clippedContentResponse = (title, html, imageSizes, anchorNames) => {
+ const clippedContentResponse = (title, html, imageSizes, anchorNames, stylesheets) => {
return {
name: 'clippedContent',
title: title,
@@ -234,6 +246,9 @@
tags: command.tags || '',
image_sizes: imageSizes,
anchor_names: anchorNames,
+ source_command: Object.assign({}, command),
+ convert_to: command.preProcessFor ? command.preProcessFor : 'markdown',
+ stylesheets: stylesheets,
};
}
@@ -255,7 +270,6 @@
} else if (command.name === "isProbablyReaderable") {
const ok = isProbablyReaderable(documentForReadability());
- console.info('isProbablyReaderable', ok);
return { name: 'isProbablyReaderable', value: ok };
} else if (command.name === "completePageHtml") {
@@ -267,7 +281,9 @@
const cleanDocument = document.body.cloneNode(true);
const imageSizes = getImageSizes(document, true);
cleanUpElement(cleanDocument, imageSizes);
- return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, imageSizes, getAnchorNames(document));
+
+ const stylesheets = command.preProcessFor === 'html' ? getStyleSheets(document) : null;
+ return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, imageSizes, getAnchorNames(document), stylesheets);
} else if (command.name === "selectedHtml") {
diff --git a/Clipper/joplin-webclipper/popup/src/App.js b/Clipper/joplin-webclipper/popup/src/App.js
index 109bf8ace..fb2ef624b 100644
--- a/Clipper/joplin-webclipper/popup/src/App.js
+++ b/Clipper/joplin-webclipper/popup/src/App.js
@@ -7,6 +7,20 @@ import led_orange from './led_orange.png';
const { connect } = require('react-redux');
const { bridge } = require('./bridge');
+function commandUserString(command) {
+ const s = [];
+
+ if (command.name === 'simplifiedPageHtml') s.push('Simplified page');
+ if (command.name === 'completePageHtml') s.push('Complete page');
+ if (command.name === 'selectedHtml') s.push('Selection');
+ if (command.name === 'pageUrl') s.push('URL only');
+
+ const p = command.preProcessFor ? command.preProcessFor : 'markdown';
+ s.push('(' + p + ')');
+
+ return s.join(' ');
+}
+
class PreviewComponent extends React.PureComponent {
constructor() {
@@ -17,7 +31,7 @@ class PreviewComponent extends React.PureComponent {
componentDidMount() {
if (!this.bodyRef.current) return;
-
+
// Because the text size is made twice smaller with CSS, we need
// to also reduce the size of the images
const imgs = this.bodyRef.current.getElementsByTagName('img');
@@ -32,6 +46,7 @@ class PreviewComponent extends React.PureComponent {
);
@@ -84,6 +99,14 @@ class AppComponent extends Component {
this.clipComplete_click = () => {
bridge().sendCommandToActiveTab({
name: 'completePageHtml',
+ preProcessFor: 'markdown',
+ });
+ }
+
+ this.clipCompleteHtml_click = () => {
+ bridge().sendCommandToActiveTab({
+ name: 'completePageHtml',
+ preProcessFor: 'html',
});
}
@@ -259,6 +282,7 @@ class AppComponent extends Component {
title={content.title}
body_html={content.body_html}
onTitleChange={this.contentTitle_change}
+ command={content.source_command}
/>
}
@@ -360,6 +384,7 @@ class AppComponent extends Component {
- {simplifiedPageButtonLabel}
- Clip complete page
+ - Clip complete page (HTML) (Beta)
- Clip selection
- Clip screenshot
- Clip URL
diff --git a/Clipper/joplin-webclipper/popup/src/bridge.js b/Clipper/joplin-webclipper/popup/src/bridge.js
index 36a1597b5..03c219c9d 100644
--- a/Clipper/joplin-webclipper/popup/src/bridge.js
+++ b/Clipper/joplin-webclipper/popup/src/bridge.js
@@ -35,6 +35,9 @@ class Bridge {
tags: command.tags || '',
image_sizes: command.image_sizes || {},
anchor_names: command.anchor_names || [],
+ source_command: command.source_command,
+ convert_to: command.convert_to,
+ stylesheets: command.stylesheets,
};
this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content });
diff --git a/ElectronClient/app/gui/note-viewer/index.html b/ElectronClient/app/gui/note-viewer/index.html
index 3e7e290b4..120189e0c 100644
--- a/ElectronClient/app/gui/note-viewer/index.html
+++ b/ElectronClient/app/gui/note-viewer/index.html
@@ -9,6 +9,9 @@
}
#content {
+ /* Needs this in case the content contains elements with absolute positioning */
+ /* Without this they would just stay at a fixed position when scrolling */
+ position: relative;
overflow-y: auto;
height: 100%;
padding-left: 10px;
diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json
index 60366142f..8a818eee5 100644
--- a/ElectronClient/app/package-lock.json
+++ b/ElectronClient/app/package-lock.json
@@ -154,9 +154,9 @@
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
- "version": "5.7.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
- "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
+ "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
},
"acorn-globals": {
"version": "4.3.2",
@@ -165,13 +165,6 @@
"requires": {
"acorn": "^6.0.1",
"acorn-walk": "^6.0.1"
- },
- "dependencies": {
- "acorn": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.0.tgz",
- "integrity": "sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw=="
- }
}
},
"acorn-walk": {
@@ -1260,6 +1253,15 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
"integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
},
+ "camel-case": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
+ "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
+ "requires": {
+ "no-case": "^2.2.0",
+ "upper-case": "^1.1.1"
+ }
+ },
"camelcase": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
@@ -1382,6 +1384,21 @@
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz",
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q=="
},
+ "clean-css": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
+ "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
+ "requires": {
+ "source-map": "~0.6.0"
+ },
+ "dependencies": {
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
"cli-boxes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
@@ -1712,18 +1729,6 @@
"abab": "^2.0.0",
"whatwg-mimetype": "^2.2.0",
"whatwg-url": "^7.0.0"
- },
- "dependencies": {
- "whatwg-url": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
- "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
- "requires": {
- "lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
- }
- }
}
},
"debug": {
@@ -2400,8 +2405,7 @@
"fast-deep-equal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
- "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
- "dev": true
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
@@ -3434,6 +3438,11 @@
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+ },
"highlight.js": {
"version": "9.15.6",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.6.tgz",
@@ -3473,6 +3482,27 @@
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
"integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
},
+ "html-minifier": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz",
+ "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==",
+ "requires": {
+ "camel-case": "^3.0.0",
+ "clean-css": "^4.2.1",
+ "commander": "^2.19.0",
+ "he": "^1.2.0",
+ "param-case": "^2.1.1",
+ "relateurl": "^0.2.7",
+ "uglify-js": "^3.5.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
+ }
+ }
+ },
"http-errors": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz",
@@ -3579,6 +3609,11 @@
"integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
"dev": true
},
+ "ip-regex": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+ "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+ },
"is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
@@ -3805,6 +3840,69 @@
"css": "^2.2.4",
"html-entities": "^1.2.1",
"jsdom": "^11.9.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "5.7.3",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
+ "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
+ },
+ "jsdom": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
+ "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "requires": {
+ "abab": "^2.0.0",
+ "acorn": "^5.5.3",
+ "acorn-globals": "^4.1.0",
+ "array-equal": "^1.0.0",
+ "cssom": ">= 0.3.2 < 0.4.0",
+ "cssstyle": "^1.0.0",
+ "data-urls": "^1.0.0",
+ "domexception": "^1.0.1",
+ "escodegen": "^1.9.1",
+ "html-encoding-sniffer": "^1.0.2",
+ "left-pad": "^1.3.0",
+ "nwsapi": "^2.0.7",
+ "parse5": "4.0.0",
+ "pn": "^1.1.0",
+ "request": "^2.87.0",
+ "request-promise-native": "^1.0.5",
+ "sax": "^1.2.4",
+ "symbol-tree": "^3.2.2",
+ "tough-cookie": "^2.3.4",
+ "w3c-hr-time": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "whatwg-encoding": "^1.0.3",
+ "whatwg-mimetype": "^2.1.0",
+ "whatwg-url": "^6.4.1",
+ "ws": "^5.2.0",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
+ "parse5": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
+ "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ },
+ "whatwg-url": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
+ "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^1.0.1",
+ "webidl-conversions": "^4.0.2"
+ }
+ },
+ "ws": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "requires": {
+ "async-limiter": "~1.0.0"
+ }
+ }
}
},
"joplin-turndown-plugin-gfm": {
@@ -3834,36 +3932,161 @@
"optional": true
},
"jsdom": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz",
- "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==",
+ "version": "15.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz",
+ "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==",
"requires": {
"abab": "^2.0.0",
- "acorn": "^5.5.3",
- "acorn-globals": "^4.1.0",
+ "acorn": "^6.1.1",
+ "acorn-globals": "^4.3.2",
"array-equal": "^1.0.0",
- "cssom": ">= 0.3.2 < 0.4.0",
- "cssstyle": "^1.0.0",
- "data-urls": "^1.0.0",
+ "cssom": "^0.3.6",
+ "cssstyle": "^1.2.2",
+ "data-urls": "^1.1.0",
"domexception": "^1.0.1",
- "escodegen": "^1.9.1",
+ "escodegen": "^1.11.1",
"html-encoding-sniffer": "^1.0.2",
- "left-pad": "^1.3.0",
- "nwsapi": "^2.0.7",
- "parse5": "4.0.0",
+ "nwsapi": "^2.1.4",
+ "parse5": "5.1.0",
"pn": "^1.1.0",
- "request": "^2.87.0",
- "request-promise-native": "^1.0.5",
- "sax": "^1.2.4",
+ "request": "^2.88.0",
+ "request-promise-native": "^1.0.7",
+ "saxes": "^3.1.9",
"symbol-tree": "^3.2.2",
- "tough-cookie": "^2.3.4",
+ "tough-cookie": "^3.0.1",
"w3c-hr-time": "^1.0.1",
+ "w3c-xmlserializer": "^1.1.2",
"webidl-conversions": "^4.0.2",
- "whatwg-encoding": "^1.0.3",
- "whatwg-mimetype": "^2.1.0",
- "whatwg-url": "^6.4.1",
- "ws": "^5.2.0",
+ "whatwg-encoding": "^1.0.5",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^7.0.0",
+ "ws": "^7.0.0",
"xml-name-validator": "^3.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.10.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz",
+ "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+ "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ },
+ "har-validator": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+ "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+ "requires": {
+ "ajv": "^6.5.5",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+ },
+ "request": {
+ "version": "2.88.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+ "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "dependencies": {
+ "tough-cookie": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+ "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
+ "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
+ },
+ "tough-cookie": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
+ "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
+ "requires": {
+ "ip-regex": "^2.1.0",
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ }
+ }
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+ "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
+ }
}
},
"jsesc": {
@@ -4115,6 +4338,11 @@
"signal-exit": "^3.0.0"
}
},
+ "lower-case": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
+ "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
+ },
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -4474,6 +4702,14 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
+ "no-case": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
+ "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
+ "requires": {
+ "lower-case": "^1.1.1"
+ }
+ },
"node-abi": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.7.1.tgz",
@@ -4924,6 +5160,14 @@
"semver": "^5.1.0"
}
},
+ "param-case": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
+ "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
+ "requires": {
+ "no-case": "^2.2.0"
+ }
+ },
"parse-color": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/parse-color/-/parse-color-1.0.0.tgz",
@@ -4983,9 +5227,9 @@
}
},
"parse5": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
- "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA=="
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+ "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ=="
},
"path-exists": {
"version": "3.0.0",
@@ -5157,6 +5401,11 @@
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
"dev": true
},
+ "psl": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz",
+ "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA=="
+ },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -5595,6 +5844,11 @@
"rc": "^1.0.1"
}
},
+ "relateurl": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
+ "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
+ },
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -5778,6 +6032,14 @@
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
+ "saxes": {
+ "version": "3.1.11",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
+ "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
+ "requires": {
+ "xmlchars": "^2.1.1"
+ }
+ },
"scheduler": {
"version": "0.13.6",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz",
@@ -6371,6 +6633,27 @@
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.5.tgz",
"integrity": "sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg=="
},
+ "uglify-js": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
+ "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
+ "requires": {
+ "commander": "~2.20.0",
+ "source-map": "~0.6.1"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.20.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+ "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ }
+ }
+ },
"uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
@@ -6472,11 +6755,15 @@
}
}
},
+ "upper-case": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
+ "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
+ },
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
- "dev": true,
"requires": {
"punycode": "^2.1.0"
}
@@ -6568,6 +6855,16 @@
"browser-process-hrtime": "^0.1.2"
}
},
+ "w3c-xmlserializer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
+ "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+ "requires": {
+ "domexception": "^1.0.1",
+ "webidl-conversions": "^4.0.2",
+ "xml-name-validator": "^3.0.0"
+ }
+ },
"wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
@@ -6611,9 +6908,9 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz",
- "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
+ "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
"requires": {
"lodash.sortby": "^4.7.0",
"tr46": "^1.0.1",
@@ -6716,11 +7013,11 @@
}
},
"ws": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
- "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.0.tgz",
+ "integrity": "sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g==",
"requires": {
- "async-limiter": "~1.0.0"
+ "async-limiter": "^1.0.0"
}
},
"xdg-basedir": {
@@ -6756,6 +7053,11 @@
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
"dev": true
},
+ "xmlchars": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.1.1.tgz",
+ "integrity": "sha512-7hew1RPJ1iIuje/Y01bGD/mXokXxegAgVS+e+E0wSi2ILHQkYAH1+JXARwTjZSM4Z4Z+c73aKspEcqj+zPPL/w=="
+ },
"xmldom": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json
index 50e1a8350..2e1df3233 100644
--- a/ElectronClient/app/package.json
+++ b/ElectronClient/app/package.json
@@ -100,9 +100,11 @@
"fs-extra": "^5.0.0",
"highlight.js": "^9.15.6",
"html-entities": "^1.2.1",
+ "html-minifier": "^4.0.0",
"image-type": "^3.0.0",
"joplin-turndown": "^4.0.17",
"joplin-turndown-plugin-gfm": "^1.0.8",
+ "jsdom": "^15.1.1",
"jssha": "^2.3.1",
"katex": "^0.10.0",
"levenshtein": "^1.0.5",
diff --git a/ReactNativeClient/lib/MdToHtml/rules/html_image.js b/ReactNativeClient/lib/MdToHtml/rules/html_image.js
index 6e3754f0d..da8dfd1fa 100644
--- a/ReactNativeClient/lib/MdToHtml/rules/html_image.js
+++ b/ReactNativeClient/lib/MdToHtml/rules/html_image.js
@@ -33,7 +33,7 @@ function installRule(markdownIt, mdOptions, ruleOptions) {
return self.renderToken(tokens, idx, options);
};
- const imageRegex = //
+ const imageRegex = //gi
const handleImageTags = function(defaultRender) {
return function(tokens, idx, options, env, self) {
diff --git a/ReactNativeClient/lib/htmlUtils.js b/ReactNativeClient/lib/htmlUtils.js
new file mode 100644
index 000000000..a7e7a142d
--- /dev/null
+++ b/ReactNativeClient/lib/htmlUtils.js
@@ -0,0 +1,45 @@
+const jsdom = require("jsdom");
+const { JSDOM } = jsdom;
+
+const htmlUtils = {
+
+ extractImageUrls(html) {
+ if (!html) return [];
+
+ const dom = new JSDOM(html);
+ const imgs = dom.window.document.getElementsByTagName('img');
+ const output = [];
+
+ for (const img of imgs) {
+ const src = img.getAttribute('src');
+ if (!src) continue;
+ output.push(src);
+ }
+
+ return output;
+ },
+
+ replaceImageUrls(html, callback) {
+ if (!html) return '';
+
+ const dom = new JSDOM(html);
+ const doc = dom.window.document;
+ const imgs = doc.getElementsByTagName('img');
+
+ for (const img of imgs) {
+ const src = img.getAttribute('src');
+ const newSrc = callback(src);
+ img.setAttribute('src', newSrc);
+ }
+
+ // This function returns the head and body but without the and
+ // tag, which for our purpose are not needed and can cause issues when present.
+ const output = [];
+ if (doc.head) output.push(doc.head.innerHTML);
+ if (doc.body) output.push(doc.body.innerHTML);
+ return output.join('\n');
+ },
+
+};
+
+module.exports = htmlUtils;
\ No newline at end of file
diff --git a/ReactNativeClient/lib/joplin-database.js b/ReactNativeClient/lib/joplin-database.js
index bce17da21..c41e08f44 100644
--- a/ReactNativeClient/lib/joplin-database.js
+++ b/ReactNativeClient/lib/joplin-database.js
@@ -303,7 +303,7 @@ class JoplinDatabase extends Database {
// must be set in the synchronizer too.
// Note: v16 and v17 don't do anything. They were used to debug an issue.
- const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23];
+ const existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24];
let currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);
@@ -634,6 +634,10 @@ class JoplinDatabase extends Database {
queries.push('CREATE UNIQUE INDEX key_values_key ON key_values (key)');
}
+ if (targetVersion == 24) {
+ queries.push('ALTER TABLE notes ADD COLUMN `markup_language` INT NOT NULL DEFAULT 1'); // 1: Markdown, 2: HTML
+ }
+
queries.push({ sql: 'UPDATE version SET version = ?', params: [targetVersion] });
try {
diff --git a/ReactNativeClient/lib/markupLanguageUtils.js b/ReactNativeClient/lib/markupLanguageUtils.js
new file mode 100644
index 000000000..c56a24d65
--- /dev/null
+++ b/ReactNativeClient/lib/markupLanguageUtils.js
@@ -0,0 +1,21 @@
+const markdownUtils = require('lib/markdownUtils');
+const htmlUtils = require('lib/htmlUtils');
+const Note = require('lib/models/Note');
+
+class MarkupLanguageUtils {
+
+ lib_(language) {
+ if (language === Note.MARKUP_LANGUAGE_HTML) return htmlUtils;
+ if (language === Note.MARKUP_LANGUAGE_MARKDOWN) return markdownUtils;
+ throw new Error('Unsupported markup language: ' + language);
+ }
+
+ extractImageUrls(language, text) {
+ return this.lib_(language).extractImageUrls(text);
+ }
+
+}
+
+const markupLanguageUtils = new MarkupLanguageUtils();
+
+module.exports = markupLanguageUtils;
\ No newline at end of file
diff --git a/ReactNativeClient/lib/models/Note.js b/ReactNativeClient/lib/models/Note.js
index 42b5cb79e..f284071b1 100644
--- a/ReactNativeClient/lib/models/Note.js
+++ b/ReactNativeClient/lib/models/Note.js
@@ -634,4 +634,7 @@ class Note extends BaseItem {
Note.updateGeolocationEnabled_ = true;
Note.geolocationUpdating_ = false;
+Note.MARKUP_LANGUAGE_MARKDOWN = 1;
+Note.MARKUP_LANGUAGE_HTML = 2;
+
module.exports = Note;
\ No newline at end of file
diff --git a/ReactNativeClient/lib/services/rest/Api.js b/ReactNativeClient/lib/services/rest/Api.js
index 0de139809..d262a30bc 100644
--- a/ReactNativeClient/lib/services/rest/Api.js
+++ b/ReactNativeClient/lib/services/rest/Api.js
@@ -7,6 +7,8 @@ const BaseItem = require('lib/models/BaseItem');
const BaseModel = require('lib/BaseModel');
const Setting = require('lib/models/Setting');
const markdownUtils = require('lib/markdownUtils');
+const htmlUtils = require('lib/htmlUtils');
+const markupLanguageUtils = require('lib/markupLanguageUtils');
const mimeUtils = require('lib/mime-utils.js').mime;
const { Logger } = require('lib/logger.js');
const md5 = require('md5');
@@ -369,7 +371,7 @@ class Api {
let note = await this.requestNoteToNote_(requestNote);
- const imageUrls = markdownUtils.extractImageUrls(note.body);
+ const imageUrls = markupLanguageUtils.extractImageUrls(note.markup_language, note.body);
this.logger().info('Request (' + requestId + '): Downloading images: ' + imageUrls.length);
@@ -379,7 +381,7 @@ class Api {
result = await this.createResourcesFromPaths_(result);
await this.removeTempFiles_(result);
- note.body = this.replaceImageUrlsByResources_(note.body, result, imageSizes);
+ note.body = this.replaceImageUrlsByResources_(note.markup_language, note.body, result, imageSizes);
this.logger().info('Request (' + requestId + '): Saving note...');
@@ -431,17 +433,30 @@ class Api {
if (requestNote.id) output.id = requestNote.id;
if (requestNote.body_html) {
- // Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed
- // when getting the content from elsewhere. So here wrap it - it won't change anything to the final
- // rendering but it makes sure everything will be parsed.
- output.body = await this.htmlToMdParser().parse('' + requestNote.body_html + '
', {
- baseUrl: requestNote.base_url ? requestNote.base_url : '',
- anchorNames: requestNote.anchor_names ? requestNote.anchor_names : [],
- });
+ if (requestNote.convert_to === 'html') {
+ const style = await this.buildNoteStyleSheet_(requestNote.stylesheets);
+ const styleTag = style.length ? '' + '\n' : '';
- // Note: to save the note as HTML, use the code below:
- // const minify = require('html-minifier').minify;
- // output.body = minify(requestNote.body_html, { collapseWhitespace: true });
+ const minify = require('html-minifier').minify;
+ output.body = minify(styleTag + requestNote.body_html, {
+ // Remove all spaces and, especially, newlines from tag attributes, as that would
+ // break the rendering.
+ customAttrCollapse: /.*/,
+ // Need to remove all whitespaces because whitespace at a beginning of a line
+ // means a code block in Markdown.
+ collapseWhitespace: true,
+ });
+ output.markup_language = Note.MARKUP_LANGUAGE_HTML;
+ } else { // Convert to Markdown
+ // Parsing will not work if the HTML is not wrapped in a top level tag, which is not guaranteed
+ // when getting the content from elsewhere. So here wrap it - it won't change anything to the final
+ // rendering but it makes sure everything will be parsed.
+ output.body = await this.htmlToMdParser().parse('' + requestNote.body_html + '
', {
+ baseUrl: requestNote.base_url ? requestNote.base_url : '',
+ anchorNames: requestNote.anchor_names ? requestNote.anchor_names : [],
+ });
+ output.markup_language = Note.MARKUP_LANGUAGE_MARKDOWN;
+ }
}
if (requestNote.parent_id) {
@@ -486,6 +501,32 @@ class Api {
return newImagePath;
}
+ async buildNoteStyleSheet_(stylesheets) {
+ if (!stylesheets) return [];
+
+ const output = [];
+
+ for (const stylesheet of stylesheets) {
+ if (stylesheet.type === 'text') {
+ output.push(stylesheet.value);
+ } else if (stylesheet.type === 'url') {
+ try {
+ const tempPath = Setting.value('tempDir') + '/' + md5(Math.random() + '_' + Date.now()) + '.css';
+ await shim.fetchBlob(stylesheet.value, { path: tempPath, maxRetry: 1 });
+ const text = await shim.fsDriver().readFile(tempPath);
+ output.push(text);
+ await shim.fsDriver().remove(tempPath);
+ } catch (error) {
+ this.logger().warn('Cannot download stylesheet at ' + stylesheet.value, error);
+ }
+ } else {
+ throw new Error('Invalid stylesheet type: ' + stylesheet.type);
+ }
+ }
+
+ return output;
+ }
+
async downloadImage_(url, allowFileProtocolImages) {
const tempDir = Setting.value('tempDir');
@@ -571,21 +612,29 @@ class Api {
}
}
- replaceImageUrlsByResources_(md, urls, imageSizes) {
- let output = md.replace(/(!\[.*?\]\()([^\s\)]+)(.*?\))/g, (match, before, imageUrl, after) => {
- const urlInfo = urls[imageUrl];
- if (!urlInfo || !urlInfo.resource) return before + imageUrl + after;
- const imageSize = imageSizes[urlInfo.originalUrl];
- const resourceUrl = Resource.internalUrl(urlInfo.resource);
+ replaceImageUrlsByResources_(markupLanguage, md, urls, imageSizes) {
+ if (markupLanguage === Note.MARKUP_LANGUAGE_HTML) {
+ return htmlUtils.replaceImageUrls(md, imageUrl => {
+ const urlInfo = urls[imageUrl];
+ if (!urlInfo || !urlInfo.resource) return imageUrl;
+ return Resource.internalUrl(urlInfo.resource);
+ });
+ } else {
+ let output = md.replace(/(!\[.*?\]\()([^\s\)]+)(.*?\))/g, (match, before, imageUrl, after) => {
+ const urlInfo = urls[imageUrl];
+ if (!urlInfo || !urlInfo.resource) return before + imageUrl + after;
+ const imageSize = imageSizes[urlInfo.originalUrl];
+ const resourceUrl = Resource.internalUrl(urlInfo.resource);
- if (imageSize && (imageSize.naturalWidth !== imageSize.width || imageSize.naturalHeight !== imageSize.height)) {
- return '';
- } else {
- return before + resourceUrl + after;
- }
- });
+ if (imageSize && (imageSize.naturalWidth !== imageSize.width || imageSize.naturalHeight !== imageSize.height)) {
+ return '';
+ } else {
+ return before + resourceUrl + after;
+ }
+ });
- return output;
+ return output;
+ }
}