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|
|
mkYesod "WebApp" [parseRoutes|
|
||||||
/ HomeR GET
|
/ HomeR GET
|
||||||
/poll PollR GET
|
/status StatusR GET
|
||||||
/config ConfigR GET
|
/config ConfigR GET
|
||||||
/static StaticR Static getStatic
|
/static StaticR Static getStatic
|
||||||
|]
|
|]
|
||||||
|
@ -66,23 +66,63 @@ instance Yesod WebApp where
|
||||||
makeSessionBackend = webAppSessionBackend
|
makeSessionBackend = webAppSessionBackend
|
||||||
jsLoader _ = BottomOfHeadBlocking
|
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 :: Handler RepHtml
|
||||||
getHomeR = defaultLayout $ do
|
getHomeR = defaultLayout $ do
|
||||||
[whamlet|<div id="poll">Starting ...|]
|
statusDisplay
|
||||||
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"
|
|
||||||
toWidgetBody $(juliusFile $ juliusTemplate "longpolling")
|
|
||||||
[whamlet|<p><a href="@{ConfigR}">config|]
|
[whamlet|<p><a href="@{ConfigR}">config|]
|
||||||
|
|
||||||
{- Called by client to poll for a new webapp status display.
|
{- Called by client to poll for a new webapp status display.
|
||||||
-
|
-
|
||||||
- Should block until the status has changed, and then return a div
|
- Should block until the status has changed, and then return a div
|
||||||
- containing the new status, which will be inserted into the calling page.
|
- 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
|
getStatusR :: Handler RepHtml
|
||||||
getPollR = do
|
getStatusR = do
|
||||||
webapp <- getYesod
|
page <- widgetToPageContent statusDisplay
|
||||||
time <- show <$> liftIO getCurrentTime
|
hamletToRepHtml $ [hamlet|^{pageBody page}|]
|
||||||
hamletToRepHtml $(hamletFile $ hamletTemplate "poll")
|
|
||||||
|
|
||||||
getConfigR :: Handler RepHtml
|
getConfigR :: Handler RepHtml
|
||||||
getConfigR = defaultLayout $ do
|
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( $ ) {
|
(function( $ ) {
|
||||||
|
|
||||||
|
@ -7,11 +11,11 @@ $.LongPoll = (function() {
|
||||||
return {
|
return {
|
||||||
send : function() {
|
send : function() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
'url': '@{PollR}',
|
'url': '@{gethtml}',
|
||||||
'dataType': 'html',
|
'dataType': 'html',
|
||||||
'success': function(data, status, jqxhr) {
|
'success': function(data, status, jqxhr) {
|
||||||
$('#poll').replaceWith(data);
|
$('##{poll}').replaceWith(data);
|
||||||
setTimeout($.LongPoll.send, 3000);
|
setTimeout($.LongPoll.send, #{delay});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -19,7 +23,7 @@ $.LongPoll = (function() {
|
||||||
}());
|
}());
|
||||||
|
|
||||||
$(document).bind('ready.app', function() {
|
$(document).bind('ready.app', function() {
|
||||||
setTimeout($.LongPoll.send, 40);
|
setTimeout($.LongPoll.send, #{startdelay});
|
||||||
});
|
});
|
||||||
|
|
||||||
})( jQuery );
|
})( 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}
|
polled at #{time}
|
Loading…
Add table
Add a link
Reference in a new issue