hexo-theme-stellar 1.35.0 → 1.37.0
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.
- package/CHANGELOG.md +1180 -0
- package/_config.yml +25 -10
- package/layout/_partial/comments/artalk/layout.ejs +2 -2
- package/layout/_partial/comments/artalk/script.ejs +3 -9
- package/layout/_partial/comments/beaudar/script.ejs +2 -8
- package/layout/_partial/comments/giscus/script.ejs +2 -8
- package/layout/_partial/comments/twikoo/layout.ejs +2 -2
- package/layout/_partial/comments/twikoo/script.ejs +3 -9
- package/layout/_partial/comments/utterances/script.ejs +2 -8
- package/layout/_partial/comments/waline/layout.ejs +1 -1
- package/layout/_partial/comments/waline/script.ejs +1 -7
- package/layout/_partial/scripts/defines.ejs +118 -1
- package/layout/_partial/scripts/lazyload.ejs +7 -6
- package/layout/_partial/scripts/services.ejs +11 -13
- package/layout/_partial/scripts/utils.ejs +359 -24
- package/layout/_partial/widgets/tagtree.ejs +1 -1
- package/layout/_partial/widgets/toc.ejs +1 -4
- package/layout/_partial/widgets/tree.ejs +1 -1
- package/layout/_plugins/fancybox.ejs +23 -8
- package/layout/_plugins/scrollreveal.ejs +77 -13
- package/package.json +1 -1
- package/scripts/filters/lib/img_lazyload.js +9 -9
- package/scripts/tags/lib/emoji.js +17 -2
- package/scripts/tags/lib/image.js +13 -18
- package/source/css/_common/html.styl +0 -2
- package/source/css/_components/widgets/toc.styl +2 -2
- package/source/css/_plugins/lazyload.styl +40 -26
- package/source/css/_plugins/scrollreveal.styl +5 -1
- package/source/js/main.js +157 -69
- package/source/js/search/algolia-search.js +62 -62
- package/source/js/search/local-search.js +37 -36
- package/source/js/services/artalk_latest_comment.js +5 -7
- package/source/js/services/contributors.js +4 -6
- package/source/js/services/fcircle.js +4 -6
- package/source/js/services/friends.js +4 -6
- package/source/js/services/friends_and_posts.js +4 -6
- package/source/js/services/ghinfo.js +6 -8
- package/source/js/services/giscus_latest_comment.js +4 -6
- package/source/js/services/mdrender.js +2 -2
- package/source/js/services/memos.js +3 -4
- package/source/js/services/rss.js +10 -12
- package/source/js/services/siteinfo.js +24 -26
- package/source/js/services/sites.js +4 -6
- package/source/js/services/timeline.js +4 -6
- package/source/js/services/twikoo_latest_comment.js +5 -7
- package/source/js/services/waline_latest_comment.js +4 -6
- package/source/js/services/weibo.js +4 -6
|
@@ -5,22 +5,22 @@
|
|
|
5
5
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// 懒加载强制开启:不再读取 enable 配置,no-lazy 是唯一例外
|
|
10
9
|
function lazyProcess(htmlContent) {
|
|
11
|
-
const cfg = this.theme.config.plugins.lazyload;
|
|
12
|
-
if (cfg == undefined || cfg.enable != true) {
|
|
13
|
-
return htmlContent;
|
|
14
|
-
}
|
|
15
10
|
return htmlContent.replace(/<img(.*?)src="(.*?)"(.*?)>/gi, function(imgTag, src_before, src_value, src_after) {
|
|
16
|
-
//
|
|
17
|
-
if (/data-
|
|
11
|
+
// 已由 tag 插件输出懒加载标记(data-src / data-srcset)的图片不重复处理
|
|
12
|
+
if (/data-src/gi.test(imgTag)) {
|
|
13
|
+
return imgTag;
|
|
14
|
+
}
|
|
15
|
+
// 使用 srcset 的图片交给浏览器原生处理,避免占位图与 srcset 冲突
|
|
16
|
+
if (/srcset=/gi.test(imgTag)) {
|
|
18
17
|
return imgTag;
|
|
19
18
|
}
|
|
20
19
|
if (/src="data:image(.*?)/gi.test(imgTag)) {
|
|
21
20
|
return imgTag;
|
|
22
21
|
}
|
|
23
|
-
|
|
22
|
+
// no-lazy 兼容 `no-lazy` / `no-lazy=""` 两种写法
|
|
23
|
+
if (/\bno-lazy\b/gi.test(imgTag)) {
|
|
24
24
|
return imgTag;
|
|
25
25
|
}
|
|
26
26
|
var newImgTag = imgTag;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* 格式与官方标签插件一致使用空格分隔,中括号内的是可选参数(中括号不需要写出来)
|
|
4
4
|
*
|
|
5
5
|
* {% emoji [source] name [height:1.75em] %}
|
|
6
|
+
* {% emoji url:https://example.com/emoji.png [name:alt] [height:1.75em] %}
|
|
6
7
|
*
|
|
7
8
|
*/
|
|
8
9
|
|
|
@@ -10,12 +11,26 @@
|
|
|
10
11
|
|
|
11
12
|
module.exports = ctx => function(args) {
|
|
12
13
|
const config = ctx.theme.config.tag_plugins.emoji
|
|
13
|
-
args = ctx.args.map(args, ['height'], ['source', 'name'])
|
|
14
|
+
args = ctx.args.map(args, ['url', 'height', 'name'], ['source', 'name'])
|
|
14
15
|
var el = ''
|
|
16
|
+
el += '<span class="tag-plugin emoji">'
|
|
17
|
+
if (args.url) {
|
|
18
|
+
// 直接引用外部图片,不再走 source 配置查找
|
|
19
|
+
el += '<img no-lazy="" class="inline"'
|
|
20
|
+
el += ' src="' + args.url + '"'
|
|
21
|
+
if (args.name) {
|
|
22
|
+
el += ' alt="' + args.name + '"'
|
|
23
|
+
}
|
|
24
|
+
if (args.height) {
|
|
25
|
+
el += ' style="height:' + args.height + '"'
|
|
26
|
+
}
|
|
27
|
+
el += '/>'
|
|
28
|
+
el += '</span>'
|
|
29
|
+
return el
|
|
30
|
+
}
|
|
15
31
|
if (args.source == undefined) {
|
|
16
32
|
return el
|
|
17
33
|
}
|
|
18
|
-
el += '<span class="tag-plugin emoji">'
|
|
19
34
|
if (args.name == undefined) {
|
|
20
35
|
// 省略了 source
|
|
21
36
|
for (let id in config) {
|
|
@@ -16,32 +16,27 @@ module.exports = ctx => function(args) {
|
|
|
16
16
|
if (args.height) {
|
|
17
17
|
style += 'height:' + args.height + ';'
|
|
18
18
|
}
|
|
19
|
-
// fancybox
|
|
20
|
-
var fancybox =
|
|
19
|
+
// fancybox 默认开启(不再支持全局关闭),单图可用 fancybox:false 关闭
|
|
20
|
+
var fancybox = true
|
|
21
21
|
var fancyboxHref = null
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
fancybox = false
|
|
31
|
-
} else if (args.fancybox === 'true') {
|
|
32
|
-
fancybox = args.fancybox
|
|
33
|
-
} else {
|
|
34
|
-
fancybox = true
|
|
35
|
-
fancyboxHref = args.fancybox
|
|
36
|
-
}
|
|
22
|
+
if (args.fancybox && args.fancybox.length > 0) {
|
|
23
|
+
if (args.fancybox == 'false') {
|
|
24
|
+
fancybox = false
|
|
25
|
+
} else if (args.fancybox === 'true') {
|
|
26
|
+
fancybox = true
|
|
27
|
+
} else {
|
|
28
|
+
fancybox = true
|
|
29
|
+
fancyboxHref = args.fancybox
|
|
37
30
|
}
|
|
38
31
|
}
|
|
39
32
|
|
|
40
33
|
var safeAlt = require('hexo-util').escapeHTML(args.alt || '')
|
|
34
|
+
// 懒加载占位图(1x1 透明 PNG),真实地址放在 data-src
|
|
35
|
+
const loadingImg = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAABGdBTUEAALGPC/xhBQAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAAaADAAQAAAABAAAAAQAAAADa6r/EAAAAC0lEQVQIHWNgAAIAAAUAAY27m/MAAAAASUVORK5CYII='
|
|
41
36
|
function img(src, alt, style) {
|
|
42
37
|
let a = '<a data-fancybox'
|
|
43
38
|
let img = ''
|
|
44
|
-
img += `<img class="lazy" src="${
|
|
39
|
+
img += `<img class="lazy" src="${loadingImg}" data-src="${src}"`
|
|
45
40
|
if (safeAlt) {
|
|
46
41
|
img += ` alt="${safeAlt}"`
|
|
47
42
|
a += ` data-caption="${safeAlt}"`
|
|
@@ -141,7 +141,7 @@
|
|
|
141
141
|
.widget-body
|
|
142
142
|
grid-template-rows: 0fr
|
|
143
143
|
|
|
144
|
-
//
|
|
144
|
+
// 操作按钮(回到顶部 / 参与讨论)
|
|
145
145
|
.widget-wrapper.toc .widget-body+.widget-footer:before
|
|
146
146
|
content: ''
|
|
147
147
|
position absolute
|
|
@@ -188,4 +188,4 @@
|
|
|
188
188
|
a
|
|
189
189
|
background: var(--block)
|
|
190
190
|
a+a
|
|
191
|
-
margin-top: 4px
|
|
191
|
+
margin-top: 4px
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
$lazyTransitionType = hexo-config('
|
|
1
|
+
$lazyTransitionType = hexo-config('dependencies.lazyload.transition')
|
|
2
2
|
$loadingImageSize = 2rem
|
|
3
3
|
|
|
4
4
|
img:not([src])
|
|
5
5
|
visibility: hidden
|
|
6
6
|
|
|
7
|
+
.lazy
|
|
8
|
+
opacity: 0
|
|
9
|
+
z-index: 1
|
|
10
|
+
|
|
7
11
|
.lazy-box
|
|
8
12
|
position: relative
|
|
9
13
|
overflow: hidden
|
|
@@ -12,26 +16,8 @@ img:not([src])
|
|
|
12
16
|
background: var(--block)
|
|
13
17
|
min-height: 4rem
|
|
14
18
|
|
|
15
|
-
// 懒加载
|
|
16
|
-
img[data-ll-status]
|
|
17
|
-
z-index: 1
|
|
18
|
-
&:not(.loaded)
|
|
19
|
-
opacity: 0
|
|
20
|
-
&.loaded,&.error
|
|
21
|
-
opacity: 1
|
|
22
|
-
if $lazyTransitionType == 'blur'
|
|
23
|
-
trans1 all 0.5s
|
|
24
|
-
&:not(.loaded)
|
|
25
|
-
filter blur(20px)
|
|
26
|
-
-webkit-filter blur(20px)
|
|
27
|
-
&.loaded,&.error
|
|
28
|
-
filter none
|
|
29
|
-
-webkit-filter none
|
|
30
|
-
else
|
|
31
|
-
trans1 all 0.38s
|
|
32
|
-
|
|
33
19
|
// 加载占位动画
|
|
34
|
-
img
|
|
20
|
+
img.lazy.loading + .lazy-icon
|
|
35
21
|
position: absolute
|
|
36
22
|
width: $loadingImageSize
|
|
37
23
|
height: $loadingImageSize
|
|
@@ -45,13 +31,41 @@ img[data-ll-status]+.lazy-icon
|
|
|
45
31
|
background-position: center
|
|
46
32
|
|
|
47
33
|
// 加载完成
|
|
48
|
-
img
|
|
49
|
-
|
|
50
|
-
|
|
34
|
+
img.lazy.loaded + .lazy-icon,
|
|
35
|
+
img.lazy.error + .lazy-icon
|
|
36
|
+
display: none
|
|
51
37
|
|
|
52
38
|
// 加载失败
|
|
53
|
-
img
|
|
39
|
+
img.lazy.error
|
|
54
40
|
width: $loadingImageSize
|
|
55
41
|
height: $loadingImageSize
|
|
56
|
-
|
|
57
|
-
|
|
42
|
+
|
|
43
|
+
// 懒加载完成动画:使用 keyframes 而非 transition,
|
|
44
|
+
// 因为缓存图片可能在 loading 状态被绘制前就完成加载,transition 没有起点会直接闪现
|
|
45
|
+
if $lazyTransitionType == 'blur'
|
|
46
|
+
.lazy
|
|
47
|
+
filter: blur(20px)
|
|
48
|
+
-webkit-filter: blur(20px)
|
|
49
|
+
.lazy.loaded, .lazy.error
|
|
50
|
+
opacity: 1
|
|
51
|
+
filter: none
|
|
52
|
+
-webkit-filter: none
|
|
53
|
+
animation: ll-blur-in 0.5s ease-out
|
|
54
|
+
@keyframes ll-blur-in
|
|
55
|
+
from
|
|
56
|
+
opacity: 0
|
|
57
|
+
filter: blur(20px)
|
|
58
|
+
-webkit-filter: blur(20px)
|
|
59
|
+
to
|
|
60
|
+
opacity: 1
|
|
61
|
+
filter: none
|
|
62
|
+
-webkit-filter: none
|
|
63
|
+
else
|
|
64
|
+
.lazy.loaded, .lazy.error
|
|
65
|
+
opacity: 1
|
|
66
|
+
animation: ll-fade-in 0.5s ease-out
|
|
67
|
+
@keyframes ll-fade-in
|
|
68
|
+
from
|
|
69
|
+
opacity: 0
|
|
70
|
+
to
|
|
71
|
+
opacity: 1
|
package/source/js/main.js
CHANGED
|
@@ -53,11 +53,14 @@ const util = {
|
|
|
53
53
|
},
|
|
54
54
|
|
|
55
55
|
scrollTop: () => {
|
|
56
|
-
|
|
56
|
+
smoothScrollTo(0);
|
|
57
57
|
},
|
|
58
58
|
|
|
59
59
|
scrollComment: () => {
|
|
60
|
-
document.getElementById('comments')
|
|
60
|
+
const el = document.getElementById('comments');
|
|
61
|
+
if (el) {
|
|
62
|
+
smoothScrollTo(el.getBoundingClientRect().top + window.scrollY - 32);
|
|
63
|
+
}
|
|
61
64
|
},
|
|
62
65
|
|
|
63
66
|
viewportLazyload: (target, func, enabled = true) => {
|
|
@@ -94,73 +97,168 @@ const hud = {
|
|
|
94
97
|
|
|
95
98
|
const l_body = document.querySelector('.l_body');
|
|
96
99
|
|
|
100
|
+
// 通用平滑滚动(自定义动画,TOC / 回到顶部 / 参与讨论共用)
|
|
101
|
+
let scrollAnim = null;
|
|
102
|
+
function cancelSmoothScroll() {
|
|
103
|
+
if (scrollAnim !== null) {
|
|
104
|
+
cancelAnimationFrame(scrollAnim);
|
|
105
|
+
scrollAnim = null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function smoothScrollTo(targetY) {
|
|
109
|
+
cancelSmoothScroll();
|
|
110
|
+
targetY = Math.max(0, targetY);
|
|
111
|
+
const startY = window.scrollY;
|
|
112
|
+
const diff = targetY - startY;
|
|
113
|
+
if (Math.abs(diff) < 2) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// 短距离 300ms,长距离最多 600ms
|
|
117
|
+
const duration = Math.min(600, Math.max(300, Math.abs(diff) * 0.15));
|
|
118
|
+
const startTime = performance.now();
|
|
119
|
+
function step(now) {
|
|
120
|
+
const t = Math.min(1, (now - startTime) / duration);
|
|
121
|
+
const eased = 1 - Math.pow(1 - t, 3); // easeOutCubic
|
|
122
|
+
// 显式指定 instant,避免全局 scroll-behavior: smooth 与自定义动画叠加导致滚动变慢
|
|
123
|
+
window.scrollTo({ top: startY + diff * eased, behavior: 'instant' });
|
|
124
|
+
if (t < 1) {
|
|
125
|
+
scrollAnim = requestAnimationFrame(step);
|
|
126
|
+
} else {
|
|
127
|
+
scrollAnim = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
scrollAnim = requestAnimationFrame(step);
|
|
131
|
+
}
|
|
132
|
+
window.addEventListener('wheel', cancelSmoothScroll, { passive: true });
|
|
133
|
+
window.addEventListener('touchstart', cancelSmoothScroll, { passive: true });
|
|
134
|
+
|
|
97
135
|
|
|
98
136
|
const init = {
|
|
99
137
|
toc: () => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
var
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (seg.offset().top > scrollTop + scrollOffset) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (!topSeg) {
|
|
115
|
-
topSeg = seg;
|
|
116
|
-
} else if (seg.offset().top >= topSeg.offset().top) {
|
|
117
|
-
topSeg = seg;
|
|
118
|
-
}
|
|
138
|
+
const scrollOffset = 32;
|
|
139
|
+
// 滚动位置取整后标题顶可能落在偏移线下方 1~2px,加容差避免高亮回跳到上一条
|
|
140
|
+
const scrollTolerance = 4;
|
|
141
|
+
var segs = utils.qsa("article.md-text h1, article.md-text h2, article.md-text h3, article.md-text h4, article.md-text h5, article.md-text h6");
|
|
142
|
+
function activeTOC() {
|
|
143
|
+
var scrollTop = window.scrollY;
|
|
144
|
+
var topSeg = null;
|
|
145
|
+
for (var i = 0; i < segs.length; i++) {
|
|
146
|
+
var segTop = segs[i].getBoundingClientRect().top + window.scrollY;
|
|
147
|
+
if (segTop > scrollTop + scrollOffset + scrollTolerance) {
|
|
148
|
+
continue;
|
|
119
149
|
}
|
|
120
|
-
if (topSeg) {
|
|
121
|
-
|
|
122
|
-
var link = "#" + topSeg.attr("id");
|
|
123
|
-
if (link != '#undefined') {
|
|
124
|
-
const highlightItem = $('#data-toc a.toc-link[href="' + encodeURI(link) + '"]');
|
|
125
|
-
if (highlightItem.length > 0) {
|
|
126
|
-
highlightItem.addClass("active");
|
|
127
|
-
}
|
|
128
|
-
} else {
|
|
129
|
-
$('#data-toc a.toc-link:first').addClass("active");
|
|
130
|
-
}
|
|
150
|
+
if (!topSeg || segTop >= topSeg.getBoundingClientRect().top + window.scrollY) {
|
|
151
|
+
topSeg = segs[i];
|
|
131
152
|
}
|
|
132
153
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
154
|
+
if (topSeg) {
|
|
155
|
+
utils.dom("#data-toc a.toc-link").removeClass("active");
|
|
156
|
+
var id = topSeg.getAttribute("id");
|
|
157
|
+
var link = id ? "#" + id : "#undefined";
|
|
158
|
+
if (link != '#undefined') {
|
|
159
|
+
const highlightItem = utils.dom('#data-toc a.toc-link[href="' + encodeURI(link) + '"]');
|
|
160
|
+
if (highlightItem.length > 0) {
|
|
161
|
+
highlightItem.addClass("active");
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
const first = utils.qs('#data-toc a.toc-link');
|
|
165
|
+
if (first) first.classList.add("active");
|
|
145
166
|
}
|
|
146
167
|
}
|
|
168
|
+
}
|
|
169
|
+
function scrollTOC() {
|
|
170
|
+
const e0 = document.querySelector('#data-toc .toc');
|
|
171
|
+
const e1 = document.querySelector('#data-toc .toc a.toc-link.active');
|
|
172
|
+
if (e0 == null || e1 == null) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const offsetBottom = e1.getBoundingClientRect().bottom - e0.getBoundingClientRect().bottom + 100;
|
|
176
|
+
const offsetTop = e1.getBoundingClientRect().top - e0.getBoundingClientRect().top - 64;
|
|
177
|
+
if (offsetTop < 0) {
|
|
178
|
+
e0.scrollBy({ top: offsetTop, behavior: "smooth" });
|
|
179
|
+
} else if (offsetBottom > 0) {
|
|
180
|
+
e0.scrollBy({ top: offsetBottom, behavior: "smooth" });
|
|
181
|
+
}
|
|
182
|
+
}
|
|
147
183
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
})
|
|
184
|
+
var timeout = null;
|
|
185
|
+
window.addEventListener('scroll', function () {
|
|
186
|
+
activeTOC();
|
|
187
|
+
if (timeout !== null) clearTimeout(timeout);
|
|
188
|
+
timeout = setTimeout(function () {
|
|
189
|
+
scrollTOC();
|
|
190
|
+
}, 50);
|
|
191
|
+
});
|
|
157
192
|
},
|
|
158
193
|
sidebar: () => {
|
|
159
|
-
utils.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
194
|
+
utils.dom("#data-toc a.toc-link").click(function (e) {
|
|
195
|
+
const href = this.getAttribute("href");
|
|
196
|
+
const id = href && href.indexOf("#") === 0 ? decodeURIComponent(href.slice(1)) : null;
|
|
197
|
+
const target = id && document.getElementById(id);
|
|
198
|
+
if (target) {
|
|
199
|
+
e.preventDefault();
|
|
200
|
+
const offset = 32; // 与 activeTOC 的 scrollOffset 保持一致
|
|
201
|
+
const targetY = target.getBoundingClientRect().top + window.scrollY - offset;
|
|
202
|
+
smoothScrollTo(targetY);
|
|
203
|
+
if (window.history && window.history.pushState) {
|
|
204
|
+
window.history.pushState(null, "", href);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
sidebar.dismiss();
|
|
208
|
+
});
|
|
209
|
+
},
|
|
210
|
+
leftbarScroll: () => {
|
|
211
|
+
const container = document.querySelector('.l_left .widgets');
|
|
212
|
+
if (container == null) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const PREFIX = 'Stellar.leftbarScroll.';
|
|
216
|
+
const encode = (s) => encodeURIComponent(String(s || ''));
|
|
217
|
+
function scope() {
|
|
218
|
+
const wikiEl = document.querySelector('.doc-tree[data-wiki]');
|
|
219
|
+
if (wikiEl != null) {
|
|
220
|
+
return 'wiki:' + encode(wikiEl.getAttribute('data-wiki'));
|
|
221
|
+
}
|
|
222
|
+
const notebookEl = document.querySelector('widget[data-notebook]');
|
|
223
|
+
if (notebookEl != null) {
|
|
224
|
+
return 'notebook:' + encode(notebookEl.getAttribute('data-notebook'));
|
|
225
|
+
}
|
|
226
|
+
const body = document.querySelector('.l_body');
|
|
227
|
+
return 'layout:' + encode((body && body.getAttribute('layout')) || 'default');
|
|
228
|
+
}
|
|
229
|
+
window.addEventListener('pagehide', function () {
|
|
230
|
+
try {
|
|
231
|
+
const s = scope();
|
|
232
|
+
sessionStorage.setItem(PREFIX + s, String(container.scrollTop));
|
|
233
|
+
sessionStorage.setItem(PREFIX + 'last', s);
|
|
234
|
+
} catch (e) {}
|
|
235
|
+
});
|
|
236
|
+
try {
|
|
237
|
+
const s = scope();
|
|
238
|
+
// 仅当上一页与当前页属于同一分区时才恢复,离开分区后再回来不跳回旧位置
|
|
239
|
+
if (sessionStorage.getItem(PREFIX + 'last') !== s) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const value = sessionStorage.getItem(PREFIX + s);
|
|
243
|
+
if (value == null) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
container.scrollTop = parseInt(value, 10) || 0;
|
|
247
|
+
const link = container.querySelector('a.link.active');
|
|
248
|
+
if (link == null) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const padding = 16;
|
|
252
|
+
const containerRect = container.getBoundingClientRect();
|
|
253
|
+
const linkRect = link.getBoundingClientRect();
|
|
254
|
+
const top = linkRect.top - containerRect.top;
|
|
255
|
+
const bottom = linkRect.bottom - containerRect.top;
|
|
256
|
+
if (top < 0) {
|
|
257
|
+
container.scrollTop += top - padding;
|
|
258
|
+
} else if (bottom > container.clientHeight) {
|
|
259
|
+
container.scrollTop += bottom - container.clientHeight + padding;
|
|
260
|
+
}
|
|
261
|
+
} catch (e) {}
|
|
164
262
|
},
|
|
165
263
|
relativeDate: (selector) => {
|
|
166
264
|
selector.forEach(item => {
|
|
@@ -293,25 +391,15 @@ window.stellar = window.stellar || {};
|
|
|
293
391
|
|
|
294
392
|
/**
|
|
295
393
|
* Initialize page components
|
|
296
|
-
* Called on initial load and after PJAX navigation
|
|
297
394
|
*/
|
|
298
395
|
stellar.initPage = function () {
|
|
299
396
|
init.toc();
|
|
300
397
|
init.sidebar();
|
|
398
|
+
init.leftbarScroll();
|
|
301
399
|
init.relativeDate(document.querySelectorAll('#post-meta time'));
|
|
302
400
|
init.registerTabsTag();
|
|
303
|
-
|
|
304
|
-
// Reinitialize comments after PJAX navigation
|
|
305
|
-
if (stellar.initComments) {
|
|
306
|
-
for (const commentSystem in stellar.initComments) {
|
|
307
|
-
if (typeof stellar.initComments[commentSystem] === 'function') {
|
|
308
|
-
stellar.initComments[commentSystem]();
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
401
|
};
|
|
313
402
|
|
|
314
403
|
// Initial page load
|
|
315
404
|
stellar.initPage();
|
|
316
405
|
init.canonicalCheck();
|
|
317
|
-
|
|
@@ -1,77 +1,77 @@
|
|
|
1
1
|
utils.js(window.searchConfig.js).then(() => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
}
|
|
2
|
+
var inputArea = document.querySelector("input#search-input");
|
|
3
|
+
if (!inputArea) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
var resultArea = document.querySelector("#search-result");
|
|
8
|
+
var searchWrapper = document.querySelector("#search-wrapper");
|
|
9
|
+
var client = algoliasearch(window.searchConfig.appId, window.searchConfig.apiKey);
|
|
10
|
+
var index = client.initIndex(window.searchConfig.indexName);
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
function filterResults(hits, filterPath) {
|
|
13
|
+
if (!filterPath || filterPath === '/') return hits;
|
|
14
|
+
var regex = new RegExp(filterPath);
|
|
15
|
+
return hits.filter(hit => regex.test(hit.url));
|
|
16
|
+
}
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
18
|
+
function displayResults(hits) {
|
|
19
|
+
var resultList = document.createElement("ul");
|
|
20
|
+
resultList.classList.add("search-result-list");
|
|
21
|
+
if (hits.length === 0) {
|
|
22
|
+
searchWrapper.classList.add('noresult');
|
|
23
|
+
} else {
|
|
24
|
+
searchWrapper.classList.remove('noresult');
|
|
25
|
+
hits.forEach(function(hit) {
|
|
26
|
+
var contentSnippet = hit._snippetResult.content.value;
|
|
27
|
+
var title = hit.hierarchy.lvl1 || 'Untitled';
|
|
28
|
+
var item = document.createElement("li");
|
|
29
|
+
item.innerHTML = `<a href="${hit.url}"><span class='search-result-title'>${title}</span><p class="search-result-content">${contentSnippet}</p></a>`;
|
|
30
|
+
resultList.appendChild(item);
|
|
31
|
+
});
|
|
33
32
|
}
|
|
33
|
+
resultArea.replaceChildren(resultList);
|
|
34
|
+
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
inputArea.addEventListener("input", function() {
|
|
37
|
+
var query = inputArea.value.trim();
|
|
38
|
+
var filterPath = inputArea.getAttribute('data-filter');
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
if (query.length <= 0) {
|
|
41
|
+
searchWrapper.setAttribute('searching', 'false');
|
|
42
|
+
resultArea.replaceChildren();
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
searchWrapper.setAttribute('searching', 'true');
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
});
|
|
48
|
+
index.search(query, {
|
|
49
|
+
hitsPerPage: window.searchConfig.hitsPerPage,
|
|
50
|
+
attributesToHighlight: ['content'],
|
|
51
|
+
attributesToSnippet: ['content:30'],
|
|
52
|
+
highlightPreTag: '<span class="search-keyword">',
|
|
53
|
+
highlightPostTag: '</span>',
|
|
54
|
+
restrictSearchableAttributes: ['content']
|
|
55
|
+
}).then(function(responses) {
|
|
56
|
+
displayResults(filterResults(responses.hits, filterPath));
|
|
57
57
|
});
|
|
58
|
+
});
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
inputArea.addEventListener("keydown", function(e) {
|
|
61
|
+
if (e.key == 'Enter') {
|
|
62
|
+
e.preventDefault();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
66
|
+
var observer = new MutationObserver(function(mutationsList) {
|
|
67
|
+
if (mutationsList.length === 1) {
|
|
68
|
+
if (mutationsList[0].addedNodes.length) {
|
|
69
|
+
searchWrapper.classList.remove('noresult');
|
|
70
|
+
} else if (mutationsList[0].removedNodes.length) {
|
|
71
|
+
searchWrapper.classList.add('noresult');
|
|
72
72
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
observer.observe($resultArea[0], { childList: true });
|
|
73
|
+
}
|
|
76
74
|
});
|
|
75
|
+
|
|
76
|
+
observer.observe(resultArea, { childList: true });
|
|
77
77
|
});
|