mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-30 04:01:31 +08:00 
			
		
		
		
	Merge branch 'stable'
# Conflicts: # package-lock.json # src/public/javascripts/services/tree_context_menu.js # src/services/import/enex.js
This commit is contained in:
		
						commit
						90d10c1ff3
					
				
							
								
								
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -498,7 +498,7 @@ | ||||
| 				t._started = false; | ||||
| 				onRenderStop(); | ||||
| 			} else { | ||||
| 				setImmediate(step); | ||||
| 				requestIdleCallback(step, { timeout: 10 }); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										4061
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4061
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -2,7 +2,7 @@ | ||||
|   "name": "trilium", | ||||
|   "productName": "Trilium Notes", | ||||
|   "description": "Trilium Notes", | ||||
|   "version": "0.37.4", | ||||
|   "version": "0.37.6", | ||||
|   "license": "AGPL-3.0-only", | ||||
|   "main": "electron.js", | ||||
|   "bin": { | ||||
|  | ||||
| @ -818,6 +818,7 @@ class Note extends Entity { | ||||
|         delete pojo.isContentAvailable; | ||||
|         delete pojo.__attributeCache; | ||||
|         delete pojo.content; | ||||
|         /** zero references to contentHash, probably can be removed */ | ||||
|         delete pojo.contentHash; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -93,7 +93,7 @@ export default class SidebarOptions { | ||||
|         this.$sidebarMinWidth.val(options.sidebarMinWidth); | ||||
|         this.$sidebarWidthPercent.val(options.sidebarWidthPercent); | ||||
| 
 | ||||
|         if (parseInt(options.showSidebarInNewTab)) { | ||||
|         if (options.showSidebarInNewTab === 'true') { | ||||
|             this.$showSidebarInNewTab.attr("checked", "checked"); | ||||
|         } | ||||
|         else { | ||||
|  | ||||
| @ -274,7 +274,9 @@ async function filterTabs(noteId) { | ||||
| 
 | ||||
| async function noteDeleted(noteId) { | ||||
|     for (const tc of tabContexts) { | ||||
|         if (tc.notePath && tc.notePath.split("/").includes(noteId)) { | ||||
|         // not removing active even if it contains deleted note since that one will move to another note (handled by deletion logic)
 | ||||
|         // and we would lose tab context state (e.g. sidebar visibility)
 | ||||
|         if (!tc.isActive() && tc.notePath && tc.notePath.split("/").includes(noteId)) { | ||||
|             await tabRow.removeTab(tc.$tab[0]); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @ -246,11 +246,15 @@ class TabContext { | ||||
|     } | ||||
| 
 | ||||
|     setCurrentNotePathToHash() { | ||||
|         if (this.$tab[0] === this.tabRow.activeTabEl) { | ||||
|         if (this.isActive()) { | ||||
|             document.location.hash = (this.notePath || "") + "-" + this.tabId; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     isActive() { | ||||
|         return this.$tab[0] === this.tabRow.activeTabEl; | ||||
|     } | ||||
| 
 | ||||
|     setupClasses() { | ||||
|         for (const clazz of Array.from(this.$tab[0].classList)) { // create copy to safely iterate over while removing classes
 | ||||
|             if (clazz !== 'note-tab') { | ||||
|  | ||||
| @ -42,7 +42,7 @@ class TreeContextMenu { | ||||
|                 || (selNodes.length === 1 && selNodes[0] === this.node); | ||||
| 
 | ||||
|         const notSearch = note.type !== 'search'; | ||||
|         const parentNotSearch = parentNote.type !== 'search'; | ||||
|         const parentNotSearch = !parentNote || parentNote.type !== 'search'; | ||||
|         const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNotSearch; | ||||
| 
 | ||||
|         return [ | ||||
| @ -78,8 +78,8 @@ class TreeContextMenu { | ||||
|                 enabled: !clipboard.isClipboardEmpty() && notSearch && noSelectedNotes }, | ||||
|             { title: 'Paste after', cmd: "pasteAfter", uiIcon: "paste", | ||||
|                 enabled: !clipboard.isClipboardEmpty() && isNotRoot && !isHoisted && parentNotSearch && noSelectedNotes }, | ||||
|             { title: 'Duplicate note here', cmd: "duplicateNote", uiIcon: "empty", | ||||
|                 enabled: noSelectedNotes && parentNotSearch && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) }, | ||||
|             { title: "Duplicate note here", cmd: "duplicateNote", uiIcon: "empty", | ||||
|                 enabled: noSelectedNotes && parentNotSearch && isNotRoot && !isHoisted && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) }, | ||||
|             { title: "----" }, | ||||
|             { title: "Export", cmd: "export", uiIcon: "empty", | ||||
|                 enabled: notSearch && noSelectedNotes }, | ||||
|  | ||||
| @ -127,11 +127,13 @@ async function consumeSyncData() { | ||||
| } | ||||
| 
 | ||||
| function connectWebSocket() { | ||||
|     const protocol = document.location.protocol === 'https:' ? 'wss' : 'ws'; | ||||
|     const loc = window.location; | ||||
|     const webSocketUri = (loc.protocol === "https:" ? "wss:" : "ws:") | ||||
|                        + "//" + loc.host + loc.pathname; | ||||
| 
 | ||||
|     // use wss for secure messaging
 | ||||
|     const ws = new WebSocket(protocol + "://" + location.host); | ||||
|     ws.onopen = () => console.debug(utils.now(), "Connected to server with WebSocket"); | ||||
|     const ws = new WebSocket(webSocketUri); | ||||
|     ws.onopen = () => console.debug(utils.now(), `Connected to server ${webSocketUri} with WebSocket`); | ||||
|     ws.onmessage = handleMessage; | ||||
|     // we're not handling ws.onclose here because reconnection is done in sendPing()
 | ||||
| 
 | ||||
|  | ||||
| @ -97,6 +97,11 @@ body { | ||||
|     font-size: inherit; | ||||
| } | ||||
| 
 | ||||
| #context-menu-container { | ||||
|     max-height: 100vh; | ||||
|     overflow: auto; /* make it scrollable when exceeding total height of the window */ | ||||
| } | ||||
| 
 | ||||
| #context-menu-container, #context-menu-container .dropdown-menu { | ||||
|     padding: 3px 0 0; | ||||
|     z-index: 1111; | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| module.exports = { buildDate:"2019-11-22T22:38:03+01:00", buildRevision: "7a2c7edd7e9b975bf64f732629e711379baecf48" }; | ||||
| module.exports = { buildDate:"2019-11-26T22:50:08+01:00", buildRevision: "5193f073e9e55f5440fe2e71fbd2cdfcdb2d2c6b" }; | ||||
|  | ||||
| @ -3,6 +3,7 @@ const fileType = require('file-type'); | ||||
| const stream = require('stream'); | ||||
| const log = require("../log"); | ||||
| const utils = require("../utils"); | ||||
| const sql = require("../sql"); | ||||
| const noteService = require("../notes"); | ||||
| const imageService = require("../image"); | ||||
| const protectedSessionService = require('../protected_session'); | ||||
| @ -11,7 +12,7 @@ const protectedSessionService = require('../protected_session'); | ||||
| function parseDate(text) { | ||||
|     // insert - and : to make it ISO format
 | ||||
|     text = text.substr(0, 4) + "-" + text.substr(4, 2) + "-" + text.substr(6, 2) | ||||
|         + "T" + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + "Z"; | ||||
|         + " " + text.substr(9, 2) + ":" + text.substr(11, 2) + ":" + text.substr(13, 2) + ".000Z"; | ||||
| 
 | ||||
|     return text; | ||||
| } | ||||
| @ -153,7 +154,7 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|             } else if (currentTag === 'created') { | ||||
|                 note.utcDateCreated = parseDate(text); | ||||
|             } else if (currentTag === 'updated') { | ||||
|                 // updated is currently ignored since utcDateModified is updated automatically with each save
 | ||||
|                 note.utcDateModified = parseDate(text); | ||||
|             } else if (currentTag === 'tag') { | ||||
|                 note.attributes.push({ | ||||
|                     type: 'label', | ||||
| @ -190,9 +191,27 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
|     async function updateDates(noteId, utcDateCreated, utcDateModified) { | ||||
|         // it's difficult to force custom dateCreated and dateModified to Note entity so we do it post-creation with SQL
 | ||||
|         await sql.execute(` | ||||
|                 UPDATE notes  | ||||
|                 SET dateCreated = ?,  | ||||
|                     utcDateCreated = ?, | ||||
|                     dateModified = ?, | ||||
|                     utcDateModified = ? | ||||
|                 WHERE noteId = ?`,
 | ||||
|             [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, noteId]); | ||||
| 
 | ||||
|         await sql.execute(` | ||||
|                 UPDATE note_contents | ||||
|                 SET utcDateModified = ? | ||||
|                 WHERE noteId = ?`,
 | ||||
|             [utcDateModified, noteId]); | ||||
|     } | ||||
| 
 | ||||
|     async function saveNote() { | ||||
|         // make a copy because stream continues with the next async call and note gets overwritten
 | ||||
|         let {title, content, attributes, resources, utcDateCreated} = note; | ||||
|         let {title, content, attributes, resources, utcDateCreated, utcDateModified} = note; | ||||
| 
 | ||||
|         content = extractContent(content); | ||||
| 
 | ||||
| @ -210,6 +229,10 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|             await noteEntity.addAttribute(attr.type, attr.name, attr.value); | ||||
|         } | ||||
| 
 | ||||
|         utcDateCreated = utcDateCreated || noteEntity.utcDateCreated; | ||||
|         // sometime date modified is not present in ENEX, then use date created
 | ||||
|         utcDateModified = utcDateModified || utcDateCreated; | ||||
| 
 | ||||
|         taskContext.increaseProgressCount(); | ||||
| 
 | ||||
|         let noteContent = await noteEntity.getContent(); | ||||
| @ -239,6 +262,8 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|                     await noteEntity.addAttribute(attr.type, attr.name, attr.value); | ||||
|                 } | ||||
| 
 | ||||
|                 await updateDates(resourceNote.noteId, utcDateCreated, utcDateModified); | ||||
| 
 | ||||
|                 taskContext.increaseProgressCount(); | ||||
| 
 | ||||
|                 const resourceLink = `<a href="#root/${resourceNote.noteId}">${utils.escapeHtml(resource.title)}</a>`; | ||||
| @ -250,7 +275,9 @@ async function importEnex(taskContext, file, parentNote) { | ||||
|                 try { | ||||
|                     const originalName = "image." + resource.mime.substr(6); | ||||
| 
 | ||||
|                     const {url} = await imageService.saveImage(noteEntity.noteId, resource.content, originalName, taskContext.data.shrinkImages); | ||||
|                     const {url, note: imageNote} = await imageService.saveImage(noteEntity.noteId, resource.content, originalName, taskContext.data.shrinkImages); | ||||
| 
 | ||||
|                     await updateDates(imageNote.noteId, utcDateCreated, utcDateModified); | ||||
| 
 | ||||
|                     const imageLink = `<img src="${url}">`; | ||||
| 
 | ||||
| @ -272,6 +299,10 @@ async function importEnex(taskContext, file, parentNote) { | ||||
| 
 | ||||
|         // save updated content with links to files/images
 | ||||
|         await noteEntity.setContent(noteContent); | ||||
| 
 | ||||
|         await noteService.scanForLinks(noteEntity.noteId); | ||||
| 
 | ||||
|         await updateDates(noteEntity.noteId, utcDateCreated, utcDateModified); | ||||
|     } | ||||
| 
 | ||||
|     saxStream.on("closetag", async tag => { | ||||
|  | ||||
| @ -37,7 +37,7 @@ function isProtectedSessionAvailable() { | ||||
| function decryptNotes(notes) { | ||||
|     for (const note of notes) { | ||||
|         if (note.isProtected) { | ||||
|             note.title = decrypt(note.title); | ||||
|             note.title = decryptString(note.title); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam