hexo-theme-volantis 4.3.1 → 5.0.0-alpha.112

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 (309) hide show
  1. package/README.md +6 -4
  2. package/_config.yml +599 -246
  3. package/languages/en.yml +7 -0
  4. package/languages/zh-CN.yml +13 -2
  5. package/languages/zh-TW.yml +7 -0
  6. package/layout/404.ejs +1 -1
  7. package/layout/_meta/author.ejs +4 -4
  8. package/layout/_meta/category.ejs +11 -8
  9. package/layout/_meta/counter.ejs +29 -7
  10. package/layout/_meta/date.ejs +1 -1
  11. package/layout/_meta/music.ejs +1 -1
  12. package/layout/_meta/share.ejs +1 -1
  13. package/layout/_meta/tags.ejs +3 -0
  14. package/layout/_meta/thumbnail.ejs +3 -1
  15. package/layout/_meta/updated.ejs +1 -1
  16. package/layout/_meta/walinecount.ejs +2 -1
  17. package/layout/{_cover → _partial/_cover}/blank.ejs +0 -0
  18. package/layout/{_cover → _partial/_cover}/dock.ejs +1 -1
  19. package/layout/{_cover → _partial/_cover}/featured.ejs +1 -1
  20. package/layout/{_cover → _partial/_cover}/focus.ejs +1 -1
  21. package/layout/_partial/_cover/layout.ejs +8 -0
  22. package/layout/{_cover → _partial/_cover}/search.ejs +2 -2
  23. package/layout/_partial/archive.ejs +2 -2
  24. package/layout/_partial/article.ejs +21 -16
  25. package/layout/_partial/categories.ejs +1 -1
  26. package/layout/_partial/cover.ejs +8 -28
  27. package/layout/_partial/footer.ejs +19 -11
  28. package/layout/_partial/head.ejs +70 -116
  29. package/layout/_partial/header.ejs +17 -11
  30. package/layout/_partial/meta.ejs +18 -4
  31. package/layout/_partial/post.ejs +35 -9
  32. package/layout/_partial/scripts/_ctrl/cdnCtrl.ejs +126 -0
  33. package/layout/_partial/scripts/{coverCtrl.ejs → _ctrl/coverCtrl.ejs} +17 -25
  34. package/layout/_partial/scripts/_ctrl.ejs +2 -0
  35. package/layout/_partial/scripts/content-visibility-scroll-fix.ejs +88 -0
  36. package/layout/_partial/scripts/global.ejs +422 -109
  37. package/layout/_partial/scripts/index.ejs +91 -46
  38. package/layout/_partial/scripts/toc.ejs +98 -68
  39. package/layout/_partial/side.ejs +4 -1
  40. package/layout/_plugins/_page_plugins/artitalk/index.ejs +15 -0
  41. package/layout/_plugins/_page_plugins/bbtalk/index.ejs +10 -0
  42. package/layout/_plugins/_page_plugins/fcircle/index.ejs +12 -0
  43. package/layout/_plugins/_page_plugins/gitter/index.ejs +14 -0
  44. package/layout/_plugins/_page_plugins/indent/index.ejs +16 -0
  45. package/layout/_plugins/_page_plugins/index.ejs +27 -0
  46. package/layout/_plugins/_page_plugins/katex/index.ejs +13 -0
  47. package/layout/{_third-party/math/mathjax/script.ejs → _plugins/_page_plugins/mathjax/index.ejs} +2 -2
  48. package/layout/_plugins/_page_plugins/snackbar/index.ejs +55 -0
  49. package/layout/{_partial/scripts/counter.ejs → _plugins/analytics/LCCounter.ejs} +0 -0
  50. package/layout/{_third-party → _plugins}/analytics/script.ejs +43 -5
  51. package/layout/{_third-party → _plugins}/aplayer/layout.ejs +0 -0
  52. package/layout/_plugins/aplayer/script.ejs +74 -0
  53. package/layout/_plugins/chat/gitter/script.ejs +17 -0
  54. package/layout/_plugins/chat/index.ejs +1 -0
  55. package/layout/_plugins/chat/tidio/script.ejs +1 -0
  56. package/layout/_plugins/comments/artalk/script.ejs +59 -0
  57. package/layout/_plugins/comments/beaudar/script.ejs +61 -0
  58. package/layout/_plugins/comments/discuss/script.ejs +30 -0
  59. package/layout/_plugins/comments/disqus/script.ejs +98 -0
  60. package/layout/_plugins/comments/disqusjs/script.ejs +35 -0
  61. package/layout/_plugins/comments/giscus/script.ejs +47 -0
  62. package/layout/_plugins/comments/gitalk/script.ejs +24 -0
  63. package/layout/_plugins/comments/hashover/script.ejs +5 -0
  64. package/layout/{_third-party → _plugins}/comments/index.ejs +10 -3
  65. package/layout/_plugins/comments/isso/script.ejs +27 -0
  66. package/layout/_plugins/comments/livere/script.ejs +15 -0
  67. package/layout/_plugins/comments/twikoo/script.ejs +40 -0
  68. package/layout/_plugins/comments/utterances/script.ejs +43 -0
  69. package/layout/_plugins/comments/vssue/script.ejs +37 -0
  70. package/layout/_plugins/comments/waline/script.ejs +62 -0
  71. package/layout/_plugins/comments/z-custom/script.ejs +1 -0
  72. package/layout/_plugins/darkmode/script.ejs +114 -0
  73. package/layout/{_third-party → _plugins}/end-of-support/script.ejs +25 -8
  74. package/layout/_plugins/github-api/script.ejs +27 -0
  75. package/layout/_plugins/highlight/highlightjs/script.ejs +26 -0
  76. package/layout/_plugins/highlight/prismjs/script.ejs +25 -0
  77. package/layout/_plugins/highlight/script.ejs +1 -0
  78. package/layout/{_third-party → _plugins}/lazyload/script.ejs +1 -1
  79. package/layout/{_third-party → _plugins}/nodewaves/script.ejs +1 -1
  80. package/layout/_plugins/parallax/script.ejs +74 -0
  81. package/layout/{_third-party → _plugins}/pjax/animate.ejs +31 -31
  82. package/layout/_plugins/pjax/index.ejs +73 -0
  83. package/layout/_plugins/pjax/pdata.ejs +56 -0
  84. package/layout/{_third-party → _plugins}/preload/script.ejs +3 -3
  85. package/layout/_plugins/rightmenu/layout.ejs +119 -0
  86. package/layout/_plugins/rightmenus/layout.ejs +137 -0
  87. package/layout/_plugins/scrollreveal/script.ejs +25 -0
  88. package/layout/_plugins/search/script.ejs +50 -0
  89. package/layout/{_third-party → _plugins}/share/layout.ejs +0 -0
  90. package/layout/_plugins/swiper/script.ejs +37 -0
  91. package/layout/_pre.ejs +2 -2
  92. package/layout/_widget/_pre.ejs +5 -0
  93. package/layout/_widget/blogger.ejs +1 -1
  94. package/layout/_widget/category.ejs +2 -2
  95. package/layout/_widget/copyright.ejs +1 -1
  96. package/layout/_widget/grid.ejs +3 -3
  97. package/layout/_widget/lastupdate.ejs +27 -0
  98. package/layout/_widget/list.ejs +2 -2
  99. package/layout/_widget/load.ejs +18 -0
  100. package/layout/_widget/music.ejs +3 -2
  101. package/layout/_widget/page.ejs +1 -1
  102. package/layout/_widget/qrcode.ejs +1 -1
  103. package/layout/_widget/related_posts.ejs +1 -1
  104. package/layout/_widget/tagcloud.ejs +1 -1
  105. package/layout/_widget/text.ejs +1 -1
  106. package/layout/_widget/toc.ejs +6 -2
  107. package/layout/_widget/webinfo.ejs +13 -76
  108. package/layout/archive.ejs +4 -4
  109. package/layout/category.ejs +9 -4
  110. package/layout/docs.ejs +1 -1
  111. package/layout/friends.ejs +6 -25
  112. package/layout/index.ejs +1 -1
  113. package/layout/layout.ejs +30 -12
  114. package/layout/list.ejs +1 -1
  115. package/layout/page.ejs +1 -1
  116. package/layout/post.ejs +1 -1
  117. package/layout/tag.ejs +8 -3
  118. package/package.json +5 -3
  119. package/scripts/events/index.js +13 -0
  120. package/scripts/events/lib/check-configuration.js +43 -0
  121. package/scripts/events/lib/check-environment.js +74 -0
  122. package/scripts/events/lib/config.js +34 -9
  123. package/scripts/events/lib/render-stylus.js +78 -0
  124. package/scripts/events/lib/stellar-tag-utils.js +76 -0
  125. package/scripts/filters/content-visibility.js +25 -0
  126. package/scripts/{render → filters}/img.js +0 -0
  127. package/scripts/filters/replace.js +15 -0
  128. package/scripts/{z-lazyload/lib/process.js → filters/z-lazyload.js} +6 -3
  129. package/scripts/helpers/custom-files.js +165 -0
  130. package/scripts/helpers/first-style.js +19 -0
  131. package/scripts/helpers/head/autoCanonical.js +15 -0
  132. package/scripts/helpers/head/generate_preload_fontfamily.js +22 -0
  133. package/scripts/helpers/head/generate_seo.js +24 -0
  134. package/scripts/helpers/head/generate_title__keywords__description.js +101 -0
  135. package/scripts/{related_posts/index.js → helpers/related-posts.js} +1 -1
  136. package/scripts/helpers/revisioned.js +158 -0
  137. package/scripts/helpers/structured-data/index.js +2 -0
  138. package/scripts/helpers/structured-data/lib/blogposting.js +77 -0
  139. package/scripts/helpers/structured-data/lib/breadcrumblist.js +152 -0
  140. package/scripts/helpers/structured-data/lib/config.js +31 -0
  141. package/scripts/helpers/structured-data/lib/index.js +30 -0
  142. package/scripts/helpers/structured-data/lib/organization.js +15 -0
  143. package/scripts/helpers/structured-data/lib/person.js +16 -0
  144. package/scripts/helpers/structured-data/lib/website.js +42 -0
  145. package/scripts/tags/btn.js +6 -1
  146. package/scripts/tags/btns.js +7 -2
  147. package/scripts/tags/checkbox.js +12 -2
  148. package/scripts/tags/contributors.js +100 -0
  149. package/scripts/tags/dropmenu.js +18 -3
  150. package/scripts/tags/fancybox.js +44 -10
  151. package/scripts/tags/folding.js +6 -1
  152. package/scripts/tags/frame.js +6 -1
  153. package/scripts/tags/friends.js +99 -0
  154. package/scripts/tags/ghcard.js +6 -1
  155. package/scripts/tags/image.js +14 -2
  156. package/scripts/tags/link.js +6 -1
  157. package/scripts/tags/md.js +59 -0
  158. package/scripts/tags/media.js +25 -1
  159. package/scripts/tags/note.js +36 -3
  160. package/scripts/tags/site.js +87 -51
  161. package/scripts/tags/span.js +12 -2
  162. package/scripts/tags/swiper.js +38 -0
  163. package/scripts/tags/tabs.js +33 -3
  164. package/scripts/tags/timeline.js +6 -1
  165. package/source/css/Readme.md +28 -0
  166. package/source/css/_defines/AutoPrefixCSS.styl +347 -0
  167. package/source/css/_defines/Readme.md +3 -0
  168. package/source/css/_defines/color.styl +41 -1
  169. package/source/css/_defines/effect.styl +0 -13
  170. package/source/css/_defines/fonts.styl +17 -18
  171. package/source/css/_defines/func.styl +12 -30
  172. package/source/css/_first/base_first.styl +118 -0
  173. package/source/css/_first/{cover.styl → cover_first.styl} +113 -87
  174. package/source/css/_first/dark_first.styl +76 -0
  175. package/source/css/_first/fontfamily_first.styl +17 -0
  176. package/source/css/_first/{navbar.styl → navbar_first.styl} +4 -10
  177. package/source/css/_first/search_first.styl +12 -0
  178. package/source/css/{_base/index.styl → _style/_base/base.styl} +9 -93
  179. package/source/css/_style/_base/fontfamily_async.styl +8 -0
  180. package/source/css/{_layout → _style/_layout}/archive.styl +0 -0
  181. package/source/css/{_layout → _style/_layout}/article.styl +3 -30
  182. package/source/css/{_layout → _style/_layout}/footer.styl +0 -0
  183. package/source/css/_style/_layout/friends-simpleuser.styl +23 -0
  184. package/source/css/_style/_layout/friends-traditional.styl +81 -0
  185. package/source/css/{_layout → _style/_layout}/img.styl +0 -0
  186. package/source/css/_style/_layout/loading.styl +14 -0
  187. package/source/css/{_layout → _style/_layout}/main.styl +19 -7
  188. package/source/css/{_layout → _style/_layout}/md.styl +0 -0
  189. package/source/css/{_layout → _style/_layout}/pagination.styl +1 -1
  190. package/source/css/{_layout → _style/_layout}/posts.styl +2 -0
  191. package/source/css/{_first → _style/_layout}/search.styl +0 -103
  192. package/source/css/{_layout → _style/_layout}/sidebar.styl +23 -3
  193. package/source/css/{_layout → _style/_layout}/snackbar.styl +0 -0
  194. package/source/css/{_layout → _style/_layout}/toc.styl +3 -3
  195. package/source/css/{_layout → _style/_layout}/video.styl +0 -0
  196. package/source/css/_style/_plugins/_dark/dark_async.styl +41 -0
  197. package/source/css/_style/_plugins/_dark/dark_plugins.styl +136 -0
  198. package/source/css/_style/_plugins/_highlight/highlightjs/clipboard.styl +36 -0
  199. package/source/css/_style/_plugins/_highlight/highlightjs/color.styl +96 -0
  200. package/source/css/_style/_plugins/_highlight/highlightjs/index.styl +102 -0
  201. package/source/css/_style/_plugins/_highlight/highlightjs/language.styl +63 -0
  202. package/source/css/_style/_plugins/_highlight/index.styl +1 -0
  203. package/source/css/_style/_plugins/_highlight/prismjs/clipboard.styl +33 -0
  204. package/source/css/_style/_plugins/_highlight/prismjs/index.styl +8 -0
  205. package/source/css/_style/_plugins/_highlight/prismjs/language.styl +63 -0
  206. package/source/css/_style/_plugins/_rightmenu/reading.styl +56 -0
  207. package/source/css/{_plugins → _style/_plugins/_rightmenu}/rightmenu.styl +22 -2
  208. package/source/css/{_plugins → _style/_plugins}/aplayer.styl +8 -1
  209. package/source/css/{_plugins → _style/_plugins}/cursor.styl +49 -19
  210. package/source/css/_style/_plugins/fontcolor.styl +84 -0
  211. package/source/css/{_plugins → _style/_plugins}/gitalk.styl +0 -0
  212. package/source/css/_style/_plugins/index.styl +24 -0
  213. package/source/css/{_plugins → _style/_plugins}/mathjax.styl +0 -0
  214. package/source/css/_style/_plugins/message.styl +14 -0
  215. package/source/css/{_plugins → _style/_plugins}/pjaxanimate.styl +0 -0
  216. package/source/css/_style/_tag-plugins/Readme.md +6 -0
  217. package/source/css/{_tag-plugins → _style/_tag-plugins}/btns.styl +0 -0
  218. package/source/css/{_tag-plugins → _style/_tag-plugins}/checkbox.styl +0 -0
  219. package/source/css/{_tag-plugins → _style/_tag-plugins}/dropmenu.styl +0 -0
  220. package/source/css/{_plugins → _style/_tag-plugins}/fancybox.styl +8 -9
  221. package/source/css/{_tag-plugins → _style/_tag-plugins}/folding.styl +0 -0
  222. package/source/css/{_tag-plugins → _style/_tag-plugins}/frame.styl +0 -0
  223. package/source/css/_style/_tag-plugins/friends.styl +72 -0
  224. package/source/css/{_tag-plugins → _style/_tag-plugins}/ghcard.styl +0 -0
  225. package/source/css/{_tag-plugins → _style/_tag-plugins}/image.styl +0 -0
  226. package/source/css/{_tag-plugins → _style/_tag-plugins}/link.styl +0 -0
  227. package/source/css/{_tag-plugins → _style/_tag-plugins}/media.styl +0 -0
  228. package/source/css/{_tag-plugins → _style/_tag-plugins}/note.styl +0 -0
  229. package/source/css/_style/_tag-plugins/sites.styl +87 -0
  230. package/source/css/{_tag-plugins → _style/_tag-plugins}/span.styl +0 -0
  231. package/source/css/_style/_tag-plugins/swiper.styl +44 -0
  232. package/source/css/{_tag-plugins → _style/_tag-plugins}/table.styl +0 -0
  233. package/source/css/{_tag-plugins → _style/_tag-plugins}/tabs.styl +0 -0
  234. package/source/css/_style/_tag-plugins/tag.json +35 -0
  235. package/source/css/_style/_tag-plugins/text.styl +31 -0
  236. package/source/css/{_tag-plugins → _style/_tag-plugins}/timeline.styl +0 -0
  237. package/source/css/_style/index.styl +8 -0
  238. package/source/css/first.styl +17 -6
  239. package/source/css/style.styl +9 -7
  240. package/source/js/app.js +1051 -278
  241. package/source/js/plugins/aplayer.js +186 -0
  242. package/source/js/plugins/parallax.js +191 -0
  243. package/source/js/plugins/rightMenu.js +577 -0
  244. package/source/js/plugins/rightMenus.js +616 -0
  245. package/source/js/plugins/tags/contributors.js +92 -0
  246. package/source/js/plugins/tags/friends.js +93 -0
  247. package/source/js/plugins/tags/sites.js +96 -0
  248. package/source/js/search/hexo.js +180 -373
  249. package/.eslintrc.json +0 -111
  250. package/layout/_meta/valinecount.ejs +0 -15
  251. package/layout/_partial/rightmenu.ejs +0 -199
  252. package/layout/_partial/scripts/cover.ejs +0 -45
  253. package/layout/_partial/scripts/darkmode.ejs +0 -85
  254. package/layout/_partial/scripts/import.ejs +0 -3
  255. package/layout/_partial/scripts/issues.ejs +0 -18
  256. package/layout/_partial/scripts/search.ejs +0 -62
  257. package/layout/_partial/snackbar.ejs +0 -22
  258. package/layout/_third-party/aplayer/script.ejs +0 -26
  259. package/layout/_third-party/clipboard/script.ejs +0 -54
  260. package/layout/_third-party/comments/disqus/layout.ejs +0 -5
  261. package/layout/_third-party/comments/disqus/script.ejs +0 -90
  262. package/layout/_third-party/comments/disqusjs/layout.ejs +0 -1
  263. package/layout/_third-party/comments/disqusjs/script.ejs +0 -34
  264. package/layout/_third-party/comments/gitalk/layout.ejs +0 -1
  265. package/layout/_third-party/comments/gitalk/script.ejs +0 -22
  266. package/layout/_third-party/comments/hashover/layout.ejs +0 -2
  267. package/layout/_third-party/comments/hashover/script.ejs +0 -1
  268. package/layout/_third-party/comments/isso/layout.ejs +0 -1
  269. package/layout/_third-party/comments/isso/script.ejs +0 -1
  270. package/layout/_third-party/comments/livere/layout.ejs +0 -3
  271. package/layout/_third-party/comments/livere/script.ejs +0 -10
  272. package/layout/_third-party/comments/minivaline/layout.ejs +0 -3
  273. package/layout/_third-party/comments/minivaline/script.ejs +0 -34
  274. package/layout/_third-party/comments/twikoo/layout.ejs +0 -3
  275. package/layout/_third-party/comments/twikoo/script.ejs +0 -32
  276. package/layout/_third-party/comments/valine/layout.ejs +0 -3
  277. package/layout/_third-party/comments/valine/script.ejs +0 -49
  278. package/layout/_third-party/comments/vssue/layout.ejs +0 -1
  279. package/layout/_third-party/comments/vssue/script.ejs +0 -21
  280. package/layout/_third-party/comments/waline/layout.ejs +0 -3
  281. package/layout/_third-party/comments/waline/script.ejs +0 -33
  282. package/layout/_third-party/fancybox/script.ejs +0 -61
  283. package/layout/_third-party/highlightjs/script.ejs +0 -11
  284. package/layout/_third-party/pjax/index.ejs +0 -78
  285. package/layout/_third-party/pjax/pdata.ejs +0 -53
  286. package/layout/_third-party/scrollreveal/script.ejs +0 -21
  287. package/layout/_third-party/tidio/script.ejs +0 -3
  288. package/layout/artitalk.ejs +0 -13
  289. package/layout/bb.ejs +0 -10
  290. package/package-lock.json +0 -916
  291. package/scripts/tags/issues.js +0 -41
  292. package/scripts/z-lazyload/index.js +0 -4
  293. package/source/css/_highlight/index.styl +0 -316
  294. package/source/css/_layout/friends.styl +0 -79
  295. package/source/css/_plugins/clipboard.styl +0 -37
  296. package/source/css/_plugins/dark.styl +0 -149
  297. package/source/css/_plugins/darkmode.styl +0 -9
  298. package/source/css/_plugins/index.styl +0 -18
  299. package/source/css/_plugins/twikoo.styl +0 -21
  300. package/source/css/_plugins/valine.styl +0 -183
  301. package/source/css/_tag-plugins/simpleuser.styl +0 -21
  302. package/source/css/_tag-plugins/site-card.styl +0 -70
  303. package/source/js/aplayer.js +0 -167
  304. package/source/js/issues.js +0 -186
  305. package/source/js/search/algolia.js +0 -344
  306. package/source/js/search/azure.js +0 -355
  307. package/source/js/search/baidu.js +0 -340
  308. package/source/js/search/google.js +0 -339
  309. package/source/js/valine.js +0 -5137
