logo

Widget

Overview

WARNING: the webapp framework is still an early prototype, so will be going through many changes during development

Widget extends Weblet to provide functionality to aid in creating reusable UI components.

Nesting

Widget has a fundamental difference from Weblet in that its entire output is buffered. The head slot captures the output that will be written in the resulting <head> tag. The body slot captures the output that will be written to the <body> tag.

Never call res.out directly. Always use head and body. The buffers are used to support nesting of Widgets, so that every Widget has the opportunity to add content to the <head> tag while the page is being written.

Widgets should assume the skeleton HTML markup will be written for them, and only output the <head> and <body> content that applies to it:

class MyWidget : Widget
{
  override Void doGet()
  {
    head.title("My title!")
    body.h1("This is my widget!")
  }
}

// produces this markup...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>
<title>My title!</title>
</head>
<body>
<h1>This is my widget!</h1>
</body>
</html>

The complete method is responsible for flushing the buffered output to the actual response OutStream. For GET requests this method is also responsible for outputing the supporting skeleton markup.

Actions

Widget also provides support for asynchronous actions. Actions are always invoked on a POST request. And are identified by a method qname, see doPost for details.

Form submissions can use the action infrastructure as well. See actionForm for details.

class MyWidget : Widget
{
  override Void doGet()
  {
    head.title("My title!")
    actionForm(&foo)
    body.p
    body.textField("name='bar'")
    body.submit
    body.pEnd
    body.formEnd
  }

  Void foo()
  {
    echo("bar: " + req.form["bar"])
    redirect(`/myWidget`)
  }
}

Flash

TODO: this is what Rails calls this, but is there a better name?

The flash field is a short-term storage that only exists for a single GET request, and is then automatically cleaned up. It is convenient for passing notifications following a POST.

class MyWidget : Widget
{
  override Void doGet()
  {
    if (flash["foo"] != null)
      body.p.esc(flash["foo"]).pEnd

    actionForm(&foo)
    body.p
    body.textField("name='bar'")
    body.submit
    body.pEnd
    body.formEnd
  }

  Void foo()
  {
    flash["foo"] = "Did something with " + req.form["bar"];
    redirect(`/myWidget`)
  }
}