mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	Merge remote-tracking branch 'origin/master'
This commit is contained in:
		
							
								
								
									
										18
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
    "version": "0.2.0",
 | 
			
		||||
    "configurations": [
 | 
			
		||||
        {
 | 
			
		||||
            "type": "node",
 | 
			
		||||
            "request": "launch",
 | 
			
		||||
            "name": "start-server",
 | 
			
		||||
            "skipFiles": [
 | 
			
		||||
                "<node_internals>/**"
 | 
			
		||||
            ],
 | 
			
		||||
            "env": {
 | 
			
		||||
                "TRILIUM_ENV": "dev"
 | 
			
		||||
            },
 | 
			
		||||
            "outputCapture": "std",
 | 
			
		||||
            "program": "${workspaceFolder}/src/www"
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@@ -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');
 | 
			
		||||
 
 | 
			
		||||
@@ -96,7 +96,8 @@ export default class NoteDetailWidget extends TabAwareWidget {
 | 
			
		||||
                shrinkImages: true,
 | 
			
		||||
                textImportedAsText: true,
 | 
			
		||||
                codeImportedAsCode: true,
 | 
			
		||||
                explodeArchives: true
 | 
			
		||||
                explodeArchives: true,
 | 
			
		||||
                replaceUnderscoresWithSpaces: true
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -300,7 +300,8 @@ export default class NoteTreeWidget extends TabAwareWidget {
 | 
			
		||||
                            shrinkImages: true,
 | 
			
		||||
                            textImportedAsText: true,
 | 
			
		||||
                            codeImportedAsCode: true,
 | 
			
		||||
                            explodeArchives: true
 | 
			
		||||
                            explodeArchives: true,
 | 
			
		||||
                            replaceUnderscoresWithSpaces: true
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
};
 | 
			
		||||
@@ -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 === '.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);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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 === '.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) {
 | 
			
		||||
@@ -318,6 +296,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if(noteMeta) {
 | 
			
		||||
                const includeNoteLinks = (noteMeta.attributes || [])
 | 
			
		||||
                    .filter(attr => attr.type === 'relation' && attr.name === 'includeNoteLink');
 | 
			
		||||
 | 
			
		||||
@@ -326,6 +305,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
 | 
			
		||||
                    content = content.replace(new RegExp(link.value, "g"), getNewNoteId(link.value));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (type === 'relation-map' && noteMeta) {
 | 
			
		||||
            const relationMapLinks = (noteMeta.attributes || [])
 | 
			
		||||
@@ -366,7 +346,7 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (type === 'text') {
 | 
			
		||||
                filePath = getTextFileWithoutExtension(filePath);
 | 
			
		||||
                filePath = utils.removeTextFileExtension(filePath);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,14 @@
 | 
			
		||||
                                <input id="code-imported-as-code-checkbox" value="1" type="checkbox" checked> Import recognized code files (e.g. <code>.json</code>) as code notes if it's unclear from metadata
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label>
 | 
			
		||||
                                <input id="replace-underscores-with-spaces-checkbox" value="1" type="checkbox" checked>
 | 
			
		||||
 | 
			
		||||
                                Replace underscores with spaces in imported note names
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="modal-footer">
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user