Implement metadata for articles and comments

This commit is contained in:
Tissevert 2019-03-02 23:44:09 +01:00
parent e9dad0fc3d
commit 2c6be28d76
7 changed files with 120 additions and 30 deletions

View File

@ -2,7 +2,9 @@ allLink = See all
allPage = All articles allPage = All articles
allTaggedPage = All articles tagged ${tag} allTaggedPage = All articles tagged ${tag}
commentsSection = Comments commentsSection = Comments
dateFormat = en-US
latestLink = See only latest latestLink = See only latest
latestPage = Latest articles latestPage = Latest articles
latestTaggedPage = Latest articles tagged ${tag} latestTaggedPage = Latest articles tagged ${tag}
metadata = ${?by ${author} ?}on ${date}${? tagged ${tags}?}
tagsList = Tags tagsList = Tags

View File

@ -8,9 +8,7 @@ function DomRenderer(modules) {
function replaceMarkdown() { function replaceMarkdown() {
var div = document.getElementById('contents'); var div = document.getElementById('contents');
if(div.children[0] && div.children[0].tagName.toLowerCase() == 'article') { if(div.children[0] && div.children[0].tagName.toLowerCase() == 'article') {
var re = new RegExp('/' + blog.path.articlesPath + '/([^.]+)\.html'); convertArticle(div.children[0], true);
var key = decodeURI(document.location.pathname.replace(re, '$1'));
convertArticle(div.children[0], key);
} else { } else {
var articles = div.getElementsByClassName('articles')[0]; var articles = div.getElementsByClassName('articles')[0];
if(articles != undefined) { if(articles != undefined) {
@ -23,13 +21,15 @@ function DomRenderer(modules) {
} }
} }
function convertArticle(article, key) { function convertArticle(article, comments) {
var header = article.getElementsByTagName('header')[0]; var header = article.getElementsByTagName('header')[0];
header.appendChild(modules.metadata.get(article.id));
var text = article.getElementsByTagName('pre')[0]; var text = article.getElementsByTagName('pre')[0];
if(text != undefined) { if(text != undefined) {
article.replaceChild(getDiv(text.innerText), text); article.replaceChild(getDiv(text.innerText), text);
if(key != undefined) { if(comments) {
modules.comments.get(key).forEach(article.appendChild.bind(article)); modules.metadata.getComments(article.id)
.forEach(article.appendChild.bind(article));
} }
} else { } else {
console.log('No content found for this article'); console.log('No content found for this article');
@ -58,16 +58,17 @@ function DomRenderer(modules) {
modules.dom.make('header', {}, [ modules.dom.make('header', {}, [
modules.dom.make('a', {href: url}, [ modules.dom.make('a', {href: url}, [
modules.dom.make('h1', {innerText: blog.articles[key].title}) modules.dom.make('h1', {innerText: blog.articles[key].title})
]) ]),
modules.metadata.get(key)
]), ]),
div div
].concat(limit != undefined ? [] : modules.comments.get(key))); ].concat(limit != undefined ? [] : modules.metadata.getComments(key)));
} }
function pageTitle(tag, all) { function pageTitle(tag, all) {
if(tag != undefined) { if(tag != undefined) {
var template = blog.wording[all ? 'allTaggedPage' : 'latestTaggedPage']; var template = all ? 'allTaggedPage' : 'latestTaggedPage';
return template.replace(/([^$]|^)\$(?:{tag}|tag([^a-zA-Z]|$))/, '$1' + tag + '$2'); return modules.template.render(template, {tag: tag});
} else { } else {
return blog.wording[all ? 'allPage' : 'latestPage']; return blog.wording[all ? 'allPage' : 'latestPage'];
} }

View File

@ -5,9 +5,10 @@ window.addEventListener('load', function() {
var fun = unitJS.Fun(); var fun = unitJS.Fun();
var md = new Remarkable(remarkableConfig); var md = new Remarkable(remarkableConfig);
md.block.ruler.enable(['footnote']); md.block.ruler.enable(['footnote']);
var comments = Comments({async: async, cache: cache, dom: dom}); var template = Template();
var domRenderer = DomRenderer({comments: comments, fun: fun, md: md, dom: dom}); var metadata = Metadata({async: async, cache: cache, dom: dom, fun:fun, template: template});
var navigation = Navigation({async: async, cache: cache, fun: fun, md: md, dom: dom, domRenderer: domRenderer}); var domRenderer = DomRenderer({dom: dom, fun: fun, md: md, metadata: metadata, template: template});
var navigation = Navigation({async: async, cache: cache, dom: dom, domRenderer: domRenderer, fun: fun, md: md});
domRenderer.replaceMarkdown(); domRenderer.replaceMarkdown();
navigation.hijackLinks(); navigation.hijackLinks();
}); });

View File

@ -1,4 +1,4 @@
function Comments(modules) { function Metadata(modules) {
var comments = modules.cache.make(function(threadId) { var comments = modules.cache.make(function(threadId) {
return modules.async.bind( return modules.async.bind(
modules.async.http({method: 'GET', url: url(threadId)}), modules.async.http({method: 'GET', url: url(threadId)}),
@ -16,14 +16,15 @@ function Comments(modules) {
); );
}) })
return { return {
get: get get: get,
getComments: getComments
}; };
function url(threadId) { function url(threadId) {
return blog.path.commentsAt + '/api/v1/statuses/' + threadId + '/context'; return blog.path.commentsAt + '/api/v1/statuses/' + threadId + '/context';
} }
function get(articleKey) { function getComments(articleKey) {
var threadId = blog.articles[articleKey].metadata.comments; var threadId = blog.articles[articleKey].metadata.comments;
if(blog.path.commentsAt != undefined && threadId != undefined) { if(blog.path.commentsAt != undefined && threadId != undefined) {
var ul = modules.dom.make('ul'); var ul = modules.dom.make('ul');
@ -55,15 +56,58 @@ function Comments(modules) {
function render(comments) { function render(comments) {
return comments.descendants.map(function(descendant) { return comments.descendants.map(function(descendant) {
return modules.dom.make('li', {}, [ return modules.dom.make('li', {}, [
modules.dom.make('cite', {}, [ modules.dom.make('div', {
modules.dom.make('a', { innerHTML: modules.template.render('metadata', {
href: descendant.account.url, author: author(descendant.account.url, descendant.account.username),
innerText: descendant.account.username date: date(descendant.created_at)
}), })
modules.dom.make('p', {innerText: descendant.created_at}), }),
modules.dom.make('div', {innerHTML: descendant.content}) modules.dom.make('div', {innerHTML: descendant.content})
])
]); ]);
}); });
} }
function author(key, name) {
var authorUrl = key;
if(blog.articles[key] != undefined) {
authorUrl = blog.articles[key].metadata.author;
}
if(authorUrl) {
var author = name || authorUrl.replace(/.*\//, '');
return '<a href="' + authorUrl + '">' + author + '</a>';
}
}
function date(key) {
if(blog.articles[key] != undefined) {
var date = new Date(blog.articles[key].metadata.date * 1000);
} else {
var date = new Date(key);
}
var format = blog.wording.dateFormat;
if(format[0] != '[') {
if(format[0] != '"') {
format = '"' + format + '"';
}
format = '[' + format + ']';
}
return Date.prototype.toLocaleDateString.apply(date, JSON.parse(format));
}
function tags(key) {
var tags = blog.articles[key].tagged;
return tags.length < 1 ? null : tags.map(function(tag) {
return '<a class="tag" href="/' + tag + '">' + tag + '</a>';
}).join(', ');
}
function get(key) {
return modules.dom.make('div', {
innerHTML: modules.template.render('metadata', {
author: author(key),
date: date(key),
tags: tags(key)
})
});
}
} }

35
share/js/template.js Normal file
View File

@ -0,0 +1,35 @@
function Template() {
return {
render: render
};
function render(template, environment) {
if(blog.wording[template] != undefined) {
var template = blog.wording[template];
}
template = template.replace(/\${\?((?:[^?]|\?[^}])*)\?}/g, renderSub(environment));
var failed = [false];
var result = template.replace(
/([^$]|^)\$(?:{(\w+)}|(\w+)\b)/g,
substitute(environment, failed)
);
return failed[0] ? null : result;
}
function renderSub(environment) {
return function(_, sub) {
return render(sub, environment) || '';
};
}
function substitute(environment, failed) {
return function(_, before, bracketed, raw) {
var replaced = environment[bracketed || raw];
if(replaced != undefined) {
return before + replaced;
} else {
failed[0] = true;
}
}
}
}

View File

@ -28,22 +28,25 @@ data Wording = Wording {
, allPage :: Text , allPage :: Text
, allTaggedPage :: Template , allTaggedPage :: Template
, commentsSection :: Text , commentsSection :: Text
, dateFormat :: Text
, latestLink :: Text , latestLink :: Text
, latestPage :: Text , latestPage :: Text
, latestTaggedPage :: Template , latestTaggedPage :: Template
, metadata :: Text
, tagsList :: Text , tagsList :: Text
} }
keys :: [String] keys :: [String]
keys = [ keys = [
"allLink", "allPage", "allTaggedPage", "commentsSection" "allLink", "allPage", "allTaggedPage", "commentsSection", "dateFormat"
, "latestLink", "latestPage", "latestTaggedPage", "tagsList" , "latestLink", "latestPage", "latestTaggedPage", "metadata", "tagsList"
] ]
values :: [Wording -> Text] values :: [Wording -> Text]
values = [ values = [
allLink, allPage, showTemplate . allTaggedPage, commentsSection allLink, allPage, showTemplate . allTaggedPage, commentsSection
, latestLink, latestPage, showTemplate . latestTaggedPage, tagsList , dateFormat, latestLink, latestPage, showTemplate . latestTaggedPage
, metadata, tagsList
] ]
texts :: Wording -> [Text] texts :: Wording -> [Text]
@ -97,8 +100,10 @@ build arguments = do
, allPage = wording ! "allPage" , allPage = wording ! "allPage"
, allTaggedPage , allTaggedPage
, commentsSection = wording ! "commentsSection" , commentsSection = wording ! "commentsSection"
, dateFormat = wording ! "dateFormat"
, latestLink = wording ! "latestLink" , latestLink = wording ! "latestLink"
, latestPage = wording ! "latestPage" , latestPage = wording ! "latestPage"
, latestTaggedPage , latestTaggedPage
, metadata = wording ! "metadata"
, tagsList = wording ! "tagsList" , tagsList = wording ! "tagsList"
} }

View File

@ -28,7 +28,7 @@ class Page a where
content :: a -> HtmlGenerator () content :: a -> HtmlGenerator ()
instance Page Article where instance Page Article where
card (Article {title, metadata}) = do card (Article {title, Article.metadata}) = do
description <- getDescription (Map.lookup "summary" metadata) description <- getDescription (Map.lookup "summary" metadata)
makeCard title (pack description) (Map.lookup "featuredImage" metadata) makeCard title (pack description) (Map.lookup "featuredImage" metadata)
where where
@ -57,7 +57,7 @@ instance Page ArticlesList where
article :: Bool -> Article -> HtmlGenerator () article :: Bool -> Article -> HtmlGenerator ()
article raw (Article {key, body, title}) = do article raw (Article {key, body, title}) = do
url <- absoluteLink . (</> key <.> extension) <$> (Blog.get $path.$articlesPath) url <- absoluteLink . (</> key <.> extension) <$> (Blog.get $path.$articlesPath)
article_ (do article_ [id_ $ pack key] (do
header_ (do header_ (do
a_ [href_ . pack $ url] . h1_ $ toHtml title a_ [href_ . pack $ url] . h1_ $ toHtml title
) )
@ -76,7 +76,9 @@ makeCard title description image = do
maybeImage = maybe (return ()) (og "image" . pack) maybeImage = maybe (return ()) (og "image" . pack)
tag :: String -> HtmlGenerator () tag :: String -> HtmlGenerator ()
tag tagName = li_ (a_ [href_ . pack $ absoluteLink tagName] $ toHtml tagName) tag tagName = li_ (
a_ [href_ . pack $ absoluteLink tagName, class_ "tag"] $ toHtml tagName
)
defaultBanner :: HtmlGenerator () defaultBanner :: HtmlGenerator ()
defaultBanner = do defaultBanner = do