hexo-theme-solitude 2.1.6 → 2.1.8

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 (73) hide show
  1. package/CONTRIBUTING.md +1 -1
  2. package/LICENSE +1 -1
  3. package/README.md +1 -1
  4. package/README_en-US.md +1 -1
  5. package/README_zh-Hant.md +1 -1
  6. package/SECURITY.md +1 -1
  7. package/_config.yml +16 -20
  8. package/languages/default.yml +173 -173
  9. package/layout/archive.pug +3 -1
  10. package/layout/category.pug +3 -1
  11. package/layout/includes/inject/body.pug +1 -1
  12. package/layout/includes/page/default.pug +1 -1
  13. package/layout/includes/page/links.pug +1 -1
  14. package/layout/includes/page/tlink.pug +1 -1
  15. package/layout/includes/rightmenu.pug +6 -5
  16. package/layout/includes/widgets/page/about/hobbies.pug +18 -17
  17. package/layout/includes/widgets/page/about/tenyear.pug +24 -25
  18. package/layout/includes/widgets/page/links/linksCard.pug +5 -2
  19. package/layout/includes/widgets/page/message/content.pug +1 -1
  20. package/layout/includes/widgets/third-party/hot/artalk.pug +56 -0
  21. package/layout/includes/widgets/third-party/hot/twikoo.pug +57 -0
  22. package/layout/includes/widgets/third-party/pjax.pug +2 -1
  23. package/layout/index.pug +1 -1
  24. package/layout/post.pug +1 -1
  25. package/layout/tag.pug +2 -0
  26. package/package.json +1 -1
  27. package/plugins.yml +10 -10
  28. package/scripts/event/init.js +0 -1
  29. package/scripts/event/merge_config.js +14 -39
  30. package/scripts/event/welcome.js +11 -7
  31. package/scripts/filter/default.js +20 -21
  32. package/scripts/filter/lazyload.js +2 -4
  33. package/scripts/filter/randomPosts.js +14 -3
  34. package/scripts/helper/getArchiveLength.js +9 -11
  35. package/scripts/helper/related_post.js +56 -56
  36. package/scripts/tags/article.js +53 -15
  37. package/scripts/tags/tabs.js +37 -46
  38. package/source/css/_comments/comment.styl +4 -3
  39. package/source/css/_comments/twikoo.styl +6 -7
  40. package/source/css/_global/animation.styl +0 -15
  41. package/source/css/_global/index.styl +19 -19
  42. package/source/css/_highlight/highlight/diff.styl +13 -1
  43. package/source/css/_highlight/index.styl +2 -2
  44. package/source/css/_highlight/prismjs/diff.styl +13 -1
  45. package/source/css/_highlight/prismjs/index.styl +1 -1
  46. package/source/css/_highlight/prismjs/line-number.styl +1 -1
  47. package/source/css/_layout/article-container.styl +1 -1
  48. package/source/css/_layout/console.styl +1 -0
  49. package/source/css/_layout/recent-post.styl +2 -2
  50. package/source/css/_page/_about/about.styl +1 -1
  51. package/source/css/_page/_about/game.styl +2 -17
  52. package/source/css/_page/error.styl +2 -3
  53. package/source/css/_page/links.styl +2 -2
  54. package/source/css/_page/other.styl +1 -0
  55. package/source/css/_page/says.styl +4 -3
  56. package/source/css/_tags/gallery.styl +1 -1
  57. package/source/css/_tags/tabs.styl +2 -2
  58. package/source/img/error_load.avif +0 -0
  59. package/source/js/covercolor/api.js +29 -14
  60. package/source/js/covercolor/ave.js +38 -24
  61. package/source/js/covercolor/local.js +60 -52
  62. package/source/js/main.js +253 -248
  63. package/source/js/music.js +21 -39
  64. package/source/js/right_menu.js +64 -127
  65. package/source/js/third_party/barrage.min.js +93 -1
  66. package/source/js/third_party/envelope.min.js +1 -1
  67. package/source/js/third_party/post_ai.min.js +184 -1
  68. package/source/js/tw_cn.js +17 -16
  69. package/source/js/utils.js +50 -57
  70. package/layout/includes/widgets/home/hot/artalk.pug +0 -45
  71. package/layout/includes/widgets/home/hot/twikoo.pug +0 -46
  72. package/source/img/loading.avif +0 -0
  73. /package/layout/includes/widgets/{home → third-party}/hot/index.pug +0 -0
package/source/js/main.js CHANGED
@@ -7,15 +7,16 @@ const sidebarFn = () => {
7
7
  const toggleMobileSidebar = (isOpen) => {
8
8
  utils.sidebarPaddingR();
9
9
  $body.style.overflow = isOpen ? 'hidden' : '';
10
- $body.style.paddingRight = isOpen ? '' : '';
11
10
  utils[isOpen ? 'fadeIn' : 'fadeOut']($menuMask, 0.5);
12
- $mobileSidebarMenus.classList[isOpen ? 'add' : 'remove']('open');
13
- }
11
+ $mobileSidebarMenus.classList.toggle('open', isOpen);
12
+ };
13
+
14
14
  const closeMobileSidebar = () => {
15
15
  if ($mobileSidebarMenus.classList.contains('open')) {
16
16
  toggleMobileSidebar(false);
17
17
  }
18
- }
18
+ };
19
+
19
20
  $toggleMenu.addEventListener('click', () => toggleMobileSidebar(true));
20
21
  $menuMask.addEventListener('click', closeMobileSidebar);
21
22
 
@@ -25,72 +26,82 @@ const sidebarFn = () => {
25
26
  }
26
27
  sco.refreshWaterFall();
27
28
  });
28
- }
29
+ };
29
30
 
