1function ReadtheDokus() 2{ 3 4 this._currentPage; 5 this._currentPageIndex; 6 this._pages; 7 this._toc = document.getElementById("dw__toc"); 8 this._sidebar =document.querySelector("#dokuwiki__aside"); 9 this._delimiter = ( window.location.search.indexOf(":") > -1 ? ":" : "/"); 10 this._id = ( this._delimiter == ":" ? JSINFO["id"] : JSINFO["id"].replaceAll(":", "/")); 11 this._startPage; 12 13} 14 15ReadtheDokus.prototype.run = function() 16{ 17 18 // Enum sidebar items to 19 // - embed toc in the corresponding sidebar item 20 // - collect all page links 21 var isFound = false; 22 this._pages = []; 23 if (JSINFO["ACT"] == "show") 24 { 25 this._enumSidebarLinks(function(elem) { 26 // Embed toc 27 if (elem.href.indexOf(this._id) > -1) 28 { 29 this._embedToc(elem, this._toc); 30 isFound = true; 31 } 32 33 // Collect page links 34 this._pages.push(elem.href); 35 }.bind(this)); 36 } 37 38 // Start page 39 this._startPage = this._getStartPage(this._pages[0], this._delimiter); 40 this._pages.unshift(this._startPage); 41 42 // Show toc on top of sidebar if item was not found in sidebar 43 if (!isFound) 44 { 45 this._showToc(this._toc); 46 } 47 48 this._initToc(this._toc); 49 this._initMobileHeader(); 50 this._initPageButtons(); 51 this._sidebar.querySelector("#sidebarheader #qsearch__in").setAttribute("placeholder", "Search docs"); 52 53 if (this._toc) 54 { 55 this._toc.scrollIntoView(true); 56 } 57 58}; 59 60ReadtheDokus.prototype.toggleTocMenu = function(elem) 61{ 62 63 var invisible = elem.parentNode.querySelector(".toc").classList.contains("invisible"); 64 if (invisible) 65 { 66 this.expandTocMenu(elem); 67 } 68 else 69 { 70 this.collapseTocMenu(elem); 71 } 72 73} 74 75ReadtheDokus.prototype.expandTocMenu = function(elem, allChildren) 76{ 77 78 if (elem && elem.classList.contains("expandable")) 79 { 80 elem.parentNode.querySelector(".toc").classList.remove("invisible"); 81 82 var i = elem.children[0].children[0].children[0]; 83 i.classList.remove("fa-plus-square"); 84 i.classList.add("fa-minus-square"); 85 86 var img = elem.children[0].children[0].children[1]; 87 img.classList.remove("plus"); 88 img.classList.add("minus"); 89 img.src="/docs/lib/images/minus.gif"; 90 } 91 92} 93 94ReadtheDokus.prototype.collapseTocMenu = function(elem, allChildren) 95{ 96 97 if (elem && elem.classList.contains("expandable")) 98 { 99 elem.parentNode.querySelector(".toc").classList.add("invisible"); 100 101 var i = elem.children[0].children[0].children[0]; 102 i.classList.remove("fa-minus-square"); 103 i.classList.add("fa-plus-square"); 104 105 var img = elem.children[0].children[0].children[1]; 106 img.classList.remove("minus"); 107 img.classList.add("plus"); 108 img.src="/docs/lib/images/plus.gif"; 109 } 110 111} 112 113ReadtheDokus.prototype._enumSidebarLinks = function(callback) 114{ 115 116 callback = ( typeof callback === "function" ? callback : function(){} ); 117 var links = this._sidebar.querySelectorAll(".aside > ul .level1 a"); 118 119 links.forEach(function(elem) { 120 callback(elem); 121 }); 122 123}; 124 125ReadtheDokus.prototype._getStartPage = function(basePage, delimiter) 126{ 127 128 var result = ""; 129 130 if (basePage && delimiter) 131 { 132 var re = new RegExp("\\" + delimiter + "[^\\" + delimiter + "]*[^\\" + delimiter + "]*$"); 133 result = basePage.replace(re, "").replace(re, "") + delimiter + "start"; 134 } 135 136 return result; 137 138} 139 140ReadtheDokus.prototype._embedToc = function(target, toc) 141{ 142 143 if (target && toc) 144 { 145 target.parentNode.parentNode.appendChild(toc); 146 target.parentNode.style.display = "none"; 147 } 148 149}; 150 151ReadtheDokus.prototype._showToc = function(toc) 152{ 153 154 if (toc) 155 { 156 this._toc.parentNode.style.display = "block"; 157 } 158 159}; 160 161ReadtheDokus.prototype._initToc = function(toc) 162{ 163 164 if (toc) 165 { 166 this._installTocSelectHandler(); 167 this._installTocMenuHandler(); 168 } 169 170}; 171 172// Install click handler to highlight and expand toc menu 173ReadtheDokus.prototype._installTocSelectHandler = function() 174{ 175 176 this._toc.querySelectorAll(".level2 div.li").forEach(function(elem) { 177 elem.addEventListener("click", function() { 178 // Get level2 parent 179 let p = this._getParent(elem, "level2"); 180 181 // Remove all current 182 this._toc.querySelectorAll(".current").forEach(function(elem) { 183 elem.classList.remove("current"); 184 }); 185 186 // Set current to this and level2 parent 187 p.parentNode.classList.add("current"); 188 p.classList.add("current"); 189 elem.classList.add("current"); 190 elem.scrollIntoView(true); 191 192 // Expand 193 this.expandTocMenu(elem); 194 195 // Fold the other level2 items 196 this._toc.querySelectorAll(".level2 > div.li.expandable").forEach(function(item) { 197 if (item != p) 198 { 199 this.collapseTocMenu(item); 200 } 201 }.bind(this)); 202 }.bind(this)); 203 }.bind(this)); 204 205}; 206 207// Install click handler to expand/collapse toc menu 208ReadtheDokus.prototype._installTocMenuHandler = function() 209{ 210 211 // Search for toc menu items which have children 212 this._toc.querySelectorAll("div.li").forEach(function(elem) { 213 if (elem.parentNode.querySelector(".toc")) 214 { 215 elem.classList.add("expandable"); 216 217 // Insert +/- fontawesome icon and image 218 elem.children[0].insertAdjacentHTML("afterbegin", '<div class="btn-expand"><i class="far fa-minus-square"></i><img class="minus" src="/docs/lib/images/minus.gif" alt="−"></div>'); 219 220 // Install click handler 221 elem.children[0].children[0].addEventListener("click", function(e) { 222 this.toggleTocMenu(elem); 223 224 e.stopPropagation(); 225 e.preventDefault(); 226 }.bind(this)); 227 228 // Only level1 menu items are open at start 229 if (!elem.parentNode.classList.contains("level1")) 230 { 231 this.collapseTocMenu(elem); 232 } 233 } 234 235 // Install click handler to move an clicked item to top 236 elem.addEventListener("click", function() { 237 elem.scrollIntoView(true); 238 }); 239 }.bind(this)); 240 241}; 242 243ReadtheDokus.prototype._getParent = function(elem, level) 244{ 245 246 let current = elem.parentNode; 247 248 while (current) 249 { 250 if (current.classList.contains(level)) 251 { 252 return current.children[0]; 253 } 254 255 current = current.parentNode.parentNode; 256 } 257 258} 259 260ReadtheDokus.prototype._initMobileHeader = function() 261{ 262 263 // Add click event handler for mobile menu 264 document.getElementById("btn-mobilemenu").addEventListener("click", function(){ 265 this._sidebar.classList.toggle("visible"); 266 document.querySelector("#dokuwiki__content").classList.toggle("shift"); 267 }.bind(this)); 268 269}; 270 271ReadtheDokus.prototype._initPageButtons = function() 272{ 273 274 // Get current page (remove hash) 275 this._currentPage = window.location.href.replace(/#.*$/, ""); 276 277 // Get current page index 278 this._currentPageIndex = this._pages.indexOf(this._currentPage); 279 280 // Show prev button 281 if (this._currentPageIndex > 0) 282 { 283 document.getElementById("btn-prevpage").classList.add("visible"); 284 document.getElementById("btn-prevpage").href = this._pages[this._currentPageIndex - 1]; 285 } 286 287 // Show next button 288 if (this._currentPageIndex < this._pages.length - 1) 289 { 290 document.getElementById("btn-nextpage").classList.add("visible"); 291 document.getElementById("btn-nextpage").href = this._pages[this._currentPageIndex + 1]; 292 } 293 294}; 295