Skip to content
Snippets Groups Projects
ResponsiveContentBar.vue 9.63 KiB
Newer Older
<template>
    <div v-if="realContentbarSource === ''">
        <MountingPortal mount-to="#responsive-contentbar-container" append>
            <portal-target name="layout-page"></portal-target>
        </MountingPortal>
        <portal to="layout-page">
            <div id="responsive-contentbar" class="contentbar" ref="contentbar">
                <div v-if="hasSidebar" class="contentbar-nav" ref="leftNav">
                    <button :class="sidebarIconClasses" @click.prevent="toggleSidebar" id="toggle-sidebar"
                            :title="$gettext('Sidebar öffnen')">
                        <studip-icon shape="sidebar3" :size="24" ref="sidebarIcon"
                                     alt=""></studip-icon>
                    </button>
                </div>
                <div class="contentbar-wrapper-left">
                    <studip-icon :shape="icon" :size="24" role="info" class="text-bottom contentbar-icon"></studip-icon>
                    <nav class="contentbar-breadcrumb" ref="breadcrumbs">
                        <span>{{ title }}</span>
                    </nav>
                </div>
                <div class="contentbar-wrapper-right" ref="wrapperRight"></div>
            </div>
        </portal>
    </div>
</template>

<script>
import StudipIcon from '../StudipIcon.vue';

