Better form editor (#187)

This commit is contained in:
formsdev 2023-09-05 19:55:33 +05:30 committed by GitHub
parent a21eb851aa
commit c66c09e17b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 101 additions and 104 deletions

View File

@ -84,7 +84,8 @@ export default {
message: '', message: '',
confirmationProceed: null, confirmationProceed: null,
confirmationCancel: null confirmationCancel: null
} },
navbarHidden: false
}), }),
mounted () { mounted () {
@ -106,6 +107,9 @@ export default {
}, },
workspaceAdded () { workspaceAdded () {
this.$router.push({ name: 'home' }) this.$router.push({ name: 'home' })
},
hideNavbar (hidden = true) {
this.navbarHidden = hidden
} }
}, },

View File

@ -183,7 +183,7 @@ export default {
return false return false
} }
} }
return true return !this.$root.navbarHidden
}, },
isIframe() { isIframe() {
return window.location !== window.parent.location || window.frameElement return window.location !== window.parent.location || window.frameElement

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-if="form" class="open-complete-form"> <div v-if="form" class="open-complete-form">
<h1 v-if="!isHideTitle" class="mb-4 px-2" :class="{&quot;mt-4&quot;:isEmbedPopup}" v-text="form.title" /> <h1 v-if="!isHideTitle" class="mb-4 px-2" :class="{'mt-4':isEmbedPopup}" v-text="form.title" />
<div v-if="isPublicFormPage && form.is_password_protected"> <div v-if="isPublicFormPage && form.is_password_protected">
<p class="form-description mb-4 text-gray-700 dark:text-gray-300 px-2"> <p class="form-description mb-4 text-gray-700 dark:text-gray-300 px-2">
@ -76,7 +76,7 @@
> >
<template #submit-btn="{submitForm}"> <template #submit-btn="{submitForm}">
<open-form-button :loading="loading" :theme="theme" :color="form.color" class="mt-2 px-8 mx-1" <open-form-button :loading="loading" :theme="theme" :color="form.color" class="mt-2 px-8 mx-1"
@click.prevent="submitForm" :class="submitButtonClass" @click.prevent="submitForm"
> >
{{ form.submit_button_text }} {{ form.submit_button_text }}
</open-form-button> </open-form-button>
@ -123,7 +123,8 @@ export default {
props: { props: {
form: { type: Object, required: true }, form: { type: Object, required: true },
creating: { type: Boolean, default: false }, // If true, fake form submit creating: { type: Boolean, default: false }, // If true, fake form submit
adminPreview: { type: Boolean, default: false } // If used in FormEditorPreview adminPreview: { type: Boolean, default: false }, // If used in FormEditorPreview
submitButtonClass: { type: String, default: '' }
}, },
mixins: [FormPendingSubmissionKey], mixins: [FormPendingSubmissionKey],

View File

@ -1,54 +1,80 @@
<template> <template>
<div v-if="form" id="form-editor" class="w-full flex flex-grow relative overflow-x-hidden"> <div v-if="form" id="form-editor" class="relative flex w-full flex-col grow max-h-screen">
<!-- Form fields selection --> <!-- Navbar -->
<div class="w-full md:w-1/2 lg:w-2/5 border-r relative overflow-y-scroll md:max-w-sm flex-shrink-0"> <div class="w-full border-b p-2 flex items-center justify-between bg-white">
<div class="p-4 bg-blue-50 border-b text-nt-blue-dark md:hidden"> <a v-if="backButton" href="#" class="ml-2 flex text-blue font-semibold text-sm"
We suggest you create this form on a device with a larger screen such as computed. That will allow you @click.prevent="$router.back()"
to preview your form changes. >
</div> <svg class="w-3 h-3 text-blue mt-1 mr-1" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<div class="p-4 pb-0"> <path d="M5 9L1 5L5 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"
<a v-if="!isGuest" href="#" @click.prevent="$router.back()" class="flex text-blue mb-2 font-semibold text-sm"> stroke-linejoin="round"
<svg class="w-3 h-3 text-blue mt-1 mr-1" viewBox="0 0 6 10" fill="none" xmlns="http://www.w3.org/2000/svg"> />
<path d="M5 9L1 5L5 1" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" </svg>
stroke-linejoin="round"/> Go back
</svg> </a>
Go back <div class="hidden md:flex items-center ml-3">
</a> <h3 class="font-semibold text-lg max-w-[14rem] truncate text-gray-500">
<template v-if="isEdit"> {{ form.title }}
<h3 class="font-semibold text-lg">{{ form.title }}</h3> </h3>
<small class="text-gray-500">Edited {{ form.last_edited_human }}</small>
</template>
</div> </div>
<div class="p-4 border-b sticky top-0 z-10 bg-white"> <div class="flex items-center" :class="{'mx-auto md:mx-0':!backButton}">
<v-button v-track.save_form_click class="w-full" :loading="updateFormLoading" <div class="hidden md:block mr-10 relative">
@click="saveForm"> <a href="#"
<svg class="w-4 h-4 text-white inline mr-1 -mt-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> class="text-sm px-3 py-2 hover:bg-gray-50 cursor-pointer rounded-md text-gray-500 px-0 sm:px-3 hover:text-gray-800 cursor-pointer mt-1"
<path d="M17 21V13H7V21M7 3V8H15M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> @click.prevent="$crisp.push(['do', 'helpdesk:search'])"
>
Help
</a>
</div>
<v-button v-track.save_form_click size="small" class="w-full px-8 md:px-4 py-2"
:loading="updateFormLoading" :class="saveButtonClass"
@click="saveForm"
>
<svg class="w-4 h-4 text-white inline mr-1 -mt-1" viewBox="0 0 24 24" fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17 21V13H7V21M7 3V8H15M19 21H5C4.46957 21 3.96086 20.7893 3.58579 20.4142C3.21071 20.0391 3 19.5304 3 19V5C3 4.46957 3.21071 3.96086 3.58579 3.58579C3.96086 3.21071 4.46957 3 5 3H16L21 8V19C21 19.5304 20.7893 20.0391 20.4142 20.4142C20.0391 20.7893 19.5304 21 19 21Z"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
/>
</svg> </svg>
<template v-if="form.visibility === 'public'">
Save changes Publish Form
</template>
<template v-else>
Save Changes
</template>
</v-button> </v-button>
</div> </div>
<form-information/>
<form-structure/>
<form-customization/>
<form-about-submission/>
<form-notifications/>
<form-security-privacy/>
<form-custom-seo />
<form-custom-code/>
<form-integrations/>
</div> </div>
<form-editor-preview/> <div class="w-full flex grow overflow-y-scroll">
<div class="relative w-full shrink-0 overflow-y-scroll border-r md:w-1/2 md:max-w-sm lg:w-2/5">
<div class="border-b bg-blue-50 p-5 text-nt-blue-dark md:hidden">
Please create this form on a device with a larger screen. That will allow you to preview your form changes.
</div>
<!-- Form Error Modal --> <form-information/>
<form-error-modal :show="showFormErrorModal" <form-structure/>
:validation-error-response="validationErrorResponse" <form-customization/>
@close="showFormErrorModal=false" <form-about-submission/>
/> <form-notifications/>
<form-security-privacy/>
<form-custom-seo />
<form-custom-code/>
<form-integrations/>
</div>
<form-editor-preview/>
<!-- Form Error Modal -->
<form-error-modal
:show="showFormErrorModal"
:validation-error-response="validationErrorResponse"
@close="showFormErrorModal=false"
/>
</div>
</div> </div>
<div v-else class="flex justify-center items-center"> <div v-else class="flex justify-center items-center">
<loader class="w-6 h-6"/> <loader class="w-6 h-6"/>
@ -98,6 +124,16 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
backButton: {
required: false,
type: Boolean,
default: true
},
saveButtonClass: {
required: false,
type: String,
default: ''
}
}, },
data() { data() {
@ -170,6 +206,11 @@ export default {
mounted() { mounted() {
this.$emit('mounted') this.$emit('mounted')
this.$root.hideNavbar()
},
beforeDestroy () {
this.$root.hideNavbar(false)
}, },
methods: { methods: {

View File

@ -6,11 +6,8 @@
@close="showInitialFormModal=false"/> @close="showInitialFormModal=false"/>
<form-editor v-if="!workspacesLoading" ref="editor" <form-editor v-if="!workspacesLoading" ref="editor"
class="w-full flex flex-grow" class="w-full flex flex-grow"
:style="{ :error="error"
'max-height': editorMaxHeight + 'px'
}" :error="error"
:isGuest="isGuest" :isGuest="isGuest"
@mounted="onResize"
@openRegister="openRegister" @openRegister="openRegister"
/> />
<div v-else class="text-center mt-4 py-6"> <div v-else class="text-center mt-4 py-6">
@ -61,7 +58,6 @@ export default {
stateReady: false, stateReady: false,
loading: false, loading: false,
error: '', error: '',
editorMaxHeight: 500,
registerModal: false, registerModal: false,
isGuest: true, isGuest: true,
showInitialFormModal: false showInitialFormModal: false
@ -120,25 +116,13 @@ export default {
this.stateReady = true this.stateReady = true
}, },
created() { created() {},
window.addEventListener('resize', this.onResize) destroyed() {},
},
destroyed() {
window.removeEventListener('resize', this.onResize)
},
methods: { methods: {
...mapActions({ ...mapActions({
loadWorkspaces: 'open/workspaces/load' loadWorkspaces: 'open/workspaces/load'
}), }),
/**
* Compute max height of editor
*/
onResize() {
if (this.$refs.editor) {
this.editorMaxHeight = window.innerHeight - this.$refs.editor.$el.offsetTop
}
},
openRegister() { openRegister() {
this.registerModal = true this.registerModal = true
}, },

View File

@ -6,10 +6,7 @@
@close="showInitialFormModal=false"/> @close="showInitialFormModal=false"/>
<form-editor v-if="!workspacesLoading" ref="editor" <form-editor v-if="!workspacesLoading" ref="editor"
class="w-full flex flex-grow" class="w-full flex flex-grow"
:style="{ :error="error"
'max-height': editorMaxHeight + 'px'
}" :error="error"
@mounted="onResize"
@on-save="formInitialHash=null" @on-save="formInitialHash=null"
/> />
<div v-else class="text-center mt-4 py-6"> <div v-else class="text-center mt-4 py-6">
@ -64,7 +61,6 @@ export default {
stateReady: false, stateReady: false,
loading: false, loading: false,
error: '', error: '',
editorMaxHeight: 500,
showInitialFormModal: false, showInitialFormModal: false,
formInitialHash: null formInitialHash: null
} }
@ -125,25 +121,13 @@ export default {
this.stateReady = this.user !== null this.stateReady = this.user !== null
}, },
created() { created() {},
window.addEventListener('resize', this.onResize) destroyed() {},
},
destroyed() {
window.removeEventListener('resize', this.onResize)
},
methods: { methods: {
...mapActions({ ...mapActions({
loadWorkspaces: 'open/workspaces/loadIfEmpty' loadWorkspaces: 'open/workspaces/loadIfEmpty'
}), }),
/**
* Compute max height of editor
*/
onResize() {
if (this.$refs.editor) {
this.editorMaxHeight = window.innerHeight - this.$refs.editor.$el.offsetTop
}
},
formGenerated(form) { formGenerated(form) {
this.form = new Form({...this.form.data(), ...form}) this.form = new Form({...this.form.data(), ...form})
}, },

View File

@ -1,11 +1,7 @@
<template> <template>
<div class="w-full flex flex-col"> <div class="w-full flex flex-col">
<form-editor v-if="pageLoaded" ref="editor" <form-editor v-if="pageLoaded" ref="editor"
:style="{
'max-height': editorMaxHeight + 'px'
}"
:isEdit="true" :isEdit="true"
@mounted="onResize"
@on-save="formInitialHash=null" @on-save="formInitialHash=null"
/> />
<div v-else-if="!loading && error" class="mt-4 rounded-lg max-w-xl mx-auto p-6 bg-red-100 text-red-500"> <div v-else-if="!loading && error" class="mt-4 rounded-lg max-w-xl mx-auto p-6 bg-red-100 text-red-500">
@ -61,7 +57,6 @@ export default {
return { return {
loading: false, loading: false,
error: null, error: null,
editorMaxHeight: 500,
formInitialHash: null formInitialHash: null
} }
}, },
@ -96,12 +91,8 @@ export default {
} }
}, },
created () { created () {},
window.addEventListener('resize', this.onResize) destroyed () {},
},
destroyed () {
window.removeEventListener('resize', this.onResize)
},
mounted () { mounted () {
window.onbeforeunload = () => { window.onbeforeunload = () => {
@ -120,14 +111,6 @@ export default {
}, },
methods: { methods: {
/**
* Compute max height of editor
*/
onResize () {
if (this.$refs.editor) {
this.editorMaxHeight = Math.max(500, window.innerHeight - this.$refs.editor.$el.offsetTop)
}
},
isDirty () { isDirty () {
return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.updatedForm.data())) return !this.loading && this.formInitialHash && this.formInitialHash !== this.hashString(JSON.stringify(this.updatedForm.data()))
}, },