xref: /template/sprintdoc/js/sidebar.js (revision 3b8715b10b97ef97ff3ffed9148c7e80a15af156)
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            // fade in the navigation (was hidden until now
149            $main.css({opacity: 0, visibility: "visible"}).animate({opacity: 1}, 200);
150        },
151
152        /**
153         * Initialize the open/close toggling of menu entries
154         */
155        initMenuHandling = function () {
156            $nav.on('click', 'div.nav a', function (e) {
157                toggleNav(jQuery(this));
158                e.preventDefault();
159            });
160        },
161
162        /**
163         * adds a given class to the toggler link
164         * @param $toggler link or parent of link to whom the class is added
165         * @param classVal class to be added
166         */
167        setTogglerClass = function ($toggler, classVal) {
168            if($toggler.is('a')) {
169                $toggler.addClass(classVal);
170            } else {
171                $toggler.find('a').addClass(classVal);
172            }
173        },
174
175        /**
176         * marks a $toggler link as active if the following menu has an active state
177         * @param $menuObj jQuery Object of the menu / container
178         * @param $toggler
179         */
180        addContentMenuCurrentStates = function ($menuObj, $toggler) {
181            if($menuObj[0] && String($menuObj[0].innerHTML).indexOf('curid') > 0) {
182                setTogglerClass($toggler,'is-active');
183            }
184        },
185
186        /**
187         * Make sure the content area is always as high as the sidebar
188         */
189        initContentMinHeight = function () {
190            var $sidebar = jQuery('.page-wrapper').find('> .tools').find('.col-xs-12');
191            if ($sidebar.length == 1) {
192                var num = parseFloat($sidebar.height());
193                if (!isNaN(num)) {
194                    jQuery('#dokuwiki__content').css('minHeight', num + 100);
195                }
196            }
197        },
198
199        /**
200         * Initialize the sidebar handle behaviour
201         */
202        initSidebarToggling = function () {
203            var $toggler = jQuery('.togglelink.page_main-content').find('a');
204            $toggler.click(function (e) {
205                e.preventDefault();
206                if (jQuery('body').hasClass('wide-content')) {
207                    setDefaultContent();
208                } else {
209                    setWideContent();
210                    removeOpenStates();
211                }
212            });
213
214            if (window.sessionStorage.getItem('wide-content') === 'true') {
215                setWideContent();
216            }
217        },
218
219        /**
220         * Show sidebar when accessing the search
221         */
222        initSearchToggling = function () {
223            jQuery('.toggleSearch').find('a').click(function (e) {
224                setDefaultContent();
225                e.preventDefault();
226                jQuery('#qsearch__in').focus();
227            });
228
229        },
230
231        /**
232         * Open and close the sidebar in mobile view
233         */
234        initMobileToggling = function () {
235            jQuery('.menu-togglelink').find('a').click(function (e) {
236                e.preventDefault();
237                var $body = jQuery('body');
238                $body.toggleClass('show-mobile-sidebar');
239            });
240        },
241
242        /**
243         * set is-active class if body has at least one of the given selectors
244         * @param selectorArray Array of selectors
245         * @param $nav container in which the $toggler is situated
246         */
247        setActive = function(selectorArray, $nav) {
248            for(var i=0; i< selectorArray.length; i++) {
249                var mode = selectorArray[i];
250                if(jQuery('body').is('.do-'+mode)){
251                    setTogglerClass($nav.find('.nav'),'is-active');
252                    $nav.find('a[href*="do='+mode+'"]').wrapAll('<span class="curid"></span>');
253                }
254            }
255        },
256
257        /**
258         * sets active states in site tool menu and user tool menu for certain modes
259         * adds sessionStorage behaviour equivalent approach to content menus
260         *
261         */
262        initTemplateMenues = function () {
263            var $body = jQuery('body'),
264                $siteTools = $nav.find('> .nav-sitetools'),
265                $userTools = $nav.find('> .nav-usermenu'),
266                $templateMenus = $nav.find('> nav:not(.nav-main)'),
267
268                stModes = ['recent', 'media', 'index'],
269                utModes = ['profile','admin'],
270                isWideContent = false;
271
272            /* set active states for site tool menu and user tool menu */
273            setActive(stModes,$siteTools);
274            setActive(utModes,$userTools);
275
276            if($body.is('.do-show') && $body.is('.wide-content')) {
277                window.sessionStorage.setItem('wide-content', true);
278                isWideContent = true;
279            }
280
281
282
283            /* set data attributes for sessionStorage and check onload if one of the template menus should be opened */
284            $templateMenus.each(function( index ) {
285                var $t = jQuery(this).find('.nav'),
286                    y = $nav.find('.nav-main').find('.nav').length,
287                    $toggler = ($t.is('a')) ? $t : $t.find('a:last'),
288                    tIndex = y + index;
289                $toggler.data('index', tIndex);
290
291                var item = window.sessionStorage.getItem('sidebar-section-' + tIndex + '-open');
292                if (item) {
293                    if(isWideContent) {
294                        window.sessionStorage.setItem('sidebar-section-' + tIndex + '-open', 'false');
295                    } else {
296                        if (item === 'true') {
297                            jQuery(this).find('.nav-panel').css('display', 'block');
298                            setTogglerClass($toggler, 'is-open');
299                        }
300                    }
301                }
302                //console.log(window.sessionStorage);
303
304            });
305
306        };
307
308
309    // main
310    initContentNav();
311    initSidebarToggling();
312    initTemplateMenues();
313    initMenuHandling();
314    initContentMinHeight();
315    initSearchToggling();
316    initMobileToggling();
317});
318
319