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