webapp simplestate; import HTMLDocument; import Webapp; data AppState(String name, String address, PersonStatus status); data PersonStatus = PSUnknown | PSNewCustomer | PSCurrentCustomer | PSValuedCustomer; HTMLDocument webmain() { doc = HTMLDocument::new(HTML4Strict,"Simple state handling"); void(addHeading(doc.body,1,"Simple state handling application")); void(addParagraph(doc.body,"This web application demonstrates basic state handling.")); appendExisting(doc.body,runHandler(@startApp)); return doc; } ElementTree startApp() { newstate = AppState("","",PSUnknown); form = addLocalForm(anonymousBlock); f1 = addFieldset(form,"Add a new customer record!"); void(addLabelledInput(f1,"Customer's name:",InputText,"cname","",30)); void(addLocalControlInput(f1,"Next step",formStage2@(),newstate)); void(addParagraph(form,"At this stage, no particular state exists, so the default 'handler' function is called, which initialises the application workflow.")); return form; } ElementTree formStage2(AppState state) { // other examples demonstrate how to check that the name is valid // and redisplay the first form if not. cname = incomingValue("cname",DataPost); state.name = cname; form = addLocalForm(anonymousBlock); f1 = addFieldset(form,"Set the customer status"); statuses = [SelectOption("New customer","new",true), SelectOption("Current customer","current",false), SelectOption("Valued customer","valued",false)]; void(addOptionList(f1,"Select status","status",statuses,false)); // at this point, the name is encoded into the state. void(addLocalControlInput(f1,"Next step",formStage3@(),state)); return form; } ElementTree formStage3(AppState state) { status = incomingValue("status",DataPost); if (status == "new") { state.status = PSNewCustomer; } else if (status == "current") { state.status = PSCurrentCustomer; } else if (status == "valued") { state.status = PSValuedCustomer; } else { // for simplicity of this example, the error handling code for // this stage has been omitted. state.status = PSNewCustomer; } form = addLocalForm(anonymousBlock); f1 = addFieldset(form,"Enter the customer's address"); void(addLabelledTextarea(f1,"address","Address")); // at this point, the name is encoded into the state. void(addLocalControlInput(f1,"Next step",formFinish@(),state)); void(addParagraph(form,"Obviously, in a real application, the individual forms would probably be longer, or the options at later stages would be affected by earlier stages.")); return form; } ElementTree formFinish(AppState state) { state.address = incomingValue("address",DataPost); results = anonymousBlock; void(addHeading(results,2,"The new customer record is:")); void(addParagraph(results,"Name: "+state.name)); void(addParagraph(results,"Address: "+state.address)); case state.status of { PSUnknown -> status = "unknown"; |PSNewCustomer -> status = "new"; |PSCurrentCustomer -> status = "current"; |PSValuedCustomer -> status = "valued"; } void(addParagraph(results,"Status: "+status)); void(appendInlineElement(results,Hyperlink("simplestate.cgi"),"Add another customer")); return results; }