Newer
Older
<form
class="ui form"
@submit.prevent.stop="submit"
>
<div
v-if="errors.length > 0"
role="alert"
class="ui negative message"
>
<h4 class="header">
<translate translate-context="Content/*/Error message.Title">
Error while saving channel
</translate>
</h4>
<li
v-for="(error, key) in errors"
:key="key"
>
{{ error }}
</li>
</ul>
</div>
<template v-if="metadataChoices">
<fieldset
v-if="creating && step === 1"
class="ui grouped channel-type required field"
>
<translate translate-context="Content/Channel/Paragraph">
What will this channel be used for?
</translate>
<div
v-for="(choice, key) in categoryChoices"
:key="key"
:class="['ui', 'radio', 'checkbox', {selected: choice.value == newValues.content_category}]"
>
<input
:id="`category-${choice.value}`"
v-model="newValues.content_category"
type="radio"
name="channel-category"
:value="choice.value"
>
<label :for="`category-${choice.value}`">
<span :class="['right floated', 'placeholder', 'image', {circular: choice.value === 'music'}]" />
<strong>{{ choice.label }}</strong>
{{ choice.helpText }}
</label>
</div>
</div>
<template v-if="!creating || step === 2">
<div class="ui required field">
<label for="channel-name">
<translate translate-context="Content/Channel/*">Name</translate>
</label>
<input
v-model="newValues.name"
type="text"
required
:placeholder="labels.namePlaceholder"
>
</div>
<div class="ui required field">
<label for="channel-username">
jovuit
committed
<translate translate-context="Content/Channel/*">Fediverse handle</translate>
</label>
<div class="ui left labeled input">
<div class="ui basic label">
@
</div>
<input
v-model="newValues.username"
type="text"
:required="creating"
:disabled="!creating"
:placeholder="labels.usernamePlaceholder"
>
</div>
<template v-if="creating">
<translate translate-context="Content/Channels/Paragraph">
Used in URLs and to follow this channel in the Fediverse. It cannot be changed later.
</translate>
</p>
</template>
</div>
<div class="six wide column">
<attachment-input
v-model="newValues.cover"
:required="false"
:image-class="newValues.content_category === 'podcast' ? '' : 'circular'"
@delete="newValues.cover = null"
>
<translate
slot="label"
translate-context="Content/Channel/*"
>
Channel Picture
</translate>
</attachment-input>
</div>
<div class="ui stackable grid row">
<div class="ten wide column">
<div class="ui field">
<label for="channel-tags">
<translate translate-context="*/*/*">Tags</translate>
</label>
<tags-selector
id="channel-tags"
v-model="newValues.tags"
:required="false"
/>
<div
v-if="newValues.content_category === 'podcast'"
class="six wide column"
>
<div class="ui required field">
<label for="channel-language">
<translate translate-context="*/*/*">Language</translate>
</label>
<select
id="channel-language"
v-model="newValues.metadata.language"
class="ui search selection dropdown"
>
<option
v-for="(v, key) in metadataChoices.language"
:key="key"
:value="v.value"
>
{{ v.label }}
</option>
</select>
</div>
</div>
</div>
<div class="ui field">
<label for="channel-name">
<translate translate-context="*/*/*">Description</translate>
</label>
<div
v-if="newValues.content_category === 'podcast'"
class="ui two fields"
>
<div class="ui required field">
<label for="channel-itunes-category">
<translate translate-context="*/*/*">Category</translate>
</label>
<select
id="itunes-category"
v-model="newValues.metadata.itunes_category"
class="ui dropdown"
>
<option
v-for="(v, key) in metadataChoices.itunes_category"
:key="key"
:value="v.value"
>
{{ v.label }}
</option>
</select>
</div>
<div class="ui field">
<label for="channel-itunes-category">
<translate translate-context="*/*/*">Subcategory</translate>
</label>
<select
id="itunes-category"
v-model="newValues.metadata.itunes_subcategory"
:disabled="!newValues.metadata.itunes_category"
class="ui dropdown"
>
<option
v-for="(v, key) in itunesSubcategories"
:key="key"
:value="v"
>
{{ v }}
</option>
</select>
</div>
</div>
<div
v-if="newValues.content_category === 'podcast'"
class="ui two fields"
>
<div class="ui field">
<label for="channel-itunes-email">
jovuit
committed
<translate translate-context="*/*/*">Owner e-mail address</translate>
</label>
<input
id="channel-itunes-email"
v-model="newValues.metadata.owner_email"
name="channel-itunes-email"
type="email"
</div>
<div class="ui field">
<label for="channel-itunes-name">
<translate translate-context="*/*/*">Owner name</translate>
</label>
<input
id="channel-itunes-name"
v-model="newValues.metadata.owner_name"
name="channel-itunes-name"
maxlength="255"
</div>
</div>
<p>
<translate translate-context="*/*/*">
Used for the itunes:email and itunes:name field required by certain platforms such as Spotify or iTunes.
</translate>
</p>
</template>
</template>
<div
v-else
class="ui active inverted dimmer"
>
<div class="ui text loader">
<translate translate-context="*/*/*">
Loading
</translate>
</div>
</div>
</form>
</template>
<script>
import axios from 'axios'
import AttachmentInput from '@/components/common/AttachmentInput.vue'
import TagsSelector from '@/components/library/TagsSelector.vue'
return text.toString().toLowerCase()
.replace(/\s+/g, '') // Remove spaces
.replace(/[^\w]+/g, '') // Remove all non-word chars
}
export default {
components: {
AttachmentInput,
TagsSelector
},
props: {
object: { type: Object, required: false, default: null },
step: { type: Number, required: false, default: 1 }
oldValues.metadata = { ...(this.object.metadata || {}) }
oldValues.name = this.object.artist.name
oldValues.description = this.object.artist.description
oldValues.cover = this.object.artist.cover
oldValues.tags = this.object.artist.tags
oldValues.content_category = this.object.artist.content_category
oldValues.username = this.object.actor.preferred_username
}
return {
isLoading: false,
errors: [],
metadataChoices: null,
newValues: {
name: oldValues.name || '',
username: oldValues.username || '',
tags: oldValues.tags || [],
description: (oldValues.description || {}).text || '',
cover: (oldValues.cover || {}).uuid || null,
content_category: oldValues.content_category || 'podcast',
metadata: oldValues.metadata || {}
}
}
},
computed: {
creating () {
return this.object === null
},
categoryChoices () {
return [
{
value: 'podcast',
label: this.$pgettext('*/*/*', 'Podcasts'),
helpText: this.$pgettext('Content/Channels/Help', 'Host your episodes and keep your community updated.')
value: 'music',
label: this.$pgettext('*/*/*', 'Artist discography'),
helpText: this.$pgettext('Content/Channels/Help', 'Publish music you make as a nice discography of albums and singles.')
}
]
},
itunesSubcategories () {
for (let index = 0; index < this.metadataChoices.itunes_category.length; index++) {
const element = this.metadataChoices.itunes_category[index]
if (element.value === this.newValues.metadata.itunes_category) {
return element.children || []
}
}
return []
},
labels () {
return {
namePlaceholder: this.$pgettext('Content/Channel/Form.Field.Placeholder', 'Awesome channel name'),
usernamePlaceholder: this.$pgettext('Content/Channel/Form.Field.Placeholder', 'awesomechannelname')
}
},
submittable () {
let v = this.newValues.name && this.newValues.username
if (this.newValues.content_category === 'podcast') {
v = v && this.newValues.metadata.itunes_category && this.newValues.metadata.language
}
return !!v
}
},
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
watch: {
'newValues.name' (v) {
if (this.creating) {
this.newValues.username = slugify(v)
}
},
'newValues.metadata.itunes_category' (v) {
this.newValues.metadata.itunes_subcategory = null
},
'newValues.content_category': {
handler (v) {
this.$emit('category', v)
},
immediate: true
},
isLoading: {
handler (v) {
this.$emit('loading', v)
},
immediate: true
},
submittable: {
handler (v) {
this.$emit('submittable', v)
},
immediate: true
}
},
created () {
this.fetchMetadataChoices()
},
methods: {
fetchMetadataChoices () {
axios.get('channels/metadata-choices').then((response) => {
self.metadataChoices = response.data
}, error => {
self.errors = error.backendErrors
})
},
submit () {
this.isLoading = true
const self = this
const handler = this.creating ? axios.post : axios.patch
const url = this.creating ? 'channels/' : `channels/${this.object.uuid}`
const payload = {
name: this.newValues.name,
username: this.newValues.username,
tags: this.newValues.tags,
content_category: this.newValues.content_category,
cover: this.newValues.cover,
}
if (this.newValues.description) {
payload.description = {
content_type: 'text/markdown',
}
} else {
payload.description = null
}
handler(url, payload).then((response) => {
self.isLoading = false
if (self.creating) {
self.$emit('created', response.data)
} else {
self.$emit('updated', response.data)
}
}, error => {
self.isLoading = false
self.errors = error.backendErrors
self.$emit('errored', self.errors)
})
}
}
}
</script>