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