30
31
  const scrollFn = () => {
31
- let initTop = 0;
32
+ const $rightside = document.getElementById('rightside');
32
33
  const $header = document.getElementById('page-header');
33
- const $rightside = document.getElementById('rightside') || null;
34
- const throttledScroll = utils.throttle(() => {
35
- initThemeColor();
36
- const currentTop = window.scrollY || document.documentElement.scrollTop;
37
- const isDown = scrollDirection(currentTop);
34
+ let initTop = 0;
35
+
36
+ const updateHeaderAndRightside = (isDown, currentTop) => {
38
37
  if (currentTop > 0) {
39
- if (isDown) {
40
- if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible');
41
- } else {
42
- if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible');
43
- }
38
+ $header.classList.toggle('nav-visible', !isDown);
44
39
  $header.classList.add('nav-fixed');
45
- $rightside && ($rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px);');
40
+ if ($rightside) {
41
+ $rightside.style.opacity = '0.8';
42
+ $rightside.style.transform = 'translateX(-58px)';
43
+ }
46
44
  } else {
47
45
  $header.classList.remove('nav-fixed', 'nav-visible');
48
- $rightside && ($rightside.style.cssText = "opacity: ''; transform: ''");
46
+ if ($rightside) {
47
+ $rightside.style.opacity = '';
48
+ $rightside.style.transform = '';
49
+ }
49
50
  }
51
+ };
52
+
53
+ const throttledScroll = utils.throttle(() => {
54
+ initThemeColor();
55
+ const currentTop = window.scrollY || document.documentElement.scrollTop;
56
+ const isDown = currentTop > initTop;
57
+ initTop = currentTop;
58
+ updateHeaderAndRightside(isDown, currentTop);
50
59
  }, 200);
60
+
51
61
  window.addEventListener('scroll', (e) => {
52
62
  throttledScroll(e);
53
63
  if (window.scrollY === 0) {
54
- $header.classList.remove('nav-fixed', 'nav-visible');
55
- $rightside && ($rightside.style.cssText = "opacity: ''; transform: ''");
64
+ $header.classList.remove('nav-fixed', 'nav-visible');
65
+ if ($rightside) {
66
+ $rightside.style.cssText = "opacity: ''; transform: ''";
67
+ }
56
68
  }
57
69
  });
70
+ };
58
71
 
59
- function scrollDirection(currentTop) {
60
- const result = currentTop > initTop;
61
- initTop = currentTop;
62
- return result;
63
- }
64
- }
65
72
  const percent = () => {
66
73
  const docEl = document.documentElement;
67
74
  const body = document.body;
68
75
  const scrollPos = window.pageYOffset || docEl.scrollTop;
69
76
  const totalScrollableHeight = Math.max(body.scrollHeight, docEl.scrollHeight, body.offsetHeight, docEl.offsetHeight, body.clientHeight, docEl.clientHeight) - docEl.clientHeight;
70
77
  const scrolledPercent = Math.round((scrollPos / totalScrollableHeight) * 100);
71
- const navToTop = document.querySelector("#nav-totop") || null;
72
- const rsToTop = document.querySelector(".rs_show .top i") || null;
78
+ const navToTop = document.querySelector("#nav-totop");
79
+ const rsToTop = document.querySelector(".rs_show .top i");
73
80
  const percentDisplay = document.querySelector("#percent");
74
81
  const isNearEnd = (window.scrollY + docEl.clientHeight) >= (document.getElementById("post-comment") || document.getElementById("footer")).offsetTop;
75
- navToTop && navToTop.classList.toggle("long", isNearEnd || scrolledPercent > 90);
76
- rsToTop && rsToTop.classList.toggle("show", isNearEnd || scrolledPercent > 90);
77
- percentDisplay.textContent = isNearEnd || scrolledPercent > 90 ? navToTop ? GLOBAL_CONFIG.lang.backtop : '' : scrolledPercent;
82
+
83
+ navToTop?.classList.toggle("long", isNearEnd || scrolledPercent > 90);
84
+ rsToTop?.classList.toggle("show", isNearEnd || scrolledPercent > 90);
85
+ percentDisplay.textContent = isNearEnd || scrolledPercent > 90 ? (navToTop ? GLOBAL_CONFIG.lang.backtop : '') : scrolledPercent;
86
+
78
87
  document.querySelectorAll(".needEndHide").forEach(item => item.classList.toggle("hide", totalScrollableHeight - scrollPos < 100));
79
- }
88
+ };
89
+
80
90
  const showTodayCard = () => {
81
91
  const el = document.getElementById('todayCard');
82
92
  const topGroup = document.querySelector('.topGroup');
83
93
  topGroup?.addEventListener('mouseleave', () => el?.classList.remove('hide'));
84
- }
94
+ };
95
+
85
96
  const initObserver = () => {
86
97
  const commentElement = document.getElementById("post-comment");
87
98
  const paginationElement = document.getElementById("pagination");
88
99
  const commentBarrageElement = document.querySelector(".comment-barrage");
100
+
89
101
  if (commentElement && paginationElement) {
90
102
  const observer = new IntersectionObserver(entries => {
91
103
  entries.forEach(entry => {
92
- const action = entry.isIntersecting ? 'add' : 'remove';
93
- paginationElement.classList[action]("show-window");
104
+ paginationElement.classList.toggle("show-window", entry.isIntersecting);
94
105
  if (GLOBAL_CONFIG.comment.commentBarrage) {
95
106
  commentBarrageElement.style.bottom = entry.isIntersecting ? "-200px" : "0px";
96
107
  }
@@ -99,9 +110,11 @@ const initObserver = () => {
99
110
  observer.observe(commentElement);
100
111
  }
101
112
  };
113
+
102
114
  const addCopyright = () => {
103
115
  if (!GLOBAL_CONFIG.copyright) return;
104
- const {limit, author, link, source, info} = GLOBAL_CONFIG.copyright;
116
+ const { limit, author, link, source, info } = GLOBAL_CONFIG.copyright;
117
+
105
118
  document.body.addEventListener('copy', (e) => {
106
119
  e.preventDefault();
107
120
  const copyText = window.getSelection().toString();
@@ -109,10 +122,11 @@ const addCopyright = () => {
109
122
  e.clipboardData.setData('text', text);
110
123
  });
111
124
  };
125
+
112
126
  const asideStatus = () => {
113
127
  const status = utils.saveToLocal.get('aside-status');
114
128
  document.documentElement.classList.toggle('hide-aside', status === 'hide');
115
- }
129
+ };
116
130
 
117
131
  function initThemeColor() {
118
132
  const currentTop = window.scrollY || document.documentElement.scrollTop;
@@ -131,11 +145,10 @@ function applyThemeColor(color) {
131
145
  }
132
146
 
133
147
  const handleThemeChange = mode => {
134
- const themeChange = window.globalFn?.themeChange || {}
135
- for (let key in themeChange) {
136
- themeChange[key](mode)
137
- }
138
- }
148
+ const themeChange = window.globalFn?.themeChange || {};
149
+ Object.values(themeChange).forEach(fn => fn(mode));
150
+ };
151
+
139
152
  const sco = {
140
153
  lastSayHello: "",
141
154
  wasPageHidden: false,
@@ -144,10 +157,7 @@ const sco = {
144
157
  const targetElement = document.getElementById(elementId);
145
158
  if (targetElement) {
146
159
  const targetPosition = targetElement.getBoundingClientRect().top + window.pageYOffset - 80;
147
- window.scroll({
148
- top: targetPosition,
149
- behavior: "smooth"
150
- });
160
+ window.scroll({ top: targetPosition, behavior: "smooth" });
151
161
  }
152
162
  },
153
163
  musicToggle(isMeting = true) {
@@ -159,25 +169,18 @@ const sco = {
159
169
  const $console = document.getElementById('consoleMusic');
160
170
  const $rmText = document.querySelector('#menu-music-toggle span');
161
171
  const $rmIcon = document.querySelector('#menu-music-toggle i');
162
-
172
+
163
173
  this.musicPlaying = !this.musicPlaying;
164
174
  $music.classList.toggle("playing", this.musicPlaying);
165
175
  $music.classList.toggle("stretch", this.musicPlaying);
166
176
  $console?.classList.toggle("on", this.musicPlaying);
167
-
168
- if (this.musicPlaying) {
169
- if (typeof rm !== 'undefined' && rm?.menuItems.music[0]) {
170
- $rmText.textContent = GLOBAL_CONFIG.right_menu.music.stop;
171
- $rmIcon.className = 'solitude fas fa-pause';
172
- }
173
- } else {
174
- if (typeof rm !== 'undefined' && rm?.menuItems.music[0]) {
175
- $rmText.textContent = GLOBAL_CONFIG.right_menu.music.start;
176
- $rmIcon.className = 'solitude fas fa-play';
177
- }
177
+
178
+ if (typeof rm !== 'undefined' && rm?.menuItems.music[0]) {
179
+ $rmText.textContent = this.musicPlaying ? GLOBAL_CONFIG.right_menu.music.stop : GLOBAL_CONFIG.right_menu.music.start;
180
+ $rmIcon.className = this.musicPlaying ? 'solitude fas fa-pause' : 'solitude fas fa-play';
178
181
  }
179
182
 
180
- if(isMeting){
183
+ if (isMeting) {
181
184
  this.musicPlaying ? $meting.aplayer.play() : $meting.aplayer.pause();
182
185
  }
183
186
  },
@@ -185,7 +188,7 @@ const sco = {
185
188
  const $music = document.querySelector('#nav-music');
186
189
  const $name = document.querySelector('#nav-music .aplayer-music');
187
190
  const $button = document.querySelector('#nav-music .aplayer-button');
188
-
191
+
189
192
  $name?.addEventListener('click', () => {
190
193
  $music.classList.toggle("stretch");
191
194
  });
@@ -193,18 +196,19 @@ const sco = {
193
196
  $button?.addEventListener('click', () => {
194
197
  this.musicToggle(false);
195
198
  });
196
-
199
+
197
200
  this.isMusicBind = true;
198
201
  },
199
202
  switchCommentBarrage() {
200
- let commentBarrageElement = document.querySelector(".comment-barrage");
201
- let consoleCommentBarrage = document.querySelector("#consoleCommentBarrage");
203
+ const commentBarrageElement = document.querySelector(".comment-barrage");
204
+ const consoleCommentBarrage = document.querySelector("#consoleCommentBarrage");
202
205
  if (!commentBarrageElement) return;
206
+
203
207
  const isDisplayed = window.getComputedStyle(commentBarrageElement).display === "flex";
204
208
  commentBarrageElement.style.display = isDisplayed ? "none" : "flex";
205
- consoleCommentBarrage && consoleCommentBarrage.classList.toggle("on", !isDisplayed);
209
+ consoleCommentBarrage?.classList.toggle("on", !isDisplayed);
206
210
  utils.saveToLocal.set("commentBarrageSwitch", !isDisplayed, .2);
207
- rm?.menuItems.barrage && rm.barrage(isDisplayed)
211
+ rm?.menuItems.barrage && rm.barrage(isDisplayed);
208
212
  },
209
213
  switchHideAside() {
210
214
  const htmlClassList = document.documentElement.classList;
@@ -266,15 +270,17 @@ const sco = {
266
270
  document.querySelectorAll('.waterfall').forEach(el => observer.observe(el));
267
271
  },
268
272
  addRuntime() {
269
- let el = document.getElementById('runtimeshow');
270
- el && GLOBAL_CONFIG.runtime && (el.innerText = utils.timeDiff(new Date(GLOBAL_CONFIG.runtime), new Date()) + GLOBAL_CONFIG.lang.day);
273
+ const el = document.getElementById('runtimeshow');
274
+ if (el && GLOBAL_CONFIG.runtime) {
275
+ el.innerText = utils.timeDiff(new Date(GLOBAL_CONFIG.runtime), new Date()) + GLOBAL_CONFIG.lang.day;
276
+ }
271
277
  },
272
278
  toTalk(txt) {
273
279
  const inputs = ["#wl-edit", ".el-textarea__inner", "#veditor", ".atk-textarea"];
274
280
  inputs.forEach(selector => {
275
281
  const el = document.querySelector(selector);
276
282
  if (el) {
277
- el.dispatchEvent(new Event('input', {bubble: true, cancelable: true}));
283
+ el.dispatchEvent(new Event('input', { bubble: true, cancelable: true }));
278
284
  el.value = '> ' + txt.replace(/\n/g, '\n> ') + '\n\n';
279
285
  utils.scrollToDest(utils.getEleTop(document.getElementById('post-comment')), 300);
280
286
  el.focus();
@@ -297,9 +303,11 @@ const sco = {
297
303
  }
298
304
  },
299
305
  addPhotoFigcaption() {
300
- document.querySelectorAll('#article-container img:not(.gallery-item img)').forEach(image => {
306
+ document.querySelectorAll('.article-container img:not(.gallery-item img)').forEach(image => {
301
307
  const captionText = image.getAttribute('alt');
302
- captionText && image.insertAdjacentHTML('afterend', `<div class="img-alt is-center">${captionText}</div>`);
308
+ if (captionText) {
309
+ image.insertAdjacentHTML('afterend', `<div class="img-alt is-center">${utils.escapeHtml(captionText)}</div>`);
310
+ }
303
311
  });
304
312
  },
305
313
  scrollToComment: () => utils.scrollToDest(utils.getEleTop(document.getElementById('post-comment')), 300),
@@ -320,22 +328,16 @@ const sco = {
320
328
  }
321
329
  return null;
322
330
  };
323
- const nick = localData ? (localData.nick ? localData.nick : localData.display_name) : null;
324
-
325
- let prefix;
326
- if (this.wasPageHidden) {
327
- prefix = GLOBAL_CONFIG.aside.sayhello3.back + nick;
328
- this.wasPageHidden = false;
329
- } else {
330
- prefix = GLOBAL_CONFIG.aside.sayhello3.prefix + nick;
331
- }
331
+ const nick = localData ? (localData.nick || localData.display_name) : null;
332
+
333
+ const prefix = this.wasPageHidden ? GLOBAL_CONFIG.aside.sayhello3.back + nick : GLOBAL_CONFIG.aside.sayhello3.prefix + nick;
332
334
 
333
335
  const greetings = [
334
- {start: 0, end: 5, text: nick ? prefix : lang.goodnight},
335
- {start: 6, end: 10, text: nick ? prefix : lang.morning},
336
- {start: 11, end: 14, text: nick ? prefix : lang.noon},
337
- {start: 15, end: 18, text: nick ? prefix : lang.afternoon},
338
- {start: 19, end: 24, text: nick ? prefix : lang.night},
336
+ { start: 0, end: 5, text: nick ? prefix : lang.goodnight },
337
+ { start: 6, end: 10, text: nick ? prefix : lang.morning },
338
+ { start: 11, end: 14, text: nick ? prefix : lang.noon },
339
+ { start: 15, end: 18, text: nick ? prefix : lang.afternoon },
340
+ { start: 19, end: 24, text: nick ? prefix : lang.night },
339
341
  ];
340
342
  const greeting = greetings.find(g => hours >= g.start && hours <= g.end);
341
343
  el.innerText = greeting.text;
@@ -375,11 +377,7 @@ const sco = {
375
377
  if (scrollBar) {
376
378
  const isScrollBarAtEnd = () => scrollBar.scrollLeft + scrollBar.clientWidth >= scrollBar.scrollWidth - 8;
377
379
  const scroll = () => {
378
- if (isScrollBarAtEnd()) {
379
- scrollBar.scroll({left: 0, behavior: "smooth"});
380
- } else {
381
- scrollBar.scrollBy({left: scrollBar.clientWidth, behavior: "smooth"});
382
- }
380
+ scrollBar.scroll({ left: isScrollBarAtEnd() ? 0 : scrollBar.clientWidth, behavior: "smooth" });
383
381
  };
384
382
  scrollBar.addEventListener("scroll", () => {
385
383
  clearTimeout(this.timeoutId);
@@ -395,7 +393,7 @@ const sco = {
395
393
  document.getElementById("more-tags-btn")?.remove();
396
394
  },
397
395
  listenToPageInputPress() {
398
- const toGroup = document.querySelector(".toPageGroup")
396
+ const toGroup = document.querySelector(".toPageGroup");
399
397
  const pageText = document.getElementById("toPageText");
400
398
  if (!pageText) return;
401
399
  const pageButton = document.getElementById("toPageButton");
@@ -403,7 +401,7 @@ const sco = {
403
401
  const lastPageNumber = +pageNumbers[pageNumbers.length - 1].textContent;
404
402
  if (!pageText || lastPageNumber === 1) {
405
403
  toGroup.style.display = "none";
406
- return
404
+ return;
407
405
  }
408
406
  pageText.addEventListener("keydown", (event) => {
409
407
  if (event.keyCode === 13) {
@@ -420,7 +418,9 @@ const sco = {
420
418
  },
421
419
  addNavBackgroundInit() {
422
420
  const scrollTop = document.documentElement.scrollTop;
423
- (scrollTop !== 0) && document.getElementById("page-header").classList.add("nav-fixed", "nav-visible");
421
+ if (scrollTop !== 0) {
422
+ document.getElementById("page-header").classList.add("nav-fixed", "nav-visible");
423
+ }
424
424
  },
425
425
  toPage() {
426
426
  const pageNumbers = document.querySelectorAll(".page-number");
@@ -459,178 +459,185 @@ const sco = {
459
459
  const itemRect = owoItem.getBoundingClientRect();
460
460
  owoBig.style.left = `${itemRect.left - (owoBig.offsetWidth / 4)}px`;
461
461
  owoBig.style.top = `${itemRect.top}px`;
462
- }
462
+ };
463
463
  document.addEventListener('mouseover', showOwoBig);
464
464
  document.addEventListener('mouseout', hideOwoBig);
465
465
  },
466
466
  changeTimeFormat(selector) {
467
467
  selector.forEach(item => {
468
- const timeVal = item.getAttribute('datetime')
469
- item.textContent = utils.diffDate(timeVal, true)
470
- item.style.display = 'inline'
471
- })
468
+ const timeVal = item.getAttribute('datetime');
469
+ item.textContent = utils.diffDate(timeVal, true);
470
+ item.style.display = 'inline';
471
+ });
472
472
  },
473
473
  switchComments() {
474
- const switchBtn = document.getElementById('switch-btn')
475
- if (!switchBtn) return
476
- let switchDone = false
477
- const commentContainer = document.getElementById('post-comment')
474
+ const switchBtn = document.getElementById('switch-btn');
475
+ if (!switchBtn) return;
476
+ let switchDone = false;
477
+ const commentContainer = document.getElementById('post-comment');
478
478
  const handleSwitchBtn = () => {
479
- commentContainer.classList.toggle('move')
479
+ commentContainer.classList.toggle('move');
480
480
  if (!switchDone && typeof loadTwoComment === 'function') {
481
- switchDone = true
482
- loadTwoComment()
481
+ switchDone = true;
482
+ loadTwoComment();
483
483
  }
484
- }
485
- utils.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn)
484
+ };
485
+ utils.addEventListenerPjax(switchBtn, 'click', handleSwitchBtn);
486
486
  }
487
487
  };
488
+
488
489
  const addHighlight = () => {
489
490
  const highlight = GLOBAL_CONFIG.highlight;
490
491
  if (!highlight) return;
491
- const {copy, expand, limit, syntax} = highlight;
492
+ const { copy, expand, limit, syntax } = highlight;
492
493
  const $isPrismjs = syntax === 'prismjs';
493
494
  const $isShowTool = highlight.enable || copy || expand || limit;
494
- const expandClass = !expand === true ? 'closed' : ''
495
- const $syntaxHighlight = syntax === 'highlight.js' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]')
496
- if (!(($isShowTool || limit) && $syntaxHighlight.length)) return
495
+ const expandClass = expand ? '' : 'closed';
496
+ const $syntaxHighlight = syntax === 'highlight.js' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]');
497
+
498
+ if (!(($isShowTool || limit) && $syntaxHighlight.length)) return;
499
+
497
500
  const copyEle = copy ? `<i class="solitude fas fa-copy copy-button"></i>` : '<i></i>';
498
501
  const expandEle = `<i class="solitude fas fa-angle-down expand"></i>`;
499
502
  const limitEle = limit ? `<i class="solitude fas fa-angles-down"></i>` : '<i></i>';
500
- const alertInfo = (ele, text) => utils.snackbarShow(text, false, 2000)
503
+
504
+ const alertInfo = (ele, text) => utils.snackbarShow(text, false, 2000);
505
+
501
506
  const copyFn = (e) => {
502
- const $buttonParent = e.parentNode
503
- $buttonParent.classList.add('copy-true')
504
- const selection = window.getSelection()
505
- const range = document.createRange()
506
- const preCodeSelector = $isPrismjs ? 'pre code' : 'table .code pre'
507
- range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0])
508
- selection.removeAllRanges()
509
- selection.addRange(range)
510
- document.execCommand('copy')
511
- alertInfo(e.lastChild, GLOBAL_CONFIG.lang.copy.success)
512
- selection.removeAllRanges()
513
- $buttonParent.classList.remove('copy-true')
514
- }
515
- const expandClose = (e) => e.classList.toggle('closed')
507
+ const $buttonParent = e.parentNode;
508
+ $buttonParent.classList.add('copy-true');
509
+ const selection = window.getSelection();
510
+ const range = document.createRange();
511
+ const preCodeSelector = $isPrismjs ? 'pre code' : 'table .code pre';
512
+ range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0]);
513
+ selection.removeAllRanges();
514
+ selection.addRange(range);
515
+ document.execCommand('copy');
516
+ alertInfo(e.lastChild, GLOBAL_CONFIG.lang.copy.success);
517
+ selection.removeAllRanges();
518
+ $buttonParent.classList.remove('copy-true');
519
+ };
520
+
521
+ const expandClose = (e) => e.classList.toggle('closed');
516
522
  const shrinkEle = function () {
517
- this.classList.toggle('expand-done')
518
- }
523
+ this.classList.toggle('expand-done');
524
+ };
525
+
519
526
  const ToolsFn = function (e) {
520
- const $target = e.target.classList
521
- if ($target.contains('expand')) expandClose(this)
522
- else if ($target.contains('copy-button')) copyFn(this)
523
- }
527
+ const $target = e.target.classList;
528
+ if ($target.contains('expand')) expandClose(this);
529
+ else if ($target.contains('copy-button')) copyFn(this);
530
+ };
531
+
524
532
  const createEle = (lang, item, service) => {
525
- const fragment = document.createDocumentFragment()
533
+ const fragment = document.createDocumentFragment();
526
534
  if ($isShowTool) {
527
- const captionItem = item.querySelector('figcaption')
528
- let caption = ''
535
+ const captionItem = item.querySelector('figcaption');
536
+ let caption = '';
529
537
  if (captionItem) {
530
- caption = `<div class="caption">${captionItem.innerHTML}</div>`
531
- item.removeChild(captionItem)
538
+ caption = `<div class="caption">${captionItem.innerHTML}</div>`;
539
+ item.removeChild(captionItem);
532
540
  }
533
- const hlTools = document.createElement('div')
534
- hlTools.className = `highlight-tools ${expandClass}`
535
- hlTools.innerHTML = expandEle + lang + caption + copyEle
536
- utils.addEventListenerPjax(hlTools, 'click', ToolsFn)
537
- fragment.appendChild(hlTools)
541
+ const hlTools = document.createElement('div');
542
+ hlTools.className = `highlight-tools ${expandClass}`;
543
+ hlTools.innerHTML = expandEle + lang + caption + copyEle;
544
+ utils.addEventListenerPjax(hlTools, 'click', ToolsFn);
545
+ fragment.appendChild(hlTools);
538
546
  }
539
547
  if (limit && item.offsetHeight > limit + 30) {
540
- const ele = document.createElement('div')
541
- ele.className = 'code-expand-btn'
542
- ele.innerHTML = limitEle
543
- utils.addEventListenerPjax(ele, 'click', shrinkEle)
544
- fragment.appendChild(ele)
548
+ const ele = document.createElement('div');
549
+ ele.className = 'code-expand-btn';
550
+ ele.innerHTML = limitEle;
551
+ utils.addEventListenerPjax(ele, 'click', shrinkEle);
552
+ fragment.appendChild(ele);
545
553
  }
546
554
  if (service === 'hl') {
547
- item.insertBefore(fragment, item.firstChild)
555
+ item.insertBefore(fragment, item.firstChild);
548
556
  } else {
549
- item.parentNode.insertBefore(fragment, item)
557
+ item.parentNode.insertBefore(fragment, item);
550
558
  }
551
- }
559
+ };
560
+
552
561
  if ($isPrismjs) {
553
562
  $syntaxHighlight.forEach(item => {
554
- const langName = item.getAttribute('data-language') || 'Code'
555
- const highlightLangEle = `<div class="code-lang">${langName}</div>`
556
- utils.wrap(item, 'figure', {
557
- class: 'highlight'
558
- })
559
- createEle(highlightLangEle, item)
560
- })
563
+ const langName = item.getAttribute('data-language') || 'Code';
564
+ const highlightLangEle = `<div class="code-lang">${utils.escapeHtml(langName)}</div>`;
565
+ utils.wrap(item, 'figure', { class: 'highlight' });
566
+ createEle(highlightLangEle, item);
567
+ });
561
568
  } else {
562
569
  $syntaxHighlight.forEach(item => {
563
- let langName = item.getAttribute('class').split(' ')[1]
564
- if (langName === 'plain' || langName === undefined) langName = 'Code'
565
- const highlightLangEle = `<div class="code-lang">${langName}</div>`
566
- createEle(highlightLangEle, item, 'hl')
567
- })
570
+ let langName = item.getAttribute('class').split(' ')[1];
571
+ if (langName === 'plain' || langName === undefined) langName = 'Code';
572
+ const highlightLangEle = `<div class="code-lang">${utils.escapeHtml(langName)}</div>`;
573
+ createEle(highlightLangEle, item, 'hl');
574
+ });
568
575
  }
569
- }
576
+ };
570
577
 
571
578
  class toc {
572
579
  static init() {
573
- const tocContainer = document.getElementById('card-toc')
580
+ const tocContainer = document.getElementById('card-toc');
574
581
  if (!tocContainer || !tocContainer.querySelector('.toc a')) {
575
- tocContainer.style.display = 'none'
576
- return
582
+ tocContainer.style.display = 'none';
583
+ return;
577
584
  }
578
- const el = document.querySelectorAll('.toc a')
585
+ const el = document.querySelectorAll('.toc a');
579
586
  el.forEach((e) => {
580
587
  e.addEventListener('click', (event) => {
581
- event.preventDefault()
582
- utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI((event.target.className === 'toc-text' ? event.target.parentNode.hash : event.target.hash).replace('#', '')))), 300)
583
- })
584
- })
585
- this.active(el)
588
+ event.preventDefault();
589
+ utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI((event.target.className === 'toc-text' ? event.target.parentNode.hash : event.target.hash).replace('#', '')))), 300);
590
+ });
591
+ });
592
+ this.active(el);
586
593
  }
