Skip to content

Commit

Permalink
patch event listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
EugeneN committed Sep 4, 2017
1 parent c352364 commit d659f72
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
25 changes: 19 additions & 6 deletions src/Data/VirtualDOM.hs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ data DOM l = DOM
, setAttribute :: String -> String -> l -> IO ()
, removeAttribute :: String -> l -> IO ()
, addEventListener :: String -> (JSVal -> IO ()) -> l -> IO ()
, removeEventListener :: String -> l -> IO ()
}

domAPI :: DOM DOM.Node
Expand All @@ -95,6 +96,7 @@ domAPI = DOM
, setAttribute = DOM.setAttribute
, removeAttribute = DOM.removeAttribute
, addEventListener = DOM.addEventListener
, removeEventListener = DOM.removeEventListener
}

newtype Elem = Elem JSVal
Expand All @@ -108,14 +110,22 @@ createEl api e = do
mapM_ (createEl api >=> flip (appendChild api) el) (children e)
return el

addListener :: DOM l-> l -> EventListener l-> IO ()
addListener :: DOM l -> l -> EventListener l -> IO ()
addListener api target (On n handler) = addEventListener api n handler target

changed :: VNode l-> VNode l-> Bool
removeListener :: DOM l -> l -> EventListener l -> IO ()
removeListener api target (On n _) = removeEventListener api n target

changed :: VNode l -> VNode l-> Bool
changed (Text t1) (Text t2) = t1 /= t2
changed e1 e2 = name e1 /= name e2

updateProps :: DOM l-> l -> Props -> Props -> IO ()
updateListeners :: DOM l -> l -> [EventListener l] -> [EventListener l] -> IO ()
updateListeners api me oldListeners newListeners = do
mapM_ (removeListener api me) oldListeners
mapM_ (addListener api me) newListeners

updateProps :: DOM l -> l -> Props -> Props -> IO ()
updateProps api target old new =
mapM_ update (Map.keys (Map.union old new))
where
Expand All @@ -125,8 +135,10 @@ updateProps api target old new =
setAttribute api key value target
(Just _, Nothing) ->
removeAttribute api key target
(Just prev, Just next) ->
when (prev /= next) (setAttribute api key next target)
-- (Just prev, Just next) ->
(Just _, Just next) ->
setAttribute api key next target
-- when (prev /= next) (setAttribute api key next target) -- TODO skip comparison only for event listeners
(Nothing, Nothing) ->
return ()

Expand Down Expand Up @@ -180,7 +192,8 @@ patchIndexed api parent (Just old) (Just new) index = do
replaceChild api n me parent
else do
case (old, new) of
(Element {props = oldProps}, Element {props = newProps}) ->
(Element {props = oldProps, listeners = oldListeners}, Element {props = newProps, listeners = newListeners}) -> do
updateListeners api me oldListeners newListeners
updateProps api me oldProps newProps
(_, _) -> return ()
walkChildren api me old new
Expand Down
13 changes: 12 additions & 1 deletion src/Data/VirtualDOM/DOM.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}

module Data.VirtualDOM.DOM where

-- import Foundation
Expand Down Expand Up @@ -61,6 +63,10 @@ addEventListener eventName f (Node node) = do
cb <- asyncCallback1 f
js_addEventListener (toJSString eventName) cb node

removeEventListener :: String -> Node -> IO ()
removeEventListener eventName (Node node) = do
js_removeEventListener (toJSString eventName) node

-- FFI

foreign import javascript unsafe "document.createElement($1)"
Expand Down Expand Up @@ -93,7 +99,12 @@ foreign import javascript unsafe "$3.setAttribute($1, $2);"
foreign import javascript unsafe "$2.removeAttribute($1);"
js_removeAttribute :: JSString -> JSVal -> IO ()

foreign import javascript unsafe "$3.addEventListener($1, $2);"
foreign import javascript unsafe "function(eventName, handler, node){ node.addEventListener(eventName, handler); node.__zzz = node.__zzz || {}; node.__zzz[eventName] = node.__zzz[eventName] || []; node.__zzz[eventName].push(handler); }($1, $2, $3)"
js_addEventListener :: JSString -> Callback (JSVal -> IO()) -> JSVal -> IO ()

-- XXX currently js_removeEventListener removes _all_ event listeners for a given event name
-- TODO remove event listeners individually (is it possible at all?)
foreign import javascript unsafe "function(eventName, node){ if(node.__zzz && node.__zzz[eventName]) { for(var i=0; i < node.__zzz[eventName].length; i++) { node.removeEventListener(eventName, node.__zzz[eventName][i]); } node.__zzz[eventName] = []; } }($1, $2)"
js_removeEventListener :: JSString -> JSVal -> IO ()

--

0 comments on commit d659f72

Please sign in to comment.