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