Implement comments activated by the presence of a 'comments:' field in the article's metadata

This commit is contained in:
Tissevert 2019-02-16 08:13:14 +01:00
parent 9d2411ef61
commit 6c3f31ea6c
6 changed files with 84 additions and 4 deletions

69
js/comments.js Normal file
View file

@ -0,0 +1,69 @@
function Comments(modules) {
var comments = modules.cache.make(function(threadId) {
return modules.async.bind(
modules.async.http({method: 'GET', url: url(threadId)}),
function(queryResult) {
if(queryResult.status == 200) {
try {
return modules.async.wrap(render(JSON.parse(queryResult.responseText)));
} catch(e) {
return modules.async.fail('Server returned invalid JSON for ' + url);
}
} else {
return modules.async.fail('Could not load comments at ' + url);
}
}
);
})
return {
get: get
};
function url(threadId) {
return blog.path.commentsAt + '/api/v1/statuses/' + threadId + '/context';
}
function get(articleKey) {
var threadId = blog.articles[articleKey].metadata.comments;
if(blog.path.commentsAt != undefined && threadId != undefined) {
var ul = modules.dom.make('ul');
modules.async.run(
modules.async.bind(
comments.get(threadId),
modules.async.map(function(comments) {
comments.forEach(function(comment) {ul.appendChild(comment);});
})
)
);
return emptySection(ul, threadId);
} else {
return [];
}
}
function emptySection(ul, threadId) {
return [modules.dom.make('div', {class: 'comments'}, [
modules.dom.make('h2', {innerText: 'Comments'}),
ul,
modules.dom.make('a', {
href: blog.path.commentsAt + '/notice/' + threadId,
innerText: 'Comment on the fediverse'
})
])];
}
function render(comments) {
return comments.descendants.map(function(descendant) {
return modules.dom.make('li', {}, [
modules.dom.make('cite', {}, [
modules.dom.make('a', {
href: descendant.account.url,
innerText: descendant.account.username
}),
modules.dom.make('p', {innerText: descendant.created_at}),
modules.dom.make('div', {innerHTML: descendant.content})
])
]);
});
}
}

View file

@ -8,7 +8,8 @@ function DomRenderer(modules) {
function replaceMarkdown() {
var div = document.getElementById('contents');
if(div.children[0] && div.children[0].tagName.toLowerCase() == 'article') {
convertArticle(div.children[0]);
var re = new RegExp('/' + blog.path.articlesPath + '/([^.]+)\.html');
convertArticle(div.children[0], document.location.pathname.replace(re, '$1'));
} else {
var articles = div.getElementsByClassName('articles')[0];
if(articles != undefined) {
@ -21,11 +22,14 @@ function DomRenderer(modules) {
}
}
function convertArticle(article) {
function convertArticle(article, key) {
var header = article.getElementsByTagName('header')[0];
var text = article.getElementsByTagName('pre')[0];
if(text != undefined) {
article.replaceChild(getDiv(text.innerText), text);
if(key != undefined) {
article.appendChild(modules.comments.get(key)[0]);
}
} else {
console.log('No content found for this article');
}
@ -56,7 +60,7 @@ function DomRenderer(modules) {
])
]),
div
]);
].concat(limit != undefined ? [] : modules.comments.get(key)));
}
function pageTitle(tag, all) {

View file

@ -5,7 +5,8 @@ window.addEventListener('load', function() {
var fun = unitJS.Fun();
var md = new Remarkable({html: true});
md.block.ruler.enable(['footnote']);
var domRenderer = DomRenderer({fun: fun, md: md, dom: dom});
var comments = Comments({async: async, cache: cache, dom: dom});
var domRenderer = DomRenderer({comments: comments, fun: fun, md: md, dom: dom});
var navigation = Navigation({async: async, cache: cache, fun: fun, md: md, dom: dom, domRenderer: domRenderer});
domRenderer.replaceMarkdown();
navigation.hijackLinks();

View file

@ -18,6 +18,7 @@ data Arguments = BlogConfig {
, articlesPath :: FilePath
, bannerPath :: Maybe FilePath
, cardImage :: Maybe FilePath
, commentsAt :: Maybe String
, favicon :: Maybe FilePath
, headPath :: Maybe FilePath
, name :: Maybe String
@ -49,6 +50,7 @@ blogConfig = BlogConfig
)
<*> option filePath 'b' "banner" "BANNER_PATH" "path to the file to use for the blog's banner"
<*> option filePath 'c' "card-image" "CARD_IMAGE" "path to the image to use for the blog's card"
<*> option filePath 'C' "comments-at" "INSTANCE_URL" "url of the instance where comments are stored"
<*> option filePath 'f' "favicon" "FAVICON" "path to the image to use for the blog's favicon"
<*> option filePath 'H' "head" "HEAD_PATH" "path to the file to add in the blog's head"
<*> option str 'n' "name" "BLOG_NAME" "name of the blog"

View file

@ -8,6 +8,7 @@ import qualified Arguments as Arguments (Arguments(..))
data Path = Path {
articlesPath :: FilePath
, commentsAt :: Maybe String
, pagesPath :: Maybe FilePath
, root :: FilePath
}
@ -15,6 +16,7 @@ data Path = Path {
build :: Arguments -> Path
build arguments = Path {
articlesPath = Arguments.articlesPath arguments
, commentsAt = Arguments.commentsAt arguments
, pagesPath = Arguments.pagesPath arguments
, root = Arguments.sourceDir arguments
}

View file

@ -28,6 +28,7 @@ instance ToJSON ArticleExport where
data PathExport = PathExport {
articlesPath :: FilePath
, commentsAt :: Maybe String
, pagesPath :: Maybe FilePath
} deriving (Generic)
@ -67,6 +68,7 @@ exportBlog = do
articles = mapWithKey (export blog) $ Blog.articles blog
, path = PathExport {
articlesPath = Blog.articlesPath $ Blog.path blog
, commentsAt = Blog.commentsAt $ Blog.path blog
, pagesPath = Blog.pagesPath $ Blog.path blog
}
, skin = SkinExport {