hexo-theme-linen 1.0.32 → 1.0.34

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/layout/layout.ejs CHANGED
@@ -122,9 +122,6 @@ const version = theme.version;
122
122
  <script src="<%=url_for(`${url}?v=${version}`)%>"></script>
123
123
  <% }); %>
124
124
  <% } %>
125
- <% if (theme?.lazyload?.enable ?? true) { %>
126
- <script src="<%=url_for(`/linen-theme/js/lazyload.js?v=${version}`)%>"></script>
127
- <% } %>
128
125
  <% if (page.hdrAssetsPrefix) { %>
129
126
  <script>
130
127
  var hdrAssetsPrefix = "<%-page.hdrAssetsPrefix%>"
@@ -133,6 +130,9 @@ const version = theme.version;
133
130
  <% if (page.hdrSwitch) { %>
134
131
  <script src="<%=url_for(`/linen-theme/js/hdr.js?v=${version}`)%>"></script>
135
132
  <% } %>
133
+ <% if (theme?.lazyload?.enable ?? true) { %>
134
+ <script src="<%=url_for(`/linen-theme/js/lazyload.js?v=${version}`)%>"></script>
135
+ <% } %>
136
136
  <% if (theme?.appends?.length > 0) { %>
137
137
  <% theme.appends.forEach(appendItem => { %>
138
138
  <%-appendItem%>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hexo-theme-linen",
3
- "version": "1.0.32",
3
+ "version": "1.0.34",
4
4
  "description": "A clean Hexo theme",
5
5
  "main": "index.js",
6
6
  "homepage": "https://github.com/lynanbreeze/hexo-theme-linen",
@@ -94,26 +94,34 @@
94
94
  if (typeof window === "undefined") {
95
95
  return;
96
96
  }
97
- function get(object, path, defaultValue) {
98
- if (object == null) return defaultValue;
99
-
100
- // 把 a[0].b 转成 a.0.b
101
- var pathArray =
102
- typeof path === "string"
103
- ? path.replace(/\[(\w+)\]/g, ".$1").split(".")
104
- : path;
105
-
106
- var result = object;
107
-
108
- for (var i = 0; i < pathArray.length; i++) {
109
- if (result == null) return defaultValue;
110
- result = result[pathArray[i]];
111
- }
112
-
113
- return result === undefined ? defaultValue : result;
114
- }
115
97
  var lazyloadItems = document.querySelectorAll(".lazyload-wrap");
116
98
  var loadingQueue = [];
99
+ var scheduleFrame = window.requestAnimationFrame || function (callback) {
100
+ return window.setTimeout(callback, 16);
101
+ };
102
+ var revealQueue = [];
103
+ var revealScheduled = false;
104
+ var flushRevealQueue = function flushRevealQueue() {
105
+ var callbacks = revealQueue.splice(0);
106
+ revealScheduled = false;
107
+ callbacks.forEach(function (callback) {
108
+ if (callback) callback();
109
+ });
110
+ if (revealQueue.length) {
111
+ scheduleReveal();
112
+ }
113
+ };
114
+ var scheduleReveal = function scheduleReveal(callback) {
115
+ if (callback) revealQueue.push(callback);
116
+ if (revealScheduled) return;
117
+ revealScheduled = true;
118
+ // Wait for one paint opportunity before revealing. The second frame is
119
+ // shared by all images that become ready together, avoiding per-image
120
+ // frame callbacks and preserving the transition for cached HDR images.
121
+ scheduleFrame(function () {
122
+ scheduleFrame(flushRevealQueue);
123
+ });
124
+ };
117
125
  var appendStyles = function appendStyles(element, styles) {
118
126
  var currentStyle = element.getAttribute("style");
119
127
  var newStyles = "";
@@ -128,6 +136,10 @@
128
136
  var nElement = document.createElement("div");
129
137
  nElement.innerHTML = contentStr;
130
138
  nElement.classList.add("inner-wrap");
139
+ nElement.style.opacity = "0";
140
+ if (!window.$lazyload || window.$lazyload.showTransition !== false) {
141
+ nElement.style.transition = "opacity ease-in-out 0.3s";
142
+ }
131
143
  return nElement;
132
144
  };
133
145
  var restore_fallback = function restore_fallback(element) {
@@ -151,6 +163,28 @@
151
163
  }
152
164
  return obj;
153
165
  };
166
+ var renderBlurHashPlaceholder = function renderBlurHashPlaceholder(element) {
167
+ var placeholderImage = element.dataset.blurhash;
168
+ if (!placeholderImage || element.dataset.blurhashRendered === "true") {
169
+ return;
170
+ }
171
+ var width = 32;
172
+ var height = 32;
173
+ var pixels = blurhash.decodeBlurHash(
174
+ placeholderImage.replace("blurhash:", ""),
175
+ width,
176
+ height,
177
+ );
178
+ var canvas = document.createElement("canvas");
179
+ var ctx = canvas.getContext("2d");
180
+ canvas.width = width;
181
+ canvas.height = height;
182
+ var imageData = ctx.createImageData(width, height);
183
+ imageData.data.set(pixels);
184
+ ctx.putImageData(imageData, 0, 0);
185
+ element.children[0].appendChild(canvas);
186
+ element.dataset.blurhashRendered = "true";
187
+ };
154
188
  var initPlaceholder = function initPlaceholder(element) {
155
189
  var wrap = document.createElement("div");
156
190
  // prevent triggering load event
@@ -166,25 +200,9 @@
166
200
  var placeholderImage =
167
201
  resourceElement.dataset.placeholderimg || altAttributes.placeholderImage;
168
202
  if (placeholderImage && /blurhash:/.test(placeholderImage)) {
169
- var createCanvas = function createCanvas() {
170
- var canvas = document.createElement("canvas");
171
- var width = 32;
172
- var height = 32;
173
- var pixels = blurhash.decodeBlurHash(
174
- placeholderImage.replace("blurhash:", ""),
175
- width,
176
- height,
177
- );
178
- var ctx = canvas.getContext("2d");
179
- canvas.width = width;
180
- canvas.height = height;
181
- var imageData = ctx.createImageData(width, height);
182
- imageData.data.set(pixels);
183
- ctx.putImageData(imageData, 0, 0);
184
- return canvas;
185
- };
186
- var cv = createCanvas();
187
- element.children[0].appendChild(cv);
203
+ // Decode only when this item is actually restored. Doing this for
204
+ // every image during page initialization can block the main thread.
205
+ element.dataset.blurhash = placeholderImage;
188
206
  }
189
207
  element.dataset.content = element.dataset.content
190
208
  .replace(/%24placeholder%3D(\S+)%3Dplaceholder/gi, "")
@@ -196,34 +214,70 @@
196
214
  loadingQueue.push(element);
197
215
  }
198
216
  if (element.classList && element.classList.contains("loaded")) return;
217
+ renderBlurHashPlaceholder(element);
199
218
  var contentStr = decodeURIComponent(element.dataset.content);
200
219
  var newElement = createResourceElement(contentStr);
201
220
  var initOnLoadEvent = function initOnLoadEvent(resourceElement) {
202
- resourceElement.children[0].onload = function () {
221
+ var imageElement = resourceElement.children[0];
222
+ var revealedSource = "";
223
+ var revealToken = 0;
224
+ var showTransition =
225
+ !window.$lazyload || window.$lazyload.showTransition !== false;
226
+ var clearPlaceholder = function clearPlaceholder() {
227
+ var keepPlaceholder =
228
+ element.getAttribute("data-hdr-active") === "true" ||
229
+ (window.$lazyload && window.$lazyload.keepPlaceholder === true);
230
+ if (!keepPlaceholder) {
231
+ element.children[0].classList.add("loaded");
232
+ }
233
+ };
234
+ var revealResource = function revealResource() {
235
+ var source = imageElement.currentSrc || imageElement.src || "";
236
+ if (revealedSource === source && element.classList.contains("loaded")) {
237
+ return;
238
+ }
239
+ var token = ++revealToken;
240
+ // `load` means the resource is available, but the browser may still
241
+ // need a paint opportunity before the image becomes visible. Do not
242
+ // call HTMLImageElement.decode() here: some HDR decoders crash the
243
+ // renderer before JavaScript can handle the resulting exception.
244
+ scheduleReveal(function () {
245
+ if (token !== revealToken) return;
246
+ if ((imageElement.currentSrc || imageElement.src || "") !== source) {
247
+ return;
248
+ }
249
+ revealedSource = source;
250
+ // The inline opacity is already 0 and the inline transition is set
251
+ // before insertion, so the next frame can reveal without forcing a
252
+ // synchronous layout for every image.
253
+ resourceElement.style.opacity = "1";
254
+ resourceElement.classList.add("loaded");
255
+ element.classList.add("loaded");
256
+ if (!showTransition) {
257
+ clearPlaceholder();
258
+ }
259
+ });
260
+ };
261
+ imageElement.onload = function () {
203
262
  try {
204
- setTimeout(function () {
205
- element.classList.add("loaded");
206
- var isImage =
207
- resourceElement.children &&
208
- resourceElement.children[0] &&
209
- resourceElement.children[0].tagName === "IMG";
210
- var wrapElement = element.parentElement;
211
- var width = resourceElement.children[0].naturalWidth;
212
- if (
213
- isImage &&
214
- wrapElement &&
215
- wrapElement.tagName === "A" &&
216
- wrapElement.getAttribute("data-pswp-hassize") !== "true"
217
- ) {
218
- var height = resourceElement.children[0].naturalHeight;
219
- element.children[0].style.paddingBottom = `${
220
- (height / width) * 100
221
- }%`;
222
- wrapElement.setAttribute("data-pswp-width", width);
223
- wrapElement.setAttribute("data-pswp-height", height);
224
- wrapElement.setAttribute("data-cropped", true);
225
- }
226
- }, 100);
263
+ revealResource();
264
+ var isImage = imageElement && imageElement.tagName === "IMG";
265
+ var wrapElement = element.parentElement;
266
+ var width = imageElement.naturalWidth;
267
+ if (
268
+ isImage &&
269
+ wrapElement &&
270
+ wrapElement.tagName === "A" &&
271
+ wrapElement.getAttribute("data-pswp-hassize") !== "true"
272
+ ) {
273
+ var height = imageElement.naturalHeight;
274
+ element.children[0].style.paddingBottom = `${
275
+ (height / width) * 100
276
+ }%`;
277
+ wrapElement.setAttribute("data-pswp-width", width);
278
+ wrapElement.setAttribute("data-pswp-height", height);
279
+ wrapElement.setAttribute("data-cropped", true);
280
+ }
227
281
  var errorElement = element.querySelectorAll(".error-wrap")[0];
228
282
  if (errorElement) {
229
283
  element.removeChild(errorElement);
@@ -232,10 +286,17 @@
232
286
  console.log(e);
233
287
  }
234
288
  };
235
- resourceElement.ontransitionend = function () {
236
- if (get(window, "$lazyload.keepPlaceholder", false) === false) {
237
- element.children[0].classList.add("loaded");
238
- }
289
+ // Cached images can already be complete before the load listener is
290
+ // observed. Use the same paint-safe path for that case.
291
+ if (imageElement.complete && imageElement.naturalWidth) {
292
+ revealResource();
293
+ }
294
+ resourceElement.ontransitionend = function (event) {
295
+ if (event.propertyName && event.propertyName !== "opacity") return;
296
+ // HDR gain-map composition can finish after the normal image
297
+ // load/opacity transition. Keep its placeholder, but clear it for
298
+ // normal images so transparent PNG/WebP images are not covered by it.
299
+ clearPlaceholder();
239
300
  };
240
301
  if (/<video/.test(contentStr)) {
241
302
  setTimeout(function () {
@@ -135,7 +135,8 @@ module.exports = function (hexo) {
135
135
 
136
136
  let settingsContent = `<script>var $lazyload = {
137
137
  intersectionRatio: ${intersectionRatio},
138
- preloadCount: ${preloadCount},
138
+ preloadCount: ${preloadCount},
139
+ showTransition: ${showTransition},
139
140
  keepPlaceholder: ${
140
141
  page?.lazyload?.keepPlaceholder ?? false
141
142
  }}</script>`;
@@ -20,7 +20,7 @@
20
20
  padding-bottom: 66.66667%;
21
21
  background-size: 100% 100%;
22
22
  background-repeat: no-repeat;
23
- background-image: url(../img/lazyload/loading.svg);
23
+ background-image: url(../linen-theme/img/lazyload/loading.svg);
24
24
  background-color: #fff;
25
25
  }
26
26
  .lazyload-wrap .placeholder canvas{
@@ -77,7 +77,7 @@
77
77
  .lazyload-wrap .error-wrap .error-tip{
78
78
  width: 60%;
79
79
  background-size: cover;
80
- background-image: url(../img/lazyload/error-tip.svg);
80
+ background-image: url(../linen-theme/img/lazyload/error-tip.svg);
81
81
  }
82
82
  .lazyload-wrap .error-wrap .error-tip::before{
83
83
  content: '';