purescript-puppeteer/src/Puppeteer.Page.Event.purs

165 lines
4.7 KiB
Haskell
Raw Normal View History

2023-09-29 05:14:09 +00:00
module Puppeteer.Page.Event
( once
, listen
, eventKey
, eventData
, class Event
, connectPageConsole
, defaultEventData
, FrameEvent(..)
, UnitEvent(..)
, ErrorEvent(..)
, NullablePageEvent(..)
, RequestEvent(..)
, ResponseEvent(..)
, DialogEvent(..)
, ConsoleMessageEvent(..)
) where
import Prelude
import Control.Monad.Error.Class (liftEither, try)
2023-09-29 05:14:09 +00:00
import Control.Monad.Except (runExcept)
import Data.Bifunctor (lmap)
import Data.Either (hush, note)
import Data.Maybe (Maybe)
import Data.Nullable (Nullable)
import Data.String as String
import Effect (Effect)
import Effect.Aff (Aff, launchAff_, makeAff)
import Effect.Class (liftEffect)
import Effect.Console as Console
import Effect.Exception (Error, error)
import Effect.Unsafe (unsafePerformEffect)
import Foreign (Foreign, unsafeFromForeign)
import Puppeteer.Base (Context(..), Frame, Page, closeContext)
2023-09-29 22:32:24 +00:00
import Puppeteer.HTTP as HTTP
2023-09-29 05:14:09 +00:00
import Puppeteer.Page as Page
import Puppeteer.Page.Event.ConsoleMessage (ConsoleMessage, messageTypeString)
import Puppeteer.Page.Event.ConsoleMessage as ConsoleMessage
import Puppeteer.Page.Event.Dialog (Dialog)
import Simple.JSON (class ReadForeign, readImpl)
connectPageConsole :: Page -> Effect Unit
2023-09-29 18:23:27 +00:00
connectPageConsole p =
let
onmsg m = launchAff_ do
2023-09-29 05:14:09 +00:00
title <- Page.title p
let t = ConsoleMessage.messageType m
let textLevel = "[" <> String.toUpper (messageTypeString t) <> "]"
let textPrefix = "[Puppeteer.Page@\"" <> title <> "\"]"
let text = textLevel <> " " <> textPrefix <> " " <> ConsoleMessage.text m
liftEffect $ case t of
ConsoleMessage.Debug -> Console.debug text
ConsoleMessage.Error -> Console.error text
ConsoleMessage.Warning -> Console.warn text
_ -> Console.log text
in
launchAff_ do
stop <- liftEffect $ listen Console (void <<< try <<< onmsg) p
once Close p
closeContext stop
2023-09-29 05:14:09 +00:00
data UnitEvent
= Close
| DomContentLoaded
| Load
instance unitEvent :: Event UnitEvent Unit where
eventKey Close = "close"
eventKey DomContentLoaded = "domcontentloaded"
eventKey Load = "load"
eventData = const $ pure unit
data ErrorEvent
= Error
| PageError
instance errorEvent :: Event ErrorEvent Error where
eventKey Error = "error"
eventKey PageError = "pageerror"
eventData = pure <<< unsafeFromForeign
data FrameEvent
= FrameAttached
| FrameDetached
| FrameNavigated
instance frameEvent :: Event FrameEvent Frame where
eventKey FrameAttached = "frameattached"
eventKey FrameDetached = "framedetached"
eventKey FrameNavigated = "framenavigated"
eventData = defaultEventData
data ConsoleMessageEvent = Console
instance consoleEvent :: Event ConsoleMessageEvent ConsoleMessage where
eventKey Console = "console"
eventData = defaultEventData
data DialogEvent = Dialog
instance dialogEvent :: Event DialogEvent Dialog where
eventKey Dialog = "dialog"
eventData = defaultEventData
data NullablePageEvent = Popup
instance nullablePageEvent :: Event NullablePageEvent (Nullable Page) where
eventKey Popup = "popup"
eventData = defaultEventData
data ResponseEvent = Response
2023-09-29 22:32:24 +00:00
instance responseEvent :: Event ResponseEvent HTTP.Response where
2023-09-29 05:14:09 +00:00
eventKey Response = "response"
eventData = defaultEventData
data RequestEvent
= Request
| RequestFailed
| RequestFinished
| RequestServedFromCache
2023-09-29 22:32:24 +00:00
instance requestEvent :: Event RequestEvent HTTP.Request where
2023-09-29 05:14:09 +00:00
eventKey Request = "request"
eventKey RequestFailed = "requestfailed"
eventKey RequestFinished = "requestfinished"
eventKey RequestServedFromCache = "requestservedfromcache"
eventData = defaultEventData
class Event :: Type -> Type -> Constraint
class Event ev d | ev -> d, d -> ev where
eventKey :: ev -> String
eventData :: Foreign -> Maybe d
defaultEventData :: forall d. ReadForeign d => Foreign -> Maybe d
defaultEventData = hush <<< runExcept <<< readImpl
foreign import data ListenerToken :: Type
foreign import _once :: String -> (Foreign -> Unit) -> Page -> Effect Unit
foreign import _addListener :: String -> (Foreign -> Unit) -> Page -> Effect ListenerToken
foreign import _removeListener :: ListenerToken -> Page -> Effect Unit
once :: forall ev evd. Event ev evd => ev -> Page -> Aff evd
once ev p =
let
k = eventKey ev
f res = do
let cb = unsafePerformEffect <<< res <<< lmap error <<< note "parse failed" <<< eventData
_once k cb p
pure mempty
in
makeAff f
listen :: forall ev evd. Event ev evd => ev -> (evd -> Effect Unit) -> Page -> Effect (Context "event listener")
2023-09-29 05:14:09 +00:00
listen ev cb p =
let
cb' f = unsafePerformEffect $ do
evd <- liftEither $ lmap error $ note "parse failed" $ eventData f
cb evd
2023-09-29 05:14:09 +00:00
in
do
t <- _addListener (eventKey ev) cb' p
2023-09-29 05:14:09 +00:00
pure $ Context (\_ -> liftEffect $ _removeListener t p)