export default {
    name: 'ResponsiveContentBar',
    components: { StudipIcon },
    props: {
        icon: {
            type: String,
            default: 'seminar'
        },
        title: {
            type: String,
            default: ''
        },
        hasSidebar: {
            type: Boolean,
            default: true
        }
    },
    data() {
        return {
            realContentbar: null,
            realContentbarSource: null,
            realContentbarIconContainer: null,
            realContentbarType: null,
            sidebarOpen: false
        }
    },
    computed: {
        sidebarIconClasses() {
            let classes = ['styleless', 'contentbar-button', 'contentbar-button-sidebar'];
            if (this.sidebarOpen) {
                classes.push('contentbar-button-sidebar-open');
            }
            return classes;
        }
    },
    methods: {
        toggleSidebar() {

            const sidebar = document.getElementById('sidebar');
            const content = document.getElementById('content-wrapper');
            const pageTitle = document.getElementById('page-title-container');
            if (this.sidebarOpen) {
                sidebar.classList.add('responsive-hide');
                sidebar.classList.remove('responsive-show');

                if (document.documentElement.classList.contains('responsive-display')
                        && !document.documentElement.classList.contains('fullscreen-mode')) {
                    content.style.display = '';
                    pageTitle.style.display = '';
                if (!document.documentElement.classList.contains('responsive-display')) {
                        document.body.classList.remove('fullscreen-sidebar-shown');
                this.sidebarOpen = false;
            } else {
                sidebar.classList.add('responsive-show');
                sidebar.classList.remove('responsive-hide');
                if (document.documentElement.classList.contains('responsive-display')
                    && !document.documentElement.classList.contains('fullscreen-mode')) {
                    // Set a timeout here so that the content "disappears" after slide-in aninmation is finished.
                    setTimeout(() => {
                        content.style.display = 'none';
                        pageTitle.style.display = 'none';
                    }, 300);

                if (!document.documentElement.classList.contains('responsive-display')) {
                    document.body.classList.add('fullscreen-sidebar-shown');
                this.sidebarOpen = true;
            }

            // Adjust toggle sidebar button title
            document.getElementById('toggle-sidebar').title = this.sidebarOpen
                ? this.$gettext('Sidebar schließen')
                : this.$gettext('Sidebar öffnen');
        },
        adjustExistingContentbar(responsiveMode) {
            if (this.realContentbar) {
                if (responsiveMode) {
                    this.realContentbar.id = 'responsive-contentbar';
                    this.realContentbar.classList.add('contentbar');
                    if (!this.realContentbar.querySelector('#toggle-sidebar')) {
                        this.realContentbar.querySelector(this.realContentbarIconContainer)
                            .prepend(this.createSidebarIcon());
                    }
                    if (this.realContentbarType === 'courseware') {
                        this.realContentbar.querySelector('.cw-ribbon-wrapper-left')
                            .classList.add('contentbar-wrapper-left');
                        this.realContentbar.querySelector('.cw-ribbon-wrapper-right')
                            .classList.add('contentbar-wrapper-right');
                    }

                    document.getElementById('responsive-contentbar-container').prepend(this.realContentbar);
                } else {
                    this.realContentbar.id = 'contentbar';
                    document.getElementById('toggle-sidebar').remove();

                    if (this.realContentbarType === 'courseware') {
                        this.realContentbar.classList.remove('contentbar');
                        this.realContentbar.querySelector('.cw-ribbon-wrapper-left')
                            .classList.remove('contentbar-wrapper-left');
                        this.realContentbar.querySelector('.cw-ribbon-wrapper-right')
                            .classList.remove('contentbar-wrapper-right');
                    }

                    document.querySelector(this.realContentbarSource).prepend(this.realContentbar);
                }
            }
        },
        createSidebarIcon() {
            const button = document.createElement('button');

            this.sidebarIconClasses.map(className => {
                button.classList.add(className);
            });
            button.id = 'toggle-sidebar';
            button.title = this.$gettext('Sidebar einblenden');
            button.addEventListener('click', (event) => {
                button.classList.toggle('contentbar-button-sidebar-open');
                event.preventDefault();
                this.toggleSidebar();
            })
            const sidebarIcon = document.createElement('img');
            sidebarIcon.src = STUDIP.ASSETS_URL + '/images/icons/blue/sidebar3.svg';
            sidebarIcon.height = 24;
            sidebarIcon.width = 24;
            button.appendChild(sidebarIcon);

            return button;
        }
    },
    mounted() {
        // There's already a PHP contentbar on this page, use it.
        this.$nextTick(() => {
            const realContentbar = document.querySelector('.contentbar:not(#responsive-contentbar)');
            if (realContentbar) {
                STUDIP.eventBus.emit('has-contentbar', true);

                this.realContentbar = realContentbar;
                this.realContentbarSource = '#content';
                this.realContentbarIconContainer = '.contentbar-nav';
                this.realContentbarType = 'wiki';
                this.adjustExistingContentbar(true);
            } else {
                this.realContentbarSource = '';

                const cwContentbar = document.querySelector('#contentbar header');
                if (cwContentbar) {
                    STUDIP.eventBus.emit('has-contentbar', true);

                    this.realContentbar = cwContentbar;
                    this.realContentbarSource = '.cw-structural-element-content > div';
                    this.realContentbarIconContainer = '.cw-ribbon-nav';
                    this.realContentbarType = 'courseware';
                    this.adjustExistingContentbar(true);
                }
            }

            // Add click listener to sidebar so that it can be hidden on clicking an item
            document.querySelectorAll('.sidebar-widget a').forEach(item => {
                item.addEventListener('click', () => this.toggleSidebar());
            });
        })

        // Use courseware contentbar instead of this Vue component.
        this.globalOn('courseware-contentbar-mounted', element => {
            STUDIP.eventBus.emit('has-contentbar', true);

            this.realContentbar = element.$el.querySelector('header');
            this.realContentbarSource = '.cw-structural-element-content > div';
            this.realContentbarIconContainer = '.cw-ribbon-nav';
            this.realContentbarType = 'courseware';
            this.adjustExistingContentbar(true);

            document.querySelectorAll('.sidebar-widget button span').forEach(item => {
                item.addEventListener('click', () => this.toggleSidebar());
            });
        })

        this.globalOn('toggle-focus-mode', (state) => {
            const html = document.querySelector('html');
            if (html.classList.contains('responsive-display') || html.classList.contains('fullscreen-mode')) {
                this.adjustExistingContentbar(!state);
            }

    },
    beforeDestroy() {
        if (this.realContentbar) {
            this.adjustExistingContentbar(false);
        }

        STUDIP.eventBus.off('toggle-focus-mode');
        STUDIP.eventBus.off('courseware-contentbar-mounted');