Shpadoinkle-html-0.3.0.0: Shpadoinkle/Html/Event/Throttle.hs
{-# LANGUAGE FlexibleContexts #-}
module Shpadoinkle.Html.Event.Throttle
( throttle
, Throttle
, runThrottle
) where
import Control.Monad (when)
import Control.Monad.IO.Class (MonadIO (..))
import Data.Text (Text)
import Data.Time.Clock (NominalDiffTime, diffUTCTime,
getCurrentTime)
import Shpadoinkle (Continuation, JSM, Prop, RawEvent,
RawNode, atomically, bakedProp,
cataProp, dataProp, done, flagProp,
listenerProp, newTVarIO, readTVar,
textProp, writeTVar)
newtype Throttle m a b = Throttle { runThrottle
:: (a -> (Text, Prop m b))
-> a -> (Text, Prop m b) }
throttleRaw :: MonadIO n
=> NominalDiffTime
-> n ( (RawNode -> RawEvent -> JSM (Continuation m a))
-> RawNode -> RawEvent -> JSM (Continuation m a) )
throttleRaw duration = do
lastTriggered <- liftIO $ newTVarIO Nothing
return $ \handler rn re -> do
t1 <- liftIO getCurrentTime
continue <- liftIO . atomically $ do
t0m <- readTVar lastTriggered
case t0m of
Nothing -> do
writeTVar lastTriggered (Just t1)
return True
Just t0 -> do
let continue = diffUTCTime t1 t0 > duration
when continue $ writeTVar lastTriggered (Just t1)
return continue
if continue then handler rn re else return done
throttle :: MonadIO n
=> NominalDiffTime
-> n (Throttle m a b)
throttle duration = do
f <- throttleRaw duration
return . Throttle $ \g x ->
let (attr, p) = g x
in (attr, cataProp dataProp textProp flagProp (listenerProp . f) bakedProp p)