Remove dreadful absoluteLink, fix image URL + at-root-only blogs, test URL generation
This commit is contained in:
parent
75252dc236
commit
f229a17bbb
13 changed files with 179 additions and 88 deletions
|
@ -96,6 +96,7 @@ test-suite tests
|
||||||
, Mock.Markdown
|
, Mock.Markdown
|
||||||
, Mock.URL
|
, Mock.URL
|
||||||
, Structure
|
, Structure
|
||||||
|
, URLs
|
||||||
, Utils
|
, Utils
|
||||||
, XML.Card
|
, XML.Card
|
||||||
, XML.Card.Component
|
, XML.Card.Component
|
||||||
|
|
|
@ -15,9 +15,7 @@ import Blog (Blog(..), Renderer, Skin(..), template)
|
||||||
import Collection (Collection(..))
|
import Collection (Collection(..))
|
||||||
import Control.Monad.Reader (MonadReader, asks)
|
import Control.Monad.Reader (MonadReader, asks)
|
||||||
import Data.Text (Text, pack)
|
import Data.Text (Text, pack)
|
||||||
import Files (absoluteLink)
|
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
import System.FilePath.Posix ((</>))
|
|
||||||
|
|
||||||
data ArticlesList = ArticlesList {
|
data ArticlesList = ArticlesList {
|
||||||
full :: Bool
|
full :: Bool
|
||||||
|
@ -29,9 +27,8 @@ getArticles (ArticlesList {full, collection = Collection {featured}}) = do
|
||||||
limit <- take <$> (asks $skin.$previewArticlesCount)
|
limit <- take <$> (asks $skin.$previewArticlesCount)
|
||||||
return $ if full then featured else limit featured
|
return $ if full then featured else limit featured
|
||||||
|
|
||||||
otherURL :: ArticlesList -> String
|
otherURL :: ArticlesList -> FilePath
|
||||||
otherURL al@(ArticlesList {full}) = absoluteLink $
|
otherURL (ArticlesList {full}) = if full then "." else "all.html"
|
||||||
(if full then id else (</> "all.html")) $ ArticlesList.path al
|
|
||||||
|
|
||||||
description :: Renderer m => ArticlesList -> m Text
|
description :: Renderer m => ArticlesList -> m Text
|
||||||
description (ArticlesList {full, collection}) =
|
description (ArticlesList {full, collection}) =
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
module Blog.URL (
|
module Blog.URL (
|
||||||
AbsoluteURL(..)
|
AbsoluteURL(..)
|
||||||
, URLs(..)
|
, URLs(..)
|
||||||
, (./)
|
|
||||||
, (/?)
|
|
||||||
, build
|
, build
|
||||||
, checkURL
|
, checkURL
|
||||||
|
, defaultOn
|
||||||
|
, localPrefix
|
||||||
|
, pathOn
|
||||||
, pathRelative
|
, pathRelative
|
||||||
, toText
|
, toText
|
||||||
) where
|
) where
|
||||||
|
@ -93,14 +94,20 @@ addParams url newParams = url {
|
||||||
urlParams = unionBy ((==) `on` fst) newParams (urlParams url)
|
urlParams = unionBy ((==) `on` fst) newParams (urlParams url)
|
||||||
}
|
}
|
||||||
|
|
||||||
(./) :: AbsoluteURL -> FilePath -> Text
|
pathOn :: AbsoluteURL -> FilePath -> Text
|
||||||
(./) url = toText . setPath
|
pathOn url = toText . setPath
|
||||||
where setPath ('/':urlPath) = url {urlPath}
|
where setPath ('/':urlPath) = url {urlPath}
|
||||||
setPath subPath = url {urlPath = urlPath url </> subPath}
|
setPath subPath = url {urlPath = urlPath url </> subPath}
|
||||||
|
|
||||||
(/?) :: AbsoluteURL -> URL -> Text
|
defaultOn :: AbsoluteURL -> URL -> Text
|
||||||
(/?) _ (URL {url_type = Absolute host, url_path, url_params}) =
|
defaultOn _ (URL {url_type = Absolute host, url_path, url_params}) =
|
||||||
toText $ AbsoluteURL host url_path url_params
|
toText $ AbsoluteURL host url_path url_params
|
||||||
(/?) url (URL {url_type = HostRelative, url_path, url_params}) =
|
defaultOn url (URL {url_type = HostRelative, url_path, url_params}) =
|
||||||
toText $ addParams (url {urlPath = url_path}) url_params
|
toText $ addParams (url {urlPath = url_path}) url_params
|
||||||
(/?) url (URL {url_path, url_params}) = (addParams url url_params) ./ url_path
|
defaultOn url (URL {url_path, url_params}) =
|
||||||
|
pathOn (addParams url url_params) url_path
|
||||||
|
|
||||||
|
localPrefix :: FilePath -> URL -> Text
|
||||||
|
localPrefix base url = pack . prefix (url_type url) $ exportURL url
|
||||||
|
where prefix PathRelative = (base </>)
|
||||||
|
prefix _ = id
|
||||||
|
|
81
src/DOM.hs
81
src/DOM.hs
|
@ -1,7 +1,7 @@
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module DOM (
|
module DOM (
|
||||||
HasContent(..)
|
PageType(..)
|
||||||
, htmlDocument
|
, htmlDocument
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
@ -11,44 +11,48 @@ import ArticlesList (
|
||||||
ArticlesList(..), description, getArticles, otherURL, rssLinkTexts
|
ArticlesList(..), description, getArticles, otherURL, rssLinkTexts
|
||||||
)
|
)
|
||||||
import Blog (Blog(..), Skin(..), URLs(..), template)
|
import Blog (Blog(..), Skin(..), URLs(..), template)
|
||||||
|
import Blog.URL (localPrefix)
|
||||||
|
import qualified Collection (tag)
|
||||||
import Control.Monad.Reader (ReaderT, asks)
|
import Control.Monad.Reader (ReaderT, asks)
|
||||||
import Data.Map as Map (Map, toList)
|
import Data.Map as Map (Map, toList)
|
||||||
import Data.Text (Text, pack, empty)
|
import Data.Text (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)
|
||||||
import Files (absoluteLink)
|
|
||||||
import Lucid (
|
import Lucid (
|
||||||
HtmlT, a_, article_, body_, charset_, class_, div_, doctypehtml_, h1_, h2_
|
Attribute, HtmlT, a_, article_, body_, charset_, class_, div_, doctypehtml_
|
||||||
, head_, header_, href_, li_, link_, id_, meta_, pre_, rel_, script_, src_
|
, h1_, h2_, head_, header_, href_, li_, link_, id_, meta_, pre_, rel_
|
||||||
, title_, toHtml, toHtmlRaw, type_, ul_
|
, script_, src_, title_, toHtml, toHtmlRaw, type_, ul_
|
||||||
)
|
)
|
||||||
import Markdown (Markdown(..), MarkdownContent(..))
|
import Markdown (Markdown(..), MarkdownContent(..))
|
||||||
import Network.URL (URL, exportURL)
|
import Network.URL (URL)
|
||||||
import Page (Page)
|
import Page (Page)
|
||||||
import Prelude hiding (head, lookup)
|
import Prelude hiding (head, lookup)
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
import System.FilePath.Posix ((<.>))
|
import System.FilePath.Posix ((</>), (<.>))
|
||||||
|
|
||||||
type HtmlGenerator = HtmlT (ReaderT Blog IO)
|
type HtmlGenerator = HtmlT (ReaderT Blog IO)
|
||||||
|
|
||||||
class HasCard a => HasContent a where
|
class HasCard a => PageType a where
|
||||||
content :: a -> HtmlGenerator ()
|
content :: a -> HtmlGenerator ()
|
||||||
|
pathToRoot :: a -> FilePath
|
||||||
|
|
||||||
instance HasContent Article where
|
instance PageType Article where
|
||||||
content = mDContent True . getMarkdown
|
content = mDContent True ".." . getMarkdown
|
||||||
|
pathToRoot _ = ".."
|
||||||
|
|
||||||
instance HasContent Page where
|
instance PageType Page where
|
||||||
content = mDContent True . getMarkdown
|
content = mDContent True ".." . getMarkdown
|
||||||
|
pathToRoot _ = ".."
|
||||||
|
|
||||||
instance HasContent ArticlesList where
|
instance PageType ArticlesList where
|
||||||
content al@(ArticlesList {full}) = do
|
content al@(ArticlesList {full}) = do
|
||||||
preview <- Article.preview <$> (asks $skin.$previewLinesCount)
|
preview <- Article.preview <$> (asks $skin.$previewLinesCount)
|
||||||
h2_ . toHtml =<< description al
|
h2_ . toHtml =<< description al
|
||||||
ul_ $ do
|
ul_ $ do
|
||||||
asks hasRSS >>= rssLink
|
asks hasRSS >>= rssLink
|
||||||
li_ . a_ [href_ . pack $ otherURL al, class_ "other"] =<< otherLink
|
li_ . a_ [href "" $ otherURL al, class_ "other"] =<< otherLink
|
||||||
div_ [class_ "articles"] (
|
div_ [class_ "articles"] (
|
||||||
mapM_ (mDContent False . preview) =<< getArticles al
|
mapM_ (mDContent False (pathToRoot al) . preview) =<< getArticles al
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
otherLink =
|
otherLink =
|
||||||
|
@ -59,34 +63,38 @@ instance HasContent ArticlesList where
|
||||||
li_ . a_ [href_ "rss.xml", class_ "RSS", title_ title] $ toHtml text
|
li_ . a_ [href_ "rss.xml", class_ "RSS", title_ title] $ toHtml text
|
||||||
rssLink False = return ()
|
rssLink False = return ()
|
||||||
|
|
||||||
mDContent :: Bool -> Markdown -> HtmlGenerator ()
|
pathToRoot = maybe "." (\_ -> "..") . Collection.tag . collection
|
||||||
mDContent raw markdown@(Markdown {key, body}) =
|
|
||||||
|
mDContent :: Bool -> FilePath -> Markdown -> HtmlGenerator ()
|
||||||
|
mDContent raw base markdown@(Markdown {key, body}) =
|
||||||
article_ [id_ $ pack key] (do
|
article_ [id_ $ pack key] (do
|
||||||
header_ . h1_ $ mDLink raw markdown
|
header_ . h1_ $ mDLink raw base markdown
|
||||||
pre_ . toHtml $ unlines body
|
pre_ . toHtml $ unlines body
|
||||||
)
|
)
|
||||||
|
|
||||||
mDLink :: Bool -> Markdown -> HtmlGenerator ()
|
mDLink :: Bool -> FilePath -> Markdown -> HtmlGenerator ()
|
||||||
mDLink raw (Markdown {Markdown.path, title}) =
|
mDLink raw base (Markdown {Markdown.path, title}) = link $ toHtml title
|
||||||
a_ [href_ $ pack url] $ toHtml title
|
|
||||||
where
|
where
|
||||||
url = absoluteLink $ path <.> (if raw then "md" else "html")
|
link = a_ [href base $ path <.> (if raw then "md" else "html")]
|
||||||
|
|
||||||
tag :: String -> HtmlGenerator ()
|
href :: FilePath -> FilePath -> Attribute
|
||||||
tag name =
|
href base = href_ . pack . (base </>)
|
||||||
a_ [href_ . pack $ absoluteLink name ++ "/", class_ "tag"] $ toHtml name
|
|
||||||
|
|
||||||
defaultBanner :: HtmlGenerator ()
|
tag :: FilePath -> String -> HtmlGenerator ()
|
||||||
defaultBanner =
|
tag base name =
|
||||||
|
a_ [href base $ name ++ "/", class_ "tag"] $ toHtml name
|
||||||
|
|
||||||
|
defaultBanner :: FilePath -> HtmlGenerator ()
|
||||||
|
defaultBanner base =
|
||||||
div_ [id_ "header"] (
|
div_ [id_ "header"] (
|
||||||
a_ [href_ "/"] (
|
a_ [href_ $ pack base] (
|
||||||
h1_ . toHtml =<< asks name
|
h1_ . toHtml =<< asks name
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
faviconLink :: URL -> HtmlGenerator ()
|
faviconLink :: FilePath -> URL -> HtmlGenerator ()
|
||||||
faviconLink url = link_ [
|
faviconLink base url = link_ [
|
||||||
rel_ "shortcut icon", href_ . pack $ exportURL url, type_ "image/x-icon"
|
rel_ "shortcut icon", href_ $ localPrefix base url, type_ "image/x-icon"
|
||||||
]
|
]
|
||||||
|
|
||||||
optional :: (a -> HtmlGenerator ()) -> Maybe a -> HtmlGenerator ()
|
optional :: (a -> HtmlGenerator ()) -> Maybe a -> HtmlGenerator ()
|
||||||
|
@ -102,24 +110,25 @@ navigationSection sectionId templateKey generator collection
|
||||||
ul_ . mapM_ (li_ . generator) $ Map.toList collection
|
ul_ . mapM_ (li_ . generator) $ Map.toList collection
|
||||||
)
|
)
|
||||||
|
|
||||||
htmlDocument :: HasContent a => a -> HtmlGenerator ()
|
htmlDocument :: PageType a => a -> HtmlGenerator ()
|
||||||
htmlDocument someContent =
|
htmlDocument someContent =
|
||||||
|
let base = pathToRoot someContent in
|
||||||
doctypehtml_ (do
|
doctypehtml_ (do
|
||||||
head_ (do
|
head_ (do
|
||||||
meta_ [charset_ "utf-8"]
|
meta_ [charset_ "utf-8"]
|
||||||
title_ . toHtml =<< asks name
|
title_ . toHtml =<< asks name
|
||||||
script_ [src_ "/js/remarkable.min.js"] empty
|
script_ [src_ "/js/remarkable.min.js"] empty
|
||||||
script_ [src_ "/js/hablo.js"] empty
|
script_ [src_ "/js/hablo.js"] empty
|
||||||
optional faviconLink =<< (asks $skin.$favicon)
|
optional (faviconLink base) =<< (asks $skin.$favicon)
|
||||||
optional (Card.make someContent) =<< (asks $urls.$cards)
|
optional (Card.make someContent) =<< (asks $urls.$cards)
|
||||||
optional toHtmlRaw =<< (asks $skin.$head)
|
optional toHtmlRaw =<< (asks $skin.$head)
|
||||||
)
|
)
|
||||||
body_ (do
|
body_ (do
|
||||||
maybe defaultBanner toHtmlRaw =<< (asks $skin.$banner)
|
maybe (defaultBanner base) toHtmlRaw =<< (asks $skin.$banner)
|
||||||
asks tags >>= navigationSection "tags" "tagsList"
|
asks tags >>= navigationSection "tags" "tagsList"
|
||||||
(\(key, _) -> tag key)
|
(\(key, _) -> tag base key)
|
||||||
asks pages >>= navigationSection "pages" "pagesList"
|
asks pages >>= navigationSection "pages" "pagesList"
|
||||||
(\(_, page) -> mDLink False $ getMarkdown page)
|
(\(_, page) -> mDLink False base $ getMarkdown page)
|
||||||
div_ [id_ "contents"] $ content someContent
|
div_ [id_ "contents"] $ content someContent
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Article (Article(..))
|
||||||
import ArticlesList (ArticlesList(..))
|
import ArticlesList (ArticlesList(..))
|
||||||
import qualified ArticlesList (description)
|
import qualified ArticlesList (description)
|
||||||
import Blog (Blog(..), Renderer, Skin(..), template)
|
import Blog (Blog(..), Renderer, Skin(..), template)
|
||||||
import Blog.URL ((./), (/?), AbsoluteURL, checkURL)
|
import Blog.URL (AbsoluteURL, checkURL, defaultOn, pathOn)
|
||||||
import Collection (Collection(..))
|
import Collection (Collection(..))
|
||||||
import qualified Collection (title)
|
import qualified Collection (title)
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
|
@ -42,14 +42,14 @@ og attribute value =
|
||||||
|
|
||||||
make :: (HasCard a, Renderer m) => a -> AbsoluteURL -> HtmlT m ()
|
make :: (HasCard a, Renderer m) => a -> AbsoluteURL -> HtmlT m ()
|
||||||
make element siteURL = do
|
make element siteURL = do
|
||||||
og "url" . (siteURL ./) =<< urlPath element
|
og "url" . (pathOn siteURL) =<< urlPath element
|
||||||
og "type" =<< cardType element
|
og "type" =<< cardType element
|
||||||
og "title" . pack =<< title element
|
og "title" . pack =<< title element
|
||||||
og "description" =<< description element
|
og "description" =<< description element
|
||||||
maybeImage =<< ((<|>) <$> image element <*> (asks $skin.$cardImage))
|
maybeImage =<< ((<|>) <$> image element <*> (asks $skin.$cardImage))
|
||||||
og "site_name" =<< (asks $name.$pack)
|
og "site_name" =<< (asks $name.$pack)
|
||||||
where
|
where
|
||||||
maybeImage = maybe (return ()) (og "image" . (siteURL /?))
|
maybeImage = maybe (return ()) (og "image" . defaultOn siteURL)
|
||||||
|
|
||||||
mDImage :: (Renderer m, MarkdownContent a) => a -> m (Maybe URL)
|
mDImage :: (Renderer m, MarkdownContent a) => a -> m (Maybe URL)
|
||||||
mDImage = mapM checkURL . Map.lookup "featuredImage" . metadata . getMarkdown
|
mDImage = mapM checkURL . Map.lookup "featuredImage" . metadata . getMarkdown
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
module Files (
|
module Files (
|
||||||
File(..)
|
File(..)
|
||||||
, absoluteLink
|
|
||||||
, filePath
|
, filePath
|
||||||
, find
|
, find
|
||||||
) where
|
) where
|
||||||
|
@ -10,10 +9,6 @@ import System.FilePath ((</>))
|
||||||
|
|
||||||
data File = File FilePath | Dir FilePath
|
data File = File FilePath | Dir FilePath
|
||||||
|
|
||||||
absoluteLink :: FilePath -> FilePath
|
|
||||||
absoluteLink ('.':path) = path
|
|
||||||
absoluteLink path = "/" </> path
|
|
||||||
|
|
||||||
filePath :: File -> IO (Either String FilePath)
|
filePath :: File -> IO (Either String FilePath)
|
||||||
filePath = filePathAux
|
filePath = filePathAux
|
||||||
where
|
where
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Control.Monad.IO.Class (MonadIO(..))
|
||||||
import Control.Monad.Reader (ReaderT, asks)
|
import Control.Monad.Reader (ReaderT, asks)
|
||||||
import qualified Data.Map as Map (elems)
|
import qualified Data.Map as Map (elems)
|
||||||
import qualified Data.Text.Lazy.IO as TextIO (writeFile)
|
import qualified Data.Text.Lazy.IO as TextIO (writeFile)
|
||||||
import DOM (HasContent, htmlDocument)
|
import DOM (PageType, htmlDocument)
|
||||||
import Lucid (renderTextT)
|
import Lucid (renderTextT)
|
||||||
import Markdown (Markdown(..), MarkdownContent(..))
|
import Markdown (Markdown(..), MarkdownContent(..))
|
||||||
import Pretty ((.$))
|
import Pretty ((.$))
|
||||||
|
@ -26,7 +26,7 @@ articlesLists collection@(Collection {basePath}) = [
|
||||||
file bool = if bool then "all" else "index"
|
file bool = if bool then "all" else "index"
|
||||||
path bool = basePath </> file bool <.> "html"
|
path bool = basePath </> file bool <.> "html"
|
||||||
|
|
||||||
generateMarkdown :: (HasContent a, MarkdownContent a) => [a] -> ReaderT Blog IO ()
|
generateMarkdown :: (PageType a, MarkdownContent a) => [a] -> ReaderT Blog IO ()
|
||||||
generateMarkdown = mapM_ $ \content -> do
|
generateMarkdown = mapM_ $ \content -> do
|
||||||
let relativePath = Markdown.path (getMarkdown content) <.> "html"
|
let relativePath = Markdown.path (getMarkdown content) <.> "html"
|
||||||
filePath <- (</> relativePath) <$> (asks $Blog.path.$root)
|
filePath <- (</> relativePath) <$> (asks $Blog.path.$root)
|
||||||
|
|
|
@ -9,7 +9,7 @@ import Article (Article(..))
|
||||||
import ArticlesList (ArticlesList(..), getArticles)
|
import ArticlesList (ArticlesList(..), getArticles)
|
||||||
import qualified ArticlesList (description, path)
|
import qualified ArticlesList (description, path)
|
||||||
import Blog (Blog(urls), Renderer, URLs(..))
|
import Blog (Blog(urls), Renderer, URLs(..))
|
||||||
import Blog.URL ((./), AbsoluteURL)
|
import Blog.URL (AbsoluteURL, pathOn)
|
||||||
import Collection (Collection(..), getAll)
|
import Collection (Collection(..), getAll)
|
||||||
import qualified Collection (title)
|
import qualified Collection (title)
|
||||||
import Control.Monad.IO.Class (MonadIO(..))
|
import Control.Monad.IO.Class (MonadIO(..))
|
||||||
|
@ -62,7 +62,7 @@ articleItem :: Monad m => AbsoluteURL -> Article -> HtmlT m ()
|
||||||
articleItem siteURL (Article (Markdown {path, metadata, title})) =
|
articleItem siteURL (Article (Markdown {path, metadata, title})) =
|
||||||
item_ $ do
|
item_ $ do
|
||||||
title_ $ toHtml title
|
title_ $ toHtml title
|
||||||
link_ . toHtml $ siteURL ./ (path <.> "html")
|
link_ . toHtml $ pathOn siteURL (path <.> "html")
|
||||||
pubDate_ . toHtml . rfc822Date $ metadata ! "date"
|
pubDate_ . toHtml . rfc822Date $ metadata ! "date"
|
||||||
where
|
where
|
||||||
rfc822Date =
|
rfc822Date =
|
||||||
|
@ -75,7 +75,7 @@ feed siteURL al@(ArticlesList {collection}) = do
|
||||||
rss_ [version, content, atom] $ do
|
rss_ [version, content, atom] $ do
|
||||||
channel_ $ do
|
channel_ $ do
|
||||||
title_ . toHtml =<< Collection.title collection
|
title_ . toHtml =<< Collection.title collection
|
||||||
link_ . toHtml $ siteURL ./ ArticlesList.path al
|
link_ . toHtml . pathOn siteURL $ ArticlesList.path al
|
||||||
description_ . toHtml =<< ArticlesList.description al
|
description_ . toHtml =<< ArticlesList.description al
|
||||||
mapM_ (articleItem siteURL) =<< getArticles al
|
mapM_ (articleItem siteURL) =<< getArticles al
|
||||||
where
|
where
|
||||||
|
|
|
@ -4,27 +4,19 @@ module Mock.Blog.URL (
|
||||||
, subPath
|
, subPath
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Blog.URL (AbsoluteURL(..), URLs(..))
|
import Blog.URL (URLs(..))
|
||||||
import Mock.URL (testHost)
|
import Mock.URL (prefixedTestSite, testSite)
|
||||||
|
|
||||||
simple :: URLs
|
simple :: URLs
|
||||||
simple = URLs {
|
simple = URLs {
|
||||||
cards = Just (AbsoluteURL {
|
cards = Just testSite
|
||||||
Blog.URL.host = testHost
|
|
||||||
, urlPath = ""
|
|
||||||
, urlParams = []
|
|
||||||
})
|
|
||||||
, comments = Nothing
|
, comments = Nothing
|
||||||
, rss = Nothing
|
, rss = Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
subPath :: URLs
|
subPath :: URLs
|
||||||
subPath = URLs {
|
subPath = URLs {
|
||||||
cards = Just (AbsoluteURL {
|
cards = Just prefixedTestSite
|
||||||
Blog.URL.host = testHost
|
|
||||||
, urlPath = "subPath"
|
|
||||||
, urlParams = []
|
|
||||||
})
|
|
||||||
, comments = Nothing
|
, comments = Nothing
|
||||||
, rss = Nothing
|
, rss = Nothing
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,33 @@
|
||||||
module Mock.URL (
|
module Mock.URL (
|
||||||
cdnFavicon
|
cdnFavicon
|
||||||
|
, hostFavicon
|
||||||
, localDiscovered
|
, localDiscovered
|
||||||
, localFavicon
|
, localFavicon
|
||||||
|
, prefixedTestSite
|
||||||
, testHost
|
, testHost
|
||||||
|
, testSite
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Blog.URL (AbsoluteURL(..))
|
||||||
import Network.URL (Host(..), Protocol(..), URL(..), URLType(..))
|
import Network.URL (Host(..), Protocol(..), URL(..), URLType(..))
|
||||||
|
|
||||||
testHost :: Host
|
testHost :: Host
|
||||||
testHost = Host (HTTP True) "test.net" Nothing
|
testHost = Host (HTTP True) "test.net" Nothing
|
||||||
|
|
||||||
|
testSite :: AbsoluteURL
|
||||||
|
testSite = AbsoluteURL {
|
||||||
|
Blog.URL.host = testHost
|
||||||
|
, urlPath = ""
|
||||||
|
, urlParams = []
|
||||||
|
}
|
||||||
|
|
||||||
|
prefixedTestSite :: AbsoluteURL
|
||||||
|
prefixedTestSite = AbsoluteURL {
|
||||||
|
Blog.URL.host = testHost
|
||||||
|
, urlPath = "subPath"
|
||||||
|
, urlParams = []
|
||||||
|
}
|
||||||
|
|
||||||
cdn :: Host
|
cdn :: Host
|
||||||
cdn = Host (HTTP True) "cdn.net" Nothing
|
cdn = Host (HTTP True) "cdn.net" Nothing
|
||||||
|
|
||||||
|
@ -20,16 +38,23 @@ cdnFavicon = URL {
|
||||||
, url_params = []
|
, url_params = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hostFavicon :: URL
|
||||||
|
hostFavicon = URL {
|
||||||
|
url_type = HostRelative
|
||||||
|
, url_path = "favicon.png"
|
||||||
|
, url_params = []
|
||||||
|
}
|
||||||
|
|
||||||
localFavicon :: URL
|
localFavicon :: URL
|
||||||
localFavicon = URL {
|
localFavicon = URL {
|
||||||
url_type = HostRelative
|
url_type = PathRelative
|
||||||
, url_path = "favicon.png"
|
, url_path = "favicon.png"
|
||||||
, url_params = []
|
, url_params = []
|
||||||
}
|
}
|
||||||
|
|
||||||
localDiscovered :: URL
|
localDiscovered :: URL
|
||||||
localDiscovered = URL {
|
localDiscovered = URL {
|
||||||
url_type = HostRelative
|
url_type = PathRelative
|
||||||
, url_path = "skin/favicon.png"
|
, url_path = "skin/favicon.png"
|
||||||
, url_params = []
|
, url_params = []
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ module Tests (
|
||||||
|
|
||||||
import Distribution.TestSuite
|
import Distribution.TestSuite
|
||||||
import qualified Structure (test)
|
import qualified Structure (test)
|
||||||
|
import qualified URLs (test)
|
||||||
import Utils (tag)
|
import Utils (tag)
|
||||||
import qualified XML.Card (test)
|
import qualified XML.Card (test)
|
||||||
import qualified XML.Favicon (test)
|
import qualified XML.Favicon (test)
|
||||||
|
@ -13,4 +14,5 @@ tests = return $ tag "xml" <$> [
|
||||||
XML.Card.test
|
XML.Card.test
|
||||||
, XML.Favicon.test
|
, XML.Favicon.test
|
||||||
, Structure.test
|
, Structure.test
|
||||||
|
, URLs.test
|
||||||
]
|
]
|
||||||
|
|
69
test/URLs.hs
69
test/URLs.hs
|
@ -1,12 +1,73 @@
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
module URLs (
|
module URLs (
|
||||||
test
|
test
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Blog.URL (URL(..))
|
import Blog.URL (defaultOn, pathOn, localPrefix)
|
||||||
|
import Data.Text (Text)
|
||||||
import Distribution.TestSuite
|
import Distribution.TestSuite
|
||||||
|
import Mock.URL (
|
||||||
|
cdnFavicon, hostFavicon, localDiscovered, localFavicon, prefixedTestSite
|
||||||
|
, testSite
|
||||||
|
)
|
||||||
import Utils (simpleTest, tag)
|
import Utils (simpleTest, tag)
|
||||||
|
|
||||||
test :: Test
|
check :: Text -> Text -> IO Progress
|
||||||
test = tag "URLs" . testGroup "URLs handling" $ simpleTest <$> [
|
check actual expected =
|
||||||
("nothing", return $ Finished Pass)
|
return . Finished $
|
||||||
|
if actual == expected
|
||||||
|
then Pass
|
||||||
|
else Fail $ "Expected " ++ show expected ++ " but got " ++ show actual
|
||||||
|
|
||||||
|
testPathOn :: Test
|
||||||
|
testPathOn = tag "pathOn" . testGroup "Concat path" $ simpleTest <$> [
|
||||||
|
("no prefix / relative path",
|
||||||
|
check (pathOn testSite "tag/all.html") "https://test.net/tag/all.html")
|
||||||
|
, ("no prefix / absolute path",
|
||||||
|
check
|
||||||
|
(pathOn testSite "/media/logo.png")
|
||||||
|
"https://test.net/media/logo.png")
|
||||||
|
, ("prefixed / relative path",
|
||||||
|
check
|
||||||
|
(pathOn prefixedTestSite "tag/all.html")
|
||||||
|
"https://test.net/subPath/tag/all.html")
|
||||||
|
, ("prefixed / absolute path ",
|
||||||
|
check
|
||||||
|
(pathOn prefixedTestSite "/media/logo.png")
|
||||||
|
"https://test.net/media/logo.png")
|
||||||
|
]
|
||||||
|
|
||||||
|
testDefaultOn :: Test
|
||||||
|
testDefaultOn = tag "defaultOn" . testGroup "Concat path or pick URL" $ simpleTest <$> [
|
||||||
|
("external resource", -- shouldn't even touch the first argument when the second is an absolute URL
|
||||||
|
check (defaultOn undefined cdnFavicon) "https://cdn.net/favicon.png")
|
||||||
|
, ("host relative",
|
||||||
|
check (defaultOn testSite hostFavicon) "https://test.net/favicon.png")
|
||||||
|
, ("host relative / prefix",
|
||||||
|
check
|
||||||
|
(defaultOn prefixedTestSite hostFavicon)
|
||||||
|
"https://test.net/favicon.png")
|
||||||
|
, ("relative",
|
||||||
|
check
|
||||||
|
(defaultOn testSite localDiscovered)
|
||||||
|
"https://test.net/skin/favicon.png")
|
||||||
|
, ("relative / prefix",
|
||||||
|
check
|
||||||
|
(defaultOn prefixedTestSite localDiscovered)
|
||||||
|
"https://test.net/subPath/skin/favicon.png")
|
||||||
|
]
|
||||||
|
|
||||||
|
testLocalPrefix :: Test
|
||||||
|
testLocalPrefix = tag "localPrefix" . testGroup "Prefixed URLs" $ simpleTest <$> [
|
||||||
|
("absolute URL", check (localPrefix ".." cdnFavicon) "https://cdn.net/favicon.png")
|
||||||
|
, ("host relative", check (localPrefix ".." hostFavicon) "/favicon.png")
|
||||||
|
, ("relative path", check (localPrefix ".." localDiscovered) "../skin/favicon.png")
|
||||||
|
, ("relative path no prefix", check (localPrefix "" localFavicon) "favicon.png")
|
||||||
|
]
|
||||||
|
|
||||||
|
test :: Test
|
||||||
|
test = tag "URLs" $ testGroup "URLs handling" [
|
||||||
|
testPathOn
|
||||||
|
, testDefaultOn
|
||||||
|
, testLocalPrefix
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,22 +4,24 @@ module XML.Favicon (
|
||||||
|
|
||||||
import Blog.Skin (findImage)
|
import Blog.Skin (findImage)
|
||||||
import Distribution.TestSuite
|
import Distribution.TestSuite
|
||||||
import Mock.URL (cdnFavicon, localDiscovered, localFavicon)
|
import Mock.URL (cdnFavicon, hostFavicon, localDiscovered, localFavicon)
|
||||||
import Network.URL (URL)
|
import Network.URL (URL)
|
||||||
import Utils (assertAll, assertEqual, simpleTest, tag)
|
import System.Directory (withCurrentDirectory)
|
||||||
|
import Utils (assertAll, assertEqual, simpleTest, tag, testDataPath)
|
||||||
|
|
||||||
check :: IO (Maybe URL) -> Maybe URL -> IO Progress
|
check :: IO (Maybe URL) -> Maybe URL -> IO Progress
|
||||||
check getter expected = do
|
check getter expected =
|
||||||
actual <- getter
|
withCurrentDirectory (testDataPath "XML/Favicon/Input") $ do
|
||||||
assertAll $ [
|
actual <- getter
|
||||||
assertEqual "URLs" actual expected
|
assertAll $ [
|
||||||
]
|
assertEqual "URLs" actual expected
|
||||||
|
]
|
||||||
|
|
||||||
test :: Test
|
test :: Test
|
||||||
test = tag "favicon" . testGroup "Favicons" $ simpleTest <$> [
|
test = tag "favicon" . testGroup "Favicons" $ simpleTest <$> [
|
||||||
("auto-discover", check (findImage "favicon" Nothing) (Just localDiscovered))
|
("auto-discover", check (findImage "favicon" Nothing) (Just localDiscovered))
|
||||||
, ("none", check (findImage "blerp" Nothing) Nothing)
|
, ("none", check (findImage "blerp" Nothing) Nothing)
|
||||||
, ("manual absolute", check (findImage "" (Just "https://cdn.net/favicon.png")) (Just cdnFavicon))
|
, ("manual absolute", check (findImage "" (Just "https://cdn.net/favicon.png")) (Just cdnFavicon))
|
||||||
|
, ("manual host-relative", check (findImage "" (Just "/favicon.png")) (Just hostFavicon))
|
||||||
, ("manual relative", check (findImage "" (Just "favicon.png")) (Just localFavicon))
|
, ("manual relative", check (findImage "" (Just "favicon.png")) (Just localFavicon))
|
||||||
, ("manual host-relative", check (findImage "" (Just "/favicon.png")) (Just localFavicon))
|
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue