xref: /template/sprintdoc/js/sidebar.js (revision 634eb790ea982d0dc8b285b55f5561b234b13e7c)
1/**
2 * Sets up the sidebar behaviour
3 *
4 *  @author Andreas Gohr <gohr@cosmocode.de>
5 *  @author Michael Große <gohr@cosmocode.de>
6 *  @author Jana Deutschlaender <deutschlaender@cosmocode.de>
7 */
8jQuery(function () {
9    var $nav = jQuery('#dokuwiki__aside');
10    if (!$nav.length) return;
11
12        /**
13         * closes sidebar
14         */
15    var setWideContent = function () {
16            $nav.find('div.nav-panel').hide(); // close all panels
17            jQuery('body').addClass('wide-content');
18            removeToggleStorage();
19            window.sessionStorage.setItem('wide-content', true);
20        },
21
22        /**
23         * removes information about the toggle-state
24         */
25        removeToggleStorage = function () {
26            for (var index=0; index <= window.sessionStorage.length; index += 1) {
27                var item = window.sessionStorage.getItem('sidebar-section-' + index + '-open');
28                if (!item) {
29                    continue;
30                }
31                window.sessionStorage.setItem('sidebar-section-' + index + '-open', 'false');
32            }
33        },
34
35        /**
36         * opens the sidebar
37         */
38        setDefaultContent = function () {
39            jQuery('body').removeClass('wide-content');
40            window.sessionStorage.setItem('wide-content', false);
41        },
42
43        /**
44         * Accessibility helper, focuses the first link witih the given element
45         *
46         * @param {jQuery} $elem
47         */
48        focusFirstSubLink = function ($elem) {
49            $elem.find('a').first().focus();
50        },
51
52        removeOpenStates = function() {
53            $nav.find('.is-open').removeClass('is-open');
54        },
55
56        /**
57         * Toggle a navigation panel
58         *
59         * @param {jQuery} $toggler The a toggler
60         */
61         toggleNav = function ($toggler) {
62            var $panel = $toggler.parent().next('div.nav-panel');
63            var isOpen = $panel.is(':visible');
64            // open sidebar on interaction
65            setDefaultContent();
66            // toggle the panel, focus first link after opening
67            $panel.dw_toggle(!isOpen, function () {
68                if (!isOpen) {
69                    focusFirstSubLink($panel);
70                    $toggler.addClass('is-open');
71                } else {
72                    $toggler.removeClass('is-open');
73                }
74            });
75            window.sessionStorage.setItem('sidebar-section-' + $toggler.data('index') + '-open', !isOpen);
76        },
77
78        /**
79         * Initialize the content navigation
80         *
81         * It mangles the sidebar content and handles inline Icon configuration
82         */
83        initContentNav = function () {
84            var $main = $nav.find('nav.nav-main');
85            if (!$main.length) return;
86
87            if(jQuery('body').hasClass('wide-content')) {
88                removeToggleStorage();
89            }
90
91            var ELEMENT = JSINFO.template.sprintdoc.sidebar_toggle_elements;
92            var $elements = $main.find(ELEMENT);
93            $elements.each(function (index) {
94                var $me = jQuery(this),
95
96                // prepare text and the optional icon
97                    data = $me.text().split('@', 2),
98                    text = data[0].trim();
99
100                var $icon = jQuery('<span class="ico">')
101                    .text(text.substr(0, 1).toUpperCase() + text.substr(1, 1).toLowerCase())
102                    .wrapInner('<strong>');
103                if (data[1]) {
104                    var src = data[1].trim();
105                    $icon.load(DOKU_BASE + 'lib/tpl/sprintdoc/svg.php?svg=' + src + '&e=1'); // directly embed
106                }
107
108                // make the new toggler
109                var $toggler = jQuery('<a>')
110                        .attr('href', '#')
111                        .attr('role', 'heading')
112                        .attr('aria-level', '2')
113                        .text(text)
114                        .wrapInner('<span class="lbl">')
115                        .prepend($icon)
116                        .data('index', index)
117                    ;
118                $toggler = jQuery('<div class="nav">').prepend($toggler);
119
120
121                // wrap all following siblings til the next element in a wrapper
122                var $wrap = jQuery('<div>')
123                    .addClass('nav-panel');
124                var $sibs = $me.nextAll();
125
126                for (var i = 0; i < $sibs.length; i++) {
127                    var $sib = jQuery($sibs[i]);
128                    if ($sib.is(ELEMENT)) break;
129                    $sib.detach().appendTo($wrap);
130                    addContentMenuCurrentStates($sib, $toggler);
131                }
132                $wrap.insertAfter($me);
133
134                // replace element with toggler
135                $me.replaceWith($toggler);
136
137                if ($toggler.parent('li').length) {
138                    $toggler.parent('li').addClass('toggler');
139                }
140
141                if (window.sessionStorage.getItem('sidebar-section-' + index + '-open') === 'true') {
142                    $wrap.css('display', 'block');
143                    setTogglerClass($toggler,'is-open');
144                }
145
146            });
147        },
148
149        /**
150         * Initialize the open/close toggling of menu entries
151         */
152        initMenuHandling = function () {
153            $nav.on('click', 'div.nav a', function (e) {
154                toggleNav(jQuery(this));
155                e.preventDefault();
156            });
157        },
158
159        /**
160         * adds a given class to the toggler link
161         * @param $toggler link or parent of link to whom the class is added
162         * @param classVal class to be added
163         */
164        setTogglerClass = function ($toggler, classVal) {
165            if($toggler.is('a')) {
166                $toggler.addClass(classVal);
167            } else {
168                $toggler.find('a').addClass(classVal);
169            }
170        },
171
172        /**
173         * marks a $toggler link as active if the following menu has an active state
174         * @param $menuObj jQuery Object of the menu / container
175         * @param $toggler
176         */
177        addContentMenuCurrentStates = function ($menuObj, $toggler) {
178            if($menuObj[0] && String($menuObj[0].innerHTML).indexOf('curid') > 0) {
179                setTogglerClass($toggler,'is-active');
180            }
181        },
182
183        /**
184         * Make sure the content area is always as high as the sidebar
185         */
186        initContentMinHeight = function () {
187            var $sidebar = jQuery('.page-wrapper').find('> .tools').find('.col-xs-12');
188            if ($sidebar.length == 1) {
189                var num = parseFloat($sidebar.height());
190                if (!isNaN(num)) {
191                    jQuery('#dokuwiki__content').css('minHeight', num + 100);
192                }
193            }
194        },
195
196        /**
197         * Initialize the sidebar handle behaviour
198         */
199        initSidebarToggling = function () {
200            var $toggler = jQuery('.togglelink.page_main-content').find('a');
201            $toggler.click(function (e) {
202                e.preventDefault();
203                if (jQuery('body').hasClass('wide-content')) {
204                    setDefaultContent();
205                } else {
206                    setWideContent();
207                    removeOpenStates();
208                }
209            });
210
211            if (window.sessionStorage.getItem('wide-content') === 'true') {
212                setWideContent();
213            }
214        },
215
216        /**
217         * Show sidebar when accessing the search
218         */
219        initSearchToggling = function () {
220            jQuery('.toggleSearch').find('a').click(function (e) {
221                setDefaultContent();
222                e.preventDefault();
223                jQuery('#qsearch__in').focus();
224            });
225
226        },
227
228        /**
229         * Open and close the sidebar in mobile view
230         */
231        initMobileToggling = function () {
232            jQuery('.menu-togglelink').find('a').click(function (e) {
233                e.preventDefault();
234                var $body = jQuery('body');
235                $body.toggleClass('show-mobile-sidebar');
236            });
237        },
238
239        /**
240         * set is-active class if body has at least one of the given selectors
241         * @param selectorArray Array of selectors
242         * @param $nav container in which the $toggler is situated
243         */
244        setActive = function(selectorArray, $nav) {
245            for(var i=0; i< selectorArray.length; i++) {
246                var mode = selectorArray[i];
247                if(jQuery('body').is('.do-'+mode)){
248                    setTogglerClass($nav.find('.nav'),'is-active');
249                    $nav.find('a[href*="do='+mode+'"]').wrapAll('<span class="curid"></span>');
250                }
251            }
252        },
253
254        /**
255         * sets active states in site tool menu and user tool menu for certain modes
256         * adds sessionStorage behaviour equivalent approach to content menus
257         *
258         */
259        initTemplateMenues = function () {
260            var $body = jQuery('body'),
261                $siteTools = $nav.find('> .nav-sitetools'),
262                $userTools = $nav.find('> .nav-usermenu'),
263                $templateMenus = $nav.find('> nav:not(.nav-main)'),
264
265                stModes = ['recent', 'media', 'index'],
266                utModes = ['profile','admin'],
267                isWideContent = false;
268
269            /* set active states for site tool menu and user tool menu */
270            setActive(stModes,$siteTools);
271            setActive(utModes,$userTools);
272
273            if($body.is('.do-show') && $body.is('.wide-content')) {
274                window.sessionStorage.setItem('wide-content', true);
275                isWideContent = true;
276            }
277
278
279
280            /* set data attributes for sessionStorage and check onload if one of the template menus should be opened */
281            $templateMenus.each(function( index ) {
282                var $t = jQuery(this).find('.nav'),
283                    y = $nav.find('.nav-main').find('.nav').length,
284                    $toggler = ($t.is('a')) ? $t : $t.find('a:last'),
285                    tIndex = y + index;
286                $toggler.data('index', tIndex);
287
288                var item = window.sessionStorage.getItem('sidebar-section-' + tIndex + '-open');
289                if (item) {
290                    if(isWideContent) {
291                        window.sessionStorage.setItem('sidebar-section-' + tIndex + '-open', 'false');
292                    } else {
293                        if (item === 'true') {
294                            jQuery(this).find('.nav-panel').css('display', 'block');
295                            setTogglerClass($toggler, 'is-open');
296                        }
297                    }
298                }
299                //console.log(window.sessionStorage);
300
301            });
302
303        };
304
305
306    // main
307    initContentNav();
308    initSidebarToggling();
309    initTemplateMenues();
310    initMenuHandling();
311    initContentMinHeight();
312    initSearchToggling();
313    initMobileToggling();
314});
315
316