You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Clipper: Fixes #2489: Fixed clipping of pages that contain images without sources (YouTube), and improved support for SVG graphics
This commit is contained in:
		| @@ -20,6 +20,7 @@ describe('htmlUtils', function() { | ||||
| 			['<img src="http://test.com/img.png"/>', ['http://test.com/img.png']], | ||||
| 			['<img src="http://test.com/img.png"/> <img src="http://test.com/img2.png"/>', ['http://test.com/img.png', 'http://test.com/img2.png']], | ||||
| 			['<img src="http://test.com/img.png" alt="testing"  >', ['http://test.com/img.png']], | ||||
| 			['<img src=""/> <img src="http://test.com/img2.png"/>', ['http://test.com/img2.png']], | ||||
| 			['nothing here', []], | ||||
| 			['', []], | ||||
| 		]; | ||||
|   | ||||
| @@ -39,13 +39,15 @@ describe('markdownUtils', function() { | ||||
| 			[' ', ['http://test.com/img.png', 'http://test.com/img2.png']], | ||||
| 			['', ['http://test.com/img.png']], | ||||
| 			['.png)', ['https://test.com/ohoh_(123).png']], | ||||
| 			['![nothing]() ', ['http://test.com/img.png']], | ||||
| 		]; | ||||
|  | ||||
| 		for (let i = 0; i < testCases.length; i++) { | ||||
| 			const md = testCases[i][0]; | ||||
| 			const actual = markdownUtils.extractImageUrls(md); | ||||
| 			const expected = testCases[i][1]; | ||||
|  | ||||
| 			expect(markdownUtils.extractImageUrls(md).join('')).toBe(expected.join('')); | ||||
| 			expect(actual.join(' ')).toBe(expected.join(' ')); | ||||
| 		} | ||||
| 	})); | ||||
|  | ||||
|   | ||||
| @@ -60,9 +60,17 @@ | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| 	function getJoplinClipperSvgClassName(svg) { | ||||
| 		for (const className of svg.classList) { | ||||
| 			if (className.indexOf('joplin-clipper-svg-') === 0) return className; | ||||
| 		} | ||||
| 		return ''; | ||||
| 	} | ||||
|  | ||||
| 	function getImageSizes(element, forceAbsoluteUrls = false) { | ||||
| 		const images = element.getElementsByTagName('img'); | ||||
| 		const output = {}; | ||||
|  | ||||
| 		const images = element.getElementsByTagName('img'); | ||||
| 		for (let i = 0; i < images.length; i++) { | ||||
| 			const img = images[i]; | ||||
| 			if (img.classList && img.classList.contains('joplin-clipper-hidden')) continue; | ||||
| @@ -79,6 +87,33 @@ | ||||
| 				naturalHeight: img.naturalHeight, | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		const svgs = element.getElementsByTagName('svg'); | ||||
| 		for (let i = 0; i < svgs.length; i++) { | ||||
| 			const svg = svgs[i]; | ||||
| 			if (svg.classList && svg.classList.contains('joplin-clipper-hidden')) continue; | ||||
|  | ||||
| 			const className = getJoplinClipperSvgClassName(svg);// 'joplin-clipper-svg-' + i; | ||||
|  | ||||
| 			if (!className) { | ||||
| 				console.warn('SVG without a Joplin class:', svg); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			if (!svg.classList.contains(className)) { | ||||
| 				svg.classList.add(className); | ||||
| 			} | ||||
|  | ||||
| 			const rect = svg.getBoundingClientRect(); | ||||
|  | ||||
| 			if (!output[className]) output[className] = []; | ||||
|  | ||||
| 			output[className].push({ | ||||
| 				width: rect.width, | ||||
| 				height: rect.height, | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		return output; | ||||
| 	} | ||||
|  | ||||
| @@ -152,6 +187,23 @@ | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if (nodeName === 'svg') { | ||||
| 					const className = getJoplinClipperSvgClassName(node); | ||||
| 					if (!(className in imageIndexes)) imageIndexes[className] = 0; | ||||
|  | ||||
| 					if (!imageSizes[className]) { | ||||
| 						// This seems to concern dynamic images that don't really such as Gravatar, etc. | ||||
| 						console.warn('Found an SVG for which the size had not been fetched:', className); | ||||
| 					} else { | ||||
| 						const imageSize = imageSizes[className][imageIndexes[className]]; | ||||
| 						imageIndexes[className]++; | ||||
| 						if (imageSize) { | ||||
| 							node.style.width = `${imageSize.width}px`; | ||||
| 							node.style.height = `${imageSize.height}px`; | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				cleanUpElement(convertToMarkup, node, imageSizes, imageIndexes); | ||||
| 			} | ||||
| 		} | ||||
| @@ -221,6 +273,18 @@ | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	function addSvgClass(doc) { | ||||
| 		const svgs = doc.getElementsByTagName('svg'); | ||||
| 		let svgId = 0; | ||||
|  | ||||
| 		for (const svg of svgs) { | ||||
| 			if (!getJoplinClipperSvgClassName(svg)) { | ||||
| 				svg.classList.add(`joplin-clipper-svg-${svgId}`); | ||||
| 				svgId++; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Given a document, return a <style> tag that contains all the styles | ||||
| 	// required to render the page. Not currently used but could be as an | ||||
| 	// option to clip pages as HTML. | ||||
| @@ -311,6 +375,7 @@ | ||||
| 		} else if (command.name === 'completePageHtml') { | ||||
|  | ||||
| 			hardcodePreStyles(document); | ||||
| 			addSvgClass(document); | ||||
| 			preProcessDocument(document); | ||||
| 			// Because cleanUpElement is going to modify the DOM and remove elements we don't want to work | ||||
| 			// directly on the document, so we make a copy of it first. | ||||
| @@ -325,6 +390,7 @@ | ||||
| 		} else if (command.name === 'selectedHtml') { | ||||
|  | ||||
| 			hardcodePreStyles(document); | ||||
| 			addSvgClass(document); | ||||
| 			preProcessDocument(document); | ||||
|  | ||||
| 			const container = document.createElement('div'); | ||||
|   | ||||
| @@ -24,7 +24,7 @@ class HtmlUtils { | ||||
| 			output.push(matches[2]); | ||||
| 		} | ||||
|  | ||||
| 		return output; | ||||
| 		return output.filter(url => !!url); | ||||
| 	} | ||||
|  | ||||
| 	replaceImageUrls(html, callback) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user