diff --git a/share/defaultWording.conf b/share/defaultWording.conf index 21b431b..430e168 100644 --- a/share/defaultWording.conf +++ b/share/defaultWording.conf @@ -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 diff --git a/share/js/DomRenderer.js b/share/js/DomRenderer.js index e9f9727..8b07ea6 100644 --- a/share/js/DomRenderer.js +++ b/share/js/DomRenderer.js @@ -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) { diff --git a/share/js/Navigation.js b/share/js/Navigation.js index 8309249..61bd13b 100644 --- a/share/js/Navigation.js +++ b/share/js/Navigation.js @@ -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) ); } ); diff --git a/src/Blog/Wording.hs b/src/Blog/Wording.hs index e393db8..6d5e7a2 100644 --- a/src/Blog/Wording.hs +++ b/src/Blog/Wording.hs @@ -32,6 +32,7 @@ variables = Map.fromList [ , ("latestLink", []) , ("latestPage", ["tag"]) , ("metadata", ["author", "date", "tags"]) + , ("pagesList", []) , ("rssLink", []) , ("rssTitle", ["tag"]) , ("tagsList", []) diff --git a/src/DOM.hs b/src/DOM.hs index b38d31b..a15f723 100644 --- a/src/DOM.hs +++ b/src/DOM.hs @@ -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 ) ) diff --git a/test/Mock/Blog/Wording.hs b/test/Mock/Blog/Wording.hs index 175763a..456b1d6 100644 --- a/test/Mock/Blog/Wording.hs +++ b/test/Mock/Blog/Wording.hs @@ -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")