<template> <div class="cw-block cw-block-headline"> <courseware-default-block :block="block" :canEdit="canEdit" :isTeacher="isTeacher" :preview="true" @showEdit="initCurrentData" @storeEdit="storeText" @closeEdit="initCurrentData" > <template #content> <div class="cw-block-headline-content" :class="[currentStyle, currentHeight === 'half' ? 'half' : 'full']" :style="headlineStyle" > <div class="icon-layer" :class="['icon-' + currentIconColor + '-' + currentIcon, currentHeight === 'half' ? 'half' : 'full']" > </div> <div class="cw-block-headline-textbox"> <div class="cw-block-headline-title"> <h1 :style="textStyle">{{ currentTitle }}</h1> </div> <div class="cw-block-headline-subtitle"> <h2 :style="textStyle">{{ currentSubtitle }}</h2> </div> </div> </div> </template> <template v-if="canEdit" #edit> <form class="default" @submit.prevent=""> <label> <translate>Layout</translate> <select v-model="currentStyle"> <option value="heavy"><translate>Große Schrift</translate></option> <option value="ribbon"><translate>Band</translate></option> <option value="bigicon_top"><translate>Großes Icon oben</translate></option> <option value="bigicon_before"><translate>Großes Icon davor</translate></option> </select> </label> <label> <translate>Höhe</translate> <select v-model="currentHeight"> <option value="full"><translate>Voll</translate></option> <option value="half"><translate>Halb</translate></option> </select> </label> <label> <translate>Haupttitel</translate> <input type="text" v-model="currentTitle" /> </label> <label v-if="hasSubtitle"> <translate>Untertitel</translate> <input type="text" v-model="currentSubtitle" /> </label> <label> <translate>Textfarbe</translate> <studip-select :options="colors" label="hex" :reduce="color => color.hex" :clearable="false" v-model="currentTextColor" > <template #open-indicator="selectAttributes"> <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> </template> <template #no-options> <translate>Es steht keine Auswahl zur Verfügung.</translate> </template> <template #selected-option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> <template #option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> </studip-select> </label> <label> <translate>Icon</translate> <studip-select :clearable="false" :options="icons" v-model="currentIcon"> <template #open-indicator="selectAttributes"> <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> </template> <template #no-options> <translate>Es steht keine Auswahl zur Verfügung.</translate> </template> <template #selected-option="option"> <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> </template> <template #option="option"> <studip-icon :shape="option.label"/> <span class="vs__option-with-icon">{{option.label}}</span> </template> </studip-select> </label> <label> <translate>Icon-Farbe</translate> <studip-select :options="iconColors" label="name" :reduce="iconColor => iconColor.class" :clearable="false" v-model="currentIconColor" > <template #open-indicator="selectAttributes"> <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> </template> <template #no-options> <translate>Es steht keine Auswahl zur Verfügung.</translate> </template> <template #selected-option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> <template #option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> </studip-select> </label> <label> <translate>Hintergrundtyp</translate> <select v-model="currentBackgroundType"> <option value="color"><translate>Farbe</translate></option> <option value="image"><translate>Bild</translate></option> </select> </label> <label v-if="currentBackgroundType === 'color'"> <translate>Hintergrundfarbe</translate> <studip-select :options="colors" label="hex" :reduce="color => color.hex" v-model="currentBackgroundColor" :clearable="false" > <template #open-indicator="selectAttributes"> <span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span> </template> <template #no-options> <translate>Es steht keine Auswahl zur Verfügung.</translate> </template> <template #selected-option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> <template #option="{name, hex}"> <span class="vs__option-color" :style="{'background-color': hex}"></span><span>{{name}}</span> </template> </studip-select> </label> <label v-if="currentBackgroundType === 'image'"> <translate>Hintergrundbild</translate> <courseware-file-chooser v-model="currentBackgroundImageId" :isImage="true" @selectFile="updateCurrentBackgroundImage" /> </label> </form> </template> <template #info><translate>Informationen zum Blickfang-Block</translate></template> </courseware-default-block> </div> </template> <script> import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue'; import CoursewareFileChooser from './CoursewareFileChooser.vue'; import { blockMixin } from './block-mixin.js'; import colorMixin from '@/vue/mixins/courseware/colors.js'; import { mapGetters, mapActions } from 'vuex'; import contentIcons from './content-icons.js'; export default { name: 'courseware-headline-block', mixins: [blockMixin, colorMixin], components: { CoursewareDefaultBlock, CoursewareFileChooser, }, props: { block: Object, canEdit: Boolean, isTeacher: Boolean, }, data() { return { currentTitle: '', currentSubtitle: '', currentStyle: '', currentHeight: '', currentBackgroundColor: '', currentTextColor: '', currentIcon: '', currentIconColor: '', currentBackgroundType: '', currentBackgroundImageId: '', currentBackgroundImage: {}, currentBackgroundURL: '', }; }, computed: { ...mapGetters({ fileRefById: 'file-refs/byId', urlHelper: 'urlHelper', relatedTermOfUse: 'terms-of-use/related', }), title() { return this.block?.attributes?.payload?.title; }, subtitle() { return this.block?.attributes?.payload?.subtitle; }, style() { return this.block?.attributes?.payload?.style; }, height() { return this.block?.attributes?.payload?.height; }, backgroundColor() { return this.block?.attributes?.payload?.background_color; }, textColor() { return this.block?.attributes?.payload?.text_color; }, icon() { return this.block?.attributes?.payload?.icon; }, iconColor() { return this.block?.attributes?.payload?.icon_color; }, backgroundImageId() { return this.block?.attributes?.payload?.background_image_id; }, backgroundImage() { return this.block?.attributes?.payload?.background_image; }, backgroundType() { return this.block?.attributes?.payload?.background_type; }, complementBackgroundColor() { return this.calcComplement(this.backgroundColor); }, icons() { return contentIcons; }, colors() { return this.mixinColors; }, iconColors() { return this.mixinColors.filter(color => color.icon && color.class !== 'studip-lightblue'); }, textStyle() { let style = {}; style.color = this.currentTextColor; return style; }, headlineStyle() { let style = {}; if (this.currentBackgroundType === 'color') { style['background-color'] = this.currentBackgroundColor; } if (this.currentBackgroundType === 'image') { style['background-color'] = this.currentBackgroundColor; style['background-image'] = 'url(' + this.currentBackgroundURL + ')'; } return style; }, hasSubtitle() { return !['bigicon_before'].includes(this.currentStyle); } }, mounted() { this.initCurrentData(); }, methods: { ...mapActions({ loadFileRef: 'file-refs/loadById', updateBlock: 'updateBlockInContainer', }), initCurrentData() { this.currentTitle = this.title; this.currentSubtitle = this.subtitle; this.currentStyle = this.style; this.currentHeight = this.height; this.currentBackgroundColor = this.backgroundColor; this.currentTextColor = this.textColor; this.currentIcon = this.icon; this.currentIconColor = this.iconColor; this.currentBackgroundType = this.backgroundType; this.currentBackgroundImageId = this.backgroundImageId; if (this.currentBackgroundImageId !== '') { this.loadFile(); } }, async loadFile() { const id = this.currentBackgroundImageId; const options = { include: 'terms-of-use' }; await this.loadFileRef({ id: id, options }); const fileRef = this.fileRefById({ id: id }); if (fileRef && this.relatedTermOfUse({parent: fileRef, relationship: 'terms-of-use'}).attributes['download-condition'] === 0) { this.updateCurrentBackgroundImage({ id: fileRef.id, name: fileRef.attributes.name, download_url: this.urlHelper.getURL( 'sendfile.php', { type: 0, file_id: fileRef.id, file_name: fileRef.attributes.name }, true ), }); } }, updateCurrentBackgroundImage(file) { this.currentBackgroundImage = file; this.currentBackgroundImageId = file.id; this.currentBackgroundURL = file.download_url; }, storeText() { let attributes = {}; attributes.payload = {}; attributes.payload.title = this.currentTitle; attributes.payload.subtitle = this.currentSubtitle; attributes.payload.style = this.currentStyle; attributes.payload.height = this.currentHeight; attributes.payload.text_color = this.currentTextColor; attributes.payload.icon = this.currentIcon; attributes.payload.icon_color = this.currentIconColor; attributes.payload.background_type = this.currentBackgroundType; attributes.payload.background_color = ''; attributes.payload.background_image_id = ''; if (this.currentBackgroundType === 'color') { attributes.payload.background_color = this.currentBackgroundColor; } if (this.currentBackgroundType === 'image') { attributes.payload.background_image_id = this.currentBackgroundImageId; } this.updateBlock({ attributes: attributes, blockId: this.block.id, containerId: this.block.relationships.container.data.id, }); }, calcComplement(color) { let RGB = this.calcRGB(color); return '#' + this.compToHex(255 - RGB.r) + this.compToHex(255 - RGB.g) + this.compToHex(255 - RGB.b); }, calcIconColor(color) { let RGB = this.calcRGB(color); return (RGB.r + RGB.g + RGB.b) / 3 > 129 ? 'black' : 'white'; }, calcRGB(color) { color = color.slice(1); // remove # let val = parseInt(color, 16); let r = val >> 16; let g = (val >> 8) & 0x00ff; let b = val & 0x0000ff; if (g > 255) { g = 255; } else if (g < 0) { g = 0; } if (b > 255) { b = 255; } else if (b < 0) { b = 0; } return { r: r, g: g, b: b }; }, compToHex(comp) { let hex = comp.toString(16); return hex.length === 1 ? '0' + hex : hex; }, }, }; </script>