mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	prompt user when there are unsaved changes, #1692
This commit is contained in:
		
							parent
							
								
									02016ed031
								
							
						
					
					
						commit
						78e48095e6
					
				| @ -12,6 +12,7 @@ import keyboardActionsService from "./keyboard_actions.js"; | |||||||
| import MobileScreenSwitcherExecutor from "../widgets/mobile_widgets/mobile_screen_switcher.js"; | import MobileScreenSwitcherExecutor from "../widgets/mobile_widgets/mobile_screen_switcher.js"; | ||||||
| import MainTreeExecutors from "./main_tree_executors.js"; | import MainTreeExecutors from "./main_tree_executors.js"; | ||||||
| import protectedSessionHolder from "./protected_session_holder.js"; | import protectedSessionHolder from "./protected_session_holder.js"; | ||||||
|  | import toast from "./toast.js"; | ||||||
| 
 | 
 | ||||||
| class AppContext extends Component { | class AppContext extends Component { | ||||||
|     constructor(isMainWindow) { |     constructor(isMainWindow) { | ||||||
| @ -19,6 +20,7 @@ class AppContext extends Component { | |||||||
| 
 | 
 | ||||||
|         this.isMainWindow = isMainWindow; |         this.isMainWindow = isMainWindow; | ||||||
|         this.executors = []; |         this.executors = []; | ||||||
|  |         this.beforeUnloadListeners = []; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     setLayout(layout) { |     setLayout(layout) { | ||||||
| @ -104,6 +106,15 @@ class AppContext extends Component { | |||||||
|     getComponentByEl(el) { |     getComponentByEl(el) { | ||||||
|         return $(el).closest(".component").prop('component'); |         return $(el).closest(".component").prop('component'); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     addBeforeUnloadListener(obj) { | ||||||
|  |         if (typeof WeakRef !== "function") { | ||||||
|  |             // older browsers don't support WeakRef
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.beforeUnloadListeners.push(new WeakRef(obj)); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const appContext = new AppContext(window.glob.isMainWindow); | const appContext = new AppContext(window.glob.isMainWindow); | ||||||
| @ -112,7 +123,29 @@ const appContext = new AppContext(window.glob.isMainWindow); | |||||||
| $(window).on('beforeunload', () => { | $(window).on('beforeunload', () => { | ||||||
|     protectedSessionHolder.resetSessionCookie(); |     protectedSessionHolder.resetSessionCookie(); | ||||||
| 
 | 
 | ||||||
|     appContext.triggerEvent('beforeUnload'); |     let allSaved = true; | ||||||
|  | 
 | ||||||
|  |     appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter(wr => !!wr.deref()); | ||||||
|  | 
 | ||||||
|  |     for (const weakRef of appContext.beforeUnloadListeners) { | ||||||
|  |         const component = weakRef.deref(); | ||||||
|  | 
 | ||||||
|  |         if (!component) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!component.beforeUnloadEvent()) { | ||||||
|  |             console.log(`Component ${component.componentId} is not finished saving its state.`); | ||||||
|  | 
 | ||||||
|  |             toast.showMessage("Please wait for a couple of seconds for the save to finish, then you can try again.", 10000); | ||||||
|  | 
 | ||||||
|  |             allSaved = false; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!allSaved) { | ||||||
|  |         return "some string"; | ||||||
|  |     } | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| function isNotePathInAddress() { | function isNotePathInAddress() { | ||||||
|  | |||||||
| @ -15,11 +15,27 @@ export default class SpacedUpdate { | |||||||
| 
 | 
 | ||||||
|     async updateNowIfNecessary() { |     async updateNowIfNecessary() { | ||||||
|         if (this.changed) { |         if (this.changed) { | ||||||
|             this.changed = false; |             this.changed = false; // optimistic...k
 | ||||||
|             await this.updater(); | 
 | ||||||
|  |             try { | ||||||
|  |                 await this.updater(); | ||||||
|  |             } | ||||||
|  |             catch (e) { | ||||||
|  |                 this.changed = true; | ||||||
|  | 
 | ||||||
|  |                 throw e; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     isAllSavedAndTriggerUpdate() { | ||||||
|  |         const allSaved = !this.changed; | ||||||
|  | 
 | ||||||
|  |         this.updateNowIfNecessary(); | ||||||
|  | 
 | ||||||
|  |         return allSaved; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     triggerUpdate() { |     triggerUpdate() { | ||||||
|         if (!this.changed) { |         if (!this.changed) { | ||||||
|             return; |             return; | ||||||
|  | |||||||
| @ -27,6 +27,8 @@ export default class TabManager extends Component { | |||||||
|                 openTabs: JSON.stringify(openTabs) |                 openTabs: JSON.stringify(openTabs) | ||||||
|             }); |             }); | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         appContext.addBeforeUnloadListener(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** @type {TabContext[]} */ |     /** @type {TabContext[]} */ | ||||||
| @ -329,6 +331,8 @@ export default class TabManager extends Component { | |||||||
| 
 | 
 | ||||||
|     beforeUnloadEvent() { |     beforeUnloadEvent() { | ||||||
|         this.tabsUpdate.updateNowIfNecessary(); |         this.tabsUpdate.updateNowIfNecessary(); | ||||||
|  | 
 | ||||||
|  |         return true; // don't block closing the tab, this metadata is not that important
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     openNewTabCommand() { |     openNewTabCommand() { | ||||||
|  | |||||||
| @ -54,8 +54,6 @@ export default class NoteDetailWidget extends TabAwareWidget { | |||||||
| 
 | 
 | ||||||
|         this.typeWidgets = {}; |         this.typeWidgets = {}; | ||||||
| 
 | 
 | ||||||
|         const updateInterval = utils.isDesktop() ? 1000 : 5000; |  | ||||||
| 
 |  | ||||||
|         this.spacedUpdate = new SpacedUpdate(async () => { |         this.spacedUpdate = new SpacedUpdate(async () => { | ||||||
|             const {note} = this.tabContext; |             const {note} = this.tabContext; | ||||||
|             const {noteId} = note; |             const {noteId} = note; | ||||||
| @ -66,7 +64,9 @@ export default class NoteDetailWidget extends TabAwareWidget { | |||||||
|             protectedSessionHolder.touchProtectedSessionIfNecessary(note); |             protectedSessionHolder.touchProtectedSessionIfNecessary(note); | ||||||
| 
 | 
 | ||||||
|             await server.put('notes/' + noteId, dto, this.componentId); |             await server.put('notes/' + noteId, dto, this.componentId); | ||||||
|         }, updateInterval); |         }); | ||||||
|  | 
 | ||||||
|  |         appContext.addBeforeUnloadListener(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     isEnabled() { |     isEnabled() { | ||||||
| @ -295,7 +295,7 @@ export default class NoteDetailWidget extends TabAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     beforeUnloadEvent() { |     beforeUnloadEvent() { | ||||||
|         this.spacedUpdate.updateNowIfNecessary(); |         return this.spacedUpdate.isAllSavedAndTriggerUpdate(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     textPreviewDisabledEvent({tabContext}) { |     textPreviewDisabledEvent({tabContext}) { | ||||||
|  | |||||||
| @ -3,6 +3,7 @@ import utils from "../services/utils.js"; | |||||||
| import protectedSessionHolder from "../services/protected_session_holder.js"; | import protectedSessionHolder from "../services/protected_session_holder.js"; | ||||||
| import server from "../services/server.js"; | import server from "../services/server.js"; | ||||||
| import SpacedUpdate from "../services/spaced_update.js"; | import SpacedUpdate from "../services/spaced_update.js"; | ||||||
|  | import appContext from "../services/app_context.js"; | ||||||
| 
 | 
 | ||||||
| const TPL = ` | const TPL = ` | ||||||
| <div class="note-title-container"> | <div class="note-title-container"> | ||||||
| @ -37,6 +38,8 @@ export default class NoteTitleWidget extends TabAwareWidget { | |||||||
| 
 | 
 | ||||||
|             await server.put(`notes/${this.noteId}/change-title`, {title}); |             await server.put(`notes/${this.noteId}/change-title`, {title}); | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         appContext.addBeforeUnloadListener(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     doRender() { |     doRender() { | ||||||
| @ -101,6 +104,6 @@ export default class NoteTitleWidget extends TabAwareWidget { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     beforeUnloadEvent() { |     beforeUnloadEvent() { | ||||||
|         this.spacedUpdate.updateNowIfNecessary(); |         return this.spacedUpdate.isAllSavedAndTriggerUpdate(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam