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