587
594
 
588
595
  static active(toc) {
589
- const $article = document.getElementById('article-container')
590
- const $tocContent = document.getElementById('toc-content')
591
- const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6')
592
- let detectItem = ''
593
-
594
- function autoScroll(el) {
595
- const activePosition = el.getBoundingClientRect().top
596
- const sidebarScrollTop = $tocContent.scrollTop
596
+ const $article = document.querySelector('.article-container');
597
+ const $tocContent = document.getElementById('toc-content');
598
+ const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6');
599
+ let detectItem = '';
600
+
601
+ const autoScroll = (el) => {
602
+ const activePosition = el.getBoundingClientRect().top;
603
+ const sidebarScrollTop = $tocContent.scrollTop;
597
604
  if (activePosition > (document.documentElement.clientHeight - 100)) {
598
- $tocContent.scrollTop = sidebarScrollTop + 150
605
+ $tocContent.scrollTop = sidebarScrollTop + 150;
599
606
  }
600
607
  if (activePosition < 100) {
601
- $tocContent.scrollTop = sidebarScrollTop - 150
608
+ $tocContent.scrollTop = sidebarScrollTop - 150;
602
609
  }
603
- }
610
+ };
604
611
 
605
- function findHeadPosition(top) {
606
- if (top === 0) return false
607
- let currentIndex = ''
608
- list.forEach(function (ele, index) {
612
+ const findHeadPosition = (top) => {
613
+ if (top === 0) return false;
614
+ let currentIndex = '';
615
+ list.forEach((ele, index) => {
609
616
  if (top > utils.getEleTop(ele) - 80) {
610
- currentIndex = index
617
+ currentIndex = index;
611
618
  }
612
- })
613
- if (detectItem === currentIndex) return
614
- detectItem = currentIndex
619
+ });
620
+ if (detectItem === currentIndex) return;
621
+ detectItem = currentIndex;
615
622
  document.querySelectorAll('.toc .active').forEach((i) => {
616
- i.classList.remove('active')
617
- })
618
- const activeitem = toc[detectItem]
623
+ i.classList.remove('active');
624
+ });
625
+ const activeitem = toc[detectItem];
619
626
  if (activeitem) {
620
- let parent = toc[detectItem].parentNode
621
- activeitem.classList.add('active')
622
- autoScroll(activeitem)
627
+ let parent = toc[detectItem].parentNode;
628
+ activeitem.classList.add('active');
629
+ autoScroll(activeitem);
623
630
  for (; !parent.matches('.toc'); parent = parent.parentNode) {
624
- if (parent.matches('li')) parent.classList.add('active')
631
+ if (parent.matches('li')) parent.classList.add('active');
625
632
  }
626
633
  }
627
- }
634
+ };
628
635
 
