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 latestLink = See only latest
latestPage = Latest articles{? tagged ${tag}?} latestPage = Latest articles{? tagged ${tag}?}
metadata = {?by ${author} ?}on ${date}{? tagged ${tags}?} metadata = {?by ${author} ?}on ${date}{? tagged ${tags}?}
pagesList = Pages
rssLink = Subscribe rssLink = Subscribe
rssTitle = Follow all articles{? tagged ${tag}?} rssTitle = Follow all articles{? tagged ${tag}?}
tagsList = Tags tagsList = Tags

View file

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

View file

@ -1,12 +1,14 @@
import {article, articlesList} from DomRenderer; import {articlesList, render} from DomRenderer;
import blog from Hablo.Config; import blog from Hablo.Config;
import * as Async from UnitJS.Async; import * as Async from UnitJS.Async;
import * as Cache from UnitJS.Cache; import * as Cache from UnitJS.Cache;
import * as Dom from UnitJS.Dom; import * as Dom from UnitJS.Dom;
import * as Fun from UnitJS.Fun; import * as Fun from UnitJS.Fun;
var articles = Cache.make(function(key) { var cache = {};
var url = ["", blog.path.articlesPath, key + '.md'].join('/'); ['article', 'page'].forEach(function(contentType) {
cache[contentType] = Cache.make(function(key) {
var url = ["", blog.path[contentType + 'sPath'], key + '.md'].join('/');
return Async.bind( return Async.bind(
Async.http({method: 'GET', url: url}), Async.http({method: 'GET', url: url}),
function(queryResult) { function(queryResult) {
@ -14,12 +16,14 @@ var articles = Cache.make(function(key) {
return Async.wrap(queryResult.responseText); return Async.wrap(queryResult.responseText);
} else { } else {
return Async.fail( return Async.fail(
"Could not load article " + url + " (" + queryResult.status + " " + queryResult.statusText + ")" "Could not load " + contentType + " " + url + " (" + queryResult.status + " " + queryResult.statusText + ")"
); );
} }
} }
); );
}); });
});
window.addEventListener('popstate', function(e) { window.addEventListener('popstate', function(e) {
if(e.state != undefined) { if(e.state != undefined) {
navigate(e.state.url); navigate(e.state.url);
@ -60,27 +64,29 @@ function navigate(url) {
if(blog.tags[path[0]] != undefined) { if(blog.tags[path[0]] != undefined) {
show(getArticlesList(path[0], path[1] == "all.html")); show(getArticlesList(path[0], path[1] == "all.html"));
} else if(path[0] == blog.path.articlesPath) { } 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 { } else {
show(getArticlesList(null, path[0] == "all.html")); show(getArticlesList(null, path[0] == "all.html"));
} }
} }
function getArticle(key) { function getResource(contentType, key) {
return Async.bind( return Async.bind(
articles.get(key), cache[contentType].get(key),
Async.map( Async.map(
function(contents) {return [article(key, contents)];} function(contents) {return [render(contentType, key, contents)];}
) )
); );
} }
function preview(key) { function preview(key) {
return Async.bind( return Async.bind(
articles.get(key), cache.article.get(key),
function(contents) { function(contents) {
return Async.wrap( 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", []) , ("latestLink", [])
, ("latestPage", ["tag"]) , ("latestPage", ["tag"])
, ("metadata", ["author", "date", "tags"]) , ("metadata", ["author", "date", "tags"])
, ("pagesList", [])
, ("rssLink", []) , ("rssLink", [])
, ("rssTitle", ["tag"]) , ("rssTitle", ["tag"])
, ("tagsList", []) , ("tagsList", [])

View file

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

View file

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