Add links to static pages and handle dynamic navigation on the JS side

This commit is contained in:
Tissevert 2020-06-20 22:59:39 +02:00
parent 937a6858e0
commit 47f5c70e21
6 changed files with 74 additions and 38 deletions

View File

@ -6,6 +6,7 @@ dateFormat = en-US
latestLink = See only latest
latestPage = Latest articles{? tagged ${tag}?}
metadata = {?by ${author} ?}on ${date}{? tagged ${tags}?}
pagesList = Pages
rssLink = Subscribe
rssTitle = Follow all articles{? tagged ${tag}?}
tagsList = Tags

View File

@ -6,20 +6,21 @@ import * as Dom from UnitJS.Dom;
import {defined} from UnitJS.Fun;
return {
article: article,
articlesList: articlesList,
render: render,
replaceMarkdown: replaceMarkdown
};
function replaceMarkdown() {
var div = document.getElementById('contents');
if(div.children[0] && div.children[0].tagName.toLowerCase() == 'article') {
convertArticle(div.children[0], true);
var contentType = window.location.pathname.slice(1).replace(/\/.*/, '');
convertContent(contentType, div.children[0], true);
} else {
var articles = div.getElementsByClassName('articles')[0];
if(articles != undefined) {
for(var i = 0; i < articles.children.length; i++) {
convertArticle(articles.children[i]);
convertContent('article', articles.children[i]);
}
} else {
console.log('No articles found for this page');
@ -27,13 +28,15 @@ function replaceMarkdown() {
}
}
function convertArticle(article, comments) {
function convertContent(contentType, article, comments) {
var header = article.getElementsByTagName('header')[0];
header.appendChild(Metadata.get(article.id));
if(contentType == 'article') {
header.appendChild(Metadata.get(article.id));
}
var text = article.getElementsByTagName('pre')[0];
if(text != undefined) {
article.replaceChild(getDiv(text.innerText), text);
if(comments) {
if(contentType == 'article' && comments) {
Metadata.getComments(article.id)
.forEach(article.appendChild.bind(article));
}
@ -56,19 +59,33 @@ function getDiv(markdown) {
return d;
}
function article(key, markdown, limit) {
var url = ["", blog.path.articlesPath, key + (limit != undefined ? '.html' : '.md')].join('/');
var lines = markdown.split(/\n/).slice(blog.articles[key].bodyOffset);
function contentUrl(contentType, key, limit) {
var directory = blog.path[contentType + 'sPath'];
var extension = limit != undefined ? '.html' : '.md';
return ["", directory, key + extension].join('/');
}
function commentsSection(contentType, key, limit) {
if(contentType != 'article' || limit != undefined) {
return [];
} else {
return Metadata.getComments(key);
}
}
function render(contentType, key, markdown, limit) {
var url = contentUrl(contentType, key, limit);
var resource = blog[contentType + 's'][key];
var lines = markdown.split(/\n/).slice(resource.bodyOffset);
var div = getDiv(lines.slice(0, limit).join('\n'));
return Dom.make('article', {}, [
Dom.make('header', {}, [
Dom.make('a', {href: url}, [
Dom.make('h1', {innerText: blog.articles[key].title})
]),
Metadata.get(key)
]),
Dom.make('h1', {}, [
Dom.make('a', {href: url, innerText: resource.title})
])].concat(contentType == 'article' ? Metadata.get(key) : [])
),
div
].concat(limit != undefined ? [] : Metadata.getComments(key)));
].concat(commentsSection(contentType, key, limit)));
}
function pageTitle(tag, all) {

View File

@ -1,25 +1,29 @@
import {article, articlesList} from DomRenderer;
import {articlesList, render} from DomRenderer;
import blog from Hablo.Config;
import * as Async from UnitJS.Async;
import * as Cache from UnitJS.Cache;
import * as Dom from UnitJS.Dom;
import * as Fun from UnitJS.Fun;
var articles = Cache.make(function(key) {
var url = ["", blog.path.articlesPath, key + '.md'].join('/');
return Async.bind(
Async.http({method: 'GET', url: url}),
function(queryResult) {
if(queryResult.status == 200) {
return Async.wrap(queryResult.responseText);
} else {
return Async.fail(
"Could not load article " + url + " (" + queryResult.status + " " + queryResult.statusText + ")"
);
var cache = {};
['article', 'page'].forEach(function(contentType) {
cache[contentType] = Cache.make(function(key) {
var url = ["", blog.path[contentType + 'sPath'], key + '.md'].join('/');
return Async.bind(
Async.http({method: 'GET', url: url}),
function(queryResult) {
if(queryResult.status == 200) {
return Async.wrap(queryResult.responseText);
} else {
return Async.fail(
"Could not load " + contentType + " " + url + " (" + queryResult.status + " " + queryResult.statusText + ")"
);
}
}
}
);
);
});
});
window.addEventListener('popstate', function(e) {
if(e.state != undefined) {
navigate(e.state.url);
@ -60,27 +64,29 @@ function navigate(url) {
if(blog.tags[path[0]] != undefined) {
show(getArticlesList(path[0], path[1] == "all.html"));
} else if(path[0] == blog.path.articlesPath) {
show(getArticle(path[1].replace(/\.html$/, '')));
show(getResource('article', path[1].replace(/\.html$/, '')));
} else if(path[0] == blog.path.pagesPath) {
show(getResource('page', path[1].replace(/\.html$/, '')));
} else {
show(getArticlesList(null, path[0] == "all.html"));
}
}
function getArticle(key) {
function getResource(contentType, key) {
return Async.bind(
articles.get(key),
cache[contentType].get(key),
Async.map(
function(contents) {return [article(key, contents)];}
function(contents) {return [render(contentType, key, contents)];}
)
);
}
function preview(key) {
return Async.bind(
articles.get(key),
cache.article.get(key),
function(contents) {
return Async.wrap(
article(key, contents, blog.skin.previewLinesCount)
render('article', key, contents, blog.skin.previewLinesCount)
);
}
);

View File

@ -32,6 +32,7 @@ variables = Map.fromList [
, ("latestLink", [])
, ("latestPage", ["tag"])
, ("metadata", ["author", "date", "tags"])
, ("pagesList", [])
, ("rssLink", [])
, ("rssTitle", ["tag"])
, ("tagsList", [])

View File

@ -12,7 +12,7 @@ import ArticlesList (
)
import Blog (Blog(..), Skin(..), URL(..), template)
import Control.Monad.Reader (ReaderT, asks)
import qualified Data.Map as Map (keys)
import qualified Data.Map as Map (elems, keys)
import Data.Text (pack, empty)
import DOM.Card (HasCard)
import qualified DOM.Card as Card (make)
@ -63,12 +63,18 @@ markdown raw (Markdown {key, Markdown.path, body, title}) =
let url = absoluteLink $ path <.> extension in
article_ [id_ $ pack key] (do
header_ (do
a_ [href_ $ pack url] . h1_ $ toHtml title
h1_ . a_ [href_ $ pack url] $ toHtml title
)
pre_ . toHtml $ unlines body
)
where extension = if raw then "md" else "html"
mDLink :: MarkdownContent a => Bool -> a -> HtmlGenerator ()
mDLink raw a = a_ [href_ $ pack url] $ toHtml title
where
Markdown {Markdown.path, title} = getMarkdown a
url = absoluteLink $ path <.> (if raw then "md" else "html")
tag :: String -> HtmlGenerator ()
tag name = li_ (
a_ [href_ . pack $ absoluteLink name ++ "/", class_ "tag"] $ toHtml name
@ -104,10 +110,14 @@ htmlDocument someContent =
)
body_ (do
maybe defaultBanner toHtmlRaw =<< (asks $skin.$banner)
div_ [id_ "navigator"] (do
div_ [id_ "tags"] (do
h2_ . toHtml =<< template "tagsList" []
ul_ . mapM_ tag . Map.keys =<< asks tags
)
div_ [id_ "pages"] (do
h2_ . toHtml =<< template "pagesList" []
ul_ . mapM_ (mDLink False) . Map.elems =<< asks pages
)
div_ [id_ "contents"] $ content someContent
)
)

View File

@ -16,6 +16,7 @@ defaultWording = Wording $ Map.fromList [
, ("latestLink", "See only latest")
, ("latestPage", "Latest articles{? tagged ${tag}?}")
, ("metadata", "{?by ${author} ?}on ${date}{? tagged ${tags}?}")
, ("pagesList", "Pages")
, ("rssLink", "Subscribe")
, ("rssTitle", "Follow all articles{? tagged ${tag}?}")
, ("tagsList", "Tags")