1/** 2 * Page behaviours 3 * 4 * This class adds various behaviours to the rendered page 5 */ 6dw_page = { 7 /** 8 * initialize page behaviours 9 */ 10 init: function(){ 11 dw_page.sectionHighlight(); 12 dw_page.currentIDHighlight(); 13 jQuery('a.fn_top').on('mouseover', dw_page.footnoteDisplay); 14 dw_page.makeToggle('#dw__toc h3','#dw__toc > div'); 15 }, 16 17 /** 18 * Highlight the section when hovering over the appropriate section edit button 19 * 20 * @author Andreas Gohr <andi@splitbrain.org> 21 */ 22 sectionHighlight: function() { 23 jQuery('form.btn_secedit') 24 /* 25 * wrap the editable section in a div 26 */ 27 .each(function () { 28 let $tgt = jQuery(this).parent(); 29 const nr = $tgt.attr('class').match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2]; 30 let $highlight = jQuery(); // holder for elements in the section to be highlighted 31 const $highlightWrap = jQuery('<div class="section_highlight_wrapper"></div>'); 32 33 // the edit button should be part of the highlight 34 $highlight = $highlight.add($tgt); 35 36 // Walk the dom tree in reverse to find the sibling which is or contains the section edit marker 37 while ($tgt.length > 0 && !($tgt.hasClass('sectionedit' + nr) || $tgt.find('.sectionedit' + nr).length)) { 38 $tgt = $tgt.prev(); 39 $highlight = $highlight.add($tgt); 40 } 41 // wrap the elements to be highlighted in the section highlight wrapper 42 $highlight.wrapAll($highlightWrap); 43 }) 44 /* 45 * highlight the section 46 */ 47 .on('mouseover', function () { 48 jQuery(this).parents('.section_highlight_wrapper').addClass('section_highlight'); 49 }) 50 /* 51 * remove highlight 52 */ 53 .on('mouseout', function () { 54 jQuery(this).parents('.section_highlight_wrapper').removeClass('section_highlight'); 55 }); 56 }, 57 58 59 /** 60 * Highlight internal link pointing to current page 61 * 62 * @author Henry Pan <dokuwiki@phy25.com> 63 */ 64 currentIDHighlight: function(){ 65 jQuery('a.wikilink1, a.wikilink2').filter('[data-wiki-id="'+JSINFO.id+'"]').wrap('<span class="curid"></div>'); 66 }, 67 68 /** 69 * Create/get a insitu popup used by the footnotes 70 * 71 * @param target - the DOM element at which the popup should be aligned at 72 * @param popup_id - the ID of the (new) DOM popup 73 * @return the Popup jQuery object 74 */ 75 insituPopup: function(target, popup_id) { 76 // get or create the popup div 77 var $fndiv = jQuery('#' + popup_id); 78 79 // popup doesn't exist, yet -> create it 80 if($fndiv.length === 0){ 81 $fndiv = jQuery(document.createElement('div')) 82 .attr('id', popup_id) 83 .addClass('insitu-footnote JSpopup') 84 .attr('aria-hidden', 'true') 85 .on('mouseleave', function () {jQuery(this).hide().attr('aria-hidden', 'true');}) 86 .attr('role', 'tooltip'); 87 jQuery('.dokuwiki:first').append($fndiv); 88 } 89 90 // position() does not support hidden elements 91 $fndiv.show().position({ 92 my: 'left top', 93 at: 'left center', 94 of: target 95 }).hide(); 96 97 return $fndiv; 98 }, 99 100 /** 101 * Display an insitu footnote popup 102 * 103 * @author Andreas Gohr <andi@splitbrain.org> 104 * @author Chris Smith <chris@jalakai.co.uk> 105 * @author Anika Henke <anika@selfthinker.org> 106 */ 107 footnoteDisplay: function () { 108 var $content = jQuery(jQuery(this).attr('href')) // Footnote text anchor 109 .parent().siblings('.content').clone(); 110 111 if (!$content.length) { 112 return; 113 } 114 115 // prefix ids on any elements with "insitu__" to ensure they remain unique 116 jQuery('[id]', $content).each(function(){ 117 var id = jQuery(this).attr('id'); 118 jQuery(this).attr('id', 'insitu__' + id); 119 }); 120 121 var content = $content.html().trim(); 122 // now put the content into the wrapper 123 dw_page.insituPopup(this, 'insitu__fn').html(content) 124 .show().attr('aria-hidden', 'false'); 125 }, 126 127 /** 128 * Makes an element foldable by clicking its handle 129 * 130 * This is used for the TOC toggling, but can be used for other elements 131 * as well. A state indicator is inserted into the handle and can be styled 132 * by CSS. 133 * 134 * To properly reserve space for the expanded element, the sliding animation is 135 * done on the children of the content. To make that look good and to make sure aria 136 * attributes are assigned correctly, it's recommended to make sure that the content 137 * element contains a single child element only. 138 * 139 * @param {selector} handle What should be clicked to toggle 140 * @param {selector} content This element will be toggled 141 * @param {int} state initial state (-1 = open, 1 = closed) 142 */ 143 makeToggle: function(handle, content, state){ 144 var $handle, $content, $clicky, $child, setClicky; 145 $handle = jQuery(handle); 146 if(!$handle.length) return; 147 $content = jQuery(content); 148 if(!$content.length) return; 149 150 // we animate the children 151 $child = $content.children(); 152 153 // class/display toggling 154 setClicky = function(hiding){ 155 if(hiding){ 156 $clicky.html('<span>+</span>'); 157 $handle.addClass('closed'); 158 $handle.removeClass('open'); 159 }else{ 160 $clicky.html('<span>−</span>'); 161 $handle.addClass('open'); 162 $handle.removeClass('closed'); 163 } 164 }; 165 166 $handle[0].setState = function(state){ 167 var hidden; 168 if(!state) state = 1; 169 170 // Assert that content instantly takes the whole space 171 $content.css('min-height', $content.height()).show(); 172 173 // stop any running animation 174 $child.stop(true, true); 175 176 // was a state given or do we toggle? 177 if(state === -1) { 178 hidden = false; 179 } else if(state === 1) { 180 hidden = true; 181 } else { 182 hidden = $child.is(':hidden'); 183 } 184 185 // update the state 186 setClicky(!hidden); 187 188 // Start animation and assure that $toc is hidden/visible 189 $child.dw_toggle(hidden, function () { 190 $content.toggle(hidden); 191 $content.attr('aria-expanded', hidden); 192 $content.css('min-height',''); // remove min-height again 193 }, true); 194 }; 195 196 // the state indicator 197 $clicky = jQuery(document.createElement('strong')); 198 199 // click function 200 $handle.css('cursor','pointer') 201 .on('click', $handle[0].setState) 202 .prepend($clicky); 203 204 // initial state 205 $handle[0].setState(state); 206 } 207}; 208 209jQuery(dw_page.init); 210