1/** 2 * DokuWiki Mikio Template Javascript 3 * 4 * @link http://dokuwiki.org/template:mikio 5 * @author James Collins <james.collins@outlook.com.au> 6 * @license GPLv2 (http://www.gnu.org/licenses/gpl-2.0.html) 7 */ 8"use strict"; 9 10var mikio = { 11 queueResize: false, 12 mikioCSS: false, 13 14 ready: function () { 15 var self = this; 16 17 this.addToggleClick('mikio-sidebar-toggle', 'mikio-sidebar-collapse'); 18 this.addToggleClick('mikio-navbar-toggle', 'mikio-navbar-collapse'); 19 this.addDropdownClick('mikio-nav-dropdown', 'mikio-dropdown'); 20 21 window.onresize = function () { 22 if (!this.queueResize) { 23 this.queueResize = true; 24 window.setTimeout(function () { 25 this.queueResize = false; 26 Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) { 27 if (!elem.classList.contains('closed')) { 28 elem.classList.add('closed'); 29 } 30 }); 31 }, 100); 32 } 33 }; 34 35 // Mikio-Dropdown - Click 36 Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) { 37 elem.addEventListener('click', function (event) { 38 event.stopPropagation(); 39 }); 40 }); 41 42 // Mikio-Dropdown - Close when clicked outside dropdown 43 Array.from(document.getElementsByTagName('body')).forEach(function (elem) { 44 elem.addEventListener('click', function (event) { 45 Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) { 46 if (!elem.classList.contains('closed')) { 47 elem.classList.add('closed'); 48 } 49 }); 50 }); 51 }); 52 53 // Mikio-Navbar-Toggle - Fix 54 Array.from(document.getElementsByClassName('mikio-navbar-toggle')).forEach(function (elem) { 55 elem.classList.add('closed'); 56 }); 57 58 // Mikio-Dropdown - Fix 59 Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) { 60 elem.classList.add('closed'); 61 }); 62 63 // Input File - Cleanup 64 Array.from(document.querySelectorAll('input[type=file]')).forEach(function (elem) { 65 var style = window.getComputedStyle(elem); 66 67 if (style.display != 'none') { 68 var parentElem = elem.parentElement; 69 var fileRect = elem.getBoundingClientRect(); 70 var parentRect = parentElem.getBoundingClientRect(); 71 var spanElem = document.createElement('span'); 72 73 elem.style.opacity = 0; 74 parentElem.style.position = 'relative'; 75 spanElem.innerHTML = 'Choose file...'; 76 spanElem.classList.add('mikio-input-file'); 77 spanElem.style.left = Math.floor(fileRect.left - parentRect.left) + 'px'; 78 spanElem.style.width = Math.floor(fileRect.right - fileRect.left) + 'px'; 79 mikio.insertAfter(spanElem, elem); 80 81 spanElem.addEventListener('click', function (event) { 82 if (event.target.parentElement.tagName.toLowerCase() != 'label') { 83 let sibling = mikio.getPrevSibling(event.target, 'input'); 84 if (typeof sibling !== 'undefined') { 85 sibling.click(); 86 } 87 } 88 }); 89 90 elem.addEventListener('change', function () { 91 if (this.files.length > 0) { 92 let mikioInput = mikio.getNextSibling(this, '.mikio-input-file'); 93 if (typeof mikioInput !== 'undefined') { 94 mikioInput.innerHTML = this.files[0].name; 95 } 96 } 97 }); 98 } 99 }); 100 101 // Input - Span (Placeholder) clear when typing 102 Array.from(document.querySelectorAll('.mikio.dokuwiki .mode_login fieldset label.block input.edit, .mikio.dokuwiki .mode_denied fieldset label.block input.edit')).forEach(function (elem) { 103 if (elem.value.length != 0) { 104 var sibling = mikio.getPrevSibling(elem, 'span'); 105 if (sibling) { 106 sibling.style.display = 'none'; 107 } 108 } 109 110 elem.addEventListener('keydown', function (event) { 111 var sibling = mikio.getPrevSibling(event.target, 'span'); 112 113 setTimeout(function () { 114 if (sibling) { 115 if (event.target.value != '') { 116 sibling.style.display = 'none'; 117 } else { 118 sibling.style.display = 'block'; 119 } 120 } 121 }, 50); 122 }); 123 }); 124 125 // Admin - Exit button 126 Array.from(document.querySelectorAll('a[rel="exit-admin"]')).forEach(function (elem) { 127 elem.addEventListener('click', function (event) { 128 event.preventDefault(); 129 130 var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname; 131 132 var params = window.location.search; 133 if (params !== '') { 134 params = params.substr(1).split('&'); 135 if (params.length > 1) { 136 href += '?'; 137 params.forEach(function (p) { 138 if (p.substring(0, 3) == 'id=') { 139 href += p; 140 } 141 }); 142 } 143 } 144 145 window.location = href; 146 }); 147 }); 148 149 // Admin - Back button 150 Array.from(document.querySelectorAll('a[rel="exit-page"]')).forEach(function (elem) { 151 elem.addEventListener('click', function (event) { 152 event.preventDefault(); 153 154 var href = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname; 155 156 var params = window.location.search; 157 if (params != '') { 158 params = params.substr(1).split('&'); 159 if (params.length > 1) { 160 href += '?'; 161 params.forEach(function (p) { 162 if (p.substring(0, 5) != 'page=') { 163 href += p + '&'; 164 } 165 }); 166 } 167 } 168 169 window.location = href; 170 }); 171 }); 172 173 // Admin - Resize large text blocks in tasks 174 Array.from(document.querySelectorAll('.admin_tasks span.prompt')).forEach(function (elem) { 175 if (elem.offsetHeight > 48) { 176 elem.style.fontSize = '80%'; 177 } 178 }); 179 180 // Media Manager - ui-resizable is always auto 181 var mediaChangedObserver = new MutationObserver(function (mutationsList) { 182 for (let mutation of mutationsList) { 183 if (mutation.type === 'childList') { 184 if (mutation.addedNodes) { 185 mutation.addedNodes.forEach(function (node) { 186 if (node.nodeName == 'LI') { 187 188 } 189 }); 190 } 191 } 192 193 if (mutation.type === 'attributes' && mutation.attributeName == 'style' && mutation.target && mutation.target.style.height) { 194 mutation.target.style.height = ''; 195 } 196 } 197 }); 198 199 var target = document.getElementById('mediamanager__page'); 200 if (target) { 201 mediaChangedObserver.observe(target, { attributes: true, childList: true, subtree: true }); 202 } 203 204 // Media Manager - file click 205 Array.from(document.querySelectorAll('#mediamanager__page .filelist')).forEach(function (elem) { 206 elem.addEventListener('click', function (event) { 207 var liElem = event.target.closest('li'); 208 if (liElem && event.target.closest('ul.thumbs')) { 209 var aElem = liElem.querySelector('dd.name a'); 210 if (aElem) aElem.click(); 211 } 212 }); 213 }); 214 215 // Popup Media Manager - clean file info 216 var mediaPopupFileInfoClean = function (elem) { 217 var file = { resolution: '', date: '', time: '', size: '' }; 218 219 var infoElem = elem.querySelector('span.info'); 220 if (infoElem) { 221 var infoText = infoElem.innerText.replace(/(<[^>]*>|[\(\)])/g, ''); 222 var detail = infoText.split(' '); 223 while (detail.length < 4) { 224 detail.unshift(''); 225 } 226 227 infoElem.innerHTML = detail[0] + '<br>' + detail[1] + ' ' + detail[2] + '<br>' + detail[3]; 228 } 229 230 Array.from(elem.querySelectorAll('img')).forEach(function (elem) { 231 elem.removeAttribute('width'); 232 elem.removeAttribute('height'); 233 }); 234 } 235 236 var mediaPopupObserver = new MutationObserver(function (mutationsList) { 237 for (let mutation of mutationsList) { 238 if (mutation.type === 'childList') { 239 if (mutation.addedNodes) { 240 mutation.addedNodes.forEach(function (node) { 241 if (node.nodeName == 'DIV') { 242 mediaPopupFileInfoClean(node); 243 } 244 }); 245 } 246 } 247 } 248 }); 249 250 var target = document.getElementById('media__content'); 251 if (target) { 252 Array.from(target.querySelectorAll('div.odd, div.even')).forEach(function (elem) { 253 mediaPopupFileInfoClean(elem); 254 }); 255 256 mediaPopupObserver.observe(target, { attributes: false, childList: true }); 257 } 258 259 if (typeof mikioFooterRun === "function") mikioFooterRun(); 260 261 // TESTING 262 263 var mediaChangedObserver = new MutationObserver(function (mutationsList) { 264 for (let mutation of mutationsList) { 265 if (mutation.type === 'attributes' && mutation.attributeName == 'href') { 266 if (self.mikioCSS != false) { 267 var elem = self.mikioCSS; 268 var prev = elem.href; 269 270 setTimeout(function () { 271 var url = new URL(prev); 272 var params = url.searchParams; 273 params.set('seed', new Date().getTime()); 274 url.search = params.toString(); 275 elem.href = url.toString(); 276 }, 500); 277 } 278 } 279 } 280 }); 281 282 var linkElements = document.getElementsByTagName('link'); 283 for (let element of linkElements) { 284 if (element.rel == 'stylesheet' && element.href) { 285 if (element.href.includes('/lib/exe/css.php')) { 286 mediaChangedObserver.observe(element, { attributes: true, childList: true, subtree: true }); 287 } else if (element.href.includes('/lib/tpl/mikio/css.php')) { 288 this.mikioCSS = element; 289 } 290 } 291 } 292 }, 293 294 insertAfter: function (newNode, existingNode) { 295 existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); 296 }, 297 298 addToggleClick: function (elemToggle, elemCollapse) { 299 this.addEventListenerByClassName(elemToggle, 'click', function (event) { 300 event.preventDefault(); 301 event.stopPropagation(); 302 let nextSibling = mikio.getNextSibling(this, '.' + elemCollapse); 303 304 if (typeof nextSibling !== 'undefined') { 305 mikio.toggleCollapse(this, nextSibling); 306 } 307 }); 308 }, 309 310 addDropdownClick: function (elemToggle, elemCollapse) { 311 this.addEventListenerByClassName(elemToggle, 'click', function (event) { 312 event.preventDefault(); 313 event.stopPropagation(); 314 315 var dropdown = this.querySelector('.' + elemCollapse); 316 if (dropdown) { 317 mikio.toggleDropdown(dropdown); 318 } 319 }); 320 }, 321 322 addEventListenerByClassName: function (className, eventType, callback) { 323 Array.from(document.getElementsByClassName(className)).forEach(function (elem) { 324 elem.addEventListener(eventType, callback); 325 }); 326 }, 327 328 getNextSibling: function (elem, selector) { 329 var sibling = elem.nextElementSibling; 330 331 while (sibling) { 332 if (sibling.matches(selector)) return sibling; 333 sibling = sibling.nextElementSibling; 334 } 335 }, 336 337 getPrevSibling: function (elem, selector) { 338 var sibling = elem.previousElementSibling; 339 340 while (sibling) { 341 if (sibling.matches(selector)) return sibling; 342 sibling = sibling.previousElementSibling; 343 } 344 }, 345 346 toggleCollapse: function (objToggle, objCollapse) { 347 if (objToggle.classList.contains('closed')) { 348 objToggle.classList.remove('closed'); 349 objToggle.classList.add('open'); 350 var height = objCollapse.offsetHeight; 351 objCollapse.style.overflow = 'hidden'; 352 objCollapse.style.height = 0; 353 objCollapse.style.paddingTop = 0; 354 objCollapse.style.paddingBottom = 0; 355 objCollapse.style.marginTop = 0; 356 objCollapse.style.marginBottom = 0; 357 objCollapse.offsetHeight; 358 objCollapse.style.boxSizing = 'border-box'; 359 objCollapse.style.transitionProperty = "height, margin, padding"; 360 objCollapse.style.transitionDuration = '500ms'; 361 objCollapse.style.height = height + 'px'; 362 objCollapse.style.removeProperty('padding-top'); 363 objCollapse.style.removeProperty('padding-bottom'); 364 objCollapse.style.removeProperty('margin-top'); 365 objCollapse.style.removeProperty('margin-bottom'); 366 window.setTimeout(function () { 367 objCollapse.style.removeProperty('height'); 368 objCollapse.style.removeProperty('overflow'); 369 objCollapse.style.removeProperty('transition-duration'); 370 objCollapse.style.removeProperty('transition-property'); 371 objCollapse.style.removeProperty('box-sizing'); 372 }, 500); 373 } else { 374 objCollapse.style.transitionProperty = 'height, margin, padding'; 375 objCollapse.style.transitionDuration = '500ms'; 376 objCollapse.style.boxSizing = 'border-box'; 377 objCollapse.style.height = objCollapse.offsetHeight + 'px'; 378 objCollapse.offsetHeight; 379 objCollapse.style.overflow = 'hidden'; 380 objCollapse.style.height = 0; 381 objCollapse.style.paddingTop = 0; 382 objCollapse.style.paddingBottom = 0; 383 objCollapse.style.marginTop = 0; 384 objCollapse.style.marginBottom = 0; 385 window.setTimeout(function () { 386 objToggle.classList.add('closed'); 387 objToggle.classList.remove('open'); 388 objCollapse.style.removeProperty('height'); 389 objCollapse.style.removeProperty('padding-top'); 390 objCollapse.style.removeProperty('padding-bottom'); 391 objCollapse.style.removeProperty('margin-top'); 392 objCollapse.style.removeProperty('margin-bottom'); 393 objCollapse.style.removeProperty('overflow'); 394 objCollapse.style.removeProperty('transition-duration'); 395 objCollapse.style.removeProperty('transition-property'); 396 objCollapse.style.removeProperty('box-sizing'); 397 }, 500); 398 } 399 }, 400 401 402 toggleDropdown: function (objToggle) { 403 if (objToggle.classList.contains('closed')) { 404 objToggle.classList.remove('closed'); 405 } else { 406 objToggle.classList.add('closed'); 407 } 408 409 Array.from(document.getElementsByClassName('mikio-dropdown')).forEach(function (elem) { 410 if (!elem.classList.contains('closed') && elem != objToggle) { 411 elem.classList.add('closed'); 412 } 413 }); 414 }, 415 416 setHeroSubTitle: function (str) { 417 Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function (elem) { 418 elem.innerHTML = str; 419 }); 420 }, 421 422 setHeroImage: function (str) { 423 var heroImages = document.getElementsByClassName('mikio-hero-image'); 424 425 if (heroImages.length > 0) { 426 Array.from(document.getElementsByClassName('mikio-hero-image')).forEach(function (elem) { 427 elem.style.backgroundImage = 'url(\'' + str + '\')'; 428 elem.classList.add('mikio-hero-image-resize'); 429 }); 430 } else { 431 Array.from(document.getElementsByClassName('mikio-hero-text')).forEach(function (elem) { 432 elem.insertAdjacentHTML('afterend', '<div class="mikio-hero-image mikio-hero-image-resize" style="background-image:url(\'' + str + '\');"></div>'); 433 }); 434 } 435 }, 436 437 setHeroColor: function (str) { 438 var colors = str.trim().replace(/ +(?= )/g, '').split(/(?!\(.*)\s(?![^(]*?\))/g); 439 if (colors.length > 0 && colors[0] != '') { 440 Array.from(document.getElementsByClassName('mikio-hero')).forEach(function (elem) { 441 elem.style.backgroundColor = colors[0]; 442 }); 443 444 if (colors.length > 1) { 445 Array.from(document.getElementsByClassName('mikio-hero-title')).forEach(function (elem) { 446 elem.style.color = colors[1]; 447 }); 448 } 449 450 if (colors.length > 2) { 451 Array.from(document.getElementsByClassName('mikio-hero-subtitle')).forEach(function (elem) { 452 elem.style.color = colors[2]; 453 }); 454 } 455 456 if (colors.length > 3) { 457 Array.from(document.getElementsByClassName('mikio-hero')).forEach(function (parentElem) { 458 Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li a')).forEach(function (elem) { 459 elem.style.color = colors[3]; 460 }); 461 462 Array.from(parentElem.querySelectorAll('.mikio-breadcrumbs ul li, .mikio-breadcrumbs ul li a')).forEach(function (elem) { 463 elem.style.color = colors[3]; 464 elem.onmouseover = function () { this.style.color = (colors.length > 4 ? colors[4] : 'initial'); }; 465 elem.onmouseout = function () { this.style.color = colors[3]; }; 466 }); 467 }); 468 } 469 } 470 }, 471 472 setTags: function (str) { 473 Array.from(document.getElementsByClassName('mikio-tags')).forEach(function (elem) { 474 elem.innerHTML = str; 475 }); 476 }, 477 478 hidePart: function (part) { 479 var selectorArray = { 480 topheader: '.mikio-page-topheader', 481 header: '.mikio-page-header', 482 contentheader: '.mikio-page-contentheader', 483 contentfooter: '.mikio-page-contentfooter', 484 sidebarheader: '.mikio-sidebar-left .mikio-sidebar-header', 485 sidebarfooter: '.mikio-sidebar-left .mikio-sidebar-footer', 486 rightsidebarheader: '.mikio-sidebar-right .mikio-sidebar-header', 487 rightsidebarfooter: '.mikio-sidebar-right .mikio-sidebar-footer', 488 footer: '.mikio-footer', 489 bottomfooter: '.mikio-page-bottomfooter', 490 navbar: '.mikio-navbar', 491 hero: '.mikio-hero' 492 }; 493 494 if (selectorArray.hasOwnProperty(part)) { 495 Array.from(document.querySelectorAll(selectorArray[part])).forEach(function (elem) { 496 elem.style.display = 'none'; 497 }); 498 } 499 } 500}; 501 502 503if (document.readyState != 'loading') { 504 mikio.ready(); 505} else { 506 document.addEventListener('DOMContentLoaded', function () { mikio.ready() }); 507} 508