Skip to content
Snippets Groups Projects
SignupFormBuilder.vue 6.38 KiB
Newer Older
  • Learn to ignore specific revisions
  • <template>
      <div>
    
        <div class="ui top attached tabular menu">
          <button :class="[{active: !isPreviewing}, 'item']" @click.stop.prevent="isPreviewing = false">
            <translate translate-context="Content/*/Button.Label/Verb">Edit form</translate>
          </button>
          <button :class="[{active: isPreviewing}, 'item']" @click.stop.prevent="isPreviewing = true">
            <translate translate-context="*/Form/Menu.item">Preview form</translate>
          </button>
        </div>
        <div v-if="isPreviewing" class="ui bottom attached segment">
          <signup-form
            :customization="local"
            :signup-approval-enabled="signupApprovalEnabled"
            :fetch-description-html="true"></signup-form>
          <div class="ui clearing hidden divider"></div>
        </div>
        <div v-else class="ui bottom attached segment">
          <div class="field">
            <label for="help-text">
              <translate translate-context="*/*/Label">Help text</translate>
            </label>
            <p>
              <translate translate-context="*/*/Help">An optional text to be displayed at the start of the sign-up form.</translate>
            </p>
            <content-form
              field-id="help-text"
              :permissive="true"
              :value="(local.help_text || {}).text"
              @input="update('help_text.text', $event)"></content-form>
          </div>
          <div class="field">
            <label>
              <translate translate-context="*/*/Label">Additional fields</translate>
            </label>
            <p>
              <translate translate-context="*/*/Help">Additional form fields to be displayed in the form. Only shown if manual sign-up validation is enabled.</translate>
            </p>
            <table v-if="local.fields.length > 0">
              <thead>
                <tr>
                  <th>
                    <translate translate-context="*/*/Form-builder,Help">Field label</translate>
                  </th>
                  <th>
                    <translate translate-context="*/*/Form-builder,Help">Field type</translate>
                  </th>
                  <th>
                    <translate translate-context="*/*/Form-builder,Help">Required</translate>
                  </th>
                  <th></th>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(field, idx) in local.fields">
                  <td>
                    <input type="text" v-model="field.label" required>
                  </td>
                  <td>
                    <select v-model="field.input_type">
                      <option value="short_text">
                        <translate translate-context="*/*/Form-builder">Short text</translate>
                      </option>
                      <option value="long_text">
                        <translate translate-context="*/*/Form-builder">Long text</translate>
                      </option>
                    </select>
                  </td>
                  <td>
                    <select v-model="field.required">
                      <option :value="true">
                        <translate translate-context="*/*/*">Yes</translate>
                      </option>
                      <option :value="false">
                        <translate translate-context="*/*/*">No</translate>
                      </option>
                    </select>
                  </td>
                  <td>
                    <i
                      :disabled="idx === 0"
                      @click="move(idx, -1)" rel="button"
                      :title="labels.up"
                      :class="['up', 'arrow', {disabled: idx === 0}, 'icon']"></i>
                    <i
                      :disabled="idx >= local.fields.length - 1"
                      @click="move(idx, 1)" rel="button"
                      :title="labels.up"
                      :class="['down', 'arrow', {disabled: idx >= local.fields.length - 1}, 'icon']"></i>
                    <i @click="remove(idx)" rel="button" :title="labels.delete" class="x icon"></i>
                  </td>
                </tr>
              </tbody>
            </table>
            <div class="ui hidden divider"></div>
            <button v-if="local.fields.length < maxFields" class="ui basic button" @click.stop.prevent="addField">
              <translate translate-context="*/*/Form-builder">Add a new field</translate>
            </button>
          </div>
        </div>
        <div class="ui hidden divider"></div>
      </div>
    </template>
    
    <script>
    import lodash from '@/lodash'
    
    import SignupForm from "@/components/auth/SignupForm"
    
    function arrayMove(arr, oldIndex, newIndex) {
      if (newIndex >= arr.length) {
        var k = newIndex - arr.length + 1
        while (k--) {
          arr.push(undefined)
        }
      }
      arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0])
      return arr
    };
    
    // v-model with objects is complex, cf
    // https://simonkollross.de/posts/vuejs-using-v-model-with-objects-for-custom-components
    export default {
      props: {
        value: {type: Object},
        signupApprovalEnabled: {type: Boolean},
      },
      components: {
        SignupForm
      },
      data () {
        return {
          maxFields: 10,
          isPreviewing: false
        }
      },
      created () {
        this.$emit('input', this.local)
      },
      computed: {
        labels () {
          return {
            delete: this.$pgettext('*/*/*', 'Delete'),
            up: this.$pgettext('*/*/*', 'Move up'),
            down: this.$pgettext('*/*/*', 'Move down'),
          }
        },
        local() {
          return (this.value && this.value.fields) ? this.value : { help_text: {text: null, content_type: "text/markdown"}, fields: [] }
        },
      },
      methods: {
        addField () {
          let newValue = lodash.tap(lodash.cloneDeep(this.local), v => v.fields.push({
            label: this.$pgettext('*/*/Form-builder', 'Additional field') + ' ' + (this.local.fields.length + 1),
            required: true,
            input_type: 'short_text',
          }))
          this.$emit('input', newValue)
        },
        remove (idx) {
          this.$emit('input', lodash.tap(lodash.cloneDeep(this.local), v => v.fields.splice(idx, 1)))
        },
        move (idx, incr) {
          if (idx === 0 && incr < 0) {
            return
          }
          if (idx + incr >= this.local.fields.length) {
            return
          }
          let newFields = arrayMove(lodash.cloneDeep(this.local).fields, idx, idx + incr)
          this.update('fields', newFields)
        },
        update(key, value) {
          if (key === 'help_text.text') {
            key = 'help_text'
            if (!value || value.length === 0) {
              value = null
            } else {
              value = {
                text: value,
                content_type: "text/markdown"
              }
            }
          }
          this.$emit('input', lodash.tap(lodash.cloneDeep(this.local), v => lodash.set(v, key, value)))
        },
      },
    }
    </script>