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