cansin-blogdata 3.0.91 → 3.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/.github/workflows/autopublish.yml +18 -18
  2. package/README.md +9 -9
  3. package/css/APlayer.min.css +2 -2
  4. package/css/gavin.min.css +1 -1
  5. package/css/index.css +8716 -8463
  6. package/img/AI/346/202/246/345/210/233.svg +21 -21
  7. package/img/CAN-CIN-0-200.svg +29 -29
  8. package/img/CAN-CIN-f-200.svg +29 -29
  9. package/img/CANCIN-0-200.svg +29 -29
  10. package/img/CANCIN-f-200.svg +29 -29
  11. package/img/H501SE.webp +0 -0
  12. package/img/MX_Keys.webp +0 -0
  13. package/img/MX_Master2S.webp +0 -0
  14. package/img/Mate40Pro.webp +0 -0
  15. package/img/StarfishS5.webp +0 -0
  16. package/img/ThinkBook14.webp +0 -0
  17. package/img/ZHITAITiPlus7100.webp +0 -0
  18. package/img/star_blank.svg +1 -0
  19. package/img/star_fill.svg +1 -0
  20. package/js/APlayer.min.js +1 -1
  21. package/js/Meting2.min.js +109 -109
  22. package/js/gavin.min.js +1 -1
  23. package/js/main.js +785 -785
  24. package/js/tw_cn.js +124 -124
  25. package/js/utils.js +278 -278
  26. package/js/winbox.bundle.min.js +34 -34
  27. package/lrc/Blueming.lrc +45 -45
  28. package/lrc//344/270/200/346/240/274/346/240/274.lrc +68 -68
  29. package/lrc//344/270/216/345/246/206.lrc +49 -49
  30. package/lrc//344/270/224/347/254/221/347/272/242/345/260/230.lrc +34 -34
  31. package/lrc//344/272/272/351/227/264/345/237/216.lrc +45 -45
  32. package/lrc//344/272/272/351/227/264/350/234/211/350/235/243.lrc +31 -31
  33. package/lrc//344/275/234/346/233/262/345/256/266.lrc +78 -78
  34. package/lrc//345/200/237.lrc +44 -44
  35. package/lrc//345/200/276/345/260/275/345/244/251/344/270/213.lrc +61 -61
  36. package/lrc//345/203/217/346/210/221/350/277/231/346/240/267/347/232/204/344/272/272.lrc +67 -67
  37. package/lrc//345/203/217/351/261/274.lrc +34 -34
  38. package/lrc//345/205/270/347/213/261/345/217/270.lrc +70 -70
  39. package/lrc//345/207/272/345/261/261.lrc +50 -50
  40. package/lrc//345/214/227/345/237/216/344/273/245/345/214/227/345/215/227/345/237/216/344/273/245/345/215/227.lrc +53 -53
  41. package/lrc//345/215/203/345/215/203/344/270/207/344/270/207.lrc +62 -62
  42. package/lrc//345/215/227/345/261/261/345/215/227.lrc +47 -47
  43. package/lrc//345/215/227/346/226/271/345/247/221/345/250/230.lrc +26 -26
  44. package/lrc//345/216/213/350/275/264/346/210/217.lrc +48 -48
  45. package/lrc//345/217/252/350/246/201/345/271/263/345/207/241.lrc +56 -56
  46. package/lrc//345/220/214/346/270/241.lrc +79 -79
  47. package/lrc//345/226/234/345/211/247/344/271/213/347/216/213.lrc +45 -45
  48. package/lrc//345/233/215.lrc +79 -79
  49. package/lrc//345/233/275/347/216/213/344/270/216/344/271/236/344/270/220.lrc +82 -82
  50. package/lrc//345/234/250/344/275/240/347/232/204/350/272/253/350/276/271.lrc +73 -73
  51. package/lrc//345/260/217/351/227/256/351/242/230.lrc +49 -49
  52. package/lrc//345/261/261/346/234/211/346/234/250/345/205/256.lrc +53 -53
  53. package/lrc//345/262/201/346/234/210/347/245/236/345/201/267.lrc +55 -55
  54. package/lrc//345/275/222/345/216/273/346/235/245/345/205/256.lrc +43 -43
  55. package/lrc//346/201/213/346/201/213/346/225/205/344/272/272/351/232/276.lrc +89 -89
  56. package/lrc//346/202/254/346/272/272.lrc +37 -37
  57. package/lrc//346/210/221/344/273/254/347/232/204/346/227/266/345/205/211.lrc +22 -22
  58. package/lrc//346/210/221/350/256/260/345/276/227.lrc +89 -89
  59. package/lrc//346/212/212/345/233/236/345/277/206/346/213/274/345/245/275/347/273/231/344/275/240.lrc +125 -125
  60. package/lrc//346/227/240/350/250/200.lrc +39 -39
  61. package/lrc//346/227/240/351/227/256.lrc +40 -40
  62. package/lrc//346/230/237/346/262/263/344/270/207/351/207/214.lrc +40 -40
  63. package/lrc//346/235/200/346/255/273/351/202/243/344/270/252/347/237/263/345/256/266/345/272/204/344/272/272.lrc +22 -22
  64. package/lrc//346/235/245/346/227/245/346/226/271/351/225/277.lrc +38 -38
  65. package/lrc//346/265/252/345/255/220/345/233/236/345/244/264.lrc +45 -45
  66. package/lrc//346/266/210/346/204/201.lrc +65 -65
  67. package/lrc//347/210/270/347/210/270/345/246/210/345/246/210.lrc +79 -79
  68. package/lrc//347/211/265/344/270/235/346/210/217.lrc +39 -39
  69. package/lrc//347/220/264/345/270/210.lrc +51 -51
  70. package/lrc//347/224/237/346/255/273/346/261/237/346/271/226.lrc +58 -58
  71. package/lrc//347/224/237/350/200/214/344/270/272/344/272/272.lrc +57 -57
  72. package/lrc//347/227/205/345/217/230.lrc +64 -64
  73. package/lrc//347/233/227/345/260/206/350/241/214.lrc +47 -47
  74. package/lrc//347/237/245/346/210/221.lrc +56 -56
  75. package/lrc//350/207/264/344/275/240.lrc +94 -94
  76. package/lrc//350/221/243/345/260/217/345/247/220.lrc +38 -38
  77. package/lrc//350/231/236/345/205/256/345/217/271.lrc +33 -33
  78. package/lrc//350/264/253/351/201/223.lrc +68 -68
  79. package/lrc//350/270/217/345/261/261/346/262/263.lrc +42 -42
  80. package/lrc//350/277/231/345/260/261/346/230/257/347/210/261.lrc +48 -48
  81. package/lrc//351/202/243/345/271/264/345/271/264/345/260/221.lrc +55 -55
  82. package/lrc//351/270/263/351/270/257/345/200/272.lrc +36 -36
  83. package/package.json +23 -23
