You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

212 lines
7.1 KiB

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