add navigation module

This commit is contained in:
Marko Andjelic 2026-02-11 06:22:09 +00:00
commit 7cd9e79c94
4 changed files with 53 additions and 7 deletions

View file

@ -25,8 +25,9 @@ import Data.Maybe (fromMaybe)
import qualified Data.Text as T
import qualified Data.Text.Encoding as TE
import System.FilePath (normalise, takeDirectory, (</>))
import Text.HTML.Scalpel (Scraper, ScraperT, anySelector, attr, chroot, chroots, html, innerHTML, scrapeStringLike, text, (@:), (@=))
import Text.HTML.Scalpel (Scraper, ScraperT, anySelector, attr, chroot, chroots, html, innerHTML, scrapeStringLike, text)
import Types (Chapter (..), EpubAction, EpubEnv (..))
import Navigation (navFinder)
openEpub :: FilePath -> IO (Either String EpubEnv)
openEpub path = do
@ -155,7 +156,3 @@ chapterScraper = do
title <- chTitleScraper <|> pure "Untitled Chapter"
content <- chroot "body" (innerHTML anySelector) <|> innerHTML anySelector
pure (title, content)
-- needed for epub3 support, find the nav file
navFinder :: Scraper String FilePath
navFinder = attr "href" ("item" @: ["properties" @= "nav"])

41
app/Navigation.hs Normal file
View file

@ -0,0 +1,41 @@
{-# LANGUAGE OverloadedStrings #-}
module Navigation
( navFinder,
lndmkScraper
)
where
import Text.HTML.Scalpel (Scraper, attr, (@:), (@=), chroot, chroots, text, match)
import Types (NavItem(..))
import Data.Maybe (fromMaybe)
import Control.Applicative (optional)
import Control.Monad (guard)
import qualified Data.Text as T
-- ------------------------------------------------------------
-- EPub 3 navigation
-- ------------------------------------------------------------
-- The epub-metadata library is good for epub 2.x. As there could be a seperate nav.xhtml file in the epub 3.x spec, we need these functions to support it.
navFinder :: Scraper String FilePath
navFinder = attr "href" ("item" @: ["properties" @= "nav"])
itemScraper :: [T.Text] -> Scraper T.Text NavItem
itemScraper allowedTypes = do
label <- text "a"
path <- attr "href" "a"
rawTypes <- fromMaybe "" <$> optional (attr "epub:type" "a")
let foundTypes = T.words rawTypes
guard $ any (`elem` allowedTypes) foundTypes
pure $ NavItem label (T.unpack path) foundTypes
lndmkScraper :: [T.Text] -> Scraper T.Text [NavItem]
lndmkScraper labels =
chroot ("nav" @: [match navPredicate]) $ chroots "li" (itemScraper labels)
where
navPredicate "epub:type" xs = T.pack xs `elem` labels
navPredicate _ _ = False

View file

@ -4,7 +4,8 @@ module Types
Chapter(..),
AppState(..),
UserAction(..),
EpubAction
EpubAction,
NavItem(..)
)
where
@ -55,3 +56,9 @@ data UserAction
| ZoomIn
| ZoomOut
| LoadSpecific Int
data NavItem = NavItem
{ navLabel :: T.Text,
navPath :: FilePath,
navTypes :: [T.Text]
} deriving (Show)

View file

@ -55,7 +55,8 @@ executable svitak
UI,
Persistence,
State,
Types
Types,
Navigation
build-depends: base ^>=4.21.0.0,
base64-bytestring,