webapp now does long polling

The webapp is now a constantly updating clock! I accomplished this amazing
feat using "long polling", with some jquery and a little custom java
script.

There are more modern techniques, but this one works everywhere.
This commit is contained in:
Joey Hess 2012-07-26 17:56:24 -04:00
parent e79198aacb
commit 9fd03c65f9
5 changed files with 50 additions and 2 deletions

View file

@ -21,9 +21,11 @@ import Git
import Yesod import Yesod
import Yesod.Static import Yesod.Static
import Text.Hamlet import Text.Hamlet
import Text.Julius
import Network.Socket (PortNumber) import Network.Socket (PortNumber)
import Text.Blaze.Renderer.String import Text.Blaze.Renderer.String
import Data.Text import Data.Text
import Data.Time.Clock
thisThread :: String thisThread :: String
thisThread = "WebApp" thisThread = "WebApp"
@ -39,6 +41,7 @@ staticFiles "static"
mkYesod "WebApp" [parseRoutes| mkYesod "WebApp" [parseRoutes|
/ HomeR GET / HomeR GET
/poll PollR GET
/config ConfigR GET /config ConfigR GET
/static StaticR Static getStatic /static StaticR Static getStatic
|] |]
@ -61,10 +64,25 @@ instance Yesod WebApp where
excludeStatic (p:_) = p /= "static" excludeStatic (p:_) = p /= "static"
makeSessionBackend = webAppSessionBackend makeSessionBackend = webAppSessionBackend
jsLoader _ = BottomOfHeadBlocking
getHomeR :: Handler RepHtml getHomeR :: Handler RepHtml
getHomeR = defaultLayout $ do getHomeR = defaultLayout $ do
[whamlet|Hello, World<p><a href="@{ConfigR}">config|] [whamlet|<div id="poll">Starting ...|]
addScriptRemote "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"
toWidgetBody $(juliusFile $ juliusTemplate "longpolling")
[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.
-}
getPollR :: Handler RepHtml
getPollR = do
webapp <- getYesod
time <- show <$> liftIO getCurrentTime
hamletToRepHtml $(hamletFile $ hamletTemplate "poll")
getConfigR :: Handler RepHtml getConfigR :: Handler RepHtml
getConfigR = defaultLayout $ do getConfigR = defaultLayout $ do

View file

@ -16,3 +16,7 @@ template f = "templates" </> f
{- A hamlet template file. -} {- A hamlet template file. -}
hamletTemplate :: FilePath -> FilePath hamletTemplate :: FilePath -> FilePath
hamletTemplate f = template f ++ ".hamlet" hamletTemplate f = template f ++ ".hamlet"
{- A julius template file. -}
juliusTemplate :: FilePath -> FilePath
juliusTemplate f = template f ++ ".julius"

View file

@ -3,7 +3,6 @@ $doctype 5
<head> <head>
<title>#{baseTitle webapp} #{pageTitle page} <title>#{baseTitle webapp} #{pageTitle page}
<link rel="icon" href=@{StaticR favicon_ico} type="image/x-icon"> <link rel="icon" href=@{StaticR favicon_ico} type="image/x-icon">
^{pageHead page} ^{pageHead page}
<body> <body>
$maybe msg <- mmsg $maybe msg <- mmsg

View file

@ -0,0 +1,25 @@
// Uses long-polling to update a div with id=poll.
// The PollR route should return a new div, also with id=poll.
(function( $ ) {
$.LongPoll = (function() {
return {
send : function() {
$.ajax({
'url': '@{PollR}',
'dataType': 'html',
'success': function(data, status, jqxhr) {
$('#poll').replaceWith(data);
setTimeout($.LongPoll.send, 3000);
},
});
}
}
}());
$(document).bind('ready.app', function() {
setTimeout($.LongPoll.send, 40);
});
})( jQuery );

2
templates/poll.hamlet Normal file
View file

@ -0,0 +1,2 @@
<div id="poll">
polled at #{time}