diff options
| author | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2024-07-13 18:04:05 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze <zerodaysfordays@sdf.org> | 2024-07-13 18:11:42 -0400 |
| commit | 81c4d517735983a5afd6e9dc800257c761598527 (patch) | |
| tree | 6b924707914d385126e6d330d2c628fd26f23a27 /static/js/webmention.js | |
| parent | 7f37518e4792f040a753a5d8d68d51e76cc0b2be (diff) | |
The `org' directory is no longer necessary
Diffstat (limited to 'static/js/webmention.js')
| -rw-r--r-- | static/js/webmention.js | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/static/js/webmention.js b/static/js/webmention.js new file mode 100644 index 0000000..d280d4d --- /dev/null +++ b/static/js/webmention.js @@ -0,0 +1,229 @@ +/* + * webmention.js -- Fetch and display mentions from webmention.io. + * Copyright © 2019 - 2023 Jakob L. Kreuze <zerodaysfordays@sdf.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * <http://www.gnu.org/licenses/>. + */ + +function buildApiUri() { + const ref = "jakob.space"; + const slug = /[^\/]*(?=\.html)/.exec(window.location.href); + const endpoints = [ + `http://${ref}/${slug}.html`, + `https://${ref}/${slug}.html`, + `http://${ref}/blog/${slug}.html`, + `https://${ref}/blog/${slug}.html`, + ]; + return ["https://webmention.io/api/mentions.jf2?per-page=200&page=0"].concat( + endpoints.map((endpoint) => { + return `target[]=${endpoint}`; + }).join("&") + ).join(""); +} + +function getData(url, callback) { + if (fetch) { + fetch(url).then(function(response) { + if (response.status >= 200 && response.status < 300) { + return Promise.resolve(response); + } else { + return Promise.reject(new Error(`Request failed: ${response.statusText}`)); + } + }).then(function(response) { + return response.json(); + }).then(callback); + } else { + let xhr = new XMLHttpRequest(); + xhr.onload = function(data) { + callback(JSON.parse(data)); + } + xhr.onerror = function(error) { + throw new Error(`Request failed: ${error}`); + } + } +} + +function makeComment(comment) { + const strip = (uri) => { + const sep = "://"; + return uri.substring(uri.indexOf(sep) + sep.length); + }; + + const element = (type, attributes) => { + let res = document.createElement(type); + for (const attribute in attributes) { + res.setAttribute(attribute, attributes[attribute]); + } + return res; + }; + + // Create the h-card section. + let avatar = element("img", { + "class": "u-photo", + "src": comment.url.startsWith("https://lobste.rs/") + ? "/static/image/lobsters.png" + : comment.author.photo || "/static/image/default-icon.png" + }); + + let authorName = element("a", { + "class": "p-name u-url", + "href": comment.author.url + }); + authorName.textContent = comment.author.name; + + let authorURI = element("a", { + "class": "author_url", + "href": comment.author.url + }); + authorURI.textContent = strip(comment.author.url); + + let hCardContainer = element("div", { + "class": "p-author h-card author" + }); + hCardContainer.appendChild(avatar); + hCardContainer.appendChild(authorName); + hCardContainer.appendChild(authorURI); + + // Create the content section. + let contentContainer = element("div", { + "class": "e-content p-name comment-content", + }); + + if (comment.hasOwnProperty("content")) { + contentContainer.textContent = comment.content.text; + } else { + let em = element("em", {}); + if (comment.hasOwnProperty("wm-property")) { + if ("repost-of" === comment["wm-property"]) { + em.textContent = "Reposted this!"; + } else if ("like-of" === comment["wm-property"]) { + em.textContent = "Favorited this!"; + } else { + em.textContent = "No text provided :("; + } + } else { + em.textContent = "No text provided :("; + } + contentContainer.appendChild(em); + } + + // Create the metaline section. + let pubTime = comment.published || comment["wm-received"]; + let time = element("time", { + "class": "dt-published", + "datetime": pubTime, + }); + time.textContent = (new Date(pubTime)).toString(); + + let linkBack = element("a", { + "class": "u-url", + "href": comment.url + }); + linkBack.appendChild(time); + + let metalineContainer = element("div", { + "class": "metaline" + }); + metalineContainer.appendChild(linkBack); + + let sourceIcon = document.createElement("img"); + sourceIcon.classList.add("comment-source-identifier") + sourceIcon.src = "/static/image/webmention-logo.png"; + + // Put it all together. + let wrapper = element("li", { + "class": "p-comment h-cite comment comment-source-webmention", + }); + wrapper.appendChild(sourceIcon); + wrapper.appendChild(hCardContainer); + wrapper.appendChild(contentContainer); + wrapper.appendChild(metalineContainer); + + return wrapper; +} + +function makeInteraction(ent) { + const strip = (uri) => { + const sep = "://"; + return uri.substring(uri.indexOf(sep) + sep.length); + }; + + const element = (type, attributes) => { + let res = document.createElement(type); + for (const attribute in attributes) { + res.setAttribute(attribute, attributes[attribute]); + } + return res; + }; + + // Create the h-card section. + let avatar = element("img", { + "class": "u-photo", + "src": ent.url.startsWith("https://lobste.rs/") + ? "/static/image/lobsters.png" + : ent.author.photo || "/static/image/default-icon.png" + }); + let avatarContainer = element("a", { + "href": ent.author.url + }); + avatarContainer.appendChild(avatar); + + // Create the content section. + let contentContainer = element("div", { + "class": "e-content p-name comment-content", + }); + let em = element("em", {}); + if ("repost-of" === ent["wm-property"]) { + em.textContent = "Reposted this!"; + } else if ("like-of" === ent["wm-property"]) { + em.textContent = "Favorited this!"; + } else { + return null; + } + contentContainer.appendChild(em); + + let sourceIcon = document.createElement("img"); + sourceIcon.classList.add("comment-source-identifier") + sourceIcon.src = "/static/image/webmention-logo.png"; + + // Put it all together. + let wrapper = element("li", { + "class": "p-comment h-cite interaction comment-source-webmention", + }); + wrapper.appendChild(avatarContainer); + wrapper.appendChild(contentContainer); + wrapper.appendChild(sourceIcon); + + return wrapper; +} + +function makeEntry(ent) { + if (ent.hasOwnProperty("wm-property")) { + if (ent.hasOwnProperty("content") && ent["wm-property"] !== "repost-of") { + return makeComment(ent); + } else { + return makeInteraction(ent); + } + } + return null; +} + +getData(buildApiUri(), (json) => { + json.children + .map(makeEntry) + .filter((x) => x !== null) + .forEach((elem) => { + document.getElementById("webmention-container").appendChild(elem); + })}); |