feat: Unsaved changes confirmation (#4)
parent
641b3c45ed
commit
b098e4cb99
|
@ -115,6 +115,7 @@
|
|||
},
|
||||
"permanent": "Permanent",
|
||||
"prompts": {
|
||||
"unsavedChanges": "Changes that you made may not be saved. Leave page?",
|
||||
"archive": "Archive",
|
||||
"archiveMessage": "Choose archive name and format:",
|
||||
"unarchive": "Unarchive",
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
<breadcrumbs base="/files" />
|
||||
|
||||
<errors v-if="error" :errorCode="error.message" />
|
||||
<component v-else-if="currentView" :is="currentView"></component>
|
||||
<component
|
||||
v-else-if="currentView"
|
||||
:is="currentView"
|
||||
@changed="setChanged"
|
||||
></component>
|
||||
<div v-else>
|
||||
<h2 class="message delayed">
|
||||
<div class="spinner">
|
||||
|
@ -47,6 +51,7 @@ export default {
|
|||
return {
|
||||
error: null,
|
||||
width: window.innerWidth,
|
||||
unsavedChanges: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -68,6 +73,12 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
this.verifyRouteChange(next);
|
||||
},
|
||||
beforeRouteLeave(to, from, next) {
|
||||
this.verifyRouteChange(next);
|
||||
},
|
||||
created() {
|
||||
this.fetchData();
|
||||
},
|
||||
|
@ -92,6 +103,21 @@ export default {
|
|||
this.$store.commit("updateRequest", {});
|
||||
},
|
||||
methods: {
|
||||
verifyRouteChange(next) {
|
||||
if (
|
||||
this.currentView === "editor" &&
|
||||
this.unsavedChanges &&
|
||||
!confirm(this.$t("prompts.unsavedChanges"))
|
||||
) {
|
||||
next(false);
|
||||
} else {
|
||||
this.unsavedChanges = false;
|
||||
next();
|
||||
}
|
||||
},
|
||||
setChanged(value) {
|
||||
this.unsavedChanges = value;
|
||||
},
|
||||
...mapMutations(["setLoading"]),
|
||||
async fetchData() {
|
||||
// Reset view information.
|
||||
|
|
|
@ -44,7 +44,9 @@ export default {
|
|||
Breadcrumbs,
|
||||
},
|
||||
data: function () {
|
||||
return {};
|
||||
return {
|
||||
unsavedChanges: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["req", "user"]),
|
||||
|
@ -78,10 +80,17 @@ export default {
|
|||
return breadcrumbs;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
unsavedChanges() {
|
||||
this.$emit("changed", this.unsavedChanges);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
window.addEventListener("beforeunload", this.beforeWindowUnload);
|
||||
window.addEventListener("keydown", this.keyEvent);
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener("beforeunload", this.beforeWindowUnload);
|
||||
window.removeEventListener("keydown", this.keyEvent);
|
||||
this.editor.destroy();
|
||||
},
|
||||
|
@ -97,14 +106,18 @@ export default {
|
|||
wrap: true,
|
||||
});
|
||||
|
||||
this.editor.on("change", () => (this.unsavedChanges = true));
|
||||
|
||||
if (theme == "dark") {
|
||||
this.editor.setTheme("ace/theme/twilight");
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||
this.$router.push({ path: uri });
|
||||
beforeWindowUnload(e) {
|
||||
if (this.unsavedChanges) {
|
||||
e.preventDefault();
|
||||
e.returnValue = "";
|
||||
}
|
||||
},
|
||||
keyEvent(event) {
|
||||
if (!event.ctrlKey && !event.metaKey) {
|
||||
|
@ -121,6 +134,7 @@ export default {
|
|||
async save() {
|
||||
const button = "save";
|
||||
buttons.loading("save");
|
||||
this.unsavedChanges = false;
|
||||
|
||||
try {
|
||||
await api.put(this.$route.path, this.editor.getValue());
|
||||
|
@ -131,6 +145,10 @@ export default {
|
|||
}
|
||||
},
|
||||
close() {
|
||||
if (this.unsavedChanges && !confirm(this.$t("prompts.unsavedChanges"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$store.commit("updateRequest", {});
|
||||
|
||||
let uri = url.removeLastDir(this.$route.path) + "/";
|
||||
|
|
Loading…
Reference in New Issue