Skip to content
Snippets Groups Projects
SignupFormBuilder.vue 7.27 KiB
Newer Older
  • Learn to ignore specific revisions
  • <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)))