axiom 0.4.4 → 0.4.5
raw patch · 3 files changed
+39/−13 lines, 3 filesdep ~transientPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: transient
API changes (from Hackage documentation)
+ GHCJS.HPlay.View: redraw :: JSString -> Widget a -> TransIO a
- GHCJS.HPlay.View: tlink :: (Show a, Read a, Typeable a) => a -> Perch -> Widget a
+ GHCJS.HPlay.View: tlink :: (Show a, Typeable a) => a -> Perch -> Widget a
Files
- README.md +18/−1
- axiom.cabal +2/−2
- src/GHCJS/HPlay/View.hs +19/−10
README.md view
@@ -1,7 +1,7 @@ [](http://hackage.haskell.org/package/ghcjs-hplay) [](http://stackage.org/lts/package/ghcjs-hplay) [](http://stackage.org/nightly/package/ghcjs-hplay) -[](https://travis-ci.org/agocorona/ghcjs-hplay) +[](https://travis-ci.org/transient-haskell/axiom) Axiom (ghcjs-hplay) ========== @@ -22,6 +22,23 @@ To see how it integrates with Transient and how to create client-server applications, see the web paragraphs of the [transient tutorial](https://github.com/agocorona/transient/wiki/Transient-tutorial). To see how to create client side applications and widgets (with no server code integration), look for [hplayground](https://github.com/agocorona/hplayground) package. [Tutorial](https://www.airpair.com/haskell-tutorial/intro-to-haskell-web-apps) + +How it works +============ +The JS program compiled with GHCJS is sent to the browser, then it opens a websockets connection. Then the most useful primitive is `atRemote` wich execute his argument in the server and return the result back to the client (or viceversa, see below). The communication transport the variables necessary for executing the computation remotely. There is no explicit serialization neither communication. All is done implicitly. + +`atRemote` can be executed inside itself, so a computation can jump from server to client and back. So a browser can be controlled by the server or the other way aroud. But the execution starts in the browser. There is very little data to transport to execute remotely. In the other side, streaming and reactivity in both directions is included with no additional considerations with `atRemote` and other primitives. Isn't awesome? + +In the other side, there is an experimental template editor to generate static HTML templates. The server can execute a rest route and bring the corresponding page template and the JS code to the browser, so web crawlers can find something to read. +Also in Axiom everithing compose algebraically with standard applicative, alternative and monoidal operators, and also monadically: + +Larger widgets can be composed with algebraic combinations of smaller widgets. No limits. Widgets can have server side (they can use `atRemote`) so they are full stack, autonomous pieces down to the cloud. They make perfect software components. + +Events do not bubble up to the top like in the case of React. An event within a widget produce a monadic response that executes widgets down trough the monad without affecting the surrounding rendering not affected by the event. That is why Axiom does not need a Virtual DOM, and the logic of the application and the execution flow match, so it produces a clean and understandable code. look at the TODO app (it is client-side only) + +tryplayg.herokuapp.com/try/todo.hs/edit + +Axiom also implement widgets that works as spreadsheet cells, with formulas depending on other cells. These formulas can be executed in the server, so they have full access to databases, mumber crunching, map-reduce etc. This functionality need some testing. Plans: ======
axiom.cabal view
@@ -1,6 +1,6 @@ name: axiom -version: 0.4.4 +version: 0.4.5 cabal-version: >=1.10 build-type: Simple @@ -29,7 +29,7 @@ build-depends: base > 4.0 && <6.0 , transformers -any , containers -any - , transient >= 0.5.1 + , transient >= 0.5.4 , transient-universe >= 0.4.1 , mtl -any
src/GHCJS/HPlay/View.hs view
@@ -25,6 +25,7 @@ , (++>) , validate , wcallback + , redraw -- * Basic Widgets , option , wprint @@ -144,14 +145,13 @@ import GHCJS.Marshal import GHCJS.Perch hiding (JsEvent (..), eventName, - option,head) + option,head,map) import GHCJS.Types import Transient.Move hiding (pack) import Data.JSString as JS hiding (empty, center,span, strip,foldr,head,tail) #else -import GHCJS.Perch hiding (JSVal, JsEvent (..), eventName, - option,head) +import GHCJS.Perch hiding (JSVal, JsEvent (..), eventName, option,head, map) import Transient.Move hiding (JSString, pack) #endif @@ -308,7 +308,15 @@ at nid Insert $ f r +-- | execute a widget but redraw itself too when some event happens. +-- The first parameter is the path of the DOM element that hold the widget, used by `at` +redraw :: JSString -> Widget a -> TransIO a +redraw idelem w= do + path <- getState <|> return ( Path []) + r <- render $ at idelem Insert w + setState path + redraw idelem w <|> return r @@ -772,7 +780,8 @@ wlink x v= do (a ! href "#" $ v) `pass` OnClick Path paths <- Widget $ getSData <|> return (Path []) - let paths'= paths ++ [pack $ show1 x] + + let paths'= paths ++ [ toLower $ JS.pack $ show1 x ] setData $ Path paths' -- !> ("paths", paths') let fpath= ("/" <> (Prelude.foldl (\p p' -> p <> "/" <> p') (head paths') $ tail paths')<> ".html") @@ -782,6 +791,7 @@ wlink _ _= empty #endif +show1 :: (Typeable a,Show a) => a -> String show1 x | typeOf x== typeOf (undefined :: String) = unsafeCoerce x | otherwise= show x @@ -792,7 +802,7 @@ -- | template link. Besides the wlink behaviour, it loads the page from the server if there is any -- -- the page many have been saved with `edit` -tlink :: (Show a, Read a, Typeable a) => a -> Perch -> Widget a +tlink :: (Show a, Typeable a) => a -> Perch -> Widget a tlink x v= Widget $ let showx= show1 x @@ -941,9 +951,6 @@ if s == tok then return () -- !> ("FOUND", tok) else empty -try p= do - ParseContext readit str <- getSData :: TransIO (ParseContext BS.ByteString) - p <|> (setData ( ParseContext readit str) >> empty) parseString= do -- dropSpaces @@ -1640,8 +1647,8 @@ --- | Run the widget as the content of the element with the given id. The content can --- be appended, prepended to the previous content or it can be the only content depending on the +-- | Run the widget as the content of the element with the given path identifier. The content can +-- be appended, prepended to the previous content or it can erase the previous content depending on the -- update method. at :: JSString -> UpdateMethod -> Widget a -> Widget a at id method w= setAt id method <<< w @@ -1677,6 +1684,8 @@ f <- getData `onNothing` return noHtml setData $ rest <> v f return mx + + #ifdef ghcjs_HOST_OS