forked from marko/svitak
add Html and PlainText types, improved type safety
This commit is contained in:
parent
6ca9e43520
commit
8be29359fc
3 changed files with 23 additions and 14 deletions
|
|
@ -48,6 +48,8 @@ import Types
|
|||
EpubEnv (..),
|
||||
InternalPath (..),
|
||||
TocEntry (..),
|
||||
Html(..),
|
||||
PlainText(..)
|
||||
)
|
||||
import Navigation (RawToc (..), guideToc, navDocHref, navToc, ncxToc)
|
||||
|
||||
|
|
@ -181,11 +183,11 @@ renderRef ref = do
|
|||
env <- ask
|
||||
let InternalPath p = refPath ref
|
||||
pure $ case findEntry env p of
|
||||
Nothing -> Chapter (refPath ref) (refTitle ref) "" (refIndex ref)
|
||||
Nothing -> Chapter (refPath ref) (refTitle ref) (Html "") (refIndex ref)
|
||||
Just entry ->
|
||||
let withImages = embedImages env (takeDirectory p) (decodeEntry entry)
|
||||
body = fromMaybe "" (scrapeStringLike withImages bodyScraper)
|
||||
in Chapter (refPath ref) (refTitle ref) body (refIndex ref)
|
||||
in Chapter (refPath ref) (refTitle ref) (Html body) (refIndex ref)
|
||||
|
||||
stripTags :: T.Text -> T.Text
|
||||
stripTags = T.unwords . T.words . go
|
||||
|
|
@ -197,14 +199,14 @@ stripTags = T.unwords . T.words . go
|
|||
|
||||
-- | Read a chapter file and render its @\<body\>@ to plaintext, excluding
|
||||
-- any tags.
|
||||
readPText :: ChapterRef -> EpubAction T.Text
|
||||
readPText :: ChapterRef -> EpubAction PlainText
|
||||
readPText ref = do
|
||||
env <- ask
|
||||
let InternalPath p = refPath ref
|
||||
pure $ case findEntry env p of
|
||||
Nothing -> ""
|
||||
Nothing -> PlainText ""
|
||||
Just entry ->
|
||||
stripTags $ fromMaybe "" (scrapeStringLike (decodeEntry entry) bodyScraper)
|
||||
PlainText $ stripTags $ fromMaybe "" (scrapeStringLike (decodeEntry entry) bodyScraper)
|
||||
|
||||
-- | Grab the contents of @\<body\>@, falling back to the whole document.
|
||||
bodyScraper :: Scraper T.Text T.Text
|
||||
|
|
|
|||
11
app/Types.hs
11
app/Types.hs
|
|
@ -25,6 +25,8 @@ module Types
|
|||
EpubEnv (..),
|
||||
EpubAction,
|
||||
ReadMode(..),
|
||||
Html(..),
|
||||
PlainText(..),
|
||||
)
|
||||
where
|
||||
|
||||
|
|
@ -56,11 +58,14 @@ data ChapterRef = ChapterRef
|
|||
data Chapter = Chapter
|
||||
{ chapterPath :: InternalPath,
|
||||
chapterTitle :: T.Text,
|
||||
chapterHtml :: T.Text,
|
||||
chapterHtml :: Html,
|
||||
chapterIndex :: ChapterIndex
|
||||
}
|
||||
deriving (Show)
|
||||
|
||||
newtype Html = Html T.Text deriving (Show, Eq)
|
||||
newtype PlainText = PlainText T.Text deriving (Show, Eq)
|
||||
|
||||
-- | A node in the (possibly nested) table of contents. @tocTarget@ is the
|
||||
-- resolved chapter path; @tocFragment@ is the optional in-page anchor.
|
||||
data TocEntry = TocEntry
|
||||
|
|
@ -91,7 +96,7 @@ class BookInfo a where
|
|||
renderChapter :: a -> ChapterRef -> IO (Either String Chapter)
|
||||
|
||||
-- | Extract a single chapter's plain text (tags stripped), for search.
|
||||
chapterText :: a -> ChapterRef -> IO (Either String T.Text)
|
||||
chapterText :: a -> ChapterRef -> IO (Either String PlainText)
|
||||
|
||||
-- | Mutable application state, held in a 'Control.Concurrent.STM.TVar'.
|
||||
-- Rendered chapters accumulate in 'stCache' as the reader visits them.
|
||||
|
|
@ -106,7 +111,7 @@ data AppState = AppState
|
|||
stGen :: Int,
|
||||
stUse :: M.Map ChapterIndex Int,
|
||||
stTick :: Int,
|
||||
stSearchIndex :: M.Map ChapterIndex T.Text,
|
||||
stSearchIndex :: M.Map ChapterIndex PlainText,
|
||||
stMode :: ReadMode
|
||||
}
|
||||
|
||||
|
|
|
|||
14
app/UI.hs
14
app/UI.hs
|
|
@ -39,6 +39,8 @@ import Types
|
|||
TocEntry (..),
|
||||
UserAction (..),
|
||||
ReadMode(..),
|
||||
Html(..),
|
||||
PlainText(..),
|
||||
)
|
||||
|
||||
-- | Widget handles the rest of the module needs.
|
||||
|
|
@ -402,7 +404,7 @@ showLoading :: Ctx -> ChapterRef -> IO ()
|
|||
showLoading ctx ref = do
|
||||
mode <- getMode ctx
|
||||
setWindowTitle ctx (refIndex ref) (refTitle ref)
|
||||
WebKit.webViewLoadHtml (appWebView (ctxWidgets ctx)) (wrapHtml "<p style=\"opacity:0.5\">Loading…</p>" StartTop mode) Nothing
|
||||
WebKit.webViewLoadHtml (appWebView (ctxWidgets ctx)) (wrapHtml (Html "<p style=\"opacity:0.5\">Loading…</p>") StartTop mode) Nothing
|
||||
|
||||
setWindowTitle :: Ctx -> ChapterIndex -> T.Text -> IO ()
|
||||
setWindowTitle ctx (ChapterIndex i) chapter = do
|
||||
|
|
@ -419,8 +421,8 @@ setZoom ctx level = do
|
|||
-- | Wrap a chapter's @\<body\>@ fragment in a full, styled HTML document
|
||||
-- (WebKit renders bare fragments unreliably). If @frag@ names an anchor, a
|
||||
-- small script scrolls it into view after load.
|
||||
wrapHtml :: T.Text -> StartAt -> ReadMode -> T.Text
|
||||
wrapHtml body start mode =
|
||||
wrapHtml :: Html -> StartAt -> ReadMode -> T.Text
|
||||
wrapHtml (Html body) start mode =
|
||||
T.concat
|
||||
[ "<!DOCTYPE html><html><head><meta charset=\"utf-8\"><style>",
|
||||
( case mode of
|
||||
|
|
@ -492,11 +494,11 @@ evalJSBool wv src k =
|
|||
b <- JSC.valueToBoolean val
|
||||
k b)
|
||||
|
||||
chaptersMatching :: T.Text -> M.Map ChapterIndex T.Text -> [ChapterIndex]
|
||||
chaptersMatching :: T.Text -> M.Map ChapterIndex PlainText -> [ChapterIndex]
|
||||
chaptersMatching q = map fst . filter (matches q . snd) . M.toAscList
|
||||
|
||||
matches :: T.Text -> T.Text -> Bool
|
||||
matches q txt = T.toCaseFold q `T.isInfixOf` T.toCaseFold txt
|
||||
matches :: T.Text -> PlainText -> Bool
|
||||
matches q (PlainText txt) = T.toCaseFold q `T.isInfixOf` T.toCaseFold txt
|
||||
|
||||
nextMatch :: ChapterIndex -> [ChapterIndex] -> Maybe ChapterIndex
|
||||
nextMatch cur hits =
|
||||
|
|
|
|||
Loading…
Reference in a new issue