1/** 2 * Hides elements with a slide animation 3 * 4 * @param {function} fn optional callback to run after hiding 5 * @param {bool} noaria supress aria-expanded state setting 6 * @author Adrian Lang <mail@adrianlang.de> 7 */ 8jQuery.fn.dw_hide = function(fn, noaria) { 9 if(!noaria) this.attr('aria-expanded', 'false'); 10 return this.slideUp('fast', fn); 11}; 12 13/** 14 * Unhides elements with a slide animation 15 * 16 * @param {function} fn optional callback to run after hiding 17 * @param {bool} noaria supress aria-expanded state setting 18 * @author Adrian Lang <mail@adrianlang.de> 19 */ 20jQuery.fn.dw_show = function(fn, noaria) { 21 if(!noaria) this.attr('aria-expanded', 'true'); 22 return this.slideDown('fast', fn); 23}; 24 25/** 26 * Toggles visibility of an element using a slide element 27 * 28 * @param {bool} state the current state of the element (optional) 29 * @param {function} fn callback after the state has been toggled 30 * @param {bool} noaria supress aria-expanded state setting 31 */ 32jQuery.fn.dw_toggle = function(state, fn, noaria) { 33 return this.each(function() { 34 var $this = jQuery(this); 35 if (typeof state === 'undefined') { 36 state = $this.is(':hidden'); 37 } 38 $this[state ? "dw_show" : "dw_hide" ](fn, noaria); 39 }); 40}; 41 42/** 43 * Automatic behaviours 44 * 45 * This class wraps various JavaScript functionalities that are triggered 46 * automatically whenever a certain object is in the DOM or a certain CSS 47 * class was found 48 */ 49var dw_behaviour = { 50 51 init: function(){ 52 dw_behaviour.focusMarker(); 53 dw_behaviour.scrollToMarker(); 54 dw_behaviour.removeHighlightOnClick(); 55 dw_behaviour.quickSelect(); 56 dw_behaviour.checkWindowsShares(); 57 dw_behaviour.subscription(); 58 dw_behaviour.pageRestoreConfirm(); 59 dw_behaviour.securityCheck(); 60 61 dw_behaviour.revisionBoxHandler(); 62 jQuery(document).on('click','#page__revisions input[type=checkbox]', 63 dw_behaviour.revisionBoxHandler 64 ); 65 66 jQuery('.bounce').effect('bounce', {times:10}, 2000 ); 67 }, 68 69 /** 70 * Looks for an element with the ID scroll__here at scrolls to it 71 */ 72 scrollToMarker: function(){ 73 var $obj = jQuery('#scroll__here'); 74 if($obj.length) { 75 if($obj.offset().top != 0) { 76 jQuery('html, body').animate({ 77 scrollTop: $obj.offset().top - 100 78 }, 500); 79 } else { 80 // hidden object have no offset but can still be scrolled into view 81 $obj[0].scrollIntoView(); 82 } 83 } 84 }, 85 86 /** 87 * Display confirm dialog on page restore action 88 */ 89 pageRestoreConfirm: function(){ 90 jQuery('#dokuwiki__pagetools li.revert a').on('click', 91 function() { 92 return confirm(LANG.restore_confirm); 93 } 94 ); 95 }, 96 97 /** 98 * Looks for an element with the ID focus__this at sets focus to it 99 */ 100 focusMarker: function(){ 101 jQuery('#focus__this').trigger('focus'); 102 }, 103 104 /** 105 * Remove all search highlighting when clicking on a highlighted term 106 */ 107 removeHighlightOnClick: function(){ 108 jQuery('span.search_hit').on('click', 109 function(e){ 110 jQuery(e.target).removeClass('search_hit', 1000); 111 } 112 ); 113 }, 114 115 /** 116 * Autosubmit quick select forms 117 * 118 * When a <select> or <input> tag has the class "quickselect", this script will 119 * automatically submit its parent form when the select value changes. 120 * It also hides the submit button of the form. 121 * 122 * This includes a workaround a weird behaviour when the submit button has a name 123 * 124 * @link https://trackjs.com/blog/when-form-submit-is-not-a-function/ 125 * @author Andreas Gohr <andi@splitbrain.org> 126 */ 127 quickSelect: function(){ 128 jQuery('.quickselect') 129 .change(function(e){ HTMLFormElement.prototype.submit.call(e.target.form); }) 130 .closest('form').find(':button').not('.show').hide(); 131 }, 132 133 /** 134 * Display error for Windows Shares on browsers other than IE 135 * 136 * @author Michael Klier <chi@chimeric.de> 137 */ 138 checkWindowsShares: function() { 139 if(!LANG.nosmblinks || navigator.userAgent.match(/(Trident|MSIE|Edge)/)) { 140 // No warning requested or none necessary 141 return; 142 } 143 144 jQuery('a.windows').on('click', function(){ 145 alert(LANG.nosmblinks.replace(/\\n/,"\n")); 146 }); 147 }, 148 149 /** 150 * Hide list subscription style if target is a page 151 * 152 * @author Adrian Lang <lang@cosmocode.de> 153 * @author Pierre Spring <pierre.spring@caillou.ch> 154 */ 155 subscription: function(){ 156 var $form, $list, $digest; 157 158 $form = jQuery('#subscribe__form'); 159 if (0 === $form.length) return; 160 161 $list = $form.find("input[name='sub_style'][value='list']"); 162 $digest = $form.find("input[name='sub_style'][value='digest']"); 163 164 $form.find("input[name='sub_target']") 165 .on('click', 166 function () { 167 var $this = jQuery(this), show_list; 168 if (!$this.prop('checked')) { 169 return; 170 } 171 172 show_list = $this.val().match(/:$/); 173 $list.parent().dw_toggle(show_list); 174 if (!show_list && $list.prop('checked')) { 175 $digest.prop('checked', 'checked'); 176 } 177 } 178 ) 179 .filter(':checked') 180 .trigger('click'); 181 }, 182 183 /** 184 * disable multiple revisions checkboxes if two are checked 185 * 186 * @author Andreas Gohr <andi@splitbrain.org> 187 * @author Anika Henke <anika@selfthinker.org> 188 */ 189 revisionBoxHandler: function() { 190 var $revisions = jQuery('#page__revisions'); 191 var $all = jQuery('input[type="checkbox"][name="rev2[]"]', $revisions); 192 var $checked = $all.filter(':checked'); 193 var $button = jQuery('button', $revisions); 194 195 if($checked.length < 2) { 196 $all.prop('disabled', false); 197 $button.prop('disabled', true); 198 } else { 199 $all.prop('disabled', true); 200 $button.prop('disabled', false); 201 $checked.each(function(i) { 202 jQuery(this).prop('disabled', false); 203 if(i>1) { 204 jQuery(this).prop('checked', false); 205 } 206 }); 207 } 208 }, 209 210 /** 211 * Check that access to the data directory is properly secured 212 * 213 * A successful check (a 403 error was returned when loading the image) is saved 214 * to session storage and not repeated again until the next browser session. This 215 * avoids overeager security bans (see #3363) 216 */ 217 securityCheck: function () { 218 var $checkDiv = jQuery('#security__check'); 219 if (!$checkDiv.length) return; 220 if (sessionStorage.getItem('dw-security-check:' + DOKU_BASE)) { 221 // check was already executed successfully 222 $checkDiv.remove(); 223 return; 224 } 225 226 var img = new Image(); 227 img.onerror = function () { 228 // successful check will not be repeated during session 229 $checkDiv.remove(); 230 sessionStorage.setItem('dw-security-check:' + DOKU_BASE, true); 231 }; 232 img.onload = function () { 233 // check failed, display a warning message 234 $checkDiv.html(LANG.data_insecure); 235 $checkDiv.addClass('error'); 236 }; 237 img.src = $checkDiv.data('src') + '?t=' + Date.now(); 238 } 239}; 240 241jQuery(dw_behaviour.init); 242