629
- window.tocScrollFn = utils.throttle(function () {
630
- const currentTop = window.scrollY || document.documentElement.scrollTop
631
- findHeadPosition(currentTop)
632
- }, 100)
633
- window.addEventListener('scroll', tocScrollFn)
636
+ window.tocScrollFn = utils.throttle(() => {
637
+ const currentTop = window.scrollY || document.documentElement.scrollTop;
638
+ findHeadPosition(currentTop);
639
+ }, 100);
640
+ window.addEventListener('scroll', tocScrollFn);
634
641
  }
635
642
  }
636
643
 
@@ -641,20 +648,17 @@ class tabs {
641
648
  }
642
649
 
643
650
  static clickFnOfTabs() {
644
- document.querySelectorAll('#article-container .tab > button').forEach((item) => {
651
+ document.querySelectorAll('.article-container .tab > button').forEach((item) => {
645
652
  item.addEventListener('click', function () {
646
- const that = this;
647
- const $tabItem = that.parentNode;
653
+ const $tabItem = this.parentNode;
648
654
  if (!$tabItem.classList.contains('active')) {
649
655
  const $tabContent = $tabItem.parentNode.nextElementSibling;
650
656
  const $siblings = utils.siblings($tabItem, '.active')[0];
651
657
  $siblings && $siblings.classList.remove('active');
652
658
  $tabItem.classList.add('active');
653
- const tabId = that.getAttribute('data-href').replace('#', '');
654
- const childList = [...$tabContent.children];
655
- childList.forEach((item) => {
656
- if (item.id === tabId) item.classList.add('active');
657
- else item.classList.remove('active');
659
+ const tabId = this.getAttribute('data-href').replace('#', '');
660
+ [...$tabContent.children].forEach((item) => {
661
+ item.classList.toggle('active', item.id === tabId);
658
662
  });
659
663
  }
660
664
  });
@@ -662,22 +666,20 @@ class tabs {
662
666
  }
663
667
 
664
668
  static backToTop() {
665
- document.querySelectorAll('#article-container .tabs .tab-to-top').forEach((item) => {
669
+ document.querySelectorAll('.article-container .tabs .tab-to-top').forEach((item) => {
666
670
  item.addEventListener('click', function () {
667
- utils.scrollToDest(utils.getEleTop(item.parentElement.parentElement.parentNode), 300);
671
+ utils.scrollToDest(utils.getEleTop(this.parentElement.parentElement.parentNode), 300);
668
672
  });
669
673
  });
670
674
  }
671
675
 
672
676
  static lureAddListener() {
673
677
  if (!GLOBAL_CONFIG.lure) return;
674
- let title = document.title;
678
+ const title = document.title;
675
679
  document.addEventListener('visibilitychange', () => {
676
- const {lure} = GLOBAL_CONFIG;
677
- if (document.visibilityState === 'hidden') {
678
- document.title = lure.jump;
679
- } else if (document.visibilityState === 'visible') {
680
- document.title = lure.back;
680
+ const { lure } = GLOBAL_CONFIG;
681
+ document.title = document.visibilityState === 'hidden' ? lure.jump : lure.back;
682
+ if (document.visibilityState === 'visible') {
681
683
  setTimeout(() => {
682
684
  document.title = title;
683
685
  }, 2000);
@@ -686,7 +688,7 @@ class tabs {
686
688
  }
687
689
 
688
690
  static expireAddListener() {
689
- const {expire} = GLOBAL_CONFIG;
691
+ const { expire } = GLOBAL_CONFIG;
690
692
  if (!expire) return;
691
693
  const list = document.querySelectorAll('.post-meta-date time');
692
694
  const post_date = list.length ? list[list.length - 1] : document.querySelector('.datatime');
@@ -705,72 +707,74 @@ const scrollFnToDo = () => {
705
707
  const { toc } = PAGE_CONFIG;
706
708
 
707
709
  if (toc) {
708
- const $cardTocLayout = document.getElementById('card-toc')
709
- $cardToc = $cardTocLayout.querySelector('.toc-content')
710
- $tocLink = $cardToc.querySelectorAll('.toc-link')
711
- $tocPercentage = $cardTocLayout.querySelector('.toc-percentage')
712
- isExpand = $cardToc.classList.contains('is-expand')
713
-
714
- // toc percentage
715
- const tocItemClickFn = e => {
716
- const target = e.target.closest('.toc-link')
717
- if (!target) return
718
-
719
- e.preventDefault()
720
- utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI(target.getAttribute('href')).replace('#', ''))), 300)
721
- if (window.innerWidth < 900) {
722
- $cardTocLayout.classList.remove('open')
723
- }
710
+ const $cardTocLayout = document.getElementById('card-toc');
711
+ const $cardToc = $cardTocLayout.querySelector('.toc-content');
712
+ const $tocLink = $cardToc.querySelectorAll('.toc-link');
713
+ const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage');
714
+ const isExpand = $cardToc.classList.contains('is-expand');
715
+
716
+ const tocItemClickFn = e => {
717
+ const target = e.target.closest('.toc-link');
718
+ if (!target) return;
719
+
720
+ e.preventDefault();
721
+ utils.scrollToDest(utils.getEleTop(document.getElementById(decodeURI(target.getAttribute('href')).replace('#', ''))), 300);
722
+ if (window.innerWidth < 900) {
723
+ $cardTocLayout.classList.remove('open');
724
724
  }
725
- utils.addEventListenerPjax($cardToc, 'click', tocItemClickFn)
725
+ };
726
+ utils.addEventListenerPjax($cardToc, 'click', tocItemClickFn);
726
727
  }
727
- }
728
+ };
728
729
 
729
730
  const forPostFn = () => {
730
- scrollFnToDo()
731
- }
731
+ scrollFnToDo();
732
+ };
732
733
 
733
734
  window.refreshFn = () => {
734
- const {is_home, is_page, page, is_post} = PAGE_CONFIG;
735
- const {runtime, lazyload, lightbox, randomlink, covercolor, post_ai, lure, expire} = GLOBAL_CONFIG;
735
+ const { is_home, is_page, page, is_post } = PAGE_CONFIG;
736
+ const { runtime, lazyload, lightbox, randomlink, covercolor, post_ai, lure, expire } = GLOBAL_CONFIG;
736
737
  const timeSelector = (is_home ? '.post-meta-date time' : is_post ? '.post-meta-date time' : '.datatime') + ', .webinfo-item time';
737
738
  document.body.setAttribute('data-type', page);
738
739
  sco.changeTimeFormat(document.querySelectorAll(timeSelector));
739
740
  runtime && sco.addRuntime();
740
741
  [scrollFn, sidebarFn, sco.addPhotoFigcaption, sco.setTimeState, sco.tagPageActive, sco.categoriesBarActive, sco.listenToPageInputPress, sco.addNavBackgroundInit, sco.refreshWaterFall].forEach(fn => fn());
741
742
  lazyload.enable && utils.lazyloadImg();
742
- lightbox && utils.lightbox(document.querySelectorAll("#article-container img:not(.flink-avatar,.gallery-group img, .no-lightbox)"));
743
+ lightbox && utils.lightbox(document.querySelectorAll(".article-container img:not(.flink-avatar,.gallery-group img, .no-lightbox)"));
743
744
  randomlink && randomLinksList();
744
745
  post_ai && is_post && ai.init();
745
746
  sco.switchComments();
746
747
  initObserver();
747
748
  if (is_home) {
748
749
  showTodayCard();
749
- typeof updatePostsBasedOnComments === 'function' && updatePostsBasedOnComments()
750
750
  }
751
+ typeof updatePostsBasedOnComments === 'function' && updatePostsBasedOnComments();
751
752
  if (is_post || is_page) {
752
753
  addHighlight();
753
754
  tabs.init();
754
755
  }
755
- if (is_post) {
756
- if (expire) tabs.expireAddListener();
756
+ if (is_post && expire) {
757
+ tabs.expireAddListener();
757
758
  }
758
759
  if (covercolor.enable) coverColor();
759
760
  if (PAGE_CONFIG.toc) toc.init();
760
761
  if (lure) tabs.lureAddListener();
761
762
 
762
763
  forPostFn();
763
- }
764
+ };
765
+
764
766
  document.addEventListener('DOMContentLoaded', () => {
765
767
  [addCopyright, window.refreshFn, asideStatus, () => window.onscroll = percent, sco.initConsoleState].forEach(fn => fn());
766
768
  });
769
+
767
770
  document.addEventListener('visibilitychange', () => {
768
771
  if (document.hidden) {
769
772
  sco.wasPageHidden = true;
770
773
  }
771
774
  });
775
+
772
776
  window.onkeydown = e => {
773
- const {keyCode, ctrlKey, shiftKey} = e;
777
+ const { keyCode, ctrlKey, shiftKey } = e;
774
778
  if (keyCode === 123 || (ctrlKey && shiftKey && keyCode === 67)) {
775
779
  utils.snackbarShow(GLOBAL_CONFIG.lang.f12, false, 3000);
776
780
  }
@@ -778,6 +782,7 @@ window.onkeydown = e => {
778
782
  sco.hideConsole();
779
783
  }
780
784
  };
785
+
781
786
  document.addEventListener('copy', () => {
782
787
  utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success, false, 3000);
783
788
  });