skillbox/client/src/components/content-block-form/ContentsForm.vue

294 lines
8.1 KiB
Vue

<template>
<modal>
<template slot="header">
<modal-input v-on:input="updateTitle"
:placeholder="titlePlaceholder"
:value="localContentBlock.title"
:error="error"></modal-input>
<checkbox :checked="localContentBlock.isAssignment"
:item="localContentBlock"
:label="'Aufgabe'"
@input="setContentBlockType"
class="contents-form__task"
></checkbox>
<modal-input v-if="blockType === 'RoomEntry'"
placeholder="Untertitel für Raumeintrag erfassen"
v-model="localContentBlock.subtitle"></modal-input>
</template>
<add-content-element class="contents-form__add"
v-on:add-element="addElement"
:index="-1"
></add-content-element>
<div v-for="(element, index) in localContentBlock.contents" :key="index" class="contents-form__element">
<component
class="contents-form__element-component"
:is="type(element)"
:class="{'contents-form__chooser': type(element) === 'content-block-element-chooser-widget'}"
v-bind="element" :index="index"
v-on:change-type="changeType"
v-on:link-change-url="changeLinkUrl"
v-on:link-change-text="changeLinkText"
v-on:text-change-value="changeTextValue"
v-on:document-change-url="changeDocumentUrl"
v-on:image-change-url="changeImageUrl"
v-on:video-change-url="changeVideoUrl"
v-on:assignment-change-title="changeAssignmentTitle"
v-on:assignment-change-assignment="changeAssignmentAssignment"
>
</component>
<a class="contents-form__remove" v-on:click="removeElement(index)">
<trash-icon v-if="type(element) !== 'content-block-element-chooser-widget'"
class="contents-form__trash-icon"></trash-icon>
</a>
<add-content-element class="contents-form__add"
v-on:add-element="addElement"
:index="index"
></add-content-element>
</div>
<div slot="footer">
<a class="button button--primary" v-on:click="save">Speichern</a>
<a class="button" v-on:click="$emit('hide')">Abbrechen</a>
</div>
</modal>
</template>
<script>
import Modal from '@/components/Modal';
import ContentBlockElementChooserWidget from '@/components/content-forms/ContentBlockElementChooserWidget';
import ModalInput from '@/components/ModalInput';
import AddContentElement from '@/components/AddContentElement';
import LinkForm from '@/components/content-forms/LinkForm';
import VideoForm from '@/components/content-forms/VideoForm';
import ImageForm from '@/components/content-forms/ImageForm';
import DocumentForm from '@/components/content-forms/DocumentForm';
import AssignmentForm from '@/components/content-forms/AssignmentForm';
import TextForm from '@/components/content-forms/TextForm';
import TrashIcon from '@/components/icons/TrashIcon';
import Checkbox from '@/components/Checkbox';
export default {
props: {
'content-block': Object,
'block-type': {
type: String,
default: 'ContentBlock'
}
},
components: {
Modal,
ContentBlockElementChooserWidget,
ModalInput,
AddContentElement,
LinkForm,
VideoForm,
ImageForm,
DocumentForm,
AssignmentForm,
TextForm,
TrashIcon,
Checkbox
},
data() {
return {
error: false,
localContentBlock: Object.assign({}, {
title: this.contentBlock.title,
contents: [...this.contentBlock.contents],
id: this.contentBlock.id || undefined,
subtitle: this.contentBlock.subtitle,
isAssignment: this.contentBlock.type && this.contentBlock.type === 'TASK'
})
}
},
computed: {
titlePlaceholder() {
return this.blockType === 'RoomEntry' ? 'Titel für Raumeintrag erfassen' : 'Titel für Inhaltsblock erfassen';
}
},
methods: {
type(element) {
switch (element.type) {
case 'link_block':
return 'link-form';
case 'video_block':
return 'video-form';
case 'image_url_block':
return 'image-form';
case 'text_block':
return 'text-form';
case 'assignment':
return 'assignment-form';
case 'document_block':
return 'document-form';
}
return 'content-block-element-chooser-widget'
},
_updateProperty(value, index, key) {
const content = this.localContentBlock.contents[index];
this.localContentBlock.contents.splice(index, 1, {
...content,
value: {
...content.value,
[key]: value
}
});
},
changeLinkUrl(value, index) {
this._updateProperty(value, index, 'url')
},
changeLinkText(value, index) {
this._updateProperty(value, index, 'text')
},
changeVideoUrl(value, index) {
this._updateProperty(value, index, 'url')
},
changeImageUrl(value, index) {
this._updateProperty(value, index, 'url')
},
changeDocumentUrl(value, index) {
this._updateProperty(value, index, 'url')
},
changeTextValue(value, index) {
this._updateProperty(value, index, 'text')
},
changeAssignmentTitle(value, index) {
this._updateProperty(value, index, 'title')
},
changeAssignmentAssignment(value, index) {
this._updateProperty(value, index, 'assignment')
},
removeElement(index) {
this.localContentBlock.contents.splice(index, 1);
},
addElement(index) {
this.localContentBlock.contents.splice(index + 1, 0, {})
},
updateTitle(title) {
this.localContentBlock.title = title;
this.error = false;
},
changeType(index, type) {
let el = {
type: type,
value: {}
};
switch (type) {
case 'text_block':
el = {
...el,
value: {
text: ''
}
};
break;
case 'link_block':
el = {
...el,
value: {
text: '',
url: ''
}
};
break;
case 'video_block':
el = {
...el,
value: {
url: ''
}
};
break;
case 'document_block':
el = {
...el,
value: {
url: ''
}
};
break;
case 'image_url_block':
el = {
...el,
value: {
url: ''
}
};
break;
}
this.localContentBlock.contents.splice(index, 1, el);
},
save() {
if (!this.localContentBlock.title) {
this.error = true;
return false;
}
this.$emit('save', this.localContentBlock);
},
setContentBlockType(checked, localContentBlock) {
this.localContentBlock.isAssignment = checked;
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/_variables.scss";
.contents-form {
/* top level does not exist, because of the modal */
&__element {
display: grid;
grid-template-columns: 1fr 50px;
grid-auto-rows: auto;
/*width: 95%; // reserve space for scrollbar*/
}
&__element-component {
margin-bottom: 25px;
}
&__remove {
display: flex;
justify-content: center;
align-items: center;
width: 50px;
height: 50px;
}
&__trash-icon {
width: 25px;
height: 25px;
fill: $color-grey;
cursor: pointer;
justify-self: center;
}
&__chooser {
grid-column: 1 / span 2;
}
&__add {
grid-column: 1 / span 2;
}
&__task {
margin: 15px 0 10px;
}
}
</style>