Skip to content

Latest commit

 

History

History
151 lines (117 loc) · 4.44 KB

README.md

File metadata and controls

151 lines (117 loc) · 4.44 KB

Perch

Build Status

This is a GHCJS port of Perch library1 originally written by Alberto Gómez Corona.

perch

Perch defines DOM element builders (perches) that are append-able, so that dynamic HTML can be created in the client application in natural way, like textual HTML but programmatically and with the advantage of static type checking.

Main use case of Perch is client side applications, however it can be used in monolithic server-and-client apps too, if this is what you need take a look at HPlay2 library.

This package makes the creation of DOM elements easy with a syntax similar to other Haskell HTML generators such as blaze-html3, using monoids and monads.

Examples

Build DOM tree

{-# LANGUAGE ExtendedDefaultRules #-}
{-# LANGUAGE OverloadedStrings    #-}
module Main where

import           Data.JSString (JSString)
import           GHCJS.Perch
import           Prelude       hiding (div, id)
default (JSString)

dom :: Perch
dom =
  div ! id "wrap" $
    do div ! id "content" $
         do p "Hello World!"
            a ! href "https://github.com/geraldus/ghcjs-perch" $
              "Perch on GitHub"
       div ! id "footer" $ "Happy Haskelling!"

main :: IO ()
main =
  do documentBody <- getBody
     build dom documentBody
     return ()

This will create following DOM inside document's body at run time:

<div id="wrap">
  <div id="content">
    <p>Hello World!</p>
    <a href="https://github.com/geraldus/ghcjs-perch">Perch on GitHub</a>
  </div>
  <div id="footer">Happy Haskelling!</div>
</div>

This example program takes already existing DOM element, attaches click event handler to it and adds some content:

import Prelude hiding (div, span)

main :: IO ()
main =
  do forElemId_ "my-element" $
       do addEvent' this Click (\ _ -> print "Hello, world!")
          div $
            do span "GHC"
               span ! atr "style" "color:red" $ "JS"
  return ()

yields following DOM as result:

<div id="my-element">   <!-- was already in the DOM -->
  "Hello World!"
  <div>
    <span>GHC</span>
    <span style="color:red">JS</span>
  </div>
</div>

Next example modifies the previously created elements when the event is raised, the event handler is attched using CSS selector and modifies all elements with modify class:

main :: IO ()
main =
  do body <- getBody
     flip build body $
       do div ! atr "class" "modify" $ "click"
          div "not changed"
          div ! atr "class" "modify" $ "here"
          addEvent' this Click $ \_ ->
              forElems_ ".modify" $
                this ! style "color:red" `child` " modified"
     return ()

The monoid expression can also be used. Concatenate elements with the <> operator. term1 <> term2 <> ... is equivalent to

do term1
   term2
   ...

Perch can also be used to navigate the tree, search, etc.

The monad instance provided in order to use do-notation. This adds a new level of syntax in the fashion of blaze-html package. This monad invokes the same appending mechanism. But be aware that Perch is a fake-monad, it lacks of bind function implementation and does not satisfies monad laws.

Perch is a generalization of a list and it is handled in the same way.

While a list is an unary tree, perch create N-ary trees. Monoid instance of list adds child nodes down, and this is the only direction list can grow. While perch monoid adds child horizontally at the same level. To create down branching there is child primitive.

Few Words About Library Name

The basic element is a builder that has a "hole" parameter and an IO action which creates DOM element. That "hole" will be filled with parent element created by the build action. So builder can be considered like a perch that has other perches that hang from it. Either no one or an entire tree.

The call nelem (new element) is a perch that creates a single DOM element. Upon created, it is added to the given parent and return itself as parent for the next build actions that can be hooked from it using child. When appending two elements, both are added to the parent.