@ecency/render-helper 2.4.14 → 2.4.16
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 +26 -3
- package/dist/browser/index.js +58 -49
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +58 -49
- package/dist/node/index.cjs.map +1 -1
- package/dist/node/index.mjs +58 -49
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.d.ts
CHANGED
|
@@ -9,7 +9,27 @@ interface Entry {
|
|
|
9
9
|
json_metadata?: any;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* SEO context for controlling rel attributes on external links in user-generated content.
|
|
14
|
+
*
|
|
15
|
+
* By default, all external links get rel="nofollow ugc noopener" to prevent link spam.
|
|
16
|
+
* High-quality content (high author reputation + meaningful post rewards) earns followed links.
|
|
17
|
+
*/
|
|
18
|
+
interface SeoContext {
|
|
19
|
+
/** Human-readable author reputation score (after accountReputation() conversion) */
|
|
20
|
+
authorReputation?: number;
|
|
21
|
+
/** Total post payout in USD */
|
|
22
|
+
postPayout?: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param obj - Entry object or raw markdown string
|
|
27
|
+
* @param forApp - Whether rendering for app context
|
|
28
|
+
* @param _webp - @deprecated Ignored. Format is now handled server-side via Accept header content negotiation.
|
|
29
|
+
* @param parentDomain - Parent domain for iframe embed parameters
|
|
30
|
+
* @param seoContext - Optional SEO context for structured data
|
|
31
|
+
*/
|
|
32
|
+
declare function markdown2Html(obj: Entry | string, forApp?: boolean, _webp?: boolean, parentDomain?: string, seoContext?: SeoContext): string;
|
|
13
33
|
|
|
14
34
|
declare function catchPostImage(obj: Entry | string, width?: number, height?: number, format?: string): string | null;
|
|
15
35
|
|
|
@@ -24,7 +44,10 @@ declare function catchPostImage(obj: Entry | string, width?: number, height?: nu
|
|
|
24
44
|
declare function getPostBodySummary(obj: Entry | string, length?: number, platform?: 'ios' | 'android' | 'web'): string;
|
|
25
45
|
|
|
26
46
|
declare function setProxyBase(p: string): void;
|
|
27
|
-
|
|
47
|
+
/**
|
|
48
|
+
* @param _format - @deprecated Ignored. Always uses 'match' — format is handled server-side via Accept header.
|
|
49
|
+
*/
|
|
50
|
+
declare function proxifyImageSrc(url?: string, width?: number, height?: number, _format?: string): string;
|
|
28
51
|
|
|
29
52
|
declare function setCacheSize(size: number): void;
|
|
30
53
|
|
|
@@ -32,4 +55,4 @@ declare const SECTION_LIST: string[];
|
|
|
32
55
|
|
|
33
56
|
declare function isValidPermlink(permlink: string): boolean;
|
|
34
57
|
|
|
35
|
-
export { type Entry, SECTION_LIST, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase };
|
|
58
|
+
export { type Entry, SECTION_LIST, type SeoContext, catchPostImage, isValidPermlink, getPostBodySummary as postBodySummary, proxifyImageSrc, markdown2Html as renderPostBody, setCacheSize, setProxyBase };
|
package/dist/browser/index.js
CHANGED
|
@@ -78,8 +78,8 @@ var LBRY_REGEX = /^(https?:)?\/\/lbry.tv\/\$\/embed\/[^?#]+(?:$|[?#])/i;
|
|
|
78
78
|
var ODYSEE_REGEX = /^(https?:)?\/\/odysee\.com\/(?:\$|%24)\/embed\/[^/?#]+(?:$|[?#])/i;
|
|
79
79
|
var SKATEHIVE_IPFS_REGEX = /^https?:\/\/ipfs\.skatehive\.app\/ipfs\/([^/?#]+)/i;
|
|
80
80
|
var ARCH_REGEX = /^(https?:)?\/\/archive.org\/embed\/[^/?#]+(?:$|[?#])/i;
|
|
81
|
-
var SPEAK_REGEX = /(?:https?:\/\/(?:(?:play\.)?3speak
|
|
82
|
-
var SPEAK_EMBED_REGEX = /^(https?:)?\/\/(?:play\.)?3speak
|
|
81
|
+
var SPEAK_REGEX = /(?:https?:\/\/(?:(?:play\.)?3speak\.([a-z]+)\/watch\?v=)|(?:(?:play\.)?3speak\.([a-z]+)\/embed\?v=))([A-Za-z0-9_\-\.\/]+)(&.*)?/i;
|
|
82
|
+
var SPEAK_EMBED_REGEX = /^(https?:)?\/\/(?:play\.)?3speak\.([a-z]+)\/(?:embed|watch)\?.+$/i;
|
|
83
83
|
var TWITTER_REGEX = /(?:https?:\/\/(?:(?:twitter\.com\/(.*?)\/status\/(.*))))/gi;
|
|
84
84
|
var SPOTIFY_REGEX = /^https:\/\/open\.spotify\.com\/playlist\/(.*)?$/gi;
|
|
85
85
|
var RUMBLE_REGEX = /^https:\/\/rumble.com\/embed\/([a-zA-Z0-9-]+)\/\?pub=\w+/;
|
|
@@ -284,15 +284,13 @@ function sanitizeHtml(html) {
|
|
|
284
284
|
});
|
|
285
285
|
}
|
|
286
286
|
var proxyBase = "https://images.ecency.com";
|
|
287
|
-
var fileExtension = true;
|
|
288
287
|
function setProxyBase(p2) {
|
|
289
288
|
proxyBase = p2;
|
|
290
|
-
fileExtension = proxyBase == "https://images.ecency.com";
|
|
291
289
|
}
|
|
292
290
|
function extractPHash(url) {
|
|
293
291
|
if (url.startsWith(`${proxyBase}/p/`)) {
|
|
294
292
|
const [hash] = url.split("/p/")[1].split("?");
|
|
295
|
-
return hash.replace(
|
|
293
|
+
return hash.replace(/\.(webp|png)$/, "");
|
|
296
294
|
}
|
|
297
295
|
return null;
|
|
298
296
|
}
|
|
@@ -307,7 +305,7 @@ function getLatestUrl(str) {
|
|
|
307
305
|
const [last] = [...str.replace(/https?:\/\//g, "\n$&").trim().split("\n")].reverse();
|
|
308
306
|
return last;
|
|
309
307
|
}
|
|
310
|
-
function proxifyImageSrc(url, width = 0, height = 0,
|
|
308
|
+
function proxifyImageSrc(url, width = 0, height = 0, _format = "match") {
|
|
311
309
|
if (!url || typeof url !== "string" || !isValidUrl(url)) {
|
|
312
310
|
return "";
|
|
313
311
|
}
|
|
@@ -320,7 +318,7 @@ function proxifyImageSrc(url, width = 0, height = 0, format = "match") {
|
|
|
320
318
|
const realUrl = getLatestUrl(url);
|
|
321
319
|
const pHash = extractPHash(realUrl);
|
|
322
320
|
const options = {
|
|
323
|
-
format,
|
|
321
|
+
format: "match",
|
|
324
322
|
mode: "fit"
|
|
325
323
|
};
|
|
326
324
|
if (width > 0) {
|
|
@@ -331,31 +329,29 @@ function proxifyImageSrc(url, width = 0, height = 0, format = "match") {
|
|
|
331
329
|
}
|
|
332
330
|
const qs = querystring.stringify(options);
|
|
333
331
|
if (pHash) {
|
|
334
|
-
|
|
335
|
-
return `${proxyBase}/p/${pHash}${format === "webp" ? ".webp" : ".png"}?${qs}`;
|
|
336
|
-
} else {
|
|
337
|
-
return `${proxyBase}/p/${pHash}?${qs}`;
|
|
338
|
-
}
|
|
332
|
+
return `${proxyBase}/p/${pHash}?${qs}`;
|
|
339
333
|
}
|
|
340
334
|
const b58url = multihash.toB58String(Buffer.from(realUrl.toString()));
|
|
341
|
-
return `${proxyBase}/p/${b58url}
|
|
335
|
+
return `${proxyBase}/p/${b58url}?${qs}`;
|
|
342
336
|
}
|
|
343
337
|
|
|
344
338
|
// src/methods/img.method.ts
|
|
345
|
-
function img(el,
|
|
346
|
-
|
|
339
|
+
function img(el, state) {
|
|
340
|
+
const src = el.getAttribute("src") || "";
|
|
347
341
|
const decodedSrc = decodeURIComponent(
|
|
348
342
|
src.replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(dec)).replace(/&#x([0-9a-f]+);/gi, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
349
343
|
).trim();
|
|
344
|
+
["onerror", "dynsrc", "lowsrc", "width", "height"].forEach((attr) => el.removeAttribute(attr));
|
|
350
345
|
const isInvalid = !src || decodedSrc.startsWith("javascript") || decodedSrc.startsWith("vbscript") || decodedSrc === "x";
|
|
351
346
|
if (isInvalid) {
|
|
352
|
-
src
|
|
347
|
+
el.removeAttribute("src");
|
|
348
|
+
return;
|
|
353
349
|
}
|
|
354
350
|
const isRelative = !/^https?:\/\//i.test(decodedSrc) && !decodedSrc.startsWith("/");
|
|
355
351
|
if (isRelative) {
|
|
356
|
-
src
|
|
352
|
+
el.removeAttribute("src");
|
|
353
|
+
return;
|
|
357
354
|
}
|
|
358
|
-
["onerror", "dynsrc", "lowsrc", "width", "height"].forEach((attr) => el.removeAttribute(attr));
|
|
359
355
|
el.setAttribute("itemprop", "image");
|
|
360
356
|
const isLCP = state && !state.firstImageFound;
|
|
361
357
|
if (isLCP) {
|
|
@@ -370,14 +366,17 @@ function img(el, webp, state) {
|
|
|
370
366
|
const shouldReplace = !cls.includes("no-replace");
|
|
371
367
|
const hasAlreadyProxied = src.startsWith("https://images.ecency.com");
|
|
372
368
|
if (shouldReplace && !hasAlreadyProxied) {
|
|
373
|
-
const proxified = proxifyImageSrc(
|
|
374
|
-
|
|
369
|
+
const proxified = proxifyImageSrc(decodedSrc);
|
|
370
|
+
if (proxified) {
|
|
371
|
+
el.setAttribute("src", proxified);
|
|
372
|
+
}
|
|
375
373
|
}
|
|
376
374
|
}
|
|
377
|
-
function createImageHTML(src, isLCP
|
|
375
|
+
function createImageHTML(src, isLCP) {
|
|
376
|
+
const proxified = proxifyImageSrc(src);
|
|
377
|
+
if (!proxified) return "";
|
|
378
378
|
const loading = isLCP ? "eager" : "lazy";
|
|
379
379
|
const fetch = isLCP ? 'fetchpriority="high"' : 'decoding="async"';
|
|
380
|
-
const proxified = proxifyImageSrc(src, 0, 0, webp ? "webp" : "match");
|
|
381
380
|
return `<img
|
|
382
381
|
class="markdown-img-link"
|
|
383
382
|
src="${proxified}"
|
|
@@ -388,6 +387,14 @@ function createImageHTML(src, isLCP, webp) {
|
|
|
388
387
|
}
|
|
389
388
|
|
|
390
389
|
// src/methods/a.method.ts
|
|
390
|
+
var NOFOLLOW_REPUTATION_THRESHOLD = 40;
|
|
391
|
+
var FOLLOW_PAYOUT_THRESHOLD = 5;
|
|
392
|
+
function getExternalLinkRel(seoContext) {
|
|
393
|
+
if (seoContext?.authorReputation !== void 0 && seoContext?.postPayout !== void 0 && seoContext.authorReputation >= NOFOLLOW_REPUTATION_THRESHOLD && seoContext.postPayout > FOLLOW_PAYOUT_THRESHOLD) {
|
|
394
|
+
return "noopener";
|
|
395
|
+
}
|
|
396
|
+
return "nofollow ugc noopener";
|
|
397
|
+
}
|
|
391
398
|
var normalizeValue = (value) => value ? value.trim() : "";
|
|
392
399
|
var matchesHref = (href, value) => {
|
|
393
400
|
const normalizedHref = normalizeValue(href);
|
|
@@ -421,7 +428,7 @@ var addLineBreakBeforePostLink = (el, forApp, isInline) => {
|
|
|
421
428
|
el.parentNode.insertBefore(br, el);
|
|
422
429
|
}
|
|
423
430
|
};
|
|
424
|
-
function a(el, forApp,
|
|
431
|
+
function a(el, forApp, parentDomain = "ecency.com", seoContext) {
|
|
425
432
|
if (!el || !el.parentNode) {
|
|
426
433
|
return;
|
|
427
434
|
}
|
|
@@ -439,7 +446,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
439
446
|
}
|
|
440
447
|
if (href.match(IMG_REGEX) && href.trim().replace(/&/g, "&") === getSerializedInnerHTML(el).trim().replace(/&/g, "&")) {
|
|
441
448
|
const isLCP = false;
|
|
442
|
-
const imgHTML = createImageHTML(href, isLCP
|
|
449
|
+
const imgHTML = createImageHTML(href, isLCP);
|
|
443
450
|
const doc = DOMParser.parseFromString(imgHTML, "text/html");
|
|
444
451
|
const replaceNode = doc.body?.firstChild || doc.firstChild;
|
|
445
452
|
if (replaceNode) {
|
|
@@ -761,7 +768,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
761
768
|
el.setAttribute("class", "markdown-video-link markdown-video-link-youtube");
|
|
762
769
|
el.removeAttribute("href");
|
|
763
770
|
const vid = match[1];
|
|
764
|
-
const thumbnail = proxifyImageSrc(`https://img.youtube.com/vi/${vid.split("?")[0]}/hqdefault.jpg`, 0, 0,
|
|
771
|
+
const thumbnail = proxifyImageSrc(`https://img.youtube.com/vi/${vid.split("?")[0]}/hqdefault.jpg`, 0, 0, "match");
|
|
765
772
|
const embedSrc = `https://www.youtube.com/embed/${vid}?autoplay=1`;
|
|
766
773
|
el.textContent = "";
|
|
767
774
|
el.setAttribute("data-embed-src", embedSrc);
|
|
@@ -857,7 +864,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
857
864
|
if (imgEls.length === 1) {
|
|
858
865
|
const src = imgEls[0].getAttribute("src");
|
|
859
866
|
if (src) {
|
|
860
|
-
const thumbnail = proxifyImageSrc(src.replace(/\s+/g, ""), 0, 0,
|
|
867
|
+
const thumbnail = proxifyImageSrc(src.replace(/\s+/g, ""), 0, 0, "match");
|
|
861
868
|
const thumbImg = el.ownerDocument.createElement("img");
|
|
862
869
|
thumbImg.setAttribute("class", "no-replace video-thumbnail");
|
|
863
870
|
thumbImg.setAttribute("itemprop", "thumbnailUrl");
|
|
@@ -892,7 +899,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
892
899
|
const imgEls2 = el.getElementsByTagName("img");
|
|
893
900
|
if (imgEls2.length === 1 || el.textContent.trim() === href) {
|
|
894
901
|
if ((match[1] || match[2]) && match[3]) {
|
|
895
|
-
const videoHref = `https://play.3speak.tv/
|
|
902
|
+
const videoHref = `https://play.3speak.tv/embed?v=${match[3]}&mode=iframe`;
|
|
896
903
|
el.setAttribute("class", "markdown-video-link markdown-video-link-speak");
|
|
897
904
|
el.removeAttribute("href");
|
|
898
905
|
el.setAttribute("data-embed-src", videoHref);
|
|
@@ -902,7 +909,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
902
909
|
if (imgEls2.length === 1) {
|
|
903
910
|
const src = imgEls2[0].getAttribute("src");
|
|
904
911
|
if (src) {
|
|
905
|
-
const thumbnail = proxifyImageSrc(src.replace(/\s+/g, ""), 0, 0,
|
|
912
|
+
const thumbnail = proxifyImageSrc(src.replace(/\s+/g, ""), 0, 0, "match");
|
|
906
913
|
const thumbImg = el.ownerDocument.createElement("img");
|
|
907
914
|
thumbImg.setAttribute("class", "no-replace video-thumbnail");
|
|
908
915
|
thumbImg.setAttribute("itemprop", "thumbnailUrl");
|
|
@@ -981,7 +988,7 @@ function a(el, forApp, webp, parentDomain = "ecency.com") {
|
|
|
981
988
|
el.setAttribute("class", "markdown-internal-link");
|
|
982
989
|
} else {
|
|
983
990
|
el.setAttribute("target", "_blank");
|
|
984
|
-
el.setAttribute("rel",
|
|
991
|
+
el.setAttribute("rel", getExternalLinkRel(seoContext));
|
|
985
992
|
}
|
|
986
993
|
el.setAttribute("href", href);
|
|
987
994
|
}
|
|
@@ -1025,7 +1032,8 @@ function iframe(el, parentDomain = "ecency.com") {
|
|
|
1025
1032
|
return;
|
|
1026
1033
|
}
|
|
1027
1034
|
if (src.match(SPEAK_EMBED_REGEX)) {
|
|
1028
|
-
let normalizedSrc = src.replace(/3speak\.[a-z]+/i, "play.3speak.tv");
|
|
1035
|
+
let normalizedSrc = src.replace(/(?:play\.)?3speak\.[a-z]+/i, "play.3speak.tv");
|
|
1036
|
+
normalizedSrc = normalizedSrc.replace(/\/watch\?/, "/embed?");
|
|
1029
1037
|
const hasMode = /[?&]mode=/.test(normalizedSrc);
|
|
1030
1038
|
if (!hasMode) {
|
|
1031
1039
|
normalizedSrc = `${normalizedSrc}&mode=iframe`;
|
|
@@ -1033,6 +1041,7 @@ function iframe(el, parentDomain = "ecency.com") {
|
|
|
1033
1041
|
const hasAutoplay = /[?&]autoplay=/.test(normalizedSrc);
|
|
1034
1042
|
const s = hasAutoplay ? normalizedSrc : `${normalizedSrc}&autoplay=true`;
|
|
1035
1043
|
el.setAttribute("src", s);
|
|
1044
|
+
el.setAttribute("class", "speak-iframe");
|
|
1036
1045
|
return;
|
|
1037
1046
|
}
|
|
1038
1047
|
if (src.match(SPOTIFY_EMBED_REGEX)) {
|
|
@@ -1141,7 +1150,7 @@ function p(el) {
|
|
|
1141
1150
|
}
|
|
1142
1151
|
|
|
1143
1152
|
// src/methods/linkify.method.ts
|
|
1144
|
-
function linkify(content, forApp
|
|
1153
|
+
function linkify(content, forApp) {
|
|
1145
1154
|
content = content.replace(/(^|\s|>)(#[-a-z\d]+)/gi, (tag) => {
|
|
1146
1155
|
if (/#[\d]+$/.test(tag)) return tag;
|
|
1147
1156
|
const preceding = /^\s|>/.test(tag) ? tag[0] : "";
|
|
@@ -1183,21 +1192,21 @@ function linkify(content, forApp, webp) {
|
|
|
1183
1192
|
content = content.replace(IMG_REGEX, (imglink) => {
|
|
1184
1193
|
const isLCP = !firstImageUsed;
|
|
1185
1194
|
firstImageUsed = true;
|
|
1186
|
-
return createImageHTML(imglink, isLCP
|
|
1195
|
+
return createImageHTML(imglink, isLCP);
|
|
1187
1196
|
});
|
|
1188
1197
|
return content;
|
|
1189
1198
|
}
|
|
1190
1199
|
|
|
1191
1200
|
// src/methods/text.method.ts
|
|
1192
|
-
function text(node, forApp
|
|
1201
|
+
function text(node, forApp) {
|
|
1193
1202
|
if (!node || !node.parentNode) {
|
|
1194
1203
|
return;
|
|
1195
1204
|
}
|
|
1196
|
-
if (
|
|
1205
|
+
if (["a", "code"].includes(node.parentNode.nodeName.toLowerCase())) {
|
|
1197
1206
|
return;
|
|
1198
1207
|
}
|
|
1199
1208
|
const nodeValue = node.nodeValue || "";
|
|
1200
|
-
const linkified = linkify(nodeValue, forApp
|
|
1209
|
+
const linkified = linkify(nodeValue, forApp);
|
|
1201
1210
|
if (linkified !== nodeValue) {
|
|
1202
1211
|
const doc = DOMParser.parseFromString(
|
|
1203
1212
|
`<span class="wr">${linkified}</span>`,
|
|
@@ -1212,7 +1221,7 @@ function text(node, forApp, webp) {
|
|
|
1212
1221
|
}
|
|
1213
1222
|
if (nodeValue.match(IMG_REGEX)) {
|
|
1214
1223
|
const isLCP = false;
|
|
1215
|
-
const imageHTML = createImageHTML(nodeValue, isLCP
|
|
1224
|
+
const imageHTML = createImageHTML(nodeValue, isLCP);
|
|
1216
1225
|
const doc = DOMParser.parseFromString(imageHTML, "text/html");
|
|
1217
1226
|
const replaceNode = doc.body?.firstChild || doc.firstChild;
|
|
1218
1227
|
if (replaceNode) {
|
|
@@ -1224,7 +1233,7 @@ function text(node, forApp, webp) {
|
|
|
1224
1233
|
const e = YOUTUBE_REGEX.exec(nodeValue);
|
|
1225
1234
|
if (e && e[1]) {
|
|
1226
1235
|
const vid = e[1];
|
|
1227
|
-
const thumbnail = proxifyImageSrc(`https://img.youtube.com/vi/${vid.split("?")[0]}/hqdefault.jpg`, 0, 0,
|
|
1236
|
+
const thumbnail = proxifyImageSrc(`https://img.youtube.com/vi/${vid.split("?")[0]}/hqdefault.jpg`, 0, 0, "match");
|
|
1228
1237
|
const embedSrc = `https://www.youtube.com/embed/${vid}?autoplay=1`;
|
|
1229
1238
|
const startTime = extractYtStartTime(nodeValue);
|
|
1230
1239
|
const container = node.ownerDocument.createElement("p");
|
|
@@ -1270,7 +1279,7 @@ function text(node, forApp, webp) {
|
|
|
1270
1279
|
}
|
|
1271
1280
|
|
|
1272
1281
|
// src/methods/traverse.method.ts
|
|
1273
|
-
function traverse(node, forApp, depth = 0,
|
|
1282
|
+
function traverse(node, forApp, depth = 0, state = { firstImageFound: false }, parentDomain = "ecency.com", seoContext) {
|
|
1274
1283
|
if (!node || !node.childNodes) {
|
|
1275
1284
|
return;
|
|
1276
1285
|
}
|
|
@@ -1278,23 +1287,23 @@ function traverse(node, forApp, depth = 0, webp = false, state = { firstImageFou
|
|
|
1278
1287
|
const child = node.childNodes[i];
|
|
1279
1288
|
if (!child) return;
|
|
1280
1289
|
if (child.nodeName.toLowerCase() === "a") {
|
|
1281
|
-
a(child, forApp,
|
|
1290
|
+
a(child, forApp, parentDomain, seoContext);
|
|
1282
1291
|
}
|
|
1283
1292
|
if (child.nodeName.toLowerCase() === "iframe") {
|
|
1284
1293
|
iframe(child, parentDomain);
|
|
1285
1294
|
}
|
|
1286
1295
|
if (child.nodeName === "#text") {
|
|
1287
|
-
text(child, forApp
|
|
1296
|
+
text(child, forApp);
|
|
1288
1297
|
}
|
|
1289
1298
|
if (child.nodeName.toLowerCase() === "img") {
|
|
1290
|
-
img(child,
|
|
1299
|
+
img(child, state);
|
|
1291
1300
|
}
|
|
1292
1301
|
if (child.nodeName.toLowerCase() === "p") {
|
|
1293
1302
|
p(child);
|
|
1294
1303
|
}
|
|
1295
1304
|
const currentChild = node.childNodes[i];
|
|
1296
1305
|
if (currentChild) {
|
|
1297
|
-
traverse(currentChild, forApp, depth + 1,
|
|
1306
|
+
traverse(currentChild, forApp, depth + 1, state, parentDomain, seoContext);
|
|
1298
1307
|
}
|
|
1299
1308
|
});
|
|
1300
1309
|
}
|
|
@@ -1345,7 +1354,7 @@ function fixBlockLevelTagsInParagraphs(html) {
|
|
|
1345
1354
|
html = html.replace(/<p><br>\s*<\/p>/g, "");
|
|
1346
1355
|
return html;
|
|
1347
1356
|
}
|
|
1348
|
-
function markdownToHTML(input, forApp,
|
|
1357
|
+
function markdownToHTML(input, forApp, parentDomain = "ecency.com", seoContext) {
|
|
1349
1358
|
input = input.replace(new RegExp("https://leofinance.io/threads/view/", "g"), "/@");
|
|
1350
1359
|
input = input.replace(new RegExp("https://leofinance.io/posts/", "g"), "/@");
|
|
1351
1360
|
input = input.replace(new RegExp("https://leofinance.io/threads/", "g"), "/@");
|
|
@@ -1405,7 +1414,7 @@ function markdownToHTML(input, forApp, webp, parentDomain = "ecency.com") {
|
|
|
1405
1414
|
output = md.render(input);
|
|
1406
1415
|
output = fixBlockLevelTagsInParagraphs(output);
|
|
1407
1416
|
const doc = DOMParser.parseFromString(`<body id="root">${removeDuplicateAttributes(output)}</body>`, "text/html");
|
|
1408
|
-
traverse(doc, forApp, 0,
|
|
1417
|
+
traverse(doc, forApp, 0, { firstImageFound: false }, parentDomain, seoContext);
|
|
1409
1418
|
output = serializer.serializeToString(doc);
|
|
1410
1419
|
} catch (error) {
|
|
1411
1420
|
try {
|
|
@@ -1418,7 +1427,7 @@ function markdownToHTML(input, forApp, webp, parentDomain = "ecency.com") {
|
|
|
1418
1427
|
});
|
|
1419
1428
|
const repairedHtml = domSerializer(dom.children);
|
|
1420
1429
|
const doc = DOMParser.parseFromString(`<body id="root">${removeDuplicateAttributes(repairedHtml)}</body>`, "text/html");
|
|
1421
|
-
traverse(doc, forApp, 0,
|
|
1430
|
+
traverse(doc, forApp, 0, { firstImageFound: false }, parentDomain, seoContext);
|
|
1422
1431
|
output = serializer.serializeToString(doc);
|
|
1423
1432
|
} catch (fallbackError) {
|
|
1424
1433
|
const escapedContent = he2.encode(output || md.render(input));
|
|
@@ -1446,18 +1455,18 @@ function cacheSet(key, value) {
|
|
|
1446
1455
|
}
|
|
1447
1456
|
|
|
1448
1457
|
// src/markdown-2-html.ts
|
|
1449
|
-
function markdown2Html(obj, forApp = true,
|
|
1458
|
+
function markdown2Html(obj, forApp = true, _webp = false, parentDomain = "ecency.com", seoContext) {
|
|
1450
1459
|
if (typeof obj === "string") {
|
|
1451
1460
|
const cleanedStr = cleanReply(obj);
|
|
1452
|
-
return markdownToHTML(cleanedStr, forApp,
|
|
1461
|
+
return markdownToHTML(cleanedStr, forApp, parentDomain, seoContext);
|
|
1453
1462
|
}
|
|
1454
|
-
const key = `${makeEntryCacheKey(obj)}-md
|
|
1463
|
+
const key = `${makeEntryCacheKey(obj)}-md-${forApp ? "app" : "site"}-${parentDomain}${seoContext ? `-seo${seoContext.authorReputation ?? ""}-${seoContext.postPayout ?? ""}` : ""}`;
|
|
1455
1464
|
const item = cacheGet(key);
|
|
1456
1465
|
if (item) {
|
|
1457
1466
|
return item;
|
|
1458
1467
|
}
|
|
1459
1468
|
const cleanBody = cleanReply(obj.body);
|
|
1460
|
-
const res = markdownToHTML(cleanBody, forApp,
|
|
1469
|
+
const res = markdownToHTML(cleanBody, forApp, parentDomain, seoContext);
|
|
1461
1470
|
cacheSet(key, res);
|
|
1462
1471
|
return res;
|
|
1463
1472
|
}
|