#{messageContent}|]
})
---------------------
diff --git a/src/Utils/Icon.hs b/src/Utils/Icon.hs
index 09299e310..4d9dd168d 100644
--- a/src/Utils/Icon.hs
+++ b/src/Utils/Icon.hs
@@ -1,6 +1,6 @@
module Utils.Icon where
-import ClassyPrelude.Yesod hiding (foldlM, Proxy)
+import ClassyPrelude.Yesod hiding (Proxy)
import Data.Universe
import Data.Char
@@ -12,6 +12,8 @@ import Language.Haskell.TH
import Language.Haskell.TH.Instances ()
import Language.Haskell.TH.Lift (deriveLift)
import Instances.TH.Lift ()
+import Data.Aeson
+import Data.Aeson.TH
-- | A @Widget@ for any site; no language interpolation, etc.
type WidgetSiteless = forall site. forall m. (MonadIO m, MonadThrow m, MonadBaseControl IO m)
@@ -23,8 +25,10 @@ type WidgetSiteless = forall site. forall m. (MonadIO m, MonadThrow m, MonadBase
-----------
-- We collect all used icons here for an overview.
-- For consistency, some conditional icons are also provided, having suffix True/False
--- IMPORTANT: Alert-Icons must be registered in alert-icons.js as well
+---------------------------------------------------------------------------
+-- IMPORTANT: Alert-Icons must be registered in alert-icons.js as well!!!
+---------------------------------------------------------------------------
data Icon
= IconNew
| IconOK
@@ -48,7 +52,7 @@ data Icon
| IconSFTHint -- for SheetFileType only
| IconSFTSolution -- for SheetFileType only
| IconSFTMarking -- for SheetFileType only
- deriving (Eq, Enum, Bounded, Show, Read)
+ deriving (Eq, Ord, Enum, Bounded, Show, Read)
iconText :: Icon -> Text
iconText = \case
@@ -75,11 +79,19 @@ iconText = \case
IconSFTSolution -> "exclamation-circle" -- for SheetFileType only
IconSFTMarking -> "check-circle" -- for SheetFileType only
+-- | like iconText, but eliminates '-' since these are problemativ in alert-icons.js
+iconJS :: Icon -> Text
+iconJS = filter ('-' /=) . iconText
+
instance Universe Icon
instance Finite Icon
nullaryPathPiece ''Icon $ camelToPathPiece' 1
deriveLift ''Icon
+deriveJSON defaultOptions
+ { constructorTagModifier = camelToPathPiece' 1
+ } ''Icon
+
-- Create an icon from font-awesome without additional space
icon :: Icon -> Markup
icon ic = let ict = iconText ic in
@@ -93,11 +105,10 @@ iconShortcuts = foldMap mkIcon (universeF :: [Icon])
where
mkIcon :: Icon -> Q [Dec]
mkIcon ic = do
- do
- iname <- newName $ over (ix 0) Data.Char.toLower $ show ic
- isig <- sigD iname [t|Markup|]
- idef <- valD (varP iname) (normalB [|icon ic|]) []
- return $ [isig, idef]
+ iname <- newName $ over (ix 0) Data.Char.toLower $ show ic
+ isig <- sigD iname [t|Markup|]
+ idef <- valD (varP iname) (normalB [|icon ic|]) []
+ return [isig, idef]
----------------------
@@ -140,7 +151,7 @@ iconEnrol False = icon IconEnrolFalse
iconExamRegister :: Bool -> Markup
iconExamRegister True = icon IconExamRegisterTrue
-iconExamRegister False = icon IconExamRegisterTrue
+iconExamRegister False = icon IconExamRegisterFalse
----------------
diff --git a/src/Utils/Message.hs b/src/Utils/Message.hs
index c4153b17d..4302dac79 100644
--- a/src/Utils/Message.hs
+++ b/src/Utils/Message.hs
@@ -1,19 +1,23 @@
module Utils.Message
- ( MessageStatus(..)
+ ( MessageStatus(..), MessageIconStatus(..)
, UnknownMessageStatus(..)
+ , getMessages
+ , addMessage',addMessageIcon, addMessageIconI -- messages with special icons (needs registering in alert-icons.js)
, addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget
, statusToUrgencyClass
, Message(..)
, messageI, messageIHamlet, messageFile, messageWidget
+ , encodeMessageIconStatus, decodeMessageIconStatus, decodeMessageIconStatus'
) where
import Data.Universe
+import Utils.Icon
import Utils.PathPiece
import Data.Aeson
import Data.Aeson.TH
-import qualified ClassyPrelude.Yesod (addMessage, addMessageI)
-import ClassyPrelude.Yesod hiding (addMessage, addMessageI)
+import qualified ClassyPrelude.Yesod (addMessage, addMessageI, getMessages)
+import ClassyPrelude.Yesod hiding (addMessage, addMessageI, getMessages)
import Text.Hamlet
@@ -28,8 +32,11 @@ import Text.HTML.SanitizeXSS (sanitizeBalance)
data MessageStatus = Error | Warning | Info | Success
deriving (Eq, Ord, Enum, Bounded, Show, Read, Lift)
+
instance Universe MessageStatus
instance Finite MessageStatus
+instance Default MessageStatus where
+ def = Info
deriveJSON defaultOptions
{ constructorTagModifier = camelToPathPiece
@@ -43,11 +50,52 @@ newtype UnknownMessageStatus = UnknownMessageStatus Text
instance Exception UnknownMessageStatus
+-- ms2mis :: MessageStatus -> MessageIconStatus
+-- ms2mis s = def { misStatus= s}
+
+data MessageIconStatus = MIS { misStatus :: MessageStatus, misIcon :: Maybe Icon }
+ deriving (Eq, Ord, Show, Read, Lift)
+
+instance Default MessageIconStatus where
+ def = MIS { misStatus=def, misIcon=Nothing }
+
+deriveJSON defaultOptions
+ { fieldLabelModifier = camelToPathPiece' 1
+ } ''MessageIconStatus
+
+encodeMessageStatus :: MessageStatus -> Text
+encodeMessageStatus ms = encodeMessageIconStatus $ def{ misStatus=ms }
+
+encodeMessageIconStatus :: MessageIconStatus -> Text
+encodeMessageIconStatus = decodeUtf8 . toStrict . encode
+
+decodeMessageIconStatus :: Text -> Maybe MessageIconStatus
+decodeMessageIconStatus = decode' . fromStrict . encodeUtf8
+
+decodeMessageIconStatus' :: Text -> MessageIconStatus
+decodeMessageIconStatus' t
+ | Just mis <- decodeMessageIconStatus t = mis
+ | otherwise = def
+
+decodeMessage :: (Text, Html) -> Message
+decodeMessage (mis, msgContent)
+ | Just MIS{ misStatus=messageStatus, misIcon=messageIcon } <- decodeMessageIconStatus mis
+ = let messageContent = msgContent in Message{..}
+ | Just messageStatus <- fromPathPiece mis
+ = let messageIcon = Nothing -- legacy case, should no longer occur ($logDebug ???)
+ messageContent = msgContent <> "!!!"
+ in Message{..}
+ | otherwise -- should not happen, if refactored correctly ($logDebug ???)
+ = let messageStatus = Utils.Message.Warning
+ messageContent = msgContent <> "!!!!"
+ messageIcon = Nothing
+ in Message{..}
+
data Message = Message
- { messageStatus :: MessageStatus
+ { messageStatus :: MessageStatus
, messageContent :: Html
- -- , messageIcon :: Maybe Icon
+ , messageIcon :: Maybe Icon
}
instance Eq Message where
@@ -60,26 +108,39 @@ instance ToJSON Message where
toJSON Message{..} = object
[ "status" .= messageStatus
, "content" .= renderHtml messageContent
+ , "icon" .= messageIcon
]
instance FromJSON Message where
parseJSON = withObject "Message" $ \o -> do
messageStatus <- o .: "status"
messageContent <- preEscapedText . sanitizeBalance <$> o .: "content"
+ messageIcon <- o .: "icon"
return Message{..}
statusToUrgencyClass :: MessageStatus -> Text
statusToUrgencyClass status = "urgency__" <> toPathPiece status
+addMessage' :: MonadHandler m => Message -> m ()
+addMessage' Message{..} = ClassyPrelude.Yesod.addMessage (encodeMessageIconStatus mis) messageContent
+ where mis = MIS{misStatus=messageStatus, misIcon=messageIcon}
+
+addMessageIcon :: MonadHandler m => MessageStatus -> Icon -> Html -> m ()
+addMessageIcon ms mi = ClassyPrelude.Yesod.addMessage $ encodeMessageIconStatus MIS{misStatus=ms, misIcon=Just mi}
+
+addMessageIconI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageStatus -> Icon -> msg -> m ()
+addMessageIconI ms mi = ClassyPrelude.Yesod.addMessageI $ encodeMessageIconStatus MIS{misStatus=ms, misIcon=Just mi}
+
addMessage :: MonadHandler m => MessageStatus -> Html -> m ()
-addMessage mc = ClassyPrelude.Yesod.addMessage (toPathPiece mc)
+addMessage mc = ClassyPrelude.Yesod.addMessage $ encodeMessageStatus mc
addMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageStatus -> msg -> m ()
-addMessageI mc = ClassyPrelude.Yesod.addMessageI (toPathPiece mc)
+addMessageI mc = ClassyPrelude.Yesod.addMessageI $ encodeMessageStatus mc
messageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageStatus -> msg -> m Message
messageI messageStatus msg = do
messageContent <- toHtml . ($ msg) <$> getMessageRender
+ let messageIcon = Nothing
return Message{..}
addMessageIHamlet :: ( MonadHandler m
@@ -88,15 +149,16 @@ addMessageIHamlet :: ( MonadHandler m
) => MessageStatus -> HtmlUrlI18n msg (Route site) -> m ()
addMessageIHamlet mc iHamlet = do
mr <- getMessageRender
- ClassyPrelude.Yesod.addMessage (toPathPiece mc) =<< withUrlRenderer (iHamlet $ toHtml . mr)
+ ClassyPrelude.Yesod.addMessage (encodeMessageStatus mc) =<< withUrlRenderer (iHamlet $ toHtml . mr)
messageIHamlet :: ( MonadHandler m
, RenderMessage (HandlerSite m) msg
, HandlerSite m ~ site
) => MessageStatus -> HtmlUrlI18n msg (Route site) -> m Message
-messageIHamlet mc iHamlet = do
+messageIHamlet ms iHamlet = do
mr <- getMessageRender
- Message mc <$> withUrlRenderer (iHamlet $ toHtml . mr)
+ let mi = Nothing
+ Message ms <$> withUrlRenderer (iHamlet $ toHtml . mr) <*> pure mi
addMessageFile :: MessageStatus -> FilePath -> ExpQ
addMessageFile mc tPath = [e|addMessageIHamlet mc $(ihamletFile tPath)|]
@@ -123,3 +185,9 @@ messageWidget :: forall m site.
messageWidget mc wgt = do
PageContent{pageBody} <- liftHandlerT $ widgetToPageContent wgt
messageIHamlet mc (const pageBody :: HtmlUrlI18n (SomeMessage site) (Route site))
+
+
+getMessages :: MonadHandler m => m [Message]
+getMessages = fmap decodeMessage <$> ClassyPrelude.Yesod.getMessages
+
+
diff --git a/templates/widgets/alerts/alerts.hamlet b/templates/widgets/alerts/alerts.hamlet
index 8ddc0f6cd..0dd303f8a 100644
--- a/templates/widgets/alerts/alerts.hamlet
+++ b/templates/widgets/alerts/alerts.hamlet
@@ -1,15 +1,15 @@
$newline never
- $forall (status, msg) <- mmsgs
- $with status2 <- bool status "info" (status == "")
-
-
+ $forall Message{..} <- mmsgs
+ $with icn <- maybeAttribute "data-icon" iconJS messageIcon
+
- #{msg}
+ #{messageContent}
+