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(".level1 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 if (p) 188 { 189 p.parentNode.classList.add("current"); 190 p.classList.add("current"); 191 elem.classList.add("current"); 192 elem.scrollIntoView(true); 193 } 194 195 // Expand 196 this.expandTocMenu(elem); 197 198 // Fold the other level2 items 199 this._toc.querySelectorAll(".level2 > div.li.expandable").forEach(function(item) { 200 if (item != p) 201 { 202 this.collapseTocMenu(item); 203 } 204 }.bind(this)); 205 }.bind(this)); 206 }.bind(this)); 207 208}; 209 210// Install click handler to expand/collapse toc menu 211ReadtheDokus.prototype._installTocMenuHandler = function() 212{ 213 214 // Search for toc menu items which have children 215 this._toc.querySelectorAll("div.li").forEach(function(elem) { 216 if (elem.parentNode.querySelector(".toc")) 217 { 218 elem.classList.add("expandable"); 219 220 // Insert +/- fontawesome icon and image 221 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>'); 222 223 // Install click handler 224 elem.children[0].children[0].addEventListener("click", function(e) { 225 this.toggleTocMenu(elem); 226 227 e.stopPropagation(); 228 e.preventDefault(); 229 }.bind(this)); 230 231 // Only level1 menu items are open at start 232 if (!elem.parentNode.classList.contains("level1")) 233 { 234 this.collapseTocMenu(elem); 235 } 236 } 237 238 // Install click handler to move an clicked item to top 239 elem.addEventListener("click", function() { 240 elem.scrollIntoView(true); 241 }); 242 }.bind(this)); 243 244}; 245 246ReadtheDokus.prototype._getParent = function(elem, level) 247{ 248 249 let current = elem.parentNode; 250 251 while (current && !current.classList.contains("level1")) 252 { 253 if (current.classList.contains(level)) 254 { 255 return current.children[0]; 256 } 257 258 current = current.parentNode.parentNode; 259 } 260 261 return null; 262 263} 264 265ReadtheDokus.prototype._initMobileHeader = function() 266{ 267 268 // Add click event handler for mobile menu 269 document.getElementById("btn-mobilemenu").addEventListener("click", function(){ 270 this._sidebar.classList.toggle("visible"); 271 document.querySelector("#dokuwiki__content").classList.toggle("shift"); 272 }.bind(this)); 273 274}; 275 276ReadtheDokus.prototype._initPageButtons = function() 277{ 278 279 // Get current page (remove hash) 280 this._currentPage = window.location.href.replace(/#.*$/, ""); 281 282 // Get current page index 283 this._currentPageIndex = this._pages.indexOf(this._currentPage); 284 285 // Show prev button 286 if (this._currentPageIndex > 0) 287 { 288 document.getElementById("btn-prevpage").classList.add("visible"); 289 document.getElementById("btn-prevpage").href = this._pages[this._currentPageIndex - 1]; 290 } 291 292 // Show next button 293 if (this._currentPageIndex < this._pages.length - 1) 294 { 295 document.getElementById("btn-nextpage").classList.add("visible"); 296 document.getElementById("btn-nextpage").href = this._pages[this._currentPageIndex + 1]; 297 } 298 299}; 300