From 68884e608f5236987b741c6ab2cebae9c01670d1 Mon Sep 17 00:00:00 2001 From: Divam Date: Fri, 18 Jan 2019 20:57:54 +0900 Subject: [PATCH 1/4] Generate script to make cabal project for examples, and some fixes to DragnDrop --- .../src/Frontend/Examples/DragAndDrop/Main.hs | 22 ++++---- .../generateAndTestExamples.hs | 49 ++++++++++++++++ reflex-dom-projects/template/Main.hs | 56 +++++++++++++++++++ reflex-dom-projects/template/Setup.hs | 2 + reflex-dom-projects/template/template.cabal | 35 ++++++++++++ 5 files changed, 153 insertions(+), 11 deletions(-) create mode 100755 reflex-dom-projects/generateAndTestExamples.hs create mode 100644 reflex-dom-projects/template/Main.hs create mode 100644 reflex-dom-projects/template/Setup.hs create mode 100644 reflex-dom-projects/template/template.cabal diff --git a/frontend/src/Frontend/Examples/DragAndDrop/Main.hs b/frontend/src/Frontend/Examples/DragAndDrop/Main.hs index b1d44f1..c801fe3 100644 --- a/frontend/src/Frontend/Examples/DragAndDrop/Main.hs +++ b/frontend/src/Frontend/Examples/DragAndDrop/Main.hs @@ -21,13 +21,8 @@ import qualified GHCJS.DOM.GlobalEventHandlers as DOM import qualified GHCJS.DOM.MouseEvent as DOM import qualified GHCJS.DOM.Types as DOM (uncheckedCastTo) -import Language.Javascript.JSaddle -import Reflex.Dom hiding (mainWidget) -import Reflex.Dom.Core (mainWidget) -import Obelisk.Generated.Static - -main :: IO () -main = run $ mainWidget app +import Language.Javascript.JSaddle +import Reflex.Dom.Core app :: ( DomBuilder t m @@ -39,18 +34,23 @@ app ) => m () app = do - draggable item1 "a picture" - draggable item2 "some code" + el "h3" $ text "Drag and Drop" + el "div" $ draggable item1 "Haskell logo" + el "div" $ draggable item2 "some text" + text "Drap either the above logo or the text to the below box" handleDragEvents return () + item1 :: DomBuilder t m => m (Element EventResult (DomBuilderSpace m) t, ()) -item1 = elAttr' "img" ("draggable" =: "true" <> "src" =: static @"obelisk.jpg") blank +item1 = elAttr' "img" ("draggable" =: "true" <> "src" =: haskellLogoUrl) blank + where + haskellLogoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Haskell-Logo.svg/180px-Haskell-Logo.svg.png" item2 :: DomBuilder t m => m (Element EventResult (DomBuilderSpace m) t, ()) item2 = elAttr' "pre" ("draggable" =: "true" <> "style" =: "-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;") - $ text "main = putStrLn \"Hello world!\"" + $ text "Draggable text" draggable :: ( DomBuilder t m diff --git a/reflex-dom-projects/generateAndTestExamples.hs b/reflex-dom-projects/generateAndTestExamples.hs new file mode 100755 index 0000000..6350c68 --- /dev/null +++ b/reflex-dom-projects/generateAndTestExamples.hs @@ -0,0 +1,49 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i runghc -p "ghc.withPackages (pkgs: [ pkgs.shelly ])" + +{-# LANGUAGE OverloadedStrings #-} +-- | This script provides basic tests for the try-reflex functionality; it should be run before committing code to important branches, such as 'develop' + +import Shelly +import Control.Monad +import qualified Data.Text as T + +examples = + [ "BasicToDo" + , "DragAndDrop" + , "FileReader" + , "NasaPod" + , "PegSolitaire" + , "ScreenKeyboard" + , "TicTacToe" + , "WebSocketEcho" + ] + +main :: IO () +main = shelly $ verbosely $ do + forM_ examples $ \exampleName -> do + -- Create the cabal project skeleton + let + genDir = fromText "generated" + templateDir = fromText "template" + targetDir = genDir (fromText exampleName) + rm_rf targetDir >> mkdir_p targetDir + cp_r templateDir genDir + mv (genDir templateDir (fromText "")) targetDir + mv (targetDir (fromText "template.cabal")) (targetDir (fromText exampleName <.> "cabal")) + files <- run "find" [(toTextIgnore targetDir), "-type", "f"] + forM_ (T.words files) $ \f -> do + let sedRegex = "s/EXAMPLENAME/" <> exampleName <> "/g" + run_ "sed" ["-i", "-e", sedRegex, f] + -- Copy the source code + let + prefixDir = (fromText "Frontend/Examples") + srcDir = (fromText "../frontend/src/Frontend/Examples") (fromText exampleName) + mkdir_p (targetDir prefixDir) + cp_r srcDir (targetDir prefixDir) + + -- copy static assets + let + srcDir = (fromText "../static") + cp_r srcDir targetDir + -- Test cabal build diff --git a/reflex-dom-projects/template/Main.hs b/reflex-dom-projects/template/Main.hs new file mode 100644 index 0000000..6753d2c --- /dev/null +++ b/reflex-dom-projects/template/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.EXAMPLENAME.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/template/Setup.hs b/reflex-dom-projects/template/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/template/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/template/template.cabal b/reflex-dom-projects/template/template.cabal new file mode 100644 index 0000000..29d35dd --- /dev/null +++ b/reflex-dom-projects/template/template.cabal @@ -0,0 +1,35 @@ +name: reflex-examples-EXAMPLENAME +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-EXAMPLENAME + main-is: Main.hs + other-modules: Frontend.Examples.EXAMPLENAME.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + -- , jsaddle-warp + default-language: Haskell2010 From 3b2cbba8a23d8da7a6fe0c0bd3190c727c8ce4ca Mon Sep 17 00:00:00 2001 From: Divam Date: Fri, 18 Jan 2019 21:09:04 +0900 Subject: [PATCH 2/4] Fix UI of BasicToDo --- frontend/src/Frontend/Examples/BasicToDo/Main.hs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/Frontend/Examples/BasicToDo/Main.hs b/frontend/src/Frontend/Examples/BasicToDo/Main.hs index 2e87691..b55209c 100644 --- a/frontend/src/Frontend/Examples/BasicToDo/Main.hs +++ b/frontend/src/Frontend/Examples/BasicToDo/Main.hs @@ -31,9 +31,10 @@ new v m = case M.maxViewWithKey m of ulW :: (DomBuilder t m, PostBuild t m, MonadFix m, MonadHold t m) => Dynamic t (MM T.Text) -> m (Dynamic t (MM (Event t Int))) ulW xs = elClass "ul" "list" $ listWithKey xs $ \k x -> elClass "li" "element" $ do - dynText x -- output the text - fmap (const k) <$> elClass "div" "delete" (button "x") + e <- fmap (const k) <$> elClass "span" "delete" (button "x") -- tag the event of button press with the key of the text + elAttr "span" ("style" =: "padding: 0.5em;") $ dynText x -- output the text + return e -- output an input text widget with auto clean on return and return an -- event firing on return containing the string before clean @@ -67,4 +68,6 @@ listW e = do return () app :: (DomBuilder t m, PostBuild t m, MonadFix m, MonadHold t m) => m () -app = el "div" $ inputW >>= listW +app = el "div" $ do + el "h4" $ text "ToDo List" + inputW >>= listW From d89fd0599e25b8eac37801ab4d701ce4bee5893f Mon Sep 17 00:00:00 2001 From: Divam Date: Fri, 18 Jan 2019 21:51:47 +0900 Subject: [PATCH 3/4] Some UI fixes and generated cabal projects --- .../src/Frontend/Examples/TicTacToe/Main.hs | 8 +- .../Frontend/Examples/WebSocketEcho/Main.hs | 8 +- .../generateAndTestExamples.hs | 9 +- .../generated/BasicToDo/BasicToDo.cabal | 37 ++++ .../Frontend/Examples/BasicToDo/Main.hs | 73 ++++++++ .../generated/BasicToDo/Main.hs | 56 ++++++ .../generated/BasicToDo/Setup.hs | 2 + .../generated/DragAndDrop/DragAndDrop.cabal | 37 ++++ .../Frontend/Examples/DragAndDrop/Main.hs | 127 +++++++++++++ .../generated/DragAndDrop/Main.hs | 56 ++++++ .../generated/DragAndDrop/Setup.hs | 2 + .../generated/FileReader/FileReader.cabal | 37 ++++ .../Frontend/Examples/FileReader/Main.hs | 68 +++++++ .../generated/FileReader/Main.hs | 56 ++++++ .../generated/FileReader/Setup.hs | 2 + .../NasaPod/Frontend/Examples/NasaPod/Main.hs | 90 +++++++++ reflex-dom-projects/generated/NasaPod/Main.hs | 56 ++++++ .../generated/NasaPod/NasaPod.cabal | 37 ++++ .../generated/NasaPod/Setup.hs | 2 + .../Frontend/Examples/ScreenKeyboard/Main.hs | 87 +++++++++ .../generated/ScreenKeyboard/Main.hs | 56 ++++++ .../ScreenKeyboard/ScreenKeyboard.cabal | 37 ++++ .../generated/ScreenKeyboard/Setup.hs | 2 + .../Frontend/Examples/TicTacToe/Main.hs | 171 ++++++++++++++++++ .../Frontend/Examples/TicTacToe/tictactoe.ts | 144 +++++++++++++++ .../generated/TicTacToe/Main.hs | 56 ++++++ .../generated/TicTacToe/Setup.hs | 2 + .../generated/TicTacToe/TicTacToe.cabal | 37 ++++ .../Frontend/Examples/WebSocketEcho/Main.hs | 46 +++++ .../generated/WebSocketEcho/Main.hs | 56 ++++++ .../generated/WebSocketEcho/Setup.hs | 2 + .../WebSocketEcho/WebSocketEcho.cabal | 37 ++++ reflex-dom-projects/template/template.cabal | 2 + 33 files changed, 1482 insertions(+), 16 deletions(-) create mode 100644 reflex-dom-projects/generated/BasicToDo/BasicToDo.cabal create mode 100644 reflex-dom-projects/generated/BasicToDo/Frontend/Examples/BasicToDo/Main.hs create mode 100644 reflex-dom-projects/generated/BasicToDo/Main.hs create mode 100644 reflex-dom-projects/generated/BasicToDo/Setup.hs create mode 100644 reflex-dom-projects/generated/DragAndDrop/DragAndDrop.cabal create mode 100644 reflex-dom-projects/generated/DragAndDrop/Frontend/Examples/DragAndDrop/Main.hs create mode 100644 reflex-dom-projects/generated/DragAndDrop/Main.hs create mode 100644 reflex-dom-projects/generated/DragAndDrop/Setup.hs create mode 100644 reflex-dom-projects/generated/FileReader/FileReader.cabal create mode 100644 reflex-dom-projects/generated/FileReader/Frontend/Examples/FileReader/Main.hs create mode 100644 reflex-dom-projects/generated/FileReader/Main.hs create mode 100644 reflex-dom-projects/generated/FileReader/Setup.hs create mode 100644 reflex-dom-projects/generated/NasaPod/Frontend/Examples/NasaPod/Main.hs create mode 100644 reflex-dom-projects/generated/NasaPod/Main.hs create mode 100644 reflex-dom-projects/generated/NasaPod/NasaPod.cabal create mode 100644 reflex-dom-projects/generated/NasaPod/Setup.hs create mode 100644 reflex-dom-projects/generated/ScreenKeyboard/Frontend/Examples/ScreenKeyboard/Main.hs create mode 100644 reflex-dom-projects/generated/ScreenKeyboard/Main.hs create mode 100644 reflex-dom-projects/generated/ScreenKeyboard/ScreenKeyboard.cabal create mode 100644 reflex-dom-projects/generated/ScreenKeyboard/Setup.hs create mode 100644 reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/Main.hs create mode 100644 reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts create mode 100644 reflex-dom-projects/generated/TicTacToe/Main.hs create mode 100644 reflex-dom-projects/generated/TicTacToe/Setup.hs create mode 100644 reflex-dom-projects/generated/TicTacToe/TicTacToe.cabal create mode 100644 reflex-dom-projects/generated/WebSocketEcho/Frontend/Examples/WebSocketEcho/Main.hs create mode 100644 reflex-dom-projects/generated/WebSocketEcho/Main.hs create mode 100644 reflex-dom-projects/generated/WebSocketEcho/Setup.hs create mode 100644 reflex-dom-projects/generated/WebSocketEcho/WebSocketEcho.cabal diff --git a/frontend/src/Frontend/Examples/TicTacToe/Main.hs b/frontend/src/Frontend/Examples/TicTacToe/Main.hs index 1556ef3..f5c0c82 100644 --- a/frontend/src/Frontend/Examples/TicTacToe/Main.hs +++ b/frontend/src/Frontend/Examples/TicTacToe/Main.hs @@ -111,8 +111,10 @@ gameBoard gameBoard squares = divClass "game-board" $ do evs <- forM [minBound .. maxBound] $ \row -> divClass "board-row" $ do evs <- forM [minBound .. maxBound] $ \col -> do - let square = (row, col) - (btn1,_) <- elAttr' "button" ("class" =: "square") $ + let + square = (row, col) + style = "height: 2em; width: 2em; position: block;" + (btn1,_) <- elAttr' "button" ("style" =: style) $ dynText (getSquareText square <$> squares) return (square <$ domEvent Click btn1) return (leftmost evs) @@ -121,7 +123,7 @@ gameBoard squares = divClass "game-board" $ do -- | What to display on square getSquareText :: (Row, Col) -> Squares -> Text getSquareText square squares = case squares A.! square of - Nothing -> "_" + Nothing -> "." (Just Player_X) -> "X" (Just Player_O) -> "O" diff --git a/frontend/src/Frontend/Examples/WebSocketEcho/Main.hs b/frontend/src/Frontend/Examples/WebSocketEcho/Main.hs index f79679a..6a27790 100644 --- a/frontend/src/Frontend/Examples/WebSocketEcho/Main.hs +++ b/frontend/src/Frontend/Examples/WebSocketEcho/Main.hs @@ -4,14 +4,10 @@ module Frontend.Examples.WebSocketEcho.Main where -import Data.Text.Encoding (encodeUtf8, decodeUtf8) -import Reflex.Dom hiding (mainWidget) -import Reflex.Dom.Core (mainWidget) +import Data.Text.Encoding (encodeUtf8, decodeUtf8) +import Reflex.Dom import Control.Monad.Fix (MonadFix) -main :: IO () -main = run $ mainWidget app - app :: ( DomBuilder t m , MonadFix m diff --git a/reflex-dom-projects/generateAndTestExamples.hs b/reflex-dom-projects/generateAndTestExamples.hs index 6350c68..8386d60 100755 --- a/reflex-dom-projects/generateAndTestExamples.hs +++ b/reflex-dom-projects/generateAndTestExamples.hs @@ -2,7 +2,7 @@ #! nix-shell -i runghc -p "ghc.withPackages (pkgs: [ pkgs.shelly ])" {-# LANGUAGE OverloadedStrings #-} --- | This script provides basic tests for the try-reflex functionality; it should be run before committing code to important branches, such as 'develop' +-- | This script creates cabal projects from the template for individual examples import Shelly import Control.Monad @@ -13,7 +13,6 @@ examples = , "DragAndDrop" , "FileReader" , "NasaPod" - , "PegSolitaire" , "ScreenKeyboard" , "TicTacToe" , "WebSocketEcho" @@ -42,8 +41,4 @@ main = shelly $ verbosely $ do mkdir_p (targetDir prefixDir) cp_r srcDir (targetDir prefixDir) - -- copy static assets - let - srcDir = (fromText "../static") - cp_r srcDir targetDir - -- Test cabal build + -- TODO - Test cabal build diff --git a/reflex-dom-projects/generated/BasicToDo/BasicToDo.cabal b/reflex-dom-projects/generated/BasicToDo/BasicToDo.cabal new file mode 100644 index 0000000..cd88246 --- /dev/null +++ b/reflex-dom-projects/generated/BasicToDo/BasicToDo.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-BasicToDo +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-BasicToDo + main-is: Main.hs + other-modules: Frontend.Examples.BasicToDo.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/BasicToDo/Frontend/Examples/BasicToDo/Main.hs b/reflex-dom-projects/generated/BasicToDo/Frontend/Examples/BasicToDo/Main.hs new file mode 100644 index 0000000..b55209c --- /dev/null +++ b/reflex-dom-projects/generated/BasicToDo/Frontend/Examples/BasicToDo/Main.hs @@ -0,0 +1,73 @@ +{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Frontend.Examples.BasicToDo.Main + (app) + where + +{- + - Stripped version of todo list: just add new todo and delete an old one + -} + +import Control.Lens +import qualified Data.Map as M +import qualified Data.Text as T +import Reflex.Dom +import Control.Monad.Fix (MonadFix) + + +type MM a = M.Map Int a + +-- add a new value to a map, automatically choosing an unused key +new :: a -> MM a -> MM a +new v m = case M.maxViewWithKey m of + Nothing -> [(0,v)] -- overloadedlists + Just ((k, _), _) -> M.insert (succ k) v m + +-- output the ul of the elements of the given map and return the delete +-- event for each key +ulW :: (DomBuilder t m, PostBuild t m, MonadFix m, MonadHold t m) + => Dynamic t (MM T.Text) -> m (Dynamic t (MM (Event t Int))) +ulW xs = elClass "ul" "list" $ listWithKey xs $ \k x -> elClass "li" "element" $ do + e <- fmap (const k) <$> elClass "span" "delete" (button "x") + -- tag the event of button press with the key of the text + elAttr "span" ("style" =: "padding: 0.5em;") $ dynText x -- output the text + return e + +-- output an input text widget with auto clean on return and return an +-- event firing on return containing the string before clean +inputW :: (DomBuilder t m, MonadFix m) => m (Event t T.Text) +inputW = do + rec + let send = keypress Enter input + -- send signal firing on *return* key press + input <- inputElement $ def + & inputElementConfig_setValue .~ fmap (const "") send + & inputElementConfig_elementConfig . elementConfig_initialAttributes .~ + ("placeholder" =: "Write task and press enter") + -- inputElement with content reset on send + return $ tag (current $ _inputElement_value input) send + -- tag the send signal with the inputText value BEFORE resetting + +-- circuit ulW with a MM String kept updated by new strings from the passed +-- event and deletion of single element in the MM +listW :: (DomBuilder t m, PostBuild t m, MonadFix m, MonadHold t m) + => Event t T.Text -> m () +listW e = do + rec + xs <- foldDyn ($) M.empty $ mergeWith (.) + -- live state, updated by two signals + [ fmap new e -- insert a new text + , switch . current $ zs -- delete text at specific keys + ] + bs <- ulW xs -- delete signals from outputted state + let zs = fmap (mergeWith (.) . map (fmap M.delete) . M.elems) bs + -- merge delete events + return () + +app :: (DomBuilder t m, PostBuild t m, MonadFix m, MonadHold t m) => m () +app = el "div" $ do + el "h4" $ text "ToDo List" + inputW >>= listW diff --git a/reflex-dom-projects/generated/BasicToDo/Main.hs b/reflex-dom-projects/generated/BasicToDo/Main.hs new file mode 100644 index 0000000..0473774 --- /dev/null +++ b/reflex-dom-projects/generated/BasicToDo/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.BasicToDo.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/BasicToDo/Setup.hs b/reflex-dom-projects/generated/BasicToDo/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/BasicToDo/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/DragAndDrop/DragAndDrop.cabal b/reflex-dom-projects/generated/DragAndDrop/DragAndDrop.cabal new file mode 100644 index 0000000..4793375 --- /dev/null +++ b/reflex-dom-projects/generated/DragAndDrop/DragAndDrop.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-DragAndDrop +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-DragAndDrop + main-is: Main.hs + other-modules: Frontend.Examples.DragAndDrop.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/DragAndDrop/Frontend/Examples/DragAndDrop/Main.hs b/reflex-dom-projects/generated/DragAndDrop/Frontend/Examples/DragAndDrop/Main.hs new file mode 100644 index 0000000..c801fe3 --- /dev/null +++ b/reflex-dom-projects/generated/DragAndDrop/Frontend/Examples/DragAndDrop/Main.hs @@ -0,0 +1,127 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE DataKinds #-} + +module Frontend.Examples.DragAndDrop.Main where + +import Data.Maybe (fromMaybe) +import Data.Monoid ((<>)) +import qualified GHCJS.DOM.DataTransfer as DOM +import qualified GHCJS.DOM.HTMLElement as DOM +import qualified GHCJS.DOM.Element as DOM +import qualified GHCJS.DOM.EventM as DOM +import qualified GHCJS.DOM.GlobalEventHandlers as DOM +import qualified GHCJS.DOM.MouseEvent as DOM +import qualified GHCJS.DOM.Types as DOM (uncheckedCastTo) + +import Language.Javascript.JSaddle +import Reflex.Dom.Core + +app + :: ( DomBuilder t m + , MonadHold t m + , PostBuild t m + , PerformEvent t m + , TriggerEvent t m + , Prerender js m + ) + => m () +app = do + el "h3" $ text "Drag and Drop" + el "div" $ draggable item1 "Haskell logo" + el "div" $ draggable item2 "some text" + text "Drap either the above logo or the text to the below box" + handleDragEvents + return () + + +item1 :: DomBuilder t m => m (Element EventResult (DomBuilderSpace m) t, ()) +item1 = elAttr' "img" ("draggable" =: "true" <> "src" =: haskellLogoUrl) blank + where + haskellLogoUrl = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Haskell-Logo.svg/180px-Haskell-Logo.svg.png" + +item2 :: DomBuilder t m => m (Element EventResult (DomBuilderSpace m) t, ()) +item2 = elAttr' "pre" ("draggable" =: "true" + <> "style" =: "-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;user-select:none;") + $ text "Draggable text" + +draggable + :: ( DomBuilder t m + , TriggerEvent t m + , PerformEvent t m + , Prerender js m + ) + => m (Element EventResult (DomBuilderSpace m) t, ()) + -> String + -> m () +draggable elmnt attachment = do + dragsite <- fst <$> elmnt + prerender (return ()) $ do + dragStartEvent <- wrapDomEvent -- (_el_element dragsite) + -- (DOM.getToElement $ _element_raw dragsite) + (DOM.uncheckedCastTo DOM.HTMLElement $ _element_raw dragsite) + (`DOM.on` DOM.dragStart) $ do + dt <- fromMaybe (error "no dt?") + <$> (DOM.getDataTransfer =<< DOM.event) + DOM.setEffectAllowed dt ("all" :: JSString) + DOM.setDropEffect dt ("move" :: JSString) + DOM.setData dt + ("application/x-reflex-description" :: JSString) attachment + -- Bit of a hack here; this actually hooks the drag-start + -- event to the DOM, since otherwise nothing reflex-side + -- cares about the event + performEvent_ $ return () <$ dragStartEvent + return () + +handleDragEvents + :: ( DomBuilder t m + , TriggerEvent t m + , PostBuild t m + , MonadHold t m + , PerformEvent t m + , Prerender js m + ) + => m () +handleDragEvents = prerender (return ()) $ do + let + ddEvent :: (DOM.DataTransfer -> DOM.EventM e DOM.MouseEvent a) -> + DOM.EventM e DOM.MouseEvent a + ddEvent op = do + dt <- fromMaybe (error "no DT?") + <$> (DOM.getDataTransfer =<< DOM.event) + op dt + ddEvent_ :: DOM.EventM e DOM.MouseEvent () -> + DOM.EventM e DOM.MouseEvent () + ddEvent_ op = ddEvent (const op) + + rec + dragEnterEvent <- wrapDomEvent + dsHTMLel (`DOM.on` DOM.dragEnter) (ddEvent_ DOM.preventDefault) + dragLeaveEvent <- wrapDomEvent + dsHTMLel (`DOM.on` DOM.dragLeave) (ddEvent_ $ return ()) + dropsite <- fst <$> elDynAttr' "div" dropsiteAttrs (dynText dropText) + -- The following is defined to shorten the wrapDomEvent calls. + let dsHTMLel = DOM.uncheckedCastTo DOM.HTMLElement $ _element_raw dropsite + inDrop <- holdDyn False $ leftmost + [ True <$ dragEnterEvent + , False <$ dragLeaveEvent + , False <$ dropEvent] + dropsiteAttrs <- return . ffor inDrop $ \case + True -> "style" =: "border:1em solid blue;padding:2em;margin:2em;background-color:green;" + False -> "style" =: "border:1em solid blue;padding:2em;margin:2em;" + dragOverEvent <- wrapDomEvent + dsHTMLel (`DOM.on` DOM.dragOver) (ddEvent_ DOM.preventDefault) + performEvent_ $ return () <$ dragOverEvent + + dropEvent <- wrapDomEvent dsHTMLel (`DOM.on` DOM.drop) $ ddEvent $ \dt -> do + DOM.preventDefault + DOM.getData dt ("application/x-reflex-description" :: String) + dropText <- holdDyn "Drop here" $ fmap ("Dropped " <>) dropEvent + return () diff --git a/reflex-dom-projects/generated/DragAndDrop/Main.hs b/reflex-dom-projects/generated/DragAndDrop/Main.hs new file mode 100644 index 0000000..549e7f8 --- /dev/null +++ b/reflex-dom-projects/generated/DragAndDrop/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.DragAndDrop.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/DragAndDrop/Setup.hs b/reflex-dom-projects/generated/DragAndDrop/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/DragAndDrop/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/FileReader/FileReader.cabal b/reflex-dom-projects/generated/FileReader/FileReader.cabal new file mode 100644 index 0000000..5208e93 --- /dev/null +++ b/reflex-dom-projects/generated/FileReader/FileReader.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-FileReader +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-FileReader + main-is: Main.hs + other-modules: Frontend.Examples.FileReader.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/FileReader/Frontend/Examples/FileReader/Main.hs b/reflex-dom-projects/generated/FileReader/Frontend/Examples/FileReader/Main.hs new file mode 100644 index 0000000..5796deb --- /dev/null +++ b/reflex-dom-projects/generated/FileReader/Frontend/Examples/FileReader/Main.hs @@ -0,0 +1,68 @@ +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE TypeFamilies #-} + +module Frontend.Examples.FileReader.Main where + +import Control.Monad ((<=<), void) +import Data.Maybe (listToMaybe) +import Data.Monoid ((<>)) +import Data.Text (Text) +import qualified Data.Text as T +import GHCJS.DOM.EventM (on) +import GHCJS.DOM.FileReader (newFileReader, readAsDataURL, load + , getResult) +import Language.Javascript.JSaddle +import Reflex.Dom + +app + :: ( DomBuilder t m + , MonadHold t m + , PerformEvent t m + , TriggerEvent t m + , Prerender js m + ) + => m () +app = do + header + filesDyn <- fileInputElement + urlE <- fmap (ffilter ("data:image" `T.isPrefixOf`)) + . dataURLFileReader + . fmapMaybe listToMaybe + . updated $ filesDyn + el "br" blank + void $ el "div" + . widgetHold blank + . ffor urlE $ \url -> + elAttr "img" ("src" =: url <> "style" =: "max-width: 80%") blank + +fileInputElement :: DomBuilder t m => m (Dynamic t [RawFile (DomBuilderSpace m)]) +fileInputElement = do + ie <- inputElement $ def + & inputElementConfig_elementConfig . elementConfig_initialAttributes .~ + ("type" =: "file" <> "accept" =: "image/png, image/jpeg") + return (_inputElement_files ie) + +dataURLFileReader + :: ( DomBuilder t m + , TriggerEvent t m + , PerformEvent t m + , Prerender js m + ) + => Event t (RawFile (DomBuilderSpace m)) -> m (Event t Text) +dataURLFileReader request = prerender (return never) $ do + fileReader <- liftJSM newFileReader + performEvent_ (fmap (readAsDataURL fileReader . Just) request) + e <- wrapDomEvent fileReader (`on` load) . liftJSM $ do + v <- getResult fileReader + (fromJSVal <=< toJSVal) v + return (fmapMaybe id e) + +header :: DomBuilder t m => m () +header = do + el "strong" $ do + text " FileReader test page" + el "p" $ + text "Select an image file. It will be shown below" diff --git a/reflex-dom-projects/generated/FileReader/Main.hs b/reflex-dom-projects/generated/FileReader/Main.hs new file mode 100644 index 0000000..60c0ce4 --- /dev/null +++ b/reflex-dom-projects/generated/FileReader/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.FileReader.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/FileReader/Setup.hs b/reflex-dom-projects/generated/FileReader/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/FileReader/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/NasaPod/Frontend/Examples/NasaPod/Main.hs b/reflex-dom-projects/generated/NasaPod/Frontend/Examples/NasaPod/Main.hs new file mode 100644 index 0000000..f9b4e04 --- /dev/null +++ b/reflex-dom-projects/generated/NasaPod/Frontend/Examples/NasaPod/Main.hs @@ -0,0 +1,90 @@ +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Frontend.Examples.NasaPod.Main where + +import Data.Aeson (FromJSON, ToJSON) +import Data.Map (Map) +import Data.Monoid ((<>)) +import qualified Data.Text as T +import Data.Text (Text) +import GHC.Generics (Generic) +import Reflex.Dom +import Control.Monad.Fix (MonadFix) + +data Apod = + Apod { date :: T.Text + , explanation :: T.Text + , hdurl :: T.Text + , media_type :: T.Text + , service_version :: T.Text + , title :: T.Text + , url :: T.Text + } + deriving (Generic, Show) + +instance FromJSON Apod +instance ToJSON Apod + +app + :: ( DomBuilder t m + , MonadFix m + , MonadHold t m + , PostBuild t m + , PerformEvent t m + , TriggerEvent t m + , Prerender js m + ) + => m () +app = el "div" $ do + apiKey <- inputElement $ def & initialAttributes .~ ("placeholder" =: "Enter NASA API Key") + submitEvent <- button "Submit" + let submitApiKey = tagPromptlyDyn (value apiKey) submitEvent + loadingWidget = el "div" $ do + el "p" $ do + text "Get your API key from the " + elAttr "a" ("href" =: "https://api.nasa.gov/" <> "target" =: "_blank") $ text "NASA Open API" + text " site" + _ <- widgetHold loadingWidget $ fmap apod submitApiKey + return () + +apod + :: ( DomBuilder t m + , MonadFix m + , PerformEvent t m + , MonadHold t m + , PostBuild t m + , TriggerEvent t m + , Prerender js m + ) + => Text + -> m () +apod apiKey = prerender (blank) $ do + pb :: Event t () <- getPostBuild + let + defReq = "https://api.nasa.gov/planetary/apod?api_key=" <> apiKey + xhrTxt :: Maybe T.Text -> T.Text + xhrTxt = maybe defReq (\d -> defReq <> "&date=" <> d) + req md = XhrRequest "GET" (xhrTxt md) def + rec + eRsp :: Event t XhrResponse <- performRequestAsync $ req <$> + leftmost [ Nothing <$ pb + , fmap Just eValidDate + ] + let + eRspApod :: Event t Apod = fmapMaybe decodeXhrResponse eRsp + imgUrl :: Event t T.Text = fmap url eRspApod + explEv :: Event t T.Text = fmap explanation eRspApod + srcAttr :: Event t (Map T.Text T.Text) = ffor imgUrl $ \u -> "src" =: u + srcAttrDyn :: Dynamic t (Map T.Text T.Text) + <- holdDyn mempty srcAttr + elDynAttr "img" srcAttrDyn $ return () + date <- textInput $ def & + attributes .~ constDyn ("placeholder" =: "YYYY-MM-DD") + let eValidDate = ffilter ((==10) . T.length) $ updated $ value date + el "p" $ + dynText =<< holdDyn "Waiting for response" explEv + return () + diff --git a/reflex-dom-projects/generated/NasaPod/Main.hs b/reflex-dom-projects/generated/NasaPod/Main.hs new file mode 100644 index 0000000..5247b9f --- /dev/null +++ b/reflex-dom-projects/generated/NasaPod/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.NasaPod.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/NasaPod/NasaPod.cabal b/reflex-dom-projects/generated/NasaPod/NasaPod.cabal new file mode 100644 index 0000000..c850f16 --- /dev/null +++ b/reflex-dom-projects/generated/NasaPod/NasaPod.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-NasaPod +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-NasaPod + main-is: Main.hs + other-modules: Frontend.Examples.NasaPod.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/NasaPod/Setup.hs b/reflex-dom-projects/generated/NasaPod/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/NasaPod/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/ScreenKeyboard/Frontend/Examples/ScreenKeyboard/Main.hs b/reflex-dom-projects/generated/ScreenKeyboard/Frontend/Examples/ScreenKeyboard/Main.hs new file mode 100644 index 0000000..4961ee9 --- /dev/null +++ b/reflex-dom-projects/generated/ScreenKeyboard/Frontend/Examples/ScreenKeyboard/Main.hs @@ -0,0 +1,87 @@ +{-# LANGUAGE OverloadedLists #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE PartialTypeSignatures #-} +{-# LANGUAGE FlexibleContexts #-} + +module Frontend.Examples.ScreenKeyboard.Main where + +{- + - buttons + real keyboard both writing to a text box + -} + +import Control.Monad (forM, void) +import Control.Monad.Fix (MonadFix) +import qualified Data.List.NonEmpty as DL (head) +import Data.Monoid ((<>)) +import qualified Data.Text as T +import Data.Text (Text) +import GHCJS.DOM.HTMLElement (focus) +import GHCJS.DOM.HTMLInputElement hiding (setValue) +import Language.Javascript.JSaddle +import Reflex.Dom + +-- import Language.Javascript.JSaddle.Warp + + +insertAt :: Int -> Char -> T.Text -> T.Text +insertAt n c v = T.take n v <> T.singleton c <> T.drop n v + +fromListE :: Reflex t => [Event t a] -> Event t a +fromListE = fmap DL.head . mergeList + +performArg :: (PerformEvent t m, MonadJSM (Performable m)) + => (b -> JSM a) -> Event t b -> m (Event t a) +performArg f x = performEvent (fmap (liftJSM . f) x) + +inputW + :: ( DomBuilder t m + , Prerender js m + , PerformEvent t m + , MonadFix m + ) + => Event t Char + -> m () +inputW buttonE = do + rec + let + html = _inputElement_raw input -- html element + cur = current $ value input -- actual string + input <- inputElement $ def + & inputElementConfig_setValue .~ fmap snd newStringE + newStringE <- doStuff cur html buttonE + return () + +doStuff + :: ( DomBuilder t m + , Prerender js m + , PerformEvent t m + ) + => Behavior t Text + -> RawInputElement (DomBuilderSpace m) + -> Event t Char + -> m (Event t (Int, Text)) +doStuff cur html buttonE = do + posCharE :: Event t (Char, Int) <- prerender (return never) $ do + ev <- performArg (\c -> (,) c <$> getSelectionStart html) buttonE + void $ (flip performArg) (fmap snd ev) $ \n -> do + setSelectionStart html (n + 1) + setSelectionEnd html (n + 1) + void $ performArg (const $ focus html) buttonE -- keep the focus right + return ev + let + newStringE = attachWith (\v (c, n) -> (n + 1, insertAt n c v)) cur posCharE + return newStringE + +keys :: DomBuilder t m => m [Event t Char] +keys = forM "qwerty" $ \c -> fmap (const c) <$> button [c] -- OverloadedLists + +app + :: ( DomBuilder t m + , MonadFix m + , PerformEvent t m + , Prerender js m + ) + => m () +app = el "div" $ elClass "div" "keys" keys >>= inputW . fromListE diff --git a/reflex-dom-projects/generated/ScreenKeyboard/Main.hs b/reflex-dom-projects/generated/ScreenKeyboard/Main.hs new file mode 100644 index 0000000..6a443de --- /dev/null +++ b/reflex-dom-projects/generated/ScreenKeyboard/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.ScreenKeyboard.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
@ tag that will set its title and the class of its child +-- @
@ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/ScreenKeyboard/ScreenKeyboard.cabal b/reflex-dom-projects/generated/ScreenKeyboard/ScreenKeyboard.cabal new file mode 100644 index 0000000..065ceaa --- /dev/null +++ b/reflex-dom-projects/generated/ScreenKeyboard/ScreenKeyboard.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-ScreenKeyboard +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-ScreenKeyboard + main-is: Main.hs + other-modules: Frontend.Examples.ScreenKeyboard.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/ScreenKeyboard/Setup.hs b/reflex-dom-projects/generated/ScreenKeyboard/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/ScreenKeyboard/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/Main.hs b/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/Main.hs new file mode 100644 index 0000000..f5c0c82 --- /dev/null +++ b/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/Main.hs @@ -0,0 +1,171 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecursiveDo #-} +{-# LANGUAGE LambdaCase #-} + +module Frontend.Examples.TicTacToe.Main + (app) + where + +import qualified Data.Text as T +import Data.Text (Text) +import Control.Monad (forM) +import Control.Monad.Fix (MonadFix) +import Data.List (elem) +import Reflex.Dom +import Data.Array (Array, Ix) +import qualified Data.Array as A + +data Row = + Row_1 + | Row_2 + | Row_3 + deriving (Eq, Show, Ord, Enum, Bounded, Ix) + +data Col = + Col_1 + | Col_2 + | Col_3 + deriving (Eq, Show, Ord, Enum, Bounded, Ix) + +data Player = + Player_X + | Player_O + deriving (Eq, Show, Ord, Enum, Bounded) + +winningPos :: [[(Row, Col)]] +winningPos = + [[(a, b) | a <- [Row_1 .. ]] | b <- [Col_1 .. ]] + <> [[(a, b) | b <- [Col_1 .. ]] | a <- [Row_1 .. ]] + <> [ [(Row_1, Col_1), (Row_2, Col_2), (Row_3, Col_3)] + , [(Row_1, Col_3), (Row_2, Col_2), (Row_3, Col_1)] + ] + +-- This is not really required, as the Moves is sufficient +type Squares = Array (Row, Col) (Maybe Player) +type MovePos = (Row, Col) +type Moves = [MovePos] + +data State = State + { state_currentMove :: Int + , state_moves :: Moves + } + +data Action = + Action_GoToMove Int + | Action_DoMove MovePos + +app + :: ( DomBuilder t m + , MonadFix m + , MonadHold t m + , PostBuild t m + ) + => m () +app = divClass "game" $ do + let initState = State 0 [] + + rec + let + squares = ffor stateDyn $ \(State p mvs) -> makeSquares $ take p mvs + stateDyn <- foldDynMaybe changeGameState initState $ + leftmost [goToMove, newMove] + newMove <- gameBoard squares + goToMove <- gameInfo stateDyn + return () + +makeSquares :: Moves -> Squares +makeSquares mvs = A.accumArray (flip const) Nothing ((Row_1, Col_1), (Row_3, Col_3)) ls + where + ls = zip mvs $ concat $ repeat [Just Player_X, Just Player_O] + +changeGameState :: Action -> State -> Maybe State +changeGameState a (State p moves) = case a of + (Action_GoToMove i) -> Just $ State i moves + (Action_DoMove m) -> case (checkWon curMoves, elem m curMoves) of + (Nothing, False) -> Just $ State (p + 1) newMoves + _ -> Nothing + where + newMoves = curMoves ++ [m] + curMoves = take p moves + +checkWon :: Moves -> Maybe Player +checkWon mvs = case (isWin pX, isWin pO) of + (True, _) -> Just Player_X + (False, True) -> Just Player_O + (False, False) -> Nothing + where + -- find if any set of winning moves are present in player' moves + isWin pmvs = any (\wmvs -> all (\wm -> elem wm pmvs) wmvs) winningPos + -- divide moves for X and O + (pX, pO) = f mvs Player_X ([], []) + f [] _ v = v + f (m:ms) Player_X (xs, os)= f ms Player_O (xs ++ [m], os) + f (m:ms) Player_O (xs, os)= f ms Player_X (xs, os ++ [m]) + +gameBoard + :: ( DomBuilder t m + , PostBuild t m + ) + => Dynamic t Squares + -> m (Event t Action) +gameBoard squares = divClass "game-board" $ do + evs <- forM [minBound .. maxBound] $ \row -> divClass "board-row" $ do + evs <- forM [minBound .. maxBound] $ \col -> do + let + square = (row, col) + style = "height: 2em; width: 2em; position: block;" + (btn1,_) <- elAttr' "button" ("style" =: style) $ + dynText (getSquareText square <$> squares) + return (square <$ domEvent Click btn1) + return (leftmost evs) + return $ Action_DoMove <$> leftmost evs + +-- | What to display on square +getSquareText :: (Row, Col) -> Squares -> Text +getSquareText square squares = case squares A.! square of + Nothing -> "." + (Just Player_X) -> "X" + (Just Player_O) -> "O" + +gameInfo + :: ( DomBuilder t m + , MonadFix m + , PostBuild t m + , MonadHold t m + ) + => Dynamic t State + -> m (Event t Action) +gameInfo stateDyn = divClass "game-info" $ do + let + nextPlayer = ffor stateDyn $ \(State p _) -> if even p + then Player_X + else Player_O + moveCount = (length . state_moves <$> stateDyn) + + el "div" $ do + dyn_ $ ffor (checkWon . state_moves <$> stateDyn) $ \case + Nothing -> do + text "Next player: " + dynText $ ffor nextPlayer $ \case + Player_X -> "X" + Player_O -> "O" + (Just p) -> do + text "Winner player: " + text $ case p of + Player_X -> "X" + Player_O -> "O" + + el "ol" $ do + ev1 <- el "li" $ do + button "Go to game start" + + let + moves = ffor moveCount $ \i -> [1..i] + evDyn <- simpleList moves $ \iDyn -> do + i <- sample $ current iDyn + el "li" $ do + ev <- button $ "Go to move #" <> T.pack (show i) + return (Action_GoToMove i <$ ev) + + let ev2 = switch (current $ leftmost <$> evDyn) + return $ leftmost $ [Action_GoToMove 0 <$ ev1, ev2] diff --git a/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts b/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts new file mode 100644 index 0000000..6e8b0b6 --- /dev/null +++ b/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts @@ -0,0 +1,144 @@ +function Square(props) { + return ( + + ); +} + +class Board extends React.Component { + renderSquare(i) { + return ( + this.props.onClick(i)} + /> + ); + } + + render() { + return ( +
+
+ {this.renderSquare(0)} + {this.renderSquare(1)} + {this.renderSquare(2)} +
+
+ {this.renderSquare(3)} + {this.renderSquare(4)} + {this.renderSquare(5)} +
+
+ {this.renderSquare(6)} + {this.renderSquare(7)} + {this.renderSquare(8)} +
+
+ ); + } +} + +class Game extends React.Component { + constructor(props) { + super(props); + this.state = { + history: [ + { + squares: Array(9).fill(null) + } + ], + stepNumber: 0, + xIsNext: true + }; + } + + handleClick(i) { + const history = this.state.history.slice(0, this.state.stepNumber + 1); + const current = history[history.length - 1]; + const squares = current.squares.slice(); + if (calculateWinner(squares) || squares[i]) { + return; + } + squares[i] = this.state.xIsNext ? "X" : "O"; + this.setState({ + history: history.concat([ + { + squares: squares + } + ]), + stepNumber: history.length, + xIsNext: !this.state.xIsNext + }); + } + + jumpTo(step) { + this.setState({ + stepNumber: step, + xIsNext: (step % 2) === 0 + }); + } + + render() { + const history = this.state.history; + const current = history[this.state.stepNumber]; + const winner = calculateWinner(current.squares); + + const moves = history.map((step, move) => { + const desc = move ? + 'Go to move #' + move : + 'Go to game start'; + return ( +
  • + +
  • + ); + }); + + let status; + if (winner) { + status = "Winner: " + winner; + } else { + status = "Next player: " + (this.state.xIsNext ? "X" : "O"); + } + + return ( +
    +
    + this.handleClick(i)} + /> +
    +
    +
    {status}
    +
      {moves}
    +
    +
    + ); + } +} + +// ======================================== + +ReactDOM.render(, document.getElementById("root")); + +function calculateWinner(squares) { + const lines = [ + [0, 1, 2], + [3, 4, 5], + [6, 7, 8], + [0, 3, 6], + [1, 4, 7], + [2, 5, 8], + [0, 4, 8], + [2, 4, 6] + ]; + for (let i = 0; i < lines.length; i++) { + const [a, b, c] = lines[i]; + if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { + return squares[a]; + } + } + return null; +} diff --git a/reflex-dom-projects/generated/TicTacToe/Main.hs b/reflex-dom-projects/generated/TicTacToe/Main.hs new file mode 100644 index 0000000..7ed8795 --- /dev/null +++ b/reflex-dom-projects/generated/TicTacToe/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.TicTacToe.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
    @ tag that will set its title and the class of its child +-- @
    @ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/TicTacToe/Setup.hs b/reflex-dom-projects/generated/TicTacToe/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/TicTacToe/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/TicTacToe/TicTacToe.cabal b/reflex-dom-projects/generated/TicTacToe/TicTacToe.cabal new file mode 100644 index 0000000..f8b3457 --- /dev/null +++ b/reflex-dom-projects/generated/TicTacToe/TicTacToe.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-TicTacToe +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-TicTacToe + main-is: Main.hs + other-modules: Frontend.Examples.TicTacToe.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/generated/WebSocketEcho/Frontend/Examples/WebSocketEcho/Main.hs b/reflex-dom-projects/generated/WebSocketEcho/Frontend/Examples/WebSocketEcho/Main.hs new file mode 100644 index 0000000..6a27790 --- /dev/null +++ b/reflex-dom-projects/generated/WebSocketEcho/Frontend/Examples/WebSocketEcho/Main.hs @@ -0,0 +1,46 @@ +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RecursiveDo #-} + +module Frontend.Examples.WebSocketEcho.Main where + +import Data.Text.Encoding (encodeUtf8, decodeUtf8) +import Reflex.Dom +import Control.Monad.Fix (MonadFix) + +app + :: ( DomBuilder t m + , MonadFix m + , MonadHold t m + , PostBuild t m + , PerformEvent t m + , TriggerEvent t m + , Prerender js m + ) + => m () +app = do + header + rec t <- inputElement $ def & inputElementConfig_setValue .~ fmap (const "") newMessage + b <- button "Send" + let newMessage = fmap ((:[]) . encodeUtf8) + $ tag (current $ value t) + $ leftmost [b, keypress Enter t] + + receivedMessages <- prerender (return (constDyn [])) $ do + ws <- webSocket "wss://echo.websocket.org" $ def + & webSocketConfig_send .~ newMessage + foldDyn (\m ms -> ms ++ [m]) [] $ _webSocket_recv ws + + el "p" $ text "Responses from the WebSocket.org echo service:" + _ <- el "ul" + $ simpleList receivedMessages + $ \m -> el "li" $ dynText $ fmap decodeUtf8 m + return () + +header :: DomBuilder t m => m () +header = do + el "strong" $ do + text " WebSocket test page" + el "p" $ do + text "Send a message to the WebSocket.org: https://www.websocket.org/echo.html" + text "'s websocket echo service:" diff --git a/reflex-dom-projects/generated/WebSocketEcho/Main.hs b/reflex-dom-projects/generated/WebSocketEcho/Main.hs new file mode 100644 index 0000000..70606bc --- /dev/null +++ b/reflex-dom-projects/generated/WebSocketEcho/Main.hs @@ -0,0 +1,56 @@ +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Frontend.Examples.WebSocketEcho.Main +import Reflex.Dom +import Data.Map (Map) +import Data.Text (Text) +import qualified Data.Text as T + +main :: IO () +main = mainWidgetWithHead pageHead $ do + article $ app + +-- | An @
    @ tag that will set its title and the class of its child +-- @
    @ based on the current route +article + :: ( DomBuilder t m + , PostBuild t m + ) + => m () -- ^ Article content widget + -> m () +article c = el "main" $ el "article" c + +pageHead :: DomBuilder t m => m () +pageHead = do + el "title" $ text "Reflex FRP Examples" + elAttr "meta" metaDesc blank + elAttr "meta" metaKeywords blank + elAttr "meta" viewport blank + styleSheet $ "static/css/normalize.css" + styleSheet $ "static/css/fontawesome.min.css" + styleSheet $ "static/css/font.css" + styleSheet $ "static/css/style.css" + -- elAttr "script" ("type" =: "text/javascript" <> "src" =: static @"echarts.min.js") blank + +metaDesc :: Map Text Text +metaDesc = "name" =: "description" + <> "content" =: "Reflex Functional Reactive Programming Examples" + +metaKeywords :: Map Text Text +metaKeywords = "name" =: "keywords" + <> "content" =: "reflex, reflex frp, functional reactive programming, haskell, framework, reflex dom" + +viewport :: Map Text Text +viewport = "name" =: "viewport" + <> "content" =: "width=device-width, initial-scale=1" + +-- styleSheet are functions to add links to html +styleSheet :: DomBuilder t m => Text -> m () +styleSheet myLink = elAttr "link" attrs blank + where attrs = "rel" =: "stylesheet" + <> "type" =: "text/css" + <> "href" =: myLink + +tshow :: Show a => a -> Text +tshow = T.pack . show diff --git a/reflex-dom-projects/generated/WebSocketEcho/Setup.hs b/reflex-dom-projects/generated/WebSocketEcho/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/reflex-dom-projects/generated/WebSocketEcho/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/reflex-dom-projects/generated/WebSocketEcho/WebSocketEcho.cabal b/reflex-dom-projects/generated/WebSocketEcho/WebSocketEcho.cabal new file mode 100644 index 0000000..19720b4 --- /dev/null +++ b/reflex-dom-projects/generated/WebSocketEcho/WebSocketEcho.cabal @@ -0,0 +1,37 @@ +name: reflex-examples-WebSocketEcho +version: 0.1.0.0 +synopsis: Examples for reflex and reflex-dom +-- description: +homepage: https://github.com/reflex-frp/reflex-examples +license: BSD3 +license-file: LICENSE +author: Divam +maintainer: dfordivam@gmail.com +-- copyright: +category: Web +build-type: Simple +extra-source-files: ChangeLog.md +cabal-version: >=1.10 + +executable reflex-examples-WebSocketEcho + main-is: Main.hs + other-modules: Frontend.Examples.WebSocketEcho.Main + -- other-extensions: + build-depends: base >=4.11 && <4.12 + , bytestring + , containers + , ghcjs-dom + , jsaddle + , lens + , modern-uri + , reflex + , reflex-dom + , random + , time + , vector + , unordered-containers + , text + , aeson + , array + -- , jsaddle-warp + default-language: Haskell2010 diff --git a/reflex-dom-projects/template/template.cabal b/reflex-dom-projects/template/template.cabal index 29d35dd..e392647 100644 --- a/reflex-dom-projects/template/template.cabal +++ b/reflex-dom-projects/template/template.cabal @@ -31,5 +31,7 @@ executable reflex-examples-EXAMPLENAME , vector , unordered-containers , text + , aeson + , array -- , jsaddle-warp default-language: Haskell2010 From cc1992e74da9e2410b38dd371aa1eea87af46f9c Mon Sep 17 00:00:00 2001 From: Divam Date: Fri, 18 Jan 2019 22:01:11 +0900 Subject: [PATCH 4/4] Remove stray file --- .../Frontend/Examples/TicTacToe/tictactoe.ts | 144 ------------------ 1 file changed, 144 deletions(-) delete mode 100644 reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts diff --git a/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts b/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts deleted file mode 100644 index 6e8b0b6..0000000 --- a/reflex-dom-projects/generated/TicTacToe/Frontend/Examples/TicTacToe/tictactoe.ts +++ /dev/null @@ -1,144 +0,0 @@ -function Square(props) { - return ( - - ); -} - -class Board extends React.Component { - renderSquare(i) { - return ( - this.props.onClick(i)} - /> - ); - } - - render() { - return ( -
    -
    - {this.renderSquare(0)} - {this.renderSquare(1)} - {this.renderSquare(2)} -
    -
    - {this.renderSquare(3)} - {this.renderSquare(4)} - {this.renderSquare(5)} -
    -
    - {this.renderSquare(6)} - {this.renderSquare(7)} - {this.renderSquare(8)} -
    -
    - ); - } -} - -class Game extends React.Component { - constructor(props) { - super(props); - this.state = { - history: [ - { - squares: Array(9).fill(null) - } - ], - stepNumber: 0, - xIsNext: true - }; - } - - handleClick(i) { - const history = this.state.history.slice(0, this.state.stepNumber + 1); - const current = history[history.length - 1]; - const squares = current.squares.slice(); - if (calculateWinner(squares) || squares[i]) { - return; - } - squares[i] = this.state.xIsNext ? "X" : "O"; - this.setState({ - history: history.concat([ - { - squares: squares - } - ]), - stepNumber: history.length, - xIsNext: !this.state.xIsNext - }); - } - - jumpTo(step) { - this.setState({ - stepNumber: step, - xIsNext: (step % 2) === 0 - }); - } - - render() { - const history = this.state.history; - const current = history[this.state.stepNumber]; - const winner = calculateWinner(current.squares); - - const moves = history.map((step, move) => { - const desc = move ? - 'Go to move #' + move : - 'Go to game start'; - return ( -
  • - -
  • - ); - }); - - let status; - if (winner) { - status = "Winner: " + winner; - } else { - status = "Next player: " + (this.state.xIsNext ? "X" : "O"); - } - - return ( -
    -
    - this.handleClick(i)} - /> -
    -
    -
    {status}
    -
      {moves}
    -
    -
    - ); - } -} - -// ======================================== - -ReactDOM.render(, document.getElementById("root")); - -function calculateWinner(squares) { - const lines = [ - [0, 1, 2], - [3, 4, 5], - [6, 7, 8], - [0, 3, 6], - [1, 4, 7], - [2, 5, 8], - [0, 4, 8], - [2, 4, 6] - ]; - for (let i = 0; i < lines.length; i++) { - const [a, b, c] = lines[i]; - if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) { - return squares[a]; - } - } - return null; -}