diff options
| author | Jakob L. Kreuze | 2019-07-20 17:07:39 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze | 2019-07-20 17:07:39 -0400 |
| commit | b4fdc3017b9c05734b92151d7aa2e0353682fc09 (patch) | |
| tree | a056a6a6e379bcae01b22c6dca203218c609cac3 /haunt/static | |
| parent | aed8c20a9488f1ed4f4e316068cbafb07e8676ff (diff) | |
Stage everything. Bleh, I'll commit to a clean history from now on
Diffstat (limited to 'haunt/static')
| -rw-r--r-- | haunt/static/css/style.css | 43 | ||||
| -rw-r--r-- | haunt/static/image/profile-picture.jpg | bin | 0 -> 69228 bytes | |||
| -rw-r--r-- | haunt/static/js/webmention.js | 140 |
3 files changed, 182 insertions, 1 deletions
diff --git a/haunt/static/css/style.css b/haunt/static/css/style.css index ef354f9..02001ec 100644 --- a/haunt/static/css/style.css +++ b/haunt/static/css/style.css @@ -101,7 +101,7 @@ body > header > nav > ul { /* Links. */ -a:link, a:visited { color:#0000EE; } +a:link, a:visited { color: #00E; text-decoration: none; } /* Figures */ @@ -138,6 +138,47 @@ figure > figcaption { display: inline; } +/* Webmention. */ + +#webmention { + border-top: 2px solid #d2d6dd; +} + +ul#webmention-container { + list-style-type: none; +} + +div.h-entry, ul#webmention-container li { + border: 2px solid #d2d6dd; + padding: 1rem; +} + +img.u-photo { + width: 4rem; + padding: 0 1rem 1rem 0; + float: left; +} + +div.p-author * { + padding-right: 1rem; +} + +/* Webmention form. */ + +form { + border-top: 2px solid #d2d6dd; + padding-top: 1rem; +} + +form input { + margin-top: 1rem; +} + +form input[type=url] { + display: block; + width: 100%; +} + /* Source code. */ pre { diff --git a/haunt/static/image/profile-picture.jpg b/haunt/static/image/profile-picture.jpg Binary files differnew file mode 100644 index 0000000..cd2e07e --- /dev/null +++ b/haunt/static/image/profile-picture.jpg diff --git a/haunt/static/js/webmention.js b/haunt/static/js/webmention.js new file mode 100644 index 0000000..d1bb8e8 --- /dev/null +++ b/haunt/static/js/webmention.js @@ -0,0 +1,140 @@ +/* + * webmention.js -- Fetch and display mentions from webmention.io. + * Copyright © 2019 Jakob L. Kreuze <zerodaysfordays@sdf.lonestar.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 snip = /https?:\/\/.*?\//.exec(window.location.href); + const page = window.location.href.substring(snip[0].length); + + // TODO: Build up from aliases, etc. + const aliases = [page]; + + return Array.concat( + ["https://webmention.io/api/mentions.jf2?"], + aliases.flatMap((alias) => { + const ref = "jakob.space"; + return [ + `target[]=http://${ref}/${alias}`, + `target[]=https://${ref}/${alias}` + ]; + }).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.author.photo + }); + + 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", + }); + contentContainer.textContent = comment.content.text; + + // Create the metaline section. + let time = element("time", { + "class": "dt-published", + "datetime": comment.published + }); + time.textContent = (new Date(comment.published)).toString(); + + let linkBack = element("a", { + "class": "u-url", + "href": comment.url + }); + linkBack.appendChild(time); + + let metalineContainer = element("div", { + "class": "metaline" + }); + metalineContainer.appendChild(linkBack); + + // Put it all together. + let wrapper = element("li", { + "class": "p-comment h-cite comment", + }); + wrapper.appendChild(hCardContainer); + wrapper.appendChild(contentContainer); + wrapper.appendChild(metalineContainer); + + return wrapper; +} + +getData(buildApiUri(), (json) => { + json.children + .map(makeComment) + .forEach((elem) => { + document.getElementById("webmention-container").appendChild(elem); + })}); |