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