@ecency/render-helper 2.4.30 → 2.4.32
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/dist/browser/index.d.ts +6 -1
- package/dist/browser/index.js +58 -9
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +59 -9
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.mjs +58 -9
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.d.ts
CHANGED
|
@@ -54,6 +54,11 @@ declare function setProxyBase(p: string): void;
|
|
|
54
54
|
* @param _format - @deprecated Ignored. Always uses 'match' — format is handled server-side via Accept header.
|
|
55
55
|
*/
|
|
56
56
|
declare function proxifyImageSrc(url?: string, width?: number, height?: number, _format?: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Builds a srcset string with multiple width variants for responsive images.
|
|
59
|
+
* Uses the image proxy's width parameter to serve appropriately sized images.
|
|
60
|
+
*/
|
|
61
|
+
declare function buildSrcSet(url?: string): string;
|
|
57
62
|
|
|
58
63
|
declare function setCacheSize(size: number): void;
|
|
59
64
|
|
|
@@ -71,4 +76,4 @@ declare function isValidPermlink(permlink: string): boolean;
|
|
|
71
76
|
*/
|
|
72
77
|
declare function simpleMarkdownToHTML(input: string): string;
|
|
73
78
|
|
|
74
|
-
export { type Entry, type RenderOptions, SECTION_LIST, type SeoContext, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
|
|
79
|
+
export { type Entry, type RenderOptions, SECTION_LIST, type SeoContext, buildSrcSet, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
|
package/dist/browser/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DOMParser as DOMParser$1, XMLSerializer } from '@xmldom/xmldom';
|
|
1
|
+
import { DOMParser as DOMParser$1, XMLSerializer as XMLSerializer$1 } from '@xmldom/xmldom';
|
|
2
2
|
import xss from 'xss';
|
|
3
3
|
import multihash from 'multihashes';
|
|
4
4
|
import querystring from 'querystring';
|
|
@@ -123,6 +123,8 @@ var ALLOWED_ATTRIBUTES = {
|
|
|
123
123
|
],
|
|
124
124
|
"img": [
|
|
125
125
|
"src",
|
|
126
|
+
"srcset",
|
|
127
|
+
"sizes",
|
|
126
128
|
"alt",
|
|
127
129
|
"class",
|
|
128
130
|
"loading",
|
|
@@ -166,14 +168,13 @@ var ALLOWED_ATTRIBUTES = {
|
|
|
166
168
|
"del": [],
|
|
167
169
|
"ins": []
|
|
168
170
|
};
|
|
169
|
-
var
|
|
171
|
+
var hasDOMParser = typeof globalThis.DOMParser !== "undefined";
|
|
172
|
+
var hasXMLSerializer = typeof globalThis.XMLSerializer !== "undefined";
|
|
173
|
+
var lenientErrorHandler = (level, msg, _context) => {
|
|
170
174
|
return void 0;
|
|
171
175
|
};
|
|
172
|
-
var DOMParser = new DOMParser$1({
|
|
173
|
-
|
|
174
|
-
// By providing a non-throwing error handler, parsing continues despite malformed HTML
|
|
175
|
-
onError: lenientErrorHandler
|
|
176
|
-
});
|
|
176
|
+
var DOMParser = hasDOMParser ? new globalThis.DOMParser() : new DOMParser$1({ onError: lenientErrorHandler });
|
|
177
|
+
var XMLSerializer = hasXMLSerializer ? globalThis.XMLSerializer : XMLSerializer$1;
|
|
177
178
|
|
|
178
179
|
// src/helper.ts
|
|
179
180
|
function removeDuplicateAttributes(html) {
|
|
@@ -251,6 +252,8 @@ function isValidUsername(username) {
|
|
|
251
252
|
!label.includes("..");
|
|
252
253
|
});
|
|
253
254
|
}
|
|
255
|
+
|
|
256
|
+
// src/methods/get-inner-html.method.ts
|
|
254
257
|
function getSerializedInnerHTML(node) {
|
|
255
258
|
const serializer = new XMLSerializer();
|
|
256
259
|
if (node.childNodes[0]) {
|
|
@@ -278,6 +281,10 @@ function sanitizeHtml(html) {
|
|
|
278
281
|
const decodedLower = decoded.toLowerCase();
|
|
279
282
|
if (name.startsWith("on")) return "";
|
|
280
283
|
if (tag === "img" && name === "src" && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
|
|
284
|
+
if (tag === "img" && name === "srcset") {
|
|
285
|
+
const candidates = decoded.split(",").map((c) => c.trim().split(/\s+/)[0]);
|
|
286
|
+
if (candidates.some((url) => !/^https?:\/\//.test(url))) return "";
|
|
287
|
+
}
|
|
281
288
|
if (tag === "video" && ["src", "poster"].includes(name) && (!/^https?:\/\//.test(decodedLower) || decodedLower.startsWith("javascript:"))) return "";
|
|
282
289
|
if (tag === "img" && ["dynsrc", "lowsrc"].includes(name)) return "";
|
|
283
290
|
if (tag === "span" && name === "class" && decoded.toLowerCase().trim() === "wr") return "";
|
|
@@ -292,6 +299,9 @@ var proxyBase = "https://images.ecency.com";
|
|
|
292
299
|
function setProxyBase(p2) {
|
|
293
300
|
proxyBase = p2;
|
|
294
301
|
}
|
|
302
|
+
function getProxyBase() {
|
|
303
|
+
return proxyBase;
|
|
304
|
+
}
|
|
295
305
|
function extractPHash(url) {
|
|
296
306
|
if (url.startsWith(`${proxyBase}/p/`)) {
|
|
297
307
|
const [hash] = url.split("/p/")[1].split("?");
|
|
@@ -339,8 +349,24 @@ function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
|
|
|
339
349
|
const b58url = multihash.toB58String(Buffer.from(realUrl.toString()));
|
|
340
350
|
return `${proxyBase}/p/${b58url}?${qs}`;
|
|
341
351
|
}
|
|
352
|
+
var SRCSET_WIDTHS = [320, 600, 800, 1024, 1280];
|
|
353
|
+
function buildSrcSet(url) {
|
|
354
|
+
if (!url || typeof url !== "string") return "";
|
|
355
|
+
const escapedBase = proxyBase.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
356
|
+
const proxyPattern = new RegExp(`^${escapedBase}/p/([^?]+)`);
|
|
357
|
+
const match = url.match(proxyPattern);
|
|
358
|
+
if (match) {
|
|
359
|
+
const phash = extractPHash(url) || match[1];
|
|
360
|
+
return SRCSET_WIDTHS.map((w) => `${proxyBase}/p/${phash}?format=match&mode=fit&width=${w} ${w}w`).join(", ");
|
|
361
|
+
}
|
|
362
|
+
return SRCSET_WIDTHS.map((w) => {
|
|
363
|
+
const proxied = proxifyImageSrc(url, w);
|
|
364
|
+
return proxied ? `${proxied} ${w}w` : "";
|
|
365
|
+
}).filter(Boolean).join(", ");
|
|
366
|
+
}
|
|
342
367
|
|
|
343
368
|
// src/methods/img.method.ts
|
|
369
|
+
var IMAGE_SIZES = "(max-width: 768px) 100vw, 700px";
|
|
344
370
|
function img(el, state) {
|
|
345
371
|
const src = el.getAttribute("src") || "";
|
|
346
372
|
const decodedSrc = decodeURIComponent(
|
|
@@ -350,11 +376,15 @@ function img(el, state) {
|
|
|
350
376
|
const isInvalid = !src || decodedSrc.startsWith("javascript") || decodedSrc.startsWith("vbscript") || decodedSrc === "x";
|
|
351
377
|
if (isInvalid) {
|
|
352
378
|
el.removeAttribute("src");
|
|
379
|
+
el.removeAttribute("srcset");
|
|
380
|
+
el.removeAttribute("sizes");
|
|
353
381
|
return;
|
|
354
382
|
}
|
|
355
383
|
const isRelative = !/^https?:\/\//i.test(decodedSrc) && !decodedSrc.startsWith("/");
|
|
356
384
|
if (isRelative) {
|
|
357
385
|
el.removeAttribute("src");
|
|
386
|
+
el.removeAttribute("srcset");
|
|
387
|
+
el.removeAttribute("sizes");
|
|
358
388
|
return;
|
|
359
389
|
}
|
|
360
390
|
el.setAttribute("itemprop", "image");
|
|
@@ -369,22 +399,41 @@ function img(el, state) {
|
|
|
369
399
|
}
|
|
370
400
|
const cls = el.getAttribute("class") || "";
|
|
371
401
|
const shouldReplace = !cls.includes("no-replace");
|
|
372
|
-
const
|
|
402
|
+
const base = getProxyBase().replace(/\/+$/, "");
|
|
403
|
+
const hasAlreadyProxied = src.startsWith(`${base}/p/`) || src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
|
|
373
404
|
if (shouldReplace && !hasAlreadyProxied) {
|
|
374
405
|
const proxified = proxifyImageSrc(decodedSrc);
|
|
375
406
|
if (proxified) {
|
|
376
407
|
el.setAttribute("src", proxified);
|
|
408
|
+
const srcset = buildSrcSet(decodedSrc);
|
|
409
|
+
if (srcset) {
|
|
410
|
+
el.setAttribute("srcset", srcset);
|
|
411
|
+
el.setAttribute("sizes", IMAGE_SIZES);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
} else if (shouldReplace && hasAlreadyProxied) {
|
|
415
|
+
if (src.startsWith(`${base}/p/`)) {
|
|
416
|
+
const srcset = buildSrcSet(src);
|
|
417
|
+
if (srcset) {
|
|
418
|
+
el.setAttribute("srcset", srcset);
|
|
419
|
+
el.setAttribute("sizes", IMAGE_SIZES);
|
|
420
|
+
}
|
|
377
421
|
}
|
|
378
422
|
}
|
|
379
423
|
}
|
|
380
424
|
function createImageHTML(src, isLCP) {
|
|
381
425
|
const proxified = proxifyImageSrc(src);
|
|
382
426
|
if (!proxified) return "";
|
|
427
|
+
const base = getProxyBase().replace(/\/+$/, "");
|
|
428
|
+
const isAlreadyProxied = src.startsWith(`${base}/u/`) || new RegExp(`^${base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}/\\d+x\\d+/`).test(src);
|
|
429
|
+
const srcset = isAlreadyProxied ? "" : buildSrcSet(src);
|
|
383
430
|
const loading = isLCP ? "eager" : "lazy";
|
|
384
431
|
const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
|
|
432
|
+
const srcsetAttr = srcset ? `srcset="${srcset}" sizes="${IMAGE_SIZES}"` : "";
|
|
385
433
|
return `<img
|
|
386
434
|
class="markdown-img-link"
|
|
387
435
|
src="${proxified}"
|
|
436
|
+
${srcsetAttr}
|
|
388
437
|
loading="${loading}"
|
|
389
438
|
${fetch}
|
|
390
439
|
itemprop="image"
|
|
@@ -1777,6 +1826,6 @@ function getPostBodySummary(obj, length, platform) {
|
|
|
1777
1826
|
return res;
|
|
1778
1827
|
}
|
|
1779
1828
|
|
|
1780
|
-
export { SECTION_LIST, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
|
|
1829
|
+
export { SECTION_LIST, buildSrcSet, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase, simpleMarkdownToHTML };
|
|
1781
1830
|
//# sourceMappingURL=index.js.map
|
|
1782
1831
|
//# sourceMappingURL=index.js.map
|