hexo-theme-solitude 1.8.3 → 1.8.4

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.
@@ -8,10 +8,10 @@ contact_links:
8
8
  url: https://solitude-docs.efu.me/faq
9
9
  about: Solitude Q&A
10
10
 
11
+ - name: Discord
12
+ url: https://discord.gg/Y8VEvVgW
13
+ about: 'Official Discord Group'
14
+
11
15
  - name: Telegram
12
- url: https://t.me/efuome
16
+ url: https://t.me/solitudePro
13
17
  about: 'Official Telegram Group'
14
-
15
- - name: QQ 群
16
- url: https://qm.qq.com/q/VlqOewI4Cu
17
- about: '群号 773016811'
package/_config.yml CHANGED
@@ -410,6 +410,7 @@ footer:
410
410
  # 底部上方一排图标
411
411
  # Bottom row of icons
412
412
  information:
413
+ author: false # 是否显示 site_icon / enable site_icon in footer
413
414
  left: # 左侧显示图标
414
415
  # Github: https://github.com/efuo || st-github-line # 名称:链接 || 图标 / Name: link || icon
415
416
  # Mail: mailto:o@efu.me || st-mail-line
@@ -17,8 +17,9 @@ div#footer_deal
17
17
  a.deal_link(href=url_for(trim(array[0])), title=label)
18
18
  i.solitude(class=array[1])
19
19
 
20
- div#footer_mini_logo.nolazyload.footer_mini_logo(title=_p('nav.backtop'), onclick="sco.toTop()")
21
- img(src=theme.site.icon, alt=_p('nav.backtop'))
20
+ if theme.footer.information.author
21
+ div#footer_mini_logo.nolazyload.footer_mini_logo(title=_p('nav.backtop'), onclick="sco.toTop()")
22
+ img(src=theme.site.icon, alt=_p('nav.backtop'))
22
23
 
23
24
  each value, label in rightInfo
24
25
  - var array = value.split('||')
@@ -11,6 +11,8 @@ mixin katex
11
11
  })();
12
12
 
13
13
  div
14
+ script(src=url_for(theme.cdn.utils))
15
+ script(src=url_for(theme.cdn.main))
14
16
  script(src=url_for(theme.cdn.waterfall))
15
17
  script(src=url_for(theme.cdn.pjax))
16
18
 
@@ -104,7 +106,7 @@ if theme.footer.randomlink
104
106
  include ../widgets/third-party/news-comment/newest-comment.pug
105
107
 
106
108
  // pjax
107
- include ../widgets/third-party/pjax.pug
109
+ != partial("includes/widgets/third-party/pjax", {}, { cache: true })
108
110
 
109
111
  // theme
110
112
  include ../body/mode
@@ -28,7 +28,7 @@ if theme.pwa.enable
28
28
 
29
29
  script.
