Add links to static pages and handle dynamic navigation on the JS side
This commit is contained in:
parent
937a6858e0
commit
47f5c70e21
6 changed files with 74 additions and 38 deletions
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -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", [])
|
||||||
|
|
16
src/DOM.hs
16
src/DOM.hs
|
@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in a new issue