diff options
Diffstat (limited to '')
-rw-r--r-- | themes/even/src/js/even.js | 246 | ||||
-rw-r--r-- | themes/even/src/js/main.js | 16 |
2 files changed, 262 insertions, 0 deletions
diff --git a/themes/even/src/js/even.js b/themes/even/src/js/even.js new file mode 100644 index 0000000..6b544a4 --- /dev/null +++ b/themes/even/src/js/even.js @@ -0,0 +1,246 @@ +'use strict' + +const Even = {} + +Even.backToTop = function () { + const $backToTop = $('#back-to-top') + + $(window).scroll(function () { + if ($(window).scrollTop() > 100) { + $backToTop.fadeIn(1000) + } else { + $backToTop.fadeOut(1000) + } + }) + + $backToTop.click(function () { + $('body,html').animate({ scrollTop: 0 }) + }) +} + +Even.mobileNavbar = function () { + const $mobileNav = $('#mobile-navbar') + const $mobileNavIcon = $('.mobile-navbar-icon') + const slideout = new Slideout({ + 'panel': document.getElementById('mobile-panel'), + 'menu': document.getElementById('mobile-menu'), + 'padding': 180, + 'tolerance': 70 + }) + slideout.disableTouch() + + $mobileNavIcon.click(function () { + slideout.toggle() + }) + + slideout.on('beforeopen', function () { + $mobileNav.addClass('fixed-open') + $mobileNavIcon.addClass('icon-click').removeClass('icon-out') + }) + + slideout.on('beforeclose', function () { + $mobileNav.removeClass('fixed-open') + $mobileNavIcon.addClass('icon-out').removeClass('icon-click') + }) + + $('#mobile-panel').on('touchend', function () { + slideout.isOpen() && $mobileNavIcon.click() + }) +} + +Even._initToc = function () { + const SPACING = 20 + const $toc = $('.post-toc') + const $footer = $('.post-footer') + + if ($toc.length) { + const minScrollTop = $toc.offset().top - SPACING + const maxScrollTop = $footer.offset().top - $toc.height() - SPACING + + const tocState = { + start: { + 'position': 'absolute', + 'top': minScrollTop + }, + process: { + 'position': 'fixed', + 'top': SPACING + }, + end: { + 'position': 'absolute', + 'top': maxScrollTop + } + } + + $(window).scroll(function () { + const scrollTop = $(window).scrollTop() + + if (scrollTop < minScrollTop) { + $toc.css(tocState.start) + } else if (scrollTop > maxScrollTop) { + $toc.css(tocState.end) + } else { + $toc.css(tocState.process) + } + }) + } + + const HEADERFIX = 30 + const $toclink = $('.toc-link') + const $headerlink = $('.headerlink') + const $tocLinkLis = $('.post-toc-content li') + + const headerlinkTop = $.map($headerlink, function (link) { + return $(link).offset().top + }) + + const headerLinksOffsetForSearch = $.map(headerlinkTop, function (offset) { + return offset - HEADERFIX + }) + + const searchActiveTocIndex = function (array, target) { + for (let i = 0; i < array.length - 1; i++) { + if (target > array[i] && target <= array[i + 1]) return i + } + if (target > array[array.length - 1]) return array.length - 1 + return -1 + } + + $(window).scroll(function () { + const scrollTop = $(window).scrollTop() + const activeTocIndex = searchActiveTocIndex(headerLinksOffsetForSearch, scrollTop) + + $($toclink).removeClass('active') + $($tocLinkLis).removeClass('has-active') + + if (activeTocIndex !== -1) { + $($toclink[activeTocIndex]).addClass('active') + let ancestor = $toclink[activeTocIndex].parentNode + while (ancestor.tagName !== 'NAV') { + $(ancestor).addClass('has-active') + ancestor = ancestor.parentNode.parentNode + } + } + }) +} + +Even.fancybox = function () { + if ($.fancybox) { + $('.post-content').each(function () { + $(this).find('img').each(function () { + $(this).wrap(`<a class="fancybox" href="${this.src}" data-fancybox="gallery" data-caption="${this.title}"></a>`) + }) + }) + + $('.fancybox').fancybox({ + selector: '.fancybox', + protect: true + }) + } +} + +Even.highlight = function () { + const blocks = document.querySelectorAll('pre code') + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i] + const rootElement = block.parentElement + const lineCodes = block.innerHTML.split(/\n/) + if (lineCodes[lineCodes.length - 1] === '') lineCodes.pop() + const lineLength = lineCodes.length + + let codeLineHtml = '' + for (let i = 0; i < lineLength; i++) { + codeLineHtml += `<div class="line">${i + 1}</div>` + } + + let codeHtml = '' + for (let i = 0; i < lineLength; i++) { + codeHtml += `<div class="line">${lineCodes[i]}</div>` + } + + block.className += ' highlight' + const figure = document.createElement('figure') + figure.className = block.className + figure.innerHTML = `<table><tbody><tr><td class="gutter"><pre>${codeLineHtml}</pre></td><td class="code"><pre>${codeHtml}</pre></td></tr></tbody></table>` + + rootElement.parentElement.replaceChild(figure, rootElement) + } +} + +Even.toc = function () { + const tocContainer = document.getElementById('post-toc') + if (tocContainer !== null) { + const toc = document.getElementById('TableOfContents') + if (toc === null) { + // toc = true, but there are no headings + tocContainer.parentNode.removeChild(tocContainer) + } else { + this._refactorToc(toc) + this._linkToc() + this._initToc() + } + } +} + +Even._refactorToc = function (toc) { + // when headings do not start with `h1` + const oldTocList = toc.children[0] + let newTocList = oldTocList + let temp + while (newTocList.children.length === 1 && (temp = newTocList.children[0].children[0]).tagName === 'UL') newTocList = temp + + if (newTocList !== oldTocList) toc.replaceChild(newTocList, oldTocList) +} + +Even._linkToc = function () { + const links = document.querySelectorAll('#TableOfContents a:first-child') + for (let i = 0; i < links.length; i++) links[i].className += ' toc-link' + + for (let num = 1; num <= 6; num++) { + const headers = document.querySelectorAll('.post-content>h' + num) + for (let i = 0; i < headers.length; i++) { + const header = headers[i] + header.innerHTML = `<a href="#${header.id}" class="headerlink"></a>${header.innerHTML}` + } + } +} + +Even.flowchart = function () { + if (!window.flowchart) return + + const blocks = document.querySelectorAll('pre code.language-flowchart') + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i] + const rootElement = block.parentElement + + const container = document.createElement('div') + const id = `js-flowchart-diagrams-${i}` + container.id = id + container.className = 'align-center' + rootElement.parentElement.replaceChild(container, rootElement) + + const diagram = flowchart.parse(block.childNodes[0].nodeValue) + diagram.drawSVG(id, window.flowchartDiagramsOptions ? window.flowchartDiagramsOptions : {}) + } +} + +Even.sequence = function () { + if (!window.Diagram) return + + const blocks = document.querySelectorAll('pre code.language-sequence') + for (let i = 0; i < blocks.length; i++) { + const block = blocks[i] + const rootElement = block.parentElement + + const container = document.createElement('div') + const id = `js-sequence-diagrams-${i}` + container.id = id + container.className = 'align-center' + rootElement.parentElement.replaceChild(container, rootElement) + + const diagram = Diagram.parse(block.childNodes[0].nodeValue) + diagram.drawSVG(id, window.sequenceDiagramsOptions ? window.sequenceDiagramsOptions : {theme: 'simple'}) + } +} + +export {Even} diff --git a/themes/even/src/js/main.js b/themes/even/src/js/main.js new file mode 100644 index 0000000..289b8dc --- /dev/null +++ b/themes/even/src/js/main.js @@ -0,0 +1,16 @@ +import {Even} from './even.js' + +import '../css/style.scss' + +$(document).ready(function () { + Even.backToTop() + Even.mobileNavbar() + Even.toc() + Even.fancybox() +}) + +Even.flowchart() +Even.sequence() + +hljs.initHighlighting() +Even.highlight() |