miso 0.7.2.0 → 0.7.3.0
raw patch · 7 files changed
+449/−20 lines, 7 filesnew-component:exe:canvas2dnew-component:exe:file-readernew-component:exe:threejsPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- README.md +19/−3
- examples/canvas2d/Main.hs +94/−0
- examples/file-reader/Main.hs +94/−0
- examples/three/Main.hs +156/−0
- ghcjs-src/Miso/Subscription/Keyboard.hs +23/−8
- jsbits/delegate.js +12/−8
- miso.cabal +51/−1
README.md view
@@ -45,13 +45,17 @@ - [Examples](#examples) - [TodoMVC](#todomvc) - [Flatris](#flatris)+ - [2048](#2048) - [Mario](#mario) - [Websocket](#websocket) - [SSE](#sse) - [XHR](#xhr) - [Router](#router) - [SVG](#svg)+ - [Canvas 2D](#canvas-2d)+ - [ThreeJS](#threejs) - [Simple](#simple)+ - [File Reader](#file-reader) - [Haddocks](#haddocks) - [GHC](#ghc) - [GHCJS](#ghcjs)@@ -88,14 +92,14 @@ packages: - '.' extra-deps:- - miso-0.4.0.0+ - miso-0.7.2.0 setup-info: ghcjs: source: ghcjs-0.2.0.9006020_ghc-7.10.3:- url: http://ghcjs.tolysz.org/lts-6.20-9006020.tar.gz- sha1: a6cea90cd8121eee3afb201183c6e9bd6bacd94a+ url: http://ghcjs.tolysz.org/lts-6.20-9006020.tar.gz+ sha1: a6cea90cd8121eee3afb201183c6e9bd6bacd94a ``` Add a `cabal` file@@ -291,6 +295,9 @@ ### Flatris - [Link](https://flatris.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs-flatris/) +### 2048+ - [Link](http://2048.haskell-miso.org/) / [Source](https://github.com/ptigwe/hs2048/)+ ### Mario - [Link](https://mario.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/mario/Main.hs) @@ -309,8 +316,17 @@ ### SVG - [Link](https://svg.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/svg/Main.hs) +### Canvas 2D+ - [Link](http://canvas.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/canvas2d/Main.hs)++### ThreeJS+ - [Link](http://threejs.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/three/Main.hs)+ ### Simple - [Link](https://simple.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/exe/Main.hs)++### File Reader+ - [Link](https://file-reader.haskell-miso.org/) / [Source](https://github.com/dmjio/miso/blob/master/examples/file-reader/Main.hs) ## Haddocks
+ examples/canvas2d/Main.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+module Main where++import Control.Monad+import GHCJS.Types+import JavaScript.Web.Canvas++import Miso+import Miso.String++type Model = (Double, Double)++data Action+ = NoOp+ | GetTime+ | SetTime Model++main :: IO ()+main = do+ [sun, moon, earth] <- replicateM 3 newImage+ setSrc sun "https://mdn.mozillademos.org/files/1456/Canvas_sun.png"+ setSrc moon "https://mdn.mozillademos.org/files/1443/Canvas_moon.png"+ setSrc earth "https://mdn.mozillademos.org/files/1429/Canvas_earth.png"+ startApp App { initialAction = GetTime+ , update = updateModel (sun,moon,earth)+ , ..+ }+ where+ view _ = canvas_ [ id_ "canvas"+ , width_ "300"+ , height_ "300"+ ] []+ model = (0.0, 0.0)+ subs = []+ events = defaultEvents++updateModel+ :: (Image,Image,Image)+ -> Action+ -> Model+ -> Effect Action Model+updateModel _ NoOp m = noEff m+updateModel _ GetTime m = m <# do+ date <- newDate+ (s,m') <- (,) <$> getSecs date <*> getMillis date+ pure $ SetTime (s,m')+updateModel (sun,moon,earth) (SetTime m@(secs,millis)) _ = m <# do+ ctx <- getCtx+ setGlobalCompositeOperation ctx+ clearRect 0 0 300 300 ctx+ fillStyle 0 0 0 0.6 ctx+ strokeStyle 0 153 255 0.4 ctx+ save ctx+ translate 150 150 ctx+ flip rotate ctx $ (((2 * pi) / 60) * secs) + (((2 * pi) / 60000) * millis)+ translate 105 0 ctx+ fillRect 0 (-12) 50 24 ctx+ drawImage' earth (-12) (-12) ctx+ save ctx+ flip rotate ctx $ (((2 * pi) / 6) * secs) + (((2 * pi) / 6000) * millis)+ translate 0 28.5 ctx+ drawImage' moon (-3.5) (-3.5) ctx+ replicateM_ 2 (restore ctx)+ beginPath ctx+ arc 150 150 105 0 (pi * 2) False ctx+ stroke ctx+ drawImage sun 0 0 300 300 ctx+ pure GetTime++foreign import javascript unsafe "$1.globalCompositeOperation = 'destination-over';"+ setGlobalCompositeOperation :: Context -> IO ()++foreign import javascript unsafe "$4.drawImage($1,$2,$3);"+ drawImage' :: Image -> Double -> Double -> Context -> IO ()++foreign import javascript unsafe "$r = document.getElementById('canvas').getContext('2d');"+ getCtx :: IO Context++foreign import javascript unsafe "$r = new Image();"+ newImage :: IO Image++foreign import javascript unsafe "$1.src = $2;"+ setSrc :: Image -> MisoString -> IO ()++foreign import javascript unsafe "$r = new Date();"+ newDate :: IO JSVal++foreign import javascript unsafe "$r = $1.getSeconds();"+ getSecs :: JSVal -> IO Double++foreign import javascript unsafe "$r = $1.getMilliseconds();"+ getMillis :: JSVal -> IO Double+
+ examples/file-reader/Main.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TypeFamilies #-}+module Main where++import Miso+import Miso.String+import Control.Concurrent.MVar++import GHCJS.Types+import GHCJS.Foreign.Callback++-- | Model+data Model+ = Model+ { info :: MisoString+ } deriving (Eq, Show)++-- | Action+data Action+ = ReadFile+ | NoOp+ | SetContent MisoString+ deriving (Show, Eq)++-- | Main entry point+main :: IO ()+main = do+ startApp App { model = Model ""+ , initialAction = NoOp+ , ..+ }+ where+ update = updateModel+ events = defaultEvents+ subs = []+ view = viewModel++-- | Update your model+updateModel :: Action -> Model -> Effect Action Model+updateModel ReadFile m = m <# do+ fileReaderInput <- getElementById "fileReader"+ file <- getFile fileReaderInput+ reader <- newReader+ mvar <- newEmptyMVar+ setOnLoad reader =<< do+ asyncCallback $ do+ r <- getResult reader+ putMVar mvar r+ readText reader file+ SetContent <$> readMVar mvar+updateModel (SetContent c) m = noEff m { info = c }+updateModel NoOp m = noEff m++-- | View function, with routing+viewModel :: Model -> View Action+viewModel Model {..} = view+ where+ view = div_ [] [+ "FileReader API example"+ , input_ [ id_ "fileReader"+ , type_ "file"+ , onChange ReadFile+ ] []+ , div_ [] [ text info ]+ ]++foreign import javascript unsafe "console.log($1);"+ consoleLog :: JSVal -> IO ()++foreign import javascript unsafe "$r = new FileReader();"+ newReader :: IO JSVal++foreign import javascript unsafe "$r = document.getElementById($1);"+ getElementById :: MisoString -> IO JSVal++foreign import javascript unsafe "$r = $1.files[0];"+ getFile :: JSVal -> IO JSVal++foreign import javascript unsafe "$1.onload = $2;"+ setOnLoad :: JSVal -> Callback (IO ()) -> IO ()++foreign import javascript unsafe "$r = $1.result;"+ getResult :: JSVal -> IO MisoString++foreign import javascript unsafe "$1.readAsText($2);"+ readText :: JSVal -> JSVal -> IO ()++onChange :: action -> Attribute action+onChange r = on "change" emptyDecoder (const r)
+ examples/three/Main.hs view
@@ -0,0 +1,156 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedLists #-}+{-# LANGUAGE RecordWildCards #-}+module Main where++import Control.Monad+import Data.IORef+import GHCJS.Types++import Miso+import Miso.String++data Action+ = GetTime+ | Init+ | SetTime !Double++withStats :: JSVal -> IO () -> IO ()+withStats stats m = do+ statsBegin stats >> m+ statsEnd stats++data Context = Context+ { rotateCube :: IO ()+ , renderScene :: IO ()+ , stats :: JSVal+ }++initContext :: IORef Context -> IO ()+initContext ref = do+ canvas <- getElementById "canvas"+ scene <- newScene+ camera <- newCamera+ renderer <- newRenderer canvas+ setSize renderer+ cube <- join $ newMesh+ <$> newBoxGeometry 1 1 1+ <*> newMeshBasicMaterial+ addToScene scene cube+ positionCamera camera 5+ stats <- newStats+ statsContainer <- getElementById "stats"+ addStatsToDOM statsContainer stats+ writeIORef ref Context {+ stats = stats+ , rotateCube = do+ rotateX cube 0.1+ rotateY cube 0.1+ , renderScene =+ render renderer scene camera+ }++main :: IO ()+main = do+ stats <- newStats+ ref <- newIORef $ Context (pure ()) (pure ()) stats+ m <- now+ startApp App { model = m+ , initialAction = Init+ , update = updateModel ref+ , ..+ }+ where+ events = defaultEvents+ view = viewModel+ subs = []++viewModel :: Double -> View action+viewModel _ = div_ [] [+ div_ [ id_ "stats"+ , style_ [("position", "absolute")]+ ] []+ , canvas_ [ id_ "canvas"+ , width_ "400"+ , height_ "300"+ ] []+ ]++updateModel+ :: IORef Context+ -> Action+ -> Double+ -> Effect Action Double+updateModel ref Init m = m <# do+ initContext ref+ pure GetTime++updateModel ref GetTime m = m <# do+ Context {..} <- readIORef ref+ withStats stats $ do+ rotateCube+ renderScene+ SetTime <$> now++updateModel _ (SetTime m) _ =+ m <# pure GetTime++foreign import javascript unsafe "$r = new Stats();"+ newStats :: IO JSVal++foreign import javascript unsafe "$1.begin();"+ statsBegin :: JSVal -> IO ()++foreign import javascript unsafe "$1.end();"+ statsEnd :: JSVal -> IO ()++foreign import javascript unsafe "$1.showPanel(0);"+ showPanel :: JSVal -> IO ()++foreign import javascript unsafe "$r = performance.now();"+ now :: IO Double++foreign import javascript unsafe "$r = new THREE.Scene();"+ newScene :: IO JSVal++foreign import javascript unsafe "$r = new THREE.BoxGeometry( $1, $2, $3 );"+ newBoxGeometry :: Int -> Int -> Int -> IO JSVal++foreign import javascript unsafe "$r = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );"+ newCamera :: IO JSVal++foreign import javascript unsafe "$r = new THREE.Mesh( $1, $2 );"+ newMesh :: JSVal -> JSVal -> IO JSVal++foreign import javascript unsafe "$r = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );"+ newMeshBasicMaterial :: IO JSVal++foreign import javascript unsafe "$r = new THREE.WebGLRenderer({canvas:$1, antialias : true});"+ newRenderer :: JSVal -> IO JSVal++foreign import javascript unsafe "$1.setSize( window.innerWidth, window.innerHeight );"+ setSize :: JSVal -> IO ()++foreign import javascript unsafe "$r = document.getElementById($1);"+ getElementById :: MisoString -> IO JSVal++foreign import javascript unsafe "$1.add($2);"+ addToScene :: JSVal -> JSVal -> IO ()++foreign import javascript unsafe "$1.position.z = $2;"+ cameraZ :: JSVal -> Int -> IO ()++foreign import javascript unsafe "$1.rotation.x += $2;"+ rotateX :: JSVal -> Double -> IO ()++foreign import javascript unsafe "$1.rotation.y += $2;"+ rotateY :: JSVal -> Double -> IO ()++foreign import javascript unsafe "$1.render($2, $3);"+ render :: JSVal -> JSVal -> JSVal -> IO ()++foreign import javascript unsafe "$1.position.z = $2;"+ positionCamera :: JSVal -> Double -> IO ()++foreign import javascript unsafe "$1.appendChild( $2.domElement );"+ addStatsToDOM :: JSVal -> JSVal -> IO ()
ghcjs-src/Miso/Subscription/Keyboard.hs view
@@ -16,7 +16,9 @@ Arrows (..) -- * Subscriptions , arrowsSub+ , directionSub , keyboardSub+ , wasdSub ) where import Data.IORef@@ -40,25 +42,38 @@ , arrowY :: !Int } deriving (Show, Eq) --- | Helper function to convert keys currently pressed to `Arrow`-toArrows :: Set Int -> Arrows-toArrows set =+-- | Helper function to convert keys currently pressed to `Arrow`, given a+-- mapping for keys representing up, down, left and right respectively.+toArrows :: ([Int], [Int], [Int], [Int]) -> Set Int -> Arrows+toArrows (up, down, left, right) set = Arrows { arrowX =- case (S.member 37 set, S.member 39 set) of+ case (check left, check right) of (True, False) -> -1 (False, True) -> 1 (_,_) -> 0- , arrowY =- case (S.member 40 set, S.member 38 set) of+ , arrowY =+ case (check down, check up) of (True, False) -> -1 (False, True) -> 1 (_,_) -> 0- }+ }+ where+ check = any (`S.member` set) -- | Maps `Arrows` onto a Keyboard subscription arrowsSub :: (Arrows -> action) -> Sub action model-arrowsSub = keyboardSub . (. toArrows)+arrowsSub = directionSub ([38], [40], [37], [39])++-- | Maps `WASD` onto a Keyboard subscription for directions+wasdSub :: (Arrows -> action) -> Sub action model+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+directionSub dirs = keyboardSub . (. toArrows dirs) -- | Returns subscription for Keyboard keyboardSub :: (Set Int -> action) -> Sub action model
jsbits/delegate.js view
@@ -33,14 +33,18 @@ /* stack.length == 1 */ else { if (obj.domRef === stack[0]) {- if (obj.events[event.type]) {- var eventObj = obj.events[event.type],- options = eventObj.options;- if (options.preventDefault) event.preventDefault();- eventObj.runEvent(event);- if (!options.stopPropagation)- propogateWhileAble (parentStack, event);- }+ var eventObj = obj.events[event.type];+ if (eventObj) {+ var options = eventObj.options;+ if (options.preventDefault)+ event.preventDefault();+ eventObj.runEvent(event);+ if (!options.stopPropagation)+ propogateWhileAble (parentStack, event);+ } else {+ /* still propagate to parent handlers even if event not defined */+ propogateWhileAble (parentStack, event);+ } } } }
miso.cabal view
@@ -1,5 +1,5 @@ name: miso-version: 0.7.2.0+version: 0.7.3.0 category: Web, Miso, Data Structures license: BSD3 license-file: LICENSE@@ -53,6 +53,40 @@ default-language: Haskell2010 +executable threejs+ main-is:+ Main.hs+ if !impl(ghcjs) || !flag(examples)+ buildable: False+ else+ hs-source-dirs:+ examples/three+ build-depends:+ aeson,+ base < 5,+ ghcjs-base,+ containers,+ miso+ default-language:+ Haskell2010++executable file-reader+ main-is:+ Main.hs+ if !impl(ghcjs) || !flag(examples)+ buildable: False+ else+ hs-source-dirs:+ examples/file-reader+ build-depends:+ aeson,+ base < 5,+ containers,+ ghcjs-base,+ miso+ default-language:+ Haskell2010+ executable xhr main-is: Main.hs@@ -65,6 +99,22 @@ aeson, base < 5, containers,+ ghcjs-base,+ miso+ default-language:+ Haskell2010++executable canvas2d+ main-is:+ Main.hs+ if !impl(ghcjs) || !flag(examples)+ buildable: False+ else+ hs-source-dirs:+ examples/canvas2d+ build-depends:+ aeson,+ base < 5, ghcjs-base, miso default-language: