miso 0.14.0.0 → 0.15.0.0
raw patch · 15 files changed
+117/−98 lines, 15 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Miso.Html.Element: br_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: br_ :: [Attribute action] -> View action
- Miso.Html.Element: col_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: col_ :: [Attribute action] -> View action
- Miso.Html.Element: embed_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: embed_ :: [Attribute action] -> View action
- Miso.Html.Element: hr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: hr_ :: [Attribute action] -> View action
- Miso.Html.Element: img_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: img_ :: [Attribute action] -> View action
- Miso.Html.Element: input_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: input_ :: [Attribute action] -> View action
- Miso.Html.Element: link_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: link_ :: [Attribute action] -> View action
- Miso.Html.Element: param_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: param_ :: [Attribute action] -> View action
- Miso.Html.Element: source_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: source_ :: [Attribute action] -> View action
- Miso.Html.Element: track_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: track_ :: [Attribute action] -> View action
- Miso.Html.Element: wbr_ :: [Attribute action] -> [View action] -> View action
+ Miso.Html.Element: wbr_ :: [Attribute action] -> View action
Files
- examples/file-reader/Main.hs +1/−1
- examples/todo-mvc/Main.hs +3/−4
- examples/websocket/Main.hs +1/−1
- ghcjs-src/Miso.hs +24/−26
- ghcjs-src/Miso/Effect.hs +28/−8
- ghcjs-src/Miso/Html/Internal.hs +5/−12
- ghcjs-src/Miso/Subscription/History.hs +2/−2
- ghcjs-src/Miso/Subscription/Keyboard.hs +5/−6
- ghcjs-src/Miso/Subscription/Mouse.hs +2/−3
- ghcjs-src/Miso/Subscription/SSE.hs +2/−3
- ghcjs-src/Miso/Subscription/WebSocket.hs +3/−3
- ghcjs-src/Miso/Subscription/Window.hs +2/−3
- ghcjs-src/Miso/Types.hs +16/−3
- miso.cabal +1/−1
- src/Miso/Html/Element.hs +22/−22
examples/file-reader/Main.hs view
@@ -66,7 +66,7 @@ , input_ [ id_ "fileReader" , type_ "file" , onChange (const ReadFile)- ] []+ ] , div_ [] [ text info ] ]
examples/todo-mvc/Main.hs view
@@ -175,7 +175,7 @@ , name_ "toggle" , checked_ allCompleted , onClick $ CheckAll (not allCompleted)- ] []+ ] , label_ [ for_ "toggle-all" ] [ text $ S.pack "Mark all as complete" ]@@ -207,7 +207,7 @@ , type_ "checkbox" , checked_ completed , onClick $ Check eid (not completed)- ] []+ ] , label_ [ onDoubleClick $ EditingEntry eid True ] [ text description ]@@ -225,7 +225,6 @@ , onBlur $ EditingEntry eid False , onEnter $ EditingEntry eid False ]- [] ] viewControls :: Model -> MisoString -> [ Entry ] -> View Msg@@ -291,7 +290,7 @@ , name_ "newTodo" , onInput UpdateField , onEnter Add- ] []+ ] ] onEnter :: Msg -> Attribute Msg
examples/websocket/Main.hs view
@@ -63,7 +63,7 @@ , input_ [ type_ "text" , onInput UpdateMessage , onEnter (SendMessage msg)- ] []+ ] , button_ [ onClick (SendMessage msg) ] [ text (S.pack "Send to echo server") ] , div_ [ ] [ p_ [ ] [ text received | not . S.null $ received ] ]
ghcjs-src/Miso.hs view
@@ -51,13 +51,11 @@ :: Eq model => App model action -> model- -> ((action -> IO ()) -> IO (IORef VTree))+ -> (Sink action -> IO (IORef VTree)) -> IO b common App {..} m getView = do -- init Notifier Notify {..} <- newNotify- -- init empty Model- modelRef <- newIORef m -- init empty actions actionsRef <- newIORef S.empty let writeEvent a = void . forkIO $ do@@ -65,7 +63,7 @@ notify -- init Subs forM_ subs $ \sub ->- sub (readIORef modelRef) writeEvent+ sub writeEvent -- Hack to get around `BlockedIndefinitelyOnMVar` exception -- that occurs when no event handlers are present on a template -- and `notify` is no longer in scope@@ -79,24 +77,22 @@ -- Process initial action of application writeEvent initialAction -- Program loop, blocking on SkipChan- forever $ wait >> do- -- Apply actions to model- actions <- atomicModifyIORef' actionsRef $ \actions -> (S.empty, actions)- (shouldDraw, effects) <- atomicModifyIORef' modelRef $! \oldModel ->- let (newModel, effects) =- foldl' (foldEffects writeEvent update)- (oldModel, pure ()) actions- in (newModel, (oldModel /= newModel, effects))- effects- when shouldDraw $ do- newVTree <-- flip runView writeEvent- =<< view <$> readIORef modelRef- oldVTree <- readIORef viewRef- void $ waitForAnimationFrame- (diff mountPoint) (Just oldVTree) (Just newVTree)- atomicWriteIORef viewRef newVTree + let loop !oldModel = wait >> do+ -- Apply actions to model+ actions <- atomicModifyIORef' actionsRef $ \actions -> (S.empty, actions)+ let (Acc newModel effects) = foldl' (foldEffects writeEvent update)+ (Acc oldModel (pure ())) actions+ effects+ when (oldModel /= newModel) $ do+ newVTree <- runView (view newModel) writeEvent+ oldVTree <- readIORef viewRef+ void $ waitForAnimationFrame+ (diff mountPoint) (Just oldVTree) (Just newVTree)+ atomicWriteIORef viewRef newVTree+ loop newModel+ loop m+ -- | Runs an isomorphic miso application -- Assumes the pre-rendered DOM is already present miso :: (HasURI model, Eq model) => App model action -> IO ()@@ -123,13 +119,15 @@ -- | Helper foldEffects- :: (action -> IO ())+ :: Sink action -> (action -> model -> Effect action model)- -> (model, IO ()) -> action -> (model, IO ())-foldEffects sink update = \(!model, !as) action ->+ -> Acc model -> action -> Acc model+foldEffects sink update = \(Acc model as) action -> case update action model of- Effect newModel effs -> (newModel, newAs)+ Effect newModel effs -> Acc newModel newAs where newAs = as >> do forM_ effs $ \eff ->- void $ forkIO (sink =<< eff)+ void $ forkIO (eff sink)++data Acc model = Acc !model !(IO ())
ghcjs-src/Miso/Effect.hs view
@@ -11,10 +11,11 @@ module Miso.Effect.Storage , module Miso.Effect.XHR , module Miso.Effect.DOM-, Effect (..)+, Effect (..), Sub, Sink , noEff , (<#) , (#>)+, effectSub ) where import Data.Bifunctor@@ -25,12 +26,20 @@ -- | An effect represents the results of an update action. ----- It consists of the updated model and a list of actions. Each action--- is run in a new thread so there is no risk of accidentally--- blocking the application.-data Effect action model- = Effect model [IO action]+-- It consists of the updated model and a list of subscriptions. Each 'Sub' is+-- run in a new thread so there is no risk of accidentally blocking the+-- application.+data Effect action model = Effect model [Sub action] +-- | Type synonym for constructing event subscriptions.+--+-- The 'Sink' callback is used to dispatch actions which are then fed+-- back to the 'update' function.+type Sub action = Sink action -> IO ()++-- | Function to asynchronously dispatch actions to the 'update' function.+type Sink action = action -> IO ()+ instance Functor (Effect action) where fmap f (Effect m acts) = Effect (f m) acts @@ -45,7 +54,7 @@ Effect m' acts' -> Effect m' (acts ++ acts') instance Bifunctor Effect where- bimap f g (Effect m acts) = Effect (g m) (map (fmap f) acts)+ bimap f g (Effect m acts) = Effect (g m) (map (\act -> \sink -> act (sink . f)) acts) -- | Smart constructor for an 'Effect' with no actions. noEff :: model -> Effect action model@@ -53,8 +62,19 @@ -- | Smart constructor for an 'Effect' with exactly one action. (<#) :: model -> IO action -> Effect action model-(<#) m a = Effect m [a]+(<#) m a = effectSub m $ \sink -> a >>= sink -- | `Effect` smart constructor, flipped (#>) :: IO action -> model -> Effect action model (#>) = flip (<#)++-- | Like '<#' but schedules a subscription which is an IO computation which has+-- access to a 'Sink' which can be used to asynchronously dispatch actions to+-- the 'update' function.+--+-- A use-case is scheduling an IO computation which creates a 3rd-party JS+-- widget which has an associated callback. The callback can then call the sink+-- to turn events into actions. To do this without accessing a sink requires+-- going via a @'Sub'scription@ which introduces a leaky-abstraction.+effectSub :: model -> Sub action -> Effect action model+effectSub model sub = Effect model [sub]
ghcjs-src/Miso/Html/Internal.hs view
@@ -69,22 +69,15 @@ import JavaScript.Object import JavaScript.Object.Internal (Object (Object)) import qualified JavaScript.Array as JSArray-import JavaScript.Array.Internal (SomeJSArray(..)) import Servant.API +import Miso.Effect (Sub) import Miso.Event.Decoder import Miso.Event.Types import Miso.String+import Miso.Effect (Sink) import Miso.FFI --- | Type synonym for constructing event subscriptions.------ The first argument passed to a subscription provides a way to--- access the current value of the model (without blocking). The--- callback is used to dispatch actions which are then fed back to the--- @update@ function.-type Sub action model = IO model -> (action -> IO ()) -> IO ()- -- | Virtual DOM implemented as a JavaScript `Object`. -- Used for diffing, patching and event delegation. -- Not meant to be constructed directly, see `View` instead.@@ -92,7 +85,7 @@ -- | Core type for constructing a `VTree`, use this instead of `VTree` directly. newtype View action = View {- runView :: (action -> IO ()) -> IO VTree+ runView :: Sink action -> IO VTree } deriving Functor -- | For constructing type-safe links@@ -205,11 +198,11 @@ -- | Attribute of a vnode in a `View`. ----- The callback can be used to dispatch actions which are fed back to+-- The 'Sink' callback can be used to dispatch actions which are fed back to -- the @update@ function. This is especially useful for event handlers -- like the @onclick@ attribute. The second argument represents the -- vnode the attribute is attached to.-newtype Attribute action = Attribute ((action -> IO ()) -> Object -> IO ())+newtype Attribute action = Attribute (Sink action -> Object -> IO ()) -- | @prop k v@ is an attribute that will set the attribute @k@ of the DOM node associated with the vnode -- to @v@.
ghcjs-src/Miso/Subscription/History.hs view
@@ -83,8 +83,8 @@ chan = unsafePerformIO newNotify -- | Subscription for `popState` events, from the History API-uriSub :: (URI -> action) -> Sub action model-uriSub = \f _ sink -> do+uriSub :: (URI -> action) -> Sub action+uriSub = \f sink -> do void.forkIO.forever $ do wait chan >> do sink =<< f <$> getURI
ghcjs-src/Miso/Subscription/Keyboard.hs view
@@ -62,22 +62,22 @@ check = any (`S.member` set) -- | Maps `Arrows` onto a Keyboard subscription-arrowsSub :: (Arrows -> action) -> Sub action model+arrowsSub :: (Arrows -> action) -> Sub action arrowsSub = directionSub ([38], [40], [37], [39]) -- | Maps `WASD` onto a Keyboard subscription for directions-wasdSub :: (Arrows -> action) -> Sub action model+wasdSub :: (Arrows -> action) -> Sub action wasdSub = directionSub ([87], [83], [65], [68]) -- | Maps a specified list of keys to directions (up, down, left, right) directionSub :: ([Int], [Int], [Int], [Int]) -> (Arrows -> action)- -> Sub action model+ -> Sub action directionSub dirs = keyboardSub . (. toArrows dirs) -- | Returns subscription for Keyboard-keyboardSub :: (Set Int -> action) -> Sub action model-keyboardSub f _ sink = do+keyboardSub :: (Set Int -> action) -> Sub action+keyboardSub f sink = do keySetRef <- newIORef mempty windowAddEventListener "keyup" =<< keyUpCallback keySetRef windowAddEventListener "keydown" =<< keyDownCallback keySetRef@@ -97,4 +97,3 @@ let !new = S.delete key keys in (new, new) sink (f newKeys)-
ghcjs-src/Miso/Subscription/Mouse.hs view
@@ -21,11 +21,10 @@ -- | Captures mouse coordinates as they occur and writes them to -- an event sink-mouseSub :: ((Int,Int) -> action) -> Sub action model-mouseSub f _ = \sink -> do+mouseSub :: ((Int,Int) -> action) -> Sub action+mouseSub f = \sink -> do windowAddEventListener "mousemove" =<< do asyncCallback1 $ \mouseEvent -> do Just x <- fromJSVal =<< getProp "clientX" (Object mouseEvent) Just y <- fromJSVal =<< getProp "clientY" (Object mouseEvent) sink $ f (x,y)-
ghcjs-src/Miso/Subscription/SSE.hs view
@@ -25,8 +25,8 @@ import Miso.String -- | Server-sent events Subscription-sseSub :: FromJSON msg => MisoString -> (SSE msg -> action) -> Sub action model-sseSub url f _ = \sink -> do+sseSub :: FromJSON msg => MisoString -> (SSE msg -> action) -> Sub action+sseSub url f = \sink -> do es <- newEventSource url onMessage es =<< do asyncCallback1 $ \val -> do@@ -66,4 +66,3 @@ -- | Test URL -- http://sapid.sourceforge.net/ssetest/webkit.events.php -- var source = new EventSource("demo_sse.php");-
ghcjs-src/Miso/Subscription/WebSocket.hs view
@@ -70,8 +70,8 @@ => URL -> Protocols -> (WebSocket m -> action)- -> Sub action model-websocketSub (URL u) (Protocols ps) f getModel sink = do+ -> Sub action+websocketSub (URL u) (Protocols ps) f sink = do socket <- createWebSocket u ps writeIORef websocket (Just socket) void . forkIO $ handleReconnect@@ -103,7 +103,7 @@ if status == 3 then do unless (code == Just CLOSE_NORMAL) $- websocketSub (URL u) (Protocols ps) f getModel sink+ websocketSub (URL u) (Protocols ps) f sink else handleReconnect -- | Sends message to a websocket server
ghcjs-src/Miso/Subscription/Window.hs view
@@ -21,8 +21,8 @@ -- | Captures window coordinates changes as they occur and writes them to -- an event sink-windowSub :: ((Int, Int) -> action) -> Sub action model-windowSub f _ = \sink -> do+windowSub :: ((Int, Int) -> action) -> Sub action+windowSub f = \sink -> do sink . f =<< (,) <$> windowInnerHeight <*> windowInnerWidth windowAddEventListener "resize" =<< do asyncCallback1 $ \windowEvent -> do@@ -30,4 +30,3 @@ Just w <- fromJSVal =<< getProp "innerWidth" (Object target) Just h <- fromJSVal =<< getProp "innerHeight" (Object target) sink $ f (h, w)-
ghcjs-src/Miso/Types.hs view
@@ -15,6 +15,7 @@ , fromTransition , toTransition , scheduleIO+ , scheduleSub ) where import Control.Monad.Trans.Class (lift)@@ -34,7 +35,7 @@ -- See the 'Transition' monad for succinctly expressing model transitions. , view :: model -> View action -- ^ Function to draw `View`- , subs :: [ Sub action model ]+ , subs :: [ Sub action ] -- ^ List of subscriptions to run during application lifetime , events :: M.Map MisoString Bool -- ^ List of delegated events that the body element will listen for@@ -72,7 +73,7 @@ -- , ... -- } -- @-type Transition action model = StateT model (Writer [IO action])+type Transition action model = StateT model (Writer [Sub action]) -- | Convert a @Transition@ computation to a function that can be given to 'update'. fromTransition@@ -93,4 +94,16 @@ -- Note that multiple IO action can be scheduled using -- @Control.Monad.Writer.Class.tell@ from the @mtl@ library. scheduleIO :: IO action -> Transition action model ()-scheduleIO ioAction = lift $ tell [ ioAction ]+scheduleIO ioAction = scheduleSub $ \sink -> ioAction >>= sink++-- | Like 'scheduleIO' but schedules a subscription which is an IO+-- computation that has access to a 'Sink' which can be used to+-- asynchronously dispatch actions to the 'update' function.+--+-- A use-case is scheduling an IO computation which creates a+-- 3rd-party JS widget which has an associated callback. The callback+-- can then call the sink to turn events into actions. To do this+-- without accessing a sink requires going via a @'Sub'scription@+-- which introduces a leaky-abstraction.+scheduleSub :: Sub action -> Transition action model ()+scheduleSub sub = lift $ tell [ sub ]
miso.cabal view
@@ -1,5 +1,5 @@ name: miso-version: 0.14.0.0+version: 0.15.0.0 category: Web, Miso, Data Structures license: BSD3 license-file: LICENSE
src/Miso/Html/Element.hs view
@@ -251,16 +251,16 @@ h6_ = nodeHtml "h6" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr-hr_ :: [Attribute action] -> [View action] -> View action-hr_ = nodeHtml "hr"+hr_ :: [Attribute action] -> View action+hr_ = flip (nodeHtml "hr") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre pre_ :: [Attribute action] -> [View action] -> View action pre_ = nodeHtml "pre" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input-input_ :: [Attribute action] -> [View action] -> View action-input_ = nodeHtml "input"+input_ :: [Attribute action] -> View action+input_ = flip (nodeHtml "input") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/label label_ :: [Attribute action] -> [View action] -> View action@@ -288,8 +288,8 @@ bdo_ :: [Attribute action] -> [View action] -> View action bdo_ = nodeHtml "bdo" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/wbr-wbr_ :: [Attribute action] -> [View action] -> View action-wbr_ = nodeHtml "wbr"+wbr_ :: [Attribute action] -> View action+wbr_ = flip (nodeHtml "wbr") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details details_ :: [Attribute action] -> [View action] -> View action details_ = nodeHtml "details"@@ -336,20 +336,20 @@ video_ :: [Attribute action] -> [View action] -> View action video_ = nodeHtml "video" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/source-source_ :: [Attribute action] -> [View action] -> View action-source_ = nodeHtml "source"+source_ :: [Attribute action] -> View action+source_ = flip (nodeHtml "source") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/track-track_ :: [Attribute action] -> [View action] -> View action-track_ = nodeHtml "track"+track_ :: [Attribute action] -> View action+track_ = flip (nodeHtml "track") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/embed-embed_ :: [Attribute action] -> [View action] -> View action-embed_ = nodeHtml "embed"+embed_ :: [Attribute action] -> View action+embed_ = flip (nodeHtml "embed") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/object object_ :: [Attribute action] -> [View action] -> View action object_ = nodeHtml "object" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/param-param_ :: [Attribute action] -> [View action] -> View action-param_ = nodeHtml "param"+param_ :: [Attribute action] -> View action+param_ = flip (nodeHtml "param") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ins ins_ :: [Attribute action] -> [View action] -> View action ins_ = nodeHtml "ins"@@ -387,8 +387,8 @@ colgroup_ :: [Attribute action] -> [View action] -> View action colgroup_ = nodeHtml "colgroup" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/col-col_ :: [Attribute action] -> [View action] -> View action-col_ = nodeHtml "col"+col_ :: [Attribute action] -> View action+col_ = flip (nodeHtml "col") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/nav nav_ :: [Attribute action] -> [View action] -> View action nav_ = nodeHtml "nav"@@ -423,8 +423,8 @@ dd_ :: [Attribute action] -> [View action] -> View action dd_ = nodeHtml "dd" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img-img_ :: [Attribute action] -> [View action] -> View action-img_ = nodeHtml "img"+img_ :: [Attribute action] -> View action+img_ = flip (nodeHtml "img") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe iframe_ :: [Attribute action] -> [View action] -> View action iframe_ = nodeHtml "iframe"@@ -450,8 +450,8 @@ sup_ :: [Attribute action] -> [View action] -> View action sup_ = nodeHtml "sup" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/br-br_ :: [Attribute action] -> [View action] -> View action-br_ = nodeHtml "br"+br_ :: [Attribute action] -> View action+br_ = flip (nodeHtml "br") [] -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ol ol_ :: [Attribute action] -> [View action] -> View action ol_ = nodeHtml "ol"@@ -480,5 +480,5 @@ script_ :: [Attribute action] -> [View action] -> View action script_ = nodeHtml "script" -- | https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link-link_ :: [Attribute action] -> [View action] -> View action-link_ = nodeHtml "link"+link_ :: [Attribute action] -> View action+link_ = flip (nodeHtml "link") []