packages feed

haste-lib-0.6.0.0: src/Haste/Events/MessageEvents.hs

{-# LANGUAGE OverloadedStrings, TypeFamilies, GeneralizedNewtypeDeriving #-}
-- | Events relating to the @postMessage@ API for passing messages between
--   windows.
module Haste.Events.MessageEvents
  ( MessageEvent (..) , MessageData (..), Recipient (..), Window
  , getContentWindow, window, fromAny
  ) where
import Control.Monad.IO.Class
import Haste.JSString (JSString)
import Haste.Prim.Foreign
import Haste.Events.Core
import Haste.DOM.Core (Elem (..))

-- | A DOM window.
newtype Window = Window JSAny
  deriving (ToAny, FromAny, Eq)

class Recipient a where
  -- | Post a message to the given window. Messages are serialized using the
  --   structured clone algorithm, meaning that you can post pretty much any
  --   type of data, except functions, references and the like.
  postMessage :: (ToAny msg, MonadIO m) => a -> msg -> m ()

instance Recipient Window where
  postMessage wnd msg = liftIO $ postMessage' wnd (toAny msg)

instance EventSource Window where
  eventSource (Window e) = e

-- | The window in which the program is executing.
window :: Window
window = constant "window"

-- | Event data for keyboard events.
data MessageData = MessageData
  { messageData   :: !JSAny
  , messageOrigin :: !JSString
  , messageSource :: !Window
  }

data MessageEvent = Message

instance Event MessageEvent where
  type EventData MessageEvent = MessageData
  eventName Message = "message"
  eventData _ e =
    MessageData <$> get e "data"
                <*> get e "origin"
                <*> get e "source"

postMessage' :: Window -> JSAny -> IO ()
postMessage' = ffi "(function(w,m){w.postMessage(m,'*');})"

-- | Get the window object for an iframe. Must be called after the iframe is
--   attached to the DOM.
getContentWindow :: MonadIO m => Elem -> m (Maybe Window)
getContentWindow e = liftIO $ getContentWindow' e

getContentWindow' :: Elem -> IO (Maybe Window)
getContentWindow' = ffi "(function(e){return e.contentWindow;})"