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

356 lines
10 KiB
Vue

<template>
<div class="content-element">
<!-- Element Chooser if element has chooser type or no type -->
<content-block-element-chooser-widget
:class="['content-element__component', 'content-element__chooser']"
v-bind="element"
v-if="isChooser"
@change-type="changeType"
@remove="$emit('remove', false)"
/>
<!-- Content Forms -->
<content-form-section
:title="title"
:actions="actions"
v-else
@top="$emit('top')"
@up="$emit('up')"
@down="$emit('down')"
@bottom="$emit('bottom')"
@remove="$emit('remove')"
>
<div class="content-element__section">
<!-- Form depending on type of element -->
<component
:class="['content-element__component']"
v-bind="element"
:is="component"
@change-text="changeText"
@link-change-url="changeUrl"
@change-url="changeUrl"
@switch-to-document="switchToDocument"
@assignment-change-title="changeAssignmentTitle"
@assignment-change-assignment="changeAssignmentAssignment"
/>
</div>
</content-form-section>
</div>
</template>
<script>
import ContentFormSection from '@/components/content-block-form/ContentFormSection';
import ContentElementActions from '@/components/content-block-form/ContentElementActions';
const TrashIcon = () => import(/* webpackChunkName: "icons" */'@/components/icons/TrashIcon');
const ContentBlockElementChooserWidget = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ContentBlockElementChooserWidget');
const LinkForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/LinkForm');
const VideoForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/VideoForm');
const ImageForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/ImageForm');
const DocumentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/DocumentForm');
const AssignmentForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/AssignmentForm');
const TextForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/TipTap.vue');
const SubtitleForm = () => import(/* webpackChunkName: "content-forms" */'@/components/content-forms/SubtitleForm');
// readonly blocks
const Assignment = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/assignment/Assignment');
const SurveyBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/SurveyBlock');
const Solution = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/Solution');
const ImageBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ImageBlock');
const Instruction = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/Instruction');
const ModuleRoomSlug = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ModuleRoomSlug');
const CmsDocumentBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/CmsDocumentBlock');
const ThinglinkBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/ThinglinkBlock');
const InfogramBlock = () => import(/* webpackChunkName: "content-forms" */'@/components/content-blocks/InfogramBlock');
const CHOOSER = 'content-block-element-chooser-widget';
export default {
props: {
element: {
type: Object,
default: null,
},
// is this element at the top level, or is it nested? we assume top level
topLevel: {
type: Boolean,
default: true,
},
firstElement: {
type: Boolean,
required: true,
},
lastElement: {
type: Boolean,
required: true,
},
},
components: {
ContentElementActions,
ContentFormSection,
TrashIcon,
ContentBlockElementChooserWidget,
LinkForm,
VideoForm,
ImageForm,
DocumentForm,
AssignmentForm,
TextForm,
SubtitleForm,
SurveyBlock,
Solution,
ImageBlock,
Instruction,
ModuleRoomSlug,
CmsDocumentBlock,
InfogramBlock,
ThinglinkBlock,
Assignment
},
computed: {
actions() {
return {
up: !this.firstElement,
down: !this.lastElement,
extended: this.topLevel,
};
},
isChooser() {
return this.component === CHOOSER;
},
type() {
return this.getType(this.element);
},
component() {
return this.type.component;
},
title() {
return this.type.title;
},
icon() {
return this.type.icon;
},
},
methods: {
getType(element) {
switch (element.type) {
case 'subtitle':
return {
component: 'subtitle-form',
title: 'Untertitel',
icon: 'title-icon',
};
case 'link_block':
return {
component: 'link-form',
title: 'Link',
icon: 'link-icon',
};
case 'video_block':
return {
component: 'video-form',
title: 'Video',
icon: 'video-icon',
};
case 'image_url_block':
return {
component: 'image-form',
title: 'Bild',
icon: 'image-icon',
};
case 'text_block':
return {
component: 'text-form',
title: 'Text',
icon: 'text-icon',
};
case 'assignment':
return {
component: element.id ? 'assignment' : 'assignment-form', // prevent editing of existing assignments
title: 'Aufgabe & Ergebnis',
icon: 'speech-bubble-icon',
};
case 'document_block':
return {
component: 'document-form',
title: 'Dokument',
icon: 'document-icon',
};
case 'survey':
return {
component: 'survey-block',
title: 'Übung',
};
case 'solution':
return {
component: 'solution',
title: 'Lösung',
};
case 'image_block':
return {
component: 'image-block',
title: 'Bild',
};
case 'instruction':
return {
component: 'instruction',
title: 'Instruktion',
};
case 'module_room_slug':
return {
component: 'module-room-slug',
title: 'Raum',
};
case 'cms_document_block':
return {
component: 'cms-document-block',
title: 'Dokument',
};
case 'thinglink_block':
return {
component: 'thinglink-block',
title: 'Interaktive Grafik'
};
case 'infogram_block':
return {
component: 'infogram-block',
title: 'Interaktive Grafik'
};
}
return {
component: CHOOSER,
title: '',
icon: '',
};
},
_updateProperty(value, key) {
// const content = this.localContentBlock.contents[index];
const content = this.element;
this.update({
...content,
value: {
...content.value,
[key]: value,
},
});
},
changeUrl(value) {
this._updateProperty(value, 'url');
},
changeText(value) {
this._updateProperty(value, 'text');
},
changeAssignmentTitle(value) {
this._updateProperty(value, 'title');
},
changeAssignmentAssignment(value) {
this._updateProperty(value, 'assignment');
},
changeType({type, convertToList}, value) {
let el = {
type: type,
value: Object.assign({}, value),
};
switch (type) {
case 'subtitle':
el = {
...el,
value: {
text: '',
},
};
break;
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: Object.assign({
url: '',
}, value),
};
break;
case 'image_url_block':
el = {
...el,
value: {
url: '',
},
};
break;
}
if (convertToList) {
el = {
type: 'content_list_item',
contents: [el],
};
}
this.update(el);
},
update(element) {
this.$emit('update', element);
},
switchToDocument(value) {
this.changeType('document_block', value);
},
},
};
</script>
<style scoped lang="scss">
@import '~styles/helpers';
.content-element {
display: flex;
flex-direction: column;
&__actions {
display: inline-flex;
justify-self: flex-end;
align-self: flex-end;
}
&__section {
display: grid;
//grid-template-columns: 1fr 50px;
grid-auto-rows: auto;
/*width: 95%; // reserve space for scrollbar*/
}
&__chooser {
grid-column: 1 / span 2;
}
}
</style>