diff --git a/package.json b/package.json index c67a694b3..bf134ad96 100644 --- a/package.json +++ b/package.json @@ -13,10 +13,10 @@ "url": "https://github.com/zadam/trilium.git" }, "scripts": { - "start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev node ./src/www", - "start-server-no-dir": "cross-env TRILIUM_ENV=dev node ./src/www", - "start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev electron --inspect=5858 .", - "start-electron-no-dir": "cross-env TRILIUM_ENV=dev electron --inspect=5858 .", + "start-server": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 node ./src/www", + "start-server-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 node ./src/www", + "start-electron": "cross-env TRILIUM_DATA_DIR=./data TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 TRILIUM_ENV=dev electron --inspect=5858 .", + "start-electron-no-dir": "cross-env TRILIUM_ENV=dev TRILIUM_SYNC_SERVER_HOST=http://tsyncserver:4000 electron --inspect=5858 .", "switch-server": "rm -rf ./node_modules/better-sqlite3 && npm install", "switch-electron": "rm -rf ./node_modules/better-sqlite3 && npm install && ./node_modules/.bin/electron-rebuild", "build-api-docs": "./bin/build-api-docs.sh", diff --git a/src/public/app/components/tab_manager.js b/src/public/app/components/tab_manager.js index 08c7da919..8f760cc95 100644 --- a/src/public/app/components/tab_manager.js +++ b/src/public/app/components/tab_manager.js @@ -477,13 +477,13 @@ export default class TabManager extends Component { this.openAndActivateEmptyTab(); } - async removeAllTabsCommand() { + async closeAllTabsCommand() { for (const ntxIdToRemove of this.mainNoteContexts.map(nc => nc.ntxId)) { await this.removeNoteContext(ntxIdToRemove); } } - async removeAllTabsExceptForThisCommand({ntxId}) { + async closeOtherTabsCommand({ntxId}) { for (const ntxIdToRemove of this.mainNoteContexts.map(nc => nc.ntxId)) { if (ntxIdToRemove !== ntxId) { await this.removeNoteContext(ntxIdToRemove); @@ -491,6 +491,10 @@ export default class TabManager extends Component { } } + async closeTabCommand({ntxId}) { + await this.removeNoteContext(ntxId); + } + async moveTabToNewWindowCommand({ntxId}) { const {notePath, hoistedNoteId} = this.getNoteContextById(ntxId); diff --git a/src/public/app/services/note_content_renderer.js b/src/public/app/services/note_content_renderer.js index 0a509af31..2fb805799 100644 --- a/src/public/app/services/note_content_renderer.js +++ b/src/public/app/services/note_content_renderer.js @@ -7,6 +7,7 @@ import openService from "./open.js"; import froca from "./froca.js"; import utils from "./utils.js"; import linkService from "./link.js"; +import treeService from "./tree.js"; let idCounter = 1; @@ -31,6 +32,17 @@ async function getRenderedContent(note, options = {}) { renderMathInElement($renderedContent[0], {trust: true}); } + + const getNoteIdFromLink = el => treeService.getNoteIdFromNotePath($(el).attr('href')); + const referenceLinks = $renderedContent.find("a.reference-link"); + const noteIdsToPrefetch = referenceLinks.map(el => getNoteIdFromLink(el)); + await froca.getNotes(noteIdsToPrefetch); + + for (const el of referenceLinks) { + const noteId = getNoteIdFromLink(el); + + await linkService.loadReferenceLinkTitle(noteId, $(el)); + } } else { await renderChildrenList($renderedContent, note); diff --git a/src/public/app/widgets/note_tree.js b/src/public/app/widgets/note_tree.js index 4f6825c94..01f1ce23b 100644 --- a/src/public/app/widgets/note_tree.js +++ b/src/public/app/widgets/note_tree.js @@ -460,7 +460,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget { if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) { const files = [...dataTransfer.files]; // chrome has issue that dataTransfer.files empties after async operation - const importService = await import('../services/import'); + const importService = await import('../services/import.js'); importService.uploadFiles(node.data.noteId, files, { safeImport: true, diff --git a/src/public/app/widgets/tab_row.js b/src/public/app/widgets/tab_row.js index a401157fc..41249650a 100644 --- a/src/public/app/widgets/tab_row.js +++ b/src/public/app/widgets/tab_row.js @@ -262,9 +262,10 @@ export default class TabRowWidget extends BasicWidget { x: e.pageX, y: e.pageY, items: [ - {title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "bx bx-window-open"}, - {title: "Close all tabs", command: "removeAllTabs", uiIcon: "bx bx-x"}, - {title: "Close all tabs except for this", command: "removeAllTabsExceptForThis", uiIcon: "bx bx-x"}, + {title: "Close", command: "closeTab", uiIcon: "bx bx-x"}, + {title: "Close other tabs", command: "closeOtherTabs", uiIcon: "bx bx-x"}, + {title: "Close all tabs", command: "closeAllTabs", uiIcon: "bx bx-x"}, + {title: "Move this tab to a new window", command: "moveTabToNewWindow", uiIcon: "bx bx-window-open"} ], selectMenuItemHandler: ({command}) => { this.triggerCommand(command, {ntxId}); diff --git a/src/public/app/widgets/type_widgets/editable_text.js b/src/public/app/widgets/type_widgets/editable_text.js index 46bf218b2..67003dc68 100644 --- a/src/public/app/widgets/type_widgets/editable_text.js +++ b/src/public/app/widgets/type_widgets/editable_text.js @@ -172,7 +172,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget { this.watchdog.editor.model.document.on('change:data', () => this.spacedUpdate.scheduleUpdate()); if (glob.isDev && ENABLE_INSPECTOR) { - await import(/* webpackIgnore: true */'../../../libraries/ckeditor/inspector'); + await import(/* webpackIgnore: true */'../../../libraries/ckeditor/inspector.js'); CKEditorInspector.attach(this.watchdog.editor); } } diff --git a/src/routes/api/sender.js b/src/routes/api/sender.js index 873f14c6f..f7ac768ca 100644 --- a/src/routes/api/sender.js +++ b/src/routes/api/sender.js @@ -2,10 +2,9 @@ const imageType = require('image-type'); const imageService = require('../../services/image'); -const dateNoteService = require('../../services/date_notes'); const noteService = require('../../services/notes'); -const attributeService = require('../../services/attributes'); -const {sanitizeAttributeName} = require("../../services/sanitize_attribute_name"); +const {sanitizeAttributeName} = require("../../services/sanitize_attribute_name.js"); +const specialNotesService = require("../../services/special_notes.js"); function uploadImage(req) { const file = req.file; @@ -16,7 +15,7 @@ function uploadImage(req) { const originalName = `Sender image.${imageType(file.buffer).ext}`; - const parentNote = dateNoteService.getDayNote(req.headers['x-local-date']); + const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']); const {note, noteId} = imageService.saveImage(parentNote.noteId, file.buffer, originalName, true); @@ -38,7 +37,7 @@ function uploadImage(req) { } function saveNote(req) { - const parentNote = dateNoteService.getDayNote(req.headers['x-local-date']); + const parentNote = specialNotesService.getInboxNote(req.headers['x-local-date']); const {note, branch} = noteService.createNewNote({ parentNoteId: parentNote.noteId, diff --git a/src/services/import/enex.js b/src/services/import/enex.js index 1cce0b6a5..5f9489189 100644 --- a/src/services/import/enex.js +++ b/src/services/import/enex.js @@ -8,13 +8,19 @@ const noteService = require("../notes"); const imageService = require("../image"); const protectedSessionService = require('../protected_session'); const htmlSanitizer = require("../html_sanitizer"); -const attributeService = require("../attributes"); -const {sanitizeAttributeName} = require("../sanitize_attribute_name"); +const {sanitizeAttributeName} = require("../sanitize_attribute_name.js"); -// date format is e.g. 20181121T193703Z +/** + * date format is e.g. 20181121T193703Z or 2013-04-14T16:19:00.000Z (Mac evernote, see #3496) + * @returns trilium date format, e.g. 2013-04-14 16:19:00.000Z + */ function parseDate(text) { - // insert - and : to make it ISO format - text = `${text.substr(0, 4)}-${text.substr(4, 2)}-${text.substr(6, 2)} ${text.substr(9, 2)}:${text.substr(11, 2)}:${text.substr(13, 2)}.000Z`; + // convert ISO format to the "20181121T193703Z" format + text = text.replace(/[-:]/g, ""); + + // insert - and : to convert it to trilium format + text = text.substr(0, 4) + "-" + text.substr(4, 2) + "-" + text.substr(6, 2) + + " " + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + ".000Z"; return text; } @@ -263,7 +269,7 @@ function importEnex(taskContext, file, parentNote) { continue; } - const mediaRegex = new RegExp(`<en-media hash="${hash}"[^>]*>`, 'g'); + const mediaRegex = new RegExp(`<en-media [^>]*hash="${hash}"[^>]*>`, 'g'); resource.mime = resource.mime || "application/octet-stream"; diff --git a/src/services/sync_options.js b/src/services/sync_options.js index a63b89514..28ec9cca3 100644 --- a/src/services/sync_options.js +++ b/src/services/sync_options.js @@ -15,7 +15,9 @@ function get(name) { } module.exports = { - getSyncServerHost: () => get('syncServerHost'), + // env variable is the easiest way to guarantee we won't overwrite prod data during development + // after copying prod document/data directory + getSyncServerHost: () => process.env.TRILIUM_SYNC_SERVER_HOST || get('syncServerHost'), isSyncSetup: () => { const syncServerHost = get('syncServerHost');