hexo-theme-linen 1.0.21 → 1.0.23
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/languages/en.yml +3 -0
- package/languages/zh-CN.yml +4 -1
- package/layout/footer.ejs +62 -0
- package/layout/layout.ejs +22 -9
- package/layout/partials/header.ejs +1 -1
- package/layout/partials/post-item.ejs +5 -5
- package/layout/partials/related-posts.ejs +1 -1
- package/layout/post.ejs +362 -24
- package/layout/series.ejs +277 -4
- package/package.json +1 -1
- package/scripts/font-version.js +5 -3
- package/scripts/helpers/tools.js +187 -191
- package/scripts/lazyload/client.js +11 -2
- package/scripts/lazyload/index.js +7 -5
- package/scripts/lazyload/inject.js +8 -0
- package/scripts/lazyload/process.js +202 -163
- package/scripts/markdown-it-image-grid.js +74 -10
- package/source/linen-theme/css/{mediaquery.scss → _mediaquery.scss} +183 -12
- package/source/linen-theme/css/atom.xsl +37 -0
- package/source/linen-theme/css/font-version.scss +1 -1
- package/source/linen-theme/css/images/layers-2x.png +0 -0
- package/source/linen-theme/css/images/layers.png +0 -0
- package/source/linen-theme/css/images/marker-icon-2x.png +0 -0
- package/source/linen-theme/css/images/marker-icon.png +0 -0
- package/source/linen-theme/css/images/marker-shadow.png +0 -0
- package/source/linen-theme/css/leaflet.css +661 -0
- package/source/linen-theme/css/linen.scss +1198 -114
- package/source/linen-theme/css/linkcard.scss +53 -11
- package/source/linen-theme/css/noscript.css +70 -0
- package/source/linen-theme/css/photoswipe-dynamic-caption-plugin.css +1 -1
- package/source/linen-theme/css/photoswipe.css +166 -1
- package/source/linen-theme/css/rss-en.xsl +1 -1
- package/source/linen-theme/css/rss-zh.xsl +1 -1
- package/source/linen-theme/css/vars.scss +1 -1
- package/source/linen-theme/img/pattern-randomized.svg +1 -0
- package/source/linen-theme/img/travel-map-fallback.svg +30 -0
- package/source/linen-theme/js/hdr.js +42 -12
- package/source/linen-theme/js/lazyload.js +11 -2
- package/source/linen-theme/js/leaflet.js +6 -0
- package/source/linen-theme/js/linen.js +114 -83
- package/source/linen-theme/js/photoswipe/photoswipe.esm.min.js +13 -0
- package/source/linen-theme/js/replace-emoji.js +2 -4
- package/source/linen-theme/js/toc.js +71 -121
- package/layout/partials/footer.ejs +0 -12
- package/source/linen-theme/img/icons/backref.svg +0 -1
- package/source/linen-theme/img/icons/more.svg +0 -4
|
@@ -5,13 +5,11 @@ const path = require("path");
|
|
|
5
5
|
const { defaultConfig } = require("./config");
|
|
6
6
|
function getElemAttributes(elemText) {
|
|
7
7
|
// Regex to pick out start tag from start of element's HTML.
|
|
8
|
-
var re_start_tag =
|
|
9
|
-
/^<\w+\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[\w\-.:]+))?)*\s*\/?>/;
|
|
8
|
+
var re_start_tag = /^<\w+\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[\w\-.:]+))?)*\s*\/?>/;
|
|
10
9
|
var start_tag = elemText.match(re_start_tag);
|
|
11
10
|
start_tag = start_tag ? start_tag[0] : "";
|
|
12
11
|
// Regex to pick out attribute name and (optional) value from start tag.
|
|
13
|
-
var re_attribs =
|
|
14
|
-
/\s+([\w\-.:]+)(\s*=\s*(?:"([^"]*)"|'([^']*)'|([\w\-.:]+)))?/g;
|
|
12
|
+
var re_attribs = /\s+([\w\-.:]+)(\s*=\s*(?:"([^"]*)"|'([^']*)'|([\w\-.:]+)))?/g;
|
|
15
13
|
var attribs = {}; // Store attribute name=value pairs in object.
|
|
16
14
|
var match = re_attribs.exec(start_tag);
|
|
17
15
|
while (match != null) {
|
|
@@ -22,8 +20,8 @@ function getElemAttributes(elemText) {
|
|
|
22
20
|
value = match[3]
|
|
23
21
|
? match[3] // Attribute value is in $3, $4 or $5.
|
|
24
22
|
: match[4]
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
? match[4]
|
|
24
|
+
: match[5];
|
|
27
25
|
}
|
|
28
26
|
attribs[attrib] = value;
|
|
29
27
|
match = re_attribs.exec(start_tag);
|
|
@@ -70,11 +68,46 @@ function getInlineWidthStyle(style) {
|
|
|
70
68
|
return filtered ? `style="${filtered};"` : "";
|
|
71
69
|
}
|
|
72
70
|
|
|
71
|
+
function escapeAttribute(value = "") {
|
|
72
|
+
return String(value)
|
|
73
|
+
.replace(/&/g, "&")
|
|
74
|
+
.replace(/"/g, """)
|
|
75
|
+
.replace(/</g, "<")
|
|
76
|
+
.replace(/>/g, ">");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getLivePhotoInfo(src = "", style = "") {
|
|
80
|
+
src = decodeHexEntity(src).replace(/&/g, "&");
|
|
81
|
+
|
|
82
|
+
if (!/\/static\/live-photo\//.test(src)) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const livePhotoUrl = new URL(src, "https://lynan.cn");
|
|
88
|
+
const picUrl = livePhotoUrl.searchParams.get("picUrl") || livePhotoUrl.searchParams.get("photoSrc");
|
|
89
|
+
const aspectRatio = /aspect-ratio\s*:\s*([^;]+)/i.exec(style)?.[1]?.trim() || "";
|
|
90
|
+
const [width, height] = aspectRatio.includes("/")
|
|
91
|
+
? aspectRatio.split("/").map((value) => Number(value.trim()))
|
|
92
|
+
: [Number(aspectRatio) || 16, 1];
|
|
93
|
+
|
|
94
|
+
if (!picUrl || !width || !height) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
picUrl,
|
|
100
|
+
width,
|
|
101
|
+
height
|
|
102
|
+
};
|
|
103
|
+
} catch (error) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
73
108
|
function decodeHexEntity(str) {
|
|
74
109
|
return str
|
|
75
|
-
? str.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) =>
|
|
76
|
-
String.fromCharCode(parseInt(hex, 16))
|
|
77
|
-
)
|
|
110
|
+
? str.replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
78
111
|
: "";
|
|
79
112
|
}
|
|
80
113
|
|
|
@@ -83,16 +116,26 @@ function isUrlEqual(src1 = "", src2 = "") {
|
|
|
83
116
|
const u1 = new URL(src1);
|
|
84
117
|
const u2 = new URL(src2);
|
|
85
118
|
|
|
86
|
-
return
|
|
87
|
-
u1.pathname === u2.pathname &&
|
|
88
|
-
u1.search === u2.search &&
|
|
89
|
-
u1.hash === u2.hash
|
|
90
|
-
);
|
|
119
|
+
return u1.pathname === u2.pathname && u1.search === u2.search && u1.hash === u2.hash;
|
|
91
120
|
} catch (e) {
|
|
92
121
|
return false;
|
|
93
122
|
}
|
|
94
123
|
}
|
|
95
124
|
|
|
125
|
+
function appendAttributeToTag(tag, attrName, attrValue) {
|
|
126
|
+
if (!attrValue || new RegExp(`\\s${attrName}=`).test(tag)) {
|
|
127
|
+
return tag;
|
|
128
|
+
}
|
|
129
|
+
return tag.replace(/\s*\/?>$/, (end) => ` ${attrName}="${attrValue}"${end}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function getPlaceholderStyle(placeholder = "") {
|
|
133
|
+
if (!placeholder || placeholder.startsWith("blurhash:")) {
|
|
134
|
+
return "";
|
|
135
|
+
}
|
|
136
|
+
return /http|data:image/.test(placeholder) ? `background-image: url(${placeholder})` : placeholder;
|
|
137
|
+
}
|
|
138
|
+
|
|
96
139
|
function formatAttributes(str, src, imgs = [], language) {
|
|
97
140
|
let res = {};
|
|
98
141
|
const imgItem = imgs.find((item) => isUrlEqual(item.url, src || ""));
|
|
@@ -117,9 +160,7 @@ function formatAttributes(str, src, imgs = [], language) {
|
|
|
117
160
|
aspectRatio = `${imgItem.width}/${imgItem.height}`;
|
|
118
161
|
}
|
|
119
162
|
if (styleAttr) {
|
|
120
|
-
const styleObj = styleStringToObject(
|
|
121
|
-
styleAttr.replace(/style="(.*?)"/gi, "$1")
|
|
122
|
-
);
|
|
163
|
+
const styleObj = styleStringToObject(styleAttr.replace(/style="(.*?)"/gi, "$1"));
|
|
123
164
|
if (styleObj["aspect-ratio"]) {
|
|
124
165
|
aspectRatio = styleObj["aspect-ratio"];
|
|
125
166
|
}
|
|
@@ -136,11 +177,9 @@ function formatAttributes(str, src, imgs = [], language) {
|
|
|
136
177
|
if (aspectRatio) {
|
|
137
178
|
if (/\//.test(aspectRatio)) {
|
|
138
179
|
percentage =
|
|
139
|
-
(
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
100
|
|
143
|
-
).toFixed(5) + "%";
|
|
180
|
+
((Number(aspectRatio.split("/")[1]) / Number(aspectRatio.split("/")[0])) * 100).toFixed(
|
|
181
|
+
5
|
|
182
|
+
) + "%";
|
|
144
183
|
} else {
|
|
145
184
|
percentage = 100 / Number(aspectRatio) + "%";
|
|
146
185
|
}
|
|
@@ -150,9 +189,7 @@ function formatAttributes(str, src, imgs = [], language) {
|
|
|
150
189
|
|
|
151
190
|
const getPlaceholderImage = (returnStr) => {
|
|
152
191
|
let placeholderImage = attributesObj["data-placeholderimg"] || "";
|
|
153
|
-
var placeholderImageRes = /placeholder=(\S+)=placeholder/gi.exec(
|
|
154
|
-
attributesObj.alt
|
|
155
|
-
);
|
|
192
|
+
var placeholderImageRes = /placeholder=(\S+)=placeholder/gi.exec(attributesObj.alt);
|
|
156
193
|
if (placeholderImageRes && placeholderImageRes[1]) {
|
|
157
194
|
placeholderImage = placeholderImageRes[1];
|
|
158
195
|
}
|
|
@@ -170,8 +207,8 @@ function formatAttributes(str, src, imgs = [], language) {
|
|
|
170
207
|
return isBlurHash
|
|
171
208
|
? ""
|
|
172
209
|
: /http|data:image/.test(placeholderImage)
|
|
173
|
-
|
|
174
|
-
|
|
210
|
+
? `url(${placeholderImage})`
|
|
211
|
+
: placeholderImage;
|
|
175
212
|
};
|
|
176
213
|
|
|
177
214
|
const getAltText = () => {
|
|
@@ -230,20 +267,14 @@ const getformatedStr = (str, attrs, placeholerStyle = "") => {
|
|
|
230
267
|
|
|
231
268
|
if (placeholderImageStr) {
|
|
232
269
|
if (/data-placeholderimg/.test(formatedStr)) {
|
|
233
|
-
formatedStr = formatedStr.replace(
|
|
234
|
-
`data-placeholderimg="${placeholderImageStr}"`,
|
|
235
|
-
""
|
|
236
|
-
);
|
|
270
|
+
formatedStr = formatedStr.replace(`data-placeholderimg="${placeholderImageStr}"`, "");
|
|
237
271
|
noScriptElementStr = noScriptElementStr.replace(
|
|
238
272
|
`data-placeholderimg="${placeholderImageStr}"`,
|
|
239
273
|
""
|
|
240
274
|
);
|
|
241
275
|
}
|
|
242
276
|
if (/\$placeholder=/.test(formatedStr)) {
|
|
243
|
-
formatedStr = formatedStr.replace(
|
|
244
|
-
`$placeholder=${placeholderImageStr}=placeholder`,
|
|
245
|
-
""
|
|
246
|
-
);
|
|
277
|
+
formatedStr = formatedStr.replace(`$placeholder=${placeholderImageStr}=placeholder`, "");
|
|
247
278
|
noScriptElementStr = noScriptElementStr.replace(
|
|
248
279
|
`$placeholder=${placeholderImageStr}=placeholder`,
|
|
249
280
|
""
|
|
@@ -252,10 +283,7 @@ const getformatedStr = (str, attrs, placeholerStyle = "") => {
|
|
|
252
283
|
}
|
|
253
284
|
if (aspectRatioStr) {
|
|
254
285
|
if (/\$aspect-ratio=/.test(formatedStr)) {
|
|
255
|
-
formatedStr = formatedStr.replace(
|
|
256
|
-
`$aspect-ratio=${aspectRatioStr}=aspect-ratio`,
|
|
257
|
-
""
|
|
258
|
-
);
|
|
286
|
+
formatedStr = formatedStr.replace(`$aspect-ratio=${aspectRatioStr}=aspect-ratio`, "");
|
|
259
287
|
}
|
|
260
288
|
}
|
|
261
289
|
if (style) {
|
|
@@ -273,110 +301,94 @@ function lazyProcess(htmlContent) {
|
|
|
273
301
|
const language = this.config.language;
|
|
274
302
|
const { showAltText, placeholderRatio } = {
|
|
275
303
|
...defaultConfig,
|
|
276
|
-
...(themeConfig?.lazyload || {})
|
|
304
|
+
...(themeConfig?.lazyload || {})
|
|
277
305
|
};
|
|
278
306
|
|
|
279
|
-
const enableGallery = themeConfig?.photoswipe
|
|
280
|
-
const imgs = readAllImgs(
|
|
281
|
-
|
|
282
|
-
);
|
|
307
|
+
const enableGallery = themeConfig?.photoswipe === true;
|
|
308
|
+
const imgs = readAllImgs(path.join(this.base_dir, "assets-db/imgs"));
|
|
309
|
+
let livePhotoThumbIndex = 0;
|
|
283
310
|
|
|
284
311
|
return htmlContent
|
|
285
|
-
.replace(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return str.replace(/\$?no-lazy/, "");
|
|
290
|
-
}
|
|
312
|
+
.replace(/<img([\s\S]*?)src="(.*?)"([\s\S]*?)(>|<\/img>)/gi, function (str, p1, src, attrStr) {
|
|
313
|
+
if (/no-lazy/gi.test(str)) {
|
|
314
|
+
return str.replace(/\$?no-lazy/, "");
|
|
315
|
+
}
|
|
291
316
|
|
|
292
|
-
|
|
293
|
-
|
|
317
|
+
const formatedAttributes = formatAttributes(str, src, imgs, language);
|
|
318
|
+
const wrapStyle = formatedAttributes.style;
|
|
294
319
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
320
|
+
let placeholerStyle = "";
|
|
321
|
+
if (formatedAttributes.paddingBottom || formatedAttributes.placeholderImage) {
|
|
322
|
+
placeholerStyle = `style="${
|
|
323
|
+
formatedAttributes.paddingBottom
|
|
324
|
+
? `padding-bottom: ${formatedAttributes.paddingBottom};`
|
|
325
|
+
: ""
|
|
326
|
+
}${
|
|
298
327
|
formatedAttributes.placeholderImage
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
328
|
+
? `background-image: ${formatedAttributes.placeholderImage}`
|
|
329
|
+
: ""
|
|
330
|
+
}"`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const { formatedStr, noScriptElementStr } = getformatedStr(str, formatedAttributes);
|
|
334
|
+
|
|
335
|
+
const defaultpswpConfig = {
|
|
336
|
+
width: 1920,
|
|
337
|
+
height: 1920 / placeholderRatio
|
|
338
|
+
};
|
|
339
|
+
const hasSizeConfig =
|
|
340
|
+
formatedAttributes?.originalWidth || formatedAttributes.aspectRatioStr?.split("/")?.[0];
|
|
341
|
+
const pswpWidth =
|
|
342
|
+
formatedAttributes?.originalWidth ??
|
|
343
|
+
(/\//.test(formatedAttributes.aspectRatioStr)
|
|
344
|
+
? formatedAttributes.aspectRatioStr?.split("/")?.[0]
|
|
345
|
+
: defaultpswpConfig.width);
|
|
346
|
+
const pswpHeight =
|
|
347
|
+
formatedAttributes?.originalHeight ??
|
|
348
|
+
(/\//.test(formatedAttributes.aspectRatioStr)
|
|
349
|
+
? formatedAttributes.aspectRatioStr?.split("/")?.[1]
|
|
350
|
+
: defaultpswpConfig.height);
|
|
351
|
+
const pswpConfig = enableGallery
|
|
352
|
+
? `data-pswp-hassize="${(!!hasSizeConfig).toString()}" data-pswp-width="${pswpWidth}" data-pswp-height="${pswpHeight}" ${
|
|
353
|
+
formatedAttributes["pswp-src"]
|
|
354
|
+
? `data-pswp-src="${formatedAttributes["pswp-src"]}"`
|
|
303
355
|
: ""
|
|
356
|
+
} data-cropped="true"${
|
|
357
|
+
formatedAttributes.exif ? ` data-pspw-exif="${formatedAttributes.exif}"` : ""
|
|
304
358
|
}${
|
|
305
|
-
formatedAttributes.
|
|
306
|
-
? `
|
|
359
|
+
formatedAttributes.location
|
|
360
|
+
? ` data-pspw-location="${formatedAttributes.location}"`
|
|
307
361
|
: ""
|
|
308
|
-
}
|
|
309
|
-
|
|
362
|
+
}`
|
|
363
|
+
: "";
|
|
310
364
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
formatedAttributes.
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
? formatedAttributes.aspectRatioStr?.split("/")?.[1]
|
|
332
|
-
: defaultpswpConfig.height);
|
|
333
|
-
const pswpConfig = enableGallery
|
|
334
|
-
? `data-pswp-hassize="${(!!hasSizeConfig).toString()}" data-pswp-width="${pswpWidth}" data-pswp-height="${pswpHeight}" ${
|
|
335
|
-
formatedAttributes["pswp-src"]
|
|
336
|
-
? `data-pswp-src="${formatedAttributes["pswp-src"]}"`
|
|
337
|
-
: ""
|
|
338
|
-
} data-cropped="true"${
|
|
339
|
-
formatedAttributes.exif
|
|
340
|
-
? ` data-pspw-exif="${formatedAttributes.exif}"`
|
|
341
|
-
: ""
|
|
342
|
-
}${
|
|
343
|
-
formatedAttributes.location
|
|
344
|
-
? ` data-pspw-location="${formatedAttributes.location}"`
|
|
345
|
-
: ""
|
|
346
|
-
}`
|
|
347
|
-
: "";
|
|
348
|
-
|
|
349
|
-
const itemTag = formatedAttributes.isLink ? "a" : "span";
|
|
350
|
-
const widthStyle = getInlineWidthStyle(wrapStyle || "");
|
|
351
|
-
|
|
352
|
-
return `<span class="lazyload-outer-wrap" style="width: 100%;"><${itemTag} class="gallery-item" href="${src}" ${pswpConfig} target="_blank" rel="noopener" ${
|
|
353
|
-
theme === "landscape" ? 'data-fancybox="gallery"' : ""
|
|
354
|
-
} ${widthStyle}><noscript>${noScriptElementStr}</noscript><span class="lazyload-wrap" data-content="${encodeURIComponent(
|
|
355
|
-
formatedStr
|
|
356
|
-
)}" ${
|
|
357
|
-
wrapStyle ? `style="${wrapStyle}"` : ""
|
|
358
|
-
}><span class="placeholder" ${placeholerStyle}></span></span>${
|
|
359
|
-
formatedAttributes.caption
|
|
360
|
-
? `<span class="pswp-caption-content">${formatedAttributes.caption}</span>`
|
|
361
|
-
: ""
|
|
362
|
-
}</${itemTag}>${
|
|
363
|
-
showAltText && formatedAttributes.alt
|
|
364
|
-
? `<span class="caption" ${widthStyle}>${formatedAttributes.alt}</span>`
|
|
365
|
-
: ``
|
|
366
|
-
}</span>`;
|
|
367
|
-
}
|
|
368
|
-
)
|
|
369
|
-
.replace(/<iframe(.*?)src="(.*?)"(.*?)<\/iframe>/gi, function (str) {
|
|
365
|
+
const itemTag = formatedAttributes.isLink ? "a" : "span";
|
|
366
|
+
const widthStyle = getInlineWidthStyle(wrapStyle || "");
|
|
367
|
+
|
|
368
|
+
return `<span class="lazyload-outer-wrap" style="width: 100%;"><${itemTag} class="gallery-item" href="${src}" ${pswpConfig} target="_blank" rel="noopener" ${
|
|
369
|
+
theme === "landscape" ? 'data-fancybox="gallery"' : ""
|
|
370
|
+
} ${widthStyle}><noscript>${noScriptElementStr}</noscript><span class="lazyload-wrap" data-content="${encodeURIComponent(
|
|
371
|
+
formatedStr
|
|
372
|
+
)}" ${
|
|
373
|
+
wrapStyle ? `style="${wrapStyle}"` : ""
|
|
374
|
+
}><span class="placeholder" ${placeholerStyle}></span></span>${
|
|
375
|
+
formatedAttributes.caption
|
|
376
|
+
? `<span class="pswp-caption-content">${formatedAttributes.caption}</span>`
|
|
377
|
+
: ""
|
|
378
|
+
}</${itemTag}>${
|
|
379
|
+
showAltText && formatedAttributes.alt
|
|
380
|
+
? `<span class="caption" ${widthStyle}>${formatedAttributes.alt}</span>`
|
|
381
|
+
: ``
|
|
382
|
+
}</span>`;
|
|
383
|
+
})
|
|
384
|
+
.replace(/<iframe(.*?)src="(.*?)"(.*?)<\/iframe>/gi, function (str, p1, src) {
|
|
370
385
|
if (/no-lazy/gi.test(str)) {
|
|
371
386
|
return str;
|
|
372
387
|
}
|
|
373
388
|
const formatedAttributes = formatAttributes(str);
|
|
374
389
|
const wrapStyle = formatedAttributes.style;
|
|
375
390
|
let placeholerStyle = "";
|
|
376
|
-
if (
|
|
377
|
-
formatedAttributes.paddingBottom ||
|
|
378
|
-
formatedAttributes.placeholderImage
|
|
379
|
-
) {
|
|
391
|
+
if (formatedAttributes.paddingBottom || formatedAttributes.placeholderImage) {
|
|
380
392
|
placeholerStyle = `style="${
|
|
381
393
|
formatedAttributes.paddingBottom
|
|
382
394
|
? `padding-bottom: ${formatedAttributes.paddingBottom};`
|
|
@@ -395,48 +407,56 @@ function lazyProcess(htmlContent) {
|
|
|
395
407
|
: ""
|
|
396
408
|
);
|
|
397
409
|
|
|
398
|
-
|
|
410
|
+
const livePhotoInfo = enableGallery ? getLivePhotoInfo(src, wrapStyle || "") : null;
|
|
411
|
+
const livePhotoThumbId = livePhotoInfo ? `live-photo-thumb-${livePhotoThumbIndex++}` : "";
|
|
412
|
+
const livePhotoGalleryItem = livePhotoInfo
|
|
413
|
+
? `<a class="gallery-item live-photo-gallery-item" href="${escapeAttribute(
|
|
414
|
+
livePhotoInfo.picUrl
|
|
415
|
+
)}" data-pswp-width="${livePhotoInfo.width}" data-pswp-height="${
|
|
416
|
+
livePhotoInfo.height
|
|
417
|
+
}" data-cropped="true" data-pswp-thumb-id="${livePhotoThumbId}" data-live-photo-src="${encodeURIComponent(src)}" data-live-photo-pic-url="${escapeAttribute(
|
|
418
|
+
livePhotoInfo.picUrl
|
|
419
|
+
)}" target="_blank" rel="noopener" style="display: none;" aria-hidden="true"></a>`
|
|
420
|
+
: "";
|
|
421
|
+
|
|
422
|
+
return `<span class="lazyload-outer-wrap" style="width: 100%;">${livePhotoGalleryItem}<span class="lazyload-wrap" data-content="${encodeURIComponent(
|
|
399
423
|
formatedStr
|
|
400
|
-
)}" ${
|
|
424
|
+
)}" ${livePhotoThumbId ? `id="${livePhotoThumbId}"` : ""} ${
|
|
425
|
+
wrapStyle ? `style="${wrapStyle}"` : ""
|
|
426
|
+
}><span class="placeholder" ${placeholerStyle}></span></span><noscript>[This iframe content needs to be loaded by JavaScript.]</noscript></span>`;
|
|
401
427
|
})
|
|
402
|
-
.replace(
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
placeholerStyle = `style="${
|
|
416
|
-
formatedAttributes.paddingBottom
|
|
417
|
-
? `padding-bottom: ${formatedAttributes.paddingBottom};`
|
|
418
|
-
: ""
|
|
419
|
-
}${
|
|
420
|
-
formatedAttributes.placeholderImage
|
|
421
|
-
? `background-image: ${formatedAttributes.placeholderImage}`
|
|
422
|
-
: ""
|
|
423
|
-
}"`;
|
|
424
|
-
}
|
|
425
|
-
const { formatedStr, noScriptElementStr } = getformatedStr(
|
|
426
|
-
str,
|
|
427
|
-
formatedAttributes,
|
|
428
|
+
.replace(/<video([\s\S]*?)src="(.*?)"([\s\S]*?)(>|<\/video>)/gi, function (str) {
|
|
429
|
+
if (/no-lazy/gi.test(str)) {
|
|
430
|
+
return str;
|
|
431
|
+
}
|
|
432
|
+
const formatedAttributes = formatAttributes(str);
|
|
433
|
+
const wrapStyle = formatedAttributes.style;
|
|
434
|
+
let placeholerStyle = "";
|
|
435
|
+
if (formatedAttributes.paddingBottom || formatedAttributes.placeholderImage) {
|
|
436
|
+
placeholerStyle = `style="${
|
|
437
|
+
formatedAttributes.paddingBottom
|
|
438
|
+
? `padding-bottom: ${formatedAttributes.paddingBottom};`
|
|
439
|
+
: ""
|
|
440
|
+
}${
|
|
428
441
|
formatedAttributes.placeholderImage
|
|
429
|
-
? `
|
|
442
|
+
? `background-image: ${formatedAttributes.placeholderImage}`
|
|
430
443
|
: ""
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
return `<span class="lazyload-outer-wrap" style="width: 100%;"><span class="lazyload-wrap" data-content="${encodeURIComponent(
|
|
434
|
-
formatedStr
|
|
435
|
-
)}" ${
|
|
436
|
-
wrapStyle ? `style="${wrapStyle}"` : ""
|
|
437
|
-
}><span class="placeholder" ${placeholerStyle}></span></span><noscript>${noScriptElementStr}</noscript></span>`;
|
|
444
|
+
}"`;
|
|
438
445
|
}
|
|
439
|
-
|
|
446
|
+
const { formatedStr, noScriptElementStr } = getformatedStr(
|
|
447
|
+
str,
|
|
448
|
+
formatedAttributes,
|
|
449
|
+
formatedAttributes.placeholderImage
|
|
450
|
+
? `style="background-image: ${formatedAttributes.placeholderImage}; background-size: 100% 100%;"`
|
|
451
|
+
: ""
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
return `<span class="lazyload-outer-wrap" style="width: 100%;"><span class="lazyload-wrap" data-content="${encodeURIComponent(
|
|
455
|
+
formatedStr
|
|
456
|
+
)}" ${
|
|
457
|
+
wrapStyle ? `style="${wrapStyle}"` : ""
|
|
458
|
+
}><span class="placeholder" ${placeholerStyle}></span></span><noscript>${noScriptElementStr}</noscript></span>`;
|
|
459
|
+
});
|
|
440
460
|
}
|
|
441
461
|
|
|
442
462
|
module.exports.processPost = function (data) {
|
|
@@ -456,6 +476,25 @@ module.exports.processCovers = function (str, data) {
|
|
|
456
476
|
})">`
|
|
457
477
|
);
|
|
458
478
|
}
|
|
479
|
+
str = str.replace(
|
|
480
|
+
/<div class="cover-img">\s*(<img\b[^>]*\bsrc="([^"]+)"[^>]*>)\s*<\/div>/gi,
|
|
481
|
+
(coverStr, imgStr, src) => {
|
|
482
|
+
if (/no-lazy/gi.test(imgStr)) {
|
|
483
|
+
return coverStr.replace(/\s+\$?no-lazy\b/i, "");
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
const imgData = imgs.find((item) => isUrlEqual(item.url, src || ""));
|
|
487
|
+
const placeholder = imgData?.placeholder || "";
|
|
488
|
+
const contentImgStr = appendAttributeToTag(imgStr, "data-placeholderimg", placeholder);
|
|
489
|
+
const placeholderStyle = getPlaceholderStyle(placeholder);
|
|
490
|
+
|
|
491
|
+
return `<div class="cover-img"><noscript>${imgStr}</noscript><span class="lazyload-wrap post-list-cover-lazy" data-content="${encodeURIComponent(
|
|
492
|
+
contentImgStr
|
|
493
|
+
)}"><span class="placeholder"${
|
|
494
|
+
placeholderStyle ? ` style="${placeholderStyle}"` : ""
|
|
495
|
+
}></span></span></div>`;
|
|
496
|
+
}
|
|
497
|
+
);
|
|
459
498
|
} catch (error) {
|
|
460
499
|
console.log(error);
|
|
461
500
|
return str;
|
|
@@ -2,23 +2,87 @@ hexo.extend.filter.register(
|
|
|
2
2
|
"before_post_render",
|
|
3
3
|
function (data) {
|
|
4
4
|
try {
|
|
5
|
+
const escapeAttribute = (value = "") =>
|
|
6
|
+
String(value)
|
|
7
|
+
.replace(/&/g, "&")
|
|
8
|
+
.replace(/"/g, """)
|
|
9
|
+
.replace(/</g, "<")
|
|
10
|
+
.replace(/>/g, ">");
|
|
11
|
+
|
|
12
|
+
const getImageAlt = (renderedLine) => {
|
|
13
|
+
const altMatch = renderedLine.match(/<img[\s\S]*?\salt=["']([^"']*)["']/i);
|
|
14
|
+
return altMatch?.[1]?.trim() || "";
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const getFallbackLabel = (renderedLine, index) => {
|
|
18
|
+
return getImageAlt(renderedLine) || `${index + 1}`;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const renderMarkdownLine = (line) =>
|
|
22
|
+
hexo.render
|
|
23
|
+
.renderSync({
|
|
24
|
+
text: line,
|
|
25
|
+
engine: "markdown"
|
|
26
|
+
})
|
|
27
|
+
.replace(/<p>/g, "")
|
|
28
|
+
.replace(/<\/p>/g, "")
|
|
29
|
+
.replace(/<br\s?\>/g, "");
|
|
30
|
+
|
|
5
31
|
const formatedContent = data.content.replace(
|
|
6
32
|
/:::image-grid(?:\s+([\w-]+))?([\s\S]*?):::/g,
|
|
7
33
|
(match, grid, content) => {
|
|
8
34
|
const gridClass = grid ? ` ${grid}` : "";
|
|
9
|
-
|
|
35
|
+
const lines = content
|
|
10
36
|
.split("\n")
|
|
11
37
|
.filter((v) => v)
|
|
38
|
+
.map((line) => line.trim());
|
|
39
|
+
|
|
40
|
+
if (grid === "switcher") {
|
|
41
|
+
const items = lines
|
|
42
|
+
.map((line, index) => {
|
|
43
|
+
const delimiterIndex = line.indexOf("|");
|
|
44
|
+
const hasLabel = delimiterIndex > -1;
|
|
45
|
+
const label = hasLabel ? line.slice(0, delimiterIndex).trim() : "";
|
|
46
|
+
const imageMarkdown = hasLabel ? line.slice(delimiterIndex + 1).trim() : line;
|
|
47
|
+
const renderedLine = renderMarkdownLine(imageMarkdown);
|
|
48
|
+
const alt = getImageAlt(renderedLine);
|
|
49
|
+
|
|
50
|
+
return /<img|<iframe/.test(renderedLine)
|
|
51
|
+
? {
|
|
52
|
+
label: alt || label || getFallbackLabel(renderedLine, index),
|
|
53
|
+
content: renderedLine
|
|
54
|
+
}
|
|
55
|
+
: null;
|
|
56
|
+
})
|
|
57
|
+
.filter(Boolean);
|
|
58
|
+
|
|
59
|
+
if (!items.length) return match;
|
|
60
|
+
|
|
61
|
+
return `<span class="image-grid switcher">${items
|
|
62
|
+
.map(
|
|
63
|
+
(item, index) =>
|
|
64
|
+
`<span class="grid-item${index === 0 ? " active" : ""}" data-switch-label="${escapeAttribute(
|
|
65
|
+
item.label
|
|
66
|
+
)}" role="tabpanel" aria-hidden="${index === 0 ? "false" : "true"}">${item.content}</span>`
|
|
67
|
+
)
|
|
68
|
+
.join(
|
|
69
|
+
""
|
|
70
|
+
)}<span class="image-grid-switcher-controls is-ready" role="tablist" style="--switcher-item-count: ${
|
|
71
|
+
items.length
|
|
72
|
+
}; --switcher-active-index: 0;">${items
|
|
73
|
+
.map(
|
|
74
|
+
(item, index) =>
|
|
75
|
+
`<button class="image-grid-switcher-button${index === 0 ? " active" : ""}" type="button" role="tab" aria-selected="${
|
|
76
|
+
index === 0 ? "true" : "false"
|
|
77
|
+
}">${escapeAttribute(item.label)}</button>`
|
|
78
|
+
)
|
|
79
|
+
.join("")}</span></span>`;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return `<span class="image-grid${gridClass}">${lines
|
|
12
83
|
.map((line) => {
|
|
13
|
-
const renderedLine =
|
|
14
|
-
|
|
15
|
-
text: line,
|
|
16
|
-
engine: "markdown",
|
|
17
|
-
})
|
|
18
|
-
.replace(/<p>/g, "")
|
|
19
|
-
.replace(/<\/p>/g, "")
|
|
20
|
-
.replace(/<br\s?\>/g, "");
|
|
21
|
-
return /<img/.test(renderedLine)
|
|
84
|
+
const renderedLine = renderMarkdownLine(line);
|
|
85
|
+
return /<img|<iframe/.test(renderedLine)
|
|
22
86
|
? `<span class="grid-item">${renderedLine}</span>`
|
|
23
87
|
: renderedLine;
|
|
24
88
|
})
|