Skip to content

Commit

Permalink
Merge pull request #320 from dmjio/dwaldhalm-mount_to_existing_dom_el…
Browse files Browse the repository at this point in the history
…ement

addresses issue # 223
  • Loading branch information
dmjio authored Nov 30, 2017
2 parents ab4db2a + 4c7ce8f commit ef0831f
Show file tree
Hide file tree
Showing 21 changed files with 76 additions and 32 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ main = startApp App {..}
update = updateModel -- update function
view = viewModel -- view function
events = defaultEvents -- default delegated events
mountPoint = Nothing -- mount point for miso on DOM, defaults to body
subs = [] -- empty subscription list
-- | Updates model, optionally introduces side effects
Expand Down
1 change: 1 addition & 0 deletions examples/canvas2d/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ main = do
model = (0.0, 0.0)
subs = []
events = defaultEvents
mountPoint = Nothing -- default to body

updateModel
:: (Image,Image,Image)
Expand Down
1 change: 1 addition & 0 deletions examples/compose-update/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ main = startApp App { initialAction = NoOp, ..}
view = viewModel
events = defaultEvents
subs = []
mountPoint = Nothing

viewModel :: Model -> View Action
viewModel (x, y) =
Expand Down
1 change: 1 addition & 0 deletions examples/file-reader/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ main = do
, ..
}
where
mountPoint = Nothing
update = updateModel
events = defaultEvents
subs = []
Expand Down
1 change: 1 addition & 0 deletions examples/haskell-miso.org/client/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ main = do
miso App { model = Model currentURI False, ..}
where
initialAction = NoOp
mountPoint = Nothing
update = updateModel
events = defaultEvents
subs = [ uriSub HandleURI ]
Expand Down
1 change: 1 addition & 0 deletions examples/mario/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ main = do
subs = [ arrowsSub GetArrows
, windowSub WindowCoords
]
mountPoint = Nothing

