react-haskell-2.0.0: src/React/Events.hs
{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, DeriveGeneric,
FlexibleInstances #-}
module React.Events
( EventProperties(..)
, Target(..)
, ModifierKeys(..)
, MouseEvent(..)
, KeyboardEvent(..)
, ChangeEvent(..)
, FocusEvent(..)
, BlurEvent(..)
-- * Native Events
, onBlur
, onFocus
, onChange
, onKeyDown
, onKeyPress
, onKeyUp
, onMouseEnter
, onMouseLeave
, onDoubleClick
, onClick
-- * Synthetic Events
, onEnter
) where
import Control.Applicative
import Control.DeepSeq
import Control.Monad
import Data.Maybe
import GHC.Generics
import System.IO.Unsafe
import React.GHCJS
import React.Imports
import React.Types
mkEventHandler :: (FromJSRef evt, NFData evt)
=> EvtType
-> (evt -> Maybe signal)
-> AttrOrHandler signal
mkEventHandler ty handle =
let handle' raw = handle $!! fromJust $ unsafePerformIO $ fromJSRef $ castRef raw
in Handler (EventHandler handle' ty)
-- | Low level properties common to all events
data EventProperties e =
EventProperties { bubbles :: !Bool
, cancelable :: !Bool
, currentTarget :: !e -- NativeElem
, defaultPrevented :: !Bool
, eventPhase :: !Int
, isTrusted :: !Bool
-- , nativeEvent :: DOMEvent
-- , preventDefault :: IO ()
-- , stopPropagation :: IO ()
, evtTarget :: !e -- NativeElem
--, timeStamp :: Date
, eventType :: !JSString -- type
}
instance NFData e => NFData (EventProperties e) where
rnf (EventProperties a b c d e f g h) =
a `seq` b `seq` c `seq` d `seq` e `seq` f `seq` g `seq` h `seq` ()
data ModifierKeys =
ModifierKeys { altKey :: !Bool
, ctrlKey :: !Bool
, metaKey :: !Bool
, shiftKey :: !Bool
} deriving (Eq, Show, Generic)
instance FromJSRef ModifierKeys where
instance NFData ModifierKeys where
rnf (ModifierKeys a b c d) = a `seq` b `seq` c `seq` d `seq` ()
data MouseEvent =
MouseEvent { -- mouseEventProperties :: !(EventProperties e)
-- mouseModifierKeys :: !ModifierKeys
-- , buttonNum :: !Int -- "button"
-- , buttons :: Int
clientX :: !Double
, clientY :: !Double
, pageX :: !Double
, pageY :: !Double
-- , relatedTarget :: Unpacked
, screenX :: !Double
, screenY :: !Double
} deriving (Show, Generic)
instance FromJSRef MouseEvent where
instance NFData MouseEvent where
-- rnf (MouseEvent a b c d e f g h) =
-- a `seq` b `seq` c `seq` d `seq` e `seq` f `seq` g `seq` h `seq` ()
rnf (MouseEvent a b c d e f) =
a `seq` b `seq` c `seq` d `seq` e `seq` f `seq` ()
data KeyboardEvent =
KeyboardEvent { -- keyboardEventProperties :: ! (EventProperties e)
-- keyboardModifierKeys :: !ModifierKeys
charCode :: !Int
, key :: !JSString
, keyCode :: !Int
-- , locale :: !JSString
, location :: !Int
, repeat :: !Bool
, which :: !Int
} deriving (Show, Generic)
instance FromJSRef KeyboardEvent where
instance NFData KeyboardEvent where
rnf (KeyboardEvent a b c d e f) =
a `seq` b `seq` c `seq` d `seq` e `seq` f `seq` ()
data Target = Target
{ value :: !JSString
, tagName :: !JSString
-- XXX(joel) This is gross. Added a second field so that the generic
-- FromJSRef instance does the right thing. Without a second field it
-- uses the FromJSRef instance for `value`.
} deriving (Show, Generic)
instance FromJSRef Target where
data ChangeEvent = ChangeEvent
{ target :: !Target
, timeStamp :: !Int
} deriving (Show, Generic)
instance FromJSRef ChangeEvent where
instance NFData ChangeEvent where
rnf e@(ChangeEvent str stamp) = str `seq` stamp `seq` ()
-- data FocusEvent e =
-- FocusEvent { -- focusEventProperties :: ! (EventProperties e)
-- domEventTarget :: !e -- NativeElem
-- , relatedTarget :: !e -- NativeElem
-- }
-- instance NFData e => NFData (FocusEvent e) where
-- rnf (FocusEvent a b) = a `seq` b `seq` ()
data FocusEvent = FocusEvent deriving Generic
instance NFData FocusEvent
instance FromJSRef FocusEvent where
data BlurEvent = BlurEvent deriving (Show, Generic)
instance FromJSRef BlurEvent where
instance NFData BlurEvent
-- XXX isn't this in GHCJS.Prim?
instance Eq JSString where
(==) = eqRef
-- TODO: handle (a -> Maybe b) or (a -> b)
onBlur :: (BlurEvent -> Maybe s) -> AttrOrHandler s
onBlur = mkEventHandler BlurEvt
onFocus :: (FocusEvent -> Maybe s) -> AttrOrHandler s
onFocus = mkEventHandler FocusEvt
onChange :: (ChangeEvent -> Maybe s) -> AttrOrHandler s
onChange = mkEventHandler ChangeEvt
onKeyDown :: (KeyboardEvent -> Maybe s) -> AttrOrHandler s
onKeyDown = mkEventHandler KeyDownEvt
onKeyPress :: (KeyboardEvent -> Maybe s) -> AttrOrHandler s
onKeyPress = mkEventHandler KeyPressEvt
onKeyUp :: (KeyboardEvent -> Maybe s) -> AttrOrHandler s
onKeyUp = mkEventHandler KeyUpEvt
onMouseEnter :: (MouseEvent -> Maybe s) -> AttrOrHandler s
onMouseEnter = mkEventHandler MouseEnterEvt
onMouseLeave :: (MouseEvent -> Maybe s) -> AttrOrHandler s
onMouseLeave = mkEventHandler MouseLeaveEvt
onDoubleClick :: (MouseEvent -> Maybe s) -> AttrOrHandler s
onDoubleClick = mkEventHandler DoubleClickEvt
onClick :: (MouseEvent -> Maybe s) -> AttrOrHandler s
onClick = mkEventHandler ClickEvt
onEnter :: s -> AttrOrHandler s
onEnter s = onKeyPress handler where
handler KeyboardEvent{key="Enter"} = Just s
handler _ = Nothing