1function ReadtheDokus() 2{ 3 4 this._currentPage; 5 this._currentPageIndex; 6 this._pages; 7 this._toc = document.getElementById("dw__toc"); 8 this._header = document.querySelector("header"); 9 this._sidebar = document.querySelector("#dokuwiki__aside"); 10 this._delimiter = ( window.location.search.indexOf(":") > -1 ? ":" : "/"); 11 this._id = ( this._delimiter == ":" ? JSINFO["id"] : JSINFO["id"].split(":").join("/") ); 12 this._startPage = ""; 13 14} 15 16ReadtheDokus.prototype.run = function() 17{ 18 19 // Enum sidebar items to 20 // - embed toc in the corresponding sidebar item 21 // - collect all page links 22 var isFound = false; 23 this._pages = []; 24 if (JSINFO["ACT"] == "show") 25 { 26 this._enumSidebarLinks(function(elem) { 27 // Embed toc 28 if (!isFound) 29 { 30 if (elem.href.indexOf(this._id) > -1) 31 { 32 this._embedToc(elem, this._toc); 33 isFound = true; 34 } 35 } 36 37 // Collect page links 38 this._pages.push(elem.href); 39 }.bind(this)); 40 } 41 42 // Start page 43 if (this._pages.length > 0) 44 { 45 this._startPage = this._getStartPage(this._pages[0], this._delimiter); 46 this._pages.unshift(this._startPage); 47 var list = document.querySelectorAll("#sidebarheader > div.home > a, #pageheader .breadcrumbs > .home > a"); 48 var nodes = Array.prototype.slice.call(list, 0); 49 nodes.forEach(function(elem) { 50 elem.href = this._startPage; 51 }.bind(this)); 52 } 53 54 // Show toc on top of sidebar if item was not found in sidebar 55 if (!isFound && this._toc) 56 { 57 this._showToc(this._toc); 58 this.showSidebar(); 59 } 60 61 this._initToc(this._toc); 62 this._initMobileHeader(); 63 this._initPageButtons(); 64 this._sidebar.querySelector("#sidebarheader #qsearch__in").setAttribute("placeholder", "Search docs"); 65 66 if (this._toc) 67 { 68 this._toc.scrollIntoView(true); 69 } 70 71}; 72 73ReadtheDokus.prototype.getMediaQuery = function(elem) 74{ 75 76 return getComputedStyle(document.querySelector("#__media_query")).getPropertyValue("--media-query").trim(); 77 78}; 79 80ReadtheDokus.prototype.toggleTocMenu = function(elem) 81{ 82 83 var invisible = elem.parentNode.querySelector(".toc").classList.contains("invisible"); 84 if (invisible) 85 { 86 this.expandTocMenu(elem); 87 } 88 else 89 { 90 this.collapseTocMenu(elem); 91 } 92 93}; 94 95ReadtheDokus.prototype.expandTocMenu = function(elem, allChildren) 96{ 97 98 if (elem && elem.classList.contains("expandable")) 99 { 100 elem.parentNode.querySelector(".toc").classList.remove("invisible"); 101 102 var i = elem.children[0].children[0].children[0]; 103 i.classList.remove("fa-plus-square"); 104 i.classList.add("fa-minus-square"); 105 106 var img = elem.children[0].children[0].children[1]; 107 img.classList.remove("plus"); 108 img.classList.add("minus"); 109 img.src= DOKU_BASE + "lib/images/minus.gif"; 110 } 111 112}; 113 114ReadtheDokus.prototype.collapseTocMenu = function(elem, allChildren) 115{ 116 117 if (elem && elem.classList.contains("expandable")) 118 { 119 elem.parentNode.querySelector(".toc").classList.add("invisible"); 120 121 var i = elem.children[0].children[0].children[0]; 122 i.classList.remove("fa-minus-square"); 123 i.classList.add("fa-plus-square"); 124 125 var img = elem.children[0].children[0].children[1]; 126 img.classList.remove("minus"); 127 img.classList.add("plus"); 128 img.src=DOKU_BASE + "lib/images/plus.gif"; 129 } 130 131}; 132 133ReadtheDokus.prototype.toggleSidebar = function(elem) 134{ 135 136 if (dokus.getMediaQuery() == "pc" || dokus.getMediaQuery() == "tb") 137 { 138 document.querySelector("#dokuwiki__site").classList.toggle("showSidebar"); 139 } 140 else 141 { 142 document.querySelector("#dokuwiki__site").classList.toggle("showSidebarSP"); 143 } 144 145} 146 147ReadtheDokus.prototype.showSidebar = function(elem) 148{ 149 150 if (dokus.getMediaQuery() == "pc" || dokus.getMediaQuery() == "tb") 151 { 152 document.querySelector("#dokuwiki__site").classList.add("showSidebar"); 153 } 154 else 155 { 156 document.querySelector("#dokuwiki__site").classList.add("showSidebarSP"); 157 } 158 159} 160 161ReadtheDokus.prototype.hideSidebar = function(elem) 162{ 163 164 if (dokus.getMediaQuery() == "pc" || dokus.getMediaQuery() == "tb") 165 { 166 document.querySelector("#dokuwiki__site").classList.remove("showSidebar"); 167 } 168 else 169 { 170 document.querySelector("#dokuwiki__site").classList.remove("showSidebarSP"); 171 } 172 173} 174 175 176ReadtheDokus.prototype._enumSidebarLinks = function(callback) 177{ 178 179 callback = ( typeof callback === "function" ? callback : function(){} ); 180 var links = this._sidebar.querySelectorAll(".aside > #sidebar > ul .level1 a"); 181 var nodes = Array.prototype.slice.call(links, 0); 182 nodes.forEach(function(elem) { 183 callback(elem); 184 }); 185 186}; 187 188ReadtheDokus.prototype._getStartPage = function(basePage, delimiter) 189{ 190 191 var result = ""; 192 193 if (basePage && delimiter) 194 { 195 var re = new RegExp("\\" + delimiter + "[^\\" + delimiter + "]*[^\\" + delimiter + "]*$"); 196 result = basePage.replace(re, "").replace(re, "") + delimiter + "start"; 197 } 198 199 return result; 200 201}; 202 203ReadtheDokus.prototype._embedToc = function(target, toc) 204{ 205 206 if (target && toc) 207 { 208 target.parentNode.parentNode.appendChild(toc); 209 target.parentNode.style.display = "none"; 210 } 211 212}; 213 214ReadtheDokus.prototype._showToc = function(toc) 215{ 216 217 if (toc) 218 { 219 this._toc.parentNode.style.display = "block"; 220 } 221 222}; 223 224ReadtheDokus.prototype._initToc = function(toc) 225{ 226 227 if (toc) 228 { 229 this._installTocSelectHandler(); 230 this._installTocMenuHandler(); 231 this._installTocJumpHandler(); 232 } 233 234}; 235 236// Install click handler to highlight and expand toc menu 237ReadtheDokus.prototype._installTocSelectHandler = function() 238{ 239 240 var list = this._toc.querySelectorAll(".level1 div.li"); 241 var nodes = Array.prototype.slice.call(list, 0); 242 nodes.forEach(function(elem) { 243 elem.addEventListener("click", function() { 244 // Get level2 parent 245 let p = this._getParent(elem, "level2"); 246 247 // Remove all current 248 var list2 = this._toc.querySelectorAll(".current"); 249 var nodes2 = Array.prototype.slice.call(list2, 0); 250 nodes2.forEach(function(elem) { 251 elem.classList.remove("current"); 252 }); 253 254 // Set current to this and level2 parent 255 if (p) 256 { 257 p.parentNode.classList.add("current"); 258 p.classList.add("current"); 259 elem.classList.add("current"); 260 elem.scrollIntoView(true); 261 } 262 263 // Expand 264 this.expandTocMenu(elem); 265 266 // Fold the other level2 items 267 var list3 = this._toc.querySelectorAll(".level2 > div.li.expandable"); 268 var nodes3 = Array.prototype.slice.call(list3, 0); 269 nodes3.forEach(function(item) { 270 if (item != p) 271 { 272 this.collapseTocMenu(item); 273 } 274 }.bind(this)); 275 }.bind(this)); 276 }.bind(this)); 277 278}; 279 280// Install click handler to expand/collapse toc menu 281ReadtheDokus.prototype._installTocMenuHandler = function() 282{ 283 284 // Search for toc menu items which have children 285 var list = this._toc.querySelectorAll("div.li"); 286 var nodes = Array.prototype.slice.call(list, 0); 287 nodes.forEach(function(elem) { 288 if (elem.parentNode.querySelector(".toc")) 289 { 290 elem.classList.add("expandable"); 291 292 // Insert +/- fontawesome icon and image 293 elem.children[0].insertAdjacentHTML("afterbegin", '<div class="btn-expand"><i class="far fa-minus-square"></i><img class="minus" src="' + DOKU_BASE + 'lib/images/minus.gif" alt="−"></div>'); 294 295 // Install click handler 296 elem.children[0].children[0].addEventListener("click", function(e) { 297 this.toggleTocMenu(elem); 298 299 e.stopPropagation(); 300 e.preventDefault(); 301 }.bind(this)); 302 303 // Only level1 menu items are open at start 304 if (!elem.parentNode.classList.contains("level1")) 305 { 306 this.collapseTocMenu(elem); 307 } 308 } 309 310 // Install click handler to move an clicked item to top 311 elem.addEventListener("click", function() { 312 elem.scrollIntoView(true); 313 }); 314 }.bind(this)); 315 316}; 317 318// Install click handler to jump to anchor taking fixed header into account 319ReadtheDokus.prototype._installTocJumpHandler = function() 320{ 321 322 var headerHeight = this._header.height || 0; 323 var list = this._toc.querySelectorAll('a[href*="#"]'); 324 var nodes = Array.prototype.slice.call(list, 0); 325 nodes.forEach(function(elem){ 326 elem.addEventListener("click", function(e) { 327 var hash = elem.getAttribute("href"); 328 var target = document.querySelector(hash); 329 if (target) 330 { 331 if (dokus.getMediaQuery() == "sp") 332 { 333 this.hideSidebar(); 334 } 335 336 var top = target.getBoundingClientRect().top; 337 window.scrollTo({top:window.pageYOffset + top - headerHeight}); 338 } 339 340 e.preventDefault(); 341 return false; 342 }.bind(this)); 343 }.bind(this)); 344 345}; 346ReadtheDokus.prototype._getParent = function(elem, level) 347{ 348 349 let current = elem.parentNode; 350 351 while (current && !current.classList.contains("level1")) 352 { 353 if (current.classList.contains(level)) 354 { 355 return current.children[0]; 356 } 357 358 current = current.parentNode.parentNode; 359 } 360 361 return null; 362 363}; 364 365ReadtheDokus.prototype._initMobileHeader = function() 366{ 367 368 // Add click event handler for mobile menu 369 document.getElementById("btn-mobilemenu").addEventListener("click", function(){ 370 this.toggleSidebar(); 371 }.bind(this)); 372 373}; 374 375ReadtheDokus.prototype._initPageButtons = function() 376{ 377 378 // Get current page (remove hash) 379 this._currentPage = window.location.href.replace(/#.*$/, ""); 380 381 // Get current page index 382 this._currentPageIndex = this._pages.indexOf(this._currentPage); 383 384 // Show prev button 385 if (this._currentPageIndex > 0) 386 { 387 document.getElementById("btn-prevpage").classList.remove("invisible"); 388 document.getElementById("btn-prevpage").href = this._pages[this._currentPageIndex - 1]; 389 } 390 391 // Show next button 392 if (this._currentPageIndex > -1 && this._currentPageIndex < this._pages.length - 1) 393 { 394 document.getElementById("btn-nextpage").classList.remove("invisible"); 395 document.getElementById("btn-nextpage").href = this._pages[this._currentPageIndex + 1]; 396 } 397 398}; 399