@rmdes/indiekit-endpoint-microsub 1.0.6 → 1.0.7
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/lib/controllers/reader.js +16 -4
- package/lib/feeds/normalizer.js +35 -5
- package/package.json +1 -1
- package/views/compose.njk +4 -4
- package/views/partials/item-card.njk +15 -8
|
@@ -303,6 +303,18 @@ export async function item(request, response) {
|
|
|
303
303
|
});
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
/**
|
|
307
|
+
* Ensure value is a string URL
|
|
308
|
+
* @param {string|object|undefined} value - Value to check
|
|
309
|
+
* @returns {string|undefined} String value or undefined
|
|
310
|
+
*/
|
|
311
|
+
function ensureString(value) {
|
|
312
|
+
if (!value) return;
|
|
313
|
+
if (typeof value === "string") return value;
|
|
314
|
+
if (typeof value === "object" && value.url) return value.url;
|
|
315
|
+
return String(value);
|
|
316
|
+
}
|
|
317
|
+
|
|
306
318
|
/**
|
|
307
319
|
* Compose response form
|
|
308
320
|
* @param {object} request - Express request
|
|
@@ -324,10 +336,10 @@ export async function compose(request, response) {
|
|
|
324
336
|
|
|
325
337
|
response.render("compose", {
|
|
326
338
|
title: request.__("microsub.compose.title"),
|
|
327
|
-
replyTo: replyTo || reply,
|
|
328
|
-
likeOf: likeOf || like,
|
|
329
|
-
repostOf: repostOf || repost,
|
|
330
|
-
bookmarkOf: bookmarkOf || bookmark,
|
|
339
|
+
replyTo: ensureString(replyTo || reply),
|
|
340
|
+
likeOf: ensureString(likeOf || like),
|
|
341
|
+
repostOf: ensureString(repostOf || repost),
|
|
342
|
+
bookmarkOf: ensureString(bookmarkOf || bookmark),
|
|
331
343
|
baseUrl: request.baseUrl,
|
|
332
344
|
});
|
|
333
345
|
}
|
package/lib/feeds/normalizer.js
CHANGED
|
@@ -536,18 +536,18 @@ export function normalizeHfeedItem(entry, feedUrl) {
|
|
|
536
536
|
);
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
// Interaction types
|
|
539
|
+
// Interaction types - normalize to string URLs
|
|
540
540
|
if (properties["like-of"]) {
|
|
541
|
-
normalized["like-of"] = properties["like-of"];
|
|
541
|
+
normalized["like-of"] = normalizeUrlArray(properties["like-of"]);
|
|
542
542
|
}
|
|
543
543
|
if (properties["repost-of"]) {
|
|
544
|
-
normalized["repost-of"] = properties["repost-of"];
|
|
544
|
+
normalized["repost-of"] = normalizeUrlArray(properties["repost-of"]);
|
|
545
545
|
}
|
|
546
546
|
if (properties["bookmark-of"]) {
|
|
547
|
-
normalized["bookmark-of"] = properties["bookmark-of"];
|
|
547
|
+
normalized["bookmark-of"] = normalizeUrlArray(properties["bookmark-of"]);
|
|
548
548
|
}
|
|
549
549
|
if (properties["in-reply-to"]) {
|
|
550
|
-
normalized["in-reply-to"] = properties["in-reply-to"];
|
|
550
|
+
normalized["in-reply-to"] = normalizeUrlArray(properties["in-reply-to"]);
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
// RSVP
|
|
@@ -617,6 +617,36 @@ function extractPhotoUrl(photo) {
|
|
|
617
617
|
return;
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
+
/**
|
|
621
|
+
* Extract URL string from a value that may be string or object
|
|
622
|
+
* @param {object|string} value - URL string or object with url/value property
|
|
623
|
+
* @returns {string|undefined} URL string
|
|
624
|
+
*/
|
|
625
|
+
function extractUrl(value) {
|
|
626
|
+
if (!value) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (typeof value === "string") {
|
|
630
|
+
return value;
|
|
631
|
+
}
|
|
632
|
+
if (typeof value === "object") {
|
|
633
|
+
return value.value || value.url || value.href;
|
|
634
|
+
}
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Normalize an array of URLs that may contain strings or objects
|
|
640
|
+
* @param {Array} urls - Array of URL strings or objects
|
|
641
|
+
* @returns {Array<string>} Array of URL strings
|
|
642
|
+
*/
|
|
643
|
+
function normalizeUrlArray(urls) {
|
|
644
|
+
if (!urls || !Array.isArray(urls)) {
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
return urls.map((u) => extractUrl(u)).filter(Boolean);
|
|
648
|
+
}
|
|
649
|
+
|
|
620
650
|
/**
|
|
621
651
|
* Normalize h-card author
|
|
622
652
|
* @param {object|string} hcard - h-card or author name string
|
package/package.json
CHANGED
package/views/compose.njk
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
<h2>{{ __("microsub.compose.title") }}</h2>
|
|
10
10
|
|
|
11
|
-
{% if replyTo %}
|
|
11
|
+
{% if replyTo and replyTo is string %}
|
|
12
12
|
<div class="compose__context">
|
|
13
13
|
{{ icon("reply") }} {{ __("microsub.compose.replyTo") }}:
|
|
14
14
|
<a href="{{ replyTo }}" target="_blank" rel="noopener">
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
</div>
|
|
18
18
|
{% endif %}
|
|
19
19
|
|
|
20
|
-
{% if likeOf %}
|
|
20
|
+
{% if likeOf and likeOf is string %}
|
|
21
21
|
<div class="compose__context">
|
|
22
22
|
{{ icon("like") }} {{ __("microsub.compose.likeOf") }}:
|
|
23
23
|
<a href="{{ likeOf }}" target="_blank" rel="noopener">
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
</div>
|
|
27
27
|
{% endif %}
|
|
28
28
|
|
|
29
|
-
{% if repostOf %}
|
|
29
|
+
{% if repostOf and repostOf is string %}
|
|
30
30
|
<div class="compose__context">
|
|
31
31
|
{{ icon("repost") }} {{ __("microsub.compose.repostOf") }}:
|
|
32
32
|
<a href="{{ repostOf }}" target="_blank" rel="noopener">
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
</div>
|
|
36
36
|
{% endif %}
|
|
37
37
|
|
|
38
|
-
{% if bookmarkOf %}
|
|
38
|
+
{% if bookmarkOf and bookmarkOf is string %}
|
|
39
39
|
<div class="compose__context">
|
|
40
40
|
{{ icon("bookmark") }} {{ __("microsub.compose.bookmarkOf") }}:
|
|
41
41
|
<a href="{{ bookmarkOf }}" target="_blank" rel="noopener">
|
|
@@ -7,36 +7,43 @@
|
|
|
7
7
|
data-is-read="{{ item._is_read | default(false) }}">
|
|
8
8
|
|
|
9
9
|
{# Context bar for interactions (Aperture pattern) #}
|
|
10
|
+
{# Helper to extract URL from value that may be string or object #}
|
|
11
|
+
{% macro getUrl(val) %}{{ val.url or val.value or val if val is string else val }}{% endmacro %}
|
|
12
|
+
|
|
10
13
|
{% if item["like-of"] and item["like-of"].length > 0 %}
|
|
14
|
+
{% set contextUrl = item['like-of'][0].url or item['like-of'][0].value or item['like-of'][0] %}
|
|
11
15
|
<div class="item-card__context">
|
|
12
16
|
{{ icon("like") }}
|
|
13
17
|
<span>Liked</span>
|
|
14
|
-
<a href="{{
|
|
15
|
-
{{
|
|
18
|
+
<a href="{{ contextUrl }}" target="_blank" rel="noopener">
|
|
19
|
+
{{ contextUrl | replace("https://", "") | replace("http://", "") | truncate(50) }}
|
|
16
20
|
</a>
|
|
17
21
|
</div>
|
|
18
22
|
{% elif item["repost-of"] and item["repost-of"].length > 0 %}
|
|
23
|
+
{% set contextUrl = item['repost-of'][0].url or item['repost-of'][0].value or item['repost-of'][0] %}
|
|
19
24
|
<div class="item-card__context">
|
|
20
25
|
{{ icon("repost") }}
|
|
21
26
|
<span>Reposted</span>
|
|
22
|
-
<a href="{{
|
|
23
|
-
{{
|
|
27
|
+
<a href="{{ contextUrl }}" target="_blank" rel="noopener">
|
|
28
|
+
{{ contextUrl | replace("https://", "") | replace("http://", "") | truncate(50) }}
|
|
24
29
|
</a>
|
|
25
30
|
</div>
|
|
26
31
|
{% elif item["in-reply-to"] and item["in-reply-to"].length > 0 %}
|
|
32
|
+
{% set contextUrl = item['in-reply-to'][0].url or item['in-reply-to'][0].value or item['in-reply-to'][0] %}
|
|
27
33
|
<div class="item-card__context">
|
|
28
34
|
{{ icon("reply") }}
|
|
29
35
|
<span>Reply to</span>
|
|
30
|
-
<a href="{{
|
|
31
|
-
{{
|
|
36
|
+
<a href="{{ contextUrl }}" target="_blank" rel="noopener">
|
|
37
|
+
{{ contextUrl | replace("https://", "") | replace("http://", "") | truncate(50) }}
|
|
32
38
|
</a>
|
|
33
39
|
</div>
|
|
34
40
|
{% elif item["bookmark-of"] and item["bookmark-of"].length > 0 %}
|
|
41
|
+
{% set contextUrl = item['bookmark-of'][0].url or item['bookmark-of'][0].value or item['bookmark-of'][0] %}
|
|
35
42
|
<div class="item-card__context">
|
|
36
43
|
{{ icon("bookmark") }}
|
|
37
44
|
<span>Bookmarked</span>
|
|
38
|
-
<a href="{{
|
|
39
|
-
{{
|
|
45
|
+
<a href="{{ contextUrl }}" target="_blank" rel="noopener">
|
|
46
|
+
{{ contextUrl | replace("https://", "") | replace("http://", "") | truncate(50) }}
|
|
40
47
|
</a>
|
|
41
48
|
</div>
|
|
42
49
|
{% endif %}
|