packages feed

keera-hails-reactive-htmldom-0.6.0: src/Hails/MVC/View/HTML.hs

-- |
--
-- Copyright   : (C) Keera Studios Ltd, 2013
-- License     : BSD3
-- Maintainer  : support@keera.co.uk
module Hails.MVC.View.HTML where

import Control.Applicative            ((<$>))
import Control.Monad                  (void)
import Control.Monad.IO.Class         (liftIO)
import Control.Monad.Reader           (ask)
import Data.CBMVar                    (installCallbackCBMVar, newCBMVar,
                                       readCBMVar, writeCBMVar)
import Data.CBMVar.Reactive           (cbmvarReactiveRO, cbmvarReactiveRW)
import Data.ReactiveValue
import Data.String
import GHCJS.DOM.Element              (IsElement, setInnerHTML)
import GHCJS.DOM.EventM               (mouseButton, mouseClientXY, on)
import GHCJS.DOM.EventTargetClosures  (EventName, unsafeEventName)
import GHCJS.DOM.GlobalEventHandlers  (input, mouseDown, mouseMove)
import GHCJS.DOM.HTMLElement          (setInnerText)
import GHCJS.DOM.HTMLInputElement     (getValue, setValue)
import GHCJS.DOM.HTMLParagraphElement (HTMLParagraphElement (..))
import GHCJS.DOM.MessageEvent         (getData)
import GHCJS.DOM.Types                (HTMLElement, HTMLInputElement (..),
                                       IsGlobalEventHandlers, IsHTMLElement,
                                       JSString, MouseEvent, fromJSValUnchecked,
                                       toHTMLElement, toJSString)
import GHCJS.DOM.WebSocket            (WebSocket, message, sendString)

-- * GHCJS DOM Reactive API
inputTextReactive :: HTMLInputElement -> ReactiveFieldReadWrite IO String
inputTextReactive x = ReactiveFieldReadWrite setter getter notifier
 where setter = setValue x
       getter = getValue x
       notifier p = void $ on x input (liftIO p)

htmlElementClick :: IsHTMLElement e => e -> ReactiveFieldRead IO ()
htmlElementClick e = ReactiveFieldRead (return ()) (\p -> void $ on e' click (liftIO p))
  where
    e' = toHTMLElement e

click :: EventName HTMLElement MouseEvent
click = unsafeEventName (toJSString "click")

paragraphTextReactive :: HTMLParagraphElement -> ReactiveFieldWrite IO String
paragraphTextReactive x = ReactiveFieldWrite setter
 where setter = setInnerHTML x

websocketReactive :: WebSocket -> IO (ReactiveFieldReadWrite IO String)
websocketReactive socket = do
    p <- newCBMVar ""
    void $ on socket message (ask >>= \dt -> getData dt >>= \js -> liftIO (fromJSValUnchecked js) >>= \jss -> liftIO (writeCBMVar p (show (jss :: JSString))))
    let getter     = readCBMVar p
        notifier n = installCallbackCBMVar p n
        setter x   = do
           sendString socket (fromString x :: JSString)
           writeCBMVar p x
    return (ReactiveFieldReadWrite setter getter notifier)

mouseDownReactive :: (IsGlobalEventHandlers a, IsElement a) => a -> ReactiveFieldRead IO ()
mouseDownReactive s = eventR $ \p -> void $ on s mouseDown (liftIO p)

mousePosElementReactive :: (IsGlobalEventHandlers e, IsElement e) => e -> IO (ReactiveFieldRead IO (Int, Int))
mousePosElementReactive e = do
  p <- newCBMVar (0,0)
  void $ on e mouseMove (mouseClientXY >>= \pos -> liftIO (writeCBMVar p pos))
  return (cbmvarReactiveRO p)