Skip to content
Snippets Groups Projects
Select Git revision
  • 9cc6fdc271feb763841dbe348ae0aacf4be91e1c
  • main default protected
  • studip-rector
  • ci-opt
  • course-members-export-as-word
  • data-vue-app
  • pipeline-improvements
  • webpack-optimizations
  • rector
  • icon-renewal
  • http-client-and-factories
  • jsonapi-atomic-operations
  • vueify-messages
  • tic-2341
  • 135-translatable-study-areas
  • extensible-sorm-action-parameters
  • sorm-configuration-trait
  • jsonapi-mvv-routes
  • docblocks-for-magic-methods
19 results

CoursewareHeadlineBlock.vue

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    CoursewareHeadlineBlock.vue 16.24 KiB
    <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>