{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} -- | Streaming renderer for the OPML 2.0 standard. module Text.OPML.Conduit.Render ( -- * Renderers renderOpmlHead , renderOpmlOutline , renderOpml ) where -- {{{ Imports import Control.Monad import Data.Conduit import Data.List.NonEmpty hiding (filter, map) import Data.Monoid import Data.NonNull import Data.String import Data.Text (Text, intercalate, pack, toLower) import Data.Text.Encoding import Data.Time.Clock import Data.Time.LocalTime import Data.Time.RFC822 import Data.Tree import Data.Version import Data.XML.Types import Lens.Simple import Prelude hiding (foldr, lookup, show) import qualified Prelude (show) import Text.OPML.Lens import Text.OPML.Types import Text.XML.Stream.Render import URI.ByteString -- }}} show :: (Show a, IsString t) => a -> t show = fromString . Prelude.show empty :: (Eq s, Monoid s) => s -> Bool empty t = t == mempty toMaybe :: (Eq s, Monoid s) => s -> Maybe s toMaybe s | s == mempty = mempty | otherwise = Just s formatTime :: UTCTime -> Text formatTime = formatTimeRFC822 . utcToZonedTime utc formatCategories :: [NonEmpty (NonNull Text)] -> Maybe Text formatCategories = toMaybe . intercalate "," . map (intercalate "/" . toList . fmap toNullable) formatBool :: Bool -> Text formatBool = toLower . show formatURI :: URI -> Text formatURI = decodeUtf8 . serializeURIRef' -- | Render the @\
@ section. renderOpmlHead :: (Monad m) => OpmlHead -> Source m Event renderOpmlHead input = tag "head" mempty $ do forM_ (input^.opmlCreatedL) $ tag "dateCreated" mempty . content . formatTime forM_ (input^.modifiedL) $ tag "dateModified" mempty . content . formatTime forM_ (input^.docsL) $ tag "docs" mempty . content . formatURI unless (null es) $ tag "expansionState" mempty . content . intercalate "," $ show <$> es unless (empty email) $ tag "ownerEmail" mempty $ content email forM_ (input^.ownerIdL) $ tag "ownerId" mempty . content . formatURI unless (empty name) $ tag "ownerName" mempty $ content name unless (empty title) $ tag "title" mempty $ content title forM_ (input^.vertScrollStateL) $ tag "vertScrollState" mempty . content . show forM_ (input^.windowBottomL) $ tag "windowBottom" mempty . content . show forM_ (input^.windowLeftL) $ tag "windowLeft" mempty . content . show forM_ (input^.windowRightL) $ tag "windowRight" mempty . content . show forM_ (input^.windowTopL) $ tag "windowTop" mempty . content . show where es = input ^.. expansionStateL email = input ^. ownerEmailL name = input ^. ownerNameL title = input ^. opmlTitleL -- | Render an @\