diff --git a/CliClient/tests/HtmlToMd.js b/CliClient/tests/HtmlToMd.js index e163a2e96..8eb9ae7ee 100644 --- a/CliClient/tests/HtmlToMd.js +++ b/CliClient/tests/HtmlToMd.js @@ -37,7 +37,7 @@ describe('HtmlToMd', function() { const htmlPath = basePath + '/' + htmlFilename; const mdPath = basePath + '/' + filename(htmlFilename) + '.md'; - // if (htmlFilename !== 'anchor_with_url_with_spaces.html') continue; + // if (htmlFilename !== 'picture.html') continue; const html = await shim.fsDriver().readFile(htmlPath); let expectedMd = await shim.fsDriver().readFile(mdPath); diff --git a/CliClient/tests/html_to_md/picture.html b/CliClient/tests/html_to_md/picture.html new file mode 100644 index 000000000..cd78469ce --- /dev/null +++ b/CliClient/tests/html_to_md/picture.html @@ -0,0 +1,47 @@ +
+ + + + + +
+ + + + + + + + + + + + + +A blood moon + +
+ + + + + +
+ + +
+ + + + + +A blood moon last occurred in July 2018, though clouds largely obscured the celestial phenomenon in the UK. +Photograph: JM F Almeida/Getty Images +
+
\ No newline at end of file diff --git a/CliClient/tests/html_to_md/picture.md b/CliClient/tests/html_to_md/picture.md new file mode 100644 index 000000000..219853fd7 --- /dev/null +++ b/CliClient/tests/html_to_md/picture.md @@ -0,0 +1,3 @@ + [![A blood moon](https://i.guim.co.uk/img/media/75583fcfe2eb74f1e89ea320355ff4156f4ade7b/0_49_3904_2342/master/3904.jpg?width=300&quality=85&auto=format&fit=max&s=1e9b643d2c109a1e271f50046eac1324)](#img-1) + +A blood moon last occurred in July 2018, though clouds largely obscured the celestial phenomenon in the UK. Photograph: JM F Almeida/Getty Images \ 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 2eb6ed6d5..feda99f8e 100644 --- a/Clipper/joplin-webclipper/content_scripts/index.js +++ b/Clipper/joplin-webclipper/content_scripts/index.js @@ -30,6 +30,21 @@ return output; } + function getImageSizes(element) { + const images = element.getElementsByTagName('img'); + const output = {}; + for (let i = 0; i < images.length; i++) { + const img = images[i]; + output[img.src] = { + width: img.width, + height: img.height, + naturalWidth: img.naturalWidth, + naturalHeight: img.naturalHeight, + }; + } + return output; + } + // Cleans up element by removing all its invisible children (which we don't want to render as Markdown) function cleanUpElement(element) { const childNodes = element.childNodes; @@ -74,7 +89,7 @@ async function prepareCommandResponse(command) { console.info('Got command: ' + command.name); - const clippedContentResponse = (title, html) => { + const clippedContentResponse = (title, html, imageSizes) => { return { name: 'clippedContent', title: title, @@ -83,6 +98,7 @@ url: location.origin + location.pathname + location.search, parent_id: command.parent_id, tags: command.tags || '', + image_sizes: imageSizes, }; } @@ -99,20 +115,20 @@ response.warning = 'Could not retrieve simplified version of page - full page has been saved instead.'; return response; } - return clippedContentResponse(article.title, article.body); + return clippedContentResponse(article.title, article.body, getImageSizes(document)); } else if (command.name === "completePageHtml") { const cleanDocument = document.body.cloneNode(true); cleanUpElement(cleanDocument); - return clippedContentResponse(pageTitle(), cleanDocument.innerHTML); + return clippedContentResponse(pageTitle(), cleanDocument.innerHTML, getImageSizes(document)); } else if (command.name === "selectedHtml") { const range = window.getSelection().getRangeAt(0); const container = document.createElement('div'); container.appendChild(range.cloneContents()); - return clippedContentResponse(pageTitle(), container.innerHTML); + return clippedContentResponse(pageTitle(), container.innerHTML, getImageSizes(document)); } else if (command.name === 'screenshot') { diff --git a/Clipper/joplin-webclipper/popup/src/bridge.js b/Clipper/joplin-webclipper/popup/src/bridge.js index ae57e1173..b976ba8ab 100644 --- a/Clipper/joplin-webclipper/popup/src/bridge.js +++ b/Clipper/joplin-webclipper/popup/src/bridge.js @@ -29,6 +29,7 @@ class Bridge { source_url: command.url, parent_id: command.parent_id, tags: command.tags || '', + image_sizes: command.image_sizes || {}, }; this.dispatch({ type: 'CLIPPED_CONTENT_SET', content: content }); diff --git a/ElectronClient/app/package-lock.json b/ElectronClient/app/package-lock.json index fc080a7c7..3b3cdddd4 100644 --- a/ElectronClient/app/package-lock.json +++ b/ElectronClient/app/package-lock.json @@ -59,16 +59,16 @@ }, "dependencies": { "acorn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.2.tgz", - "integrity": "sha512-GXmKIvbrN3TV7aVqAzVFaMW8F8wzVX7voEBRO3bDA64+EX37YSayggRJP5Xig6HYHBkWKpFg9W5gg6orklubhg==" + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.5.tgz", + "integrity": "sha512-i33Zgp3XWtmZBMNvCr4azvOFeWVw1Rk6p3hfi3LUDvIFraOMywb1kAtrbi+med14m4Xfpqm3zRZMT+c0FNE7kg==" } } }, "acorn-walk": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.0.tgz", - "integrity": "sha512-ugTb7Lq7u4GfWSqqpwE0bGyoBZNMTok/zDBXxfEG0QM50jNlGhIWjRC1pPN7bvV1anhF+bs+/gNcRw+o55Evbg==" + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" }, "ajv": { "version": "6.5.0", @@ -1720,12 +1720,12 @@ } }, "data-urls": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz", - "integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", "requires": { "abab": "^2.0.0", - "whatwg-mimetype": "^2.1.0", + "whatwg-mimetype": "^2.2.0", "whatwg-url": "^7.0.0" }, "dependencies": { @@ -3992,9 +3992,9 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "joplin-turndown": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.9.tgz", - "integrity": "sha512-8MOxX4t5Ai22muHhXPMGNoKc/AB7gSo0eUvNh6dyd6b3vcSiMIRZE8UHpMjS9ruJQ+8e+8TtJXc0nfbexeHwrA==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/joplin-turndown/-/joplin-turndown-4.0.11.tgz", + "integrity": "sha512-2oiwWX0nKYi1NVcaprSsrXQkYdGoRtPWFmnXdWQnQW44jlgjFV38B4VrgliwX5ZMq7cbx6A9IBwfXcBL2YV2NA==", "requires": { "jsdom": "^11.9.0" } @@ -4594,7 +4594,7 @@ }, "nan": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", + "resolved": "http://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" }, "nanomatch": { @@ -6651,17 +6651,17 @@ "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" }, "whatwg-encoding": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz", - "integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", "requires": { - "iconv-lite": "0.4.23" + "iconv-lite": "0.4.24" }, "dependencies": { "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -6674,9 +6674,9 @@ "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" }, "whatwg-mimetype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz", - "integrity": "sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" }, "whatwg-url": { "version": "6.5.0", diff --git a/ElectronClient/app/package.json b/ElectronClient/app/package.json index 8c2fce81b..6dfb5d709 100644 --- a/ElectronClient/app/package.json +++ b/ElectronClient/app/package.json @@ -96,7 +96,7 @@ "highlight.js": "^9.12.0", "html-entities": "^1.2.1", "image-type": "^3.0.0", - "joplin-turndown": "^4.0.9", + "joplin-turndown": "^4.0.11", "joplin-turndown-plugin-gfm": "^1.0.7", "jssha": "^2.3.1", "katex": "^0.10.0", diff --git a/ReactNativeClient/lib/MdToHtml.js b/ReactNativeClient/lib/MdToHtml.js index 52365f82c..dd9e09d7f 100644 --- a/ReactNativeClient/lib/MdToHtml.js +++ b/ReactNativeClient/lib/MdToHtml.js @@ -606,8 +606,8 @@ class MdToHtml { border-bottom: 1px solid ` + style.htmlDividerColor + `; } img { - /* width: auto; */ max-width: 100%; + height: auto; } .inline-code { border: 1px solid ` + style.htmlCodeBorderColor + `; diff --git a/ReactNativeClient/lib/services/rest/Api.js b/ReactNativeClient/lib/services/rest/Api.js index 32001467c..176b01c6a 100644 --- a/ReactNativeClient/lib/services/rest/Api.js +++ b/ReactNativeClient/lib/services/rest/Api.js @@ -323,6 +323,9 @@ class Api { if (request.method === 'POST') { const requestId = Date.now(); const requestNote = JSON.parse(request.body); + + const imageSizes = requestNote.image_sizes ? requestNote.image_sizes : {}; + let note = await this.requestNoteToNote(requestNote); const imageUrls = markdownUtils.extractImageUrls(note.body); @@ -335,7 +338,7 @@ class Api { result = await this.createResourcesFromPaths_(result); await this.removeTempFiles_(result); - note.body = this.replaceImageUrlsByResources_(note.body, result); + note.body = this.replaceImageUrlsByResources_(note.body, result, imageSizes); this.logger().info('Request (' + requestId + '): Saving note...'); @@ -455,7 +458,7 @@ class Api { return new Promise(async (resolve, reject) => { const imagePath = await this.downloadImage_(url); - if (imagePath) output[url] = { path: imagePath }; + if (imagePath) output[url] = { path: imagePath, originalUrl: url }; resolve(); }); } @@ -493,12 +496,18 @@ class Api { } } - replaceImageUrlsByResources_(md, urls) { + 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); - return before + resourceUrl + after; + + if (imageSize && (imageSize.naturalWidth !== imageSize.width || imageSize.naturalHeight !== imageSize.height)) { + return ''; + } else { + return before + resourceUrl + after; + } }); return output;