Skip to content
Snippets Groups Projects
SignupFormBuilder.vue 7.27 KiB
Newer Older
<template>
  <div>
    <div class="ui top attached tabular menu">
Georg Krause's avatar
Georg Krause committed
      <button
        :class="[{active: !isPreviewing}, 'item']"
        @click.stop.prevent="isPreviewing = false"
      >
        <translate translate-context="Content/*/Button.Label/Verb">
          Edit form
        </translate>
      </button>
Georg Krause's avatar
Georg Krause committed
      <button
        :class="[{active: isPreviewing}, 'item']"
        @click.stop.prevent="isPreviewing = true"
      >
        <translate translate-context="*/Form/Menu.item">
          Preview form
        </translate>
      </button>
    </div>
Georg Krause's avatar
Georg Krause committed
    <div
      v-if="isPreviewing"
      class="ui bottom attached segment"
    >
      <signup-form
        :customization="local"
        :signup-approval-enabled="signupApprovalEnabled"
Georg Krause's avatar
Georg Krause committed
        :fetch-description-html="true"
      />
      <div class="ui clearing hidden divider" />
Georg Krause's avatar
Georg Krause committed
    <div
      v-else
      class="ui bottom attached segment"
    >
      <div class="field">
        <label for="help-text">
          <translate translate-context="*/*/Label">Help text</translate>
        </label>
        <p>
Georg Krause's avatar
Georg Krause committed
          <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"
Georg Krause's avatar
Georg Krause committed
          @input="update('help_text.text', $event)"
        />
      </div>
      <div class="field">
        <label>
          <translate translate-context="*/*/Label">Additional fields</translate>
        </label>
        <p>
Georg Krause's avatar
Georg Krause committed
          <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>
Georg Krause's avatar
Georg Krause committed
                <translate translate-context="*/*/Form-builder,Help">
                  Field label
                </translate>
Georg Krause's avatar
Georg Krause committed
                <translate translate-context="*/*/Form-builder,Help">
                  Field type
                </translate>
Georg Krause's avatar
Georg Krause committed
                <translate translate-context="*/*/Form-builder,Help">
                  Required
                </translate>
              <th><span class="visually-hidden"><translate translate-context="*/*/Form-builder,Help">Actions</translate></span></th>
            </tr>
          </thead>
          <tbody>
Georg Krause's avatar
Georg Krause committed
            <tr
              v-for="(field, idx) in local.fields"
              :key="idx"
            >
Georg Krause's avatar
Georg Krause committed
                <input
                  v-model="field.label"
                  type="text"
                  required
                >
              </td>
              <td>
                <select v-model="field.input_type">
                  <option value="short_text">
Georg Krause's avatar
Georg Krause committed
                    <translate translate-context="*/*/Form-builder">
                      Short text
                    </translate>
                  </option>
                  <option value="long_text">
Georg Krause's avatar
Georg Krause committed
                    <translate translate-context="*/*/Form-builder">
                      Long text
                    </translate>
                  </option>
                </select>
              </td>
              <td>
                <select v-model="field.required">
                  <option :value="true">
Georg Krause's avatar
Georg Krause committed
                    <translate translate-context="*/*/*">
                      Yes
                    </translate>
                  </option>
                  <option :value="false">
Georg Krause's avatar
Georg Krause committed
                    <translate translate-context="*/*/*">
                      No
                    </translate>
                  </option>
                </select>
              </td>
              <td>
                <i
                  :disabled="idx === 0"
Georg Krause's avatar
Georg Krause committed
                  role="button"
                  :title="labels.up"
Georg Krause's avatar
Georg Krause committed
                  :class="['up', 'arrow', {disabled: idx === 0}, 'icon']"
                  @click="move(idx, -1)"
                />
                <i
                  :disabled="idx >= local.fields.length - 1"
Georg Krause's avatar
Georg Krause committed
                  role="button"
                  :title="labels.down"
Georg Krause's avatar
Georg Krause committed
                  :class="['down', 'arrow', {disabled: idx >= local.fields.length - 1}, 'icon']"
                  @click="move(idx, 1)"
                />
                <i
                  role="button"
                  :title="labels.delete"
                  class="x icon"
                  @click="remove(idx)"
                />
              </td>
            </tr>
          </tbody>
        </table>
Georg Krause's avatar
Georg Krause committed
        <div class="ui hidden divider" />
        <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>
Georg Krause's avatar
Georg Krause committed
    <div class="ui hidden divider" />
  </div>
</template>

<script>
import lodash from '@/lodash'

Ciaran Ainsworth's avatar
Ciaran Ainsworth committed
import SignupForm from '@/components/auth/SignupForm.vue'
Georg Krause's avatar
Georg Krause committed
function arrayMove (arr, oldIndex, newIndex) {
  if (newIndex >= arr.length) {
Georg Krause's avatar
Georg Krause committed
    let 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 {
  components: {
    SignupForm
  },
Georg Krause's avatar
Georg Krause committed
  props: {
    value: { type: Object, required: true },
    signupApprovalEnabled: { type: Boolean }
  },
  data () {
    return {
      maxFields: 10,
      isPreviewing: false
    }
  },
  computed: {
    labels () {
      return {
        delete: this.$pgettext('*/*/*', 'Delete'),
        up: this.$pgettext('*/*/*', 'Move up'),
Georg Krause's avatar
Georg Krause committed
        down: this.$pgettext('*/*/*', 'Move down')
Georg Krause's avatar
Georg Krause committed
    local () {
      return (this.value && this.value.fields) ? this.value : { help_text: { text: null, content_type: 'text/markdown' }, fields: [] }
    }
  },
  created () {
    this.$emit('input', this.local)
  },
  methods: {
    addField () {
Georg Krause's avatar
Georg Krause committed
      const 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,
Georg Krause's avatar
Georg Krause committed
        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
      }
Georg Krause's avatar
Georg Krause committed
      const newFields = arrayMove(lodash.cloneDeep(this.local).fields, idx, idx + incr)
      this.update('fields', newFields)
    },
Georg Krause's avatar
Georg Krause committed
    update (key, value) {
      if (key === 'help_text.text') {
        key = 'help_text'
        if (!value || value.length === 0) {
          value = null
        } else {
          value = {
            text: value,
Georg Krause's avatar
Georg Krause committed
            content_type: 'text/markdown'
          }
        }
      }
      this.$emit('input', lodash.tap(lodash.cloneDeep(this.local), v => lodash.set(v, key, value)))