30
30
  console.log(
31
- "%c Program: Hexo %c Theme: Solitude %c Version: v1.8.3",
31
+ "%c Program: Hexo %c Theme: Solitude %c Version: v1.8.4",
32
32
  "border-radius:5px 0 0 5px;padding: 5px 10px;color:white;background:#ff3842;",
33
33
  "padding: 5px 10px;color:white;background:#3e9f50;",
34
34
  "border-radius:0 5px 5px 0;padding: 5px 10px;background:#0084ff;color:white;"
@@ -38,5 +38,4 @@ if theme.extends.head
38
38
  each item in theme.extends.head
39
39
  != item
40
40
 
41
- script(src=url_for(theme.cdn.utils))
42
- script(src=url_for(theme.cdn.main))
41
+ !=fragment_cache('injectHeadJs', function(){return inject_head_js()})
@@ -51,4 +51,4 @@ if theme.says.enable
51
51
  if theme.says.strip === -1
52
52
  | - 已展开所有短文 -
53
53
  else
54
- | - 只展示最近 #{theme.says.strip} 条短文 -
54
+ | - 只展示最近 #{theme.says.strip} 条短文 -
@@ -2,7 +2,7 @@
2
2
  - const { lazyload, count ,use} = theme.comment
3
3
 
4
4
  script.
5
- !function () {
5
+ (() => {
6
6
  let artalkItem = null
7
7
  const initArtalk = () => {
8
8
  artalkItem = Artalk.init({
@@ -31,7 +31,7 @@ script.
31
31
  utils.addGlobalFn('pjax', destroyArtalk, 'destroyArtalk')
32
32
  }
33
33
  const loadArtalk = async () => {
34
- if (typeof Artalk === 'object') await initArtalk()
34
+ if (typeof Artalk === 'object') initArtalk()
35
35
  else {
36
36
  await utils.getCSS('!{theme.cdn.artalk_css}')
37
37
  await utils.getScript('!{theme.cdn.artalk_js}').then(initArtalk)
@@ -50,7 +50,7 @@ script.
50
50
  } else {
51
51
  window.loadTwoComment = loadArtalk
52
52
  }
53
- }()
53
+ })()
54
54
 
55
55
  if commentBarrage
56
56
  script.
@@ -1,8 +1,8 @@
1
1
  - const { envId, region, option ,accessToken } = theme.twikoo
2
2
  - const { lazyload, count, use,commentBarrage } = theme.comment
3
3
 
4
- script.
5
- !function () {
4
+ script().
5
+ (() => {
6
6
  const getCount = () => {
7
7
  const ele = document.querySelectorAll('.twikoo-count')
8
8
  if (!ele) return
@@ -17,11 +17,12 @@ script.
17
17
  console.error(err)
18
18
  })
19
19
  }
20
- const init = async () => {
20
+ const init = () => {
21
21
  twikoo.init(Object.assign({
22
22
  el: '#twikoo-wrap',
23
23
  envId: '!{envId}',
24
24
  region: '!{region}',
25
+ path: window.location.pathname,
25
26
  onCommentLoaded: () => {
26
27
  utils.lightbox(document.querySelectorAll('#twikoo .tk-content img:not(.tk-owo-emotion)'))
27
28
  }
@@ -32,12 +33,10 @@ script.
32
33
  body: '.OwO-body',
33
34
  item: '.OwO-items li'
34
35
  })
35
-
36
- if (!{commentBarrage}) await barrageTwikoo()
37
36
  }
38
37
 
39
38
  const loadTwikoo = () => {
40
- if (typeof twikoo === 'object') init()
39
+ if (typeof twikoo === 'object') setTimeout(init,0)
41
40
  else utils.getScript('!{url_for(theme.cdn.twikoo)}').then(init)
42
41
  }
43
42
 
@@ -45,9 +44,9 @@ script.
45
44
  if (!{lazyload}) utils.loadComment(document.getElementById('twikoo-wrap'), loadTwikoo)
46
45
  else loadTwikoo()
47
46
  } else {
48
- window.loadTwoComment = init
47
+ window.loadTwoComment = loadTwikoo
49
48
  }
50
- }()
49
+ })()
51
50
 
52
51
  if commentBarrage
53
52
  script.
@@ -6,7 +6,7 @@ if site.data.valine
6
6
  - emojiMaps = JSON.stringify(site.data.valine)
7
7
 
8
8
  script.
9
- !function () {
9
+ (() => {
10
10
  const initValine = () => {
11
11
  const valine = new Valine({
12
12
  el: '#vcomment',
@@ -23,7 +23,7 @@ script.
23
23
  sco.owoBig({body: '.vwrap', item: '.vemojis i'})
24
24
  }
25
25
  const loadValine = async () => {
26
- if (typeof Valine === 'function') await initValine()
26
+ if (typeof Valine === 'function') setTimeout(initValine, 0)
27
27
  else {
28
28
  await utils.getScript('!{url_for(theme.cdn.valine)}').then(initValine)
29
29
  }
@@ -35,7 +35,7 @@ script.
35
35
  } else {
36
36
  window.loadTwoComment = loadValine
37
37
  }
38
- }()
38
+ })()
39
39
 
40
40
  if commentBarrage
41
41
  script.
@@ -2,7 +2,7 @@
2
2
  - const { lazyload, count, commentBarrage,use } = theme.comment
3
3
 
4
4
  script.
5
- !function () {
5
+ (() => {
6
6
  let walineInitFunction = window.walineFn || null
7
7
 
8
8
  function initWaline(initFn) {
@@ -40,7 +40,7 @@ script.
40
40
  if (!{lazyload}) utils.loadComment(document.getElementById('waline-wrap'), loadWaline)
41
41
  else loadWaline()
42
42
  } else window.loadTwoComment = loadWaline
43
- }()
43
+ })()
44
44
 
45
45
  if commentBarrage
46
46
  script.
@@ -17,6 +17,17 @@ script.
17
17
 
18
18
  document.addEventListener('pjax:complete', () => {
19
19
  window.refreshFn()
20
+
21
+ document.querySelectorAll('script[data-pjax]').forEach(item => {
22
+ const newScript = document.createElement('script')
23
+ const content = item.text || item.textContent || item.innerHTML || ""
24
+ Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
25
+ newScript.appendChild(document.createTextNode(content))
26
+ item.parentNode.replaceChild(newScript, item)
27
+ })
28
+
29
+ GLOBAL_CONFIG.islazyload && window.lazyLoadInstance.update()
30
+
20
31
  })
21
32
 
22
33
  document.addEventListener('pjax:error', (e) => {
package/layout/index.pug CHANGED
@@ -16,7 +16,7 @@ block content
16
16
  for post, index in page.posts.sort("-sticky" || "-date").data
17
17
  include ./includes/widgets/home/postList
18
18
 
19
- // pageination
19
+ // pagination
20
20
  include ./includes/mixins/pagination
21
21
  // aside
22
22
  include ./includes/widgets/aside/aside
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-solitude",
3
- "version": "1.8.3",
3
+ "version": "1.8.4",
4
4
  "description": "A beautiful, powerful, and efficient Hexo theme developed by the efu.",
5
5
  "main": "package.json",
6
6
  "scripts": {
@@ -152,6 +152,7 @@ hexo.extend.filter.register('before_generate', () => {
152
152
  },
153
153
  footer: {
154
154
  information: {
155
+ author: false,
155
156
  left: null,
156
157
  right: null,
157
158
  },
@@ -1,14 +1,14 @@
1
1
  hexo.on('ready', () => {
2
- const {version} = require('../../package.json')
3
- hexo.log.info(`
4
- ===================================================================
5
- ##### #### # ##### ###### # # ###### ######
6
- # # # # # # # # # # #
7
- ##### # # # # # # # # # ######
8
- # # # # # # # # # # #
9
- ###### #### ##### ##### # ### ###### ######
10
- ${version}
11
- ===================================================================
12
- GitHub: https://github.com/valor-x/hexo-theme-solitude
13
- `)
2
+ const {version} = require('../../package.json')
3
+ hexo.log.info(`
4
+ ===================================================================
5
+ ##### #### # ##### ###### # # ###### ######
6
+ # # # # # # # # # # #
7
+ ##### # # # # # # # # # ######
8
+ # # # # # # # # # # #
9
+ ###### #### ##### ##### # ### ###### ######
10
+ ${version}
11
+ ===================================================================
12
+ GitHub: https://github.com/valor-x/hexo-theme-solitude
13
+ `)
14
14
  })
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Solitude
3
+ * inject is to head
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ hexo.extend.helper.register('inject_head_js', function () {
9
+ const createJS = () => `
10
+ const saveToLocal = {
11
+ set: function setWithExpiry(key, value, ttl) {
12
+ if (ttl === 0)
13
+ return
14
+ const now = new Date()
15
+ const expiryDay = ttl * 86400000
16
+ const item = {
17
+ value: value,
18
+ expiry: now.getTime() + expiryDay
19
+ }
20
+ localStorage.setItem(key, JSON.stringify(item))
21
+ },
22
+ get: function getWithExpiry(key) {
23
+ const itemStr = localStorage.getItem(key)
24
+
25
+ if (!itemStr) {
26
+ return undefined
27
+ }
28
+ const item = JSON.parse(itemStr)
29
+ const now = new Date()
30
+
31
+ if (now.getTime() > item.expiry) {
32
+ localStorage.removeItem(key)
33
+ return undefined
34
+ }
35
+ return item.value
36
+ }
37
+ };
38
+ window.utils = {
39
+ saveToLocal: saveToLocal,
40
+ getCSS: (url, id = false) => new Promise((resolve, reject) => {
41
+ const link = document.createElement('link')
42
+ link.rel = 'stylesheet'
43
+ link.href = url
44
+ if (id) link.id = id
45
+ link.onerror = reject
46
+ link.onload = link.onreadystatechange = function() {
47
+ const loadState = this.readyState
48
+ if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
49
+ link.onload = link.onreadystatechange = null
50
+ resolve()
51
+ }
52
+ document.head.appendChild(link)
53
+ }),
54
+ getScript: (url, attr = {}) => new Promise((resolve, reject) => {
55
+ const script = document.createElement('script')
56
+ script.src = url
57
+ script.async = true
58
+ script.onerror = reject
59
+ script.onload = script.onreadystatechange = function() {
60
+ const loadState = this.readyState
61
+ if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
62
+ script.onload = script.onreadystatechange = null
63
+ resolve()
64
+ }
65
+
66
+ Object.keys(attr).forEach(key => {
67
+ script.setAttribute(key, attr[key])
68
+ })
69
+
70
+ document.head.appendChild(script)
71
+ }),
72
+ addGlobalFn: (key, fn, name = false, parent = window) => {
73
+ const globalFn = parent.globalFn || {}
74
+ const keyObj = globalFn[key] || {}
75
+
76
+ if (name && keyObj[name]) return
77
+
78
+ name = name || Object.keys(keyObj).length
79
+ keyObj[name] = fn
80
+ globalFn[key] = keyObj
81
+ parent.globalFn = globalFn
82
+ },
83
+ }
84
+ `
85
+ return `<script>(()=>{${createJS()}})()</script>`
86
+ })
@@ -80,20 +80,21 @@
80
80
  background var(--efu-main)
81
81
  transform scale(1.1)
82
82
 
83
- .footer_mini_logo
84
- width 50px
85
- height 50px
86
- margin 0 1rem
87
- cursor pointer
88
- transition cubic-bezier(0, 0, 0, 1.29) .5s
89
- user-select none
90
- border-radius 50px
91
- overflow hidden
92
- +maxWidth768()
93
- display none
94
-
95
- &:hover
96
- transform scale(1.2)
83
+ if hexo-config('footer.information.author')
84
+ .footer_mini_logo
85
+ width 50px
86
+ height 50px
87
+ margin 0 1rem
88
+ cursor pointer
89
+ transition cubic-bezier(0, 0, 0, 1.29) .5s
90
+ user-select none
91
+ border-radius 50px
92
+ overflow hidden
93
+ +maxWidth768()
94
+ display none
95
+
96
+ &:hover
97
+ transform scale(1.2)
97
98
 
98
99
  #st-footer
99
100
  display flex
package/source/js/main.js CHANGED
@@ -889,6 +889,8 @@ window.refreshFn = () => {
889
889
  sco.switchComments()
890
890
  }
891
891
 
892
+ utils.addGlobalFn('pjaxComplete', refreshFn, 'refreshFn')
893
+
892
894
  document.addEventListener('DOMContentLoaded', function () {
893
895
  sco.initAdjust()
894
896
  percent()
@@ -1,343 +1,226 @@
1
- const utils = {
2
- saveToLocal: {
3
- set: function setWithExpiry(key, value, ttl) {
4
- if (ttl === 0)
5
- return
6
- const now = new Date()
7
- const expiryDay = ttl * 86400000
8
- const item = {
9
- value: value,
10
- expiry: now.getTime() + expiryDay
11
- }
12
- localStorage.setItem(key, JSON.stringify(item))
13
- },
14
-
15
- get: function getWithExpiry(key) {
16
- const itemStr = localStorage.getItem(key)
17
-
18
- if (!itemStr) {
19
- return undefined
20
- }
21
- const item = JSON.parse(itemStr)
22
- const now = new Date()
23
-
24
- if (now.getTime() > item.expiry) {
25
- localStorage.removeItem(key)
26
- return undefined
27
- }
28
- return item.value
29
- }
30
- },
31
- debounce: function (func, wait, immediate) {
32
- let timeout
33
- return function () {
34
- const context = this
35
- const args = arguments
1
+ (() => {
2
+ const utilsFn = {
3
+ throttle: (func, wait, options) => {
4
+ let timeout, context, args
5
+ let previous = 0
6
+ if (!options) options = {}
36
7
  const later = function () {
37
- timeout = null
38
- if (!immediate) func.apply(context, args)
8
+ previous = options.leading === false ? 0 : new Date().getTime()
9
+ func.apply(context, args)
10
+ context = args = null
39
11
  }
40
- const callNow = immediate && !timeout
41
- clearTimeout(timeout)
42
- timeout = setTimeout(later, wait)
43
- if (callNow) func.apply(context, args)
44
- }
45
- },
46
-
47
- throttle: function (func, wait, options) {
48
- let timeout, context, args
49
- let previous = 0
50
- if (!options) options = {}
51
-
52
- const later = function () {
53
- previous = options.leading === false ? 0 : new Date().getTime()
54
- func.apply(context, args)
55
- context = args = null
56
- }
57
-
58
- return function () {
59
- const now = new Date().getTime()
60
- if (!previous && options.leading === false) previous = now
61
- const remaining = wait - (now - previous)
62
- context = this
63
- args = arguments
64
- if (remaining <= 0 || remaining > wait) {
65
- if (timeout) {
66
- clearTimeout(timeout)
67
- timeout = null
12
+ return function () {
13
+ const now = new Date().getTime()
14
+ if (!previous && options.leading === false) previous = now
15
+ const remaining = wait - (now - previous)
16
+ context = this
17
+ args = arguments
18
+ if (remaining <= 0 || remaining > wait) {
19
+ if (timeout) {
20
+ clearTimeout(timeout)
21
+ timeout = null
22
+ }
23
+ previous = now
24
+ func.apply(context, args)
25
+ if (!timeout) context = args = null
26
+ } else if (!timeout && options.trailing !== false) {
27
+ timeout = setTimeout(later, remaining)
68
28
  }
69
- previous = now
70
- func.apply(context, args)
71
- if (!timeout) context = args = null
72
- } else if (!timeout && options.trailing !== false) {
73
- timeout = setTimeout(later, remaining)
74
29
  }
75
- }
76
- },
77
-
78
- fadeIn: (ele, time) => {
79
- ele.style.cssText = `display:block;animation: to_show ${time}s`
80
- },
81
-
82
- fadeOut: (ele, time) => {
83
- ele.addEventListener('animationend', function f() {
84
- ele.style.cssText = "display: none; animation: '' "
85
- ele.removeEventListener('animationend', f)
86
- })
87
- ele.style.animation = `to_hide ${time}s`
88
- },
89
-
90
- sidebarPaddingR: () => {
91
- const innerWidth = window.innerWidth
92
- const clientWidth = document.body.clientWidth
93
- const paddingRight = innerWidth - clientWidth
94
- if (innerWidth !== clientWidth) {
95
- document.body.style.paddingRight = paddingRight + 'px'
96
- }
97
- },
98
-
99
- snackbarShow: (text, showAction, duration) => {
100
- const sa = (typeof showAction !== 'undefined') ? showAction : false
101
- const dur = (typeof duration !== 'undefined') ? duration : 5000
102
- document.styleSheets[0].addRule(':root', '--efu-snackbar-time:' + dur + 'ms!important')
103
- Snackbar.show({
104
- text: text,
105
- showAction: sa,
106
- duration: dur,
107
- pos: 'top-center'
108
- })
109
- },
110
-
111
- copy: async (text) => {
112
- try {
113
- await navigator.clipboard.writeText(text)
114
- utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success, false, 2000)
115
- } catch (err) {
116
- utils.snackbarShow(GLOBAL_CONFIG.lang.copy.error, false, 2000)
117
- }
118
- },
119
-
120
- getEleTop: ele => {
121
- let actualTop = 0
122
- while (ele) {
123
- actualTop += ele.offsetTop
124
- ele = ele.offsetParent
125
- }
126
- return actualTop
127
- },
128
-
129
- randomNum: (length) => {
130
- return Math.floor(Math.random() * length)
131
- },
132
-
133
- timeDiff: (timeObj, today) => {
134
- const timeDiff = today.getTime() - timeObj.getTime();
135
- return Math.floor(timeDiff / (1000 * 3600 * 24));
136
- },
137
-
138
- scrollToDest: (pos, time = 500) => {
139
- const currentPos = window.pageYOffset
140
- const isNavFixed = document.getElementById('page-header').classList.contains('nav-fixed')
141
- if (currentPos > pos || isNavFixed) pos = pos - 70
142
- if ('scrollBehavior' in document.documentElement.style) {
143
- window.scrollTo({
144
- top: pos,
145
- behavior: 'smooth'
30
+ },
31
+ fadeIn: (ele, time) => ele.style.cssText = `display:block;animation: to_show ${time}s`,
32
+ fadeOut: (ele, time) => {
33
+ ele.addEventListener('animationend', function f() {
34
+ ele.style.cssText = "display: none; animation: '' "
35
+ ele.removeEventListener('animationend', f)
146
36
  })
147
- return
148
- }
149
- let start = null
150
- const distance = pos - currentPos
151
- window.requestAnimationFrame(function step(currentTime) {
152
- start = !start ? currentTime : start
153
- const progress = currentTime - start
154
- if (progress < time) {
155
- window.scrollTo(0, currentPos + distance * progress / time)
156
- window.requestAnimationFrame(step)
157
- } else {
158
- window.scrollTo(0, pos)
37
+ ele.style.animation = `to_hide ${time}s`
38
+ },
39
+ sidebarPaddingR: () => {
40
+ const innerWidth = window.innerWidth
41
+ const clientWidth = document.body.clientWidth
42
+ const paddingRight = innerWidth - clientWidth
43
+ if (innerWidth !== clientWidth) {
44
+ document.body.style.paddingRight = paddingRight + 'px'
159
45
  }
160
- })
161
- },
162
- siblings: (ele, selector) => {
163
- return [...ele.parentNode.children].filter((child) => {
164
- if (selector) {
165
- return child !== ele && child.matches(selector)
46
+ },
47
+ snackbarShow: (text, showAction, duration) => {
48
+ const sa = (typeof showAction !== 'undefined') ? showAction : false
49
+ const dur = (typeof duration !== 'undefined') ? duration : 5000
50
+ document.styleSheets[0].addRule(':root', '--efu-snackbar-time:' + dur + 'ms!important')
51
+ Snackbar.show({
52
+ text: text,
53
+ showAction: sa,
54
+ duration: dur,
55
+ pos: 'top-center'
56
+ })
57
+ },
58
+ copy: async (text) => {
59
+ try {
60
+ await navigator.clipboard.writeText(text)
61
+ utils.snackbarShow(GLOBAL_CONFIG.lang.copy.success, false, 2000)
62
+ } catch (err) {
63
+ utils.snackbarShow(GLOBAL_CONFIG.lang.copy.error, false, 2000)
166
64
  }
167
- return child !== ele
168
- })
169
- },
170
- isMobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
171
- isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth,
172
- addEventListenerPjax: (ele, event, fn, option = false) => {
173
- ele.addEventListener(event, fn, option)
174
- utils.addGlobalFn('pjax', () => {
175
- ele.removeEventListener(event, fn, option)
176
- })
177
- },
178
- addGlobalFn: (key, fn, name = false, parent = window) => {
179
- const globalFn = parent.globalFn || {}
180
- const keyObj = globalFn[key] || {}
181
-
182
- if (name && keyObj[name]) return
183
-
184
- name = name || Object.keys(keyObj).length
185
- keyObj[name] = fn
186
- globalFn[key] = keyObj
187
- parent.globalFn = globalFn
188
- },
189
- animateIn: (ele, text) => {
190
- ele.style.display = 'block'
191
- ele.style.animation = text
192
- },
193
- animateOut: (ele, text) => {
194
- ele.addEventListener('animationend', function f() {
195
- ele.style.display = ''
196
- ele.style.animation = ''
197
- ele.removeEventListener('animationend', f)
198
- })
199
- ele.style.animation = text
200
- },
201
- wrap: (selector, eleType, options) => {
202
- const createEle = document.createElement(eleType)
203
- for (const [key, value] of Object.entries(options)) {
204
- createEle.setAttribute(key, value)
205
- }
206
- selector.parentNode.insertBefore(createEle, selector)
207
- createEle.appendChild(selector)
208
- },
209
- lazyloadImg: function () {
210
- window.lazyLoadInstance = new LazyLoad({
211
- elements_selector: 'img',
212
- threshold: 0,
213
- data_src: 'lazy-src',
214
- callback_error: (img) => {
215
- img.setAttribute("src", GLOBAL_CONFIG.lazyload.error);
65
+ },
66
+ getEleTop: ele => {
67
+ let actualTop = 0
68
+ while (ele) {
69
+ actualTop += ele.offsetTop
70
+ ele = ele.offsetParent
216
71
  }
217
- })
218
- },
219
- lightbox: function (selector) {
220
- const lightbox = GLOBAL_CONFIG.lightbox
221
-
222
- if (lightbox === 'mediumZoom' && mediumZoom) {
223
- mediumZoom(selector, {
224
- background: "var(--efu-card-bg)"
225
- });
226
- }
227
-
228
- if (lightbox === 'fancybox') {
229
- selector.forEach(i => {
230
- if (i.parentNode.tagName !== 'A') {
231
- const dataSrc = i.dataset.lazySrc || i.src
232
- const dataCaption = i.title || i.alt || ''
233
- utils.wrap(i, 'a', {
234
- class: 'fancybox',
235
- href: dataSrc,
236
- 'data-fancybox': 'gallery',
237
- 'data-caption': dataCaption,
238
- 'data-thumb': dataSrc
239
- })
72
+ return actualTop
73
+ },
74
+ randomNum: (length) => {
75
+ return Math.floor(Math.random() * length)
76
+ },
77
+ timeDiff: (timeObj, today) => {
78
+ const timeDiff = today.getTime() - timeObj.getTime();
79
+ return Math.floor(timeDiff / (1000 * 3600 * 24));
80
+ },
81
+ scrollToDest: (pos, time = 500) => {
82
+ const currentPos = window.pageYOffset
83
+ const isNavFixed = document.getElementById('page-header').classList.contains('nav-fixed')
84
+ if (currentPos > pos || isNavFixed) pos = pos - 70
85
+ if ('scrollBehavior' in document.documentElement.style) {
86
+ window.scrollTo({
87
+ top: pos,
88
+ behavior: 'smooth'
89
+ })
90
+ return
91
+ }
92
+ let start = null
93
+ const distance = pos - currentPos
94
+ window.requestAnimationFrame(function step(currentTime) {
95
+ start = !start ? currentTime : start
96
+ const progress = currentTime - start
97
+ if (progress < time) {
98
+ window.scrollTo(0, currentPos + distance * progress / time)
99
+ window.requestAnimationFrame(step)
100
+ } else {
101
+ window.scrollTo(0, pos)
240
102
  }
241
103
  })
242
-
243
- if (!window.fancyboxRun) {
244
- Fancybox.bind('[data-fancybox]', {
245
- Hash: false,
246
- Thumbs: {
247
- showOnStart: false
248
- },
249
- Images: {
250
- Panzoom: {
251
- maxScale: 4
252
- }
253
- },
254
- Carousel: {
255
- transition: 'slide'
256
- },
257
- Toolbar: {
258
- display: {
259
- left: ['infobar'],
260
- middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
261
- right: ['slideshow', 'thumbs', 'close']
262
- }
263
- }
264
- })
265
- window.fancyboxRun = true
104
+ },
105
+ siblings: (ele, selector) => {
106
+ return [...ele.parentNode.children].filter((child) => {
107
+ if (selector) {
108
+ return child !== ele && child.matches(selector)
109
+ }
110
+ return child !== ele
111
+ })
112
+ },
113
+ isMobile: () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),
114
+ isHidden: e => 0 === e.offsetHeight && 0 === e.offsetWidth,
115
+ addEventListenerPjax: (ele, event, fn, option = false) => {
116
+ ele.addEventListener(event, fn, option)
117
+ utils.addGlobalFn('pjax', () => {
118
+ ele.removeEventListener(event, fn, option)
119
+ })
120
+ },
121
+ animateIn: (ele, text) => {
122
+ ele.style.display = 'block'
123
+ ele.style.animation = text
124
+ },
125
+ animateOut: (ele, text) => {
126
+ ele.addEventListener('animationend', function f() {
127
+ ele.style.display = ''
128
+ ele.style.animation = ''
129
+ ele.removeEventListener('animationend', f)
130
+ })
131
+ ele.style.animation = text
132
+ },
133
+ wrap: (selector, eleType, options) => {
134
+ const createEle = document.createElement(eleType)
135
+ for (const [key, value] of Object.entries(options)) {
136
+ createEle.setAttribute(key, value)
266
137
  }
267
- }
268
- },
269
- diffDate: (d, more = false) => {
270
- const dateNow = new Date()
271
- const datePost = new Date(d)
272
- const dateDiff = dateNow.getTime() - datePost.getTime()
273
- const minute = 1000 * 60
274
- const hour = minute * 60
275
- const day = hour * 24
276
- const month = day * 30
277
- const {
278
- time
279
- } = GLOBAL_CONFIG.lang
280
-
281
- if (!more) return parseInt(dateDiff / day)
282
-
283
- const monthCount = dateDiff / month
284
- const dayCount = dateDiff / day
285
- const hourCount = dateDiff / hour
286
- const minuteCount = dateDiff / minute
287
-
288
- if (monthCount > 12) return datePost.toISOString().slice(0, 10)
289
- if (monthCount >= 1) return `${parseInt(monthCount)} ${time.month}`
290
- if (dayCount >= 1) return `${parseInt(dayCount)} ${time.day}`
291
- if (hourCount >= 1) return `${parseInt(hourCount)} ${time.hour}`
292
- if (minuteCount >= 1) return `${parseInt(minuteCount)} ${time.min}`
293
- return time.just
294
- },
295
- loadComment: (dom, callback) => {
296
- if ('IntersectionObserver' in window) {
297
- const observerItem = new IntersectionObserver((entries) => {
298
- if (entries[0].isIntersecting) {
299
- callback()
300
- observerItem.disconnect()
138
+ selector.parentNode.insertBefore(createEle, selector)
139
+ createEle.appendChild(selector)
140
+ },
141
+ lazyloadImg: function () {
142
+ window.lazyLoadInstance = new LazyLoad({
143
+ elements_selector: 'img',
144
+ threshold: 0,
145
+ data_src: 'lazy-src',
146
+ callback_error: (img) => {
147
+ img.setAttribute("src", GLOBAL_CONFIG.lazyload.error);
301
148
  }
302
- }, {
303
- threshold: [0]
304
149
  })
305
- observerItem.observe(dom)
306
- } else {
307
- callback()
308
- }
309
- },
310
- getCSS: (url, id = false) => new Promise((resolve, reject) => {
311
- const link = document.createElement('link')
312
- link.rel = 'stylesheet'
313
- link.href = url
314
- if (id) link.id = id
315
- link.onerror = reject
316
- link.onload = link.onreadystatechange = function () {
317
- const loadState = this.readyState
318
- if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
319
- link.onload = link.onreadystatechange = null
320
- resolve()
321
- }
322
- document.head.appendChild(link)
323
- }),
324
-
325
- getScript: (url, attr = {}) => new Promise((resolve, reject) => {
326
- const script = document.createElement('script')
327
- script.src = url
328
- script.async = true
329
- script.onerror = reject
330
- script.onload = script.onreadystatechange = function () {
331
- const loadState = this.readyState
332
- if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
333
- script.onload = script.onreadystatechange = null
334
- resolve()
335
- }
336
-
337
- Object.keys(attr).forEach(key => {
338
- script.setAttribute(key, attr[key])
339
- })
340
- document.head.appendChild(script)
341
- })
342
-
343
- }
150
+ },
151
+ lightbox: function (selector) {
152
+ const lightboxType = GLOBAL_CONFIG.lightbox;
153
+ switch (lightboxType) {
154
+ case 'mediumZoom':
155
+ mediumZoom ? mediumZoom(selector, {background: "var(--efu-card-bg)"}) : false
156
+ break;
157
+ case 'fancybox':
158
+ selector.forEach(i => {
159
+ if (i.parentNode.tagName !== 'A') {
160
+ const dataSrc = i.dataset.lazySrc || i.src;
161
+ const dataCaption = i.title || i.alt || '';
162
+ utils.wrap(i, 'a', {
163
+ class: 'fancybox',
164
+ href: dataSrc,
165
+ 'data-fancybox': 'gallery',
166
+ 'data-caption': dataCaption,
167
+ 'data-thumb': dataSrc
168
+ });
169
+ }
170
+ });
171
+ if (!window.fancyboxRun) {
172
+ Fancybox.bind('[data-fancybox]', {
173
+ Hash: false,
174
+ Thumbs: {showOnStart: false},
175
+ Images: {Panzoom: {maxScale: 4}},
176
+ Carousel: {transition: 'slide'},
177
+ Toolbar: {
178
+ display: {
179
+ left: ['infobar'],
180
+ middle: ['zoomIn', 'zoomOut', 'toggle1to1', 'rotateCCW', 'rotateCW', 'flipX', 'flipY'],
181
+ right: ['slideshow', 'thumbs', 'close']
182
+ }
183
+ }
184
+ });
185
+ window.fancyboxRun = true;
186
+ }
187
+ break;
188
+ }
189
+ },
190
+ diffDate: (d, more = false) => {
191
+ const dateNow = new Date();
192
+ const datePost = new Date(d);
193
+ const dateDiff = dateNow - datePost; // Simplified date difference calculation
194
+ const minute = 60000;
195
+ const hour = 3600000;
196
+ const day = 86400000;
197
+ const month = 2592000000;
198
+ const {time} = GLOBAL_CONFIG.lang;
199
+ if (!more) return Math.floor(dateDiff / day)
200
+ const minuteCount = Math.floor(dateDiff / minute)
201
+ const hourCount = Math.floor(dateDiff / hour)
202
+ const dayCount = Math.floor(dateDiff / day)
203
+ const monthCount = Math.floor(dateDiff / month)
204
+ if (monthCount > 12) return datePost.toISOString().slice(0, 10)
205
+ if (monthCount >= 1) return `${monthCount} ${time.month}`
206
+ if (dayCount >= 1) return `${dayCount} ${time.day}`
207
+ if (hourCount >= 1) return `${hourCount} ${time.hour}`
208
+ if (minuteCount >= 1) return `${minuteCount} ${time.min}`
209
+ return time.just
210
+ },
211
+ loadComment: (dom, callback) => {
212
+ if ('IntersectionObserver' in window) {
213
+ const observerItem = new IntersectionObserver((entries) => {
214
+ if (entries[0].isIntersecting) {
215
+ callback()
216
+ observerItem.disconnect()
217
+ }
218
+ }, {threshold: [0]})
219
+ observerItem.observe(dom)
220
+ } else {
221
+ callback()
222
+ }
223
+ },
224
+ }
225
+ window.utils = {...window.utils, ...utilsFn};
226
+ })()