1 package HTML::Widgets::SelectLayers;
10 HTML::Widgets::SelectLayers - Perl extension for selectable HTML layers
14 use HTML::Widgets::SelectLayers;
17 tie my %options, 'Tie::IxHash',
18 'value' => 'Select One',
19 'value2' => 'Select Two',
22 $widget = new HTML::Widgets::SelectLayers(
23 'options' => \%options,
24 'form_name' => 'dummy',
25 'form_action' => 'process.cgi',
26 'form_text' => [ qw( textfield1 textfield2 ) ],
27 'form_checkbox' => [ qw( checkbox1 ) ],
28 'form_radio' => [ qw( radio1 ) ],
29 'form_select' => [ qw( select1 ) ],
30 'layer_callback' => sub {
32 my $html = qq!<INPUT TYPE="hidden" NAME="layer" VALUE="$layer">!;
33 $html .= $other_stuff;
38 print '<FORM NAME=dummy>'.
39 '<INPUT TYPE="text" NAME="textfield1">'.
40 '<INPUT TYPE="text" NAME="textfield2">'.
41 '<INPUT TYPE="checkbox" NAME="checkbox1" VALUE="Y">'.
46 This module implements an HTML widget with multiple layers. Only one layer
47 is visible at any given time, controlled by a E<lt>SELECTE<gt> box. For an
48 example see http://www.420.am/selectlayers/
50 This HTML generated by this module uses JavaScript, but nevertheless attempts
51 to be as cross-browser as possible, testing for features via DOM support rather
52 than specific browsers or versions. It has been tested under Mozilla 0.9.8,
53 Netscape 4.77, IE 5.5, Konqueror 2.2.2, and Opera 5.0.
57 Not all browsers seem happy with forms that span layers. The generated HTML
58 will have a E<lt>/FORME<gt> tag before the layers and will generate
59 E<lt>FORME<gt> and E<lt>/FORME<gt> tags for each layer. To facilitate
60 E<lt>SUBMITE<gt> buttons located within the layers, you can pass a form name
61 and element names, and the relevant values will be copied to the layer's form.
62 See the B<form_> options below.
68 =item new KEY, VALUE, KEY, VALUE...
70 Options are passed as name/value pairs:
72 options - Hash reference of layers and labels for the E<lt>SELECTE<gt>. See
73 L<Tie::IxHash> to control ordering.
74 In HTML: E<lt>OPTION VALUE="$layer"E<gt>$labelE<lt>/OPTIONE<gt>
76 layer_callback - subroutine reference to create each layer. The layer name
77 is passed as an option in I<@_>
79 selected_layer - (optional) initially selected layer
81 form_name - (optional) Form name to copy values from. If not supplied, no
82 values will be copied.
84 form_action - Form action
86 form_text - (optional) Array reference of text (or hidden) form fields to copy
87 from the B<form_name> form.
89 form_checkbox - (optional) Array reference of checkbox form fields to copy from
90 the B<form_name> form.
92 form_radio - (optional) Array reference of radio form fields to copy from the
95 form_select - (optional) Array reference of select (not select multiple) form
96 fields to copy from the B<form_name> form.
98 fixup_callback - (optional) subroutine reference, returns supplimentary
99 JavaScript for the function described above under FORMS.
101 size - (optional) size of the E<lt>SELECTE<gt>, default 1.
103 unique_key - (optional) prepended to all JavaScript function/variable/object
104 names to avoid namespace collisions.
106 html_beween - (optional) HTML between the E<lt>SELECTE<gt> and the layers.
111 my($proto, %options) = @_;
112 my $class = ref($proto) || $proto;
113 my $self = \%options;
114 bless($self, $class);
121 Returns HTML for the widget.
127 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
128 my $between = exists($self->{html_between}) ? $self->{html_between} : '';
129 my $options = $self->{options};
130 my $form_action = exists($self->{form_action}) ? $self->{form_action} : '';
132 exists($self->{form_text}) ? $self->{form_text} : [];
134 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
136 exists($self->{form_radio}) ? $self->{form_radio} : [];
138 exists($self->{form_select}) ? $self->{form_select} : [];
140 my $html = $self->_safeonload.
142 "<SCRIPT>SafeAddOnLoad(${key}visualize)</SCRIPT>".
145 $self->_select. $between. '</FORM>';
147 #foreach my $layer ( 'konq_kludge', keys %$options ) {
148 foreach my $layer ( keys %$options ) {
151 my $visibility = "hidden";
154 if (document.getElementById) {
155 document.write("<DIV ID=\\"${key}d$layer\\" STYLE=\\"visibility: $visibility; position: absolute\\">");
158 $visibility="show" if $visibility eq "visible";
160 document.write("<LAYER ID=\\"${key}l$layer\\" VISIBILITY=\\"$visibility\\">");
167 <FORM NAME="${key}$layer" ACTION="$form_action" METHOD=POST onSubmit="${key}fixup(this)">
169 foreach my $f ( @$form_text, @$form_checkbox, @$form_radio, @$form_select )
172 <INPUT TYPE="hidden" NAME="$f" VALUE="">
177 $html .= &{$self->{layer_callback}}($layer);
184 if (document.getElementById) {
185 document.write("</DIV>");
187 document.write("</LAYER>");
199 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
200 my $form_name = $self->{form_name} or return '';
202 exists($self->{form_text}) ? $self->{form_text} : [];
204 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
206 exists($self->{form_radio}) ? $self->{form_radio} : [];
208 exists($self->{form_select}) ? $self->{form_select} : [];
211 function ${key}fchanged(what) {
212 ${key}fixup(what.form);
214 function ${key}fixup(what) {\n";
216 foreach my $f ( @$form_text ) {
217 $html .= "what.$f.value = document.$form_name.$f.value;\n";
220 foreach my $f ( @$form_checkbox ) {
221 $html .= "if (document.$form_name.$f.checked)
222 what.$f.value = document.$form_name.$f.value;
224 what.$f.value = '';\n"
227 foreach my $f ( @$form_radio ) {
228 $html .= "what.$f.value = '';
229 for ( i=0; i< document.$form_name.$f.length; i++ )
230 if ( document.$form_name.${f}[i].checked )
231 what.$f.value = document.$form_name.${f}[i].value;\n";
234 foreach my $f ( @$form_select ) {
235 $html .= "what.$f.value = document.$form_name.$f.options[document.$form_name.$f.selectedIndex].value;\n";
238 $html .= &{$self->{fixup_callback}}() if exists($self->{fixup_callback});
240 $html .= "}\n</SCRIPT>";
248 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
249 my $options = $self->{options};
250 my $selected = exists($self->{selected_layer}) ? $self->{selected_layer} : '';
251 my $size = exists($self->{size}) ? $self->{size} : 1;
253 <SELECT NAME=\"${key}select\" SIZE=$size onChange=\"${key}changed(this);\">
255 foreach my $option ( keys %$options ) {
256 $html .= "<OPTION VALUE=\"$option\"";
257 $html .= ' SELECTED' if $option eq $selected;
258 $html .= '>'. $options->{$option}. '</OPTION>';
260 $html .= '</SELECT>';
265 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
266 my $options = $self->{options};
269 var ${key}layer = null;
270 function ${key}changed(what) {
271 ${key}layer = what.options[what.selectedIndex].value;\n";
272 foreach my $layer ( keys %$options ) {
273 $html .= "if (${key}layer == \"$layer\" ) {\n";
274 foreach my $not ( grep { $_ ne $layer } keys %$options ) {
276 if (document.getElementById) {
277 document.getElementById('${key}d$not').style.visibility = \"hidden\";
279 document.${key}l$not.visibility = \"hidden\";
283 if (document.getElementById) {
284 document.getElementById('${key}d$layer').style.visibility = \"visible\";
286 document.${key}l$layer.visibility = \"visible\";
290 $html .= "}\n</SCRIPT>";
296 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
297 return '' unless exists($self->{selected_layer});
298 my $selected = $self->{selected_layer};
301 function ${key}visualize() {
302 if (document.getElementById) {
303 document.getElementById('${key}d$selected').style.visibility = "visible";
305 document.${key}l$selected.visibility = "visible";
315 var gSafeOnload = new Array();
316 function SafeAddOnLoad(f) {
318 if (window.onload != SafeOnload) {
319 gSafeOnload[0] = window.onload;
320 window.onload = SafeOnload;
322 gSafeOnload[gSafeOnload.length] = f;
327 function SafeOnload()
329 for (var i=0;i<gSafeOnload.length;i++)
340 Ivan Kohler E<lt>ivan-selectlayers@420.amE<gt>
344 Copyright (c) 2002 Ivan Kohler
346 This program is free software; you can redistribute it and/or modify it under
347 the same terms as Perl itself.
355 L<perl>. L<Tie::IxHash>, http://www.xs4all.nl/~ppk/js/dom.html,
356 http://javascript.about.com/library/scripts/blsafeonload.htm