1// utils 2const util = { 3 4 // https://github.com/jerryc127/hexo-theme-butterfly 5 diffDate: (d, more = false) => { 6 const dateNow = new Date() 7 const datePost = new Date(d) 8 const dateDiff = dateNow.getTime() - datePost.getTime() 9 const minute = 1000 * 60 10 const hour = minute * 60 11 const day = hour * 24 12 13 let result 14 if (more) { 15 const dayCount = dateDiff / day 16 const hourCount = dateDiff / hour 17 const minuteCount = dateDiff / minute 18 19 if (dayCount > 14) { 20 result = null 21 } else if (dayCount >= 1) { 22 result = parseInt(dayCount) + ' ' + ctx.date_suffix.day 23 } else if (hourCount >= 1) { 24 result = parseInt(hourCount) + ' ' + ctx.date_suffix.hour 25 } else if (minuteCount >= 1) { 26 result = parseInt(minuteCount) + ' ' + ctx.date_suffix.min 27 } else { 28 result = ctx.date_suffix.just 29 } 30 } else { 31 result = parseInt(dateDiff / day) 32 } 33 return result 34 }, 35 36 copy: (id, msg) => { 37 const el = document.getElementById(id); 38 if (el) { 39 el.select(); 40 document.execCommand("Copy"); 41 if (msg && msg.length > 0) { 42 hud.toast(msg, 2500); 43 } 44 } 45 }, 46 47 toggle: (id) => { 48 const el = document.getElementById(id); 49 if (el) { 50 el.classList.toggle("display"); 51 } 52 }, 53 54 scrollTop: () => { 55 window.scrollTo({top: 0, behavior: "smooth"}); 56 }, 57 58 scrollComment: () => { 59 document.getElementById('comments').scrollIntoView({behavior: "smooth"}); 60 }, 61 62 viewportLazyload: (target, func, enabled = true) => { 63 if (!enabled || !("IntersectionObserver" in window)) { 64 func(); 65 return; 66 } 67 const observer = new IntersectionObserver((entries) => { 68 if (entries[0].intersectionRatio > 0) { 69 func(); 70 observer.disconnect(); 71 } 72 }); 73 observer.observe(target); 74 } 75} 76 77const hud = { 78 toast: (msg, duration) => { 79 const d = Number(isNaN(duration) ? 2000 : duration); 80 var el = document.createElement('div'); 81 el.classList.add('toast'); 82 el.classList.add('show'); 83 el.innerHTML = msg; 84 document.body.appendChild(el); 85 86 setTimeout(function(){ document.body.removeChild(el) }, d); 87 88 }, 89 90} 91 92// defines 93 94const l_body = document.querySelector('.l_body'); 95 96 97const init = { 98 toc: () => { 99 utils.jq(() => { 100 const scrollOffset = 32; 101 var segs = []; 102 $("article.md-text :header").each(function (idx, node) { 103 segs.push(node); 104 }); 105 function activeTOC() { 106 var scrollTop = $(this).scrollTop(); 107 var topSeg = null; 108 for (var idx in segs) { 109 var seg = $(segs[idx]); 110 if (seg.offset().top > scrollTop + scrollOffset) { 111 continue; 112 } 113 if (!topSeg) { 114 topSeg = seg; 115 } else if (seg.offset().top >= topSeg.offset().top) { 116 topSeg = seg; 117 } 118 } 119 if (topSeg) { 120 $("#data-toc a.toc-link").removeClass("active"); 121 var link = "#" + topSeg.attr("id"); 122 if (link != '#undefined') { 123 const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]'); 124 if (highlightItem.length > 0) { 125 highlightItem.addClass("active"); 126 } 127 } else { 128 $('#data-toc a.toc-link:first').addClass("active"); 129 } 130 } 131 } 132 function scrollTOC() { 133 const e0 = document.querySelector('#data-toc .toc'); 134 const e1 = document.querySelector('#data-toc .toc a.toc-link.active'); 135 if (e0 == null || e1 == null) { 136 return; 137 } 138 const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100; 139 const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64; 140 if (offsetTop < 0) { 141 e0.scrollBy({top: offsetTop, behavior: "smooth"}); 142 } else if (offsetBottom > 0) { 143 e0.scrollBy({top: offsetBottom, behavior: "smooth"}); 144 } 145 } 146 147 var timeout = null; 148 window.addEventListener('scroll', function() { 149 activeTOC(); 150 if(timeout !== null) clearTimeout(timeout); 151 timeout = setTimeout(function() { 152 scrollTOC(); 153 }.bind(this), 50); 154 }); 155 }) 156 }, 157 sidebar: () => { 158 utils.jq(() => { 159 $("#data-toc a.toc-link").click(function (e) { 160 sidebar.dismiss(); 161 }); 162 }) 163 }, 164 relativeDate: (selector) => { 165 selector.forEach(item => { 166 const $this = item 167 const timeVal = $this.getAttribute('datetime') 168 let relativeValue = util.diffDate(timeVal, true) 169 if (relativeValue) { 170 $this.innerText = relativeValue 171 } 172 }) 173 }, 174 /** 175 * Tabs tag listener (without twitter bootstrap). 176 */ 177 registerTabsTag: function () {
178 // Binding `nav-tabs` & `tab-content` by real time permalink changing. 179 document.querySelectorAll('.tabs .nav-tabs .tab').forEach(element => { 180 element.addEventListener('click', event => { 181 event.preventDefault(); 182 // Prevent selected tab to select again. 183 if (element.classList.contains('active')) return; 184 // Add & Remove active class on `nav-tabs` & `tab-content`. 185 [...element.parentNode.children].forEach(target => { 186 target.classList.toggle('active', target === element); 187 }); 188 // https://stackoverflow.com/questions/20306204/using-queryselector-with-ids-that-are-numbers 189 const tActive = document.getElementById(element.querySelector('a').getAttribute('href').replace('#', '')); 190 [...tActive.parentNode.children].forEach(target => { 191 target.classList.toggle('active', target === tActive); 192 }); 193 // Trigger event 194 tActive.dispatchEvent(new Event('tabs:click', { 195 bubbles: true 196 })); 197 }); 198 }); 199 200 window.dispatchEvent(new Event('tabs:register')); 201 }, 202 203} 204 205 206// init 207init.toc() 208init.sidebar() 209init.relativeDate(document.querySelectorAll('#post-meta time')) 210init.registerTabsTag()
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.