Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/leonardofaria/bento.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'assets/js/webmentions.js')
-rw-r--r--assets/js/webmentions.js216
1 files changed, 216 insertions, 0 deletions
diff --git a/assets/js/webmentions.js b/assets/js/webmentions.js
new file mode 100644
index 0000000..0576560
--- /dev/null
+++ b/assets/js/webmentions.js
@@ -0,0 +1,216 @@
+// based on https://shindakun.dev/posts/adding-webmentions-to-microblog/
+
+// user-circle icon from heroicons.com encoded by https://yoksel.github.io/url-encoder/
+const ANON_AVATAR = 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"%3E%3Cpath fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-6-3a2 2 0 11-4 0 2 2 0 014 0zm-2 4a5 5 0 00-4.546 2.916A5.986 5.986 0 0010 16a5.986 5.986 0 004.546-2.084A5 5 0 0010 11z" clip-rule="evenodd" /%3E%3C/svg%3E';
+
+const fetchWebmentions = (url, aliases, productionBaseUrl) => {
+ if (!document.getElementById('comments')) {
+ return;
+ }
+ if (!url) {
+ url = document.location.origin + document.location.pathname;
+ }
+ const targets = getUrlPermutations(url, aliases, productionBaseUrl);
+
+ const script = document.createElement('script');
+ let src =
+ 'https://webmention.io/api/mentions?perPage=500&jsonp=parseWebmentions';
+ targets.forEach((targetUrl) => {
+ src += `&target[]=${encodeURIComponent(targetUrl)}`;
+ });
+ src += `&_=${Math.random()}`;
+ script.src = src;
+ script.async = true;
+ document.body.appendChild(script);
+}
+
+const getUrlPermutations = (url, aliases, productionBaseUrl) => {
+ const urls = [];
+
+ // Replace the current base URL (ex.: http://localhost:1313) to the production one
+ const currentUrl = new URL(window.location);
+ url = url.replace(currentUrl.origin, productionBaseUrl);
+ urls.push(url);
+
+ // Add http variation
+ urls.push(url.replace('https://', 'http://'));
+
+ // Add variation with final /
+ if (url.substr(-1) === '/') {
+ var noslash = url.substr(0, url.length - 1);
+ urls.push(noslash);
+ urls.push(noslash.replace('https://', 'http://'));
+ }
+
+ // Add aliases variations
+ if (aliases) {
+ aliases.forEach((alias) => {
+ urls.push(`${productionBaseUrl}/${alias}`);
+ });
+ }
+
+ return urls;
+}
+
+const parseWebmentions = (data) => {
+ const links = data.links.sort(wmSort);
+ const likes = [];
+ const reposts = [];
+ const replies = [];
+ const avatarUrls = [];
+
+ links.map((l) => {
+ if (!l.activity || !l.activity.type) {
+ console.warning('unknown link type', l);
+ return;
+ }
+ if (!l.verified) {
+ return;
+ }
+ if (l.data.author) {
+ avatarUrls.push(l.data.author.photo);
+ }
+ switch (l.activity.type) {
+ case 'like':
+ likes.push(l);
+ break;
+ case 'link':
+ case 'repost':
+ reposts.push(l);
+ break;
+ default:
+ replies.push(l);
+ break;
+ }
+ });
+
+ resetContainers();
+ render(likes, 'like-template', 'likes');
+ render(reposts, 'reply-template', 'likes');
+ render(replies, 'reply-template', 'shares');
+ renderSummary(likes.length, (reposts.length + replies.length), avatarUrls);
+}
+window.parseWebmentions = parseWebmentions;
+
+// Reset containers due to the usage of Turbolinks
+const resetContainers = () => {
+ const likes = document.querySelector('#likes');
+ const shares = document.querySelector('#shares');
+ const replies = document.querySelector('#replies');
+ const avatars = document.querySelector('#webmentions-avatars');
+
+ while (likes.lastChild) { likes.removeChild(likes.lastChild); }
+ while (shares.lastChild) { shares.removeChild(shares.lastChild); }
+ while (replies.lastChild) { replies.removeChild(replies.lastChild); }
+ while (avatars.lastChild) { avatars.removeChild(avatars.lastChild); }
+}
+
+const wmSort = (a, b) => {
+ const dateA = getWmDate(a);
+ const dateB = getWmDate(b);
+ if (dateA < dateB) {
+ return -1;
+ } else if (dateB < dateA) {
+ return 1;
+ }
+ return 0;
+}
+
+const getWmDate = (webmention) => {
+ if (webmention.data.published) {
+ return new Date(webmention.data.published);
+ }
+ return new Date(webmention.verified_date);
+}
+
+const render = (items, template, destination) => {
+ const t = document.getElementById(template).content;
+ const list = document.getElementById(destination);
+
+ items.map((l) => {
+ const data = {
+ url: l.data.url,
+ date: new Date(l.data.published || l.verified_date),
+ content: l.data.content,
+ };
+
+ if (l.data.author) {
+ data.photo = l.data.author.photo || ANON_AVATAR;
+ data.name = l.data.author.name;
+ data.authorUrl = l.data.author.url;
+ } else {
+ data.photo = ANON_AVATAR;
+ data.name = getHostName(l.data.url) || 'inbound link';
+ data.authorUrl = l.data.url;
+ }
+
+ if (l.activity.sentence) {
+ data.sentence = l.activity.sentence;
+ }
+
+ fillTemplate(t, data);
+ const clone = document.importNode(t, true);
+ list.appendChild(clone);
+ });
+
+}
+
+const getHostName = (url) => {
+ var a = document.createElement('a');
+ a.href = url;
+ return (a.hostname || '').replace('www.', '');
+}
+
+const fillTemplate = (template, vals) => {
+ template.querySelector('.js-avatar').src = vals.photo;
+ template.querySelector('.js-author').href = vals.authorUrl;
+ template.querySelector('.js-author-name').innerHTML = vals.name;
+ template.querySelector('.js-author-name').href = vals.authorUrl;
+ template.querySelector('.js-source').href = vals.url;
+ if (vals.sentence && template.querySelector('.js-sentence')) {
+ template.querySelector('.js-sentence').innerText = vals.sentence;
+ }
+ const date = template.querySelector('.js-date');
+ if (date) {
+ date.innerHTML = formatDate(vals.date);
+ }
+ if (vals.content) {
+ template.querySelector('.js-content').innerHTML = vals.content;
+ }
+}
+
+const formatDate = (date) => {
+ if (!date) {
+ return '';
+ }
+ return date.toLocaleDateString('en-US', {
+ month: 'short',
+ day: '2-digit',
+ year: 'numeric'
+ });
+}
+
+const renderSummary = (totalLikes, totalInteractions, avatars) => {
+ document.querySelector('#webmentions-total-likes').innerText = totalLikes;
+ document.querySelector('#webmentions-total-interactions').innerText = totalInteractions;
+ const avatarsContainer = document.querySelector('#webmentions-avatars');
+ const uniqueAvatars = [...new Set(avatars)];
+
+ for (const [index, avatar] of uniqueAvatars.entries()) {
+ const image = document.createElement("img");
+ image.src = avatar;
+ image.classList = 'inline-block h-8 w-8 rounded-full ring-2 ring-white';
+ image.alt = '';
+
+ avatarsContainer.appendChild(image);
+
+ if (index > 9) {
+ const more = document.createElement("span");
+ more.classList = 'flex items-center justify-center text-xs bg-black text-white font-bold h-8 w-8 rounded-full ring-2 ring-white';
+ more.innerHTML = `+${uniqueAvatars.length - 9}`;
+ avatarsContainer.appendChild(more);
+
+ break;
+ }
+ };
+}