diff options
author | Joey Hess <joey@kitenet.net> | 2012-07-30 22:24:19 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2012-07-30 22:24:19 -0400 |
commit | 6e40aed948c44348c977bb7ed7a9a6a84b9972ba (patch) | |
tree | 0e772d358481469c23bba935d0ed9ede3b197436 | |
parent | 2821f9f976b104bcb107f44a13ae7f2eb61f2d7a (diff) |
fix noscript mode to not allocate notification ids on each refresh
Now the javascript does an ajax call at the start to request the url
to use to poll, and the notification id is generated then, once we know
javascript is working.
-rw-r--r-- | Assistant/Threads/WebApp.hs | 82 | ||||
-rw-r--r-- | static/longpolling.js | 4 | ||||
-rw-r--r-- | templates/dashboard.hamlet | 10 | ||||
-rw-r--r-- | templates/longpolling.julius | 7 |
4 files changed, 65 insertions, 38 deletions
diff --git a/Assistant/Threads/WebApp.hs b/Assistant/Threads/WebApp.hs index a9b87ea58..79a388463 100644 --- a/Assistant/Threads/WebApp.hs +++ b/Assistant/Threads/WebApp.hs @@ -36,6 +36,7 @@ import Text.Hamlet import Network.Socket (PortNumber) import Text.Blaze.Renderer.String import Data.Text (Text, pack, unpack) +import qualified Data.Text as T import qualified Data.Map as M import Control.Concurrent.STM @@ -93,6 +94,8 @@ mkYesod "WebApp" [parseRoutes| /noscriptauto NoScriptAutoR GET /transfers/#NotificationId TransfersR GET /sidebar/#NotificationId SideBarR GET +/notifier/transfers NotifierTransfersR GET +/notifier/sidebar NotifierSideBarR GET /closealert/#AlertId CloseAlert GET /config ConfigR GET /addrepository AddRepositoryR GET @@ -136,19 +139,40 @@ instance Yesod WebApp where - - The widget should have a html element with an id=ident, which will be - replaced when it's updated. - - - - Updating is done by getting html from the gethtml route. + - + - The geturl route should return the notifier url to use for polling. - - ms_delay is how long to delay between AJAX updates - ms_startdelay is how long to delay before updating with AJAX at the start -} autoUpdate :: Text -> Route WebApp -> Int -> Int -> Widget -autoUpdate ident gethtml ms_delay ms_startdelay = do +autoUpdate ident geturl ms_delay ms_startdelay = do let delay = show ms_delay let startdelay = show ms_startdelay addScript $ StaticR longpolling_js $(widgetFile "longpolling") +{- Notifier urls are requested by the javascript, to avoid allocation + - of NotificationIds when noscript pages are loaded. This constructs a + - notifier url for a given Route and NotificationBroadcaster. + -} +notifierUrl :: (NotificationId -> Route WebApp) -> (DaemonStatus -> NotificationBroadcaster) -> Handler RepPlain +notifierUrl route selector = do + (urlbits, _params) <- renderRoute . route <$> newNotifier selector + webapp <- getYesod + return $ RepPlain $ toContent $ T.concat + [ "/" + , T.intercalate "/" urlbits + , "?auth=" + , secretToken webapp + ] + +getNotifierTransfersR :: Handler RepPlain +getNotifierTransfersR = notifierUrl TransfersR transferNotifier + +getNotifierSideBarR :: Handler RepPlain +getNotifierSideBarR = notifierUrl SideBarR alertNotifier + {- A display of currently running and queued transfers. - - Or, if there have never been any this run, an intro display. -} @@ -159,7 +183,8 @@ transfersDisplay warnNoScript = do M.toList . currentTransfers <$> liftIO (getDaemonStatus $ daemonStatus webapp) queued <- liftIO $ getTransferQueue $ transferQueue webapp - let ident = transfersDisplayIdent + let ident = "transfers" + autoUpdate ident NotifierTransfersR (10 :: Int) (10 :: Int) let transfers = current ++ queued if null transfers then ifM (lift $ showIntro <$> getWebAppState) @@ -168,9 +193,7 @@ transfersDisplay warnNoScript = do ) else $(widgetFile "transfers") -transfersDisplayIdent :: Text -transfersDisplayIdent = "transfers" - +{- An intro message, and list of repositories. -} introDisplay :: Text -> Widget introDisplay ident = do webapp <- lift getYesod @@ -206,8 +229,8 @@ getTransfersR nid = do page <- widgetToPageContent $ transfersDisplay False hamletToRepHtml $ [hamlet|^{pageBody page}|] -sideBarDisplay :: Bool -> Widget -sideBarDisplay noScript = do +sideBarDisplay :: Widget +sideBarDisplay = do let content = do {- Any yesod message appears as the first alert. -} maybe noop rendermessage =<< lift getMessage @@ -218,14 +241,9 @@ sideBarDisplay noScript = do <$> liftIO (getDaemonStatus $ daemonStatus webapp) mapM_ renderalert $ take displayAlerts $ reverse $ sortAlertPairs alertpairs - ident <- lift newIdent + let ident = "sidebar" $(widgetFile "sidebar") - - unless noScript $ do - {- Set up automatic updates of the sidebar - - when alerts come in. -} - nid <- lift $ newNotifier alertNotifier - autoUpdate ident (SideBarR nid) (10 :: Int) (10 :: Int) + autoUpdate ident NotifierSideBarR (10 :: Int) (10 :: Int) where bootstrapclass Activity = "alert-info" bootstrapclass Warning = "alert" @@ -264,7 +282,7 @@ getSideBarR :: NotificationId -> Handler RepHtml getSideBarR nid = do waitNotifier alertNotifier nid - page <- widgetToPageContent $ sideBarDisplay True + page <- widgetToPageContent sideBarDisplay hamletToRepHtml $ [hamlet|^{pageBody page}|] {- Called by the client to close an alert. -} @@ -273,43 +291,39 @@ getCloseAlert i = do webapp <- getYesod void $ liftIO $ removeAlert (daemonStatus webapp) i -dashboard :: Bool -> Bool -> Widget -dashboard noScript warnNoScript = do - sideBarDisplay noScript - transfersDisplay warnNoScript +{- The main dashboard. -} +dashboard :: Bool -> Widget +dashboard warnNoScript = do + sideBarDisplay + let content = transfersDisplay warnNoScript + $(widgetFile "dashboard") getHomeR :: Handler RepHtml -getHomeR = defaultLayout $ do - {- Set up automatic updates for the transfers display. -} - nid <- lift $ newNotifier transferNotifier - autoUpdate transfersDisplayIdent (TransfersR nid) (10 :: Int) (10 :: Int) - - dashboard False True +getHomeR = defaultLayout $ dashboard True -{- Same as HomeR, except with no javascript, so it doesn't allocate - - new resources each time the page is refreshed, and with autorefreshing - - via meta refresh. -} +{- Same as HomeR, except with autorefreshing via meta refresh. -} getNoScriptAutoR :: Handler RepHtml getNoScriptAutoR = defaultLayout $ do let ident = NoScriptR let delayseconds = 3 :: Int let this = NoScriptAutoR toWidgetHead $(hamletFile $ hamletTemplate "metarefresh") - dashboard True False + dashboard False +{- Same as HomeR, except no autorefresh at all (and no noscript warning). -} getNoScriptR :: Handler RepHtml getNoScriptR = defaultLayout $ - dashboard True True + dashboard False getConfigR :: Handler RepHtml getConfigR = defaultLayout $ do - sideBarDisplay False + sideBarDisplay setTitle "Configuration" [whamlet|<a href="@{HomeR}">main|] getAddRepositoryR :: Handler RepHtml getAddRepositoryR = defaultLayout $ do - sideBarDisplay False + sideBarDisplay setTitle "Add repository" [whamlet|<a href="@{HomeR}">main|] diff --git a/static/longpolling.js b/static/longpolling.js index 5b704acec..965c1d18d 100644 --- a/static/longpolling.js +++ b/static/longpolling.js @@ -1,5 +1,5 @@ -// Uses long-polling to update a div with a specified id, -// by polling an url, which should return a new div, with the same id. +// Updates a div with a specified id, by polling an url, +// which should return a new div, with the same id. connfails=0; diff --git a/templates/dashboard.hamlet b/templates/dashboard.hamlet new file mode 100644 index 000000000..7bcfce962 --- /dev/null +++ b/templates/dashboard.hamlet @@ -0,0 +1,10 @@ +^{content} +$if warnNoScript + <noscript> + <div .navbar .navbar-fixed-bottom> + <div .navbar-inner> + <div .container> + Javascript is disabled; cannot update in real-time. + <div .btn-group> + <a .btn .btn-primary href="@{NoScriptAutoR}">Auto-refresh every 3 seconds # + <a .btn .btn-primary href="@{NoScriptR}">Manually refresh diff --git a/templates/longpolling.julius b/templates/longpolling.julius index 67fe059cf..affa50cc8 100644 --- a/templates/longpolling.julius +++ b/templates/longpolling.julius @@ -1,9 +1,12 @@ function longpoll_#{ident}() { - longpoll('@{gethtml}', '#{ident}' + longpoll(longpoll_#{ident}_url, '#{ident}' , function() { setTimeout(longpoll_#{ident}, #{delay}); } , function() { webapp_disconnected(); } ); } $(function() { - setTimeout(longpoll_#{ident}, #{startdelay}); + $.get("@{geturl}", function(url){ + longpoll_#{ident}_url = url; + setTimeout(longpoll_#{ident}, #{startdelay}); + }); }); |