package/source/js/app.js CHANGED
@@ -1,186 +1,249 @@
1
- // 函数防抖 (只执行最后一次点击)
2
- var Debounce = (fn, t) => {
3
- const delay = t || 25;
4
- let timer;
5
- return function() {
6
- const args = arguments;
7
- if (timer) {
8
- clearTimeout(timer);
9
- }
10
- timer = setTimeout(() => {
11
- timer = null;
12
- fn.apply(this, args);
13
- },
14
- delay);
15
- };
16
- };
17
-
18
- (function($) {
19
- // 将jQuery对象缓存起来 永远不要让相同的选择器在你的代码里出现多次
20
- // 在jQuery中最快的选择器是ID选择器,尽量使用ID代替Class 时间上大约相差100倍
21
- // 在class前使用tag(标签名)
22
- // 给选择器一个上下文
23
- volantis.$bodyAnchor = $('#safearea'); // 页面主体
24
- volantis.$topBtn = $('#s-top'); // 向上
25
- volantis.$wrapper = $('#wrapper'); // 整个导航栏
26
- volantis.$postsBtn = $('.menu .active'); // 一级导航上的当前激活的按钮
27
- volantis.$titleBtn = $('h1.title', '#header-meta'); // 文章内标题
28
- volantis.$coverAnchor = $('#l_cover .cover-wrapper');
29
- volantis.$switcher = $('#l_header .switcher .s-search'); // 搜索按钮 移动端
30
- volantis.$header = $('#l_header'); // 移动端导航栏
31
- volantis.$headerMenu = $('body .navigation'); // 导航列表
32
- volantis.$search = $('#l_header .m_search'); // 搜索框 桌面端
33
- volantis.$mPhoneList = $('#l_header .m-phone .list-v'); // 手机端 子菜单
34
- const isMobile = /mobile/i.test(window.navigator.userAgent);
1
+ document.addEventListener("DOMContentLoaded", function () {
2
+ volantis.requestAnimationFrame(() => {
3
+ VolantisApp.init();
4
+ VolantisApp.subscribe();
5
+ VolantisFancyBox.init();
6
+ highlightKeyWords.startFromURL();
7
+ locationHash();
35
8
 
36
- // 校正页面定位(被导航栏挡住的区域)
37
- var scrollCorrection = 80; // (header height = 64px) + (gap = 16px)
38
- if (volantis.$header[0]) {
39
- scrollCorrection = volantis.$header[0].clientHeight + 16;
9
+ volantis.pjax.push(() => {
10
+ VolantisApp.pjaxReload();
11
+ VolantisFancyBox.init();
12
+ sessionStorage.setItem("domTitle", document.title);
13
+ highlightKeyWords.startFromURL();
14
+ }, 'app.js');
15
+ volantis.pjax.send(() => {
16
+ volantis.dom.switcher.removeClass('active'); // 关闭移动端激活的搜索框
17
+ volantis.dom.header.removeClass('z_search-open'); // 关闭移动端激活的搜索框
18
+ volantis.dom.wrapper.removeClass('sub'); // 跳转页面时关闭二级导航
19
+ volantis.EventListener.remove() // 移除事件监听器 see: layout/_partial/scripts/global.ejs
20
+ }, 'app.js');
21
+ });
22
+ });
23
+
24
+ /* 锚点定位 */
25
+ const locationHash = () => {
26
+ if (window.location.hash) {
27
+ let locationID = decodeURI(window.location.hash.split('#')[1]).replace(/\ /g, '-');
28
+ let target = document.getElementById(locationID);
29
+ if (target) {
30
+ setTimeout(() => {
31
+ if (window.location.hash.startsWith('#fn')) { // hexo-reference https://github.com/volantis-x/hexo-theme-volantis/issues/647
32
+ volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant', observer:true })
33
+ } else {
34
+ // 锚点中上半部有大片空白 高度大概是 volantis.dom.header.offsetHeight
35
+ volantis.scroll.to(target, { addTop: 5, behavior: 'instant', observer:true })
36
+ }
37
+ }, 1000)
38
+ }
40
39
  }
40
+ }
41
+ Object.freeze(locationHash);
42
+
43
+ /* Main */
44
+ const VolantisApp = (() => {
45
+ const fn = {},
46
+ COPYHTML = '<button class="btn-copy" data-clipboard-snippet=""><i class="fa-solid fa-copy"></i><span>COPY</span></button>';
47
+ let scrollCorrection = 80;
48
+
49
+ fn.init = () => {
50
+ if (volantis.dom.header) {
51
+ scrollCorrection = volantis.dom.header.clientHeight + 16;
52
+ }
41
53
 
42
- // 尝试: 重设数据值
43
- function restData() {
44
- scrollCorrection = 80;
45
- if (volantis.$header[0]) {
46
- scrollCorrection = volantis.$header[0].clientHeight + 16;
54
+ window.onresize = () => {
55
+ if (document.documentElement.clientWidth < 500) {
56
+ volantis.isMobile = 1;
57
+ } else {
58
+ volantis.isMobile = 0;
59
+ }
60
+ if (volantis.isMobile != volantis.isMobileOld) {
61
+ fn.setGlobalHeaderMenuEvent();
62
+ fn.setHeader();
63
+ fn.setHeaderSearch();
64
+ }
47
65
  }
48
- volantis.$headerMenu = $('body .navigation');
66
+ volantis.scroll.push(fn.scrollEventCallBack, "scrollEventCallBack")
49
67
  }
50
68
 
51
- // 校正页面定位(被导航栏挡住的区域)
52
- function scrolltoElement(elem, correction = scrollCorrection) {
53
- const $elem = elem.href ? $(decodeURI(elem.getAttribute('href'))) : $(elem);
54
- window.scrollTo({
55
- top : $elem.offset().top - correction,
56
- behavior: 'smooth'
69
+ fn.event = () => {
70
+ volantis.dom.$(document.getElementById("scroll-down")).on('click', function () {
71
+ fn.scrolltoElement(volantis.dom.bodyAnchor);
57
72
  });
58
- }
59
73
 
60
- // 设置滚动锚点
61
- function setScrollAnchor() {
62
- if (volantis.$postsBtn.length && volantis.$bodyAnchor) {
63
- volantis.$postsBtn.click(e => {
64
- e.preventDefault();
65
- e.stopPropagation();
66
- if (volantis.$postsBtn.attr('href') != '/') // TODO: fix it
67
- { scrolltoElement(volantis.$bodyAnchor); }
68
- e.stopImmediatePropagation();
69
- volantis.$postsBtn.unbind('click');
70
- });
74
+ // 站点信息 最后活动日期
75
+ if (volantis.GLOBAL_CONFIG.sidebar.for_page.includes('webinfo') || volantis.GLOBAL_CONFIG.sidebar.for_post.includes('webinfo')) {
76
+ const lastupd = volantis.GLOBAL_CONFIG.sidebar.webinfo.lastupd;
77
+ if (!!document.getElementById('last-update-show') && lastupd.enable && lastupd.friendlyShow) {
78
+ document.getElementById('last-update-show').innerHTML = fn.utilTimeAgo(volantis.GLOBAL_CONFIG.lastupdate);
79
+ }
71
80
  }
72
- if (volantis.$titleBtn.length && volantis.$bodyAnchor) {
73
- volantis.$titleBtn.click(e => {
74
- e.preventDefault();
75
- e.stopPropagation();
76
- scrolltoElement(volantis.$bodyAnchor);
77
- e.stopImmediatePropagation();
78
- volantis.$titleBtn.unbind('click');
79
- });
81
+
82
+ // 站点信息 运行时间
83
+ if (!!document.getElementById('webinfo-runtime-count')) {
84
+ let BirthDay = new Date(volantis.GLOBAL_CONFIG.sidebar.webinfo.runtime.data);
85
+ let timeold = (new Date().getTime() - BirthDay.getTime());
86
+ let daysold = Math.floor(timeold / (24 * 60 * 60 * 1000));
87
+ document.getElementById('webinfo-runtime-count').innerHTML = `${daysold} ${volantis.GLOBAL_CONFIG.sidebar.webinfo.runtime.unit}`;
80
88
  }
81
- if (volantis.$topBtn.length && volantis.$bodyAnchor) {
82
- volantis.$topBtn.click(e => {
83
- e.preventDefault();
84
- e.stopPropagation();
85
- scrolltoElement(volantis.$bodyAnchor);
86
- e.stopImmediatePropagation();
87
- });
89
+
90
+ // 消息提示 复制时弹出
91
+ document.body.oncopy = function () {
92
+ fn.messageCopyright()
93
+ };
94
+ }
95
+
96
+ fn.restData = () => {
97
+ scrollCorrection = volantis.dom.header ? volantis.dom.header.clientHeight + 16 : 80;
98
+ }
99
+
100
+ fn.setIsMobile = () => {
101
+ if (document.documentElement.clientWidth < 500) {
102
+ volantis.isMobile = 1;
103
+ volantis.isMobileOld = 1;
104
+ } else {
105
+ volantis.isMobile = 0;
106
+ volantis.isMobileOld = 0;
88
107
  }
108
+ }
109
+
110
+ // 校正页面定位(被导航栏挡住的区域)
111
+ fn.scrolltoElement = (elem, correction = scrollCorrection) => {
112
+ volantis.scroll.to(elem, {
113
+ top: elem.offsetTop - correction
114
+ })
115
+ }
89
116
 
90
- //==========================================
91
- var showHeaderPoint = volantis.$bodyAnchor.offset().top - scrollCorrection;
92
- var pos = document.body.scrollTop;
93
- $(document, window).scroll(Debounce(() => {
94
- const scrollTop = $(window).scrollTop(); // 滚动条距离顶部的距离
95
- const del = scrollTop - pos;
96
- pos = scrollTop;
97
- if (scrollTop > volantis.$bodyAnchor.offset().top) {
98
- volantis.$topBtn.addClass('show');
99
- if (del > 0) {
100
- volantis.$topBtn.removeClass('hl');
117
+ // 滚动事件回调们
118
+ fn.scrollEventCallBack = () => {
119
+ // 【移动端 PC】//////////////////////////////////////////////////////////////////////
120
+
121
+ // 显示/隐藏 Header导航 topBtn 【移动端 PC】
122
+ const showHeaderPoint = volantis.dom.bodyAnchor.offsetTop - scrollCorrection;
123
+ const scrollTop = volantis.scroll.getScrollTop(); // 滚动条距离顶部的距离
124
+
125
+ // topBtn
126
+ if (volantis.dom.topBtn) {
127
+ if (scrollTop > volantis.dom.bodyAnchor.offsetTop) {
128
+ volantis.dom.topBtn.addClass('show');
129
+ // 向上滚动高亮 topBtn
130
+ if (volantis.scroll.del > 0) {
131
+ volantis.dom.topBtn.removeClass('hl');
101
132
  } else {
102
- volantis.$topBtn.addClass('hl');
133
+ volantis.dom.topBtn.addClass('hl');
103
134
  }
104
135
  } else {
105
- volantis.$topBtn.removeClass('show').removeClass('hl');
136
+ volantis.dom.topBtn.removeClass('show').removeClass('hl');
106
137
  }
138
+ }
139
+
140
+ // Header导航
141
+ if (volantis.dom.header) {
107
142
  if (scrollTop - showHeaderPoint > -1) {
108
- volantis.$header.addClass('show');
143
+ volantis.dom.header.addClass('show');
109
144
  } else {
110
- volantis.$header.removeClass('show');
145
+ volantis.dom.header.removeClass('show');
111
146
  }
112
- }));
113
- //==========================================
114
- }
147
+ }
115
148
 
116
- // 设置导航栏
117
- function setHeader() {
118
- if (pdata.ispage) {
119
- window.subData = {
120
- title: pdata.postTitle,
121
- tools: true
122
- };
123
- }
124
- if (!window.subData) return;
125
- volantis.$comment = $('#s-comment'); // 评论按钮 桌面端 移动端
126
- volantis.$toc = $('#s-toc'); // 目录按钮 仅移动端
127
- volantis.$commentTarget = $('#l_body article#comments'); // 评论区域
128
- volantis.$wrapper.find('.nav-sub .title').text(window.subData.title); // 二级导航文章标题
129
- // 决定一二级导航栏的切换
130
- let pos = document.body.scrollTop;
131
- $(document, window).scroll(Debounce(() => {
132
- const scrollTop = $(window).scrollTop();
133
- const del = scrollTop - pos;
134
- if (del >= 50 && scrollTop > 100) {
135
- pos = scrollTop;
136
- volantis.$wrapper.addClass('sub');
137
- } else if (del <= -50) {
138
- pos = scrollTop;
139
- volantis.$wrapper.removeClass('sub'); // <---- 取消二级导航显示
149
+ // 决定一二级导航栏的切换 【向上滚动切换为一级导航栏;向下滚动切换为二级导航栏】 【移动端 PC】
150
+ if (pdata.ispage && volantis.dom.wrapper) {
151
+ if (volantis.scroll.del > 0 && scrollTop > 100) { // 向下滚动
152
+ volantis.dom.wrapper.addClass('sub'); // <---- 二级导航显示
153
+ } else if (volantis.scroll.del < 0) { // 向上滚动
154
+ volantis.dom.wrapper.removeClass('sub'); // <---- 取消二级导航显示 一级导航显示
155
+ }
156
+ }
157
+
158
+ // 【移动端】//////////////////////////////////////////////////////////////////////
159
+ if (volantis.isMobile) {
160
+ // 【移动端】 页面滚动 隐藏 移动端toc目录按钮
161
+ if (pdata.ispage && volantis.dom.tocTarget && volantis.dom.toc) {
162
+ volantis.dom.tocTarget.removeClass('active');
163
+ volantis.dom.toc.removeClass('active');
140
164
  }
141
- }));
165
+ // 【移动端】 滚动时隐藏子菜单
166
+ if (volantis.dom.mPhoneList) {
167
+ volantis.dom.mPhoneList.forEach(function (e) {
168
+ volantis.dom.$(e).hide();
169
+ })
170
+ }
171
+ }
172
+ }
142
173
 
143
- // bind events to every btn
144
- if (volantis.$commentTarget.length) {
145
- volantis.$comment.click(e => { // 评论按钮点击后 跳转到评论区域
174
+ // 设置滚动锚点
175
+ fn.setScrollAnchor = () => {
176
+ // click topBtn 滚动至bodyAnchor 【移动端 PC】
177
+ if (volantis.dom.topBtn && volantis.dom.bodyAnchor) {
178
+ volantis.dom.topBtn.click(e => {
146
179
  e.preventDefault();
147
180
  e.stopPropagation();
148
- scrolltoElement(volantis.$commentTarget);
181
+ fn.scrolltoElement(volantis.dom.bodyAnchor);
149
182
  e.stopImmediatePropagation();
150
183
  });
151
- } else volantis.$comment.remove(); // 关闭了评论,则隐藏
152
- volantis.$tocTarget = $('#l_body .toc-wrapper'); // 侧边栏的目录列表 PC
153
- if (volantis.$tocTarget.length && volantis.$tocTarget.children().length) {
154
- volantis.$toc.click((e) => {
155
- e.stopPropagation();
156
- volantis.$tocTarget.toggleClass('active');
157
- volantis.$toc.toggleClass('active');
158
- });
159
- $(document).click(function(e) {
184
+ }
185
+
186
+ }
187
+
188
+ // 设置导航栏
189
+ fn.setHeader = () => {
190
+ // !!! 此处的Dom对象需要重载 !!!
191
+ if (!pdata.ispage) return;
192
+
193
+ // 填充二级导航文章标题 【移动端 PC】
194
+ volantis.dom.wrapper.find('.nav-sub .title').html(document.title.split(" - ")[0]);
195
+
196
+ // ====== bind events to every btn =========
197
+ // 评论按钮 【移动端 PC】
198
+ volantis.dom.comment = volantis.dom.$(document.getElementById("s-comment")); // 评论按钮 桌面端 移动端
199
+ volantis.dom.commentTarget = volantis.dom.$(document.querySelector('#l_main article#comments')); // 评论区域
200
+ if (volantis.dom.commentTarget) {
201
+ volantis.dom.comment.click(e => { // 评论按钮点击后 跳转到评论区域
202
+ e.preventDefault();
160
203
  e.stopPropagation();
161
- volantis.$tocTarget.removeClass('active');
162
- volantis.$toc.removeClass('active');
204
+ fn.scrolltoElement(volantis.dom.commentTarget);
205
+ e.stopImmediatePropagation();
163
206
  });
164
- $(document, window).scroll(Debounce(() => {
165
- volantis.$tocTarget.removeClass('active');
166
- volantis.$toc.removeClass('active');
167
- },
168
- 100));
169
- } else volantis.$toc.remove();
207
+ } else volantis.dom.comment.style.display = 'none'; // 关闭了评论,则隐藏评论按钮
208
+
209
+ // 移动端toc目录按钮 【移动端】
210
+ if (volantis.isMobile) {
211
+ volantis.dom.toc = volantis.dom.$(document.getElementById("s-toc")); // 目录按钮 仅移动端
212
+ volantis.dom.tocTarget = volantis.dom.$(document.querySelector('#l_side .toc-wrapper')); // 侧边栏的目录列表
213
+ if (volantis.dom.tocTarget) {
214
+ // 点击移动端目录按钮 激活目录按钮 显示侧边栏的目录列表
215
+ volantis.dom.toc.click((e) => {
216
+ e.stopPropagation();
217
+ volantis.dom.tocTarget.toggleClass('active');
218
+ volantis.dom.toc.toggleClass('active');
219
+ });
220
+ // 点击空白 隐藏
221
+ volantis.dom.$(document).click(function (e) {
222
+ e.stopPropagation();
223
+ if (volantis.dom.tocTarget) {
224
+ volantis.dom.tocTarget.removeClass('active');
225
+ }
226
+ volantis.dom.toc.removeClass('active');
227
+ });
228
+ } else volantis.dom.toc.style.display = 'none'; // 隐藏toc目录按钮
229
+ }
170
230
  }
171
231
 
172
- // 设置导航栏菜单选中状态
173
- function setHeaderMenuSelection() {
232
+ // 设置导航栏菜单选中状态 【移动端 PC】
233
+ fn.setHeaderMenuSelection = () => {
234
+ // !!! 此处的Dom对象需要重载 !!!
235
+ volantis.dom.headerMenu = volantis.dom.$(document.querySelectorAll('#l_header .navigation,#l_cover .navigation,#l_side .navigation')); // 导航列表
236
+
174
237
  // 先把已经激活的取消激活
175
- volantis.$headerMenu.find('li a.active').removeClass('active');
176
- volantis.$headerMenu.find('div a.active').removeClass('active');
177
- function setUnderline($item) {
178
- if ($item && $item.length) {
179
- $item.addClass('active').siblings().removeClass('active');
180
- }
181
- }
182
- //set current active nav
183
- var $active_link = null;
238
+ volantis.dom.headerMenu.forEach(element => {
239
+ let li = volantis.dom.$(element).find('li a.active')
240
+ if (li)
241
+ li.removeClass('active')
242
+ let div = volantis.dom.$(element).find('div a.active')
243
+ if (div)
244
+ div.removeClass('active')
245
+ });
246
+
184
247
  // replace '%' '/' '.'
185
248
  var idname = location.pathname.replace(/\/|%|\./g, '');
186
249
  if (idname.length == 0) {
@@ -198,158 +261,868 @@ var Debounce = (fn, t) => {
198
261
  }
199
262
  // 转义字符如 [, ], ~, #, @
200
263
  idname = idname.replace(/(\[|\]|~|#|@)/g, '\\$1');
201
- if (idname && volantis.$headerMenu) {
202
- $active_link = $('#' + idname, volantis.$headerMenu);
203
- setUnderline($active_link);
264
+ if (idname && volantis.dom.headerMenu) {
265
+ volantis.dom.headerMenu.forEach(element => {
266
+ // idname 不能为数字开头, 加一个 action- 前缀
267
+ let id = element.querySelector("[active-action=action-" + idname + "]")
268
+ if (id) {
269
+ volantis.dom.$(id).addClass('active')
270
+ }
271
+ });
204
272
  }
205
273
  }
206
274
 
207
275
  // 设置全局事件
208
- function setGlobalHeaderMenuEvent() {
209
- if (isMobile) {
210
- // 手机端 点击展开子菜单
211
- $('#l_header .m-phone li').click(function(e) {
276
+ fn.setGlobalHeaderMenuEvent = () => {
277
+ if (volantis.isMobile) {
278
+ // 【移动端】 关闭已经展开的子菜单 点击展开子菜单
279
+ document.querySelectorAll('#l_header .m-phone li').forEach(function (e) {
280
+ if (e.querySelector(".list-v")) {
281
+ // 点击菜单
282
+ volantis.dom.$(e).click(function (e) {
283
+ e.stopPropagation();
284
+ // 关闭已经展开的子菜单
285
+ e.currentTarget.parentElement.childNodes.forEach(function (e) {
286
+ if (Object.prototype.toString.call(e) == '[object HTMLLIElement]') {
287
+ e.childNodes.forEach(function (e) {
288
+ if (Object.prototype.toString.call(e) == '[object HTMLUListElement]') {
289
+ volantis.dom.$(e).hide()
290
+ }
291
+ })
292
+ }
293
+ })
294
+ // 点击展开子菜单
295
+ let array = e.currentTarget.children
296
+ for (let index = 0; index < array.length; index++) {
297
+ const element = array[index];
298
+ if (volantis.dom.$(element).title === 'menu') { // 移动端菜单栏异常
299
+ volantis.dom.$(element).display = "flex" // https://github.com/volantis-x/hexo-theme-volantis/issues/706
300
+ } else {
301
+ volantis.dom.$(element).show()
302
+ }
303
+ }
304
+ }, 0);
305
+ }
306
+ })
307
+ } else {
308
+ // 【PC端】 hover时展开子菜单,点击时[target.baseURI==origin时]隐藏子菜单? 现有逻辑大部分情况不隐藏子菜单
309
+ document.querySelectorAll('#wrapper .m-pc li > a[href]').forEach(function (e) {
310
+ volantis.dom.$(e.parentElement).click(function (e) {
311
+ e.stopPropagation();
312
+ if (e.target.origin == e.target.baseURI) {
313
+ document.querySelectorAll('#wrapper .m-pc .list-v').forEach(function (e) {
314
+ volantis.dom.$(e).hide(); // 大概率不会执行
315
+ })
316
+ }
317
+ }, 0);
318
+ })
319
+ }
320
+ fn.setPageHeaderMenuEvent();
321
+ }
322
+
323
+ // 【移动端】隐藏子菜单
324
+ fn.setPageHeaderMenuEvent = () => {
325
+ if (!volantis.isMobile) return
326
+ // 【移动端】 点击空白处隐藏子菜单
327
+ volantis.dom.$(document).click(function (e) {
328
+ volantis.dom.mPhoneList.forEach(function (e) {
329
+ volantis.dom.$(e).hide();
330
+ })
331
+ });
332
+ }
333
+
334
+ // 设置导航栏搜索框 【移动端】
335
+ fn.setHeaderSearch = () => {
336
+ if (!volantis.isMobile) return;
337
+ if (!volantis.dom.switcher) return;
338
+ // 点击移动端搜索按钮
339
+ volantis.dom.switcher.click(function (e) {
340
+ e.stopPropagation();
341
+ volantis.dom.header.toggleClass('z_search-open'); // 激活移动端搜索框
342
+ volantis.dom.switcher.toggleClass('active'); // 移动端搜索按钮
343
+ }, false); // false : pjax 不移除监听
344
+ // 点击空白取消激活
345
+ volantis.dom.$(document).click(function (e) {
346
+ volantis.dom.header.removeClass('z_search-open');
347
+ volantis.dom.switcher.removeClass('active');
348
+ }, false); // false : pjax 不移除监听
349
+ // 移动端点击搜索框 停止事件传播
350
+ volantis.dom.search.click(function (e) {
351
+ e.stopPropagation();
352
+ }, false); // false : pjax 不移除监听
353
+ }
354
+
355
+ // 设置 tabs 标签 【移动端 PC】
356
+ fn.setTabs = () => {
357
+ let tabs = document.querySelectorAll('#l_main .tabs .nav-tabs')
358
+ if (!tabs) return
359
+ tabs.forEach(function (e) {
360
+ e.querySelectorAll('a').forEach(function (e) {
361
+ volantis.dom.$(e).on('click', (e) => {
362
+ e.preventDefault();
363
+ e.stopPropagation();
364
+ const $tab = volantis.dom.$(e.target.parentElement.parentElement.parentElement);
365
+ $tab.find('.nav-tabs .active').removeClass('active');
366
+ volantis.dom.$(e.target.parentElement).addClass('active');
367
+ $tab.find('.tab-content .active').removeClass('active');
368
+ $tab.find(e.target.className).addClass('active');
369
+ return false;
370
+ });
371
+ })
372
+ })
373
+ }
374
+
375
+ // hexo-reference 页脚跳转 https://github.com/volantis-x/hexo-theme-volantis/issues/647
376
+ fn.footnotes = () => {
377
+ let ref = document.querySelectorAll('#l_main .footnote-backref, #l_main .footnote-ref > a');
378
+ ref.forEach(function (e, i) {
379
+ ref[i].click = () => { }; // 强制清空原 click 事件
380
+ volantis.dom.$(e).on('click', (e) => {
212
381
  e.stopPropagation();
213
- $($(e.currentTarget).children('ul')).show();
382
+ e.preventDefault();
383
+ let targetID = decodeURI(e.target.hash.split('#')[1]).replace(/\ /g, '-');
384
+ let target = document.getElementById(targetID);
385
+ if (target) {
386
+ volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' })
387
+ }
214
388
  });
215
- } else {
216
- // PC端 hover时展开子菜单,点击时隐藏子菜单
217
- $('#wrapper .m-pc li > a[href]').parent().click(function(e) {
389
+ })
390
+ }
391
+
392
+ // 工具类:代码块复制
393
+ fn.utilCopyCode = (Selector) => {
394
+ document.querySelectorAll(Selector).forEach(node => {
395
+ const test = node.insertAdjacentHTML("beforebegin", COPYHTML);
396
+ const _BtnCopy = node.previousSibling;
397
+ _BtnCopy.onclick = e => {
218
398
  e.stopPropagation();
219
- if (e.target.origin == e.target.baseURI) {
220
- $('#wrapper .m-pc .list-v').hide();
399
+ const _icon = _BtnCopy.querySelector('i');
400
+ const _span = _BtnCopy.querySelector('span');
401
+
402
+ node.focus();
403
+ const range = new Range();
404
+ range.selectNodeContents(node);
405
+ document.getSelection().removeAllRanges();
406
+ document.getSelection().addRange(range);
407
+
408
+ const str = document.getSelection().toString();
409
+ fn.utilWriteClipText(str).then(() => {
410
+ fn.messageCopyright();
411
+ _BtnCopy.classList.add('copied');
412
+ _icon.classList.remove('fa-copy');
413
+ _icon.classList.add('fa-check-circle');
414
+ _span.innerText = "COPIED";
415
+ setTimeout(() => {
416
+ _icon.classList.remove('fa-check-circle');
417
+ _icon.classList.add('fa-copy');
418
+ _span.innerText = "COPY";
419
+ }, 2000)
420
+ }).catch(e => {
421
+ VolantisApp.message('系统提示', e, {
422
+ icon: 'fa fa-exclamation-circle red'
423
+ });
424
+ _BtnCopy.classList.add('copied-failed');
425
+ _icon.classList.remove('fa-copy');
426
+ _icon.classList.add('fa-exclamation-circle');
427
+ _span.innerText = "COPY FAILED";
428
+ setTimeout(() => {
429
+ _icon.classList.remove('fa-exclamation-circle');
430
+ _icon.classList.add('fa-copy');
431
+ _span.innerText = "COPY";
432
+ })
433
+ })
434
+ }
435
+ });
436
+ }
437
+
438
+ // 工具类:复制字符串到剪切板
439
+ fn.utilWriteClipText = (str) => {
440
+ return navigator.clipboard
441
+ .writeText(str)
442
+ .then(() => {
443
+ return Promise.resolve()
444
+ })
445
+ .catch(e => {
446
+ const input = document.createElement('textarea');
447
+ input.setAttribute('readonly', 'readonly');
448
+ document.body.appendChild(input);
449
+ input.innerHTML = str;
450
+ input.select();
451
+ try {
452
+ let result = document.execCommand('copy')
453
+ document.body.removeChild(input);
454
+ if (!result || result === 'unsuccessful') {
455
+ return Promise.reject('复制文本失败!')
456
+ } else {
457
+ return Promise.resolve()
458
+ }
459
+ } catch (e) {
460
+ document.body.removeChild(input);
461
+ return Promise.reject(
462
+ '当前浏览器不支持复制功能,请检查更新或更换其他浏览器操作!'
463
+ )
464
+ }
465
+ })
466
+ }
467
+
468
+ // 工具类:返回时间间隔
469
+ fn.utilTimeAgo = (dateTimeStamp) => {
470
+ const minute = 1e3 * 60, hour = minute * 60, day = hour * 24, week = day * 7, month = day * 30;
471
+ const now = new Date().getTime();
472
+ const diffValue = now - dateTimeStamp;
473
+ const minC = diffValue / minute,
474
+ hourC = diffValue / hour,
475
+ dayC = diffValue / day,
476
+ weekC = diffValue / week,
477
+ monthC = diffValue / month;
478
+ if (diffValue < 0) {
479
+ result = ""
480
+ } else if (monthC >= 1 && monthC < 7) {
481
+ result = " " + parseInt(monthC) + " 月前"
482
+ } else if (weekC >= 1 && weekC < 4) {
483
+ result = " " + parseInt(weekC) + " 周前"
484
+ } else if (dayC >= 1 && dayC < 7) {
485
+ result = " " + parseInt(dayC) + " 天前"
486
+ } else if (hourC >= 1 && hourC < 24) {
487
+ result = " " + parseInt(hourC) + " 小时前"
488
+ } else if (minC >= 1 && minC < 60) {
489
+ result = " " + parseInt(minC) + " 分钟前"
490
+ } else if (diffValue >= 0 && diffValue <= minute) {
491
+ result = "刚刚"
492
+ } else {
493
+ const datetime = new Date();
494
+ datetime.setTime(dateTimeStamp);
495
+ const Nyear = datetime.getFullYear();
496
+ const Nmonth = datetime.getMonth() + 1 < 10 ? "0" + (datetime.getMonth() + 1) : datetime.getMonth() + 1;
497
+ const Ndate = datetime.getDate() < 10 ? "0" + datetime.getDate() : datetime.getDate();
498
+ const Nhour = datetime.getHours() < 10 ? "0" + datetime.getHours() : datetime.getHours();
499
+ const Nminute = datetime.getMinutes() < 10 ? "0" + datetime.getMinutes() : datetime.getMinutes();
500
+ const Nsecond = datetime.getSeconds() < 10 ? "0" + datetime.getSeconds() : datetime.getSeconds();
501
+ result = Nyear + "-" + Nmonth + "-" + Ndate
502
+ }
503
+ return result;
504
+ }
505
+
506
+ // 消息提示:标准
507
+ fn.message = (title, message, option = {}, done = null) => {
508
+ if (typeof iziToast === "undefined") {
509
+ volantis.css(volantis.GLOBAL_CONFIG.plugins.message.css)
510
+ volantis.js(volantis.GLOBAL_CONFIG.plugins.message.js, () => {
511
+ tozashMessage(title, message, option, done);
512
+ });
513
+ } else {
514
+ tozashMessage(title, message, option, done);
515
+ }
516
+ function tozashMessage(title, message, option, done) {
517
+ const {
518
+ icon,
519
+ time,
520
+ position,
521
+ transitionIn,
522
+ transitionOut,
523
+ messageColor,
524
+ titleColor,
525
+ backgroundColor,
526
+ zindex,
527
+ displayMode
528
+ } = option;
529
+ iziToast.show({
530
+ layout: '2',
531
+ icon: 'Fontawesome',
532
+ closeOnEscape: 'true',
533
+ displayMode: displayMode || 'replace',
534
+ transitionIn: transitionIn || volantis.GLOBAL_CONFIG.plugins.message.transitionIn,
535
+ transitionOut: transitionOut || volantis.GLOBAL_CONFIG.plugins.message.transitionOut,
536
+ messageColor: messageColor || volantis.GLOBAL_CONFIG.plugins.message.messageColor,
537
+ titleColor: titleColor || volantis.GLOBAL_CONFIG.plugins.message.titleColor,
538
+ backgroundColor: backgroundColor || volantis.GLOBAL_CONFIG.plugins.message.backgroundColor,
539
+ zindex: zindex || volantis.GLOBAL_CONFIG.plugins.message.zindex,
540
+ icon: icon || volantis.GLOBAL_CONFIG.plugins.message.icon.default,
541
+ timeout: time || volantis.GLOBAL_CONFIG.plugins.message.time.default,
542
+ position: position || volantis.GLOBAL_CONFIG.plugins.message.position,
543
+ title: title,
544
+ message: message,
545
+ onClosed: () => {
546
+ if (done) done();
547
+ },
548
+ });
549
+ }
550
+ }
551
+
552
+ // 消息提示:询问
553
+ fn.question = (title, message, option = {}, success = null, cancel = null, done = null) => {
554
+ if (typeof iziToast === "undefined") {
555
+ volantis.css(volantis.GLOBAL_CONFIG.plugins.message.css)
556
+ volantis.js(volantis.GLOBAL_CONFIG.plugins.message.js, () => {
557
+ tozashQuestion(title, message, option, success, cancel, done);
558
+ });
559
+ } else {
560
+ tozashQuestion(title, message, option, success, cancel, done);
561
+ }
562
+
563
+ function tozashQuestion(title, message, option, success, cancel, done) {
564
+ const {
565
+ icon,
566
+ time,
567
+ position,
568
+ transitionIn,
569
+ transitionOut,
570
+ messageColor,
571
+ titleColor,
572
+ backgroundColor,
573
+ zindex
574
+ } = option;
575
+ iziToast.question({
576
+ id: 'question',
577
+ icon: 'Fontawesome',
578
+ close: false,
579
+ overlay: true,
580
+ displayMode: 'once',
581
+ position: 'center',
582
+ messageColor: messageColor || volantis.GLOBAL_CONFIG.plugins.message.messageColor,
583
+ titleColor: titleColor || volantis.GLOBAL_CONFIG.plugins.message.titleColor,
584
+ backgroundColor: backgroundColor || volantis.GLOBAL_CONFIG.plugins.message.backgroundColor,
585
+ zindex: zindex || volantis.GLOBAL_CONFIG.plugins.message.zindex,
586
+ icon: icon || volantis.GLOBAL_CONFIG.plugins.message.icon.quection,
587
+ timeout: time || volantis.GLOBAL_CONFIG.plugins.message.time.quection,
588
+ title: title,
589
+ message: message,
590
+ buttons: [
591
+ ['<button><b>是</b></button>', (instance, toast) => {
592
+ instance.hide({ transitionOut: transitionOut || 'fadeOut' }, toast, 'button');
593
+ if (success) success(instance, toast)
594
+ }],
595
+ ['<button><b>否</b></button>', (instance, toast) => {
596
+ instance.hide({ transitionOut: transitionOut || 'fadeOut' }, toast, 'button');
597
+ if (cancel) cancel(instance, toast)
598
+ }]
599
+ ],
600
+ onClosed: (instance, toast, closedBy) => {
601
+ if (done) done(instance, toast, closedBy);
221
602
  }
222
603
  });
223
604
  }
224
- setPageHeaderMenuEvent();
225
605
  }
226
606
 
227
- function setPageHeaderMenuEvent() {
228
- if (!isMobile) return;
229
- // 手机端 点击空白处隐藏子菜单
230
- $(document).click(function(e) {
231
- volantis.$mPhoneList.hide();
232
- });
233
- // 手机端 滚动时隐藏子菜单
234
- $(window).scroll(Debounce(() => {
235
- volantis.$mPhoneList.hide();
236
- }));
237
- }
238
- // 设置导航栏搜索框 fix √
239
- function setHeaderSearch() {
240
- if (volantis.$switcher.length === 0) return;
241
- volantis.$switcher.click(function(e) {
242
- e.stopPropagation();
243
- volantis.$header.toggleClass('z_search-open'); // 激活移动端搜索框
244
- volantis.$switcher.toggleClass('active'); // 搜索按钮
245
- volantis.$search.find('input').focus();
246
- });
247
- $(document).click(function(e) {
248
- volantis.$header.removeClass('z_search-open');
249
- volantis.$switcher.removeClass('active');
250
- });
607
+ // 消息提示:隐藏
608
+ fn.hideMessage = (done = null) => {
609
+ const toast = document.querySelector('.iziToast');
610
+ if (!toast) {
611
+ if (done) done()
612
+ return;
613
+ }
251
614
 
252
- volantis.$search.click(function(e) {
253
- e.stopPropagation();
615
+ if (typeof iziToast === "undefined") {
616
+ volantis.css(volantis.GLOBAL_CONFIG.plugins.message.css)
617
+ volantis.js(volantis.GLOBAL_CONFIG.plugins.message.js, () => {
618
+ hideMessage(done);
619
+ });
620
+ } else {
621
+ hideMessage(done);
622
+ }
623
+
624
+ function hideMessage(done) {
625
+ iziToast.hide({}, toast);
626
+ if (done) done();
627
+ }
628
+ }
629
+
630
+ // 消息提示:复制
631
+ let messageCopyrightShow = 0;
632
+ fn.messageCopyright = () => {
633
+ // 消息提示 复制时弹出
634
+ if (volantis.GLOBAL_CONFIG.plugins.message.enable
635
+ && volantis.GLOBAL_CONFIG.plugins.message.copyright.enable
636
+ && messageCopyrightShow < 1) {
637
+ messageCopyrightShow++;
638
+ VolantisApp.message(volantis.GLOBAL_CONFIG.plugins.message.copyright.title,
639
+ volantis.GLOBAL_CONFIG.plugins.message.copyright.message, {
640
+ icon: volantis.GLOBAL_CONFIG.plugins.message.copyright.icon,
641
+ transitionIn: 'flipInX',
642
+ transitionOut: 'flipOutX',
643
+ displayMode: 1
644
+ });
645
+ }
646
+ }
647
+
648
+ return {
649
+ init: () => {
650
+ fn.init();
651
+ fn.event();
652
+ },
653
+ subscribe: () => {
654
+ fn.setIsMobile();
655
+ fn.setHeader();
656
+ fn.setHeaderMenuSelection();
657
+ fn.setGlobalHeaderMenuEvent();
658
+ fn.setHeaderSearch();
659
+ fn.setScrollAnchor();
660
+ fn.setTabs();
661
+ fn.footnotes();
662
+ },
663
+ pjaxReload: () => {
664
+ fn.event();
665
+ fn.restData();
666
+ fn.setHeader();
667
+ fn.setHeaderMenuSelection();
668
+ fn.setPageHeaderMenuEvent();
669
+ fn.setScrollAnchor();
670
+ fn.setTabs();
671
+ fn.footnotes();
672
+
673
+ // 移除小尾巴的移除
674
+ document.querySelector("#l_header .nav-main").querySelectorAll('.list-v:not(.menu-phone)').forEach(function (e) {
675
+ e.removeAttribute("style")
676
+ })
677
+ document.querySelector("#l_header .menu-phone.list-v").removeAttribute("style");
678
+ messageCopyrightShow = 0;
679
+ },
680
+ utilCopyCode: fn.utilCopyCode,
681
+ utilWriteClipText: fn.utilWriteClipText,
682
+ utilTimeAgo: fn.utilTimeAgo,
683
+ message: fn.message,
684
+ question: fn.question,
685
+ hideMessage: fn.hideMessage,
686
+ messageCopyright: fn.messageCopyright,
687
+ scrolltoElement: fn.scrolltoElement
688
+ }
689
+ })()
690
+ Object.freeze(VolantisApp);
691
+
692
+ /* FancyBox */
693
+ const VolantisFancyBox = (() => {
694
+ const fn = {};
695
+
696
+ fn.loadFancyBox = (done) => {
697
+ volantis.css(volantis.GLOBAL_CONFIG.plugins.fancybox.css);
698
+ volantis.js(volantis.GLOBAL_CONFIG.plugins.fancybox.js).then(() => {
699
+ if (done) done();
700
+ })
701
+ }
702
+
703
+ /**
704
+ * 加载及处理
705
+ *
706
+ * @param {*} checkMain 是否只处理文章区域的文章
707
+ * @param {*} done FancyBox 加载完成后的动作,默认执行分组绑定
708
+ * @returns
709
+ */
710
+ fn.init = (checkMain = true, done = fn.groupBind) => {
711
+ if (!document.querySelector(".md .gallery img, .fancybox") && checkMain) return;
712
+ if (typeof Fancybox === "undefined") {
713
+ fn.loadFancyBox(done);
714
+ } else {
715
+ done();
716
+ }
717
+ }
718
+
719
+ /**
720
+ * 图片元素预处理
721
+ *
722
+ * @param {*} selectors 选择器
723
+ * @param {*} name 分组
724
+ */
725
+ fn.elementHandling = (selectors, name) => {
726
+ const nodeList = document.querySelectorAll(selectors);
727
+ nodeList.forEach($item => {
728
+ if ($item.hasAttribute('fancybox')) return;
729
+ $item.setAttribute('fancybox', '');
730
+ const $link = document.createElement('a');
731
+ $link.setAttribute('href', $item.src);
732
+ $link.setAttribute('data-caption', $item.alt);
733
+ $link.setAttribute('data-fancybox', name);
734
+ $link.classList.add('fancybox');
735
+ $link.append($item.cloneNode());
736
+ $item.replaceWith($link);
737
+ })
738
+ }
739
+
740
+ /**
741
+ * 原生绑定
742
+ *
743
+ * @param {*} selectors 选择器
744
+ */
745
+ fn.bind = (selectors) => {
746
+ fn.init(false, () => {
747
+ Fancybox.bind(selectors, {
748
+ groupAll: true,
749
+ Hash: false,
750
+ hideScrollbar: false,
751
+ Thumbs: {
752
+ autoStart: false,
753
+ },
754
+ caption: function (fancybox, carousel, slide) {
755
+ return slide.$trigger.alt || null
756
+ }
757
+ });
254
758
  });
255
- volantis.$header.ready(function() {
256
- volantis.$header.bind('keydown',
257
- function(event) {
258
- if (event.keyCode == 9) {
259
- return false;
260
- }
261
- var isie = !!document.all;
262
- var key,ev;
263
- if (isie) { //IE浏览器
264
- key = window.event.keyCode;
265
- ev = window.event;
266
- } else { //火狐浏览器
267
- key = event.which;
268
- ev = event;
269
- }
270
- if (key == 9) { //IE浏览器
271
- if (isie) {
272
- ev.keyCode = 0;
273
- ev.returnValue = false;
274
- } else { //火狐浏览器
275
- ev.which = 0;
276
- ev.preventDefault();
277
- }
278
- }
759
+ }
760
+
761
+ /**
762
+ * 分组绑定
763
+ *
764
+ * @param {*} groupName 分组名称
765
+ */
766
+ fn.groupBind = (groupName = null) => {
767
+ const group = new Set();
768
+
769
+ document.querySelectorAll(".gallery").forEach(ele => {
770
+ if (ele.querySelector("img")) {
771
+ group.add(ele.getAttribute('data-group') || 'default');
772
+ }
773
+ })
774
+
775
+ if (!!groupName) group.add(groupName);
776
+
777
+ for (const iterator of group) {
778
+ Fancybox.unbind('[data-fancybox="' + iterator + '"]');
779
+ Fancybox.bind('[data-fancybox="' + iterator + '"]', {
780
+ Hash: false,
781
+ hideScrollbar: false,
782
+ Thumbs: {
783
+ autoStart: false,
784
+ }
785
+ });
786
+ }
787
+ }
279
788
 
789
+ return {
790
+ init: fn.init,
791
+ bind: fn.bind,
792
+ groupBind: (selectors, groupName = 'default') => {
793
+ try {
794
+ fn.elementHandling(selectors, groupName);
795
+ fn.init(false, () => {
796
+ fn.groupBind(groupName)
280
797
  });
281
- });
798
+ } catch (error) {
799
+ console.error(error)
800
+ }
801
+ }
282
802
  }
803
+ })()
804
+ Object.freeze(VolantisFancyBox);
283
805
 
284
- // 设置 tabs 标签
285
- function setTabs() {
286
- $('.tabs .nav-tabs').on('click', 'a', (e) => {
287
- e.preventDefault();
288
- e.stopPropagation();
289
- const $tab = $(e.target.parentElement.parentElement.parentElement);
290
- $tab.find('.nav-tabs .active').removeClass('active');
291
- $tab.find(e.target.parentElement).addClass('active');
292
- $tab.find('.tab-content .active').removeClass('active');
293
- $tab.find($(e.target).attr('class')).addClass('active');
294
- return false;
806
+ // highlightKeyWords 搜索功能搭配 https://github.com/next-theme/hexo-theme-next/blob/eb194a7258058302baf59f02d4b80b6655338b01/source/js/third-party/search/local-search.js
807
+ // Question: 锚点稳定性未知
808
+ // ToDo: 查找模式
809
+ // 0. (/////////要知道浏览器自带全页面查找功能 CTRL + F)
810
+ // 1. 右键开启查找模式 / 导航栏菜单开启?? / CTRL + F ???
811
+ // 2. 查找模式面板 (可拖动? or 固定?)
812
+ // 3. keyword mark id 从 0 开始编号 查找下一处 highlightKeyWords.scrollToNextHighlightKeywordMark() 查找上一处 scrollToPrevHighlightKeywordMark() 循环查找(取模%)
813
+ // 4. 可输入修改 查找关键词 keywords(type:list)
814
+ // 5. 区分大小写 caseSensitive (/ 全字匹配?? / 正则匹配??)
815
+ // 6. 在选定区域中查找 querySelector ??
816
+ // 7. 关闭查找模式
817
+ // 8. 搜索跳转 (URL 入口) 自动开启查找模式 调用 scrollToNextHighlightKeywordMark()
818
+ const highlightKeyWords = (() => {
819
+ let fn = {}
820
+ fn.markNum = 0
821
+ fn.markNextId = -1
822
+ fn.startFromURL = () => {
823
+ const params = decodeURI(new URL(location.href).searchParams.get('keyword'));
824
+ const keywords = params ? params.split(' ') : [];
825
+ const post = document.querySelector('#l_main');
826
+ if (keywords.length == 1 && keywords[0] == "null") {
827
+ return;
828
+ }
829
+ fn.start(keywords, post); // 渲染耗时较长
830
+ fn.scrollToFirstHighlightKeywordMark()
831
+ }
832
+ fn.scrollToFirstHighlightKeywordMark = () => {
833
+ volantis.cleanContentVisibility();
834
+ let target = fn.scrollToNextHighlightKeywordMark("0");
835
+ if (!target) {
836
+ volantis.requestAnimationFrame(fn.scrollToFirstHighlightKeywordMark)
837
+ }
838
+ }
839
+ fn.scrollToNextHighlightKeywordMark = (id) => {
840
+ // Next Id
841
+ let input = id || (fn.markNextId + 1) % fn.markNum;
842
+ fn.markNextId = parseInt(input)
843
+ let target = document.getElementById("keyword-mark-" + fn.markNextId);
844
+ if (!target) {
845
+ fn.markNextId = (fn.markNextId + 1) % fn.markNum;
846
+ target = document.getElementById("keyword-mark-" + fn.markNextId);
847
+ }
848
+ if (target) {
849
+ volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' })
850
+ }
851
+ // Current target
852
+ return target
853
+ }
854
+ fn.scrollToPrevHighlightKeywordMark = (id) => {
855
+ // Prev Id
856
+ let input = id || (fn.markNextId - 1 + fn.markNum) % fn.markNum;
857
+ fn.markNextId = parseInt(input)
858
+ let target = document.getElementById("keyword-mark-" + fn.markNextId);
859
+ if (!target) {
860
+ fn.markNextId = (fn.markNextId - 1 + fn.markNum) % fn.markNum;
861
+ target = document.getElementById("keyword-mark-" + fn.markNextId);
862
+ }
863
+ if (target) {
864
+ volantis.scroll.to(target, { addTop: - volantis.dom.header.offsetHeight - 5, behavior: 'instant' })
865
+ }
866
+ // Current target
867
+ return target
868
+ }
869
+ fn.start = (keywords, querySelector) => {
870
+ fn.markNum = 0
871
+ if (!keywords.length || !querySelector || (keywords.length == 1 && keywords[0] == "null")) return;
872
+ console.log(keywords);
873
+ const walk = document.createTreeWalker(querySelector, NodeFilter.SHOW_TEXT, null);
874
+ const allNodes = [];
875
+ while (walk.nextNode()) {
876
+ if (!walk.currentNode.parentNode.matches('button, select, textarea')) allNodes.push(walk.currentNode);
877
+ }
878
+ allNodes.forEach(node => {
879
+ const [indexOfNode] = fn.getIndexByWord(keywords, node.nodeValue);
880
+ if (!indexOfNode.length) return;
881
+ const slice = fn.mergeIntoSlice(0, node.nodeValue.length, indexOfNode);
882
+ fn.highlightText(node, slice, 'keyword');
883
+ fn.highlightStyle()
295
884
  });
296
885
  }
886
+ fn.getIndexByWord = (words, text, caseSensitive = false) => {
887
+ const index = [];
888
+ const included = new Set();
889
+ words.forEach(word => {
890
+ const div = document.createElement('div');
891
+ div.innerText = word;
892
+ word = div.innerHTML;
297
893
 
298
- $(function() {
299
- setHeader();
300
- setHeaderMenuSelection();
301
- setGlobalHeaderMenuEvent();
302
- setHeaderSearch();
303
- setScrollAnchor();
304
- setTabs();
894
+ const wordLen = word.length;
895
+ if (wordLen === 0) return;
896
+ let startPosition = 0;
897
+ let position = -1;
898
+ if (!caseSensitive) {
899
+ text = text.toLowerCase();
900
+ word = word.toLowerCase();
901
+ }
902
+ while ((position = text.indexOf(word, startPosition)) > -1) {
903
+ index.push({ position, word });
904
+ included.add(word);
905
+ startPosition = position + wordLen;
906
+ }
907
+ });
908
+ index.sort((left, right) => {
909
+ if (left.position !== right.position) {
910
+ return left.position - right.position;
911
+ }
912
+ return right.word.length - left.word.length;
913
+ });
914
+ return [index, included];
915
+ };
916
+ fn.mergeIntoSlice = (start, end, index) => {
917
+ let item = index[0];
918
+ let { position, word } = item;
919
+ const hits = [];
920
+ const count = new Set();
921
+ while (position + word.length <= end && index.length !== 0) {
922
+ count.add(word);
923
+ hits.push({
924
+ position,
925
+ length: word.length
926
+ });
927
+ const wordEnd = position + word.length;
305
928
 
306
- // 全屏封面底部箭头
307
- $('#scroll-down').on('click', function() {
308
- scrolltoElement(volantis.$bodyAnchor);
929
+ index.shift();
930
+ while (index.length !== 0) {
931
+ item = index[0];
932
+ position = item.position;
933
+ word = item.word;
934
+ if (wordEnd > position) {
935
+ index.shift();
936
+ } else {
937
+ break;
938
+ }
939
+ }
940
+ }
941
+ return {
942
+ hits,
943
+ start,
944
+ end,
945
+ count: count.size
946
+ };
947
+ };
948
+ fn.highlightText = (node, slice, className) => {
949
+ const val = node.nodeValue;
950
+ let index = slice.start;
951
+ const children = [];
952
+ for (const { position, length } of slice.hits) {
953
+ const text = document.createTextNode(val.substring(index, position));
954
+ index = position + length;
955
+ let mark = document.createElement('mark');
956
+ mark.className = className;
957
+ mark = fn.highlightStyle(mark)
958
+ mark.appendChild(document.createTextNode(val.substr(position, length)));
959
+ children.push(text, mark);
960
+ }
961
+ node.nodeValue = val.substring(index, slice.end);
962
+ children.forEach(element => {
963
+ node.parentNode.insertBefore(element, node);
309
964
  });
965
+ }
966
+ fn.highlightStyle = (mark) => {
967
+ if (!mark) return;
968
+ mark.id = "keyword-mark-" + fn.markNum;
969
+ fn.markNum++;
970
+ mark.style.background = "transparent";
971
+ mark.style["border-bottom"] = "1px dashed #ff2a2a";
972
+ mark.style["color"] = "#ff2a2a";
973
+ mark.style["font-weight"] = "bold";
974
+ return mark
975
+ }
976
+ fn.cleanHighlightStyle = () => {
977
+ document.querySelectorAll(".keyword").forEach(mark => {
978
+ mark.style.background = "transparent";
979
+ mark.style["border-bottom"] = null;
980
+ mark.style["color"] = null;
981
+ mark.style["font-weight"] = null;
982
+ })
983
+ }
984
+ return {
985
+ start: (keywords, querySelector) => {
986
+ fn.start(keywords, querySelector)
987
+ },
988
+ startFromURL: () => {
989
+ fn.startFromURL()
990
+ },
991
+ scrollToNextHighlightKeywordMark: (id) => {
992
+ fn.scrollToNextHighlightKeywordMark(id)
993
+ },
994
+ scrollToPrevHighlightKeywordMark: (id) => {
995
+ fn.scrollToPrevHighlightKeywordMark(id)
996
+ },
997
+ cleanHighlightStyle: () => {
998
+ fn.cleanHighlightStyle()
999
+ },
1000
+ }
1001
+ })()
1002
+ Object.freeze(highlightKeyWords);
310
1003
 
311
- try {
312
- // addEventListener是先绑定先执行,此处的绑定后执行
313
- document.addEventListener('pjax:complete',
314
- function() {
315
- $(function() {
316
- restData();
317
- setHeader();
318
- setHeaderMenuSelection();
319
- setPageHeaderMenuEvent();
320
- setScrollAnchor();
321
- setTabs();
322
- // 全屏封面底部箭头
323
- $('#scroll-down').on('click', function() {
324
- scrolltoElement(volantis.$bodyAnchor);
325
- });
326
- // 处理点击事件 setHeaderSearch 没有重载,需要重新绑定单个事件
327
- if (volantis.$switcher.length !== 0) {
328
- $(document).click(function(e) {
329
- volantis.$header.removeClass('z_search-open');
330
- volantis.$switcher.removeClass('active');
331
- });
332
- }
333
- });
1004
+ /* DOM 控制 */
1005
+ const DOMController = {
1006
+ /**
1007
+ * 控制元素显隐
1008
+ */
1009
+ visible: (ele, type = true) => {
1010
+ if (ele) ele.style.display = type === true ? 'block' : 'none';
1011
+ },
1012
+
1013
+ /**
1014
+ * 移除元素
1015
+ */
1016
+ remove: (param) => {
1017
+ const node = document.querySelectorAll(param);
1018
+ node.forEach(ele => {
1019
+ ele.remove();
1020
+ })
1021
+ },
1022
+
1023
+ removeList: (list) => {
1024
+ list.forEach(param => {
1025
+ DOMController.remove(param)
1026
+ })
1027
+ },
1028
+
1029
+ /**
1030
+ * 设置属性
1031
+ */
1032
+ setAttribute: (param, attrName, attrValue) => {
1033
+ const node = document.querySelectorAll(param);
1034
+ node.forEach(ele => {
1035
+ ele.setAttribute(attrName, attrValue)
1036
+ })
1037
+ },
1038
+
1039
+ setAttributeList: (list) => {
1040
+ list.forEach(item => {
1041
+ DOMController.setAttribute(item[0], item[1], item[2])
1042
+ })
1043
+ },
1044
+
1045
+ /**
1046
+ * 设置样式
1047
+ */
1048
+ setStyle: (param, styleName, styleValue) => {
1049
+ const node = document.querySelectorAll(param);
1050
+ node.forEach(ele => {
1051
+ ele.style[styleName] = styleValue;
1052
+ })
1053
+ },
1054
+
1055
+ setStyleList: (list) => {
1056
+ list.forEach(item => {
1057
+ DOMController.setStyle(item[0], item[1], item[2])
1058
+ })
1059
+ },
334
1060
 
335
- }, {passive: true});
336
- } catch (error) {
337
- // console.log(error);
1061
+ fadeIn: (e) => {
1062
+ if (!e) return;
1063
+ e.style.visibility = "visible";
1064
+ e.style.opacity = 1;
1065
+ e.style.display = "block";
1066
+ e.style.transition = "all 0.5s linear";
1067
+ return e
1068
+ },
1069
+
1070
+ fadeOut: (e) => {
1071
+ if (!e) return;
1072
+ e.style.visibility = "hidden";
1073
+ e.style.opacity = 0;
1074
+ e.style.display = "none";
1075
+ e.style.transition = "all 0.5s linear";
1076
+ return e
1077
+ },
1078
+
1079
+ fadeToggle: (e) => {
1080
+ if (!e) return;
1081
+ if (e.style.visibility == "hidden") {
1082
+ e = DOMController.fadeIn(e)
1083
+ } else {
1084
+ e = DOMController.fadeOut(e)
338
1085
  }
1086
+ return e
1087
+ },
339
1088
 
340
- });
1089
+ fadeToggleList: (list) => {
1090
+ list.forEach(param => {
1091
+ DOMController.fadeToggle(param)
1092
+ })
1093
+ },
341
1094
 
342
- /*锚点定位*/
343
- if (window.location.hash) {
344
- var checkExist = setInterval(function() {
345
- if ($('#' + decodeURI(window.location.hash.split('#')[1]).replace(/\ /g, '-')).length) {
346
- $('html, body').animate({
347
- scrollTop: $('#' + decodeURI(window.location.hash.split('#')[1]).replace(/\ /g, '-')).offset().top - 40
348
- },
349
- 500);
350
- clearInterval(checkExist);
351
- }
352
- },
353
- 100);
1095
+ hasClass: (e, c) => {
1096
+ if (!e) return;
1097
+ return e.className.match(new RegExp('(\\s|^)' + c + '(\\s|$)'));
1098
+ },
1099
+
1100
+ addClass: (e, c) => {
1101
+ if (!e) return;
1102
+ e.classList.add(c);
1103
+ return e
1104
+ },
1105
+
1106
+ removeClass: (e, c) => {
1107
+ if (!e) return;
1108
+ e.classList.remove(c);
1109
+ return e
1110
+ },
1111
+
1112
+ toggleClass: (e, c) => {
1113
+ if (!e) return;
1114
+ if (DOMController.hasClass(e, c)) {
1115
+ DOMController.removeClass(e, c)
1116
+ } else {
1117
+ DOMController.addClass(e, c)
1118
+ }
1119
+ return e
1120
+ },
1121
+
1122
+ toggleClassList: (list) => {
1123
+ list.forEach(item => {
1124
+ DOMController.toggleClass(item[0], item[1])
1125
+ })
354
1126
  }
355
- })(jQuery);
1127
+ }
1128
+ Object.freeze(DOMController);