Home | Wiki | OI 1.x Docs | OI 2.x Docs |
OpenInteract2::Manual::Widgets - Template Widgets in OpenInteract
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.
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 -%]
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
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 (c) 2001-2003 Chris Winters. All rights reserved.
Chris Winters <chris@cwinters.com>
Generated from the OpenInteract 1.99_03 source.