<Modal
v-model="isVisible"
:title="title"
- :class="{ 'border border-l-4 border-l-theme-danger': isDanger }"
- :closeHandler="cancelHandler"
+ :closeHandler="emitClose"
class="px-6 py-4"
>
<!-- Title -->
<CustomButton
:label="cancelButtonText"
:style="cancelButtonStyle"
- @click="cancelHandler"
+ @click="emitClose('cancel')"
+ class="mr-2"
+ />
+ <CustomButton
+ v-if="rejectButtonText"
+ :label="rejectButtonText"
+ :style="rejectButtonStyle"
+ @click="emitClose('reject')"
class="mr-2"
/>
<CustomButton
v-focus
:label="confirmButtonText"
:style="confirmButtonStyle"
- @click="confirmHandler"
+ @click="emitClose('confirm')"
/>
</div>
</Modal>
confirmButtonText: { type: String, default: "Confirm" },
cancelButtonStyle: { type: String, default: "subtle" },
cancelButtonText: { type: String, default: "Cancel" },
- isDanger: Boolean,
+ rejectButtonStyle: { type: String, default: "danger" },
+ rejectButtonText: { type: String },
});
-const emit = defineEmits(["confirm", "cancel"]);
+const emit = defineEmits(["confirm", "reject", "cancel"]);
const isVisible = defineModel({ type: Boolean });
-function cancelHandler() {
- isVisible.value = false;
- emit("cancel");
-}
-
-function confirmHandler() {
+function emitClose(closeEvent = "cancel") {
isVisible.value = false;
- emit("confirm");
+ emit(closeEvent);
}
</script>
@confirm="deleteConfirmedHandler"
/>
- <!-- Confirm Cancellation Modal -->
+ <!-- Save Changes Modal -->
<ConfirmModal
- v-model="isCancellationModalVisible"
- title="Confirm Closure"
- message="Changes have been made. Are you sure you want to close the note?"
- confirmButtonText="Close"
- confirmButtonStyle="danger"
- @confirm="cancelConfirmedHandler"
+ v-model="isSaveChangesModalVisible"
+ title="Save Changes"
+ message="Do you want to save your changes?"
+ confirmButtonText="Save"
+ confirmButtonStyle="success"
+ rejectButtonText="Discard"
+ rejectButtonStyle="danger"
+ @confirm="saveHandler((close = true))"
+ @reject="closeNote"
/>
<!-- Draft Modal -->
message="There is an unsaved draft of this note stored in this browser. Do you want to resume the draft version or delete it?"
confirmButtonText="Resume Draft"
confirmButtonStyle="cta"
- cancelButtonText="Delete Draft"
- cancelButtonStyle="danger"
+ rejectButtonText="Delete Draft"
+ rejectButtonStyle="danger"
@confirm="setEditMode()"
- @cancel="
+ @reject="
clearDraft();
setEditMode();
"
<!-- Buttons -->
<div class="flex shrink-0 self-end md:self-baseline">
- <div v-show="!editMode">
- <CustomButton
- v-if="canModify"
- :iconPath="mdilDelete"
- label="Delete"
- @click="deleteHandler"
- />
- <CustomButton
- v-if="canModify"
- class="ml-1"
- :iconPath="mdilPencil"
- label="Edit"
- @click="editHandler"
- />
- </div>
- <div v-show="editMode">
- <CustomButton
- :iconPath="mdilArrowLeft"
- label="Cancel"
- @click="cancelHandler"
- />
- <CustomButton
- class="ml-1"
- :iconPath="mdilContentSave"
- label="Save"
- @click="saveHandler"
- />
- </div>
+ <CustomButton
+ v-show="canModify && !editMode"
+ label="Delete"
+ :iconPath="mdilDelete"
+ @click="deleteHandler"
+ />
+ <CustomButton
+ v-show="editMode"
+ label="Save"
+ :iconPath="mdilContentSave"
+ @click="saveHandler((close = false))"
+ />
+ <Toggle
+ v-if="canModify"
+ label="Edit"
+ :isOn="editMode"
+ class="ml-1"
+ @click="toggleEditModeHandler"
+ />
</div>
</div>
}
</style>
-
<script setup>
import { mdiNoteOffOutline } from "@mdi/js";
-import {
- mdilArrowLeft,
- mdilContentSave,
- mdilDelete,
- mdilPencil,
-} from "@mdi/light-js";
+import { mdilContentSave, mdilDelete } from "@mdi/light-js";
import Mousetrap from "mousetrap";
import { useToast } from "primevue/usetoast";
-import { computed, onMounted, ref, watch } from "vue";
+import { computed, nextTick, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import {
import ConfirmModal from "../components/ConfirmModal.vue";
import CustomButton from "../components/CustomButton.vue";
import LoadingIndicator from "../components/LoadingIndicator.vue";
+import Toggle from "../components/Toggle.vue";
import ToastEditor from "../components/toastui/ToastEditor.vue";
import ToastViewer from "../components/toastui/ToastViewer.vue";
import { authTypes } from "../constants.js";
let draftSaveTimeout = null;
const editMode = ref(false);
const globalStore = useGlobalStore();
-const isCancellationModalVisible = ref(false);
+const isSaveChangesModalVisible = ref(false);
const isDeleteModalVisible = ref(false);
const isDraftModalVisible = ref(false);
const isNewNote = computed(() => !props.title);
}
// Note Editing
+function toggleEditModeHandler() {
+ if (editMode.value) {
+ closeHandler();
+ } else {
+ editHandler();
+ }
+}
+
function editHandler() {
const draftContent = loadDraft();
if (draftContent) {
});
}
-// Note Edit Cancellation
-function cancelHandler() {
- if (
- newTitle.value != note.value.title ||
- toastEditor.value.getMarkdown() != note.value.content
- ) {
- isCancellationModalVisible.value = true;
- } else {
- cancelConfirmedHandler();
- }
-}
-
-function cancelConfirmedHandler() {
- clearDraft();
- setBeforeUnloadConfirmation(false);
- editMode.value = false;
- if (!props.title) {
- router.push({ name: "home" });
- } else {
- editMode.value = false;
- }
-}
-
// Note Saving
-function saveHandler() {
+function saveHandler(close = false) {
// Save Default Editor Mode
saveDefaultEditorMode();
// Save Note
let newContent = toastEditor.value.getMarkdown();
if (isNewNote.value) {
- saveNew(newTitle.value, newContent);
+ saveNew(newTitle.value, newContent, close);
} else {
- saveExisting(newTitle.value, newContent);
+ saveExisting(newTitle.value, newContent, close);
}
}
-function saveNew(newTitle, newContent) {
+function saveNew(newTitle, newContent, close = false) {
createNote(newTitle, newContent)
.then((data) => {
clearDraft();
note.value = data;
- router.push({ name: "note", params: { title: note.value.title } });
- noteSaveSuccess();
+ router
+ .push({
+ name: "note",
+ params: { title: note.value.title },
+ })
+ .then(() => {
+ // Wait for the route to be updated before setting edit mode to false
+ // as the route is used to determine the action.
+ noteSaveSuccess(close);
+ });
})
.catch(noteSaveFailure);
}
-function saveExisting(newTitle, newContent) {
+function saveExisting(newTitle, newContent, close = false) {
// Return if no changes
if (newTitle == note.value.title && newContent == note.value.content) {
- noteSaveSuccess();
+ noteSaveSuccess(close);
return;
}
clearDraft();
note.value = data;
router.replace({ name: "note", params: { title: note.value.title } });
- noteSaveSuccess();
+ noteSaveSuccess(close);
})
.catch(noteSaveFailure);
}
}
}
-function noteSaveSuccess() {
+function noteSaveSuccess(close = false) {
+ if (close) {
+ closeNote();
+ }
+ toast.add(getToastOptions("Note saved successfully ✓", "Success", "success"));
+}
+
+// Note Closure
+function closeHandler() {
+ if (
+ newTitle.value != note.value.title ||
+ toastEditor.value.getMarkdown() != note.value.content
+ ) {
+ isSaveChangesModalVisible.value = true;
+ } else {
+ closeNote();
+ }
+}
+
+function closeNote() {
+ clearDraft();
setBeforeUnloadConfirmation(false);
editMode.value = false;
- toast.add(getToastOptions("Note saved successfully ✓", "Success", "success"));
+ if (isNewNote.value) {
+ router.push({ name: "home" });
+ } else {
+ editMode.value = false;
+ }
}
// Image Upload