aboutsummaryrefslogtreecommitdiff
path: root/resources/vue/components/ContentBarBreadcrumbs.vue
blob: 35606b46178940d9d9e5f4e8adc4e59ae16debd5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<template>
    <ul>
        <li v-for="(breadcrumb, index) in breadcrumbs" class="cw-ribbon-breadcrumb-item" :key="index">
            <span v-if="breadcrumb.active">{{ breadcrumb.title }}</span>
            <a v-else :href="breadcrumb.url">{{ breadcrumb.title }}</a>
        </li>
    </ul>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { TOCItem, traverse } from './table-of-contents';

interface Breadcrumb {
    title: string;
    url: string;
    active: boolean;
}

export default defineComponent({
    name: 'ContentBarBreadcrumbs',
    props: {
        // The table of contents tree for the page that is currently open.
        toc: {
            type: Object as PropType<TOCItem>,
            required: true,
        },
    },
    computed: {
        // Convert the nested TOCItem into a list of breadcrumbs we can iterate through
        // in the template.
        breadcrumbs(): Breadcrumb[] {
            // First, clone the toc and add parent references to it.
            // (The parent references are lost in serialization from PHP to JS.)
            const tocClone = JSON.parse(JSON.stringify(this.toc));
            this.addParentReferences(tocClone);

            // Then, find the TOCItem corresponding to the page that is currently open.
            const activeTocItem = this.findActiveTocItem(tocClone);
            if (!activeTocItem) {
                console.error('No TOCItem is marked as active. No breadcrumbs will be rendered.');
                return [];
            }

            // Finally, iterate upwards from the active TOC Item, through its parent, grandparent, ...
            // up to the root, generating a breadcrumb at each step of the way.
            const breadcrumbs = [{ title: activeTocItem.title, url: activeTocItem.url, active: true }];
            let current = activeTocItem;
            while (current.parent) {
                current = current.parent;
                breadcrumbs.push({ title: current.title, url: current.url, active: false });
            }
            return breadcrumbs.reverse();
        },
    },
    methods: {
        // Find the TOCItem, if any, that is marked as active in the given toc tree.
        findActiveTocItem(toc: TOCItem): TOCItem | undefined {
            let activeItem: TOCItem | undefined;
            traverse(toc, (item) => {
                if (item.active) {
                    activeItem = item;
                }
            });
            return activeItem;
        },
        // Augment each node in the given toc tree with a reference to its parent.
        addParentReferences(tocItem: TOCItem, parent?: TOCItem): void {
            if (parent) {
                tocItem.parent = parent;
            }
            for (let child of tocItem.children) {
                this.addParentReferences(child, tocItem);
            }
        },
    },
});
</script>