%% vim: ts=4 sw=4 et
-module (demos_sync_panel).
-include_lib ("nitrogen_core/include/wf.hrl").

-define(TEXTFILE, "./scratch/comet_demo_text").

main() -> #template { file="./templates/demos46.html" }.
title() -> "Synchronized Elements".

headline() -> "Synchronized Elements".

left() -> 
        Nitrogen provides an easy mechanism to synchronize page elements across
        multiple clients by registering elements directly to a comet pool.
        Calling <code>element_sync_panel:refresh(Trigger)</code> will trigger
        all the elements on all connected clients to refresh their contents by
        calling their assigned render function (which might typically read
        contents from a database or other data source).
        In this demo, we will simulate users clicking one of the 'Msg' buttons,
        changing the status in the database and triggering a redraw on all
        connected clients, with the 'database' here being a simple text file on
        the hard drive.
        To fully appreciate this demo, you'll want more than one browser
        window opened on this page to see the contents change in the other
        To help you understand why this is useful, there is a <a
        href='http://sigma-star.com/blog/post/sync_panel'>blog post describing
        a specific use case</a> (after all, Nitrogen provides a number of
        comet/asynchronous tools and it might not be obvious why this
        rather simple tool is useful).  The key is that it provides a simple
        mechanism for all connected clients page contents to be synchronized
        with only a few simple lines.",


%% Notice how we use the fun ?MODULE:body_function/0 syntax rather than just
%% fun body_function/0? This is to ensure that when the module is recompiled
%% that the new version of body_function/0 will be called.
right() -> 
    _Body = [
        #panel{ text="Open this page in a couple browser windows then click some of the buttons below" },
            style="border: dotted 2px black",
            body_fun=fun ?MODULE:body_function/0
        #button{postback={message, 1}, text="Msg 1"},
        #button{postback={message, 2}, text="Msg 2"},
        #button{postback={message, 3}, text="Msg 3"},
        #button{postback={message, 4}, text="Msg 4"},
        #button{postback={message, 5}, text="Msg 5"},
        #button{postback={message, 6}, text="Msg 6"}

%% body_function() is referenced by the body_fun attribute in the
%% #sync_panel{} element above. It will simply read the contents from our
%% "database" and prepare nitrogen elements to be used as the body of the
%% panel. This function is basically no different than any other function you
%% might use to define the body of a page element, except that instead of
%% calling it, for example with #panel{body=body_function()}, you'll instead
%% assign it to the #sync_panel.body_fun field and it will be called and used
%% to refresh the contents whenever its triggered to.
body_function() ->
    Msg = read_contents(),
        #span{style="font-weight:bold", text="Boromir Says: "},

%% This emulates our database by reading text from a file.
read_contents() ->
    case file:read_file(?TEXTFILE) of
        {ok, Body} -> Body;
        _ -> stock_message(1)

%% This emulates a save operation on our text file.
save_contents(N) ->
    file:write_file(?TEXTFILE, stock_message(N)).

%% Handle the postbacks generated by the message button presses
event({message, N}) ->
    element_sync_panel:refresh(demo_sync_panel, update_sync_panel).

%% Some stock messages to use.
stock_message(1) -> "One does not simply walk into Mordor.";
stock_message(2) -> "Its black gates are guarded by more than just Orcs.";
stock_message(3) -> "There is evil there that does not sleep and the Great Eye is ever watchful.";
stock_message(4) -> "It is a barren wasteland, riddled with fire and ash and dust...the very air you breathe is a poisonous fume.";
stock_message(5) -> "Not with ten thousand men could you do this.";
stock_message(6) -> "It is folly.".