feat: Unsaved changes confirmation (#4)

pull/3756/head
Laurynas Gadliauskas 2021-06-01 12:35:56 +03:00 committed by GitHub
parent 641b3c45ed
commit b098e4cb99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 5 deletions

View File

@ -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",

View File

@ -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.

View File

@ -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) + "/";