While attending GPCE, SLE, and MoDELS in Denver, I recorded episode 2 of The Big Scheme of Things screencast series. Using a simple to-do application as example application, I illustrate various aspects of the use of WebDSL, a domain-specific language for web applications.
In this episode, I show the use of templates to divide a page definition into smaller fragments, the definition of action in templates, and the use of icons as actions.
[This is as much an experiment in screencasting, as it is a WebDSL tutorial. Feedback is welcome. Thanks for the feedback on the previous episode. For this recording I have used a proper microphone (Rode Podcaster) instead of the built-in microphone of my MacBook; sound quality should be better. I still have to look into other formats than Quicktime; suggestions for useful formats are welcome. An iTunes feed is in the planning as well. There was a request for a start and end tune; apart from the requirement that such a tune should be copyright free, music is not my strong point; suggestions are welcome.]
First the entity declaration for Tasks is extended to hold relevant data:
entity Task { name :: String description :: WikiText done :: Bool logged :: Bool isDue :: Bool dueDate :: Date created :: DateTime finished :: DateTime }
In this episode we focus on the done and logged status, which indicate that a task is completed and that it is to be moved to the log, respectively.
Next the root page definition is factored into templates:
define page root(){ addTask() tasks() loggedComplete() logged() }
For example, the following template captures the list of open tasks:
define tasks() { section{ header{"Tasks"} list{ for(t : Task where !t.logged order by t.created desc) { listitem{ task(t) } } } } }
The task template defines the interface for a single Task, showing its status and
Note that the template is parameterized with a task object and is instantiated for each task that is not logged in the iteration above.
define task(t : Task) { action check() { t.done := !t.done; if(t.done) { t.finished := now(); } else { t.logged := false; } refresh(); } if(t.done) { image("/images/accept.png")[onclick:=check()] } else { image("/images/process.png")[onclick:=check()] } output(t.name) " " if(t.done) { output(t.finished) } }
Below is the full code as realized at the end of the episode. For this to work you also need the icons. I used the freely available Luna Grey icon set.
application bigscheme section data model entity Task { name :: String description :: WikiText done :: Bool logged :: Bool isDue :: Bool dueDate :: Date created :: DateTime finished :: DateTime } section user interface define page root(){ addTask() tasks() loggedComplete() logged() } define tasks() { section{ header{"Tasks"} list{ for(t : Task where !t.logged order by t.created desc) { listitem{ task(t) } } } } } define logged() { section{ header{"Logged"} list{ for(t : Task where t.logged order by t.finished desc limit 3) { listitem{ task(t) } } } } } define addTask() { var task := Task{} form{ input(task.name) action("+", action{ task.save(); }) } } define task(t : Task) { action check() { t.done := !t.done; if(t.done) { t.finished := now(); } else { t.logged := false; } refresh(); } if(t.done) { image("/images/accept.png")[onclick:=check()] } else { image("/images/process.png")[onclick:=check()] } output(t.name) " " if(t.done) { output(t.finished) } } define loggedComplete() { action moveToLog() { for(t : Task where t.done && !t.logged) { t.logged := true; } } action("Logged Complete", moveToLog()) }