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 exists($self->{form_select}) ? $self->{form_select} : [];
133 my $html = $self->_safeonload.
135 "<SCRIPT>SafeAddOnLoad(${key}visualize)</SCRIPT>".
138 $self->_select. $between. '</FORM>';
140 #foreach my $layer ( 'konq_kludge', keys %$options ) {
141 foreach my $layer ( keys %$options ) {
144 my $visibility = "hidden";
147 if (document.getElementById) {
148 document.write("<DIV ID=\\"${key}d$layer\\" STYLE=\\"visibility: $visibility; position: absolute\\">");
151 $visibility="show" if $visibility eq "visible";
153 document.write("<LAYER ID=\\"${key}l$layer\\" VISIBILITY=\\"$visibility\\">");
160 <FORM NAME="${key}$layer" ACTION="$form_action" METHOD=POST onSubmit="${key}fixup(this)">
162 foreach my $f ( @$form_text, @$form_checkbox, @$form_select ) {
164 <INPUT TYPE="hidden" NAME="$f" VALUE="">
169 $html .= &{$self->{layer_callback}}($layer);
176 if (document.getElementById) {
177 document.write("</DIV>");
179 document.write("</LAYER>");
191 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
192 my $form_name = $self->{form_name} or return '';
194 exists($self->{form_text}) ? $self->{form_text} : [];
196 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
198 exists($self->{form_select}) ? $self->{form_select} : [];
201 function ${key}fchanged(what) {
202 ${key}fixup(what.form);
204 function ${key}fixup(what) {\n";
206 foreach my $f ( @$form_text ) {
207 $html .= "what.$f.value = document.$form_name.$f.value;\n";
210 foreach my $f ( @$form_checkbox ) {
211 $html .= "if (document.$form_name.$f.checked)
212 what.$f.value = document.$form_name.$f.value;
214 what.$f.value = '';\n"
217 foreach my $f ( @$form_select ) {
218 $html .= "what.$f.value = document.$form_name.$f.options[document.$form_name.$f.selectedIndex].value;\n";
221 $html .= &{$self->{fixup_callback}}() if exists($self->{fixup_callback});
223 $html .= "}\n</SCRIPT>";
231 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
232 my $options = $self->{options};
233 my $selected = exists($self->{selected_layer}) ? $self->{selected_layer} : '';
234 my $size = exists($self->{size}) ? $self->{size} : 1;
236 <SELECT NAME=\"${key}select\" SIZE=$size onChange=\"${key}changed(this);\">
238 foreach my $option ( keys %$options ) {
239 $html .= "<OPTION VALUE=\"$option\"";
240 $html .= ' SELECTED' if $option eq $selected;
241 $html .= '>'. $options->{$option}. '</OPTION>';
243 $html .= '</SELECT>';
248 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
249 my $options = $self->{options};
252 var ${key}layer = null;
253 function ${key}changed(what) {
254 ${key}layer = what.options[what.selectedIndex].value;\n";
255 foreach my $layer ( keys %$options ) {
256 $html .= "if (${key}layer == \"$layer\" ) {\n";
257 foreach my $not ( grep { $_ ne $layer } keys %$options ) {
259 if (document.getElementById) {
260 document.getElementById('${key}d$not').style.visibility = \"hidden\";
262 document.${key}l$not.visibility = \"hidden\";
266 if (document.getElementById) {
267 document.getElementById('${key}d$layer').style.visibility = \"visible\";
269 document.${key}l$layer.visibility = \"visible\";
273 $html .= "}\n</SCRIPT>";
279 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
280 return '' unless exists($self->{selected_layer});
281 my $selected = $self->{selected_layer};
284 function ${key}visualize() {
285 if (document.getElementById) {
286 document.getElementById('${key}d$selected').style.visibility = "visible";
288 document.${key}l$selected.visibility = "visible";
298 var gSafeOnload = new Array();
299 function SafeAddOnLoad(f) {
301 if (window.onload != SafeOnload) {
302 gSafeOnload[0] = window.onload;
303 window.onload = SafeOnload;
305 gSafeOnload[gSafeOnload.length] = f;
310 function SafeOnload()
312 for (var i=0;i<gSafeOnload.length;i++)
323 Ivan Kohler E<lt>ivan-selectlayers@420.amE<gt>
327 Copyright (c) 2002 Ivan Kohler
329 This program is free software; you can redistribute it and/or modify it under
330 the same terms as Perl itself.
338 L<perl>. L<Tie::IxHash>, http://www.xs4all.nl/~ppk/js/dom.html,
339 http://javascript.about.com/library/scripts/blsafeonload.htm