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 'layer_callback' => sub {
30 my $html = qq!<INPUT TYPE="hidden" NAME="layer" VALUE="$layer">!;
31 $html .= $other_stuff;
36 print '<FORM NAME=dummy>'.
37 '<INPUT TYPE="text" NAME="textfield1">'.
38 '<INPUT TYPE="text" NAME="textfield2">'.
39 '<INPUT TYPE="checkbox" NAME="checkbox1" VALUE="Y">'.
44 This module implements an HTML widget with multiple layers. Only one layer
45 is visible at any given time, controlled by a E<lt>SELECTE<gt> box. For an
46 example see http://www.420.am/selectlayers/
48 This HTML generated by this module uses JavaScript, but nevertheless attempts
49 to be as cross-browser as possible, testing for features via DOM support rather
50 than specific browsers or versions. It has been tested under Mozilla 0.9.8,
51 Netscape 4.77, IE 5.5, Konqueror 2.2.2, and Opera 5.0.
55 Not all browsers seem happy with forms that span layers. The generated HTML
56 will have a E<lt>/FORME<gt> tag before the layers and will generate
57 E<lt>FORME<gt> and E<lt>/FORME<gt> tags for each layer. To facilitate
58 E<lt>SUBMITE<gt> buttons located within the layers, you can pass a form name
59 and element names, and the relevant values will be copied to the layer's form.
60 See the B<form_> options below.
66 =item new KEY, VALUE, KEY, VALUE...
68 Options are passed as name/value pairs:
70 options - Hash reference of layers and labels for the E<lt>SELECTE<gt>. See
71 L<Tie::IxHash> to control ordering.
72 In HTML: E<lt>OPTION VALUE="$layer"E<gt>$labelE<lt>/OPTIONE<gt>
74 layer_callback - subroutine reference to create each layer. The layer name
75 is passed as an option in I<@_>
77 selected_layer - (optional) initially selected layer
79 form_name - (optional) Form name to copy values from. If not supplied, no
80 values will be copied.
82 form_action - Form action
84 form_text - (optional) Array reference of text (or hidden) form fields to copy
85 from the B<form_name> form.
87 form_checkbox - (optional) Array reference of checkbox form fields to copy from
88 the B<form_name> form.
90 form_select - (optional) Array reference of select (not select multiple) form
91 fields to copy from the B<form_name> form.
93 fixup_callback - (optional) subroutine reference, returns supplimentary
94 JavaScript for the function described above under FORMS.
96 size - (optional) size of the E<lt>SELECTE<gt>, default 1.
98 unique_key - (optional) prepended to all JavaScript function/variable/object
99 names to avoid namespace collisions.
101 html_beween - (optional) HTML between the E<lt>SELECTE<gt> and the layers.
106 my($proto, %options) = @_;
107 my $class = ref($proto) || $proto;
108 my $self = \%options;
109 bless($self, $class);
116 Returns HTML for the widget.
122 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
123 my $between = exists($self->{html_between}) ? $self->{html_between} : '';
124 my $options = $self->{options};
125 my $form_action = exists($self->{form_action}) ? $self->{form_action} : '';
127 exists($self->{form_text}) ? $self->{form_text} : [];
129 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
131 my $html = $self->_safeonload.
133 "<SCRIPT>SafeAddOnLoad(${key}visualize)</SCRIPT>".
136 $self->_select. $between. '</FORM>';
138 #foreach my $layer ( 'konq_kludge', keys %$options ) {
139 foreach my $layer ( keys %$options ) {
142 my $visibility = "hidden";
145 if (document.getElementById) {
146 document.write("<DIV ID=\\"${key}d$layer\\" STYLE=\\"visibility: $visibility; position: absolute\\">");
149 $visibility="show" if $visibility eq "visible";
151 document.write("<LAYER ID=\\"${key}l$layer\\" VISIBILITY=\\"$visibility\\">");
158 <FORM NAME="${key}$layer" ACTION="$form_action" METHOD=POST onSubmit="${key}fixup(this)">
160 foreach my $f ( @$form_text, @$form_checkbox ) {
162 <INPUT TYPE="hidden" NAME="$f" VALUE="">
167 $html .= &{$self->{layer_callback}}($layer);
174 if (document.getElementById) {
175 document.write("</DIV>");
177 document.write("</LAYER>");
189 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
190 my $form_name = $self->{form_name} or return '';
192 exists($self->{form_text}) ? $self->{form_text} : [];
194 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
196 exists($self->{form_select}) ? $self->{form_select} : [];
199 function ${key}fchanged(what) {
200 ${key}fixup(what.form);
202 function ${key}fixup(what) {\n";
204 foreach my $f ( @$form_text ) {
205 $html .= "what.$f.value = document.$form_name.$f.value;\n";
208 foreach my $f ( @$form_checkbox ) {
209 $html .= "if (document.$form_name.$f.checked)
210 what.$f.value = document.$form_name.$f.value;
212 what.$f.value = '';\n"
215 foreach my $f ( @$form_select ) {
216 $html .= "what.$f.value = document.$form_name.$f.options[document.$form_name.$f.selectedIndex].value;\n";
219 $html .= &{$self->{fixup_callback}}() if exists($self->{fixup_callback});
221 $html .= "}\n</SCRIPT>";
229 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
230 my $options = $self->{options};
231 my $selected = exists($self->{selected_layer}) ? $self->{selected_layer} : '';
232 my $size = exists($self->{size}) ? $self->{size} : 1;
234 <SELECT NAME=\"${key}select\" SIZE=$size onChange=\"${key}changed(this);\">
236 foreach my $option ( keys %$options ) {
237 $html .= "<OPTION VALUE=\"$option\"";
238 $html .= ' SELECTED' if $option eq $selected;
239 $html .= '>'. $options->{$option}. '</OPTION>';
241 $html .= '</SELECT>';
246 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
247 my $options = $self->{options};
250 var ${key}layer = null;
251 function ${key}changed(what) {
252 ${key}layer = what.options[what.selectedIndex].value;\n";
253 foreach my $layer ( keys %$options ) {
254 $html .= "if (${key}layer == \"$layer\" ) {\n";
255 foreach my $not ( grep { $_ ne $layer } keys %$options ) {
257 if (document.getElementById) {
258 document.getElementById('${key}d$not').style.visibility = \"hidden\";
260 document.${key}l$not.visibility = \"hidden\";
264 if (document.getElementById) {
265 document.getElementById('${key}d$layer').style.visibility = \"visible\";
267 document.${key}l$layer.visibility = \"visible\";
271 $html .= "}\n</SCRIPT>";
277 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
278 return '' unless exists($self->{selected_layer});
279 my $selected = $self->{selected_layer};
282 function ${key}visualize() {
283 if (document.getElementById) {
284 document.getElementById('${key}d$selected').style.visibility = "visible";
286 document.${key}l$selected.visibility = "visible";
296 var gSafeOnload = new Array();
297 function SafeAddOnLoad(f) {
299 if (window.onload != SafeOnload) {
300 gSafeOnload[0] = window.onload;
301 window.onload = SafeOnload;
303 gSafeOnload[gSafeOnload.length] = f;
308 function SafeOnload()
310 for (var i=0;i<gSafeOnload.length;i++)
321 Ivan Kohler E<lt>ivan-selectlayers@420.amE<gt>
325 Copyright (c) 2002 Ivan Kohler
327 This program is free software; you can redistribute it and/or modify it under
328 the same terms as Perl itself.
336 L<perl>. L<Tie::IxHash>, http://www.xs4all.nl/~ppk/js/dom.html,
337 http://javascript.about.com/library/scripts/blsafeonload.htm