module Rakka.Page
( PageName
, Page(..)
+ , LanguageTag
+ , LanguageName
+
, encodePageName
, decodePageName
+
+ , pageFileName'
+ , defaultFileName
+
, mkPageURI
, mkPageFragmentURI
, mkObjectURI
+ , mkFragmentURI
, mkAuxiliaryURI
+ , mkRakkaURI
)
where
-import Data.ByteString.Base (LazyByteString)
-import qualified Data.ByteString.Char8 as C8
-import Data.Encoding
-import Data.Encoding.UTF8
+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
+import Network.URI hiding (fragment)
import Subversion.Types
-import System.FilePath
-import System.Time
+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 :: !CalendarTime
+ , 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 :: !(Maybe RevNum)
- , pageLastMod :: !CalendarTime
+ , pageRevision :: !RevNum
+ , pageLastMod :: !UTCTime
, pageSummary :: !(Maybe String)
- , pageOtherLang :: ![(String, PageName)]
- , pageContent :: !LazyByteString
+ , pageOtherLang :: !(Map LanguageTag PageName)
+ , pageContent :: !Lazy.ByteString
}
-- UTF-8 に encode してから 0x20 - 0x7E の範圍を除いて URI escape する。
encodePageName :: PageName -> FilePath
-encodePageName = escapeURIString isSafe . C8.unpack . encode UTF8
+encodePageName = escapeURIString isSafeChar . encodeString . fixPageName
where
- isSafe :: Char -> Bool
- isSafe c
- | c >= ' ' && c <= '~' = True
- | otherwise = False
+ 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 = decode UTF8 . C8.pack . unEscapeString
+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 combine "/" [uriPath baseURI, encodePageName name ++ ".html"]
+ uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
}
mkPageFragmentURI :: URI -> PageName -> String -> URI
mkPageFragmentURI baseURI name fragment
= baseURI {
- uriPath = foldl combine "/" [uriPath baseURI, encodePageName name ++ ".html"]
- , uriFragment = ('#':fragment)
+ uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
+ , uriFragment = ('#' : encodeFragment fragment)
+ }
+
+
+mkFragmentURI :: String -> URI
+mkFragmentURI fragment
+ = nullURI {
+ uriFragment = ('#' : encodeFragment fragment)
}
mkAuxiliaryURI :: URI -> [String] -> PageName -> URI
mkAuxiliaryURI baseURI basePath name
= baseURI {
- uriPath = foldl combine "/" ([uriPath baseURI] ++ basePath ++ [encodePageName name])
+ uriPath = foldl (</>) "/" ([uriPath baseURI] ++ basePath ++ [encodePageName name])
}
+
+
+mkRakkaURI :: PageName -> URI
+mkRakkaURI name = URI {
+ uriScheme = "rakka:"
+ , uriAuthority = Nothing
+ , uriPath = encodePageName name
+ , uriQuery = ""
+ , uriFragment = ""
+ }