data Model = Model
{ x :: !Double
Expand Down
1 change: 1 addition & 0 deletions examples/router/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ main = do
events = defaultEvents
subs = [ uriSub HandleURI ]
view = viewModel
mountPoint = Nothing

-- | Update your model
updateModel :: Action -> Model -> Effect Action Model
Expand Down
1 change: 1 addition & 0 deletions examples/sse/client/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ main = do
either (const the404) id . runRoute (Proxy :: Proxy ClientRoutes) handlers
events = defaultEvents
subs = [sseSub "/sse" handleSseMsg, uriSub HandleURI]
mountPoint = Nothing

handleSseMsg :: SSE String -> Action
handleSseMsg (SSEMessage msg) = ServerMsg msg
Expand Down
1 change: 1 addition & 0 deletions examples/svg/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ main = startApp App {..}
view = viewModel
events = defaultEvents
subs = [ mouseSub HandleMouse ]
mountPoint = Nothing

emptyModel :: Model
emptyModel = Model (0,0)
Expand Down
15 changes: 8 additions & 7 deletions examples/three/Main.hs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE RecordWildCards #-}
module Main where

import Control.Monad
import Data.IORef
import GHCJS.Types
import Control.Monad
import Data.IORef
import qualified Data.Map as M
import GHCJS.Types

import Miso
import Miso.String
import Miso
import Miso.String

data Action
= GetTime
Expand Down Expand Up @@ -58,6 +58,7 @@ main = do
startApp App { model = m
, initialAction = Init
, update = updateModel ref
, mountPoint = Nothing
, ..
}
where
Expand All @@ -68,7 +69,7 @@ main = do
viewModel :: Double -> View action
viewModel _ = div_ [] [
div_ [ id_ "stats"
, style_ [("position", "absolute")]
, style_ $ M.singleton "position" "absolute"
] []
, canvas_ [ id_ "canvas"
, width_ "400"
Expand Down
11 changes: 6 additions & 5 deletions examples/todo-mvc/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ data Msg
main :: IO ()
main = startApp App { initialAction = NoOp, ..}
where
model = emptyModel
update = updateModel
view = viewModel
events = defaultEvents
subs = []
model = emptyModel
update = updateModel
view = viewModel
events = defaultEvents
mountPoint = Nothing
subs = []

updateModel :: Msg -> Model -> Effect Msg Model
updateModel NoOp m = noEff m
Expand Down
1 change: 1 addition & 0 deletions examples/websocket/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ main = startApp App { initialAction = Id, ..}
view = appView
uri = URL "wss://echo.websocket.org"
protocols = Protocols [ ]
mountPoint = Nothing

updateModel :: Action -> Model -> Effect Action Model
updateModel (HandleWebSocket (WebSocketMessage (Message m))) model
Expand Down
1 change: 1 addition & 0 deletions examples/xhr/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ main :: IO ()
main = do
startApp App { model = Model Nothing
, initialAction = NoOp
, mountPoint = Nothing
, ..
}
where
Expand Down
1 change: 1 addition & 0 deletions exe/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ main = startApp App { initialAction = SayHelloWorld, ..}
update = updateModel
view = viewModel
events = defaultEvents
mountPoint = Nothing
subs = []

updateModel :: Action -> Model -> Effect Action Model
Expand Down
8 changes: 5 additions & 3 deletions ghcjs-src/Miso.hs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ common App {..} m getView = do
void . forkIO . forever $ threadDelay (1000000 * 86400) >> notify
-- Retrieves reference view
viewRef <- getView writeEvent
-- know thy mountElement
mountEl <- mountElement mountPoint
-- Begin listening for events in the virtual dom
delegator viewRef events
delegator mountEl viewRef events
-- Process initial action of application
writeEvent initialAction
-- Program loop, blocking on SkipChan
Expand All @@ -90,7 +92,7 @@ common App {..} m getView = do
=<< view <$> readIORef modelRef
oldVTree <- readIORef viewRef
void $ waitForAnimationFrame
Just oldVTree `diff` Just newVTree
(diff mountPoint) (Just oldVTree) (Just newVTree)
atomicWriteIORef viewRef newVTree

-- | Runs an isomorphic miso application
Expand All @@ -114,7 +116,7 @@ startApp app@App {..} =
common app model $ \writeEvent -> do
let initialView = view model
initialVTree <- flip runView writeEvent initialView
Nothing `diff` (Just initialVTree)
(diff mountPoint) Nothing (Just initialVTree)
newIORef initialVTree

-- | Helper
Expand Down
8 changes: 5 additions & 3 deletions ghcjs-src/Miso/Delegate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ import Miso.FFI
import qualified JavaScript.Object.Internal as OI
import GHCJS.Foreign.Callback
import GHCJS.Marshal
import GHCJS.Types (JSVal)

-- | Entry point for event delegation
delegator
:: IORef VTree
:: JSVal
-> IORef VTree
-> M.Map MisoString Bool
-> IO ()
delegator vtreeRef es = do
delegator mountPointElement vtreeRef es = do
evts <- toJSVal (M.toList es)
getVTreeFromRef <- syncCallback' $ do
VTree (OI.Object val) <- readIORef vtreeRef
pure val
delegateEvent evts getVTreeFromRef
delegateEvent mountPointElement evts getVTreeFromRef

36 changes: 29 additions & 7 deletions ghcjs-src/Miso/Diff.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
-- Stability : experimental
-- Portability : non-portable
----------------------------------------------------------------------------
module Miso.Diff ( diff ) where
module Miso.Diff ( diff
, mountElement
) where

import GHCJS.Foreign.Internal hiding (Object)
import GHCJS.Types
Expand All @@ -16,21 +18,41 @@ import JavaScript.Object.Internal
import Miso.Html.Internal

-- | Entry point for diffing / patching algorithm
diff :: Maybe VTree -> Maybe VTree -> IO ()
diff current new = do
body <- getBody
diff :: Maybe JSString -> Maybe VTree -> Maybe VTree -> IO ()
diff mayElem current new =
case mayElem of
Nothing -> do
body <- getBody
diffElement body current new
Just elemId -> do
e <- getElementById elemId
diffElement e current new

-- | diffing / patching a given element
diffElement :: JSVal -> Maybe VTree -> Maybe VTree -> IO ()
diffElement mountEl current new = do
case (current, new) of
(Nothing, Nothing) -> pure ()
(Just (VTree current'), Just (VTree new')) -> do
diff' current' new' body
diff' current' new' mountEl
(Nothing, Just (VTree new')) -> do
diff' (Object jsNull) new' body
diff' (Object jsNull) new' mountEl
(Just (VTree current'), Nothing) -> do
diff' current' (Object jsNull) body
diff' current' (Object jsNull) mountEl

-- | return the configured mountPoint element or the body
mountElement :: Maybe JSString -> IO JSVal
mountElement mayMp =
case mayMp of
Nothing -> getBody
Just eid -> getElementById eid

foreign import javascript unsafe "$r = document.body;"
getBody :: IO JSVal

foreign import javascript unsafe "$r = document.getElementById($1);"
getElementById :: JSString -> IO JSVal

foreign import javascript unsafe "diff($1, $2, $3);"
diff'
:: Object -- ^ current object
Expand Down
5 changes: 3 additions & 2 deletions ghcjs-src/Miso/FFI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ foreign import javascript unsafe "copyDOMIntoVTree($1);"

-- | Event delegation FFI, routes events received on body through the virtual dom
-- Invokes event handler when found
foreign import javascript unsafe "delegate($1, $2);"
foreign import javascript unsafe "delegate($1, $2, $3);"
delegateEvent
:: JSVal -- ^ Events
:: JSVal -- ^ mountPoint element
-> JSVal -- ^ Events
-> Callback (IO JSVal) -- ^ Virtual DOM callback
-> IO ()

Expand Down
2 changes: 2 additions & 0 deletions ghcjs-src/Miso/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ data App model action = App
-- ^ List of delegated events that the body element will listen for
, initialAction :: action
-- ^ Initial action that is run after the application has loaded
, mountPoint :: Maybe MisoString
-- ^ root element for DOM diff
}

-- | A monad for succinctly expressing model transitions in the 'update' function.
Expand Down
10 changes: 5 additions & 5 deletions jsbits/delegate.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* event delegation algorithm */
function delegate(events, getVTree) {
function delegate(mountPointElement, events, getVTree) {
for (var event in events) {
document.body.addEventListener(events[event][0], function(e) {
mountPointElement.addEventListener(events[event][0], function(e) {
delegateEvent ( e
, getVTree()
, buildTargetToBody(document.body, e.target)
, buildTargetToElement(mountPointElement, e.target)
, []
);
}, events[event][1]);
Expand Down Expand Up @@ -49,9 +49,9 @@ function delegateEvent (event, obj, stack, parentStack) {
}
}

function buildTargetToBody (body, target) {
function buildTargetToElement (element, target) {
var stack = [];
while (body !== target) {
while (element !== target) {
stack.unshift (target);
target = target.parentNode;
}
Expand Down
1 change: 1 addition & 0 deletions sample-app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ main = startApp App {..}
view = viewModel -- view function
events = defaultEvents -- default delegated events
subs = [] -- empty subscription list
mountPoint = Nothing -- mount point for application (Nothing defaults to 'body')

-- | Updates model, optionally introduces side effects
updateModel :: Action -> Model -> Effect Action Model
Expand Down

0 comments on commit ef0831f

Please sign in to comment.