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 fixup_callback - (optional) subroutine reference, returns supplimentary
91 JavaScript for the function described above under FORMS.
95 size - (optional) size of the E<lt>SELECTE<gt>, default 1.
97 unique_key - (optional) prepended to all JavaScript function/variable/object
98 names to avoid namespace collisions.
100 html_beween - (optional) HTML between the E<lt>SELECTE<gt> and the layers.
105 my($proto, %options) = @_;
106 my $class = ref($proto) || $proto;
107 my $self = \%options;
108 bless($self, $class);
115 Returns HTML for the widget.
121 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
122 my $between = exists($self->{html_between}) ? $self->{html_between} : '';
123 my $options = $self->{options};
124 my $form_action = exists($self->{form_action}) ? $self->{form_action} : '';
126 exists($self->{form_text}) ? $self->{form_text} : [];
128 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
130 my $html = $self->_safeonload.
132 "<SCRIPT>SafeAddOnLoad(${key}visualize)</SCRIPT>".
135 $self->_select. $between. '</FORM>';
137 #foreach my $layer ( 'konq_kludge', keys %$options ) {
138 foreach my $layer ( keys %$options ) {
141 my $visibility = "hidden";
144 if (document.getElementById) {
145 document.write("<DIV ID=\\"${key}d$layer\\" STYLE=\\"visibility: $visibility; position: absolute\\">");
148 $visibility="show" if $visibility eq "visible";
150 document.write("<LAYER ID=\\"${key}l$layer\\" VISIBILITY=\\"$visibility\\">");
157 <FORM NAME="${key}$layer" ACTION="$form_action" METHOD=POST onSubmit="${key}fixup(this)">
159 foreach my $f ( @$form_text, @$form_checkbox ) {
161 <INPUT TYPE="hidden" NAME="$f" VALUE="">
166 $html .= &{$self->{layer_callback}}($layer);
173 if (document.getElementById) {
174 document.write("</DIV>");
176 document.write("</LAYER>");
188 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
189 my $form_name = $self->{form_name} or return '';
191 exists($self->{form_text}) ? $self->{form_text} : [];
193 exists($self->{form_checkbox}) ? $self->{form_checkbox} : [];
196 function ${key}fchanged(what) {
197 ${key}fixup(what.form);
199 function ${key}fixup(what) {\n";
201 foreach my $f ( @$form_text ) {
202 $html .= "what.$f.value = document.$form_name.$f.value;\n";
205 foreach my $f ( @$form_checkbox ) {
206 $html .= "if (document.$form_name.$f.checked)
207 what.$f.value = document.$form_name.$f.value;
209 what.$f.value = '';\n"
212 # foreach my $f ( @$form_select ) {
213 # $html .= "what.$f.value = document.$form_name.$f.options[document.$form_name.$f.selectedIndex].value;\n";
216 $html .= &{$self->{fixup_callback}}() if exists($self->{fixup_callback});
218 $html .= "}\n</SCRIPT>";
226 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
227 my $options = $self->{options};
228 my $selected = exists($self->{selected_layer}) ? $self->{selected_layer} : '';
229 my $size = exists($self->{size}) ? $self->{size} : 1;
231 <SELECT NAME=\"${key}select\" SIZE=$size onChange=\"${key}changed(this);\">
233 foreach my $option ( keys %$options ) {
234 $html .= "<OPTION VALUE=\"$option\"";
235 $html .= ' SELECTED' if $option eq $selected;
236 $html .= '>'. $options->{$option}. '</OPTION>';
238 $html .= '</SELECT>';
243 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
244 my $options = $self->{options};
247 var ${key}layer = null;
248 function ${key}changed(what) {
249 ${key}layer = what.options[what.selectedIndex].value;\n";
250 foreach my $layer ( keys %$options ) {
251 $html .= "if (${key}layer == \"$layer\" ) {\n";
252 foreach my $not ( grep { $_ ne $layer } keys %$options ) {
254 if (document.getElementById) {
255 document.getElementById('${key}d$not').style.visibility = \"hidden\";
257 document.${key}l$not.visibility = \"hidden\";
261 if (document.getElementById) {
262 document.getElementById('${key}d$layer').style.visibility = \"visible\";
264 document.${key}l$layer.visibility = \"visible\";
268 $html .= "}\n</SCRIPT>";
274 my $key = exists($self->{unique_key}) ? $self->{unique_key} : '';
275 return '' unless exists($self->{selected_layer});
276 my $selected = $self->{selected_layer};
279 function ${key}visualize() {
280 if (document.getElementById) {
281 document.getElementById('${key}d$selected').style.visibility = "visible";
283 document.${key}l$selected.visibility = "visible";
293 var gSafeOnload = new Array();
294 function SafeAddOnLoad(f) {
296 if (window.onload != SafeOnload) {
297 gSafeOnload[0] = window.onload;
298 window.onload = SafeOnload;
300 gSafeOnload[gSafeOnload.length] = f;
305 function SafeOnload()
307 for (var i=0;i<gSafeOnload.length;i++)
318 Ivan Kohler E<lt>ivan-selectlayers@420.amE<gt>
322 Copyright (c) 2002 Ivan Kohler
324 This program is free software; you can redistribute it and/or modify it under
325 the same terms as Perl itself.
333 L<perl>. L<Tie::IxHash>, http://www.xs4all.nl/~ppk/js/dom.html,
334 http://javascript.about.com/library/scripts/blsafeonload.htm