diff options
author | Dillon <dillonzq@outlook.com> | 2020-04-18 15:54:54 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-18 15:54:54 +0300 |
commit | 8a0e61085cfc2f2d1a342697c73b10cbc1d27a68 (patch) | |
tree | 3bce7f15d61648a3b0dce6d43c938acfc74c1895 /src | |
parent | 9f37d7bc2a2580b19c211521b68194faecd3e736 (diff) |
feat(code): add copy button for code (#239)
Diffstat (limited to 'src')
-rw-r--r-- | src/js/theme.js | 86 |
1 files changed, 53 insertions, 33 deletions
diff --git a/src/js/theme.js b/src/js/theme.js index 4f17763..781fb45 100644 --- a/src/js/theme.js +++ b/src/js/theme.js @@ -1,9 +1,7 @@ class Util { forEach(elements, handler) { elements = elements || []; - for (let i = 0; i < elements.length; i++) { - handler(elements[i]); - } + for (let i = 0; i < elements.length; i++) handler(elements[i]); } getScrollTop() { @@ -17,6 +15,17 @@ class Util { isTocStatic() { return window.matchMedia('only screen and (max-width: 960px)').matches; } + + animateCSS(element, animation, reserved, callback) { + if (!Array.isArray(animation)) animation = [animation]; + element.classList.add('animated', ...animation); + const handler = () => { + element.classList.remove('animated', ...animation); + element.removeEventListener('animationend', handler); + if (typeof callback === 'function') callback(); + }; + if (!reserved) element.addEventListener('animationend', handler, false); + } } class Theme { @@ -268,10 +277,12 @@ class Theme { initHighlight() { this.util.forEach(document.querySelectorAll('.highlight > .chroma'), $chroma => { - const $codes = $chroma.querySelectorAll('pre.chroma > code'); - const $code = $codes[$codes.length - 1]; - const lang = $code ? $code.className.toLowerCase() : ''; - $chroma.className += ' ' + lang; + const $elements = $chroma.querySelectorAll('pre.chroma > code'); + if ($elements.length) { + $chroma.className += ' ' + $elements[$elements.length - 1].className.toLowerCase(); + $elements[0].classList.add('lnc'); + $elements[$elements.length - 1].classList.remove('lnc'); + } }); this.util.forEach(document.querySelectorAll('.highlight > pre.chroma'), $preChroma => { const $chroma = document.createElement('div'); @@ -287,6 +298,20 @@ class Theme { $preChroma.parentElement.replaceChild($chroma, $preChroma); $td.appendChild($preChroma); }); + this.util.forEach(document.querySelectorAll('pre > code'), $code => { + $code.classList.add('block'); + if ($code.classList.contains('lnc') || !this.config.clipboard) return; + const $button = document.createElement('div'); + $button.classList.add('copy-button'); + $button.innerHTML = '<i class="far fa-copy fa-fw"></i>'; + $button.setAttribute('data-clipboard-text', $code.innerText); + $button.title = this.config.clipboard.title; + const clipboard = new ClipboardJS($button); + clipboard.on('success', e => { + this.util.animateCSS($code, 'flash'); + }); + $code.after($button); + }); } initTable() { @@ -351,8 +376,8 @@ class Theme { $toc.style.top = `${TOP_SPACING}px`; } - this.util.forEach($tocLinkElements, link => { link.classList.remove('active'); }); - this.util.forEach($tocLiElements, link => { link.classList.remove('has-active'); }); + this.util.forEach($tocLinkElements, $tocLink => { $tocLink.classList.remove('active'); }); + this.util.forEach($tocLiElements, $tocLi => { $tocLi.classList.remove('has-active'); }); const INDEX_SPACING = 20 + (headerIsFixed ? headerHeight : 0); let activeTocIndex = $headerLinkElements.length - 1; for (let i = 0; i < $headerLinkElements.length - 1; i++) { @@ -386,10 +411,10 @@ class Theme { const $mermaidElements = document.getElementsByClassName('mermaid'); if ($mermaidElements.length) { mermaid.initialize({startOnLoad: false, theme: 'null'}); - this.util.forEach($mermaidElements, element => { - mermaid.mermaidAPI.render('svg-' + element.id, this.contentData[element.id], svgCode => { - element.innerHTML = svgCode; - }, element); + this.util.forEach($mermaidElements, $mermaid => { + mermaid.mermaidAPI.render('svg-' + $mermaid.id, this.contentData[$mermaid.id], svgCode => { + $mermaid.innerHTML = svgCode; + }, $mermaid); }); } } @@ -401,9 +426,9 @@ class Theme { this._echartsArr[i].dispose(); } this._echartsArr = []; - this.util.forEach(document.getElementsByClassName('echarts'), element => { - const chart = echarts.init(element, this.isDark ? 'dark' : 'macarons', {renderer: 'svg'}); - chart.setOption(JSON.parse(this.contentData[element.id])); + this.util.forEach(document.getElementsByClassName('echarts'), $echarts => { + const chart = echarts.init($echarts, this.isDark ? 'dark' : 'macarons', {renderer: 'svg'}); + chart.setOption(JSON.parse(this.contentData[$echarts.id])); this._echartsArr.push(chart); }); }); @@ -422,11 +447,10 @@ class Theme { mapboxgl.accessToken = this.config.mapbox.accessToken; mapboxgl.setRTLTextPlugin(this.config.mapbox.RTLTextPlugin); this._mapboxArr = this._mapboxArr || []; - this.util.forEach(document.getElementsByClassName('mapbox'), element => { - const { lng, lat, zoom, lightStyle, darkStyle, marked, navigation, geolocate, scale, fullscreen } = this.contentData[element.id]; - const options = this.contentData[element.id]; + this.util.forEach(document.getElementsByClassName('mapbox'), $mapbox => { + const { lng, lat, zoom, lightStyle, darkStyle, marked, navigation, geolocate, scale, fullscreen } = this.contentData[$mapbox.id]; const mapbox = new mapboxgl.Map({ - container: element, + container: $mapbox, center: [lng, lat], zoom: zoom, minZoom: .2, @@ -459,8 +483,8 @@ class Theme { }); this._mapboxOnSwitchTheme = this._mapboxOnSwitchTheme || (() => { this.util.forEach(this._mapboxArr, mapbox => { - const element = mapbox.getContainer(); - const { lightStyle, darkStyle } = this.contentData[element.id]; + const $mapbox = mapbox.getContainer(); + const { lightStyle, darkStyle } = this.contentData[$mapbox.id]; mapbox.setStyle(this.isDark ? darkStyle : lightStyle); mapbox.addControl(new MapboxLanguage()); }); @@ -516,10 +540,6 @@ class Theme { const $headers = []; if (this.config.desktopHeaderMode === 'auto') $headers.push(document.getElementById('header-desktop')); if (this.config.mobileHeaderMode === 'auto') $headers.push(document.getElementById('header-mobile')); - this.util.forEach($headers, $header => { - $header.classList.add('animated'); - $header.classList.add('faster'); - }); if (document.getElementById('comments')) { const $viewComments = document.getElementById('view-comments'); $viewComments.href = `#comments`; @@ -530,23 +550,23 @@ class Theme { window.addEventListener('scroll', () => { this.newScrollTop = this.util.getScrollTop(); const scroll = this.newScrollTop - this.oldScrollTop; - this.util.forEach($headers, header => { + this.util.forEach($headers, $header => { if (scroll > MIN_SCROLL) { - header.classList.remove('fadeInDown'); - header.classList.add('fadeOutUp'); + $header.classList.remove('fadeInDown'); + this.util.animateCSS($header, ['fadeOutUp', 'faster'], true); } else if (scroll < - MIN_SCROLL) { - header.classList.remove('fadeOutUp'); - header.classList.add('fadeInDown'); + $header.classList.remove('fadeOutUp'); + this.util.animateCSS($header, ['fadeInDown', 'faster'], true); } }); if (this.newScrollTop > MIN_SCROLL) { if (scroll > MIN_SCROLL) { $fixedButtons.classList.remove('fadeIn'); - $fixedButtons.classList.add('fadeOut'); + this.util.animateCSS($fixedButtons, ['fadeOut', 'faster'], true); } else if (scroll < - MIN_SCROLL) { $fixedButtons.style.display = 'block'; $fixedButtons.classList.remove('fadeOut'); - $fixedButtons.classList.add('fadeIn'); + this.util.animateCSS($fixedButtons, ['fadeIn', 'faster'], true); } } else { $fixedButtons.style.display = 'none'; |