I have a couple modules that might be the start of what you are calling a
Widget system. I'm not sure if my modules are in line with the thoughts
expressed on this list. Pardon me if this is something different: I've been
loosely following this discussion..

Using my library, whenever I want a form I specify in one list all of the
elements along with the type of data and any validation routines. Some
information about how the form should look is also included. My code then
automatically generates the form (it looks like a dialogue box) from this
information. The same informational hash is used to parse the form and
validate the data. If the data is not validated correctly, the form is shown
again with the validation errors and the data remaining sticky. If the data
is validated then it is returned in a hash.

Here is a simplified example of the widget definitions for a form that
allows a customer to charge money on their credit card into their balance:

[
  amount => { width => "20", same_line => 1,
      label => "Amount to charge (in dollars)", _label => "Amount to
charge",
      _looks_like => "number", _required => 1, },

  [{ addl_require => [{
      type => "sub",
      fields => [qw(amount)],
      sub => sub {
          my ($require, $values, $labels) = @_;
          return "You may not initiate a charge for less than \$5.00."
              if ( $values->[0] < 5 );
          return "You may not initiate a charge for more than \$900.00. If
you really do want to
              charge this much, then you need to call us and we can do it
for you."
              if ( $values->[0] > 900 );
          return undef;
      },
  }], }],
]

Note the elements "label", "_label", and "same_line" for the "amount" widget
specify display attributes. (My actual definition of the form contains more
than the widgets themselves but rather the whole look and feel form.) The
element "_required" specifies that this widget may not be left blank by the
user. The element "_looks_like" with value "number" specifies that the value
in this text box must be a number. I can also specify dates, free text, or
whatever I needed as types for the widget.

The "addl_require" stuff you see is a way of in lining an additional
requirement: this requires that the value for the amount field must be
between 5.00 and 900.00. The additional requirement is tied specifically to
the fields that it is dependent on. For example, if the field "amount" was
left blank thus not satisfying the "_required" specification, then this
addl_require you see would not be checked, as its dependants has not been
verified.

Here is another example. This is the definition for the form elements to
collect credit card information:

[
  [qq[ <table border=0> ]],

  card_type => { c_table => 1, et => "select", label => "Card type",
      options => [
          map { [ ::DbAccess::Lookup::ccard__card_type->{euclid.drh.net},
euclid.drh.net ] }
              @::DbAccess::Lookup::ccard__card_type__keys
      ],
  },

  card_num      => { c_table => 1, width => 30, label => "Card number" },

  [{ addl_require => [{
      type => "sub",
      fields => [qw(card_num)],
      sub => sub {
          my (, , ) = @_;
          return "The credit card number you entered is not valid."
              if ( not Business::CreditCard::validate(->[0]) );
          return undef;
      },
  }], }],

  [qq[ <tr><td><font size="-1">Expiration</font></td><td> ]],

  exp_month => { c_blank => 1, et => "select", label => "Exp month",
      options => [
          map { [ ::DbAccess::Lookup::ccard__exp_month->{euclid.drh.net},
euclid.drh.net ] }
              @::DbAccess::Lookup::ccard__exp_month__keys
      ],
  },

  [qq[ / ]],

  exp_year => { c_blank => 1, et => "select", label => "Exp year",
      options => [
          map { [ ::DbAccess::Lookup::ccard__exp_year->{euclid.drh.net},
euclid.drh.net ] }
              @::DbAccess::Lookup::ccard__exp_year__keys
      ],
  },

  [qq[ </td></tr> ]],

  [q[
      <tr><td colspan=2><font size="-1">
      <img src="/resources/clear.gif" height=10 width=1><br>
      If the name on the card is different than your billing
      address you can enter it below.
      <br><img src="/resources/clear.gif" height=10 width=1><br>
      </font></td></tr>
  ]],

  card_name => { width => 30, c_table => 1, label => "Name on card" },

  [qq[ </table> ]],
]

This above code is showing the strains of evolution of my system. :-) Notice
all the [qq[ ... ]] constructs which allow HTML text to be inlined.
Originally there wasn't much inlined HTML, as each widget knew how to
display itself and its label. However I was stuck to one specific display
look constrained me. So I told the widgets how to print their labels with
"c_blank" and "c_table" parameters and inlined HTML code.

This really calls for the widgets to be embedded directly in the HTML
template which contains the formatting a la <widget name=card_name> that
Gunther proposed.

This above code actually sits in a subroutine that returns a list of the
definitional information. This list is then simply included other places so
I can write stuff like this:

[
  [qq[
      Enter your billing information and credit card.<p>
  ]],

  [qq[ <b>Billing information</b><p> ]],

  [{ default_by_name => CUST::DbAccess::Cust::default_by_name("custs") }],

  CUST::InterfaceUtil::opensrs_contact_fields($country_select_box, "bill",
"Billing"),
  undef,

  [qq[ <b>Credit card information</b><p> ]],

  [{ default_by_name => CUST::DbAccess::Ccard::default_by_name("ccards") }],

  CUST::InterfaceUtil::credit_card_fields(),
  undef,
]

It's great for reuse.

The default_by_name does something interesting: it imports all the defaults
for the fields (_looks_like and _required and _size) information from the
database table. If I change the size of a text field in a table all the
forms which use that text field are automatically updated. (However, I
should change the default_by_name system so that it doesn't need to be
specified when I'm including default confirmation. Like I said, this system
is straining under the evolution.)

I can contribute this library if it would help. I'll warn you that there's
not too much documentation. I can also contribute some examples of my code
that use the library.

David Harris
President, DRH Internet Inc.
[EMAIL PROTECTED]
http://www.drh.net/



Reply via email to