/** * 當menu過多時,自動適配,避免UI錯亂 * @param {*} n * 傳入 1 sidebar打開時 * 傳入 2 正常狀態下 */ const blogNameWidth = $('#site-name').width() const menusWidth = $('.menus').width() const sidebarWidth = $('#sidebar').width() || 300 const adjustMenu = function (n) { const $nav = $('#nav') let t if (n === 0) t = true else if (n === 1) t = blogNameWidth + menusWidth > $nav.width() - sidebarWidth - 30 else t = blogNameWidth + menusWidth > $nav.width() - 30 if (t) { $nav.addClass('hide-menu') } else { $nav.removeClass('hide-menu') } } // 初始化header const initAdjust = () => { if (window.innerWidth < 768) adjustMenu(0) else adjustMenu(2) $('#nav').css({ opacity: '1', animation: 'headerNoOpacity 1s' }) } /** * 進入post頁sidebar處理 */ const OpenSidebarAuto = () => { if (window.innerWidth > 1024 && $('#toggle-sidebar').hasClass('on')) { setTimeout(function () { openSidebar() }, 400) } } /** * 點擊左下角箭頭,顯示sidebar */ const closeSidebar = () => { $('#sidebar').removeClass('tocOpenPc').animate({ left: '-300px' }, 400) $('.menus').animate({ paddingRight: 0 }, 400) $('#body-wrap').animate({ paddingLeft: 0 }, 400) if ($('#nav').hasClass('hide-menu')) { setTimeout(function () { adjustMenu(2) }, 400) } } const openSidebar = () => { if (!$('#nav').hasClass('hide-menu')) { adjustMenu(1) } $('#sidebar').addClass('tocOpenPc').animate({ left: 0 }, 400) $('.menus').animate({ paddingRight: 300 }, 400) $('#body-wrap').animate({ paddingLeft: 300 }, 400) } const toggleSidebar = function () { $('#toggle-sidebar').on('click', function () { const isOpen = $(this).hasClass('on') isOpen ? $(this).removeClass('on') : $(this).addClass('on') if (isOpen) { closeSidebar() } else { openSidebar() } }) } /** * 手機menu和toc按鈕點擊 * 顯示menu和toc的sidebar */ const sidebarFn = () => { const $toggleMenu = $('.toggle-menu') const $mobileSidebarMenus = $('#mobile-sidebar-menus') const $mobileTocButton = $('#mobile-toc-button') const $menuMask = $('#menu_mask') const $body = $('body') const $sidebar = $('#sidebar') function openMobileSidebar (name) { sidebarPaddingR() $body.css('overflow', 'hidden') $menuMask.fadeIn() if (name === 'menu') { $toggleMenu.removeClass('close').addClass('open') $mobileSidebarMenus.addClass('open') } if (name === 'toc') { $mobileTocButton.removeClass('close').addClass('open') $sidebar.addClass('tocOpenMobile').css({ transform: 'translate3d(-100%,0,0)', left: '' }) } } function closeMobileSidebar (name) { $body.css({ overflow: '', 'padding-right': '' }) $menuMask.fadeOut() if (name === 'menu') { $toggleMenu.removeClass('open').addClass('close') $mobileSidebarMenus.removeClass('open') } if (name === 'toc') { $mobileTocButton.removeClass('open').addClass('close') $sidebar.removeClass('tocOpenMobile').css({ transform: '' }) } } $toggleMenu.on('click', function () { openMobileSidebar('menu') }) $mobileTocButton.on('click', function () { openMobileSidebar('toc') }) $menuMask.on('click touchstart', function (e) { if ($toggleMenu.hasClass('open')) { closeMobileSidebar('menu') } if ($mobileTocButton.hasClass('open')) { closeMobileSidebar('toc') } }) $(window).on('resize', function (e) { if (!$toggleMenu.is(':visible')) { if ($toggleMenu.hasClass('open')) closeMobileSidebar('menu') } }) const mql = window.matchMedia('(max-width: 1024px)') mql.addEventListener('change', function (ev) { if (ev.matches) { if ($sidebar.hasClass('tocOpenPc')) closeSidebar() } else { if ($('#toggle-sidebar').hasClass('on')) openSidebar() if ($mobileTocButton.hasClass('open')) closeMobileSidebar('toc') } }) // toc元素點擊 $sidebar.find('.toc-link').on('click', function (e) { e.preventDefault() scrollToDest(decodeURI($(this).attr('href'))) if (window.innerWidth <= 1024) { closeMobileSidebar('toc') } }) } /** * 首頁top_img底下的箭頭 */ const scrollDownInIndex = () => { $('#scroll_down').on('click', function () { scrollToDest('#content-inner') }) } /** * 代碼 * 只適用於Hexo默認的代碼渲染 */ const addHighlightTool = function () { const isHighlightCopy = GLOBAL_CONFIG.highlight.highlightCopy const isHighlightLang = GLOBAL_CONFIG.highlight.highlightLang const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined const $figureHighlight = GLOBAL_CONFIG.highlight.plugin === 'highlighjs' ? $('figure.highlight') : $('pre[class*="language-"') if (isShowTool && $figureHighlight.length) { const isPrismjs = GLOBAL_CONFIG.highlight.plugin === 'prismjs' let highlightShrinkEle = '' let highlightCopyEle = '' const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' if (isHighlightShrink !== undefined) { highlightShrinkEle = `` } if (isHighlightCopy) { highlightCopyEle = '
' } if (isHighlightLang) { if (isPrismjs) { $figureHighlight.each(function () { const $this = $(this) const langName = $this.attr('data-language') !== undefined ? $this.attr('data-language') : 'Code' const highlightLangEle = `
${langName}
` $this.wrap('
').before(`
${highlightShrinkEle + highlightLangEle + highlightCopyEle}
`) }) } else { $figureHighlight.each(function (i, o) { const $this = $(this) let langName = $this.attr('class').split(' ')[1] if (langName === 'plain' || langName === undefined) langName = 'Code' const highlightLangEle = `
${langName}
` $this.prepend(`
${highlightShrinkEle + highlightLangEle + highlightCopyEle}
`) }) } } else { const ele = `
${highlightShrinkEle + highlightCopyEle}
` if (isPrismjs) $figureHighlight.wrap('
').before(ele) else $figureHighlight.prepend(ele) } /** * 代碼收縮 */ if (isHighlightShrink !== undefined) { $('.highlight-tools >.expand').on('click', function () { const $this = $(this) const $table = $this.parent().nextAll() $this.toggleClass('closed') $table.is(':visible') ? $table.css('display', 'none') : $table.css('display', 'block') }) } /** * 代碼copy */ if (isHighlightCopy) { const copy = function (text, ctx) { if (document.queryCommandSupported && document.queryCommandSupported('copy')) { document.execCommand('copy') if (GLOBAL_CONFIG.Snackbar !== undefined) { snackbarShow(GLOBAL_CONFIG.copy.success) } else { $(ctx).prev('.copy-notice') .text(GLOBAL_CONFIG.copy.success) .animate({ opacity: 1 }, 450, function () { setTimeout(function () { $(ctx).prev('.copy-notice').animate({ opacity: 0 }, 650) }, 400) }) } } else { if (GLOBAL_CONFIG.Snackbar !== undefined) { snackbarShow(GLOBAL_CONFIG.copy.noSupport) } else { $(ctx).prev('.copy-notice').text(GLOBAL_CONFIG.copy.noSupport) } } } // click events $('.highlight-tools >.copy-button').on('click', function () { const $buttonParent = $(this).parents('figure.highlight') $buttonParent.addClass('copy-true') const selection = window.getSelection() const range = document.createRange() if (isPrismjs) range.selectNodeContents($buttonParent.find('> pre code')[0]) else range.selectNodeContents($buttonParent.find('table .code pre')[0]) selection.removeAllRanges() selection.addRange(range) const text = selection.toString() copy(text, this) selection.removeAllRanges() $buttonParent.removeClass('copy-true') }) } } } /** * PhotoFigcaption */ function addPhotoFigcaption () { const images = $('#article-container img').not('.justified-gallery img') images.each(function (i, o) { const $this = $(o) if ($this.attr('alt')) { const t = $('
' + $this.attr('alt') + '
') $this.after(t) } }) } /** * justified-gallery 圖庫排版 */ let detectJgJsLoad = false const runJustifiedGallery = function () { const $justifiedGallery = $('.justified-gallery') if ($justifiedGallery.length) { const $imgList = $justifiedGallery.find('img') $imgList.unwrap() if ($imgList.length) { $imgList.each(function (i, o) { if ($(o).attr('data-lazy-src')) $(o).attr('src', $(o).attr('data-lazy-src')) $(o).wrap('
') }) } if (detectJgJsLoad) initJustifiedGallery($justifiedGallery) else { $('head').append(``) $.getScript(`${GLOBAL_CONFIG.justifiedGallery.js}`, function () { initJustifiedGallery($justifiedGallery) }) detectJgJsLoad = true } } } /** * fancybox和 mediumZoom */ const addLightBox = function () { const isMediumZoom = GLOBAL_CONFIG.medium_zoom const isFancybox = GLOBAL_CONFIG.fancybox if (isFancybox) { const images = $('#article-container img:not(.gallery-group-img)').not($('a>img')) images.each(function (i, o) { const lazyloadSrc = $(o).attr('data-lazy-src') ? $(o).attr('data-lazy-src') : $(o).attr('src') const dataCaption = $(o).attr('alt') ? $(o).attr('alt') : '' $(o).wrap(``) }) $().fancybox({ selector: '[data-fancybox]', loop: true, transitionEffect: 'slide', protect: true, buttons: ['slideShow', 'fullScreen', 'thumbs', 'close'], hash: false }) } else if (isMediumZoom) { const zoom = mediumZoom(document.querySelectorAll('#article-container :not(a)>img')) zoom.on('open', function (event) { const photoBg = $(document.documentElement).attr('data-theme') === 'dark' ? '#121212' : '#fff' zoom.update({ background: photoBg }) }) } } /** * 滾動處理 */ const scrollFn = function () { let initTop = 0 let isChatShow = true const $rightside = $('#rightside') const $nav = $('#nav') const isChatBtnHide = typeof chatBtnHide === 'function' const isChatBtnShow = typeof chatBtnShow === 'function' $(window).scroll(throttle(function (event) { const currentTop = $(this).scrollTop() const isDown = scrollDirection(currentTop) if (currentTop > 56) { if (isDown) { if ($nav.hasClass('visible')) $nav.removeClass('visible') if (isChatBtnShow && isChatShow === true) { chatBtnHide() isChatShow = false } } else { if (!$nav.hasClass('visible')) $nav.addClass('visible') if (isChatBtnHide && isChatShow === false) { window.chatBtnShow() isChatShow = true } } $nav.addClass('fixed') if ($rightside.css('opacity') === '0') { $rightside.css({ opacity: '1', transform: 'translateX(-38px)' }) } } else { if (currentTop === 0) { $nav.removeClass('fixed').removeClass('visible') } $rightside.css({ opacity: '', transform: '' }) } }, 200)) // find the scroll direction function scrollDirection (currentTop) { const result = currentTop > initTop // true is down & false is up initTop = currentTop return result } } /** * toc */ const tocFn = function () { $('.toc-child').hide() // main of scroll $(window).scroll(throttle(function (event) { const currentTop = $(this).scrollTop() scrollPercent(currentTop) findHeadPosition(currentTop) autoScrollToc(currentTop) }, 100)) // expand toc-item const expandToc = function ($item) { if ($item.is(':visible')) { return } $item.fadeIn(400) } const scrollPercent = function (currentTop) { const docHeight = $('#article-container').height() const winHeight = $(window).height() const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight) const scrollPercent = (currentTop) / (contentMath) const scrollPercentRounded = Math.round(scrollPercent * 100) const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded $('.progress-num').text(percentage) $('.sidebar-toc__progress-bar').animate({ width: percentage + '%' }, 100) } // anchor const isAnchor = GLOBAL_CONFIG.isanchor const updateAnchor = function (anchor) { if (window.history.replaceState && anchor !== window.location.hash) { window.history.replaceState(undefined, undefined, anchor) } } // find head position & add active class // DOM Hierarchy: // ol.toc > (li.toc-item, ...) // li.toc-item > (a.toc-link, ol.toc-2child > (li.toc-item, ...)) const versionBiggerFive = GLOBAL_CONFIG.hexoversion.split('.')[0] >= 5 const findHeadPosition = function (top) { // assume that we are not in the post page if no TOC link be found, // thus no need to update the status if ($('.toc-link').length === 0) { return false } const list = $('#article-container').find('h1,h2,h3,h4,h5,h6') let currentId = '' list.each(function () { const head = $(this) if (top > head.offset().top - 70) { if (versionBiggerFive) currentId = '#' + encodeURI($(this).attr('id')) else currentId = '#' + $(this).attr('id') } }) if (currentId === '') { $('.toc-link').removeClass('active') $('.toc-child').hide() } const currentActive = $('.toc-link.active') if (currentId && currentActive.attr('href') !== currentId) { if (isAnchor) updateAnchor(currentId) $('.toc-link').removeClass('active') const _this = $('.toc-link[href="' + currentId + '"]') _this.addClass('active') const parents = _this.parents('.toc-child') // Returned list is in reverse order of the DOM elements // Thus `parents.last()` is the outermost .toc-child container // i.e. list of subsections const topLink = (parents.length > 0) ? parents.last() : _this expandToc(topLink.closest('.toc-item').find('.toc-child')) topLink // Find all top-level .toc-item containers, i.e. sections // excluding the currently active one .closest('.toc-item').siblings('.toc-item') // Hide their respective list of subsections .find('.toc-child').hide() } } const autoScrollToc = function (currentTop) { if ($('.toc-link').hasClass('active')) { const activePosition = $('.active').offset().top const sidebarScrollTop = $('#sidebar .sidebar-toc__content').scrollTop() if (activePosition > (currentTop + $(window).height() - 100)) { $('#sidebar .sidebar-toc__content').scrollTop(sidebarScrollTop + 100) } if (activePosition < currentTop + 100) { $('#sidebar .sidebar-toc__content').scrollTop(sidebarScrollTop - 100) } } } } /** * Rightside */ const $rightsideEle = $('#rightside') // read-mode $rightsideEle.on('click', '#readmode', function () { $('body').toggleClass('read-mode') }) // Switch Between Light And Dark Mode if ($('#darkmode').length) { const switchReadMode = function () { const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' if (nowMode === 'light') { activateDarkMode() saveToLocal.set('theme', 'dark', 2) GLOBAL_CONFIG.Snackbar !== undefined && snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) } else { activateLightMode() saveToLocal.set('theme', 'light', 2) GLOBAL_CONFIG.Snackbar !== undefined && snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) } } $rightsideEle.on('click', '#darkmode', () => { switchReadMode() typeof utterancesTheme === 'function' && utterancesTheme() typeof FB === 'object' && window.loadFBComment() window.DISQUS && $('#disqus_thread').children().length && setTimeout(() => window.disqusReset(), 200) }) } // rightside 點擊設置 按鈕 展開 $rightsideEle.on('click', '#rightside_config', () => $('#rightside-config-hide').toggleClass('show')) // Back to top $rightsideEle.on('click', '#go-up', () => scrollToDest('body')) /** * menu * 側邊欄sub-menu 展開/收縮 * 解決menus在觸摸屏下,滑動屏幕menus_item_child不消失的問題(手機hover的bug) */ const clickFnOfSubMenu = function () { $('#mobile-sidebar-menus .expand').on('click', function () { $(this).parents('.menus_item').find('> .menus_item_child').slideToggle() $(this).toggleClass('hide') }) $(window).on('touchmove', function (e) { const $menusChild = $('#nav .menus_item_child') if ($menusChild.is(':visible')) { $menusChild.css('display', 'none') } }) } /** * 複製時加上版權信息 */ const addCopyright = () => { const copyright = GLOBAL_CONFIG.copyright document.body.oncopy = (e) => { e.preventDefault() let textFont; const copyFont = window.getSelection(0).toString() if (copyFont.length > copyright.limitCount) { textFont = copyFont + '\n' + '\n' + '\n' + copyright.languages.author + '\n' + copyright.languages.link + window.location.href + '\n' + copyright.languages.source + '\n' + copyright.languages.info } else { textFont = copyFont } if (e.clipboardData) { return e.clipboardData.setData('text', textFont) } else { return window.clipboardData.setData('text', textFont) } } } /** * 網頁運行時間 */ const addRuntime = () => { const $runtimeCount = $('#webinfo-runtime-count') if ($runtimeCount.length) { const publishDate = $runtimeCount.attr('publish_date') $runtimeCount.text(diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime) } } /** * 最後一次更新時間 */ const addLastPushDate = () => { const $lastPushDateItem = $('.webinfo-last-push-date') if ($lastPushDateItem.length) { const lastPushDate = $lastPushDateItem.attr('last-push-date') const diffDay = diffDate(lastPushDate) if (diffDay > 365) { $lastPushDateItem.text(lastPushDate) } else { $lastPushDateItem.text(diffDay + ' ' + GLOBAL_CONFIG.last_push_date) } } } /** * table overflow */ const addTableWrap = function () { const $table = $('#article-container table').not($('figure.highlight > table')) $table.each(function () { $(this).wrap('
') }) } /** * 百度推送 */ const pushToBaidu = () => { const bp = document.createElement('script') const curProtocol = window.location.protocol.split(':')[0] if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js' } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js' } bp.dataset.pjax = '' const s = document.getElementsByTagName('script')[0] s.parentNode.insertBefore(bp, s) } /** * tag-hide */ const clickFnOfTagHide = function () { const $hideInline = $('.hide-button') if ($hideInline.length) { $hideInline.on('click', function (e) { const $this = $(this) const $hideContent = $(this).next('.hide-content') $this.toggleClass('open') $hideContent.toggle() if ($this.hasClass('open')) { if ($hideContent.find('.justified-gallery').length > 0) { initJustifiedGallery($hideContent.find('.justified-gallery')) } } }) } } const tabsFn = { clickFnOfTabs: function () { const $tab = $('#article-container .tabs') $tab.find('.tab > button:not(.tab-to-top)').on('click', function (e) { const $this = $(this) const $tabItem = $this.parent() if (!$tabItem.hasClass('active')) { const $tabContent = $this.parents('.nav-tabs').next() $tabItem.siblings('.active').removeClass('active') $tabItem.addClass('active') const tabId = $this.attr('data-href') $tabContent.find('> .tab-item-content').removeClass('active') $tabContent.find(`> ${tabId}`).addClass('active') const $isTabJustifiedGallery = $tabContent.find(tabId).find('.justified-gallery') if ($isTabJustifiedGallery.length > 0) { initJustifiedGallery($isTabJustifiedGallery) } } }) }, backToTop: () => { const backToTopBtn = $('#article-container .tabs .tab-to-top') backToTopBtn.on('click', function () { scrollToDest($(this).parents('.tabs')) }) } } const toggleCardCategory = function () { const $cardCategory = $('.card-category-list-item.parent i') $cardCategory.on('click', function (e) { e.preventDefault() const $this = $(this) $this.toggleClass('expand') $this.parents('.parent').next().toggle() }) } const switchComments = function () { let switchDone = false $('#switch-comments-btn').on('click', function () { $('#post-comment > .comment-wrap > div').each(function () { if ($(this).is(':visible')) { $(this).hide() } else { $(this).css({ display: 'block', animation: 'tabshow .5s' }) } }) if (!switchDone && typeof loadOtherComment === 'function') { switchDone = true loadOtherComment() } }) } const addPostOutdateNotice = function () { const data = GLOBAL_CONFIG.noticeOutdate var diffDay = diffDate(GLOBAL_CONFIG_SITE.postUpdate) if (diffDay >= data.limitDay) { const code = `
${data.messagePrev + ' ' + diffDay + ' ' + data.messageNext}
` if (data.position === 'top') { $('#article-container').prepend(code) } else { $('#article-container').append(code) } } } /** * lazyload */ if (GLOBAL_CONFIG.islazyload) { window.lazyLoadOptions = { elements_selector: 'img', threshold: 0, data_src: 'lazy-src' } window.addEventListener( 'LazyLoad::Initialized', function (event) { window.lazyLoadInstance = event.detail.instance }, false ) } const unRefreshFn = function () { $(window).on('resize', function () { if (window.innerWidth < 768) adjustMenu(0) else if ($('#sidebar').hasClass('tocOpenPc') && $('#nav').hasClass('fixed')) adjustMenu(1) else adjustMenu(2) }) clickFnOfSubMenu() GLOBAL_CONFIG.copyright !== undefined && addCopyright() GLOBAL_CONFIG.baiduPush && pushToBaidu() } const refreshFn = function () { initAdjust() if (GLOBAL_CONFIG_SITE.isPost) { OpenSidebarAuto() toggleSidebar() GLOBAL_CONFIG_SITE.isSidebar && tocFn() GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice() } sidebarFn() GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() GLOBAL_CONFIG.highlight && addHighlightTool() GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() runJustifiedGallery() addLightBox() scrollFn() GLOBAL_CONFIG.runtime && addRuntime() GLOBAL_CONFIG.last_push_date && addLastPushDate() addTableWrap() clickFnOfTagHide() tabsFn.clickFnOfTabs() tabsFn.backToTop() toggleCardCategory() switchComments() } $(function () { refreshFn() unRefreshFn() })