xref: /template/sprintdoc/js/sidebar.js (revision bed1717f373c6e3a610f30a3c5f090d401b05b74)
1/**
2 * Sets up the sidebar behaviour
3 */
4jQuery(function () {
5    const $nav = jQuery('#dokuwiki__aside');
6    if (!$nav.length) return;
7
8    /**
9     * closes sidebar
10     */
11    const setWideContent = function () {
12        $nav.find('div.nav-panel').hide(); // close all panels
13        jQuery('body').addClass('wide-content');
14    };
15
16    /**
17     * opens the sidebar
18     */
19    const setDefaultContent = function () {
20        jQuery('body').removeClass('wide-content');
21
22    };
23
24    /**
25     * Accessibility helper, focuses the first link witih the given element
26     *
27     * @param {jQuery} $elem
28     */
29    const focusFirstSubLink = function ($elem) {
30        $elem.find('a').first().focus();
31    };
32
33    /**
34     * Toggle a navigation panel
35     *
36     * @param {jQuery} $toggler The h6 toggler
37     */
38    const toggleNav = function ($toggler) {
39        const $panel = $toggler.next('div.nav-panel');
40        const isOpen = $panel.is(':visible');
41        // open sidebar on interaction
42        setDefaultContent();
43        // toggle the panel, focus first link after opening
44        $panel.dw_toggle(!isOpen, function () {
45            if (!isOpen) {
46                focusFirstSubLink($panel);
47            }
48        });
49    };
50
51    /**
52     * Initialize the content navigation
53     *
54     * It mangles the sidebar content and handles inline Icon configuration
55     */
56    const initContentNav = function () {
57        const $main = $nav.find('nav.nav-main');
58        if (!$main.length) return;
59
60        const ELEMENT = 'h1,h2,h3,h4,h5'; // FIXME move to config
61        const $elements = $main.find(ELEMENT);
62        $elements.each(function () {
63            const $me = jQuery(this);
64
65            // prepare text and the optional icon
66            const data = $me.text().split('@', 2);
67            const text = data[0].trim();
68            const $icon = jQuery('<span class="ico">')
69                .text(text.substr(0, 1).toUpperCase() + text.substr(1, 1).toLowerCase())
70                .wrapInner('<strong>');
71            if (data[1]) {
72                const src = data[1].trim();
73                $icon.load(DOKU_BASE + 'lib/tpl/sprintdoc/svg.php?svg=' + src + '&e=1'); // directly embed
74            }
75
76            // make the new toggler
77            const $toggler = jQuery('<h6>')
78                    .attr('role', 'heading')
79                    .attr('aria-level', '2')
80                    .attr('tabindex', '0')
81                    .text(text)
82                    .wrapInner('<span class="lbl">')
83                    .prepend($icon)
84                ;
85
86            // wrap all following siblings til the next element in a wrapper
87            const $wrap = jQuery('<div>')
88                .addClass('nav-panel');
89            const $sibs = $me.nextAll();
90            for (let i = 0; i < $sibs.length; i++) {
91                const $sib = jQuery($sibs[i]);
92                if ($sib.is(ELEMENT)) break;
93                $sib.detach().appendTo($wrap);
94            }
95            $wrap.insertAfter($me);
96
97            // replace element with toggler
98            $me.replaceWith($toggler);
99        });
100    };
101
102    /**
103     * Initialize the open/close toggling of menu entries
104     */
105    const initMenuHandling = function () {
106        $nav.on('click keypress', 'h6', function () {
107            toggleNav(jQuery(this));
108        });
109    };
110
111    /**
112     * Make sure the content area is always as high as the sidebar
113     */
114    const initContentMinHeight = function () {
115        const $sidebar = jQuery('.page-wrapper').find('> .tools').find('.col-xs-12');
116        if ($sidebar.length == 1) {
117            const num = parseFloat($sidebar.height());
118            if (!isNaN(num)) {
119                jQuery('#dokuwiki__content').css('minHeight', num + 100);
120            }
121        }
122    };
123
124    /**
125     * Initialize the sidebar handle behaviour
126     */
127    const initSidebarToggling = function () {
128        const $toggler = jQuery('.togglelink.page_main-content').find('a');
129        $toggler.click(function (e) {
130            e.preventDefault();
131            if (jQuery('body').hasClass('wide-content')) {
132                setDefaultContent();
133            } else {
134                setWideContent();
135            }
136        });
137    };
138
139    /**
140     * Show sidebar when accessing the search
141     */
142    const initSearchToggling = function () {
143        jQuery('.toggleSearch').find('a').click(function (e) {
144            setDefaultContent();
145            e.preventDefault();
146            jQuery('#qsearch__in').focus();
147        });
148
149    };
150
151    // main
152    initContentNav();
153    initSidebarToggling();
154    initMenuHandling();
155    initContentMinHeight();
156    initSearchToggling();
157});
158
159