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 jQuery('a.fn_top').mouseover(dw_page.footnoteDisplay); 13 dw_page.makeToggle('#dw__toc h3','#dw__toc > div'); 14 }, 15 16 /** 17 * Highlight the section when hovering over the appropriate section edit button 18 * 19 * @author Andreas Gohr <andi@splitbrain.org> 20 */ 21 sectionHighlight: function() { 22 jQuery('form.btn_secedit') 23 .mouseover(function(){ 24 var $tgt = jQuery(this).parent(), 25 nr = $tgt.attr('class').match(/(\s+|^)editbutton_(\d+)(\s+|$)/)[2], 26 $highlight = jQuery(), // holder for elements in the section to be highlighted 27 $highlightWrap = jQuery('<div class="section_highlight"></div>'); // section highlight wrapper 28 29 // Walk the dom tree in reverse to find the sibling which is or contains the section edit marker 30 while($tgt.length > 0 && !($tgt.hasClass('sectionedit' + nr) || $tgt.find('.sectionedit' + nr).length)) { 31 $tgt = $tgt.prev(); 32 $highlight = $highlight.add($tgt); 33 } 34 // insert the section highlight wrapper before the last element added to $highlight 35 $highlight.filter(':last').before($highlightWrap); 36 // and move the elements to be highlighted inside the section highlight wrapper 37 $highlight.detach().appendTo($highlightWrap); 38 }) 39 .mouseout(function(){ 40 // find the section highlight wrapper... 41 var $highlightWrap = jQuery('.section_highlight'); 42 // ...move its children in front of it (as siblings)... 43 $highlightWrap.before($highlightWrap.children().detach()); 44 // ...and remove the section highlight wrapper 45 $highlightWrap.detach(); 46 }); 47 }, 48 49 /** 50 * Create/get a insitu popup used by the footnotes 51 * 52 * @param target - the DOM element at which the popup should be aligned at 53 * @param popup_id - the ID of the (new) DOM popup 54 * @return the Popup jQuery object 55 */ 56 insituPopup: function(target, popup_id) { 57 // get or create the popup div 58 var $fndiv = jQuery('#' + popup_id); 59 60 // popup doesn't exist, yet -> create it 61 if($fndiv.length === 0){ 62 $fndiv = jQuery(document.createElement('div')) 63 .attr('id', popup_id) 64 .addClass('insitu-footnote JSpopup') 65 .attr('aria-hidden', 'true') 66 .mouseleave(function () {jQuery(this).hide().attr('aria-hidden', 'true');}) 67 .attr('role', 'tooltip'); 68 jQuery('.dokuwiki:first').append($fndiv); 69 } 70 71 // position() does not support hidden elements 72 $fndiv.show().position({ 73 my: 'left top', 74 at: 'left center', 75 of: target 76 }).hide(); 77 78 return $fndiv; 79 }, 80 81 /** 82 * Display an insitu footnote popup 83 * 84 * @author Andreas Gohr <andi@splitbrain.org> 85 * @author Chris Smith <chris@jalakai.co.uk> 86 */ 87 footnoteDisplay: function () { 88 var content = jQuery(jQuery(this).attr('href')) // Footnote text anchor 89 .closest('div.fn').html(); 90 91 if (content === null){ 92 return; 93 } 94 95 // strip the leading content anchors and their comma separators 96 content = content.replace(/((^|\s*,\s*)<sup>.*?<\/sup>)+\s*/gi, ''); 97 98 // prefix ids on any elements with "insitu__" to ensure they remain unique 99 content = content.replace(/\bid=(['"])([^"']+)\1/gi,'id="insitu__$2'); 100 101 // now put the content into the wrapper 102 dw_page.insituPopup(this, 'insitu__fn').html(content).show().attr('aria-hidden', 'false'); 103 }, 104 105 /** 106 * Makes an element foldable by clicking its handle 107 * 108 * This is used for the TOC toggling, but can be used for other elements 109 * as well. A state indicator is inserted into the handle and can be styled 110 * by CSS. 111 * 112 * @param selector handle What should be clicked to toggle 113 * @param selector content This element will be toggled 114 */ 115 makeToggle: function(handle, content, state){ 116 var $handle, $content, $clicky, $child, setClicky; 117 $handle = jQuery(handle); 118 if(!$handle.length) return; 119 $content = jQuery(content); 120 if(!$content.length) return; 121 122 // we animate the children 123 $child = $content.children(); 124 125 // class/display toggling 126 setClicky = function(hiding){ 127 if(hiding){ 128 $clicky.html('<span>+</span>'); 129 $handle.addClass('closed'); 130 $handle.removeClass('open'); 131 }else{ 132 $clicky.html('<span>−</span>'); 133 $handle.addClass('open'); 134 $handle.removeClass('closed'); 135 } 136 }; 137 138 $handle[0].setState = function(state){ 139 var hidden; 140 if(!state) state = 1; 141 142 // Assert that content instantly takes the whole space 143 $content.css('min-height', $content.height()).show(); 144 145 // stop any running animation 146 $child.stop(true, true); 147 148 // was a state given or do we toggle? 149 if(state === -1) { 150 hidden = false; 151 } else if(state === 1) { 152 hidden = true; 153 } else { 154 hidden = $child.is(':hidden'); 155 } 156 157 // update the state 158 setClicky(!hidden); 159 160 // Start animation and assure that $toc is hidden/visible 161 $child.dw_toggle(hidden, function () { 162 $content.toggle(hidden); 163 $content.css('min-height',''); // remove min-height again 164 }); 165 }; 166 167 // the state indicator 168 $clicky = jQuery(document.createElement('strong')); 169 170 // click function 171 $handle.css('cursor','pointer') 172 .click($handle[0].setState) 173 .prepend($clicky); 174 175 // initial state 176 $handle[0].setState(state); 177 } 178}; 179 180jQuery(dw_page.init); 181