packages feed

heist-async 0.3.0.0 → 0.4.0.0

raw patch · 3 files changed

+43/−17 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Heist.Splices.Async: fileContents :: String
+ Heist.Splices.Async: heistAsyncSplices :: Monad m => [(Text, Splice m)]

Files

Heist/Splices/Async.hs view
@@ -1,9 +1,25 @@ {-# LANGUAGE OverloadedStrings, NoMonomorphismRestriction, TemplateHaskell #-} -module Heist.Splices.Async where+module Heist.Splices.Async +  (+    -- ** All Splices+    heistAsyncSplices++    -- ** Individual Splices+  , aAsync+  , formAsync+  , divAsync+  , divAppendAsync+  , redirectAsync   +    -- ** Helpers+  , activateAsync+  )+where+   import            Text.Templating.Heist import qualified  Data.Text as T+import            Data.Text (Text) import qualified  Text.XmlHtml as X import            Data.Maybe (fromMaybe) @@ -11,14 +27,24 @@  $(loadJS) --- | heistAsyncSplices provides the six basic splices with sensible defaults--- These are:--- a-async: a link that loads it's results asynchronously and replaces parts of the page based on the contents. A normal anchor tag in all ways.--- form-async: a form that submits asynchronously and replaces parts of the page with the results. A normal form tag otherwise.--- div-async: a div that can be replaced or replace content on the page. It takes a "name" attribute that is it's unique identifier. When sending back content to replace, any div-asyncs present will replace existing div-asyncs on the page (identified by the name attribute)--- div-async-append: a special div-async that instead of replacing the corresponding one on the page, it appends it's contents inside the existing div-async-append. Note: div-async's and div-async-appends are not interchangeable. This is so that it is easy to see what is going to happen from looking at the templates. If you need this jund of behavior, wrap you div-async-append inside a div-async.--- redirect-async: this tag allows you to cause a client-side redirect. This is necessary because if you do a regular redirect, it will be followed by the browser and the result (the new page) will be handed back as if it were the page fragment response. It takes a "url" attribute that specifies where to redirect to.--- activate-async: this is a convenience tag that will include all the necessary javascript. Feel free to copy the files yourself from tho js directory - by having separate files, they can be cached, which will mean less network transfer. Of course, the intention with this tag is you can get this running as quickly as possible. It can occur any number of times on the page, but will only actually include the javascript the first time.+-- | Provides the following splices: +--+-- > <a-async href="some/url" data-loading-div="#some-div">+-- +-- where data-loading-div is optional, it causes the specified div to have it's contents replaced with \<div class="loading"/\> when the link is clicked.+--+-- > <form-async>+--+-- Note that the following two are not interchangeable, and cannot replace one another.+--+-- > <div-async name="some-unique-identifier"> +-- > <div-async-append name="some-unique-identifier"> +--   +-- > <redirect-async url="target/path"/>+--   +-- > <activate-async/> +--   +heistAsyncSplices :: Monad m => [(Text, Splice m)] heistAsyncSplices = [ ("a-async", aAsync)                     , ("form-async", formAsync)                     , ("div-async", divAsync)@@ -26,34 +52,34 @@                     , ("redirect-async", redirectAsync)                     , ("activate-async", activateAsync)                     ]--- | aAsync: the actual splice used for "a-async" in heistAsyncSplices, in case you want to bind it to another tag.+-- | a link that loads it's results asynchronously and replaces parts of the page based on the contents. A normal anchor tag in all ways. aAsync :: Monad m => Splice m aAsync = do   node <- getParamNode   return [X.setAttribute "rel" "async" $ X.Element "a" (X.elementAttrs node) (X.elementChildren node)] --- | formAsync: the actual splice used for "form-async" in heistAsyncSplices, in case you want to bind it to another tag.+-- | a form that submits asynchronously and replaces parts of the page with the results. A normal form tag otherwise. formAsync :: Monad m => Splice m formAsync = do   node <- getParamNode   return [X.setAttribute "data-async" "1" $ X.Element "form" (X.elementAttrs node) (X.elementChildren node)]  --- | divAsync: the actual splice used for "div-async" in heistAsyncSplices, in case you want to bind it to another tag.+-- | a div that can be replaced or replace content on the page. It takes a "name" attribute that is it's unique identifier. When sending back content to replace, any div-asyncs present will replace existing div-asyncs on the page (identified by the name attribute) divAsync :: Monad m => Splice m divAsync = do   node <- getParamNode   let name = fromMaybe "undefined" $ X.getAttribute "name" node   return [X.setAttribute "data-splice-name" name $ X.Element "div" (filter ((/= "name").fst) $ X.elementAttrs node) (X.elementChildren node)] --- | divAsyncAppend: the actual splice used for "div-async-append" in heistAsyncSplices, in case you want to bind it to another tag.+-- | a special div-async that instead of replacing the corresponding one on the page, it appends it's contents inside the existing div-async-append. Note: div-async's and div-async-appends are not interchangeable. This is so that it is easy to see what is going to happen from looking at the templates. If you need this sort of behavior, wrap you div-async-append inside a div-async. divAppendAsync :: Monad m => Splice m divAppendAsync = do   node <- getParamNode   let name = fromMaybe "undefined" $ X.getAttribute "name" node   return [X.setAttribute "data-append-name" name $ X.Element "div" (filter ((/= "name").fst) $ X.elementAttrs node) (X.elementChildren node)]   --- | redirectAsync: the actual splice used for "redirect-async" in heistAsyncSplices, in case you want to bind it to another tag.+-- | this tag allows you to cause a client-side redirect. This is necessary because if you do a regular redirect, it will be followed by the browser and the result (the new page) will be handed back as if it were the page fragment response. It takes a "url" attribute that specifies where to redirect to. redirectAsync :: Monad m => Splice m redirectAsync = do   node <- getParamNode@@ -62,7 +88,7 @@     Just url -> return [X.Element "div" [("data-redirect-url", url)] []]  --- | activateAsync: the actual splice used for "activate-async" in heistAsyncSplices, in case you want to bind it to another tag.+-- | this is a convenience tag that will include all the necessary javascript. Feel free to copy the files yourself from tho js directory - by having separate files, they can be cached, which will mean less network transfer. Of course, the intention with this tag is you can get this running as quickly as possible. It can occur any number of times on the page, but will only actually include the javascript the first time. activateAsync :: Monad m => Splice m activateAsync = do   -- make sure that only the first call to this does anything.
README.md view
@@ -4,7 +4,7 @@  **\<activate-async/\>** - This brings in the required javascript - mainly, the three small javascript libraries (in total weighing 12k) and the cade to make the splice replacement work (in \<1k). Minified (with uglifyjs) and regular versions are available in the js folder, and for production, serving those files would be preferable to including inline (as that way they could be cached), and implementations of heist-async.js using bigger frameworks (jQuery, prototype, etc) would be appreciated. Ideally they would be made available both as standalone files (ie, heist-async-jquery.js) and as splices (\<activate-async-jquery/\>). This splice will only run once (the first place it is called), so feel free to include it in various places throughout your templates, if that suits you needs better. -**\<a-async\>** - this is a regular \<a\> tag, except that it will add an extra attribute (rel=async) that will allow the javascript to capture the clicks, so it can be used any way a regular tag would be used. Because of this, it will automatically fall back to functioning as a normal link in the absence of javascript support. When it is clicked, the server is sent a request at the url provided in the href attribute, and then the response (which should be a list of top-level \<div-async\>s) is used to replace the corresponding \<div-async\>s on the page. This tag takes an option "data-loading-div" that is a div that will have it's contents replaced with "<div class='loading'></div>". This loading div can be styled to have, for example, a loading gif as it's background, to show that something is happening while the content loads. (note, you will obviously want to be replacing whatever div you specify with the result of the async call, because there is no "undo" and the <div class="loading"></div> will remain there forever otherwise)+**\<a-async\>** - this is a regular \<a\> tag, except that it will add an extra attribute (rel=async) that will allow the javascript to capture the clicks, so it can be used any way a regular tag would be used. Because of this, it will automatically fall back to functioning as a normal link in the absence of javascript support. When it is clicked, the server is sent a request at the url provided in the href attribute, and then the response (which should be a list of top-level \<div-async\>s) is used to replace the corresponding \<div-async\>s on the page. This tag takes an option "data-loading-div" that is a div that will have it's contents replaced with "\<div class='loading'\>\</div\>". This loading div can be styled to have, for example, a loading gif as it's background, to show that something is happening while the content loads. (note, you will obviously want to be replacing whatever div you specify with the result of the async call, because there is no "undo" and the \<div class="loading"\>\</div\> will remain there forever otherwise)    **\<form-async\>** - analogously to \<a-async\>, this is a normal \<form\> tag that has an extra attribute added (data-async=1) to allow the javascript to capture the submits. Again, this means that it will fall back to a normal submit in the absence of javascript support. If the form is submitted with a button, the button will have the class "processing" added to it when the form has been submitted. This allows the button to be styled to indicate that something has happened. This is also used to prevent multiple submits (clicking on a button that has that class will do nothing), so be sure to replace the form / at least button in the response to the form.    
heist-async.cabal view
@@ -1,5 +1,5 @@ Name:                heist-async-Version:             0.3.0.0+Version:             0.4.0.0 Synopsis:            Adding support for asynchronous updates ("AJAX") with heist Description:         This package provides six splices and some accompanying javascript to allow declarative ajax programming that involves no javascript programming. Homepage:            http://github.com/dbp/heist-async