package/js/main.js CHANGED
@@ -1,785 +1,785 @@
1
- document.addEventListener('DOMContentLoaded', function () {
2
- let blogNameWidth, menusWidth, searchWidth, $nav
3
- let mobileSidebarOpen = false
4
-
5
- const adjustMenu = (init) => {
6
- if (init) {
7
- blogNameWidth = document.getElementById('site-name').offsetWidth
8
- const $menusEle = document.querySelectorAll('#menus .menus_item')
9
- menusWidth = 0
10
- $menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth })
11
- const $searchEle = document.querySelector('#search-button')
12
- searchWidth = $searchEle ? $searchEle.offsetWidth : 0
13
- $nav = document.getElementById('nav')
14
- }
15
-
16
- let hideMenuIndex = ''
17
- if (window.innerWidth <= 768) hideMenuIndex = true
18
- else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120
19
-
20
- if (hideMenuIndex) {
21
- $nav.classList.add('hide-menu')
22
- } else {
23
- $nav.classList.remove('hide-menu')
24
- }
25
- }
26
-
27
- // 初始化header
28
- const initAdjust = () => {
29
- adjustMenu(true)
30
- $nav.classList.add('show')
31
- }
32
-
33
- // sidebar menus
34
- const sidebarFn = {
35
- open: () => {
36
- btf.sidebarPaddingR()
37
- document.body.style.overflow = 'hidden'
38
- btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')
39
- document.getElementById('sidebar-menus').classList.add('open')
40
- mobileSidebarOpen = true
41
- },
42
- close: () => {
43
- const $body = document.body
44
- $body.style.overflow = ''
45
- $body.style.paddingRight = ''
46
- btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')
47
- document.getElementById('sidebar-menus').classList.remove('open')
48
- mobileSidebarOpen = false
49
- }
50
- }
51
-
52
- /**
53
- * 首頁top_img底下的箭頭
54
- */
55
- const scrollDownInIndex = () => {
56
- const $scrollDownEle = document.getElementById('scroll-down')
57
- $scrollDownEle && $scrollDownEle.addEventListener('click', function () {
58
- if (window.innerWidth < 768) btf.scrollToDest(document.getElementById('content-inner').offsetTop - 60, 300)
59
- else btf.scrollToDest(document.getElementById('content-inner').offsetTop - 40, 300)
60
- })
61
- }
62
-
63
- /**
64
- * 代碼
65
- * 只適用於Hexo默認的代碼渲染
66
- */
67
- const addHighlightTool = function () {
68
- const highLight = GLOBAL_CONFIG.highlight
69
- if (!highLight) return
70
-
71
- const isHighlightCopy = highLight.highlightCopy
72
- const isHighlightLang = highLight.highlightLang
73
- const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink
74
- const highlightHeightLimit = highLight.highlightHeightLimit
75
- const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined
76
- const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
77
-
78
- if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return
79
-
80
- const isPrismjs = highLight.plugin === 'prismjs'
81
-
82
- let highlightShrinkEle = ''
83
- let highlightCopyEle = ''
84
- const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''
85
-
86
- if (isHighlightShrink !== undefined) {
87
- highlightShrinkEle = `<i class="fas fa-angle-down expand ${highlightShrinkClass}"></i>`
88
- }
89
-
90
- if (isHighlightCopy) {
91
- highlightCopyEle = '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>'
92
- }
93
-
94
- const copy = (text, ctx) => {
95
- if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
96
- document.execCommand('copy')
97
- if (GLOBAL_CONFIG.Snackbar !== undefined) {
98
- btf.snackbarShow(GLOBAL_CONFIG.copy.success)
99
- } else {
100
- const prevEle = ctx.previousElementSibling
101
- prevEle.innerText = GLOBAL_CONFIG.copy.success
102
- prevEle.style.opacity = 1
103
- setTimeout(() => { prevEle.style.opacity = 0 }, 700)
104
- }
105
- if(set_notice.checked) tools.showMessage("复制成功!转载请注明来源!","success",2)
106
- } else {
107
- if (GLOBAL_CONFIG.Snackbar !== undefined) {
108
- btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport)
109
- } else {
110
- ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport
111
- }
112
- if(set_notice.checked) tools.showMessage("Error!复制失败!","error",2)
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
- ele.forEach(item => {
236
- const $imgList = item.querySelectorAll('img')
237
-
238
- $imgList.forEach(i => {
239
- const dataLazySrc = i.getAttribute('data-lazy-src')
240
- if (dataLazySrc) i.src = dataLazySrc
241
- btf.wrap(i, 'div', { class: 'fj-gallery-item' })
242
- })
243
- })
244
-
245
- if (window.fjGallery) {
246
- setTimeout(() => { btf.initJustifiedGallery(ele) }, 100)
247
- return
248
- }
249
-
250
- const newEle = document.createElement('link')
251
- newEle.rel = 'stylesheet'
252
- newEle.href = GLOBAL_CONFIG.source.justifiedGallery.css
253
- document.body.appendChild(newEle)
254
- getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) })
255
- }
256
-
257
- /**
258
- * 滾動處理
259
- */
260
- const scrollFn = function () {
261
- const $rightside = document.getElementById('rightside')
262
- const innerHeight = window.innerHeight + 56
263
- const scrollHeight = document.body.scrollHeight + 400
264
- // console.log("document.body.scrollHeight: " + scrollHeight)
265
- // console.log("window.innerHeight: " + (innerHeight - 56))
266
- // 當滾動條小于 56 的時候
267
- if (scrollHeight <= innerHeight) {
268
- $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
269
- return
270
- }
271
-
272
- // find the scroll direction
273
- function scrollDirection (currentTop) {
274
- const result = currentTop > initTop // true is down & false is up
275
- initTop = currentTop
276
- return result
277
- }
278
-
279
- let initTop = 0
280
- let isChatShow = true
281
- const $header = document.getElementById('page-header')
282
- const isChatBtnHide = typeof chatBtnHide === 'function'
283
- const isChatBtnShow = typeof chatBtnShow === 'function'
284
-
285
- const scrollTask = btf.throttle(() => {
286
- const currentTop = window.scrollY || document.documentElement.scrollTop
287
- const isDown = scrollDirection(currentTop)
288
- if (currentTop > 56) {
289
- $header.classList.add('is-top-bar')
290
- if (isDown) {
291
- if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
292
- if (isChatBtnShow && isChatShow === true) {
293
- chatBtnHide()
294
- isChatShow = false
295
- }
296
- } else {
297
- if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
298
- if (isChatBtnHide && isChatShow === false) {
299
- chatBtnShow()
300
- isChatShow = true
301
- }
302
- }
303
- $header.classList.add('nav-fixed')
304
- if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
305
- $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
306
- }
307
- } else {
308
- if (currentTop === 0) {
309
- // $header.classList.remove('nav-fixed', 'nav-visible')
310
- $header.classList.remove('is-top-bar')
311
- $header.classList.add('nav-visible')
312
- }
313
- $rightside.style.cssText = "opacity: ''; transform: ''"
314
- }
315
-
316
- if (scrollHeight <= innerHeight) {
317
- $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
318
- }
319
- }, 200)
320
-
321
- window.scrollCollect = scrollTask
322
- window.addEventListener('scroll', scrollCollect)
323
- }
324
-
325
- /**
326
- * toc,anchor
327
- */
328
- const scrollFnToDo = function () {
329
- const isToc = GLOBAL_CONFIG_SITE.isToc
330
- const isAnchor = GLOBAL_CONFIG.isAnchor
331
- const $article = document.getElementById('article-container')
332
-
333
- if (!($article && (isToc || isAnchor))) return
334
-
335
- let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand
336
-
337
- if (isToc) {
338
- const $cardTocLayout = document.getElementById('card-toc')
339
- $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0]
340
- $tocLink = $cardToc.querySelectorAll('.toc-link')
341
- const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
342
- isExpand = $cardToc.classList.contains('is-expand')
343
-
344
- scrollPercent = currentTop => {
345
- const docHeight = $article.clientHeight
346
- const winHeight = document.documentElement.clientHeight
347
- const headerHeight = $article.offsetTop
348
- const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight)
349
- const scrollPercent = (currentTop - headerHeight) / (contentMath)
350
- const scrollPercentRounded = Math.round(scrollPercent * 100)
351
- const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded
352
- $tocPercentage.textContent = percentage
353
- }
354
-
355
- window.mobileToc = {
356
- open: () => {
357
- $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px'
358
- },
359
-
360
- close: () => {
361
- $cardTocLayout.style.animation = 'toc-close .2s'
362
- setTimeout(() => {
363
- $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''"
364
- }, 100)
365
- }
366
- }
367
-
368
- // toc元素點擊
369
- $cardToc.addEventListener('click', e => {
370
- e.preventDefault()
371
- const target = e.target.classList
372
- if (target.contains('toc-content')) return
373
- const $target = target.contains('toc-link')
374
- ? e.target
375
- : e.target.parentElement
376
- btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300)
377
- if (window.innerWidth < 900) {
378
- window.mobileToc.close()
379
- }
380
- })
381
-
382
- autoScrollToc = item => {
383
- const activePosition = item.getBoundingClientRect().top
384
- const sidebarScrollTop = $cardToc.scrollTop
385
- if (activePosition > (document.documentElement.clientHeight - 100)) {
386
- $cardToc.scrollTop = sidebarScrollTop + 150
387
- }
388
- if (activePosition < 100) {
389
- $cardToc.scrollTop = sidebarScrollTop - 150
390
- }
391
- }
392
- }
393
-
394
- // find head position & add active class
395
- const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
396
- let detectItem = ''
397
- const findHeadPosition = function (top) {
398
- if (top === 0) {
399
- return false
400
- }
401
-
402
- let currentId = ''
403
- let currentIndex = ''
404
-
405
- list.forEach(function (ele, index) {
406
- if (top > btf.getEleTop(ele) - 80) {
407
- const id = ele.id
408
- currentId = id ? '#' + encodeURI(id) : ''
409
- currentIndex = index
410
- }
411
- })
412
-
413
- if (detectItem === currentIndex) return
414
-
415
- if (isAnchor) btf.updateAnchor(currentId)
416
-
417
- detectItem = currentIndex
418
-
419
- if (isToc) {
420
- $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') })
421
-
422
- if (currentId === '') {
423
- return
424
- }
425
-
426
- const currentActive = $tocLink[currentIndex]
427
- currentActive.classList.add('active')
428
-
429
- setTimeout(() => {
430
- autoScrollToc(currentActive)
431
- }, 0)
432
-
433
- if (isExpand) return
434
- let parent = currentActive.parentNode
435
-
436
- for (; !parent.matches('.toc'); parent = parent.parentNode) {
437
- if (parent.matches('li')) parent.classList.add('active')
438
- }
439
- }
440
- }
441
-
442
- // main of scroll
443
- window.tocScrollFn = function () {
444
- return btf.throttle(function () {
445
- const currentTop = window.scrollY || document.documentElement.scrollTop
446
- isToc && scrollPercent(currentTop)
447
- findHeadPosition(currentTop)
448
- }, 100)()
449
- }
450
- window.addEventListener('scroll', tocScrollFn)
451
- }
452
-
453
- /**
454
- * Rightside
455
- */
456
- const rightSideFn = {
457
- switchReadMode: () => { // read-mode
458
- const $body = document.body
459
- $body.classList.add('read-mode')
460
- const newEle = document.createElement('button')
461
- newEle.type = 'button'
462
- newEle.className = 'fas fa-sign-out-alt exit-readmode'
463
- $body.appendChild(newEle)
464
-
465
- function clickFn () {
466
- $body.classList.remove('read-mode')
467
- newEle.remove()
468
- newEle.removeEventListener('click', clickFn)
469
- }
470
-
471
- newEle.addEventListener('click', clickFn)
472
- },
473
- switchDarkMode: () => { // Switch Between Light And Dark Mode
474
- const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
475
- if (nowMode === 'light') {
476
- activateDarkMode()
477
- saveToLocal.set('theme', 'dark', 2)
478
- GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
479
- } else {
480
- activateLightMode()
481
- saveToLocal.set('theme', 'light', 2)
482
- GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
483
- }
484
- // handle some cases
485
- typeof utterancesTheme === 'function' && utterancesTheme()
486
- typeof changeGiscusTheme === 'function' && changeGiscusTheme()
487
- typeof FB === 'object' && window.loadFBComment && window.loadFBComment()
488
- typeof runMermaid === 'function' && window.runMermaid()
489
- },
490
- showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開
491
- const rightsideHideClassList = document.getElementById('rightside-config-hide').classList
492
- rightsideHideClassList.toggle('show')
493
- if (e.classList.contains('show')) {
494
- rightsideHideClassList.add('status')
495
- setTimeout(() => {
496
- rightsideHideClassList.remove('status')
497
- }, 300)
498
- }
499
- e.classList.toggle('show')
500
- },
501
- scrollToTop: () => { // Back to top
502
- btf.scrollToDest(0, 500)
503
- },
504
- hideAsideBtn: () => { // Hide aside
505
- const $htmlDom = document.documentElement.classList
506
- $htmlDom.contains('hide-aside')
507
- ? saveToLocal.set('aside-status', 'show', 2)
508
- : saveToLocal.set('aside-status', 'hide', 2)
509
- $htmlDom.toggle('hide-aside')
510
- },
511
-
512
- runMobileToc: () => {
513
- if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open()
514
- else window.mobileToc.close()
515
- }
516
- }
517
-
518
- document.getElementById('rightside').addEventListener('click', function (e) {
519
- const $target = e.target.id ? e.target : e.target.parentNode
520
- switch ($target.id) {
521
- case 'go-up':
522
- rightSideFn.scrollToTop()
523
- break
524
- case 'rightside_config':
525
- rightSideFn.showOrHideBtn($target)
526
- break
527
- case 'mobile-toc-button':
528
- rightSideFn.runMobileToc()
529
- break
530
- case 'readmode':
531
- rightSideFn.switchReadMode()
532
- break
533
- case 'darkmode':
534
- rightSideFn.switchDarkMode()
535
- break
536
- case 'hide-aside-btn':
537
- rightSideFn.hideAsideBtn()
538
- break
539
- default:
540
- break
541
- }
542
- })
543
-
544
- /**
545
- * menu
546
- * 側邊欄sub-menu 展開/收縮
547
- */
548
- const clickFnOfSubMenu = () => {
549
- document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) {
550
- item.addEventListener('click', function () {
551
- this.classList.toggle('hide')
552
- })
553
- })
554
- }
555
-
556
- /**
557
- * 複製時加上版權信息
558
- */
559
- const addCopyright = () => {
560
- const copyright = GLOBAL_CONFIG.copyright
561
- document.body.oncopy = (e) => {
562
- e.preventDefault()
563
- let textFont; const copyFont = window.getSelection(0).toString()
564
- if (copyFont.length > copyright.limitCount) {
565
- textFont = copyFont + '\n' + '\n' + '\n' +
566
- copyright.languages.author + '\n' +
567
- copyright.languages.link + window.location.href + '\n' +
568
- copyright.languages.source + '\n' +
569
- copyright.languages.info
570
- } else {
571
- textFont = copyFont
572
- }
573
- if (e.clipboardData) {
574
- return e.clipboardData.setData('text', textFont)
575
- } else {
576
- return window.clipboardData.setData('text', textFont)
577
- }
578
- }
579
- }
580
-
581
- /**
582
- * 網頁運行時間
583
- */
584
- const addRuntime = () => {
585
- const $runtimeCount = document.getElementById('runtimeshow')
586
- if ($runtimeCount) {
587
- const publishDate = $runtimeCount.getAttribute('data-publishDate')
588
- $runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime
589
- }
590
- }
591
-
592
- /**
593
- * 最後一次更新時間
594
- */
595
- const addLastPushDate = () => {
596
- const $lastPushDateItem = document.getElementById('last-push-date')
597
- if ($lastPushDateItem) {
598
- const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate')
599
- $lastPushDateItem.innerText = btf.diffDate(lastPushDate, true)
600
- }
601
- }
602
-
603
- /**
604
- * table overflow
605
- */
606
- const addTableWrap = () => {
607
- const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table')
608
- if ($table.length) {
609
- $table.forEach(item => {
610
- btf.wrap(item, 'div', { class: 'table-wrap' })
611
- })
612
- }
613
- }
614
-
615
- /**
616
- * tag-hide
617
- */
618
- const clickFnOfTagHide = function () {
619
- const $hideInline = document.querySelectorAll('#article-container .hide-button')
620
- if ($hideInline.length) {
621
- $hideInline.forEach(function (item) {
622
- item.addEventListener('click', function (e) {
623
- const $this = this
624
- $this.classList.add('open')
625
- const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery')
626
- $fjGallery.length && btf.initJustifiedGallery($fjGallery)
627
- })
628
- })
629
- }
630
- }
631
-
632
- const tabsFn = {
633
- clickFnOfTabs: function () {
634
- document.querySelectorAll('#article-container .tab > button').forEach(function (item) {
635
- item.addEventListener('click', function (e) {
636
- const $this = this
637
- const $tabItem = $this.parentNode
638
-
639
- if (!$tabItem.classList.contains('active')) {
640
- const $tabContent = $tabItem.parentNode.nextElementSibling
641
- const $siblings = btf.siblings($tabItem, '.active')[0]
642
- $siblings && $siblings.classList.remove('active')
643
- $tabItem.classList.add('active')
644
- const tabId = $this.getAttribute('data-href').replace('#', '')
645
- const childList = [...$tabContent.children]
646
- childList.forEach(item => {
647
- if (item.id === tabId) item.classList.add('active')
648
- else item.classList.remove('active')
649
- })
650
- const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`)
651
- if ($isTabJustifiedGallery.length > 0) {
652
- btf.initJustifiedGallery($isTabJustifiedGallery)
653
- }
654
- }
655
- })
656
- })
657
- },
658
- backToTop: () => {
659
- document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) {
660
- item.addEventListener('click', function () {
661
- btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300)
662
- })
663
- })
664
- }
665
- }
666
-
667
- const toggleCardCategory = function () {
668
- const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i')
669
- if ($cardCategory.length) {
670
- $cardCategory.forEach(function (item) {
671
- item.addEventListener('click', function (e) {
672
- e.preventDefault()
673
- const $this = this
674
- $this.classList.toggle('expand')
675
- const $parentEle = $this.parentNode.nextElementSibling
676
- if (btf.isHidden($parentEle)) {
677
- $parentEle.style.display = 'block'
678
- } else {
679
- $parentEle.style.display = 'none'
680
- }
681
- })
682
- })
683
- }
684
- }
685
-
686
- const switchComments = function () {
687
- let switchDone = false
688
- const $switchBtn = document.querySelector('#comment-switch > .switch-btn')
689
- $switchBtn && $switchBtn.addEventListener('click', function () {
690
- this.classList.toggle('move')
691
- document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) {
692
- if (btf.isHidden(item)) {
693
- item.style.cssText = 'display: block;animation: tabshow .5s'
694
- } else {
695
- item.style.cssText = "display: none;animation: ''"
696
- }
697
- })
698
-
699
- if (!switchDone && typeof loadOtherComment === 'function') {
700
- switchDone = true
701
- loadOtherComment()
702
- }
703
- })
704
- }
705
-
706
- const addPostOutdateNotice = function () {
707
- const data = GLOBAL_CONFIG.noticeOutdate
708
- const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate)
709
- if (diffDay >= data.limitDay) {
710
- const ele = document.createElement('div')
711
- ele.className = 'post-outdate-notice'
712
- ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext
713
- const $targetEle = document.getElementById('article-container')
714
- if (data.position === 'top') {
715
- $targetEle.insertBefore(ele, $targetEle.firstChild)
716
- } else {
717
- $targetEle.appendChild(ele)
718
- }
719
- }
720
- }
721
-
722
- const lazyloadImg = () => {
723
- window.lazyLoadInstance = new LazyLoad({
724
- elements_selector: 'img',
725
- threshold: 0,
726
- data_src: 'lazy-src'
727
- })
728
- }
729
-
730
- const relativeDate = function (selector) {
731
- selector.forEach(item => {
732
- const $this = item
733
- const timeVal = $this.getAttribute('datetime')
734
- $this.innerText = btf.diffDate(timeVal, true)
735
- $this.style.display = 'inline'
736
- })
737
- }
738
-
739
- const unRefreshFn = function () {
740
- window.addEventListener('resize', () => {
741
- adjustMenu(false)
742
- btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close()
743
- })
744
-
745
- document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() })
746
-
747
- clickFnOfSubMenu()
748
- GLOBAL_CONFIG.islazyload && lazyloadImg()
749
- GLOBAL_CONFIG.copyright !== undefined && addCopyright()
750
- }
751
-
752
- window.refreshFn = function () {
753
- initAdjust()
754
-
755
- if (GLOBAL_CONFIG_SITE.isPost) {
756
- GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice()
757
- GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time'))
758
- } else {
759
- GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time'))
760
- GLOBAL_CONFIG.runtime && addRuntime()
761
- addLastPushDate()
762
- toggleCardCategory()
763
- }
764
-
765
- scrollFnToDo()
766
- GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex()
767
- addHighlightTool()
768
- GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
769
- scrollFn()
770
-
771
- const $jgEle = document.querySelectorAll('#article-container .fj-gallery')
772
- $jgEle.length && runJustifiedGallery($jgEle)
773
-
774
- runLightbox()
775
- addTableWrap()
776
- clickFnOfTagHide()
777
- tabsFn.clickFnOfTabs()
778
- tabsFn.backToTop()
779
- switchComments()
780
- document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() })
781
- }
782
-
783
- refreshFn()
784
- unRefreshFn()
785
- })
1
+ document.addEventListener('DOMContentLoaded', function () {
2
+ let blogNameWidth, menusWidth, searchWidth, $nav
3
+ let mobileSidebarOpen = false
4
+
5
+ const adjustMenu = (init) => {
6
+ if (init) {
7
+ blogNameWidth = document.getElementById('site-name').offsetWidth
8
+ const $menusEle = document.querySelectorAll('#menus .menus_item')
9
+ menusWidth = 0
10
+ $menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth })
11
+ const $searchEle = document.querySelector('#search-button')
12
+ searchWidth = $searchEle ? $searchEle.offsetWidth : 0
13
+ $nav = document.getElementById('nav')
14
+ }
15
+
16
+ let hideMenuIndex = ''
17
+ if (window.innerWidth <= 768) hideMenuIndex = true
18
+ else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120
19
+
20
+ if (hideMenuIndex) {
21
+ $nav.classList.add('hide-menu')
22
+ } else {
23
+ $nav.classList.remove('hide-menu')
24
+ }
25
+ }
26
+
27
+ // 初始化header
28
+ const initAdjust = () => {
29
+ adjustMenu(true)
30
+ $nav.classList.add('show')
31
+ }
32
+
33
+ // sidebar menus
34
+ const sidebarFn = {
35
+ open: () => {
36
+ btf.sidebarPaddingR()
37
+ document.body.style.overflow = 'hidden'
38
+ btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s')
39
+ document.getElementById('sidebar-menus').classList.add('open')
40
+ mobileSidebarOpen = true
41
+ },
42
+ close: () => {
43
+ const $body = document.body
44
+ $body.style.overflow = ''
45
+ $body.style.paddingRight = ''
46
+ btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s')
47
+ document.getElementById('sidebar-menus').classList.remove('open')
48
+ mobileSidebarOpen = false
49
+ }
50
+ }
51
+
52
+ /**
53
+ * 首頁top_img底下的箭頭
54
+ */
55
+ const scrollDownInIndex = () => {
56
+ const $scrollDownEle = document.getElementById('scroll-down')
57
+ $scrollDownEle && $scrollDownEle.addEventListener('click', function () {
58
+ if (window.innerWidth < 768) btf.scrollToDest(document.getElementById('content-inner').offsetTop - 60, 300)
59
+ else btf.scrollToDest(document.getElementById('content-inner').offsetTop - 40, 300)
60
+ })
61
+ }
62
+
63
+ /**
64
+ * 代碼
65
+ * 只適用於Hexo默認的代碼渲染
66
+ */
67
+ const addHighlightTool = function () {
68
+ const highLight = GLOBAL_CONFIG.highlight
69
+ if (!highLight) return
70
+
71
+ const isHighlightCopy = highLight.highlightCopy
72
+ const isHighlightLang = highLight.highlightLang
73
+ const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink
74
+ const highlightHeightLimit = highLight.highlightHeightLimit
75
+ const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined
76
+ const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
77
+
78
+ if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return
79
+
80
+ const isPrismjs = highLight.plugin === 'prismjs'
81
+
82
+ let highlightShrinkEle = ''
83
+ let highlightCopyEle = ''
84
+ const highlightShrinkClass = isHighlightShrink === true ? 'closed' : ''
85
+
86
+ if (isHighlightShrink !== undefined) {
87
+ highlightShrinkEle = `<i class="fas fa-angle-down expand ${highlightShrinkClass}"></i>`
88
+ }
89
+
90
+ if (isHighlightCopy) {
91
+ highlightCopyEle = '<div class="copy-notice"></div><i class="fas fa-paste copy-button"></i>'
92
+ }
93
+
94
+ const copy = (text, ctx) => {
95
+ if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
96
+ document.execCommand('copy')
97
+ if (GLOBAL_CONFIG.Snackbar !== undefined) {
98
+ btf.snackbarShow(GLOBAL_CONFIG.copy.success)
99
+ } else {
100
+ const prevEle = ctx.previousElementSibling
101
+ prevEle.innerText = GLOBAL_CONFIG.copy.success
102
+ prevEle.style.opacity = 1
103
+ setTimeout(() => { prevEle.style.opacity = 0 }, 700)
104
+ }
105
+ if(set_notice.checked) tools.showMessage("复制成功!转载请注明来源!","success",2)
106
+ } else {
107
+ if (GLOBAL_CONFIG.Snackbar !== undefined) {
108
+ btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport)
109
+ } else {
110
+ ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport
111
+ }
112
+ if(set_notice.checked) tools.showMessage("Error!复制失败!","error",2)
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
+ ele.forEach(item => {
236
+ const $imgList = item.querySelectorAll('img')
237
+
238
+ $imgList.forEach(i => {
239
+ const dataLazySrc = i.getAttribute('data-lazy-src')
240
+ if (dataLazySrc) i.src = dataLazySrc
241
+ btf.wrap(i, 'div', { class: 'fj-gallery-item' })
242
+ })
243
+ })
244
+
245
+ if (window.fjGallery) {
246
+ setTimeout(() => { btf.initJustifiedGallery(ele) }, 100)
247
+ return
248
+ }
249
+
250
+ const newEle = document.createElement('link')
251
+ newEle.rel = 'stylesheet'
252
+ newEle.href = GLOBAL_CONFIG.source.justifiedGallery.css
253
+ document.body.appendChild(newEle)
254
+ getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) })
255
+ }
256
+
257
+ /**
258
+ * 滾動處理
259
+ */
260
+ const scrollFn = function () {
261
+ const $rightside = document.getElementById('rightside')
262
+ const innerHeight = window.innerHeight + 56
263
+ const scrollHeight = document.body.scrollHeight + 400
264
+ // console.log("document.body.scrollHeight: " + scrollHeight)
265
+ // console.log("window.innerHeight: " + (innerHeight - 56))
266
+ // 當滾動條小于 56 的時候
267
+ if (scrollHeight <= innerHeight) {
268
+ $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
269
+ return
270
+ }
271
+
272
+ // find the scroll direction
273
+ function scrollDirection (currentTop) {
274
+ const result = currentTop > initTop // true is down & false is up
275
+ initTop = currentTop
276
+ return result
277
+ }
278
+
279
+ let initTop = 0
280
+ let isChatShow = true
281
+ const $header = document.getElementById('page-header')
282
+ const isChatBtnHide = typeof chatBtnHide === 'function'
283
+ const isChatBtnShow = typeof chatBtnShow === 'function'
284
+
285
+ const scrollTask = btf.throttle(() => {
286
+ const currentTop = window.scrollY || document.documentElement.scrollTop
287
+ const isDown = scrollDirection(currentTop)
288
+ if (currentTop > 56) {
289
+ $header.classList.add('is-top-bar')
290
+ if (isDown) {
291
+ if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
292
+ if (isChatBtnShow && isChatShow === true) {
293
+ chatBtnHide()
294
+ isChatShow = false
295
+ }
296
+ } else {
297
+ if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
298
+ if (isChatBtnHide && isChatShow === false) {
299
+ chatBtnShow()
300
+ isChatShow = true
301
+ }
302
+ }
303
+ $header.classList.add('nav-fixed')
304
+ if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
305
+ $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
306
+ }
307
+ } else {
308
+ if (currentTop === 0) {
309
+ // $header.classList.remove('nav-fixed', 'nav-visible')
310
+ $header.classList.remove('is-top-bar')
311
+ $header.classList.add('nav-visible')
312
+ }
313
+ $rightside.style.cssText = "opacity: ''; transform: ''"
314
+ }
315
+
316
+ if (scrollHeight <= innerHeight) {
317
+ $rightside.style.cssText = 'opacity: 1; transform: translateX(-88px)'
318
+ }
319
+ }, 200)
320
+
321
+ window.scrollCollect = scrollTask
322
+ window.addEventListener('scroll', scrollCollect)
323
+ }
324
+
325
+ /**
326
+ * toc,anchor
327
+ */
328
+ const scrollFnToDo = function () {
329
+ const isToc = GLOBAL_CONFIG_SITE.isToc
330
+ const isAnchor = GLOBAL_CONFIG.isAnchor
331
+ const $article = document.getElementById('article-container')
332
+
333
+ if (!($article && (isToc || isAnchor))) return
334
+
335
+ let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand
336
+
337
+ if (isToc) {
338
+ const $cardTocLayout = document.getElementById('card-toc')
339
+ $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0]
340
+ $tocLink = $cardToc.querySelectorAll('.toc-link')
341
+ const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
342
+ isExpand = $cardToc.classList.contains('is-expand')
343
+
344
+ scrollPercent = currentTop => {
345
+ const docHeight = $article.clientHeight
346
+ const winHeight = document.documentElement.clientHeight
347
+ const headerHeight = $article.offsetTop
348
+ const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight)
349
+ const scrollPercent = (currentTop - headerHeight) / (contentMath)
350
+ const scrollPercentRounded = Math.round(scrollPercent * 100)
351
+ const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded
352
+ $tocPercentage.textContent = percentage
353
+ }
354
+
355
+ window.mobileToc = {
356
+ open: () => {
357
+ $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px'
358
+ },
359
+
360
+ close: () => {
361
+ $cardTocLayout.style.animation = 'toc-close .2s'
362
+ setTimeout(() => {
363
+ $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''"
364
+ }, 100)
365
+ }
366
+ }
367
+
368
+ // toc元素點擊
369
+ $cardToc.addEventListener('click', e => {
370
+ e.preventDefault()
371
+ const target = e.target.classList
372
+ if (target.contains('toc-content')) return
373
+ const $target = target.contains('toc-link')
374
+ ? e.target
375
+ : e.target.parentElement
376
+ btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300)
377
+ if (window.innerWidth < 900) {
378
+ window.mobileToc.close()
379
+ }
380
+ })
381
+
382
+ autoScrollToc = item => {
383
+ const activePosition = item.getBoundingClientRect().top
384
+ const sidebarScrollTop = $cardToc.scrollTop
385
+ if (activePosition > (document.documentElement.clientHeight - 100)) {
386
+ $cardToc.scrollTop = sidebarScrollTop + 150
387
+ }
388
+ if (activePosition < 100) {
389
+ $cardToc.scrollTop = sidebarScrollTop - 150
390
+ }
391
+ }
392
+ }
393
+
394
+ // find head position & add active class
395
+ const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
396
+ let detectItem = ''
397
+ const findHeadPosition = function (top) {
398
+ if (top === 0) {
399
+ return false
400
+ }
401
+
402
+ let currentId = ''
403
+ let currentIndex = ''
404
+
405
+ list.forEach(function (ele, index) {
406
+ if (top > btf.getEleTop(ele) - 80) {
407
+ const id = ele.id
408
+ currentId = id ? '#' + encodeURI(id) : ''
409
+ currentIndex = index
410
+ }
411
+ })
412
+
413
+ if (detectItem === currentIndex) return
414
+
415
+ if (isAnchor) btf.updateAnchor(currentId)
416
+
417
+ detectItem = currentIndex
418
+
419
+ if (isToc) {
420
+ $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') })
421
+
422
+ if (currentId === '') {
423
+ return
424
+ }
425
+
426
+ const currentActive = $tocLink[currentIndex]
427
+ currentActive.classList.add('active')
428
+
429
+ setTimeout(() => {
430
+ autoScrollToc(currentActive)
431
+ }, 0)
432
+
433
+ if (isExpand) return
434
+ let parent = currentActive.parentNode
435
+
436
+ for (; !parent.matches('.toc'); parent = parent.parentNode) {
437
+ if (parent.matches('li')) parent.classList.add('active')
438
+ }
439
+ }
440
+ }
441
+
442
+ // main of scroll
443
+ window.tocScrollFn = function () {
444
+ return btf.throttle(function () {
445
+ const currentTop = window.scrollY || document.documentElement.scrollTop
446
+ isToc && scrollPercent(currentTop)
447
+ findHeadPosition(currentTop)
448
+ }, 100)()
449
+ }
450
+ window.addEventListener('scroll', tocScrollFn)
451
+ }
452
+
453
+ /**
454
+ * Rightside
455
+ */
456
+ const rightSideFn = {
457
+ switchReadMode: () => { // read-mode
458
+ const $body = document.body
459
+ $body.classList.add('read-mode')
460
+ const newEle = document.createElement('button')
461
+ newEle.type = 'button'
462
+ newEle.className = 'fas fa-sign-out-alt exit-readmode'
463
+ $body.appendChild(newEle)
464
+
465
+ function clickFn () {
466
+ $body.classList.remove('read-mode')
467
+ newEle.remove()
468
+ newEle.removeEventListener('click', clickFn)
469
+ }
470
+
471
+ newEle.addEventListener('click', clickFn)
472
+ },
473
+ switchDarkMode: () => { // Switch Between Light And Dark Mode
474
+ const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
475
+ if (nowMode === 'light') {
476
+ activateDarkMode()
477
+ saveToLocal.set('theme', 'dark', 2)
478
+ GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
479
+ } else {
480
+ activateLightMode()
481
+ saveToLocal.set('theme', 'light', 2)
482
+ GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day)
483
+ }
484
+ // handle some cases
485
+ typeof utterancesTheme === 'function' && utterancesTheme()
486
+ typeof changeGiscusTheme === 'function' && changeGiscusTheme()
487
+ typeof FB === 'object' && window.loadFBComment && window.loadFBComment()
488
+ typeof runMermaid === 'function' && window.runMermaid()
489
+ },
490
+ showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開
491
+ const rightsideHideClassList = document.getElementById('rightside-config-hide').classList
492
+ rightsideHideClassList.toggle('show')
493
+ if (e.classList.contains('show')) {
494
+ rightsideHideClassList.add('status')
495
+ setTimeout(() => {
496
+ rightsideHideClassList.remove('status')
497
+ }, 300)
498
+ }
499
+ e.classList.toggle('show')
500
+ },
501
+ scrollToTop: () => { // Back to top
502
+ btf.scrollToDest(0, 500)
503
+ },
504
+ hideAsideBtn: () => { // Hide aside
505
+ const $htmlDom = document.documentElement.classList
506
+ $htmlDom.contains('hide-aside')
507
+ ? saveToLocal.set('aside-status', 'show', 2)
508
+ : saveToLocal.set('aside-status', 'hide', 2)
509
+ $htmlDom.toggle('hide-aside')
510
+ },
511
+
512
+ runMobileToc: () => {
513
+ if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open()
514
+ else window.mobileToc.close()
515
+ }
516
+ }
517
+
518
+ document.getElementById('rightside').addEventListener('click', function (e) {
519
+ const $target = e.target.id ? e.target : e.target.parentNode
520
+ switch ($target.id) {
521
+ case 'go-up':
522
+ rightSideFn.scrollToTop()
523
+ break
524
+ case 'rightside_config':
525
+ rightSideFn.showOrHideBtn($target)
526
+ break
527
+ case 'mobile-toc-button':
528
+ rightSideFn.runMobileToc()
529
+ break
530
+ case 'readmode':
531
+ rightSideFn.switchReadMode()
532
+ break
533
+ case 'darkmode':
534
+ rightSideFn.switchDarkMode()
535
+ break
536
+ case 'hide-aside-btn':
537
+ rightSideFn.hideAsideBtn()
538
+ break
539
+ default:
540
+ break
541
+ }
542
+ })
543
+
544
+ /**
545
+ * menu
546
+ * 側邊欄sub-menu 展開/收縮
547
+ */
548
+ const clickFnOfSubMenu = () => {
549
+ document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) {
550
+ item.addEventListener('click', function () {
551
+ this.classList.toggle('hide')
552
+ })
553
+ })
554
+ }
555
+
556
+ /**
557
+ * 複製時加上版權信息
558
+ */
559
+ const addCopyright = () => {
560
+ const copyright = GLOBAL_CONFIG.copyright
561
+ document.body.oncopy = (e) => {
562
+ e.preventDefault()
563
+ let textFont; const copyFont = window.getSelection(0).toString()
564
+ if (copyFont.length > copyright.limitCount) {
565
+ textFont = copyFont + '\n' + '\n' + '\n' +
566
+ copyright.languages.author + '\n' +
567
+ copyright.languages.link + window.location.href + '\n' +
568
+ copyright.languages.source + '\n' +
569
+ copyright.languages.info
570
+ } else {
571
+ textFont = copyFont
572
+ }
573
+ if (e.clipboardData) {
574
+ return e.clipboardData.setData('text', textFont)
575
+ } else {
576
+ return window.clipboardData.setData('text', textFont)
577
+ }
578
+ }
579
+ }
580
+
581
+ /**
582
+ * 網頁運行時間
583
+ */
584
+ const addRuntime = () => {
585
+ const $runtimeCount = document.getElementById('runtimeshow')
586
+ if ($runtimeCount) {
587
+ const publishDate = $runtimeCount.getAttribute('data-publishDate')
588
+ $runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime
589
+ }
590
+ }
591
+
592
+ /**
593
+ * 最後一次更新時間
594
+ */
595
+ const addLastPushDate = () => {
596
+ const $lastPushDateItem = document.getElementById('last-push-date')
597
+ if ($lastPushDateItem) {
598
+ const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate')
599
+ $lastPushDateItem.innerText = btf.diffDate(lastPushDate, true)
600
+ }
601
+ }
602
+
603
+ /**
604
+ * table overflow
605
+ */
606
+ const addTableWrap = () => {
607
+ const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table')
608
+ if ($table.length) {
609
+ $table.forEach(item => {
610
+ btf.wrap(item, 'div', { class: 'table-wrap' })
611
+ })
612
+ }
613
+ }
614
+
615
+ /**
616
+ * tag-hide
617
+ */
618
+ const clickFnOfTagHide = function () {
619
+ const $hideInline = document.querySelectorAll('#article-container .hide-button')
620
+ if ($hideInline.length) {
621
+ $hideInline.forEach(function (item) {
622
+ item.addEventListener('click', function (e) {
623
+ const $this = this
624
+ $this.classList.add('open')
625
+ const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery')
626
+ $fjGallery.length && btf.initJustifiedGallery($fjGallery)
627
+ })
628
+ })
629
+ }
630
+ }
631
+
632
+ const tabsFn = {
633
+ clickFnOfTabs: function () {
634
+ document.querySelectorAll('#article-container .tab > button').forEach(function (item) {
635
+ item.addEventListener('click', function (e) {
636
+ const $this = this
637
+ const $tabItem = $this.parentNode
638
+
639
+ if (!$tabItem.classList.contains('active')) {
640
+ const $tabContent = $tabItem.parentNode.nextElementSibling
641
+ const $siblings = btf.siblings($tabItem, '.active')[0]
642
+ $siblings && $siblings.classList.remove('active')
643
+ $tabItem.classList.add('active')
644
+ const tabId = $this.getAttribute('data-href').replace('#', '')
645
+ const childList = [...$tabContent.children]
646
+ childList.forEach(item => {
647
+ if (item.id === tabId) item.classList.add('active')
648
+ else item.classList.remove('active')
649
+ })
650
+ const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`)
651
+ if ($isTabJustifiedGallery.length > 0) {
652
+ btf.initJustifiedGallery($isTabJustifiedGallery)
653
+ }
654
+ }
655
+ })
656
+ })
657
+ },
658
+ backToTop: () => {
659
+ document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) {
660
+ item.addEventListener('click', function () {
661
+ btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300)
662
+ })
663
+ })
664
+ }
665
+ }
666
+
667
+ const toggleCardCategory = function () {
668
+ const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i')
669
+ if ($cardCategory.length) {
670
+ $cardCategory.forEach(function (item) {
671
+ item.addEventListener('click', function (e) {
672
+ e.preventDefault()
673
+ const $this = this
674
+ $this.classList.toggle('expand')
675
+ const $parentEle = $this.parentNode.nextElementSibling
676
+ if (btf.isHidden($parentEle)) {
677
+ $parentEle.style.display = 'block'
678
+ } else {
679
+ $parentEle.style.display = 'none'
680
+ }
681
+ })
682
+ })
683
+ }
684
+ }
685
+
686
+ const switchComments = function () {
687
+ let switchDone = false
688
+ const $switchBtn = document.querySelector('#comment-switch > .switch-btn')
689
+ $switchBtn && $switchBtn.addEventListener('click', function () {
690
+ this.classList.toggle('move')
691
+ document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) {
692
+ if (btf.isHidden(item)) {
693
+ item.style.cssText = 'display: block;animation: tabshow .5s'
694
+ } else {
695
+ item.style.cssText = "display: none;animation: ''"
696
+ }
697
+ })
698
+
699
+ if (!switchDone && typeof loadOtherComment === 'function') {
700
+ switchDone = true
701
+ loadOtherComment()
702
+ }
703
+ })
704
+ }
705
+
706
+ const addPostOutdateNotice = function () {
707
+ const data = GLOBAL_CONFIG.noticeOutdate
708
+ const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate)
709
+ if (diffDay >= data.limitDay) {
710
+ const ele = document.createElement('div')
711
+ ele.className = 'post-outdate-notice'
712
+ ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext
713
+ const $targetEle = document.getElementById('article-container')
714
+ if (data.position === 'top') {
715
+ $targetEle.insertBefore(ele, $targetEle.firstChild)
716
+ } else {
717
+ $targetEle.appendChild(ele)
718
+ }
719
+ }
720
+ }
721
+
722
+ const lazyloadImg = () => {
723
+ window.lazyLoadInstance = new LazyLoad({
724
+ elements_selector: 'img',
725
+ threshold: 0,
726
+ data_src: 'lazy-src'
727
+ })
728
+ }
729
+
730
+ const relativeDate = function (selector) {
731
+ selector.forEach(item => {
732
+ const $this = item
733
+ const timeVal = $this.getAttribute('datetime')
734
+ $this.innerText = btf.diffDate(timeVal, true)
735
+ $this.style.display = 'inline'
736
+ })
737
+ }
738
+
739
+ const unRefreshFn = function () {
740
+ window.addEventListener('resize', () => {
741
+ adjustMenu(false)
742
+ btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close()
743
+ })
744
+
745
+ document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() })
746
+
747
+ clickFnOfSubMenu()
748
+ GLOBAL_CONFIG.islazyload && lazyloadImg()
749
+ GLOBAL_CONFIG.copyright !== undefined && addCopyright()
750
+ }
751
+
752
+ window.refreshFn = function () {
753
+ initAdjust()
754
+
755
+ if (GLOBAL_CONFIG_SITE.isPost) {
756
+ GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice()
757
+ GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time'))
758
+ } else {
759
+ GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time'))
760
+ GLOBAL_CONFIG.runtime && addRuntime()
761
+ addLastPushDate()
762
+ toggleCardCategory()
763
+ }
764
+
765
+ scrollFnToDo()
766
+ GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex()
767
+ addHighlightTool()
768
+ GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption()
769
+ scrollFn()
770
+
771
+ const $jgEle = document.querySelectorAll('#article-container .fj-gallery')
772
+ $jgEle.length && runJustifiedGallery($jgEle)
773
+
774
+ runLightbox()
775
+ addTableWrap()
776
+ clickFnOfTagHide()
777
+ tabsFn.clickFnOfTabs()
778
+ tabsFn.backToTop()
779
+ switchComments()
780
+ document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() })
781
+ }
782
+
783
+ refreshFn()
784
+ unRefreshFn()
785
+ })