From: Adam Dullage Date: Wed, 3 Jul 2024 12:15:37 +0000 (+0100) Subject: Add unsaved changes indicator X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=0339dc80f91a8c938c12f623fb600cbb475d27e7;p=flatnotes.git Add unsaved changes indicator --- diff --git a/client/components/CustomButton.vue b/client/components/CustomButton.vue index b6fe8c0..fb493f8 100644 --- a/client/components/CustomButton.vue +++ b/client/components/CustomButton.vue @@ -12,6 +12,7 @@ style === 'success', }" > + diff --git a/client/views/Note.vue b/client/views/Note.vue index 6851905..473fb86 100644 --- a/client/views/Note.vue +++ b/client/views/Note.vue @@ -65,7 +65,14 @@ label="Save" :iconPath="mdilContentSave" @click="saveHandler((close = false))" - /> + class="relative" + > + +
+ @@ -112,7 +119,7 @@ import { mdiNoteOffOutline } from "@mdi/js"; import { mdilContentSave, mdilDelete } from "@mdi/light-js"; import Mousetrap from "mousetrap"; import { useToast } from "primevue/usetoast"; -import { computed, nextTick, onMounted, ref, watch } from "vue"; +import { computed, onMounted, ref, watch } from "vue"; import { useRouter } from "vue-router"; import { @@ -139,7 +146,7 @@ const props = defineProps({ }); const canModify = computed(() => globalStore.authType != authTypes.readOnly); -let draftSaveTimeout = null; +let contentChangedTimeout = null; const editMode = ref(false); const globalStore = useGlobalStore(); const isSaveChangesModalVisible = ref(false); @@ -153,6 +160,7 @@ const router = useRouter(); const newTitle = ref(); const toast = useToast(); const toastEditor = ref(); +const unsavedChanges = ref(false); // 'e' to edit Mousetrap.bind("e", () => { @@ -211,6 +219,7 @@ function editHandler() { function setEditMode() { setBeforeUnloadConfirmation(true); newTitle.value = note.value.title; + unsavedChanges.value = false; editMode.value = true; } @@ -316,6 +325,7 @@ function noteSaveFailure(error) { } function noteSaveSuccess(close = false) { + unsavedChanges.value = false; if (close) { closeNote(); } @@ -324,10 +334,7 @@ function noteSaveSuccess(close = false) { // Note Closure function closeHandler() { - if ( - newTitle.value != note.value.title || - toastEditor.value.getMarkdown() != note.value.content - ) { + if (isContentChanged()) { isSaveChangesModalVisible.value = true; } else { closeNote(); @@ -403,13 +410,29 @@ function postAttachment(file) { }); } -// Drafts -function clearDraftSaveTimeout() { - if (draftSaveTimeout != null) { - clearTimeout(draftSaveTimeout); +// Content Change Watcher +function startContentChangedTimeout() { + clearContentChangedTimeout(); + contentChangedTimeout = setTimeout(contentChangedHandler, 1000); +} + +function clearContentChangedTimeout() { + if (contentChangedTimeout != null) { + clearTimeout(contentChangedTimeout); + } +} + +function contentChangedHandler() { + if (isContentChanged()) { + unsavedChanges.value = true; + saveDraft(); + } else { + unsavedChanges.value = false; + clearDraft(); } } +// Drafts function saveDraft() { const content = toastEditor.value.getMarkdown(); if (content) { @@ -417,11 +440,6 @@ function saveDraft() { } } -function startDraftSaveTimeout() { - clearDraftSaveTimeout(); - draftSaveTimeout = setTimeout(saveDraft, 1000); -} - function clearDraft() { localStorage.removeItem(note.value.title); } @@ -474,6 +492,13 @@ function loadDefaultEditorMode() { return defaultWysiwygMode || "markdown"; } +function isContentChanged() { + return ( + newTitle.value != note.value.title || + toastEditor.value.getMarkdown() != note.value.content + ); +} + watch(() => props.title, init); onMounted(init);