You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Desktop, Cli: Fixes #5325: Fixed file paths when exporting as HTML
This commit is contained in:
		| @@ -75,7 +75,8 @@ export function friendlySafeFilename(e: string, maxLength: number = null, preser | ||||
| 	let fileExt = ''; | ||||
|  | ||||
| 	if (preserveExtension) { | ||||
| 		fileExt = `.${safeFileExtension(fileExtension(e))}`; | ||||
| 		const baseExt = fileExtension(e); | ||||
| 		fileExt = baseExt ? `.${safeFileExtension(baseExt)}` : ''; | ||||
| 		e = filename(e); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,7 @@ describe('pathUtils', function() { | ||||
| 		expect(!!friendlySafeFilename('...')).toBe(true); | ||||
|  | ||||
| 		// Check that it optionally handles filenames with extension | ||||
| 		expect(friendlySafeFilename('file', null, true)).toBe('file'); | ||||
| 		expect(friendlySafeFilename('  testing.md', null, true)).toBe('testing.md'); | ||||
| 		expect(friendlySafeFilename('testing.safe??ext##', null, true)).toBe('testing.safeext'); | ||||
| 		expect(friendlySafeFilename('thatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylongthatsreallylong.md', null, true)).toBe('thatsreallylongthatsreallylongthatsreallylongthats.md'); | ||||
|   | ||||
| @@ -6,6 +6,7 @@ import Note from '../../models/Note'; | ||||
| import * as fs from 'fs-extra'; | ||||
| import { tempFilePath } from '../../testing/test-utils'; | ||||
| import { ContentScriptType } from '../../services/plugins/api/types'; | ||||
| import { FileSystemItem } from './types'; | ||||
|  | ||||
| async function recreateExportDir() { | ||||
| 	const dir = exportDir(); | ||||
| @@ -13,7 +14,7 @@ async function recreateExportDir() { | ||||
| 	await fs.mkdirp(dir); | ||||
| } | ||||
|  | ||||
| describe('services_InteropService_Exporter_Html', function() { | ||||
| describe('interop/InteropService_Exporter_Html', function() { | ||||
|  | ||||
| 	beforeEach(async (done) => { | ||||
| 		await setupDatabaseAndSynchronizer(1); | ||||
| @@ -37,6 +38,29 @@ describe('services_InteropService_Exporter_Html', function() { | ||||
| 		expect(content).toContain('<strong>ma note</strong>'); | ||||
| 	})); | ||||
|  | ||||
| 	test('should export HTML directory', (async () => { | ||||
| 		const service = InteropService.instance(); | ||||
| 		const folder1 = await Folder.save({ title: 'folder1' }); | ||||
| 		await Folder.save({ title: 'folder2' }); | ||||
| 		await Note.save({ title: 'note1', parent_id: folder1.id }); | ||||
| 		await Note.save({ title: 'note2', parent_id: folder1.id }); | ||||
|  | ||||
| 		const dir = exportDir(); | ||||
| 		await service.export({ | ||||
| 			path: dir, | ||||
| 			format: 'html', | ||||
| 			target: FileSystemItem.Directory, | ||||
| 		}); | ||||
|  | ||||
| 		const rootDirs = await fs.readdir(dir); | ||||
| 		rootDirs.sort(); | ||||
| 		expect(rootDirs).toEqual(['folder1', 'folder2']); | ||||
|  | ||||
| 		const files = await fs.readdir(`${dir}/${rootDirs[0]}`); | ||||
| 		expect(files).toContain('note1.html'); | ||||
| 		expect(files).toContain('note2.html'); | ||||
| 	})); | ||||
|  | ||||
| 	test('should export plugin assets', (async () => { | ||||
| 		const service = InteropService.instance(); | ||||
| 		const folder1 = await Folder.save({ title: 'folder1' }); | ||||
|   | ||||
| @@ -8,9 +8,8 @@ import Setting from '../../models/Setting'; | ||||
| import { MarkupToHtml } from '@joplin/renderer'; | ||||
| import { ResourceEntity } from '../database/types'; | ||||
| import { contentScriptsToRendererRules } from '../plugins/utils/loadContentScripts'; | ||||
| const { basename, friendlySafeFilename, rtrimSlashes } = require('../../path-utils'); | ||||
| import { basename, friendlySafeFilename, rtrimSlashes, dirname } from '../../path-utils'; | ||||
| const { themeStyle } = require('../../theme'); | ||||
| const { dirname } = require('../../path-utils'); | ||||
| const { escapeHtml } = require('../../string-utils.js'); | ||||
| const { assetsToHeaders } = require('@joplin/renderer'); | ||||
|  | ||||
| @@ -53,7 +52,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte | ||||
| 				if (pathPart) { | ||||
| 					output = `${pathPart}/${output}`; | ||||
| 				} else { | ||||
| 					output = `${friendlySafeFilename(item.title, null, true)}/${output}`; | ||||
| 					output = `${friendlySafeFilename(item.title)}/${output}`; | ||||
| 					output = await shim.fsDriver().findUniqueFilename(output); | ||||
| 				} | ||||
| 			} | ||||
| @@ -98,7 +97,7 @@ export default class InteropService_Exporter_Html extends InteropService_Exporte | ||||
| 			if (this.filePath_) { | ||||
| 				noteFilePath = this.filePath_; | ||||
| 			} else { | ||||
| 				noteFilePath = `${dirPath}/${friendlySafeFilename(item.title, null, true)}.html`; | ||||
| 				noteFilePath = `${dirPath}/${friendlySafeFilename(item.title)}.html`; | ||||
| 				noteFilePath = await shim.fsDriver().findUniqueFilename(noteFilePath); | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ const Resource = require('../../models/Resource').default; | ||||
| const Note = require('../../models/Note').default; | ||||
| const shim = require('../../shim').default; | ||||
|  | ||||
| describe('services_InteropService_Exporter_Md', function() { | ||||
| describe('interop/InteropService_Exporter_Md', function() { | ||||
|  | ||||
| 	beforeEach(async (done) => { | ||||
| 		await setupDatabaseAndSynchronizer(1); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user