@ecency/render-helper 2.4.30 → 2.4.31

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.
@@ -152,6 +152,8 @@ var ALLOWED_ATTRIBUTES = {
152
152
  ],
153
153
  "img": [
154
154
  "src",
155
+ "srcset",
156
+ "sizes",
155
157
  "alt",
156
158
  "class",
157
159
  "loading",
@@ -310,6 +312,10 @@ function sanitizeHtml(html) {
310
312
  const decodedLower = decoded.toLowerCase();
311
313
  if (name.startsWith("on")) return "";
312
314
  if (tag === "img" && name === "src" && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
315
+ if (tag === "img" && name === "srcset") {
316
+ const candidates = decoded.split(",").map((c) => c.trim().split(/\s+/)[0]);
317
+ if (candidates.some((url) => !/^https?:\/\//.test(url))) return "";
318
+ }
313
319
  if (tag === "video" && ["src", "poster"].includes(name) && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
314
320
  if (tag === "img" && ["dynsrc", "lowsrc"].includes(name)) return "";
315
321
  if (tag === "span" && name === "class" && decoded.toLowerCase().trim() === "wr") return "";
@@ -324,6 +330,9 @@ var proxyBase = "https://images.ecency.com";
324
330
  function setProxyBase(p2) {
325
331
  proxyBase = p2;
326
332
  }
333
+ function getProxyBase() {
334
+ return proxyBase;
335
+ }
327
336
  function extractPHash(url) {
328
337
  if (url.startsWith(`${proxyBase}/p/`)) {
329
338
  const [hash] = url.split("/p/")[1].split("?");
@@ -371,8 +380,24 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
371
380
  const b58url = multihash__default.default.toB58String(Buffer.from(realUrl.toString()));
372
381
  return `${proxyBase}/p/${b58url}?${qs}`;
373
382
  }
383
+ var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
384
+ function buildSrcSet(url) {
385
+ if (!url || typeof url !== "string") return "";
386
+ const escapedBase = proxyBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
387
+ const proxyPattern = new RegExp(`^${escapedBase}/p/([^?]+)`);
388
+ const match = url.match(proxyPattern);
389
+ if (match) {
390
+ const phash = extractPHash(url) || match[1];
391
+ return SRCSET_WIDTHS.map((w) => `${proxyBase}/p/${phash}?format=match&mode=fit&width=${w} ${w}w`).join(", ");
392
+ }
393
+ return SRCSET_WIDTHS.map((w) => {
394
+ const proxied = proxifyImageSrc(url, w);
395
+ return proxied ? `${proxied} ${w}w` : "";
396
+ }).filter(Boolean).join(", ");
397
+ }
374
398
 
375
399
  // src/methods/img.method.ts
400
+ var IMAGE_SIZES = "(max-width: 768px) 100vw, 700px";
376
401
  function img(el, state) {
377
402
  const src = el.getAttribute("src") || "";
378
403
  const decodedSrc = decodeURIComponent(
@@ -382,11 +407,15 @@ function img(el, state) {
382
407
  const isInvalid = !src || decodedSrc.startsWith("javascript") || decodedSrc.startsWith("vbscript") || decodedSrc === "x";
383
408
  if (isInvalid) {
384
409
  el.removeAttribute("src");
410
+ el.removeAttribute("srcset");
411
+ el.removeAttribute("sizes");
385
412
  return;
386
413
  }
387
414
  const isRelative = !/^https?:\/\//i.test(decodedSrc) && !decodedSrc.startsWith("/");
388
415
  if (isRelative) {
389
416
  el.removeAttribute("src");
417
+ el.removeAttribute("srcset");
418
+ el.removeAttribute("sizes");
390
419
  return;
391
420
  }
392
421
  el.setAttribute("itemprop", "image");
@@ -401,22 +430,41 @@ function img(el, state) {
401
430
  }
402
431
  const cls = el.getAttribute("class") || "";
403
432
  const shouldReplace = !cls.includes("no-replace");
404
- const hasAlreadyProxied = src.startsWith("https://images.ecency.com/p/") || src.startsWith("https://images.ecency.com/u/") || /^https:\/\/images\.ecency\.com\/\d+x\d+\//.test(src);
433
+ const base = getProxyBase().replace(/\/+$/, "");
434
+ const hasAlreadyProxied = src.startsWith(`${base}/p/`) || src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
405
435
  if (shouldReplace && !hasAlreadyProxied) {
406
436
  const proxified = proxifyImageSrc(decodedSrc);
407
437
  if (proxified) {
408
438
  el.setAttribute("src", proxified);
439
+ const srcset = buildSrcSet(decodedSrc);
440
+ if (srcset) {
441
+ el.setAttribute("srcset", srcset);
442
+ el.setAttribute("sizes", IMAGE_SIZES);
443
+ }
444
+ }
445
+ } else if (shouldReplace && hasAlreadyProxied) {
446
+ if (src.startsWith(`${base}/p/`)) {
447
+ const srcset = buildSrcSet(src);
448
+ if (srcset) {
449
+ el.setAttribute("srcset", srcset);
450
+ el.setAttribute("sizes", IMAGE_SIZES);
451
+ }
409
452
  }
410
453
  }
411
454
  }
412
455
  function createImageHTML(src, isLCP) {
413
456
  const proxified = proxifyImageSrc(src);
414
457
  if (!proxified) return "";
458
+ const base = getProxyBase().replace(/\/+$/, "");
459
+ const isAlreadyProxied = src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
460
+ const srcset = isAlreadyProxied ? "" : buildSrcSet(src);
415
461
  const loading = isLCP ? "eager" : "lazy";
416
462
  const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
463
+ const srcsetAttr = srcset ? `srcset="${srcset}" sizes="${IMAGE_SIZES}"` : "";
417
464
  return `<img
418
465
  class="markdown-img-link"
419
466
  src="${proxified}"
467
+ ${srcsetAttr}
420
468
  loading="${loading}"
421
469
  ${fetch}
422
470
  itemprop="image"
@@ -1810,6 +1858,7 @@ function getPostBodySummary(obj, length, platform) {
1810
1858
  }
1811
1859
 
1812
1860
  exports.SECTION_LIST = SECTION_LIST;
1861
+ exports.buildSrcSet = buildSrcSet;
1813
1862
  exports.catchPostImage = catchPostImage;
1814
1863
  exports.isValidPermlink = isValidPermlink;
1815
1864
  exports.postBodySummary = getPostBodySummary;