Cleaning scripts
This commit is contained in:
@@ -16,11 +16,11 @@ like: null
|
|||||||
rsvp: null
|
rsvp: null
|
||||||
bookmark: null
|
bookmark: null
|
||||||
syndication:
|
syndication:
|
||||||
- https://mastodon.social/@fundor333/115101269000557955
|
- https://mastodon.social/@fundor333/115101286930871373
|
||||||
comments:
|
comments:
|
||||||
host: mastodon.social
|
host: mastodon.social
|
||||||
username: fundor333
|
username: fundor333
|
||||||
id: '115101269000557955'
|
id: '115101286930871373'
|
||||||
---
|
---
|
||||||
|
|
||||||
Waiting for tomorrow when I am going to the PyData Event in Venice 🐍👨🏻💻🐍
|
Waiting for tomorrow when I am going to the PyData Event in Venice 🐍👨🏻💻🐍
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1 +1,25 @@
|
|||||||
[{"type": "entry", "author": {"type": "card", "name": "fundor333", "photo": "https://avatars.webmention.io/shiitake.us-east.host.bsky.network/745ae7c92d33ea40ee0a0cc07825d49dcf5f0375c9b77cf4404889a238e66f93.jpg", "url": "https://bsky.app/profile/fundor333.bsky.social"}, "url": "https://bsky.app/profile/did:plc:u7piwonv4s27ysugjaa6im2q/post/3lxfbpfjmo422", "published": "2025-08-27T14:09:19+00:00", "wm-received": "2025-08-27T14:51:03Z", "wm-id": 1933884, "wm-source": "https://bsky.brid.gy/convert/web/at://did:plc:u7piwonv4s27ysugjaa6im2q/app.bsky.feed.post/3lxfbpfjmo422%23bridgy-fed-create", "wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com", "wm-protocol": "webmention", "content": {"html": "Waiting for tomorrow when I am going to the PyData Event in Venice ????????????\u200d???????? [<a href=\"https://www.meetup.com/pydata-venice/events/310339068/?eventOrigin=home_page_upcoming_events%24all\">\u2026] https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=json</a><a href=\"https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com\">https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com</a><a href=\"https://bsky.app/search?q=%23pydatave\">ed&utm_ca</a>m<a href=\"https://bsky.app/search?q=%23event\">paign=</a>b<a href=\"https://bsky.app/search?q=%23python\">logging</a>&<a href=\"https://bsky.app/search?q=%23data\">ref=f</a>u<a href=\"https://bsky.app/search?q=%23pydata\">ndor333</a>f<a href=\"https://bsky.app/search?q=%23venice\">eed.com</a>", "text": "Waiting for tomorrow when I am going to the PyData Event in Venice ????????????\u200d???????? [\u2026] https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonhttps://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.comed&utm_campaign=blogging&ref=fundor333feed.com"}, "mention-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com", "wm-property": "mention-of", "wm-private": false}]
|
[
|
||||||
|
{
|
||||||
|
"type": "entry",
|
||||||
|
"author": {
|
||||||
|
"type": "card",
|
||||||
|
"name": "fundor333",
|
||||||
|
"photo": "https://avatars.webmention.io/shiitake.us-east.host.bsky.network/745ae7c92d33ea40ee0a0cc07825d49dcf5f0375c9b77cf4404889a238e66f93.jpg",
|
||||||
|
"url": "https://bsky.app/profile/fundor333.bsky.social"
|
||||||
|
},
|
||||||
|
"url": "https://bsky.app/profile/did:plc:u7piwonv4s27ysugjaa6im2q/post/3lxfbpfjmo422",
|
||||||
|
"published": "2025-08-27T14:09:19+00:00",
|
||||||
|
"wm-received": "2025-08-27T14:51:03Z",
|
||||||
|
"wm-id": 1933884,
|
||||||
|
"wm-source": "https://bsky.brid.gy/convert/web/at://did:plc:u7piwonv4s27ysugjaa6im2q/app.bsky.feed.post/3lxfbpfjmo422%23bridgy-fed-create",
|
||||||
|
"wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com",
|
||||||
|
"wm-protocol": "webmention",
|
||||||
|
"content": {
|
||||||
|
"html": "Waiting for tomorrow when I am going to the PyData Event in Venice ????????????\u200d???????? [<a href=\"https://www.meetup.com/pydata-venice/events/310339068/?eventOrigin=home_page_upcoming_events%24all\">\u2026] https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=json</a><a href=\"https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com\">https://fundor333.com/micro/2025/08/pydata-venezia-2025/?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com</a><a href=\"https://bsky.app/search?q=%23pydatave\">ed&utm_ca</a>m<a href=\"https://bsky.app/search?q=%23event\">paign=</a>b<a href=\"https://bsky.app/search?q=%23python\">logging</a>&<a href=\"https://bsky.app/search?q=%23data\">ref=f</a>u<a href=\"https://bsky.app/search?q=%23pydata\">ndor333</a>f<a href=\"https://bsky.app/search?q=%23venice\">eed.com</a>",
|
||||||
|
"text": "Waiting for tomorrow when I am going to the PyData Event in Venice ????????????\u200d???????? [\u2026] https://fundor333.com/micro/2025/08/pydata-venezia-2025/"
|
||||||
|
},
|
||||||
|
"mention-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-property": "mention-of",
|
||||||
|
"wm-private": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -1 +1,21 @@
|
|||||||
[{"type": "entry", "author": {"type": "card", "name": "Jonathan Rogivue", "photo": "https://avatars.webmention.io/files.mastodon.social/6cb4d618935f059605596af59ea79931acdca17c7db823392c9499fe081649ed.png", "url": "https://mastodon.social/@jrovu"}, "url": "https://mastodon.social/@fundor333/115101286930871373#favorited-by-114691517400809872", "published": null, "wm-received": "2025-08-27T15:16:17Z", "wm-id": 1933894, "wm-source": "https://brid.gy/like/mastodon/@fundor333@mastodon.social/115101286930871373/114691517400809872", "wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-protocol": "webmention", "like-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-property": "like-of", "wm-private": false}]
|
[
|
||||||
|
{
|
||||||
|
"type": "entry",
|
||||||
|
"author": {
|
||||||
|
"type": "card",
|
||||||
|
"name": "Jonathan Rogivue",
|
||||||
|
"photo": "https://avatars.webmention.io/files.mastodon.social/6cb4d618935f059605596af59ea79931acdca17c7db823392c9499fe081649ed.png",
|
||||||
|
"url": "https://mastodon.social/@jrovu"
|
||||||
|
},
|
||||||
|
"url": "https://mastodon.social/@fundor333/115101286930871373#favorited-by-114691517400809872",
|
||||||
|
"published": null,
|
||||||
|
"wm-received": "2025-08-27T15:16:17Z",
|
||||||
|
"wm-id": 1933894,
|
||||||
|
"wm-source": "https://brid.gy/like/mastodon/@fundor333@mastodon.social/115101286930871373/114691517400809872",
|
||||||
|
"wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-protocol": "webmention",
|
||||||
|
"like-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-property": "like-of",
|
||||||
|
"wm-private": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -1 +1,21 @@
|
|||||||
[{"type": "entry", "author": {"type": "card", "name": "Jonathan Rogivue", "photo": "https://avatars.webmention.io/files.mastodon.social/6cb4d618935f059605596af59ea79931acdca17c7db823392c9499fe081649ed.png", "url": "https://mastodon.social/@jrovu"}, "url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-114691517400809872", "published": null, "wm-received": "2025-08-27T15:16:20Z", "wm-id": 1933896, "wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/114691517400809872", "wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-protocol": "webmention", "repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-property": "repost-of", "wm-private": false}]
|
[
|
||||||
|
{
|
||||||
|
"type": "entry",
|
||||||
|
"author": {
|
||||||
|
"type": "card",
|
||||||
|
"name": "Jonathan Rogivue",
|
||||||
|
"photo": "https://avatars.webmention.io/files.mastodon.social/6cb4d618935f059605596af59ea79931acdca17c7db823392c9499fe081649ed.png",
|
||||||
|
"url": "https://mastodon.social/@jrovu"
|
||||||
|
},
|
||||||
|
"url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-114691517400809872",
|
||||||
|
"published": null,
|
||||||
|
"wm-received": "2025-08-27T15:16:20Z",
|
||||||
|
"wm-id": 1933896,
|
||||||
|
"wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/114691517400809872",
|
||||||
|
"wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-protocol": "webmention",
|
||||||
|
"repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-property": "repost-of",
|
||||||
|
"wm-private": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -1 +1,21 @@
|
|||||||
[{"type": "entry", "author": {"type": "card", "name": "Programming Channel", "photo": "https://avatars.webmention.io/files.mastodon.social/53dcc6ece2e0abd79a8aa637b9109d33bab0fa02e6536db85fd6c18ebc662722.png", "url": "https://newsmast.community/@programming"}, "url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-111653091517742065", "published": null, "wm-received": "2025-08-27T15:16:22Z", "wm-id": 1933897, "wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/111653091517742065", "wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-protocol": "webmention", "repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-property": "repost-of", "wm-private": false}]
|
[
|
||||||
|
{
|
||||||
|
"type": "entry",
|
||||||
|
"author": {
|
||||||
|
"type": "card",
|
||||||
|
"name": "Programming Channel",
|
||||||
|
"photo": "https://avatars.webmention.io/files.mastodon.social/53dcc6ece2e0abd79a8aa637b9109d33bab0fa02e6536db85fd6c18ebc662722.png",
|
||||||
|
"url": "https://newsmast.community/@programming"
|
||||||
|
},
|
||||||
|
"url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-111653091517742065",
|
||||||
|
"published": null,
|
||||||
|
"wm-received": "2025-08-27T15:16:22Z",
|
||||||
|
"wm-id": 1933897,
|
||||||
|
"wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/111653091517742065",
|
||||||
|
"wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-protocol": "webmention",
|
||||||
|
"repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com",
|
||||||
|
"wm-property": "repost-of",
|
||||||
|
"wm-private": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -1 +1,21 @@
|
|||||||
[{"type": "entry", "author": {"type": "card", "name": "ZioN1k9", "photo": "https://avatars.webmention.io/files.mastodon.social/cff7c181721f7b6d2ac02f8fb12a44cbea1f5e6f9defce1401e7a158d9a1d80d.png", "url": "https://livellosegreto.it/@n1k9"}, "url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-109094054789012545", "published": null, "wm-received": "2025-08-27T19:46:22Z", "wm-id": 1933981, "wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/109094054789012545", "wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-protocol": "webmention", "repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/?amp%3Butm_medium=jsonfeed&%3Butm_campaign=blogging&%3Bref=fundor333feed.com", "wm-property": "repost-of", "wm-private": false}]
|
[
|
||||||
|
{
|
||||||
|
"type": "entry",
|
||||||
|
"author": {
|
||||||
|
"type": "card",
|
||||||
|
"name": "ZioN1k9",
|
||||||
|
"photo": "https://avatars.webmention.io/files.mastodon.social/cff7c181721f7b6d2ac02f8fb12a44cbea1f5e6f9defce1401e7a158d9a1d80d.png",
|
||||||
|
"url": "https://livellosegreto.it/@n1k9"
|
||||||
|
},
|
||||||
|
"url": "https://mastodon.social/@fundor333/115101286930871373#reblogged-by-109094054789012545",
|
||||||
|
"published": null,
|
||||||
|
"wm-received": "2025-08-27T19:46:22Z",
|
||||||
|
"wm-id": 1933981,
|
||||||
|
"wm-source": "https://brid.gy/repost/mastodon/@fundor333@mastodon.social/115101286930871373/109094054789012545",
|
||||||
|
"wm-target": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-protocol": "webmention",
|
||||||
|
"repost-of": "https://fundor333.com/micro/2025/08/pydata-venezia-2025/",
|
||||||
|
"wm-property": "repost-of",
|
||||||
|
"wm-private": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
"date_published": "{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}",
|
"date_published": "{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}",
|
||||||
"date_modified": "{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}",
|
"date_modified": "{{ .Lastmod.Format "2006-01-02T15:04:05Z07:00" }}",
|
||||||
"id": "{{ .Permalink }}",
|
"id": "{{ .Permalink }}",
|
||||||
"url": "{{ .Permalink }}?utm_source=fundor333.com&utm_medium=jsonfeed&utm_campaign=blogging&ref=fundor333feed.com",
|
"url": "{{ .Permalink }}",
|
||||||
{{ with .Params.author -}}
|
{{ with .Params.author -}}
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
|
<script src="/js/jquery-3.7.1.min.js"></script>
|
||||||
<meta name="fediverse:creator" content="@fundor333@mastodon.social">
|
<meta name="fediverse:creator" content="@fundor333@mastodon.social">
|
||||||
|
|
||||||
<link rel="webmention" href="https://webmention.io/fundor333.com/webmention" />
|
<link rel="webmention" href="https://webmention.io/fundor333.com/webmention" />
|
||||||
<link rel="pingback" href="https://webmention.io/fundor333.com/xmlrpc" />
|
<link rel="pingback" href="https://webmention.io/fundor333.com/xmlrpc" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="/css/webmention.css" />
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
|
||||||
|
|
||||||
<script src="https://kit.fontawesome.com/2f3b6e2e4c.js" crossorigin="anonymous"></script>
|
<script src="https://kit.fontawesome.com/2f3b6e2e4c.js" crossorigin="anonymous"></script>
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
<footer class="footer wrapper">
|
<footer class="footer wrapper">
|
||||||
|
|
||||||
<span class="footer_item"> </span>
|
<span class="footer_item"> </span>
|
||||||
{{ partial "hcard" . }}
|
{{ partial "hcard" . }}
|
||||||
|
|
||||||
|
<div class="footer_social-icons flex">
|
||||||
<div class="footer_social-icons flex">
|
{{- partial "socialIcons.html" site.Params.socialIcons -}}
|
||||||
{{- partial "socialIcons.html" site.Params.socialIcons -}}
|
<p class="flex justify-center">
|
||||||
<p class="flex justify-center">
|
<a href='https://webring.xxiivv.com/#random' target='_blank'>
|
||||||
<a href='https://webring.xxiivv.com/#random' target='_blank'>
|
<img loading="lazy" width=" 30" height="30" src='https://webring.xxiivv.com/icon.white.svg' />
|
||||||
<img loading="lazy" width=" 30" height="30" src='https://webring.xxiivv.com/icon.white.svg' />
|
</a>
|
||||||
</a>
|
</p>
|
||||||
</p>
|
<p>
|
||||||
<p>
|
<a href="https://xn--sr8hvo.ws/previous">←</a>
|
||||||
<a href="https://xn--sr8hvo.ws/previous">←</a>
|
<a href="https://xn--sr8hvo.ws">IndieWeb Webring</a>
|
||||||
<a href="https://xn--sr8hvo.ws">IndieWeb Webring</a>
|
<a href="https://xn--sr8hvo.ws/next">→</a>
|
||||||
<a href="https://xn--sr8hvo.ws/next">→</a>
|
</p>
|
||||||
</p>
|
<div class="webring">
|
||||||
<div class="webring">
|
<webring-css site="https://fundor333.com"></webring-css>
|
||||||
<webring-css site="https://fundor333.com"></webring-css>
|
<script src="https://djangowebring.com/static/webring.js"></script>
|
||||||
<script src="https://djangowebring.com/static/webring.js"></script>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<small class="footer_copyright">
|
||||||
<small class="footer_copyright">
|
|
||||||
© {{ now.Format "2006" }} {{ .Site.Params.author.name }}.
|
© {{ now.Format "2006" }} {{ .Site.Params.author.name }}.
|
||||||
{{ T "footer.disclaimer" | safeHTML }}
|
{{ T "footer.disclaimer" | safeHTML }}
|
||||||
</small>
|
</small>
|
||||||
@@ -29,7 +28,7 @@
|
|||||||
|
|
||||||
{{- if .Site.Params.goToTop -}}
|
{{- if .Site.Params.goToTop -}}
|
||||||
<a href="#" title="{{ T "footer.go_to_top" }}" id="totop">
|
<a href="#" title="{{ T "footer.go_to_top" }}" id="totop">
|
||||||
{{ partial "svgs/arrowUp.svg" (dict "height" 48 "width" 48) . }}
|
{{ partial "svgs/arrowUp.svg" (dict "height" 48 "width" 48) . }}
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
@@ -51,15 +50,18 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
$(window).on('load', function() {
|
||||||
|
// Seleziona tutte le immagini con la classe 'u-photo'
|
||||||
|
var images = $('img.u-photo');
|
||||||
|
|
||||||
$(window).load(function(){
|
// Itera su ogni immagine trovata
|
||||||
|
images.each(function() {
|
||||||
$.each($('u-photo'), function(){
|
// 'this' si riferisce all'elemento immagine corrente
|
||||||
|
var currentImage = $(this);
|
||||||
// Set the height, hard-style!
|
|
||||||
$(this).attr('height', $(this).height());
|
|
||||||
|
|
||||||
|
// Prende l'altezza calcolata e la imposta come attributo 'height' del tag
|
||||||
|
var imageHeight = currentImage.height();
|
||||||
|
currentImage.attr('height', imageHeight);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
<section id="comments" class="article-content">
|
<section id="comments" class="article-content">
|
||||||
<p>With an account on the Fediverse or Mastodon, you can respond to this <a target="_blank" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">post</a>. Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one. Known non-private replies are displayed below.</p>
|
<p>With an account on the Fediverse or Mastodon, you can respond to this <a target="_blank" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">post</a>.
|
||||||
<p>Learn how this is implemented <a target="_blank" class="link" href="https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/">here.</a></p>
|
Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on
|
||||||
|
this one. Known non-private replies are displayed below.</p>
|
||||||
|
<p>Learn how this is implemented <a target="_blank" class="link"
|
||||||
|
href="https://carlschwan.eu/2020/12/29/adding-comments-to-your-static-blog-with-mastodon/">here.</a></p>
|
||||||
|
|
||||||
<p id="mastodon-comments-list"></p>
|
<p id="mastodon-comments-list"><button id="load-comment">Load comments</button></p>
|
||||||
<div id="comments-wrapper">
|
<div id="comments-wrapper">
|
||||||
<noscript><p>Loading comments relies on JavaScript. Try enabling JavaScript and reloading, or visit <a target="_blank" href="https://{{ .host }}/@{{ .username }}/{{ .id }}">the original post</a> on Mastodon.</p></noscript>
|
<noscript><p>Loading comments relies on JavaScript. Try enabling JavaScript and reloading, or visit <a
|
||||||
|
href="https://{{ .host }}/@{{ .username }}/{{ .id }}">the original post</a> on Mastodon.</p></noscript>
|
||||||
</div>
|
</div>
|
||||||
<noscript>You need JavaScript to view the comments.</noscript>
|
<noscript>You need JavaScript to view the comments.</noscript>
|
||||||
<script src="/js/purify.min.js"></script>
|
<script src="/js/purify.min.js"></script>
|
||||||
@@ -48,6 +51,7 @@
|
|||||||
|
|
||||||
function loadComments() {
|
function loadComments() {
|
||||||
let commentsWrapper = document.getElementById("comments-wrapper");
|
let commentsWrapper = document.getElementById("comments-wrapper");
|
||||||
|
document.getElementById("load-comment").innerHTML = "Loading";
|
||||||
fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
|
fetch('https://{{ .host }}/api/v1/statuses/{{ .id }}/context')
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
return response.json();
|
return response.json();
|
||||||
@@ -185,6 +189,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
document.addEventListener("DOMContentLoaded", loadComments);
|
document.getElementById("load-comment").addEventListener("click", loadComments);
|
||||||
</script>
|
</script>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -241,9 +241,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.5.208",
|
"version": "1.5.210",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.208.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.210.tgz",
|
||||||
"integrity": "sha512-ozZyibehoe7tOhNaf16lKmljVf+3npZcJIEbJRVftVsmAg5TeA1mGS9dVCZzOwr2xT7xK15V0p7+GZqSPgkuPg==",
|
"integrity": "sha512-20kSVv1tyNBN2VFsjCIJZfyvxqo7ylHPrJLME040f/030lzNMA7uQNpxtqJjWSNpccD8/2sqe53EAjrFPvQmjw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
|
|||||||
2
static/js/jquery-3.7.1.min.js
vendored
Normal file
2
static/js/jquery-3.7.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
static/js/purify.min.js
vendored
2
static/js/purify.min.js
vendored
File diff suppressed because one or more lines are too long
1
static/js/purify.min.js.map
Normal file
1
static/js/purify.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@@ -98,124 +98,134 @@ A more detailed example:
|
|||||||
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
|
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// Shim i18next
|
// Shim i18next
|
||||||
window.i18next = window.i18next || {
|
window.i18next = window.i18next || {
|
||||||
t: function t(/** @type {string} */key) { return key; }
|
t: function t(/** @type {string} */ key) {
|
||||||
}
|
return key;
|
||||||
const t = window.i18next.t.bind(window.i18next);
|
},
|
||||||
|
};
|
||||||
|
const t = window.i18next.t.bind(window.i18next);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the configuration value.
|
* Read the configuration value.
|
||||||
*
|
*
|
||||||
* @param {string} key The configuration key.
|
* @param {string} key The configuration key.
|
||||||
* @param {string} dfl The default value.
|
* @param {string} dfl The default value.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function getCfg(key, dfl) {
|
function getCfg(key, dfl) {
|
||||||
return document.currentScript.getAttribute("data-" + key) || dfl;
|
return (
|
||||||
}
|
document.currentScript.getAttribute("data-" + key) ||
|
||||||
|
dfl
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const refurl = getCfg("page-url", window.location.href.replace(/#.*$/, ""));
|
const refurl = getCfg(
|
||||||
const addurls = getCfg("add-urls", undefined);
|
"page-url",
|
||||||
const containerID = getCfg("id", "webmentions");
|
window.location.href.replace(/#.*$/, "")
|
||||||
/** @type {Number} */
|
);
|
||||||
const textMaxWords = getCfg("wordcount");
|
const addurls = getCfg("add-urls", undefined);
|
||||||
const maxWebmentions = getCfg("max-webmentions", 30);
|
const containerID = getCfg("id", "webmentions");
|
||||||
const mentionSource = getCfg("prevent-spoofing") ? "wm-source" : "url";
|
/** @type {Number} */
|
||||||
const sortBy = getCfg("sort-by", "published");
|
const textMaxWords = getCfg("wordcount");
|
||||||
const sortDir = getCfg("sort-dir", "up");
|
const maxWebmentions = getCfg("max-webmentions", 30);
|
||||||
/** @type {boolean} */
|
const mentionSource = getCfg("prevent-spoofing") ? "wm-source" : "url";
|
||||||
const commentsAreReactions = getCfg("comments-are-reactions", false);
|
const sortBy = getCfg("sort-by", "published");
|
||||||
|
const sortDir = getCfg("sort-dir", "up");
|
||||||
|
/** @type {boolean} */
|
||||||
|
const commentsAreReactions = getCfg("comments-are-reactions", false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef MentionType
|
* @typedef MentionType
|
||||||
* @type {"in-reply-to"|"like-of"|"repost-of"|"bookmark-of"|"mention-of"|"rsvp"|"follow-of"}
|
* @type {"in-reply-to"|"like-of"|"repost-of"|"bookmark-of"|"mention-of"|"rsvp"|"follow-of"}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a reaction to a hover title.
|
* Maps a reaction to a hover title.
|
||||||
*
|
*
|
||||||
* @type {Record<MentionType, string>}
|
* @type {Record<MentionType, string>}
|
||||||
*/
|
*/
|
||||||
const reactTitle = {
|
const reactTitle = {
|
||||||
"in-reply-to": t("replied"),
|
"in-reply-to": t("replied"),
|
||||||
"like-of": t("liked"),
|
"like-of": t("liked"),
|
||||||
"repost-of": t("reposted"),
|
"repost-of": t("reposted"),
|
||||||
"bookmark-of": t("bookmarked"),
|
"bookmark-of": t("bookmarked"),
|
||||||
"mention-of": t("mentioned"),
|
"mention-of": t("mentioned"),
|
||||||
"rsvp": t("RSVPed"),
|
rsvp: t("RSVPed"),
|
||||||
"follow-of": t("followed")
|
"follow-of": t("followed"),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a reaction to an emoji.
|
* Maps a reaction to an emoji.
|
||||||
*
|
*
|
||||||
* @type {Record<MentionType, string>}
|
* @type {Record<MentionType, string>}
|
||||||
*/
|
*/
|
||||||
const reactEmoji = {
|
const reactEmoji = {
|
||||||
"in-reply-to": "💬",
|
"in-reply-to": "💬",
|
||||||
"like-of": "❤️",
|
"like-of": "❤️",
|
||||||
"repost-of": "🔄",
|
"repost-of": "🔄",
|
||||||
"bookmark-of": "⭐️",
|
"bookmark-of": "⭐️",
|
||||||
"mention-of": "💬",
|
"mention-of": "💬",
|
||||||
"rsvp": "📅",
|
rsvp: "📅",
|
||||||
"follow-of": "🐜"
|
"follow-of": "🐜",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef RSVPEmoji
|
* @typedef RSVPEmoji
|
||||||
* @type {"yes"|"no"|"interested"|"maybe"|null}
|
* @type {"yes"|"no"|"interested"|"maybe"|null}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps a RSVP to an emoji.
|
* Maps a RSVP to an emoji.
|
||||||
*
|
*
|
||||||
* @type {Record<RSVPEmoji, string>}
|
* @type {Record<RSVPEmoji, string>}
|
||||||
*/
|
*/
|
||||||
const rsvpEmoji = {
|
const rsvpEmoji = {
|
||||||
"yes": "✅",
|
yes: "✅",
|
||||||
"no": "❌",
|
no: "❌",
|
||||||
"interested": "💡",
|
interested: "💡",
|
||||||
"maybe": "💭"
|
maybe: "💭",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTML escapes the string.
|
* HTML escapes the string.
|
||||||
*
|
*
|
||||||
* @param {string} text The string to be escaped.
|
* @param {string} text The string to be escaped.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function entities(text) {
|
function entities(text) {
|
||||||
return text.replace(/[&<>"]/g, (tag) => ({
|
return text.replace(
|
||||||
'&': '&',
|
/[&<>"]/g,
|
||||||
'<': '<',
|
(tag) =>
|
||||||
'>': '>',
|
({
|
||||||
'"': '"',
|
"&": "&",
|
||||||
}[tag] || tag));
|
"<": "<",
|
||||||
}
|
">": ">",
|
||||||
|
'"': """,
|
||||||
|
}[tag] || tag)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the markup for an reaction image.
|
* Creates the markup for an reaction image.
|
||||||
*
|
*
|
||||||
* @param {Reaction} r
|
* @param {Reaction} r
|
||||||
* @param {boolean} isComment
|
* @param {boolean} isComment
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function reactImage(r, isComment) {
|
function reactImage(r, isComment) {
|
||||||
const who = entities(
|
const who = entities(r.author?.name || r.url.split("/")[2]);
|
||||||
r.author?.name || r.url.split("/")[2]
|
/** @type {string} */
|
||||||
);
|
let response = reactTitle[r["wm-property"]] || t("reacted");
|
||||||
/** @type {string} */
|
if (!isComment && r.content && r.content.text) {
|
||||||
let response = reactTitle[r["wm-property"]] || t("reacted");
|
response += ": " + extractComment(r);
|
||||||
if (!isComment && r.content && r.content.text) {
|
}
|
||||||
response += ": " + extractComment(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
let authorPhoto = '';
|
let authorPhoto = "";
|
||||||
if (r.author && r.author.photo) {
|
if (r.author && r.author.photo) {
|
||||||
authorPhoto = `
|
authorPhoto = `
|
||||||
<img
|
<img
|
||||||
src="${entities(r.author.photo)}"
|
src="${entities(r.author.photo)}"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
@@ -223,22 +233,22 @@ A more detailed example:
|
|||||||
alt="${who}"
|
alt="${who}"
|
||||||
>
|
>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
authorPhoto = `
|
authorPhoto = `
|
||||||
<img
|
<img
|
||||||
class="missing"
|
class="missing"
|
||||||
src="data:image/webp;base64,UklGRkoCAABXRUJQVlA4TD4CAAAvP8APAIV0WduUOLr/m/iqY6SokDJSMD5xYX23SQizRsVdZmIj/f6goYUbiOj/BED7MOPReuBNT3vBesSzIex+SeqMFFkjebFmzH3S7POxDSJ1yaCbCmMnS2R46cRMPyQLw4GBK4esdK60pYwsZakecUCl5zsHv/5cPH08nx9/7i6rEEVCg2hR8VSd30PxMZpVoJZQO6Dixgg6X5oKFCmlVHIDmmMFShWumAXgCuyqVN8hHff/k+9fj8+ei7BVjpxBmZCUJv+6DhWGZwWvs+UoLHFCKsPYpfJtIcEXBTopEEsKwedZUv4ku1FZErKULLyQwFGgnmTs2vBD5qu44xwnG9uyjgrFOd+KRVlXyQfwQlauydaU6AVI7OjKXLUEqNtxJBmQegNDZgV7lxxqYMOMrDyC1NdAGbdiH9Ij0skjG+oTyfO0lmjdgvoH8iIgreuBMRYLSH+R3sAztXgL+XfS7E2bmfo6gnS0TrpnzHT7kL+skj7PgHuBwv/zpN8LDLQg7zfJZLBubMKnyeh6ZGyfDEfc2LYpnlUtG7JqsSHq1WoASbUS4KVaLwB8be5mfsGMDwBcm5VxbuxWxx3nkFanB6lYqsqSkOGkKicoDvXsneR7BkKU7DtaEuT7+pxBGVwx+9gVyqf2pVA9sC2CsmjZ1RJqEJHS4Tj/pCcS0JoyBYOsB91Xjh3OFfQPQhvCAYyeLJlaOoFp0XNNuD0BC8exr8uPx7D1JWkwFdZIXmD3MOPReuDNzHjBesSzIbQD"
|
src="data:image/webp;base64,UklGRkoCAABXRUJQVlA4TD4CAAAvP8APAIV0WduUOLr/m/iqY6SokDJSMD5xYX23SQizRsVdZmIj/f6goYUbiOj/BED7MOPReuBNT3vBesSzIex+SeqMFFkjebFmzH3S7POxDSJ1yaCbCmMnS2R46cRMPyQLw4GBK4esdK60pYwsZakecUCl5zsHv/5cPH08nx9/7i6rEEVCg2hR8VSd30PxMZpVoJZQO6Dixgg6X5oKFCmlVHIDmmMFShWumAXgCuyqVN8hHff/k+9fj8+ei7BVjpxBmZCUJv+6DhWGZwWvs+UoLHFCKsPYpfJtIcEXBTopEEsKwedZUv4ku1FZErKULLyQwFGgnmTs2vBD5qu44xwnG9uyjgrFOd+KRVlXyQfwQlauydaU6AVI7OjKXLUEqNtxJBmQegNDZgV7lxxqYMOMrDyC1NdAGbdiH9Ij0skjG+oTyfO0lmjdgvoH8iIgreuBMRYLSH+R3sAztXgL+XfS7E2bmfo6gnS0TrpnzHT7kL+skj7PgHuBwv/zpN8LDLQg7zfJZLBubMKnyeh6ZGyfDEfc2LYpnlUtG7JqsSHq1WoASbUS4KVaLwB8be5mfsGMDwBcm5VxbuxWxx3nkFanB6lYqsqSkOGkKicoDvXsneR7BkKU7DtaEuT7+pxBGVwx+9gVyqf2pVA9sC2CsmjZ1RJqEJHS4Tj/pCcS0JoyBYOsB91Xjh3OFfQPQhvCAYyeLJlaOoFp0XNNuD0BC8exr8uPx7D1JWkwFdZIXmD3MOPReuDNzHjBesSzIbQD"
|
||||||
alt="${who}$"
|
alt="${who}$"
|
||||||
>
|
>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rsvp = '';
|
let rsvp = "";
|
||||||
if (r.rsvp && rsvpEmoji[r.rsvp]) {
|
if (r.rsvp && rsvpEmoji[r.rsvp]) {
|
||||||
rsvp = `<sub>${rsvpEmoji[r.rsvp]}</sub>`;
|
rsvp = `<sub>${rsvpEmoji[r.rsvp]}</sub>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return`
|
return `
|
||||||
<a
|
<a
|
||||||
class="reaction"
|
class="reaction"
|
||||||
rel="nofollow ugc"
|
rel="nofollow ugc"
|
||||||
@@ -246,223 +256,227 @@ A more detailed example:
|
|||||||
href="${r[mentionSource]}"
|
href="${r[mentionSource]}"
|
||||||
>
|
>
|
||||||
${authorPhoto}
|
${authorPhoto}
|
||||||
${(reactEmoji[r['wm-property']] || '💥')}
|
${reactEmoji[r["wm-property"]] || "💥"}
|
||||||
${rsvp}
|
${rsvp}
|
||||||
</a>
|
</a>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strip the protocol off a URL.
|
* Strip the protocol off a URL.
|
||||||
*
|
*
|
||||||
* @param {string} url The URL to strip protocol off.
|
* @param {string} url The URL to strip protocol off.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function stripurl(url) {
|
function stripurl(url) {
|
||||||
return url.substr(url.indexOf('//'));
|
return url.substr(url.indexOf("//"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deduplicate multiple mentions from the same source URL.
|
* Deduplicate multiple mentions from the same source URL.
|
||||||
*
|
*
|
||||||
* @param {Array<Reaction>} mentions Mentions of the source URL.
|
* @param {Array<Reaction>} mentions Mentions of the source URL.
|
||||||
* @return {Array<Reaction>}
|
* @return {Array<Reaction>}
|
||||||
*/
|
*/
|
||||||
function dedupe(mentions) {
|
function dedupe(mentions) {
|
||||||
/** @type {Array<Reaction>} */
|
/** @type {Array<Reaction>} */
|
||||||
const filtered = [];
|
const filtered = [];
|
||||||
/** @type {Record<string, boolean>} */
|
/** @type {Record<string, boolean>} */
|
||||||
const seen = {};
|
const seen = {};
|
||||||
|
|
||||||
mentions.forEach(function(r) {
|
mentions.forEach(function (r) {
|
||||||
// Strip off the protocol (i.e. treat http and https the same)
|
// Strip off the protocol (i.e. treat http and https the same)
|
||||||
const source = stripurl(r.url);
|
const source = stripurl(r.url);
|
||||||
if (!seen[source]) {
|
if (!seen[source]) {
|
||||||
filtered.push(r);
|
filtered.push(r);
|
||||||
seen[source] = true;
|
seen[source] = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract comments from a reaction.
|
* Extract comments from a reaction.
|
||||||
*
|
*
|
||||||
* @param {Reactions} c
|
* @param {Reactions} c
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
function extractComment(c) {
|
function extractComment(c) {
|
||||||
let text = entities(c.content.text);
|
let text = entities(c.content.text);
|
||||||
|
|
||||||
if (textMaxWords) {
|
if (textMaxWords) {
|
||||||
let words = text.replace(/\s+/g,' ').split(' ', textMaxWords + 1);
|
let words = text
|
||||||
if (words.length > textMaxWords) {
|
.replace(/\s+/g, " ")
|
||||||
words[textMaxWords - 1] += '…';
|
.split(" ", textMaxWords + 1);
|
||||||
words = words.slice(0, textMaxWords);
|
if (words.length > textMaxWords) {
|
||||||
text = words.join(' ');
|
words[textMaxWords - 1] += "…";
|
||||||
}
|
words = words.slice(0, textMaxWords);
|
||||||
}
|
text = words.join(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format comments as HTML.
|
* Format comments as HTML.
|
||||||
*
|
*
|
||||||
* @param {Array<Reaction>} comments The comments to format.
|
* @param {Array<Reaction>} comments The comments to format.
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
function formatComments(comments) {
|
function formatComments(comments) {
|
||||||
const headline = `<h3>${t('Responses')}</h3>`;
|
const headline = `<h2>${t("Responses")}</h2>`;
|
||||||
const markup = comments
|
const markup = comments
|
||||||
.map((c) => {
|
.map((c) => {
|
||||||
const image = reactImage(c, true);
|
const image = reactImage(c, true);
|
||||||
|
|
||||||
let source = entities(c.url.split('/')[2]);
|
let source = entities(c.url.split("/")[2]);
|
||||||
if (c.author && c.author.name) {
|
if (c.author && c.author.name) {
|
||||||
source = entities(c.author.name);
|
source = entities(c.author.name);
|
||||||
}
|
}
|
||||||
const link = `<a class="source" rel="nofollow ugc" href="${c[mentionSource]}">${source}</a>`;
|
const link = `<a class="source" rel="nofollow ugc" href="${c[mentionSource]}">${source}</a>`;
|
||||||
|
|
||||||
let linkclass = "name";
|
let linkclass = "name";
|
||||||
let linktext = `(${t("mention")})`;
|
let linktext = `(${t("mention")})`;
|
||||||
if (c.name) {
|
if (c.name) {
|
||||||
linkclass = "name";
|
linkclass = "name";
|
||||||
linktext = entities(c.name);
|
linktext = entities(c.name);
|
||||||
} else if (c.content && c.content.text) {
|
} else if (c.content && c.content.text) {
|
||||||
linkclass = "text";
|
linkclass = "text";
|
||||||
linktext = extractComment(c);
|
linktext = extractComment(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
const type = `<span class="${linkclass}">${linktext}</span>`;
|
const type = `<span class="${linkclass}">${linktext}</span>`;
|
||||||
|
|
||||||
return `<li>${image} ${link} ${type}</li>`;
|
return `<li>${image} ${link} ${type}</li>`;
|
||||||
})
|
})
|
||||||
.join('');
|
.join("");
|
||||||
return `
|
return `
|
||||||
${headline}
|
${headline}
|
||||||
<ul class="comments">${markup}</ul>
|
<ul class="comments">${markup}</ul>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Reaction
|
* @typedef {Object} Reaction
|
||||||
* @property {string} url
|
* @property {string} url
|
||||||
* @property {Object?} author
|
* @property {Object?} author
|
||||||
* @property {string?} author.name
|
* @property {string?} author.name
|
||||||
* @property {string?} author.photo
|
* @property {string?} author.photo
|
||||||
* @property {Object?} content
|
* @property {Object?} content
|
||||||
* @property {string?} content.text
|
* @property {string?} content.text
|
||||||
* @property {RSVPEmoji?} rsvp
|
* @property {RSVPEmoji?} rsvp
|
||||||
* @property {MentionType?} wm-property
|
* @property {MentionType?} wm-property
|
||||||
* @property {string?} wm-source
|
* @property {string?} wm-source
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a list of reactions as HTML.
|
* Formats a list of reactions as HTML.
|
||||||
*
|
*
|
||||||
* @param {Array<Reaction>} reacts List of reactions to format
|
* @param {Array<Reaction>} reacts List of reactions to format
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
function formatReactions(reacts) {
|
function formatReactions(reacts) {
|
||||||
const headline = `<h3>${t('Reactions')}</h3>`;
|
const headline = `<h2>${t("Reactions")}</h2>`;
|
||||||
|
|
||||||
const markup = reacts.map((r) => reactImage(r)).join('');
|
const markup = reacts.map((r) => reactImage(r)).join("");
|
||||||
|
|
||||||
return `
|
return `
|
||||||
${headline}
|
${headline}
|
||||||
<ul class="reacts">${markup}</ul>
|
<ul class="reacts">${markup}</ul>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef WebmentionResponse
|
* @typedef WebmentionResponse
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
* @property {Array<Reaction>} children
|
* @property {Array<Reaction>} children
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register event listener.
|
* Register event listener.
|
||||||
*/
|
*/
|
||||||
window.addEventListener("load", async function () {
|
window.addEventListener("load", async function () {
|
||||||
const container = document.getElementById(containerID);
|
const container = document.getElementById(containerID);
|
||||||
if (!container) {
|
if (!container) {
|
||||||
// no container, so do nothing
|
// no container, so do nothing
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = [stripurl(refurl)];
|
const pages = [stripurl(refurl)];
|
||||||
if (!!addurls) {
|
if (!!addurls) {
|
||||||
addurls.split('|').forEach(function (url) {
|
addurls.split("|").forEach(function (url) {
|
||||||
pages.push(stripurl(url));
|
pages.push(stripurl(url));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let apiURL = `https://webmention.io/api/mentions.jf2?per-page=${maxWebmentions}&sort-by=${sortBy}&sort-dir=${sortDir}`;
|
let apiURL = `https://webmention.io/api/mentions.jf2?per-page=${maxWebmentions}&sort-by=${sortBy}&sort-dir=${sortDir}`;
|
||||||
|
|
||||||
pages.forEach(function (path) {
|
pages.forEach(function (path) {
|
||||||
apiURL += `&target[]=${encodeURIComponent('http:' + path)}&target[]=${encodeURIComponent('https:' + path)}`;
|
apiURL += `&target[]=${encodeURIComponent(
|
||||||
});
|
"http:" + path
|
||||||
|
)}&target[]=${encodeURIComponent("https:" + path)}`;
|
||||||
|
});
|
||||||
|
|
||||||
/** @type {WebmentionResponse} */
|
/** @type {WebmentionResponse} */
|
||||||
let json = {};
|
let json = {};
|
||||||
try {
|
try {
|
||||||
const response = await window.fetch(apiURL);
|
const response = await window.fetch(apiURL);
|
||||||
if (response.status >= 200 && response.status < 300) {
|
if (response.status >= 200 && response.status < 300) {
|
||||||
json = await response.json();
|
json = await response.json();
|
||||||
} else {
|
} else {
|
||||||
console.error("Could not parse response");
|
console.error("Could not parse response");
|
||||||
new Error(response.statusText);
|
new Error(response.statusText);
|
||||||
}
|
}
|
||||||
} catch(error) {
|
} catch (error) {
|
||||||
// Purposefully not escalate further, i.e. no UI update
|
// Purposefully not escalate further, i.e. no UI update
|
||||||
console.error("Request failed", error);
|
console.error("Request failed", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Array<Reaction>} */
|
/** @type {Array<Reaction>} */
|
||||||
let comments = [];
|
let comments = [];
|
||||||
/** @type {Array<Reaction>} */
|
/** @type {Array<Reaction>} */
|
||||||
const collects = [];
|
const collects = [];
|
||||||
|
|
||||||
if (commentsAreReactions) {
|
if (commentsAreReactions) {
|
||||||
comments = collects;
|
comments = collects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Record<MentionType, Array<Reaction>>} */
|
/** @type {Record<MentionType, Array<Reaction>>} */
|
||||||
const mapping = {
|
const mapping = {
|
||||||
"in-reply-to": comments,
|
"in-reply-to": comments,
|
||||||
"like-of": collects,
|
"like-of": collects,
|
||||||
"repost-of": collects,
|
"repost-of": collects,
|
||||||
"bookmark-of": collects,
|
"bookmark-of": collects,
|
||||||
"follow-of": collects,
|
"follow-of": collects,
|
||||||
"mention-of": comments,
|
"mention-of": comments,
|
||||||
"rsvp": comments
|
rsvp: comments,
|
||||||
};
|
};
|
||||||
|
|
||||||
json.children.forEach(function(child) {
|
json.children.forEach(function (child) {
|
||||||
// Map each mention into its respective container
|
// Map each mention into its respective container
|
||||||
const store = mapping[child['wm-property']];
|
const store = mapping[child["wm-property"]];
|
||||||
if (store) {
|
if (store) {
|
||||||
store.push(child);
|
store.push(child);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// format the comment-type things
|
// format the comment-type things
|
||||||
let formattedComments = '';
|
let formattedComments = "";
|
||||||
if (comments.length > 0 && comments !== collects) {
|
if (comments.length > 0 && comments !== collects) {
|
||||||
formattedComments = formatComments(dedupe(comments));
|
formattedComments = formatComments(dedupe(comments));
|
||||||
}
|
}
|
||||||
|
|
||||||
// format the other reactions
|
// format the other reactions
|
||||||
let reactions = '';
|
let reactions = "";
|
||||||
if (collects.length > 0) {
|
if (collects.length > 0) {
|
||||||
reactions = formatReactions(dedupe(collects));
|
reactions = formatReactions(dedupe(collects));
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = `${formattedComments}${reactions}`;
|
container.innerHTML = `${formattedComments}${reactions}`;
|
||||||
});
|
});
|
||||||
}());
|
})();
|
||||||
|
|
||||||
// End-of-file marker for LibreJS
|
// End-of-file marker for LibreJS
|
||||||
// @license-end
|
// @license-end
|
||||||
|
|||||||
1
static/js/webmention.min.js
vendored
1
static/js/webmention.min.js
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
|
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt
|
||||||
!function(){"use strict";window.i18next=window.i18next||{t:function(n){return n}};const n=window.i18next.t.bind(window.i18next);function t(n,t){return document.currentScript.getAttribute("data-"+n)||t}const e=t("page-url",window.location.href.replace(/#.*$/,"")),o=t("add-urls",void 0),r=t("id","webmentions"),s=t("wordcount"),i=t("max-webmentions",30),l=t("prevent-spoofing")?"wm-source":"url",a=t("sort-by","published"),c=t("sort-dir","up"),u=t("comments-are-reactions",!1),p={"in-reply-to":n("replied"),"like-of":n("liked"),"repost-of":n("reposted"),"bookmark-of":n("bookmarked"),"mention-of":n("mentioned"),rsvp:n("RSVPed"),"follow-of":n("followed")},f={"in-reply-to":"💬","like-of":"❤️","repost-of":"🔄","bookmark-of":"⭐️","mention-of":"💬",rsvp:"📅","follow-of":"🐜"},m={yes:"✅",no:"❌",interested:"💡",maybe:"💭"};function d(n){return n.replace(/[&<>"]/g,(n=>({"&":"&","<":"<",">":">",'"':"""}[n]||n)))}function w(t,e){const o=d(t.author?.name||t.url.split("/")[2]);let r=p[t["wm-property"]]||n("reacted");!e&&t.content&&t.content.text&&(r+=": "+x(t));let s="";s=t.author&&t.author.photo?`\n <img\n src="${d(t.author.photo)}"\n loading="lazy"\n decoding="async"\n alt="${o}"\n >\n `:`\n <img\n class="missing"\n src="data:image/webp;base64,UklGRkoCAABXRUJQVlA4TD4CAAAvP8APAIV0WduUOLr/m/iqY6SokDJSMD5xYX23SQizRsVdZmIj/f6goYUbiOj/BED7MOPReuBNT3vBesSzIex+SeqMFFkjebFmzH3S7POxDSJ1yaCbCmMnS2R46cRMPyQLw4GBK4esdK60pYwsZakecUCl5zsHv/5cPH08nx9/7i6rEEVCg2hR8VSd30PxMZpVoJZQO6Dixgg6X5oKFCmlVHIDmmMFShWumAXgCuyqVN8hHff/k+9fj8+ei7BVjpxBmZCUJv+6DhWGZwWvs+UoLHFCKsPYpfJtIcEXBTopEEsKwedZUv4ku1FZErKULLyQwFGgnmTs2vBD5qu44xwnG9uyjgrFOd+KRVlXyQfwQlauydaU6AVI7OjKXLUEqNtxJBmQegNDZgV7lxxqYMOMrDyC1NdAGbdiH9Ij0skjG+oTyfO0lmjdgvoH8iIgreuBMRYLSH+R3sAztXgL+XfS7E2bmfo6gnS0TrpnzHT7kL+skj7PgHuBwv/zpN8LDLQg7zfJZLBubMKnyeh6ZGyfDEfc2LYpnlUtG7JqsSHq1WoASbUS4KVaLwB8be5mfsGMDwBcm5VxbuxWxx3nkFanB6lYqsqSkOGkKicoDvXsneR7BkKU7DtaEuT7+pxBGVwx+9gVyqf2pVA9sC2CsmjZ1RJqEJHS4Tj/pCcS0JoyBYOsB91Xjh3OFfQPQhvCAYyeLJlaOoFp0XNNuD0BC8exr8uPx7D1JWkwFdZIXmD3MOPReuDNzHjBesSzIbQD"\n alt="${o}$"\n >\n `;let i="";return t.rsvp&&m[t.rsvp]&&(i=`<sub>${m[t.rsvp]}</sub>`),`\n <a\n class="reaction"\n rel="nofollow ugc"\n title="${o} ${r}"\n href="${t[l]}"\n >\n ${s}\n ${f[t["wm-property"]]||"💥"}\n ${i}\n </a>\n `}function h(n){return n.substr(n.indexOf("//"))}function g(n){const t=[],e={};return n.forEach((function(n){const o=h(n.url);e[o]||(t.push(n),e[o]=!0)})),t}function x(n){let t=d(n.content.text);if(s){let n=t.replace(/\s+/g," ").split(" ",s+1);n.length>s&&(n[s-1]+="…",n=n.slice(0,s),t=n.join(" "))}return t}window.addEventListener("load",(async function(){const t=document.getElementById(r);if(!t)return;const s=[h(e)];o&&o.split("|").forEach((function(n){s.push(h(n))}));let p=`https://webmention.io/api/mentions.jf2?per-page=${i}&sort-by=${a}&sort-dir=${c}`;s.forEach((function(n){p+=`&target[]=${encodeURIComponent("http:"+n)}&target[]=${encodeURIComponent("https:"+n)}`}));let f={};try{const n=await window.fetch(p);n.status>=200&&n.status<300?f=await n.json():(console.error("Could not parse response"),new Error(n.statusText))}catch(n){console.error("Request failed",n)}let m=[];const $=[];u&&(m=$);const y={"in-reply-to":m,"like-of":$,"repost-of":$,"bookmark-of":$,"follow-of":$,"mention-of":m,rsvp:m};f.children.forEach((function(n){const t=y[n["wm-property"]];t&&t.push(n)}));let b="";m.length>0&&m!==$&&(b=function(t){return`\n <h2>${n("Responses")}</h2>\n <ul class="comments">${t.map((t=>{const e=w(t,!0);let o=d(t.url.split("/")[2]);t.author&&t.author.name&&(o=d(t.author.name));const r=`<a class="source" rel="nofollow ugc" href="${t[l]}">${o}</a>`;let s="name",i=`(${n("mention")})`;return t.name?(s="name",i=d(t.name)):t.content&&t.content.text&&(s="text",i=x(t)),`<li>${e} ${r} <span class="${s}">${i}</span></li>`})).join("")}</ul>\n `}(g(m)));let k="";var B;$.length>0&&(B=g($),k=`\n <h2>${n("Reactions")}</h2>\n <ul class="reacts">${B.map((n=>w(n))).join("")}</ul>\n `),t.innerHTML=`${b}${k}`}))}();
|
!function(){"use strict";window.i18next=window.i18next||{t:function(n){return n}};const n=window.i18next.t.bind(window.i18next);function t(n,t){return document.currentScript.getAttribute("data-"+n)||t}const e=t("page-url",window.location.href.replace(/#.*$/,"")),o=t("add-urls",void 0),r=t("id","webmentions"),s=t("wordcount"),i=t("max-webmentions",30),l=t("prevent-spoofing")?"wm-source":"url",a=t("sort-by","published"),c=t("sort-dir","up"),u=t("comments-are-reactions",!1),p={"in-reply-to":n("replied"),"like-of":n("liked"),"repost-of":n("reposted"),"bookmark-of":n("bookmarked"),"mention-of":n("mentioned"),rsvp:n("RSVPed"),"follow-of":n("followed")},f={"in-reply-to":"💬","like-of":"❤️","repost-of":"🔄","bookmark-of":"⭐️","mention-of":"💬",rsvp:"📅","follow-of":"🐜"},m={yes:"✅",no:"❌",interested:"💡",maybe:"💭"};function d(n){return n.replace(/[&<>"]/g,(n=>({"&":"&","<":"<",">":">",'"':"""}[n]||n)))}function w(t,e){const o=d(t.author?.name||t.url.split("/")[2]);let r=p[t["wm-property"]]||n("reacted");!e&&t.content&&t.content.text&&(r+=": "+x(t));let s="";s=t.author&&t.author.photo?`\n <img\n src="${d(t.author.photo)}"\n loading="lazy"\n decoding="async"\n alt="${o}"\n >\n `:`\n <img\n class="missing"\n src="data:image/webp;base64,UklGRkoCAABXRUJQVlA4TD4CAAAvP8APAIV0WduUOLr/m/iqY6SokDJSMD5xYX23SQizRsVdZmIj/f6goYUbiOj/BED7MOPReuBNT3vBesSzIex+SeqMFFkjebFmzH3S7POxDSJ1yaCbCmMnS2R46cRMPyQLw4GBK4esdK60pYwsZakecUCl5zsHv/5cPH08nx9/7i6rEEVCg2hR8VSd30PxMZpVoJZQO6Dixgg6X5oKFCmlVHIDmmMFShWumAXgCuyqVN8hHff/k+9fj8+ei7BVjpxBmZCUJv+6DhWGZwWvs+UoLHFCKsPYpfJtIcEXBTopEEsKwedZUv4ku1FZErKULLyQwFGgnmTs2vBD5qu44xwnG9uyjgrFOd+KRVlXyQfwQlauydaU6AVI7OjKXLUEqNtxJBmQegNDZgV7lxxqYMOMrDyC1NdAGbdiH9Ij0skjG+oTyfO0lmjdgvoH8iIgreuBMRYLSH+R3sAztXgL+XfS7E2bmfo6gnS0TrpnzHT7kL+skj7PgHuBwv/zpN8LDLQg7zfJZLBubMKnyeh6ZGyfDEfc2LYpnlUtG7JqsSHq1WoASbUS4KVaLwB8be5mfsGMDwBcm5VxbuxWxx3nkFanB6lYqsqSkOGkKicoDvXsneR7BkKU7DtaEuT7+pxBGVwx+9gVyqf2pVA9sC2CsmjZ1RJqEJHS4Tj/pCcS0JoyBYOsB91Xjh3OFfQPQhvCAYyeLJlaOoFp0XNNuD0BC8exr8uPx7D1JWkwFdZIXmD3MOPReuDNzHjBesSzIbQD"\n alt="${o}$"\n >\n `;let i="";return t.rsvp&&m[t.rsvp]&&(i=`<sub>${m[t.rsvp]}</sub>`),`\n <a\n class="reaction"\n rel="nofollow ugc"\n title="${o} ${r}"\n href="${t[l]}"\n >\n ${s}\n ${f[t["wm-property"]]||"💥"}\n ${i}\n </a>\n `}function h(n){return n.substr(n.indexOf("//"))}function g(n){const t=[],e={};return n.forEach((function(n){const o=h(n.url);e[o]||(t.push(n),e[o]=!0)})),t}function x(n){let t=d(n.content.text);if(s){let n=t.replace(/\s+/g," ").split(" ",s+1);n.length>s&&(n[s-1]+="…",n=n.slice(0,s),t=n.join(" "))}return t}window.addEventListener("load",(async function(){const t=document.getElementById(r);if(!t)return;const s=[h(e)];o&&o.split("|").forEach((function(n){s.push(h(n))}));let p=`https://webmention.io/api/mentions.jf2?per-page=${i}&sort-by=${a}&sort-dir=${c}`;s.forEach((function(n){p+=`&target[]=${encodeURIComponent("http:"+n)}&target[]=${encodeURIComponent("https:"+n)}`}));let f={};try{const n=await window.fetch(p);n.status>=200&&n.status<300?f=await n.json():(console.error("Could not parse response"),new Error(n.statusText))}catch(n){console.error("Request failed",n)}let m=[];const $=[];u&&(m=$);const y={"in-reply-to":m,"like-of":$,"repost-of":$,"bookmark-of":$,"follow-of":$,"mention-of":m,rsvp:m};f.children.forEach((function(n){const t=y[n["wm-property"]];t&&t.push(n)}));let b="";m.length>0&&m!==$&&(b=function(t){return`\n <h2>${n("Responses")}</h2>\n <ul class="comments">${t.map((t=>{const e=w(t,!0);let o=d(t.url.split("/")[2]);t.author&&t.author.name&&(o=d(t.author.name));const r=`<a class="source" rel="nofollow ugc" href="${t[l]}">${o}</a>`;let s="name",i=`(${n("mention")})`;return t.name?(s="name",i=d(t.name)):t.content&&t.content.text&&(s="text",i=x(t)),`<li>${e} ${r} <span class="${s}">${i}</span></li>`})).join("")}</ul>\n `}(g(m)));let k="";var B;$.length>0&&(B=g($),k=`\n <h2>${n("Reactions")}</h2>\n <ul class="reacts">${B.map((n=>w(n))).join("")}</ul>\n `),t.innerHTML=`${b}${k}`}))}();
|
||||||
// @license-end
|
// @license-end
|
||||||
Reference in New Issue
Block a user