diff --git a/todo-mvc/build.nix b/todo-mvc/build.nix index 0ea8a5d..ad1050b 100644 --- a/todo-mvc/build.nix +++ b/todo-mvc/build.nix @@ -1,38 +1,11 @@ -with import {}; -let haskellPackages = pkgs.haskellPackages_ghcjs.override { - extension = self: super: { +with (import {}).pkgs; +let + hsPackages = haskell-ng.packages.ghcjs.override { + overrides = self: super: { + virtual-dom = self.callPackage ./virtual-dom {}; oHm = self.callPackage ./oHm {}; - mvc = self.callPackage ./oHm/mvc.nix {}; - todo = self.callPackage ./. {}; + todo-mvc = self.callPackage ./. {}; }; }; - inherit (haskellPackages) ghc aeson ghcjsBase ghcjsDom ghcjsPrim - oHm lens pipes pipesConcurrency mvc profunctors; - npm = pkgs.nodePackages.npm; - browserify = pkgs.nodePackages.browserify; - - client = stdenv.mkDerivation { - name = "chat-client"; - version = "1.0"; - src = ./.; - buildInputs = [ ghc aeson ghcjsBase ghcjsDom ghcjsPrim - oHm lens pipes pipesConcurrency mvc profunctors - npm browserify closurecompiler - ]; - installPhase = '' - mkdir -p $out - cp static/index.html $out - cp static/style.css $out - cp static/bg.png $out - cp "${haskellPackages.todo}/bin/todo-mvc.jsexe/all.js" $out - # closure-compiler $out/all.js --compilation_level=ADVANCED_OPTIMIZATIONS > $out/all.min.js - # gzip --best -k $out/all.min.js - ''; - }; - -in client - # { inherit (haskellPackages) ghc aeson ghcjsBase ghcjsDom ghcjsPrim - # oHm ohmChatServer lens pipes pipesConcurrency mvc profunctors; - # inherit (pkg.nodePackages) npm browserify; - # closurecompiler = pkgs.closurecompiler; - # } \ No newline at end of file +in + hsPackages.todo-mvc diff --git a/todo-mvc/default.nix b/todo-mvc/default.nix index 3e40f9e..7951a77 100644 --- a/todo-mvc/default.nix +++ b/todo-mvc/default.nix @@ -1,20 +1,17 @@ -{ cabal, aeson, ghcjsBase, ghcjsDom, ghcjsPrim, lens, mvc, oHm -, pipes, pipesConcurrency, profunctors, stm, time +{ cabal-install, mkDerivation, aeson, base, containers, ghcjs-base, ghcjs-dom +, ghcjs-prim, lens, mvc, oHm, pipes, pipes-concurrency, profunctors +, stdenv, stm, text, time, transformers, virtual-dom }: - -cabal.mkDerivation (self: { +mkDerivation { pname = "ohm-todo-mvc"; version = "0.1.0.0"; src = ./.; isLibrary = false; isExecutable = true; buildDepends = [ - aeson ghcjsBase ghcjsDom ghcjsPrim lens mvc oHm pipes - pipesConcurrency profunctors stm time + cabal-install aeson base containers ghcjs-base ghcjs-dom ghcjs-prim lens mvc oHm + pipes pipes-concurrency profunctors stm text time transformers + virtual-dom ]; - doCheck = false; - meta = { - license = self.stdenv.lib.licenses.unfree; - platforms = self.ghc.meta.platforms; - }; -}) + license = stdenv.lib.licenses.unfree; +} diff --git a/todo-mvc/ohm-todo-mvc.cabal b/todo-mvc/ohm-todo-mvc.cabal index 126f9af..c4a9ffa 100644 --- a/todo-mvc/ohm-todo-mvc.cabal +++ b/todo-mvc/ohm-todo-mvc.cabal @@ -16,7 +16,7 @@ executable todo-mvc main-is: Main.hs -- other-modules: other-extensions: ForeignFunctionInterface, GeneralizedNewtypeDeriving, OverloadedStrings - build-depends: base >=4.7 && <4.8 + build-depends: base >=4.7 && <5 , containers >=0.5 && <0.6 , lens , profunctors @@ -33,8 +33,8 @@ executable todo-mvc , ghcjs-dom >=0.1.1.1 , ghcjs-prim >= 0.1.0.0 , oHm + , virtual-dom hs-source-dirs: src - js-sources: static/deps.js ghcjs-options: -O3 -Wall cpp-options: -DGHCJS_BROWSER -DGHCJS_BUSY_YIELD=30 default-language: Haskell2010 diff --git a/todo-mvc/shell.nix b/todo-mvc/shell.nix index 2cf5fce..0bd9380 100644 --- a/todo-mvc/shell.nix +++ b/todo-mvc/shell.nix @@ -1,18 +1,12 @@ -with import {}; -let haskellPackages = pkgs.haskellPackages_ghcjs.override { - extension = self: super: { +with (import {}).pkgs; +with (import {pkgs = (import {});}); +let + hsPackages = haskell-ng.packages.ghcjs.override { + overrides = self: super: { + virtual-dom = self.callPackage ./virtual-dom {}; oHm = self.callPackage ./oHm {}; - todo = self.callPackage ./. {}; + todo-mvc = self.callPackage ./. { cabal-install = haskell-ng.packages.ghc7101.cabal-install; }; }; }; - -in pkgs.callPackage ./. { - cabal = haskellPackages.cabal.override { - extension = self: super: { - buildTools = super.buildTools ++ [ haskellPackages.ghc.ghc.parent.cabalInstall ]; - }; - }; - inherit (haskellPackages) aeson ghcjsBase ghcjsDom ghcjsPrim oHm lens mvc pipes - pipesConcurrency profunctors stm; - - } +in + hsPackages.todo-mvc.env diff --git a/todo-mvc/src/Main.hs b/todo-mvc/src/Main.hs index 4ce5182..70b5ec8 100644 --- a/todo-mvc/src/Main.hs +++ b/todo-mvc/src/Main.hs @@ -7,12 +7,16 @@ import Control.Lens hiding (Index, Action) import Pipes --import Prelude hiding ((.)) import Control.Applicative +import Control.Monad.Trans.State.Strict import Data.Foldable (traverse_) import Ohm.Component import Ohm.HTML -import Prelude hiding (div,id,span,map, filter) -import qualified Prelude as P +import VirtualDom +import VirtualDom.Prim (HTMLElement, _HTMLElement, HTML, text, properties, attributes) +import VirtualDom.HTML.Attributes hiding (form_, span_) +import GHCJS.Foreign + -------------------------------------------------------------------------------- type Index = Int @@ -72,31 +76,31 @@ showFilter Active = "Active" showFilter Completed = "Completed" filterItems :: Filter -> [Item] -> [Item] -filterItems All = P.id -filterItems Active = P.filter (not . _completed) -filterItems Completed = P.filter _completed +filterItems All = id +filterItems Active = filter (not . _completed) +filterItems Completed = filter _completed todoView :: DOMEvent Action -> ToDo -> HTML todoView chan todo@(ToDo itemList _txtEntry currentFilter) = - with div + with div_ (classes .= ["body"]) [ titleRender, itemsRender, renderFilters chan todo] where - titleRender = with h1 (classes .= ["title"]) ["todos"] - itemsRender = with ul (classes .= ["items"]) - (newItem chan todo : (P.map (renderItem chan) $ zip [0..] filteredItems)) + titleRender = with h1_ (classes .= ["title"]) ["todos"] + itemsRender = with ul_ (classes .= ["items"]) + (newItem chan todo : (map (renderItem chan) $ zip [0..] filteredItems)) filteredItems = filterItems currentFilter itemList newItem :: DOMEvent Action -> ToDo -> HTML newItem chan todo = - with li (classes .= ["newItem"]) - [ into form - [ with input (do - attrs . at "placeholder" ?= "Create a new task" - props . at "value" ?= value + with li_ (classes .= ["newItem"]) + [ into form_ + [ with input_ (do + attributes . at "placeholder" ?= "Create a new task" + properties . at "value" ?= value onInput $ contramap SetEditText chan) [] - , with (btn click "Create") (attrs . at "hidden" ?= "true") ["Create"] + , with (btn click "Create") (attributes . at "hidden" ?= "true") ["Create"] ] ] where @@ -105,34 +109,37 @@ newItem chan todo = renderItem :: DOMEvent Action -> (Int, Item) -> HTML renderItem chan (idx, (Item itemTitle complete)) = - into li - [ into form - [ with input (do - props . at "type" ?= "checkbox" - attrs . at "title" ?= "Mark as Completed" - props . at "checked" ?= (if complete then "checked" else "") + into li_ + [ into form_ + [ with input_ (do + properties . at "type" ?= "checkbox" + attributes . at "title" ?= "Mark as Completed" + properties . at "checked" ?= (if complete then "checked" else "") onChange $ contramap (const $ SetCompleted idx (if complete then False else True)) chan classes .= ["completed"]) [] - , with span (classes .= ["description"]) + , with span_ (classes .= ["description"]) [text itemTitle] - , (btn clickCancel "✖") &~ do - classes .= ["complete"] - attrs . at "title" ?= "Remove Item" + , cancelBtn ] ] - where clickCancel = const $ channel chan $ RemoveItem idx + where + clickCancel = const $ channel chan $ RemoveItem idx + cancelBtn = (btn clickCancel "✖") & _HTMLElement %~ + (execState $ do + classes .= ["complete"] + attributes . at "title" ?= "Remove Item") renderFilters :: DOMEvent Action -> ToDo -> HTML renderFilters chan todo = - with ul (classes .= ["filters"]) + with ul_ (classes .= ["filters"]) (renderFilter <$> [All, Active, Completed]) where currentFilter = (todo ^. filter) renderFilter f = - into li - [ with a (do - attrs . at "href" ?= "#" + into li_ + [ with a_ (do + attributes . at "href" ?= "#" classes .= (if f == currentFilter then ["selected"] else []) onClick $ filterClick f) [text $ showFilter f] @@ -140,7 +147,7 @@ renderFilters chan todo = filterClick f = DOMEvent $ const $ (channel chan) $ SetFilter f btn :: (() -> IO ()) -> String -> HTML -btn click txt = with button (onClick $ DOMEvent click) [text txt] +btn click txt = with button_ (onClick $ DOMEvent click) [text txt] -------------------------------------------------------------------------------- @@ -149,4 +156,5 @@ modelComp :: Component () Action ToDo Action modelComp = Component process todoView idProcessor main :: IO () -main = void $ runComponent initialToDo () modelComp +main = + void $ initDomDelegator >> runComponent initialToDo () modelComp diff --git a/todo-mvc/src/deps.js b/todo-mvc/src/deps.js deleted file mode 100644 index 66fca22..0000000 --- a/todo-mvc/src/deps.js +++ /dev/null @@ -1,8 +0,0 @@ -global.Delegator = require('dom-delegator'); -global.Delegator(); -global.h = require('virtual-hyperscript'); -global.svg = require('virtual-hyperscript/svg'); -global.hook = require('virtual-hyperscript/hooks/ev-hook'); -global.diff = require('virtual-dom/diff'); -global.patch = require('virtual-dom/patch'); -global.createElement = require('virtual-dom/create-element');