roschaefer a7a1e4affc fix: editor not visible in server-side-rendering
This is fixing a bug where sometimes the editor would not get displayed
until you click into the title text fields. This commit also removes
some obscure optimizations.

I'm really annoyed by the cruft that we still carry around until this
very day.

Every single line of untested code, which you left because you thought:
"Well sure this is going to improve performance!" is going to bite you.
2019-12-14 01:36:59 +01:00

301 lines
7.9 KiB
Vue

<template>
<ds-form
class="contribution-form"
ref="contributionForm"
v-model="form"
:schema="formSchema"
@submit="submit"
>
<template slot-scope="{ errors }">
<hc-teaser-image
:contribution="contribution"
@addTeaserImage="addTeaserImage"
@addImageAspectRatio="addImageAspectRatio"
>
<img
v-if="contribution"
class="contribution-image"
:src="contribution.image | proxyApiUrl"
/>
</hc-teaser-image>
<ds-card>
<ds-space />
<client-only>
<hc-user :user="currentUser" :trunc="35" />
</client-only>
<ds-space />
<ds-input
model="title"
class="post-title"
:placeholder="$t('contribution.title')"
name="title"
autofocus
/>
<ds-text align="right">
<ds-chip v-if="errors && errors.title" color="danger" size="base">
{{ form.title.length }}/{{ formSchema.title.max }}
<ds-icon name="warning"></ds-icon>
</ds-chip>
<ds-chip v-else size="base">{{ form.title.length }}/{{ formSchema.title.max }}</ds-chip>
</ds-text>
<hc-editor
:users="users"
:value="form.content"
:hashtags="hashtags"
@input="updateEditorContent"
/>
<ds-text align="right">
<ds-chip v-if="errors && errors.content" color="danger" size="base">
{{ contentLength }}
<ds-icon name="warning"></ds-icon>
</ds-chip>
<ds-chip v-else size="base">
{{ contentLength }}
</ds-chip>
</ds-text>
<ds-space margin-bottom="small" />
<hc-categories-select model="categoryIds" :existingCategoryIds="form.categoryIds" />
<ds-text align="right">
<ds-chip v-if="errors && errors.categoryIds" color="danger" size="base">
{{ form.categoryIds.length }} / 3
<ds-icon name="warning"></ds-icon>
</ds-chip>
<ds-chip v-else size="base">{{ form.categoryIds.length }} / 3</ds-chip>
</ds-text>
<ds-flex class="contribution-form-footer">
<ds-flex-item :width="{ lg: '50%', md: '50%', sm: '100%' }" />
<ds-flex-item>
<ds-space margin-bottom="small" />
<ds-select
model="language"
:options="languageOptions"
icon="globe"
:placeholder="$t('contribution.languageSelectText')"
:label="$t('contribution.languageSelectLabel')"
/>
</ds-flex-item>
</ds-flex>
<ds-text align="right">
<ds-chip v-if="errors && errors.language" size="base" color="danger">
<ds-icon name="warning"></ds-icon>
</ds-chip>
</ds-text>
<ds-space />
<div slot="footer" style="text-align: right">
<ds-button
class="cancel-button"
:disabled="loading"
ghost
@click.prevent="$router.back()"
>
{{ $t('actions.cancel') }}
</ds-button>
<ds-button type="submit" icon="check" :loading="loading" :disabled="errors" primary>
{{ $t('actions.save') }}
</ds-button>
</div>
<ds-space margin-bottom="large" />
</ds-card>
</template>
</ds-form>
</template>
<script>
import gql from 'graphql-tag'
import orderBy from 'lodash/orderBy'
import { mapGetters } from 'vuex'
import HcEditor from '~/components/Editor/Editor'
import locales from '~/locales'
import PostMutations from '~/graphql/PostMutations.js'
import HcCategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
import HcTeaserImage from '~/components/TeaserImage/TeaserImage'
import HcUser from '~/components/User/User'
export default {
components: {
HcEditor,
HcCategoriesSelect,
HcTeaserImage,
HcUser,
},
props: {
contribution: { type: Object, default: () => {} },
},
data() {
const languageOptions = orderBy(locales, 'name').map(locale => {
return { label: locale.name, value: locale.code }
})
const formDefaults = {
title: '',
content: '',
teaserImage: null,
imageAspectRatio: null,
image: null,
language: null,
categoryIds: [],
}
let id = null
let slug = null
const form = { ...formDefaults }
if (this.contribution && this.contribution.id) {
id = this.contribution.id
slug = this.contribution.slug
form.title = this.contribution.title
form.content = this.contribution.content
form.image = this.contribution.image
form.language =
this.contribution && this.contribution.language
? languageOptions.find(o => this.contribution.language === o.value)
: null
form.categoryIds = this.categoryIds(this.contribution.categories)
}
return {
form,
formSchema: {
title: { required: true, min: 3, max: 100 },
content: { required: true },
categoryIds: {
type: 'array',
required: true,
validator: (rule, value) => {
const errors = []
if (!(value && value.length >= 1 && value.length <= 3)) {
errors.push(new Error(this.$t('common.validations.categories')))
}
return errors
},
},
language: { required: true },
},
languageOptions,
id,
slug,
loading: false,
users: [],
contentMin: 3,
hashtags: [],
}
},
computed: {
contentLength() {
return this.$filters.removeHtml(this.form.content).length
},
...mapGetters({
currentUser: 'auth/user',
}),
},
methods: {
submit() {
const {
language: { value: language },
title,
content,
image,
teaserImage,
imageAspectRatio,
categoryIds,
} = this.form
this.loading = true
this.$apollo
.mutate({
mutation: this.id ? PostMutations().UpdatePost : PostMutations().CreatePost,
variables: {
id: this.id,
title,
content,
categoryIds,
language,
image,
imageUpload: teaserImage,
imageAspectRatio,
},
})
.then(({ data }) => {
this.loading = false
this.$toast.success(this.$t('contribution.success'))
const result = data[this.id ? 'UpdatePost' : 'CreatePost']
this.$router.push({
name: 'post-id-slug',
params: { id: result.id, slug: result.slug },
})
})
.catch(err => {
this.$toast.error(err.message)
this.loading = false
})
},
updateEditorContent(value) {
this.$refs.contributionForm.update('content', value)
},
addTeaserImage(file) {
this.form.teaserImage = file
},
addImageAspectRatio(aspectRatio) {
this.form.imageAspectRatio = aspectRatio
},
categoryIds(categories) {
return categories.map(c => c.id)
},
},
apollo: {
User: {
query() {
return gql`
query {
User(orderBy: slug_asc) {
id
slug
}
}
`
},
result({ data: { User } }) {
this.users = User
},
},
Tag: {
query() {
return gql`
query {
Tag(orderBy: id_asc) {
id
}
}
`
},
result({ data: { Tag } }) {
this.hashtags = Tag
},
},
},
}
</script>
<style lang="scss" scoped>
.smallTag {
width: 100%;
position: relative;
left: 90%;
}
.post-title {
margin-top: $space-x-small;
margin-bottom: $space-xx-small;
input {
border: 0;
font-size: $font-size-x-large;
font-weight: bold;
padding-left: 0;
padding-right: 0;
}
}
.contribution-form {
.ds-chip {
cursor: default;
}
}
</style>