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