<template> <form @submit.prevent="submit"> <FormElement :error="fieldHasErrors('name')" class="control"> <label class="control__label"> <i class="fas fa-font"></i> {{ $t('pageForm.nameLabel') }} </label> <input ref="name" v-model="values.name" type="text" class="input input--large" :class="{ 'input--error': fieldHasErrors('name') }" @focus.once="$event.target.select()" @blur="$v.values.name.$touch()" /> <div v-if="$v.values.name.$dirty && !$v.values.name.required" class="error" > {{ $t('error.requiredField') }} </div> <div v-if="$v.values.name.$dirty && !$v.values.name.maxLength" class="error" > {{ $t('error.maxLength', { max: 255 }) }} </div> <div v-if="$v.values.name.$dirty && !$v.values.name.isUnique" class="error" > {{ $t('pageForm.errorNameNotUnique') }} </div> </FormElement> <FormElement :error="fieldHasErrors('path')" class="control"> <label class="control__label"> <i class="fas fa-font"></i> {{ $t('pageForm.pathLabel') }} </label> <input ref="path" v-model="values.path" type="text" class="input input--large" :class="{ 'input--error': fieldHasErrors('path') }" @input="hasPathBeenEdited = true" @focus.once="$event.target.select()" @blur="$v.values.path.$touch()" /> <div v-if="$v.values.path.$dirty && !$v.values.path.required" class="error" > {{ $t('error.requiredField') }} </div> <div v-if="$v.values.path.$dirty && !$v.values.path.isUnique" class="error" > {{ $t('pageForm.errorPathNotUnique') }} </div> <div v-if="$v.values.path.$dirty && !$v.values.path.maxLength" class="error" > {{ $t('error.maxLength', { max: 255 }) }} </div> <div v-if="$v.values.path.$dirty && !$v.values.path.startingSlash" class="error" > {{ $t('pageForm.errorStartingSlash') }} </div> <div v-if="$v.values.path.$dirty && !$v.values.path.validPathCharacters" class="error" > {{ $t('pageForm.errorValidPathCharacters') }} </div> </FormElement> <slot></slot> </form> </template> <script> import form from '@baserow/modules/core/mixins/form' import { maxLength, required } from 'vuelidate/lib/validators' import { getNextAvailableNameInSequence, slugify, } from '@baserow/modules/core/utils/string' import { VALID_PATH_CHARACTERS } from '@baserow/modules/builder/enums' export default { name: 'PageForm', mixins: [form], props: { builder: { type: Object, required: true, }, creation: { type: Boolean, default: true, }, }, data() { return { allowedValues: ['name', 'path'], values: { name: '', path: '', }, hasPathBeenEdited: false, } }, computed: { pageNames() { return this.builder.pages.map((page) => page.name) }, pagePaths() { return this.builder.pages.map((page) => page.path) }, defaultName() { const baseName = this.$t('pageForm.defaultName') return getNextAvailableNameInSequence(baseName, this.pageNames) }, }, watch: { 'values.name': { handler(value) { if (!this.hasPathBeenEdited && this.creation) { this.values.path = `/${slugify(value)}` } }, immediate: true, }, }, created() { if (this.creation) { this.values.name = this.defaultName } }, mounted() { if (this.creation) { this.$refs.name.focus() } }, methods: { isNameUnique(name) { return !this.pageNames.includes(name) }, isPathUnique(path) { return !this.pagePaths.includes(path) }, pathStartsWithSlash(path) { return path[0] === '/' }, pathHasValidCharacters(path) { return !path .split('') .some((letter) => !VALID_PATH_CHARACTERS.includes(letter)) }, }, validations() { return { values: { name: { required, isUnique: this.isNameUnique, maxLength: maxLength(255), }, path: { required, isUnique: this.isPathUnique, maxLength: maxLength(255), startingSlash: this.pathStartsWithSlash, validPathCharacters: this.pathHasValidCharacters, }, }, } }, } </script>