diff --git a/apps/client/src/components/app_context.ts b/apps/client/src/components/app_context.ts index 80af6adf7..35b8b8585 100644 --- a/apps/client/src/components/app_context.ts +++ b/apps/client/src/components/app_context.ts @@ -40,7 +40,7 @@ interface RootWidget extends Component { render: () => JQuery; } -interface BeforeUploadListener extends Component { +export interface BeforeUploadListener extends Component { beforeUnloadEvent(): boolean; } @@ -526,7 +526,7 @@ export type FilteredCommandNames = keyof Pick[]; + beforeUnloadListeners: (WeakRef | (() => boolean))[]; tabManager!: TabManager; layout?: Layout; noteTreeWidget?: NoteTreeWidget; @@ -649,13 +649,17 @@ export class AppContext extends Component { return $(el).closest(".component").prop("component"); } - addBeforeUnloadListener(obj: BeforeUploadListener) { + addBeforeUnloadListener(obj: BeforeUploadListener | (() => boolean)) { if (typeof WeakRef !== "function") { // older browsers don't support WeakRef return; } - this.beforeUnloadListeners.push(new WeakRef(obj)); + if (typeof obj === "object") { + this.beforeUnloadListeners.push(new WeakRef(obj)); + } else { + this.beforeUnloadListeners.push(obj); + } } } @@ -665,18 +669,24 @@ const appContext = new AppContext(window.glob.isMainWindow); $(window).on("beforeunload", () => { let allSaved = true; - appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter((wr) => !!wr.deref()); + appContext.beforeUnloadListeners = appContext.beforeUnloadListeners.filter((wr) => typeof wr === "function" || !!wr.deref()); - for (const weakRef of appContext.beforeUnloadListeners) { - const component = weakRef.deref(); + for (const listener of appContext.beforeUnloadListeners) { + if (typeof listener === "object") { + const component = listener.deref(); - if (!component) { - continue; - } + if (!component) { + continue; + } - if (!component.beforeUnloadEvent()) { - console.log(`Component ${component.componentId} is not finished saving its state.`); - allSaved = false; + if (!component.beforeUnloadEvent()) { + console.log(`Component ${component.componentId} is not finished saving its state.`); + allSaved = false; + } + } else { + if (!listener()) { + allSaved = false; + } } } diff --git a/apps/client/src/widgets/note_title.bak b/apps/client/src/widgets/note_title.bak index 4b7218760..f1c0fc593 100644 --- a/apps/client/src/widgets/note_title.bak +++ b/apps/client/src/widgets/note_title.bak @@ -1,13 +1,8 @@ -import { t } from "../services/i18n.js"; import NoteContextAwareWidget from "./note_context_aware_widget.js"; -import protectedSessionHolder from "../services/protected_session_holder.js"; -import server from "../services/server.js"; import SpacedUpdate from "../services/spaced_update.js"; import appContext, { type EventData } from "../components/app_context.js"; import branchService from "../services/branches.js"; import shortcutService from "../services/shortcuts.js"; -import utils from "../services/utils.js"; -import type FNote from "../entities/fnote.js"; export default class NoteTitleWidget extends NoteContextAwareWidget { @@ -19,16 +14,11 @@ export default class NoteTitleWidget extends NoteContextAwareWidget { super(); this.deleteNoteOnEscape = false; - - appContext.addBeforeUnloadListener(this); } doRender() { this.$widget = $(TPL); this.$noteTitle = this.$widget.find(".note-title"); - - this.$noteTitle.on("input", () => this.spacedUpdate.scheduleUpdate()); - this.$noteTitle.on("blur", () => { this.spacedUpdate.updateNowIfNecessary(); @@ -71,8 +61,4 @@ export default class NoteTitleWidget extends NoteContextAwareWidget { this.deleteNoteOnEscape = isNewNote; } } - - beforeUnloadEvent() { - return this.spacedUpdate.isAllSavedAndTriggerUpdate(); - } } diff --git a/apps/client/src/widgets/note_title.tsx b/apps/client/src/widgets/note_title.tsx index 963523fda..6f1f82e32 100644 --- a/apps/client/src/widgets/note_title.tsx +++ b/apps/client/src/widgets/note_title.tsx @@ -1,11 +1,12 @@ import { useEffect, useRef, useState } from "preact/hooks"; import { t } from "../services/i18n"; import FormTextBox from "./react/FormTextBox"; -import { useNoteContext, useNoteProperty, useSpacedUpdate } from "./react/hooks"; +import { useBeforeUnload, useNoteContext, useNoteProperty, useSpacedUpdate } from "./react/hooks"; import protected_session_holder from "../services/protected_session_holder"; import server from "../services/server"; import "./note_title.css"; import { isLaunchBarConfig } from "../services/utils"; +import appContext from "../components/app_context"; export default function NoteTitleWidget() { const { note, noteId, componentId, viewScope, noteContext } = useNoteContext(); @@ -39,6 +40,10 @@ export default function NoteTitleWidget() { await server.put(`notes/${noteId}/title`, { title: newTitle.current }, componentId); }); + useEffect(() => { + appContext.addBeforeUnloadListener(() => spacedUpdate.isAllSavedAndTriggerUpdate()); + }, []); + return (
{note && = (data: EventData) => void; const registeredHandlers: Map[]>> = new Map(); @@ -302,4 +303,4 @@ export function useNoteProperty(note: FNote | null | unde }); return note[property]; -} \ No newline at end of file +}