module Rakka.Page ( PageName , Page(..) , LanguageTag , LanguageName , encodePageName , decodePageName , pageFileName' , defaultFileName , mkPageURI , mkPageFragmentURI , mkObjectURI , mkFragmentURI , mkAuxiliaryURI , mkRakkaURI ) where import Codec.Binary.UTF8.String import qualified Data.ByteString.Lazy as Lazy (ByteString) import Data.Char import Data.Map (Map) import Data.Maybe import Data.Time import Network.HTTP.Lucu import Network.URI hiding (fragment) import Subversion.Types import System.FilePath.Posix type PageName = String type LanguageTag = String -- See RFC 3066: http://www.ietf.org/rfc/rfc3066.txt type LanguageName = String -- i.e. "日本語" data Page = Redirection { redirName :: !PageName , redirDest :: !PageName , redirRevision :: !(Maybe RevNum) , redirLastMod :: !UTCTime } | Entity { pageName :: !PageName , pageType :: !MIMEType , pageLanguage :: !(Maybe LanguageTag) , pageFileName :: !(Maybe String) , pageIsTheme :: !Bool -- text/css 以外では無意味 , pageIsFeed :: !Bool -- text/x-rakka 以外では無意味 , pageIsLocked :: !Bool , pageIsBoring :: !Bool , pageIsBinary :: !Bool , pageRevision :: !RevNum , pageLastMod :: !UTCTime , pageSummary :: !(Maybe String) , pageOtherLang :: !(Map LanguageTag PageName) , pageContent :: !Lazy.ByteString } -- UTF-8 に encode してから 0x20 - 0x7E の範圍を除いて URI escape する。 encodePageName :: PageName -> FilePath encodePageName = escapeURIString isSafeChar . encodeString . fixPageName where fixPageName :: PageName -> PageName fixPageName = (\ (x:xs) -> toUpper x : xs) . map (\ c -> if c == ' ' then '_' else c) isSafeChar :: Char -> Bool isSafeChar c | c == '/' = True | isReserved c = False | c > ' ' && c <= '~' = True | otherwise = False -- URI unescape して UTF-8 から decode する。 decodePageName :: FilePath -> PageName decodePageName = decodeString . unEscapeString encodeFragment :: String -> String encodeFragment = escapeURIString isSafeChar . encodeString pageFileName' :: Page -> String pageFileName' page = fromMaybe (defaultFileName (pageType page) (pageName page)) (pageFileName page) defaultFileName :: MIMEType -> PageName -> String defaultFileName pType pName = let baseName = takeFileName pName in case pType of MIMEType "text" "x-rakka" _ -> baseName <.> "rakka" MIMEType "text" "css" _ -> baseName <.> "css" _ -> baseName mkPageURI :: URI -> PageName -> URI mkPageURI baseURI name = baseURI { uriPath = foldl () "/" [uriPath baseURI, encodePageName name ++ ".html"] } mkPageFragmentURI :: URI -> PageName -> String -> URI mkPageFragmentURI baseURI name fragment = baseURI { uriPath = foldl () "/" [uriPath baseURI, encodePageName name ++ ".html"] , uriFragment = ('#' : encodeFragment fragment) } mkFragmentURI :: String -> URI mkFragmentURI fragment = nullURI { uriFragment = ('#' : encodeFragment fragment) } mkObjectURI :: URI -> PageName -> URI mkObjectURI baseURI name = mkAuxiliaryURI baseURI ["object"] name mkAuxiliaryURI :: URI -> [String] -> PageName -> URI mkAuxiliaryURI baseURI basePath name = baseURI { uriPath = foldl () "/" ([uriPath baseURI] ++ basePath ++ [encodePageName name]) } mkRakkaURI :: PageName -> URI mkRakkaURI name = URI { uriScheme = "rakka:" , uriAuthority = Nothing , uriPath = encodePageName name , uriQuery = "" , uriFragment = "" }