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