So I created another push example theoretically more simple.
It is a countdown after which the page will navigate back to the main menu. In this case the widget generates its own output by decreasing the variable. It also illustrates the use of Hamlet.
- push has a new parameter that is the delay for a new ajax request when the previous connection has been lost.
- The last push after 0, send a script that forces a navigation to the menu. And then kill itself.
pushDecrease= do tv ← liftIO $ newTVarIO 10 page $ [shamlet| <div> <h2> Maxwell Smart push counter <p> This example shows a reverse counter <p> To avoid unnecessary load, the push process will be killed when reaching 0 <p> The last push message will be an script that will redirect to the menu" <h3> This message will be autodestroyed within ‥ |] ++> counter tv <++ b << "seconds" where counter tv = push Html 0 $ do setTimeouts 100 0 -- kill the thread if the user navigate away n ← atomic $ readTVar tv if (n≡ -1) then do script << "window.location='/'" ++> noWidget liftIO $ myThreadId ↠ killThread else do atomic $ writeTVar tv $ n - 1 liftIO $ threadDelay 1000000 h1 << (show n) ++> noWidget atomic= liftIO . atomically
killThread is never called since noWidget return an invalid formlet value, so the next statements are not executed in the View monad (See: The promising land of monadic formlets).
That kill is in order to drop the process immediately, but otherwise, the timeout of setTimeouts would do the same job. Since the delay between push sends is one second, by shortening the timeout from 100 to two seconds will do the same job. So the killthread line can be eliminated.