NAME

OpenInteract2::Manual::Widgets - Template Widgets in OpenInteract

DESCRIPTION

OpenInteract2 supports using templates as a simple graphical widget. A widget is a common element into which you can just plug in text or parameters to customize it. For example, an 'INPUT' element of type 'TEXT' is a particular type of widget -- you can customize its size, name, and default value. (Some widget implementations will maintain state for you across requests, have validation, etc. These don't do that.)

Widgets can also include other widgets. Such as a row that uses the 'INPUT TEXT' widget described above to create a labeled input field, with a label on the left and the input widget on the right.

One of the main benefits of using these over HTML is that these are centralized -- a change in one place enacts changes throughout your site. All column headers can look a certain way and be changed easily, all textboxes can be consistent and you can create widgets specific to your site and needs -- such as for inputting dates or money, or displaying addresses-- for a consistent user interface.

Here's an example:

 1: [%########################################
 2:   form_text( name, value, size, maxlength, field_label )
 3:      Generate a simple text field.
 4: 
 5:      Defaults:
 6:         size      = 20
 7:         maxlength = 50
 8:   ########################################-%]
 9: 
10: [%- DEFAULT size      = 20;
11:     DEFAULT maxlength = 50; -%]
12: [%- field_pre_label -%]
13: <input type="text" name="[% name %]" value="[% value %]"
14:        size="[% size %]" maxlength="[% maxlength %]">
15: [%- field_label -%]

And you would reference this like:

1: [% INCLUDE form_text( name = "batting_average",
2:                       value = ".389" size = 5 ) -%]

And when the template is processed, get in return:

1: <input type="text" name="batting_average"
2:        value=".389" size="5" maxlength="50">

Calling widgets from other widgets is just as simple:

 1: [%########################################
 2:   label_form_text_row( label, count, name, value, 
 3:                        field_label )
 4:      Display a row to input text: label on left,
 5:      text input on right.
 6: 
 7:      Defaults:
 8:        colspan = 2
 9:   ########################################-%]
10: 
11: [%- DEFAULT colspan = 2; -%]  
12: [%- INCLUDE label_row_begin( colspan = 1 ) -%]
13: [%- INCLUDE data_cell_begin %][% INCLUDE form_text %]
14: </td></tr>

Here we call three separate items, two of which ('label_row_begin' and 'data_cell_begin') aren't really 'widgets' but rather just named areas for common code. This might be called:

1: [% INCLUDE label_form_text_row( label = 'Batting Average',
2:                                 name  = 'batting_average',
3:                                 value = '.389', size = 5 ) -%]

And result in:

1: <tr valign="middle">
2:   <td align="right"><b>Batting Average</b></td>
3:   <td align="right">
4:     <input type="text" name="batting_average" value=".389"
5:             size="5" maxlength="50">
6:   </td>
7: </tr>

And you're not restricted to simple fill-in elements either. You can represent a common data-oriented widget -- such as a drop-down box representing countries your company services -- in this manner as well. Here's how such a call might look:

1: [%# Use USA as default, antagonizing the rest of the world...-%]
2: [%- picked_country = user.country || 'United States' -%]
3: [% INCLUDE label_form_country_select( label  = 'Countries',
4:                                       name   = 'country',
5:                                       picked = picked_country ) -%]

Using this, the page designer doesn't care how many countries the company services, whether a new one has been added to the list, etc. Just make the call and the graphic element will be created the same way every time.

Using these template widgets you can build a library of display elements very quickly.

WIDGET LISTING

As of version 2.0, OpenInteract comes with the following widgets:

  • data_cell_begin

  • date_select

  • error_message

  • form_begin

  • form_button

  • form_checkbox

  • form_end

  • form_hidden

  • form_login

  • form_password

  • form_radio

  • form_radioset

  • form_reset

  • form_select

  • form_select_intro

  • form_select_option

  • form_select_options_iterator

  • form_select_options_list

  • form_select_options_plain_list

  • form_submit

  • form_submit_row

  • form_text

  • form_textarea

  • form_upload

  • header_cell

  • header_row

  • label_form_checkbox_row

  • label_form_date_row

  • label_form_login_row

  • label_form_radio_row

  • label_form_select_row

  • label_form_text_row

  • label_form_textarea_row

  • label_row

  • label_row_begin

  • label_text_row

  • object_updates

  • page_count

  • row_color

  • search_results_page_listing

  • show_label

  • table_bordered_begin

  • table_bordered_end

  • to_group

Every website has its own copy of the widgets in the website template/ directory, so if you want to modify the appearance of any of these items, you can. For instance, if you want to pass in a Spanish equivalent for labels, you can modify 'show_label', which is currently the ultra-simple:

1: [%########################################
2:   show_label( label )
3:      Display a label.
4:   ########################################-%]
5: <b>[% label %]</b>

with:

1: [%########################################
2:   show_label( label, spanish )
3:      Display a label (displaying spanish version if available)
4:   ########################################-%]
5: <b>[% label %]</b> [% IF spanish %](<em>[% spanish %]<em>)[% END -%]

OPERATION

When you create a website you have a number of widgets installed by default in the $WEBSITE_DIR/template directory. These widgets will never be overwritten unless you ask them to be (via the oi2_manage refresh_widget command -- TODO: do we have a 'refresh_widget' command?) and they are specific to your website. You can add new ones, remove existing ones -- whatever you like

Gotchas

The Template Toolkit docs warn about this, but it's worth reiterating. You can use either the INCLUDE or PROCESS directives to run these widgets. The difference between them is subtle.

  • INCLUDE ensures that variables you modify within the widget (even with a DEFAULT) are localized to the widget.

  • PROCESS does not localize variables within the widget -- any changes you make in the widget are propogated outside the widget.

For instance, say you have the following:

1: [% PROCESS form_text( name  = 'this',
2:                       value = 'that' ) %]
3: [% PROCESS form_select( name        = 'them',
4:                         list        = object_list,
5:                         value_field = 'id',
6:                         label_field = 'full_name' ) %]

You'd be extremely surprised to find your SELECT box being 20 rows long! that's because inside the 'form_text' widget there's a statement:

1: [% DEFAULT size = 20 %]

Since we didn't pass any value for 'size' into 'form_text', it's set to 20. But the tricky part is that this value is also passed into the 'form_select' widget since it's in our environment and we didn't pass it explicitly in the PROCESS call.

You could argue that instead of using DEFAULT we should do something like:

1: [% text_size = size || 20 %]

So that the common variable 'size' isn't set as a side-effect. And that's a valid argument. But then as a widget writer you have to have knowledge of the variables the other widgets are using. And as a widget user you have to have knowledge of what happens inside the widget.

With these potential pitfalls, why use PROCESS at all? The Template Toolkit manual states that using PROCESS is a little faster. So you have a trade-off to make: a little speed for knowledge that things will work like you think they will.

The template widgets shipped with OpenInteract generally fall on the side of being able to sleep at night -- every widget works like you think it should. (Or at least how someone thought it should.) You can always change them for you site if you like, but we've found it's better to use INCLUDE and not deal with the potential headaches. If you're sure the widget won't have any side effects -- that it doesn't have any DEFAULT or other variable modification statements -- then go ahead and use PROCESS.

COPYRIGHT

Copyright (c) 2001-2004 Chris Winters. All rights reserved.

AUTHORS

Chris Winters <chris@cwinters.com>