From ac10701b55242253569795bcb1a7dcc78b793432 Mon Sep 17 00:00:00 2001 From: Adam Coyne Date: Sat, 30 May 2020 16:15:00 -0500 Subject: [PATCH] Add import option to replace underscores with spaces in note names (#1064) --- src/public/app/dialogs/import.js | 5 ++++- src/public/app/widgets/note_detail.js | 3 ++- src/public/app/widgets/note_tree.js | 3 ++- src/routes/api/import.js | 3 ++- src/services/import/single.js | 16 +++++--------- src/services/import/tar.js | 30 ++++----------------------- src/services/import/zip.js | 30 ++++----------------------- src/services/utils.js | 28 ++++++++++++++++++++++++- src/views/dialogs/import.ejs | 8 +++++++ 9 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/public/app/dialogs/import.js b/src/public/app/dialogs/import.js index 4903c3935..b6ab70ad0 100644 --- a/src/public/app/dialogs/import.js +++ b/src/public/app/dialogs/import.js @@ -12,6 +12,7 @@ const $shrinkImagesCheckbox = $("#shrink-images-checkbox"); const $textImportedAsTextCheckbox = $("#text-imported-as-text-checkbox"); const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox"); const $explodeArchivesCheckbox = $("#explode-archives-checkbox"); +const $replaceUnderscoresWithSpacesCheckbox = $("#replace-underscores-with-spaces-checkbox"); let parentNoteId = null; @@ -23,6 +24,7 @@ export async function showDialog(noteId) { $textImportedAsTextCheckbox.prop("checked", true); $codeImportedAsCodeCheckbox.prop("checked", true); $explodeArchivesCheckbox.prop("checked", true); + $replaceUnderscoresWithSpacesCheckbox.prop("checked", true); parentNoteId = noteId; @@ -48,7 +50,8 @@ async function importIntoNote(parentNoteId) { shrinkImages: boolToString($shrinkImagesCheckbox), textImportedAsText: boolToString($textImportedAsTextCheckbox), codeImportedAsCode: boolToString($codeImportedAsCodeCheckbox), - explodeArchives: boolToString($explodeArchivesCheckbox) + explodeArchives: boolToString($explodeArchivesCheckbox), + replaceUnderscoresWithSpaces: boolToString($replaceUnderscoresWithSpacesCheckbox) }; $dialog.modal('hide'); diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index 1fca3ae91..66fdb8d44 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -96,7 +96,8 @@ export default class NoteDetailWidget extends TabAwareWidget { shrinkImages: true, textImportedAsText: true, codeImportedAsCode: true, - explodeArchives: true + explodeArchives: true, + replaceUnderscoresWithSpaces: true }); }); diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index 1739b01ae..e4f56ce29 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -300,7 +300,8 @@ export default class NoteTreeWidget extends TabAwareWidget { shrinkImages: true, textImportedAsText: true, codeImportedAsCode: true, - explodeArchives: true + explodeArchives: true, + replaceUnderscoresWithSpaces: true }); } else { diff --git a/src/routes/api/import.js b/src/routes/api/import.js index f0529e888..da8969b78 100644 --- a/src/routes/api/import.js +++ b/src/routes/api/import.js @@ -21,7 +21,8 @@ async function importToBranch(req) { shrinkImages: req.body.shrinkImages !== 'false', textImportedAsText: req.body.textImportedAsText !== 'false', codeImportedAsCode: req.body.codeImportedAsCode !== 'false', - explodeArchives: req.body.explodeArchives !== 'false' + explodeArchives: req.body.explodeArchives !== 'false', + replaceUnderscoresWithSpaces: req.body.replaceUnderscoresWithSpaces !== 'false' }; const file = req.file; diff --git a/src/services/import/single.js b/src/services/import/single.js index 983cca355..55b64ad50 100644 --- a/src/services/import/single.js +++ b/src/services/import/single.js @@ -4,8 +4,8 @@ const noteService = require('../../services/notes'); const imageService = require('../../services/image'); const protectedSessionService = require('../protected_session'); const commonmark = require('commonmark'); -const path = require('path'); const mimeService = require('./mime'); +const utils = require('../../services/utils'); async function importSingleFile(taskContext, file, parentNote) { const mime = mimeService.getMime(file.originalname) || file.mimetype; @@ -59,7 +59,7 @@ async function importFile(taskContext, file, parentNote) { } async function importCodeNote(taskContext, file, parentNote) { - const title = getFileNameWithoutExtension(file.originalname); + const title = utils.getNoteTitle(file.originalname, taskContext.data.replaceUnderscoresWithSpaces); const content = file.buffer.toString("UTF-8"); const detectedMime = mimeService.getMime(file.originalname) || file.mimetype; const mime = mimeService.normalizeMimeType(detectedMime); @@ -79,7 +79,7 @@ async function importCodeNote(taskContext, file, parentNote) { } async function importPlainText(taskContext, file, parentNote) { - const title = getFileNameWithoutExtension(file.originalname); + const title = utils.getNoteTitle(file.originalname, taskContext.data.replaceUnderscoresWithSpaces); const plainTextContent = file.buffer.toString("UTF-8"); const htmlContent = convertTextToHtml(plainTextContent); @@ -124,7 +124,7 @@ async function importMarkdown(taskContext, file, parentNote) { const parsed = reader.parse(markdownContent); const htmlContent = writer.render(parsed); - const title = getFileNameWithoutExtension(file.originalname); + const title = utils.getNoteTitle(file.originalname, taskContext.data.replaceUnderscoresWithSpaces); const {note} = await noteService.createNewNote({ parentNoteId: parentNote.noteId, @@ -141,7 +141,7 @@ async function importMarkdown(taskContext, file, parentNote) { } async function importHtml(taskContext, file, parentNote) { - const title = getFileNameWithoutExtension(file.originalname); + const title = utils.getNoteTitle(file.originalname, taskContext.data.replaceUnderscoresWithSpaces); const content = file.buffer.toString("UTF-8"); const {note} = await noteService.createNewNote({ @@ -158,12 +158,6 @@ async function importHtml(taskContext, file, parentNote) { return note; } -function getFileNameWithoutExtension(filePath) { - const extension = path.extname(filePath); - - return filePath.substr(0, filePath.length - extension.length); -} - module.exports = { importSingleFile }; \ No newline at end of file diff --git a/src/services/import/tar.js b/src/services/import/tar.js index 7c607d0c5..18bccb3dd 100644 --- a/src/services/import/tar.js +++ b/src/services/import/tar.js @@ -102,19 +102,8 @@ async function importTar(taskContext, fileBuffer, importRootNote) { return parentNoteId; } - function getNoteTitle(filePath, noteMeta) { - if (noteMeta) { - return noteMeta.title; - } - else { - const basename = path.basename(filePath); - - return getTextFileWithoutExtension(basename); - } - } - function getNoteId(noteMeta, filePath) { - const filePathNoExt = getTextFileWithoutExtension(filePath); + const filePathNoExt = utils.removeTextFileExtension(filePath); if (filePathNoExt in createdPaths) { return createdPaths[filePathNoExt]; @@ -168,7 +157,7 @@ async function importTar(taskContext, fileBuffer, importRootNote) { const { parentNoteMeta, noteMeta } = getMeta(filePath); const noteId = getNoteId(noteMeta, filePath); - const noteTitle = getNoteTitle(filePath, noteMeta); + const noteTitle = utils.getNoteTitle(filePath, taskContext.data.replaceUnderscoresWithSpaces, noteMeta); const parentNoteId = await getParentNoteId(filePath, parentNoteMeta); let note = await repository.getNote(noteId); @@ -198,17 +187,6 @@ async function importTar(taskContext, fileBuffer, importRootNote) { return noteId; } - function getTextFileWithoutExtension(filePath) { - const extension = path.extname(filePath).toLowerCase(); - - if (extension === '.md' || extension === '.markdown' || extension === '.html') { - return filePath.substr(0, filePath.length - extension.length); - } - else { - return filePath; - } - } - function getNoteIdFromRelativeUrl(url, filePath) { while (url.startsWith("./")) { url = url.substr(2); @@ -267,7 +245,7 @@ async function importTar(taskContext, fileBuffer, importRootNote) { content = mdWriter.render(parsed); } - const noteTitle = getNoteTitle(filePath, noteMeta); + const noteTitle = utils.getNoteTitle(filePath, taskContext.data.replaceUnderscoresWithSpaces, noteMeta); if (type === 'text') { function isUrlAbsolute(url) { @@ -348,7 +326,7 @@ async function importTar(taskContext, fileBuffer, importRootNote) { } if (type === 'text') { - filePath = getTextFileWithoutExtension(filePath); + filePath = utils.removeTextFileExtension(filePath); } } diff --git a/src/services/import/zip.js b/src/services/import/zip.js index 7399f96b9..328d579d4 100644 --- a/src/services/import/zip.js +++ b/src/services/import/zip.js @@ -100,23 +100,12 @@ async function importZip(taskContext, fileBuffer, importRootNote) { return parentNoteId; } - function getNoteTitle(filePath, noteMeta) { - if (noteMeta) { - return noteMeta.title; - } - else { - const basename = path.basename(filePath); - - return getTextFileWithoutExtension(basename); - } - } - function getNoteId(noteMeta, filePath) { if (noteMeta) { return getNewNoteId(noteMeta.noteId); } - const filePathNoExt = getTextFileWithoutExtension(filePath); + const filePathNoExt = utils.removeTextFileExtension(filePath); if (filePathNoExt in createdPaths) { return createdPaths[filePathNoExt]; @@ -170,7 +159,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) { const { parentNoteMeta, noteMeta } = getMeta(filePath); const noteId = getNoteId(noteMeta, filePath); - const noteTitle = getNoteTitle(filePath, noteMeta); + const noteTitle = utils.getNoteTitle(filePath, taskContext.data.replaceUnderscoresWithSpaces, noteMeta); const parentNoteId = await getParentNoteId(filePath, parentNoteMeta); let note = await repository.getNote(noteId); @@ -202,17 +191,6 @@ async function importZip(taskContext, fileBuffer, importRootNote) { return noteId; } - function getTextFileWithoutExtension(filePath) { - const extension = path.extname(filePath).toLowerCase(); - - if (extension === '.md' || extension === '.markdown' || extension === '.html') { - return filePath.substr(0, filePath.length - extension.length); - } - else { - return filePath; - } - } - function getNoteIdFromRelativeUrl(url, filePath) { while (url.startsWith("./")) { url = url.substr(2); @@ -275,7 +253,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) { content = mdWriter.render(parsed); } - const noteTitle = getNoteTitle(filePath, noteMeta); + const noteTitle = utils.getNoteTitle(filePath, taskContext.data.replaceUnderscoresWithSpaces, noteMeta); if (type === 'text') { function isUrlAbsolute(url) { @@ -368,7 +346,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) { } if (type === 'text') { - filePath = getTextFileWithoutExtension(filePath); + filePath = utils.removeTextFileExtension(filePath); } } diff --git a/src/services/utils.js b/src/services/utils.js index 7cb02ae40..ff71e6d39 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -6,6 +6,7 @@ const unescape = require('unescape'); const escape = require('escape-html'); const sanitize = require("sanitize-filename"); const mimeTypes = require('mime-types'); +const path = require('path'); function newEntityId() { return randomString(12); @@ -209,6 +210,29 @@ function formatDownloadTitle(filename, type, mime) { } } +function removeTextFileExtension(filePath) { + const extension = path.extname(filePath).toLowerCase(); + + if (extension === '.md' || extension === '.markdown' || extension === '.html') { + return filePath.substr(0, filePath.length - extension.length); + } + else { + return filePath; + } +} + +function getNoteTitle(filePath, replaceUnderscoresWithSpaces, noteMeta) { + if (noteMeta) { + return noteMeta.title; + } else { + const basename = path.basename(removeTextFileExtension(filePath)); + if(replaceUnderscoresWithSpaces) { + return basename.replace(/_/g, ' ').trim(); + } + return basename; + } +} + module.exports = { randomSecureToken, randomString, @@ -237,5 +261,7 @@ module.exports = { isStringNote, quoteRegex, replaceAll, - formatDownloadTitle + formatDownloadTitle, + getNoteTitle, + removeTextFileExtension, }; diff --git a/src/views/dialogs/import.ejs b/src/views/dialogs/import.ejs index 3da631026..10eaed8f9 100644 --- a/src/views/dialogs/import.ejs +++ b/src/views/dialogs/import.ejs @@ -53,6 +53,14 @@ Import recognized code files (e.g. .json) as code notes if it's unclear from metadata + +
+ +