summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2012-07-26 21:03:46 -0400
committerGravatar Joey Hess <joey@kitenet.net>2012-07-26 21:03:46 -0400
commitf5ef46d01eb7bbaac45eec162267bcbf2500d511 (patch)
tree0e2fd9d872919d08f70d09d169d65d13c1305a6c
parent9b2eec2e7af34e107bcb438a501286996fe0eb41 (diff)
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.
-rw-r--r--Assistant/Threads/WebApp.hs58
-rw-r--r--templates/longpolling.julius16
-rw-r--r--templates/metarefresh.hamlet2
-rw-r--r--templates/status.hamlet (renamed from templates/poll.hamlet)2
4 files changed, 62 insertions, 16 deletions
diff --git a/Assistant/Threads/WebApp.hs b/Assistant/Threads/WebApp.hs
index 2d78609e8..0e1f9ba95 100644
--- a/Assistant/Threads/WebApp.hs
+++ b/Assistant/Threads/WebApp.hs
@@ -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
diff --git a/templates/longpolling.julius b/templates/longpolling.julius
index 38ecbc77d..26356f5e9 100644
--- a/templates/longpolling.julius
+++ b/templates/longpolling.julius
@@ -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 );
diff --git a/templates/metarefresh.hamlet b/templates/metarefresh.hamlet
new file mode 100644
index 000000000..be22aa899
--- /dev/null
+++ b/templates/metarefresh.hamlet
@@ -0,0 +1,2 @@
+<noscript>
+ <meta http-equiv="refresh" content="#{delayseconds}; URL=@{home}">
diff --git a/templates/poll.hamlet b/templates/status.hamlet
index fcdd705b6..1f975b35f 100644
--- a/templates/poll.hamlet
+++ b/templates/status.hamlet
@@ -1,2 +1,2 @@
-<div id="poll">
+<div id="#{poll}">
polled at #{time}