1document.addEventListener('DOMContentLoaded', function () { 2 let headerContentWidth, $nav 3 let mobileSidebarOpen = false 4 5 const adjustMenu = init => { 6 const getAllWidth = ele => { 7 let width = 0 8 ele.length && Array.from(ele).forEach(i => { width += i.offsetWidth }) 9 return width 10 } 11 12 if (init) { 13 const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children) 14 const menusWidth = getAllWidth(document.getElementById('menus').children) 15 headerContentWidth = blogInfoWidth + menusWidth 16 $nav = document.getElementById('nav') 17 } 18 19 let hideMenuIndex = '' 20 if (window.innerWidth <= 768) hideMenuIndex = true 21 else hideMenuIndex = headerContentWidth > $nav.offsetWidth - 120 22 23 if (hideMenuIndex) { 24 $nav.classList.add('hide-menu') 25 } else { 26 $nav.classList.remove('hide-menu') 27 } 28 } 29 30 // åå§åheader 31 const initAdjust = () => { 32 adjustMenu(true) 33 $nav.classList.add('show') 34 } 35 36 // sidebar menus 37 const sidebarFn = { 38 open: () => { 39 btf.sidebarPaddingR() 40 document.body.style.overflow = 'hidden' 41 btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s') 42 document.getElementById('sidebar-menus').classList.add('open') 43 mobileSidebarOpen = true 44 }, 45 close: () => { 46 const $body = document.body 47 $body.style.overflow = '' 48 $body.style.paddingRight = '' 49 btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s') 50 document.getElementById('sidebar-menus').classList.remove('open') 51 mobileSidebarOpen = false 52 } 53 } 54 55 /** 56 * é¦é top_imgåºä¸çç®é 57 */ 58 const scrollDownInIndex = () => { 59 const $scrollDownEle = document.getElementById('scroll-down') 60 $scrollDownEle && $scrollDownEle.addEventListener('click', function () { 61 btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300) 62 }) 63 } 64 65 /** 66 * 代碼 67 * åªé©ç¨æ¼Hexoé»èªç代碼渲æ 68 */ 69 const addHighlightTool = function () { 70 const highLight = GLOBAL_CONFIG.highlight 71 if (!highLight) return 72 73 const isHighlightCopy = highLight.highlightCopy 74 const isHighlightLang = highLight.highlightLang 75 const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink 76 const highlightHeightLimit = highLight.highlightHeightLimit 77 const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined 78 const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') 79 80 if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return 81 82 const isPrismjs = highLight.plugin === 'prismjs' 83 84 let highlightShrinkEle = '' 85 let highlightCopyEle = '' 86 const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' 87 88 if (isHighlightShrink !== undefined) { 89 highlightShrinkEle = `<i class="fas fa-angle-down expand ${highlightShrinkClass}"></i>` 90 } 91 92 if (isHighlightCopy) { 93 highlightCopyEle = '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>' 94 } 95 96 const copy = (text, ctx) => { 97 if (document.queryCommandSupported && document.queryCommandSupported('copy')) { 98 document.execCommand('copy') 99 if (GLOBAL_CONFIG.Snackbar !== undefined) { 100 btf.snackbarShow(GLOBAL_CONFIG.copy.success) 101 } else { 102 const prevEle = ctx.previousElementSibling 103 prevEle.innerText = GLOBAL_CONFIG.copy.success 104 prevEle.style.opacity = 1 105 setTimeout(() => { prevEle.style.opacity = 0 }, 700) 106 } 107 } else { 108 if (GLOBAL_CONFIG.Snackbar !== undefined) { 109 btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport) 110 } else { 111 ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport 112 } 113 } 114 } 115 116 // click events 117 const highlightCopyFn = (ele) => { 118 const $buttonParent = ele.parentNode 119 $buttonParent.classList.add('copy-true') 120 const selection = window.getSelection() 121 const range = document.createRange()
122 if (isPrismjs) range.selectNodeContents($buttonParent.querySelectorAll('pre code')[0]) 123 else range.selectNodeContents($buttonParent.querySelectorAll('table .code pre')[0]) 124 selection.removeAllRanges() 125 selection.addRange(range) 126 const text = selection.toString() 127 copy(text, ele.lastChild) 128 selection.removeAllRanges() 129 $buttonParent.classList.remove('copy-true') 130 } 131 132 const highlightShrinkFn = (ele) => { 133 const $nextEle = [...ele.parentNode.children].slice(1) 134 ele.firstChild.classList.toggle('closed') 135 if (btf.isHidden($nextEle[$nextEle.length - 1])) { 136 $nextEle.forEach(e => { e.style.display = 'block' }) 137 } else { 138 $nextEle.forEach(e => { e.style.display = 'none' }) 139 } 140 } 141 142 const highlightToolsFn = function (e) { 143 const $target = e.target.classList 144 if ($target.contains('expand')) highlightShrinkFn(this) 145 else if ($target.contains('copy-button')) highlightCopyFn(this) 146 } 147 148 const expandCode = function () { 149 this.classList.toggle('expand-done') 150 } 151 152 function createEle (lang, item, service) { 153 const fragment = document.createDocumentFragment() 154 155 if (isShowTool) { 156 const hlTools = document.createElement('div') 157 hlTools.className = `highlight-tools ${highlightShrinkClass}` 158 hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle 159 hlTools.addEventListener('click', highlightToolsFn) 160 fragment.appendChild(hlTools) 161 } 162 163 if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) { 164 const ele = document.createElement('div') 165 ele.className = 'code-expand-btn' 166 ele.innerHTML = '<i class="fas fa-angle-double-down"></i>' 167 ele.addEventListener('click', expandCode) 168 fragment.appendChild(ele) 169 } 170 171 if (service === 'hl') { 172 item.insertBefore(fragment, item.firstChild) 173 } else { 174 item.parentNode.insertBefore(fragment, item) 175 } 176 } 177 178 if (isHighlightLang) { 179 if (isPrismjs) { 180 $figureHighlight.forEach(function (item) { 181 const langName = item.getAttribute('data-language') ? item.getAttribute('data-language') : 'Code' 182 const highlightLangEle = `<div class="code-lang">${langName}</div>` 183 btf.wrap(item, 'figure', { class: 'highlight' }) 184 createEle(highlightLangEle, item) 185 }) 186 } else { 187 $figureHighlight.forEach(function (item) { 188 let langName = item.getAttribute('class').split(' ')[1] 189 if (langName === 'plain' || langName === undefined) langName = 'Code' 190 const highlightLangEle = `<div class="code-lang">${langName}</div>` 191 createEle(highlightLangEle, item, 'hl') 192 }) 193 } 194 } else { 195 if (isPrismjs) { 196 $figureHighlight.forEach(function (item) { 197 btf.wrap(item, 'figure', { class: 'highlight' }) 198 createEle('', item) 199 }) 200 } else { 201 $figureHighlight.forEach(function (item) { 202 createEle('', item, 'hl') 203 }) 204 } 205 } 206 } 207 208 /** 209 * PhotoFigcaption 210 */ 211 function addPhotoFigcaption () { 212 document.querySelectorAll('#article-container img').forEach(function (item) { 213 const parentEle = item.parentNode 214 const altValue = item.title || item.alt 215 if (altValue && !parentEle.parentNode.classList.contains('justified-gallery')) { 216 const ele = document.createElement('div') 217 ele.className = 'img-alt is-center' 218 ele.textContent = altValue 219 parentEle.insertBefore(ele, item.nextSibling) 220 } 221 }) 222 } 223 224 /** 225 * Lightbox 226 */ 227 const runLightbox = () => { 228 btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)')) 229 } 230 231 /** 232 * justified-gallery å庫æç 233 */ 234 const runJustifiedGallery = function (ele) { 235 const htmlStr = arr => { 236 let str = '' 237 const replaceDq = str => str.replace(/"/g, '"') // replace double quotes to " 238 arr.forEach(i => { 239 const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : '' 240 const title = i.title ? `title="${replaceDq(i.title)}"` : '' 241 str += `<div class="fj-gallery-item"><img src="${i.url}" ${alt + title}"></div>` 242 }) 243 return str 244 } 245 246 const lazyloadFn = (i, arr) => { 247 const loadItem = i.getAttribute('data-limit') 248 const arrLength = arr.length 249 if (arrLength > loadItem) i.insertAdjacentHTML('beforeend', htmlStr(arr.splice(0, loadItem))) 250 else { 251 i.insertAdjacentHTML('beforeend', htmlStr(arr)) 252 i.classList.remove('lazyload') 253 } 254 return arrLength > loadItem ? loadItem : arrLength 255 } 256 257 ele.forEach(item => { 258 const arr = JSON.parse(item.querySelector('.gallery-data').textContent) 259 if (!item.classList.contains('lazyload')) item.innerHTML = htmlStr(arr) 260 else { 261 lazyloadFn(item, arr) 262 const limit = item.getAttribute('data-limit') 263 const clickBtnFn = () => { 264 const lastItemLength = lazyloadFn(item, arr) 265 fjGallery(item, 'appendImages', item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)) 266 btf.loadLightbox(item.querySelectorAll('img')) 267 lastItemLength < limit && item.nextElementSibling.removeEventListener('click', clickBtnFn) 268 } 269 item.nextElementSibling.addEventListener('click', clickBtnFn) 270 } 271 }) 272 273 if (window.fjGallery) { 274 setTimeout(() => { btf.initJustifiedGallery(ele) }, 100) 275 return 276 } 277 278 getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`) 279 getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) }) 280 } 281 282 /** 283 * rightside scroll percent 284 */ 285 const rightsideScrollPercent = currentTop => { 286 const perNum = btf.getScrollPercent(currentTop, document.body) 287 const $goUp = document.getElementById('go-up') 288 if (perNum < 95) { 289 $goUp.classList.add('show-percent') 290 $goUp.querySelector('.scroll-percent').textContent = perNum 291 } else { 292 $goUp.classList.remove('show-percent') 293 } 294 } 295 296 /** 297 * 滾åèç 298 */ 299 const scrollFn = function () { 300 const $rightside = document.getElementById('rightside') 301 const innerHeight = window.innerHeight + 56 302 303 // ç¶æ»¾åæ¢å°äº 56 çæå
304 if (document.body.scrollHeight <= innerHeight) { 305 $rightside.style.cssText = 'opacity: 1; transform: translateX(-58px)' 306 return 307 } 308 309 // find the scroll direction 310 function scrollDirection (currentTop) { 311 const result = currentTop > initTop // true is down & false is up 312 initTop = currentTop 313 return result 314 } 315 316 let initTop = 0 317 let isChatShow = true 318 const $header = document.getElementById('page-header') 319 const isChatBtnHide = typeof chatBtnHide === 'function' 320 const isChatBtnShow = typeof chatBtnShow === 'function' 321 const isShowPercent = GLOBAL_CONFIG.percent.rightside 322 323 const scrollTask = btf.throttle(() => { 324 const currentTop = window.scrollY || document.documentElement.scrollTop 325 const isDown = scrollDirection(currentTop) 326 if (currentTop > 56) { 327 if (isDown) { 328 if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible') 329 if (isChatBtnShow && isChatShow === true) { 330 chatBtnHide() 331 isChatShow = false 332 } 333 } else { 334 if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible') 335 if (isChatBtnHide && isChatShow === false) { 336 chatBtnShow() 337 isChatShow = true 338 } 339 } 340 $header.classList.add('nav-fixed') 341 if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') { 342 $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' 343 } 344 } else { 345 if (currentTop === 0) { 346 $header.classList.remove('nav-fixed', 'nav-visible') 347 } 348 $rightside.style.cssText = "opacity: ''; transform: ''" 349 } 350 351 isShowPercent && rightsideScrollPercent(currentTop) 352
353 if (document.body.scrollHeight <= innerHeight) { 354 $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' 355 } 356 }, 200) 357 358 window.scrollCollect = scrollTask 359 360 window.addEventListener('scroll', scrollCollect) 361 } 362 363 /** 364 * toc,anchor 365 */ 366 const scrollFnToDo = function () { 367 const isToc = GLOBAL_CONFIG_SITE.isToc 368 const isAnchor = GLOBAL_CONFIG.isAnchor 369 const $article = document.getElementById('article-container') 370 371 if (!($article && (isToc || isAnchor))) return 372 373 let $tocLink, $cardToc, autoScrollToc, $tocPercentage, isExpand 374 375 if (isToc) { 376 const $cardTocLayout = document.getElementById('card-toc') 377 $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0] 378 $tocLink = $cardToc.querySelectorAll('.toc-link') 379 $tocPercentage = $cardTocLayout.querySelector('.toc-percentage') 380 isExpand = $cardToc.classList.contains('is-expand') 381 382 window.mobileToc = { 383 open: () => { 384 $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px' 385 }, 386 387 close: () => { 388 $cardTocLayout.style.animation = 'toc-close .2s' 389 setTimeout(() => { 390 $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''" 391 }, 100) 392 } 393 } 394 395 // tocå ç´ é»æ 396 $cardToc.addEventListener('click', e => { 397 e.preventDefault() 398 const target = e.target.classList 399 if (target.contains('toc-content')) return 400 const $target = target.contains('toc-link') 401 ? e.target 402 : e.target.parentElement 403 btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300) 404 if (window.innerWidth < 900) { 405 window.mobileToc.close() 406 } 407 }) 408 409 autoScrollToc = item => { 410 const activePosition = item.getBoundingClientRect().top 411 const sidebarScrollTop = $cardToc.scrollTop 412 if (activePosition > (document.documentElement.clientHeight - 100)) { 413 $cardToc.scrollTop = sidebarScrollTop + 150 414 } 415 if (activePosition < 100) { 416 $cardToc.scrollTop = sidebarScrollTop - 150 417 } 418 } 419 } 420 421 // find head position & add active class 422 const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6') 423 let detectItem = '' 424 const findHeadPosition = function (top) { 425 if (top === 0) { 426 return false 427 } 428 429 let currentId = '' 430 let currentIndex = '' 431 432 list.forEach(function (ele, index) { 433 if (top > btf.getEleTop(ele) - 80) { 434 const id = ele.id 435 currentId = id ? '#' + encodeURI(id) : '' 436 currentIndex = index 437 } 438 }) 439 440 if (detectItem === currentIndex) return 441 442 if (isAnchor) btf.updateAnchor(currentId) 443 444 detectItem = currentIndex 445 446 if (isToc) { 447 $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') }) 448 449 if (currentId === '') { 450 return 451 } 452 453 const currentActive = $tocLink[currentIndex] 454 currentActive.classList.add('active') 455 456 setTimeout(() => { 457 autoScrollToc(currentActive) 458 }, 0) 459 460 if (isExpand) return 461 let parent = currentActive.parentNode 462 463 for (; !parent.matches('.toc'); parent = parent.parentNode) { 464 if (parent.matches('li')) parent.classList.add('active') 465 } 466 } 467 } 468 469 // main of scroll 470 window.tocScrollFn = btf.throttle(() => { 471 const currentTop = window.scrollY || document.documentElement.scrollTop 472 if (isToc && GLOBAL_CONFIG.percent.toc) { 473 $tocPercentage.textContent = btf.getScrollPercent(currentTop, $article) 474 } 475 findHeadPosition(currentTop) 476 }, 100) 477 478 window.addEventListener('scroll', tocScrollFn) 479 } 480 481 /** 482 * Rightside 483 */ 484 const rightSideFn = { 485 switchReadMode: () => { // read-mode 486 $('.code-toolbar').addClass('read-fa') 487 const $body = document.body 488 $body.classList.add('read-mode') 489 const newEle = document.createElement('button') 490 newEle.type = 'button' 491 newEle.className = 'fas fa-sign-out-alt exit-readmode' 492 $body.appendChild(newEle) 493 494 function clickFn () { 495 $body.classList.remove('read-mode') 496 $('.code-toolbar').removeClass('read-fa') 497 newEle.remove() 498 newEle.removeEventListener('click', clickFn) 499 } 500 501 newEle.addEventListener('click', clickFn) 502 }, 503 switchDarkMode: () => { // Switch Between Light And Dark Mode 504 const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' 505 if (nowMode === 'light') { 506 activateDarkMode() 507 saveToLocal.set('theme', 'dark', 2) 508 GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) 509 } else { 510 activateLightMode() 511 saveToLocal.set('theme', 'light', 2) 512 GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) 513 } 514 // handle some cases 515 typeof utterancesTheme === 'function' && utterancesTheme() 516 typeof changeGiscusTheme === 'function' && changeGiscusTheme() 517 typeof FB === 'object' && window.loadFBComment() 518 window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200) 519 typeof runMermaid === 'function' && window.runMermaid() 520 }, 521 showOrHideBtn: (e) => { // rightside 黿è¨ç½® æé å±é 522 const rightsideHideClassList = document.getElementById('rightside-config-hide').classList 523 rightsideHideClassList.toggle('show') 524 if (e.classList.contains('show')) { 525 rightsideHideClassList.add('status') 526 setTimeout(() => { 527 rightsideHideClassList.remove('status') 528 }, 300) 529 } 530 e.classList.toggle('show') 531 }, 532 scrollToTop: () => { // Back to top 533 btf.scrollToDest(0, 500) 534 }, 535 hideAsideBtn: () => { // Hide aside 536 const $htmlDom = document.documentElement.classList 537 $htmlDom.contains('hide-aside') 538 ? saveToLocal.set('aside-status', 'show', 2) 539 : saveToLocal.set('aside-status', 'hide', 2) 540 $htmlDom.toggle('hide-aside') 541 }, 542 543 runMobileToc: () => { 544 if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open() 545 else window.mobileToc.close() 546 }, 547 548 adjustFontSize: (plus) => { 549 const fontSizeVal = parseInt(window.getComputedStyle(document.documentElement).getPropertyValue('--global-font-size')) 550 let newValue = '' 551 detectFontSizeChange = true 552 if (plus) { 553 if (fontSizeVal >= 20) return 554 newValue = fontSizeVal + 1 555 document.documentElement.style.setProperty('--global-font-size', newValue + 'px') 556 !document.getElementById('nav').classList.contains('hide-menu') && adjustMenu() 557 } else {
558 if (fontSizeVal <= 10) return 559 newValue = fontSizeVal - 1 560 document.documentElement.style.setProperty('--global-font-size', newValue + 'px') 561 document.getElementById('nav').classList.contains('hide-menu') && adjustMenu() 562 } 563 564 saveToLocal.set('global-font-size', newValue, 2) 565 // document.getElementById('font-text').innerText = newValue 566 } 567 } 568 569 document.getElementById('rightside').addEventListener('click', function (e) { 570 const $target = e.target.id ? e.target : e.target.parentNode 571 switch ($target.id) { 572 case 'go-up': 573 rightSideFn.scrollToTop() 574 break 575 case 'rightside_config': 576 rightSideFn.showOrHideBtn($target) 577 break 578 case 'mobile-toc-button': 579 rightSideFn.runMobileToc() 580 break 581 case 'readmode': 582 rightSideFn.switchReadMode() 583 break 584 case 'darkmode': 585 rightSideFn.switchDarkMode() 586 break 587 case 'hide-aside-btn': 588 rightSideFn.hideAsideBtn() 589 break 590 case 'font-plus': 591 rightSideFn.adjustFontSize(true) 592 break 593 case 'font-minus': 594 rightSideFn.adjustFontSize() 595 break 596 default: 597 break 598 } 599 }) 600 601 /** 602 * menu 603 * å´éæ¬sub-menu å±é/æ¶ç¸® 604 */ 605 const clickFnOfSubMenu = () => { 606 document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) { 607 item.addEventListener('click', function () { 608 this.classList.toggle('hide') 609 }) 610 }) 611 } 612 613 /** 614 * è¤è£½æå ä¸çæ¬ä¿¡æ¯ 615 */ 616 const addCopyright = () => { 617 const copyright = GLOBAL_CONFIG.copyright 618 document.body.oncopy = (e) => { 619 e.preventDefault() 620 let textFont; const copyFont = window.getSelection(0).toString() 621 if (copyFont.length > copyright.limitCount) { 622 textFont = copyFont + '\n' + '\n' + '\n' + 623 copyright.languages.author + '\n' + 624 copyright.languages.link + window.location.href + '\n' + 625 copyright.languages.source + '\n' + 626 copyright.languages.info 627 } else { 628 textFont = copyFont 629 } 630 if (e.clipboardData) { 631 return e.clipboardData.setData('text', textFont) 632 } else { 633 return window.clipboardData.setData('text', textFont) 634 } 635 } 636 } 637 638 /** 639 * ç¶²é éè¡æé 640 */ 641 const addRuntime = () => { 642 const $runtimeCount = document.getElementById('runtimeshow') 643 if ($runtimeCount) { 644 const publishDate = $runtimeCount.getAttribute('data-publishDate') 645 $runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime 646 } 647 } 648 649 /** 650 * æå¾ä¸æ¬¡æ´æ°æé 651 */ 652 const addLastPushDate = () => { 653 const $lastPushDateItem = document.getElementById('last-push-date') 654 if ($lastPushDateItem) { 655 const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate') 656 $lastPushDateItem.innerText = btf.diffDate(lastPushDate, true) 657 } 658 } 659 660 /** 661 * table overflow 662 */ 663 const addTableWrap = () => { 664 const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table') 665 if ($table.length) { 666 $table.forEach(item => { 667 btf.wrap(item, 'div', { class: 'table-wrap' }) 668 }) 669 } 670 } 671 672 /** 673 * tag-hide 674 */ 675 const clickFnOfTagHide = function () { 676 const $hideInline = document.querySelectorAll('#article-container .hide-button') 677 if ($hideInline.length) { 678 $hideInline.forEach(function (item) { 679 item.addEventListener('click', function (e) { 680 const $this = this 681 $this.classList.add('open') 682 const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery') 683 $fjGallery.length && btf.initJustifiedGallery($fjGallery) 684 }) 685 }) 686 } 687 } 688 689 const tabsFn = { 690 clickFnOfTabs: function () { 691 document.querySelectorAll('#article-container .tab > button').forEach(function (item) { 692 item.addEventListener('click', function (e) { 693 const $this = this 694 const $tabItem = $this.parentNode 695 696 if (!$tabItem.classList.contains('active')) { 697 const $tabContent = $tabItem.parentNode.nextElementSibling 698 const $siblings = btf.siblings($tabItem, '.active')[0] 699 $siblings && $siblings.classList.remove('active') 700 $tabItem.classList.add('active') 701 const tabId = $this.getAttribute('data-href').replace('#', '') 702 const childList = [...$tabContent.children] 703 childList.forEach(item => { 704 if (item.id === tabId) item.classList.add('active') 705 else item.classList.remove('active') 706 }) 707 const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`) 708 if ($isTabJustifiedGallery.length > 0) { 709 btf.initJustifiedGallery($isTabJustifiedGallery) 710 } 711 } 712 }) 713 }) 714 }, 715 backToTop: () => { 716 document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) { 717 item.addEventListener('click', function () { 718 btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300) 719 }) 720 }) 721 } 722 } 723 724 const toggleCardCategory = function () { 725 const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i') 726 if ($cardCategory.length) {
727 $cardCategory.forEach(function (item) { 728 item.addEventListener('click', function (e) { 729 e.preventDefault() 730 const $this = this 731 $this.classList.toggle('expand') 732 const $parentEle = $this.parentNode.nextElementSibling 733 if (btf.isHidden($parentEle)) { 734 $parentEle.style.display = 'block' 735 } else { 736 $parentEle.style.display = 'none' 737 } 738 }) 739 }) 740 } 741 } 742 743 const switchComments = function () { 744 let switchDone = false 745 const $switchBtn = document.querySelector('#comment-switch > .switch-btn') 746 $switchBtn && $switchBtn.addEventListener('click', function () { 747 this.classList.toggle('move') 748 document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) { 749 if (btf.isHidden(item)) { 750 item.style.cssText = 'display: block;animation: tabshow .5s' 751 } else { 752 item.style.cssText = "display: none;animation: ''" 753 } 754 }) 755 756 if (!switchDone && typeof loadOtherComment === 'function') { 757 switchDone = true 758 loadOtherComment() 759 } 760 }) 761 } 762 763 const addPostOutdateNotice = function () { 764 const data = GLOBAL_CONFIG.noticeOutdate 765 const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate) 766 if (diffDay >= data.limitDay) { 767 const ele = document.createElement('div') 768 ele.className = 'post-outdate-notice' 769 ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext 770 const $targetEle = document.getElementById('article-container') 771 if (data.position === 'top') { 772 $targetEle.insertBefore(ele, $targetEle.firstChild) 773 } else { 774 $targetEle.appendChild(ele) 775 } 776 } 777 } 778 779 const lazyloadImg = () => { 780 window.lazyLoadInstance = new LazyLoad({ 781 elements_selector: 'img', 782 threshold: 0, 783 data_src: 'lazy-src' 784 }) 785 } 786 787 const relativeDate = function (selector) { 788 selector.forEach(item => { 789 const $this = item 790 const timeVal = $this.getAttribute('datetime') 791 $this.innerText = btf.diffDate(timeVal, true) 792 $this.style.display = 'inline' 793 }) 794 } 795 796 const unRefreshFn = function () { 797 window.addEventListener('resize', () => { 798 adjustMenu(false) 799 btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close() 800 }) 801 802 document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() }) 803 804 clickFnOfSubMenu() 805 GLOBAL_CONFIG.islazyload && lazyloadImg() 806 GLOBAL_CONFIG.copyright !== undefined && addCopyright() 807 } 808 809 window.refreshFn = function () { 810 initAdjust() 811 812 if (GLOBAL_CONFIG_SITE.isPost) { 813 GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice() 814 GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time')) 815 } else { 816 GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time')) 817 GLOBAL_CONFIG.runtime && addRuntime() 818 addLastPushDate() 819 toggleCardCategory() 820 } 821 822 scrollFnToDo() 823 GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() 824 addHighlightTool() 825 GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() 826 scrollFn() 827 828 const $jgEle = document.querySelectorAll('#article-container .fj-gallery') 829 $jgEle.length && runJustifiedGallery($jgEle) 830 831 runLightbox() 832 addTableWrap() 833 clickFnOfTagHide() 834 tabsFn.clickFnOfTabs() 835 tabsFn.backToTop() 836 switchComments() 837 document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() }) 838 } 839 840 refreshFn() 841 unRefreshFn() 842})
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.