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