miso 0.9.0.0 → 0.10.0.0
raw patch · 23 files changed
+87/−54 lines, 23 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Miso.Router: FailFatal :: RoutingError
Files
- README.md +4/−3
- examples/canvas2d/Main.hs +1/−0
- examples/compose-update/Main.hs +1/−0
- examples/file-reader/Main.hs +1/−0
- examples/mario/Main.hs +1/−0
- examples/router/Main.hs +1/−0
- examples/svg/Main.hs +1/−0
- examples/three/Main.hs +8/−7
- examples/todo-mvc/Main.hs +6/−5
- examples/websocket/Main.hs +1/−0
- examples/xhr/Main.hs +1/−0
- exe/Main.hs +1/−0
- ghc-src/Miso.hs +2/−0
- ghcjs-src/Miso.hs +5/−3
- ghcjs-src/Miso/Delegate.hs +5/−3
- ghcjs-src/Miso/Diff.hs +29/−7
- ghcjs-src/Miso/FFI.hs +3/−2
- ghcjs-src/Miso/Subscription/History.hs +2/−2
- ghcjs-src/Miso/Types.hs +2/−0
- jsbits/delegate.js +5/−5
- jsbits/diff.js +0/−4
- miso.cabal +1/−1
- src/Miso/Router.hs +6/−12
README.md view
@@ -33,7 +33,7 @@ </a> </p> -**Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework featuring a virtual-dom, diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies.+**Miso** is a small "[isomorphic](http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/)" [Haskell](https://www.haskell.org/) front-end framework for quickly building highly interactive single-page web applications. It features a virtual-dom, diffing / patching algorithm, attribute and property normalization, event delegation, event batching, SVG, Server-sent events, Websockets, type-safe [servant](https://haskell-servant.github.io/)-style routing and an extensible Subscription-based subsystem. Inspired by [Elm](http://elm-lang.org/), [Redux](http://redux.js.org/) and [Bobril](http://github.com/bobris/bobril). **Miso** is pure by default, but side effects (like `XHR`) can be introduced into the system via the `Effect` data type. **Miso** makes heavy use of the [GHCJS](https://github.com/ghcjs/ghcjs) FFI and therefore has minimal dependencies. ## Table of Contents - [Quick Start](#quick-start)@@ -225,8 +225,8 @@ result = import (pkgs.fetchFromGitHub { owner = "dmjio"; repo = "miso";- sha256 = "13ckz11gbfs047hl3phj7h6fm59wsg9zw2fiqjaqkxmxv17zj5yj";- rev = "0834d5c0b309de24d836cbdcc25fd257de10be17";+ sha256 = "13wfxxplnqajqnykyxdy7477kdfxshpv800b2shr1iib8m01lygn";+ rev = "91b7194c6e0baab3d367073449a8ada7ba8dc346"; }) {}; in pkgs.haskell.packages.ghcjs.callPackage ./app.nix { miso = result.miso-ghcjs;@@ -373,6 +373,7 @@ 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
examples/canvas2d/Main.hs view
@@ -34,6 +34,7 @@ model = (0.0, 0.0) subs = [] events = defaultEvents+ mountPoint = Nothing -- default to body updateModel :: (Image,Image,Image)
examples/compose-update/Main.hs view
@@ -96,6 +96,7 @@ view = viewModel events = defaultEvents subs = []+ mountPoint = Nothing viewModel :: Model -> View Action viewModel (x, y) =
examples/file-reader/Main.hs view
@@ -35,6 +35,7 @@ , .. } where+ mountPoint = Nothing update = updateModel events = defaultEvents subs = []
examples/mario/Main.hs view
@@ -36,6 +36,7 @@ subs = [ arrowsSub GetArrows , windowSub WindowCoords ]+ mountPoint = Nothing data Model = Model { x :: !Double
examples/router/Main.hs view
@@ -46,6 +46,7 @@ events = defaultEvents subs = [ uriSub HandleURI ] view = viewModel+ mountPoint = Nothing -- | Update your model updateModel :: Action -> Model -> Effect Action Model
examples/svg/Main.hs view
@@ -19,6 +19,7 @@ view = viewModel events = defaultEvents subs = [ mouseSub HandleMouse ]+ mountPoint = Nothing emptyModel :: Model emptyModel = Model (0,0)
examples/three/Main.hs view
@@ -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@@ -58,6 +58,7 @@ startApp App { model = m , initialAction = Init , update = updateModel ref+ , mountPoint = Nothing , .. } where@@ -68,7 +69,7 @@ viewModel :: Double -> View action viewModel _ = div_ [] [ div_ [ id_ "stats"- , style_ [("position", "absolute")]+ , style_ $ M.singleton "position" "absolute" ] [] , canvas_ [ id_ "canvas" , width_ "400"
examples/todo-mvc/Main.hs view
@@ -80,11 +80,12 @@ 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
examples/websocket/Main.hs view
@@ -30,6 +30,7 @@ view = appView uri = URL "wss://echo.websocket.org" protocols = Protocols [ ]+ mountPoint = Nothing updateModel :: Action -> Model -> Effect Action Model updateModel (HandleWebSocket (WebSocketMessage (Message m))) model
examples/xhr/Main.hs view
@@ -34,6 +34,7 @@ main = do startApp App { model = Model Nothing , initialAction = NoOp+ , mountPoint = Nothing , .. } where
exe/Main.hs view
@@ -14,6 +14,7 @@ update = updateModel view = viewModel events = defaultEvents+ mountPoint = Nothing subs = [] updateModel :: Action -> Model -> Effect Action Model
ghc-src/Miso.hs view
@@ -15,9 +15,11 @@ module Miso ( module Miso.Event , module Miso.Html+ , module Miso.Router , module Miso.TypeLevel ) where import Miso.Event import Miso.Html+import Miso.Router import Miso.TypeLevel
ghcjs-src/Miso.hs view
@@ -70,8 +70,10 @@ 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@@ -90,7 +92,7 @@ =<< 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@@ -114,7 +116,7 @@ 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
ghcjs-src/Miso/Delegate.hs view
@@ -17,16 +17,18 @@ 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
ghcjs-src/Miso/Diff.hs view
@@ -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@@ -16,20 +18,40 @@ 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'
ghcjs-src/Miso/FFI.hs view
@@ -130,9 +130,10 @@ -- | 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 ()
ghcjs-src/Miso/Subscription/History.hs view
@@ -50,7 +50,7 @@ -- | Pushes a new URI onto the History stack pushURI :: URI -> IO () {-# INLINE pushURI #-}-pushURI uri = pushStateNoModel uri { uriPath = path } >> notify chan+pushURI uri = pushStateNoModel uri { uriPath = path } where path | uriPath uri == mempty = "/" | otherwise = uriPath uri@@ -58,7 +58,7 @@ -- | Replaces current URI on stack replaceURI :: URI -> IO () {-# INLINE replaceURI #-}-replaceURI uri = replaceTo' uri { uriPath = path } >> notify chan+replaceURI uri = replaceTo' uri { uriPath = path } where path | uriPath uri == mempty = "/" | otherwise = uriPath uri
ghcjs-src/Miso/Types.hs view
@@ -40,6 +40,8 @@ -- ^ 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.
jsbits/delegate.js view
@@ -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]);@@ -49,9 +49,9 @@ } } -function buildTargetToBody (body, target) {+function buildTargetToElement (element, target) { var stack = [];- while (body !== target) {+ while (element !== target) { stack.unshift (target); target = target.parentNode; }
jsbits/diff.js view
@@ -76,8 +76,6 @@ if (isSvg) { if (c === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", newProp);- else if (c === "className" || c === "class")- node.setAttributeNS("http://www.w3.org/1999/xlink", "class", newProp); else node.setAttribute(c, newProp); } else if (c in node && !(c === "list" || c === "form")) {@@ -95,8 +93,6 @@ if (isSvg) { if (n === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", newProp);- else if (n === "className" || n === "class")- node.setAttributeNS("http://www.w3.org/1999/xlink", "class", newProp); else node.setAttribute(n, newProp); } else if (n in node && !(n === "list" || n === "form")) {
miso.cabal view
@@ -1,5 +1,5 @@ name: miso-version: 0.9.0.0+version: 0.10.0.0 category: Web, Miso, Data Structures license: BSD3 license-file: LICENSE
src/Miso/Router.hs view
@@ -58,12 +58,7 @@ } deriving (Show, Eq, Ord) -- | When routing, the router may fail to match a location.--- Either this is an unrecoverable failure,--- such as failing to parse a query parameter,--- or it is recoverable by trying another path.-data RoutingError- = Fail- | FailFatal+data RoutingError = Fail deriving (Show, Eq, Ord) -- | A 'Router' contains the information necessary to execute a handler.@@ -163,28 +158,27 @@ RChoice a b -> do case routeLoc loc a m of Left Fail -> routeLoc loc b m- Left FailFatal -> Left FailFatal Right x -> Right x RCapture f -> case locPath loc of [] -> Left Fail capture:paths -> case parseUrlPieceMaybe capture of- Nothing -> Left FailFatal+ Nothing -> Left Fail Just x -> routeLoc loc { locPath = paths } (f x) m RQueryParam sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of Nothing -> routeLoc loc (f Nothing) m- Just Nothing -> Left FailFatal+ Just Nothing -> Left Fail Just (Just text) -> case parseQueryParamMaybe (decodeUtf8 text) of- Nothing -> Left FailFatal+ Nothing -> Left Fail Just x -> routeLoc loc (f (Just x)) m- RQueryParams sym f -> maybe (Left FailFatal) (\x -> routeLoc loc (f x) m) $ do+ RQueryParams sym f -> maybe (Left Fail) (\x -> routeLoc loc (f x) m) $ do ps <- sequence $ snd <$> Prelude.filter (\(k, _) -> k == BS.pack (symbolVal sym)) (locQuery loc) sequence $ (parseQueryParamMaybe . decodeUtf8) <$> ps RQueryFlag sym f -> case lookup (BS.pack $ symbolVal sym) (locQuery loc) of Nothing -> routeLoc loc (f False) m Just Nothing -> routeLoc loc (f True) m- Just (Just _) -> Left FailFatal+ Just (Just _) -> Left Fail RPath sym a -> case locPath loc of [] -> Left Fail p:paths -> if p == T.pack (symbolVal sym)