Handle hostnames with upper-case letters
[webmin.git] / Webmin / Form.pm
1 package Webmin::Form;
2 use WebminCore;
3
4 =head2 new Webmin::Form(cgi, [method])
5 Creates a new form, which submits to the given CGI
6 =cut
7 sub new
8 {
9 if (defined(&Webmin::Theme::Form::new)) {
10         return new Webmin::Theme::Form(@_[1..$#_]);
11         }
12 my ($self, $program, $method) = @_;
13 $self = { 'method' => 'get',
14           'name' => "form".++$form_count };
15 bless($self);
16 $self->set_program($program);
17 $self->set_method($method) if ($method);
18 return $self;
19 }
20
21 =head2 html()
22 Returns the HTML that makes up this form
23 =cut
24 sub html
25 {
26 my ($self) = @_;
27 my $rv;
28 if ($self->get_align()) {
29         $rv .= "<div align=".$self->get_align().">\n";
30         }
31 $rv .= $self->form_start();
32 if ($self->get_heading()) {
33         if (defined(&ui_subheading)) {
34                 $rv .= &ui_subheading($self->get_heading());
35                 }
36         else {
37                 $rv .= "<h3>".$self->get_heading()."</h3>\n";
38                 }
39         }
40
41 # Add the sections
42 foreach my $h (@{$self->{'hiddens'}}) {
43         $rv .= &ui_hidden($h->[0], $h->[1])."\n";
44         }
45 foreach my $s (@{$self->{'sections'}}) {
46         $rv .= $s->html();
47         }
48
49 # Check if we have any inputs that need disabling
50 my @dis = $self->list_disable_inputs();
51 if (@dis) {
52         # Yes .. generate a function for them
53         $rv .= "<script>\n";
54         $rv .= "function ui_disable_".$self->{'name'}."(form) {\n";
55         foreach my $i (@dis) {
56                 foreach my $n ($i->get_input_names()) {
57                         $rv .= "    form.".$n.".disabled = (".
58                                       $i->get_disable_code().");\n";
59                         }
60                 }
61         $rv .= "}\n";
62         $rv .= "</script>\n";
63         }
64
65 # Add the buttons at the end of the form
66 my @buttonargs;
67 foreach my $b (@{$self->{'buttons'}}) {
68         if (ref($b)) {
69                 # An array of inputs
70                 my $ihtml = join(" ", map { $_->html() } @$b);
71                 push(@buttonargs, $ihtml);
72                 }
73         else {
74                 # A spacer
75                 push(@buttonargs, "");
76                 }
77         }
78 $rv .= &ui_form_end(\@buttonargs);
79
80 if ($self->get_align()) {
81         $rv .= "</div>\n";
82         }
83
84 # Call the Javascript disable function
85 if (@dis) {
86         $rv .= "<script>\n";
87         $rv .= "ui_disable_".$self->{'name'}."(window.document.forms[\"$self->{'name'}\"]);\n";
88         $rv .= "</script>\n";
89         }
90
91 return $rv;
92 }
93
94 sub form_start
95 {
96 my ($self) = @_;
97 return "<form action='$self->{'program'}' ".
98                 ($self->{'method'} eq "post" ? "method=post" :
99                  $self->{'method'} eq "form-data" ?
100                         "method=post enctype=multipart/form-data" :
101                         "method=get")." name=$self->{'name'}>\n";
102 }
103
104 =head2 add_section(section)
105 Adds a Webmin::Section object to this form
106 =cut
107 sub add_section
108 {
109 my ($self, $section) = @_;
110 push(@{$self->{'sections'}}, $section);
111 $section->set_form($self);
112 }
113
114 =head2 get_section(idx)
115 =cut
116 sub get_section
117 {
118 my ($self, $idx) = @_;
119 return $self->{'sections'}->[$idx];
120 }
121
122 =head2 add_button(button, [beside, ...])
123 Adds a Webmin::Submit object to this form, for display at the bottom
124 =cut
125 sub add_button
126 {
127 my ($self, $button, @beside) = @_;
128 push(@{$self->{'buttons'}}, [ $button, @beside ]);
129 }
130
131 =head2 add_button_spacer()
132 Adds a gap between buttons, for grouping
133 =cut
134 sub add_button_spacer
135 {
136 my ($self, $spacer) = @_;
137 push(@{$self->{'buttons'}}, $spacer);
138 }
139
140 =head2 add_hidden(name, value)
141 Adds some hidden input to this form, for passing to the CGI
142 =cut
143 sub add_hidden
144 {
145 my ($self, $name, $value) = @_;
146 push(@{$self->{'hiddens'}}, [ $name, $value ]);
147 }
148
149 =head2 validate()
150 Validates all form inputs, based on the current CGI input hash. Returns a list
151 of errors, each of which is field name and error message.
152 =cut
153 sub validate
154 {
155 my ($self) = @_;
156 my @errs;
157 foreach my $s (@{$self->{'sections'}}) {
158         push(@errs, $s->validate($self->{'in'}));
159         }
160 return @errs;
161 }
162
163 =head2 validate_redirect(page, [&extra-errors])
164 Validates the form, and if any errors are found re-directs to the given page
165 with the errors, so that they can be displayed.
166 =cut
167 sub validate_redirect
168 {
169 my ($self, $page, $extras) = @_;
170 if ($self->{'in'}->{'ui_redirecting'}) {
171         # If this page is displayed as part of a redirect, no need to validate!
172         return;
173         }
174 my @errs = $self->validate();
175 push(@errs, @$extras);
176 if (@errs) {
177         my (@errlist, @vallist);
178         foreach my $e (@errs) {
179                 push(@errlist, &urlize("ui_error_".$e->[0])."=".
180                                &urlize($e->[1]));
181                 }
182         foreach my $i ($self->list_inputs()) {
183                 my $v = $i->get_value();
184                 my @vals = ref($v) ? @$v : ( $v );
185                 @vals = ( undef ) if (!@vals);
186                 foreach $v (@vals) {
187                         push(@vallist,
188                             &urlize("ui_value_".$i->get_name())."=".
189                             &urlize($v));
190                         }
191                 }
192         foreach my $h (@{$self->{'hiddens'}}) {
193                 push(@vallist,
194                     &urlize($h->[0])."=".&urlize($h->[1]));
195                 }
196         if ($page =~ /\?/) { $page .= "&"; }
197         else { $page .= "?"; }
198         &redirect($page.join("&", "ui_redirecting=1", @errlist, @vallist));
199         exit(0);
200         }
201 }
202
203 =head2 validate_error(whatfailed)
204 Validates the form, and if any errors are found displays an error page.
205 =cut
206 sub validate_error
207 {
208 my ($self, $whatfailed) = @_;
209 my @errs = $self->validate();
210 &error_setup($whatfailed);
211 if (@errs == 1) {
212         &error($errs[0]->[2] ? "$errs[0]->[2] : $errs[0]->[1]"
213                                    : $errs[0]->[1]);
214         }
215 elsif (@errs > 1) {
216         my $msg = $text{'ui_errors'}."<br>";
217         foreach my $e (@errs) {
218                 $msg .= $e->[2] ? "$e->[2] : $e->[1]<br>\n"
219                                 : "$e->[1]<br>\n";
220                 }
221         &error($msg);
222         }
223 }
224
225 =head2 field_errors(name)
226 Returns a list of error messages associated with the field of some name, from
227 the input passed to set_input
228 =cut
229 sub field_errors
230 {
231 my ($self, $name) = @_;
232 my @errs;
233 my $in = $self->{'in'};
234 foreach my $i (keys %$in) {
235         if ($i eq "ui_error_".$name) {
236                 push(@errs, split(/\0/, $in->{$i}));
237                 }
238         }
239 return @errs;
240 }
241
242 =head2 set_input(&input)
243 Passes the form input hash to this form object, for use by the validate
244 functions and for displaying errors next to fields.
245 =cut
246 sub set_input
247 {
248 my ($self, $in) = @_;
249 $self->{'in'} = $in;
250 }
251
252 =head2 get_value(input-name)
253 Returns the value of the input with the given name.
254 =cut
255 sub get_value
256 {
257 my ($self, $name) = @_;
258 foreach my $s (@{$self->{'sections'}}) {
259         my $rv = $s->get_value($name);
260         return $rv if (defined($rv));
261         }
262 return $self->{'in'}->{$name};
263 }
264
265 =head2 get_input(name)
266 Returns the input with the given name
267 =cut
268 sub get_input
269 {
270 my ($self, $name) = @_;
271 foreach my $i ($self->list_inputs()) {
272         return $i if ($i->get_name() eq $name);
273         }
274 return undef;
275 }
276
277 sub set_program
278 {
279 my ($self, $program) = @_;
280 $self->{'program'} = $program;
281 }
282
283 sub set_method
284 {
285 my ($self, $method) = @_;
286 $self->{'method'} = $method;
287 }
288
289 =head2 list_inputs()
290 Returns all inputs in all form sections
291 =cut
292 sub list_inputs
293 {
294 my ($self) = @_;
295 my @rv;
296 foreach my $s (@{$self->{'sections'}}) {
297         push(@rv, $s->list_inputs());
298         }
299 return @rv;
300 }
301
302 =head2 list_disable_inputs()
303 Returns a list of inputs that have disable functions
304 =cut
305 sub list_disable_inputs
306 {
307 my ($self) = @_;
308 my @dis;
309 foreach my $i ($self->list_inputs()) {
310         push(@dis, $i) if ($i->get_disable_code());
311         }
312 return @dis;
313 }
314
315 =head2 set_page(Webmin::Page)
316 Called when this form is added to a page
317 =cut
318 sub set_page
319 {
320 my ($self, $page) = @_;
321 $self->{'page'} = $page;
322 }
323
324 =head2 get_changefunc(&input)
325 Called by some input, to return the Javascript that should be called when this
326 input changes it's value.
327 =cut
328 sub get_changefunc
329 {
330 my ($self, $input) = @_;
331 my @dis = $self->list_disable_inputs();
332 if (@dis) {
333         return "ui_disable_".$self->{'name'}."(form)";
334         }
335 return undef;
336 }
337
338 =head2 set_heading(text)
339 Sets the heading to be displayed above the form
340 =cut
341 sub set_heading
342 {
343 my ($self, $heading) = @_;
344 $self->{'heading'} = $heading;
345 }
346
347 sub get_heading
348 {
349 my ($self) = @_;
350 return $self->{'heading'};
351 }
352
353 =head2 get_formno()
354 Returns the index of this form on the page
355 =cut
356 sub get_formno
357 {
358 my ($self) = @_;
359 my $n = 0;
360 foreach my $f (@{$self->{'page'}->{'contents'}}) {
361         if ($f eq $self) {
362                 return $n;
363                 }
364         elsif (ref($f) =~ /Form/) {
365                 $n++;
366                 }
367         }
368 return undef;
369 }
370
371 =head2 add_onload(code)
372 Adds some Javascript code for inclusion in the onLoad tag
373 =cut
374 sub add_onload
375 {
376 my ($self, $code) = @_;
377 push(@{$self->{'onloads'}}, $code);
378 }
379
380 =head2 add_script(code)
381 Adds some Javascript code for putting in the <head> section
382 =cut
383 sub add_script
384 {
385 my ($self, $script) = @_;
386 push(@{$self->{'scripts'}}, $script);
387 }
388
389 =head2 set_align(align)
390 Sets the alignment on the page (left, center, right)
391 =cut
392 sub set_align
393 {
394 my ($self, $align) = @_;
395 $self->{'align'} = $align;
396 }
397
398 sub get_align
399 {
400 my ($self) = @_;
401 return $self->{'align'};
402 }
403
404 1;
405