diff --git a/resources/js/components/common/Notifications.vue b/resources/js/components/common/Notifications.vue index 6f12a13..b7cbbdf 100644 --- a/resources/js/components/common/Notifications.vue +++ b/resources/js/components/common/Notifications.vue @@ -98,7 +98,7 @@

{{notification.text}}

Yes - No + No
diff --git a/resources/js/components/open/forms/components/FormEditor.vue b/resources/js/components/open/forms/components/FormEditor.vue index 7a5f3d8..3a8f5b2 100644 --- a/resources/js/components/open/forms/components/FormEditor.vue +++ b/resources/js/components/open/forms/components/FormEditor.vue @@ -189,6 +189,7 @@ export default { this.form.put('/api/open/forms/{id}/'.replace('{id}', this.form.id)).then((response) => { const data = response.data this.$store.commit('open/forms/addOrUpdate', data.form) + this.$emit('on-save') this.$router.push({name: 'forms.show', params: {slug: this.form.slug}}) this.$logEvent('form_saved', {form_id: this.form.id, form_slug: this.form.slug}) this.displayFormModificationAlert(data) @@ -209,6 +210,7 @@ export default { this.updateFormLoading = true this.form.post('/api/open/forms').then((response) => { this.$store.commit('open/forms/addOrUpdate', response.data.form) + this.$emit('on-save') this.createdFormId = response.data.form.id this.$logEvent('form_created', {form_id: response.data.form.id, form_slug: response.data.form.slug}) diff --git a/resources/js/pages/forms/create.vue b/resources/js/pages/forms/create.vue index ef21c5a..c827529 100644 --- a/resources/js/pages/forms/create.vue +++ b/resources/js/pages/forms/create.vue @@ -10,6 +10,7 @@ 'max-height': editorMaxHeight + 'px' }" :error="error" @mounted="onResize" + @on-save="formInitialHash=null" />
@@ -45,6 +46,16 @@ export default { next() }, + beforeRouteLeave (to, from, next) { + if (this.isDirty()) { + return this.alertConfirm('Changes you made may not be saved. Are you sure want to leave?', () => { + window.onbeforeunload = null + next() + }, () => {}) + } + next() + }, + middleware: 'auth', data() { @@ -54,7 +65,8 @@ export default { loading: false, error: '', editorMaxHeight: 500, - showInitialFormModal: false + showInitialFormModal: false, + formInitialHash: null } }, @@ -90,7 +102,14 @@ export default { }, mounted() { + window.onbeforeunload = () => { + if (this.isDirty()) { + return false + } + } + this.initForm() + this.formInitialHash = this.hashString(JSON.stringify(this.form.data())) if (this.$route.query.template !== undefined && this.$route.query.template) { const template = this.$store.getters['open/templates/getBySlug'](this.$route.query.template) if (template && template.structure) { @@ -127,6 +146,23 @@ export default { }, formGenerated(form) { this.form = new Form({...this.form.data(), ...form}) + }, + isDirty () { + return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.form.data())) + }, + hashString (str, seed = 0) { + let h1 = 0xdeadbeef ^ seed + let h2 = 0x41c6ce57 ^ seed + for (let i = 0, ch; i < str.length; i++) { + ch = str.charCodeAt(i) + h1 = Math.imul(h1 ^ ch, 2654435761) + h2 = Math.imul(h2 ^ ch, 1597334677) + } + + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909) + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909) + + return 4294967296 * (2097151 & h2) + (h1 >>> 0) } } } diff --git a/resources/js/pages/forms/edit.vue b/resources/js/pages/forms/edit.vue index 0a2f541..ddfa392 100644 --- a/resources/js/pages/forms/edit.vue +++ b/resources/js/pages/forms/edit.vue @@ -6,6 +6,7 @@ }" :isEdit="true" @mounted="onResize" + @on-save="formInitialHash=null" />
{{ error }} @@ -42,6 +43,17 @@ export default { store.commit('open/working_form/set', null) // Reset old working form next() }, + + beforeRouteLeave (to, from, next) { + if (this.isDirty()) { + return this.alertConfirm('Changes you made may not be saved. Are you sure want to leave?', () => { + window.onbeforeunload = null + next() + }, () => {}) + } + next() + }, + middleware: 'auth', mixins: [SeoMeta], @@ -49,7 +61,8 @@ export default { return { loading: false, error: null, - editorMaxHeight: 500 + editorMaxHeight: 500, + formInitialHash: null } }, @@ -91,11 +104,18 @@ export default { }, mounted () { + window.onbeforeunload = () => { + if (this.isDirty()) { + return false + } + } + this.closeAlert() if (!this.form) { loadForms() } else { this.updatedForm = new Form(this.form) + this.formInitialHash = this.hashString(JSON.stringify(this.updatedForm.data())) } }, @@ -107,6 +127,21 @@ export default { if (this.$refs.editor) { this.editorMaxHeight = Math.max(500, window.innerHeight - this.$refs.editor.$el.offsetTop) } + }, + isDirty () { + return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.updatedForm.data())) + }, + hashString (str, seed = 0) { + let h1 = 0xdeadbeef ^ seed + let h2 = 0x41c6ce57 ^ seed + for (let i = 0, ch; i < str.length; i++) { + ch = str.charCodeAt(i) + h1 = Math.imul(h1 ^ ch, 2654435761) + h2 = Math.imul(h2 ^ ch, 1597334677) + } + h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909) + h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909) + return 4294967296 * (2097151 & h2) + (h1 >>> 0) } } }