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())
}