cleaned up refreshing code into a widget
Very happy to have a reusable autoUpdate widget that can make any Yesod widget automatically refresh! Also added support for non-javascript browsers, falling back to meta refresh. Also, the home page is now rendered with the webapp status on it, before any refreshing is done.
This commit is contained in:
parent
9b2eec2e7a
commit
f5ef46d01e
4 changed files with 62 additions and 16 deletions
|
@ -41,7 +41,7 @@ staticFiles "static"
|
|||
|
||||
mkYesod "WebApp" [parseRoutes|
|
||||
/ HomeR GET
|
||||
/poll PollR GET
|
||||
/status StatusR GET
|
||||
/config ConfigR GET
|
||||
/static StaticR Static getStatic
|
||||
|]
|
||||
|
@ -66,23 +66,63 @@ instance Yesod WebApp where
|
|||
makeSessionBackend = webAppSessionBackend
|
||||
jsLoader _ = BottomOfHeadBlocking
|
||||
|
||||
{- Add to any widget to make it auto-update.
|
||||
-
|
||||
- The widget should have a html element with id=poll, which will be
|
||||
- replaced when it's updated.
|
||||
-
|
||||
- Updating is done by getting html from the gethtml route.
|
||||
- Or, the home route is used if the whole page has to be refreshed to
|
||||
- update.
|
||||
-
|
||||
- ms_delay is how long to delay between updates.
|
||||
- ms_startdelay is how long to delay before updating the widget at the
|
||||
- state.
|
||||
-}
|
||||
autoUpdate :: Text -> Route WebApp -> Route WebApp -> Int -> Int -> Widget
|
||||
autoUpdate poll gethtml home ms_delay ms_startdelay = do
|
||||
{- Fallback refreshing is provided for non-javascript browsers. -}
|
||||
let delayseconds = show $ ms_to_seconds ms_delay
|
||||
toWidgetHead $(hamletFile $ hamletTemplate "metarefresh")
|
||||
|
||||
{- Use long polling to update the status display. -}
|
||||
let delay = show ms_delay
|
||||
let startdelay = show ms_startdelay
|
||||
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"
|
||||
toWidgetHead $(juliusFile $ juliusTemplate "longpolling")
|
||||
where
|
||||
ms_to_seconds :: Int -> Int
|
||||
ms_to_seconds ms = ceiling ((fromIntegral ms :: Double) / 1000)
|
||||
|
||||
{- Continually updating status display. -}
|
||||
statusDisplay :: Widget
|
||||
statusDisplay = do
|
||||
webapp <- lift getYesod
|
||||
time <- show <$> liftIO getCurrentTime
|
||||
|
||||
poll <- lift newIdent
|
||||
$(whamletFile $ hamletTemplate "status")
|
||||
|
||||
autoUpdate poll StatusR HomeR (3000 :: Int) (40 :: Int)
|
||||
|
||||
getHomeR :: Handler RepHtml
|
||||
getHomeR = defaultLayout $ do
|
||||
[whamlet|<div id="poll">Starting ...|]
|
||||
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"
|
||||
toWidgetBody $(juliusFile $ juliusTemplate "longpolling")
|
||||
statusDisplay
|
||||
[whamlet|<p><a href="@{ConfigR}">config|]
|
||||
|
||||
{- Called by client to poll for a new webapp status display.
|
||||
-
|
||||
- Should block until the status has changed, and then return a div
|
||||
- containing the new status, which will be inserted into the calling page.
|
||||
-
|
||||
- Note that the head of the widget is not included, only its
|
||||
- body is. To get the widget head content, the widget is also
|
||||
- inserted onto the getHomeR page.
|
||||
-}
|
||||
getPollR :: Handler RepHtml
|
||||
getPollR = do
|
||||
webapp <- getYesod
|
||||
time <- show <$> liftIO getCurrentTime
|
||||
hamletToRepHtml $(hamletFile $ hamletTemplate "poll")
|
||||
getStatusR :: Handler RepHtml
|
||||
getStatusR = do
|
||||
page <- widgetToPageContent statusDisplay
|
||||
hamletToRepHtml $ [hamlet|^{pageBody page}|]
|
||||
|
||||
getConfigR :: Handler RepHtml
|
||||
getConfigR = defaultLayout $ do
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// Uses long-polling to update a div with id=poll.
|
||||
// The PollR route should return a new div, also with id=poll.
|
||||
|
||||
// Uses long-polling to update a div with id=#{poll}
|
||||
// The gethtml route should return a new div, with the same id.
|
||||
//
|
||||
// Maximum update frequency is controlled by #{startdelay}
|
||||
// and #{delay}, both in milliseconds.
|
||||
|
||||
(function( $ ) {
|
||||
|
||||
|
@ -7,11 +11,11 @@ $.LongPoll = (function() {
|
|||
return {
|
||||
send : function() {
|
||||
$.ajax({
|
||||
'url': '@{PollR}',
|
||||
'url': '@{gethtml}',
|
||||
'dataType': 'html',
|
||||
'success': function(data, status, jqxhr) {
|
||||
$('#poll').replaceWith(data);
|
||||
setTimeout($.LongPoll.send, 3000);
|
||||
$('##{poll}').replaceWith(data);
|
||||
setTimeout($.LongPoll.send, #{delay});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +23,7 @@ $.LongPoll = (function() {
|
|||
}());
|
||||
|
||||
$(document).bind('ready.app', function() {
|
||||
setTimeout($.LongPoll.send, 40);
|
||||
setTimeout($.LongPoll.send, #{startdelay});
|
||||
});
|
||||
|
||||
})( jQuery );
|
||||
|
|
2
templates/metarefresh.hamlet
Normal file
2
templates/metarefresh.hamlet
Normal file
|
@ -0,0 +1,2 @@
|
|||
<noscript>
|
||||
<meta http-equiv="refresh" content="#{delayseconds}; URL=@{home}">
|
|
@ -1,2 +1,2 @@
|
|||
<div id="poll">
|
||||
<div id="#{poll}">
|
||||
polled at #{time}
|
Loading…
Reference in a new issue