Use new module

This commit is contained in:
Jamie Cameron
2009-03-05 21:42:37 +00:00
parent a92f1708f5
commit 4b6ce0eebd
42 changed files with 5175 additions and 0 deletions

44
Webmin/All.pm Normal file
View File

@@ -0,0 +1,44 @@
use Webmin::Page;
use Webmin::ResultPage;
use Webmin::ErrorPage;
use Webmin::ConfirmPage;
use Webmin::Form;
use Webmin::Section;
use Webmin::Textbox;
use Webmin::OptTextbox;
use Webmin::OptTextarea;
use Webmin::Submit;
use Webmin::Password;
use Webmin::Checkbox;
use Webmin::Select;
use Webmin::Radios;
use Webmin::Checkboxes;
use Webmin::Table;
use Webmin::Menu;
use Webmin::LinkTable;
use Webmin::Tabs;
use Webmin::Textarea;
use Webmin::Upload;
use Webmin::DynamicText;
use Webmin::DynamicBar;
use Webmin::DynamicWait;
use Webmin::DynamicHTML;
use Webmin::Properties;
use Webmin::User;
use Webmin::Group;
use Webmin::File;
use Webmin::Button;
use Webmin::JavascriptButton;
use Webmin::PlainText;
use Webmin::Multiline;
use Webmin::Date;
use Webmin::Time;
use Webmin::TitleList;
use Webmin::Columns;
use Webmin::Icon;
use Webmin::TableAction;
use Webmin::InputTable;
use WebminCore;
1;

61
Webmin/Button.pm Normal file
View File

@@ -0,0 +1,61 @@
package Webmin::Button;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Button(cgi, label, [name])
Creates a button that when clicked will link to some other page
=cut
sub new
{
if (defined(&Webmin::Theme::Button::new) &&
caller() !~ /Webmin::Theme::Button/) {
return new Webmin::Theme::Button(@_[1..$#_]);
}
my ($self, $cgi, $value, $name) = @_;
$self = { };
bless($self);
$self->set_cgi($cgi);
$self->set_value($value);
$self->set_name($name) if ($name);
return $self;
}
=head2 html()
Returns HTML for this button
=cut
sub html
{
my ($self) = @_;
my $rv = "<form action=".$self->get_cgi().">";
foreach my $h (@{$self->{'hiddens'}}) {
$rv .= &ui_hidden($h->[0], $h->[1])."\n";
}
$rv .= &ui_submit($self->get_value(), $self->get_name(),
$self->get_disabled())."</form>";
return $rv;
}
sub set_cgi
{
my ($self, $cgi) = @_;
$self->{'cgi'} = $cgi;
}
sub get_cgi
{
my ($self) = @_;
return $self->{'cgi'};
}
=head2 add_hidden(name, value)
Adds some hidden input to this button, for passing to the CGI
=cut
sub add_hidden
{
my ($self, $name, $value) = @_;
push(@{$self->{'hiddens'}}, [ $name, $value ]);
}
1;

64
Webmin/Checkbox.pm Normal file
View File

@@ -0,0 +1,64 @@
package Webmin::Checkbox;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Checkbox(name, return, label, checked, [disabled])
Create a single checkbox field
=cut
sub new
{
if (defined(&Webmin::Theme::Checkbox::new)) {
return new Webmin::Theme::Checkbox(@_[1..$#_]);
}
my ($self, $name, $return, $label, $checked, $disabled) = @_;
$self = { };
bless($self);
$self->set_name($name);
$self->set_return($return);
$self->set_label($label);
$self->set_value($checked);
$self->set_disabled($disabled);
return $self;
}
=head2 html()
Returns the HTML for this single checkbox
=cut
sub html
{
my ($self) = @_;
my $dis = $self->{'form'}->get_changefunc($self);
return &ui_checkbox($self->get_name(), $self->get_return(),
$self->get_label(), $self->get_value(),
$dis ? "onClick='$dis'" : undef,
$self->get_disabled()).
&ui_hidden("ui_exists_".$self->get_name(), 1);
}
sub set_return
{
my ($self, $return) = @_;
$self->{'return'} = $return;
}
sub set_label
{
my ($self, $label) = @_;
$self->{'label'} = $label;
}
sub get_return
{
my ($self) = @_;
return $self->{'return'};
}
sub get_label
{
my ($self) = @_;
return $self->{'label'};
}
1;

119
Webmin/Checkboxes.pm Normal file
View File

@@ -0,0 +1,119 @@
package Webmin::Checkboxes;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Checkboxes(name, value|&values, &options, [disabled])
Create a list of checkboxes, of which zero or more may be selected
=cut
sub new
{
if (defined(&Webmin::Theme::Checkboxes::new)) {
return new Webmin::Theme::Checkboxes(@_[1..$#_]);
}
my ($self, $name, $value, $options, $disabled) = @_;
$self = { };
bless($self);
$self->set_name($name);
$self->set_value($value);
$self->set_options($options);
$self->set_disabled($disabled);
return $self;
}
=head2 add_option(name, [label])
=cut
sub add_option
{
my ($self, $name, $label) = @_;
push(@{$self->{'options'}}, [ $name, $label ]);
}
=head2 html()
Returns the HTML for all the checkboxes, one after the other
=cut
sub html
{
my ($self) = @_;
my $rv;
for(my $i=0; $i<@{$self->{'options'}}; $i++) {
$rv .= $self->one_html($i)."\n";
}
return $rv;
}
=head2 one_html(number)
Returns the HTML for a single one of the checkboxes
=cut
sub one_html
{
my ($self, $num) = @_;
my $opt = $self->{'options'}->[$num];
my $value = $self->get_value();
my %sel = map { $_, 1 } (ref($value) ? @$value : ( $value ));
return &ui_checkbox($self->get_name(), $opt->[0],
defined($opt->[1]) ? $opt->[1] : $opt->[0],
$sel{$opt->[0]}, undef, $self->get_disabled()).
($num == 0 ? &ui_hidden("ui_exists_".$self->get_name(), 1) : "");
}
=head2 get_value()
Returns a hash ref of all selected values
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && (defined($in->{$self->{'name'}}) ||
defined($in->{"ui_exists_".$self->{'name'}}))) {
return [ split(/\0/, $in->{$self->{'name'}}) ];
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return [ split(/\0/, $in->{"ui_value_".$self->{'name'}}) ];
}
else {
return $self->{'value'};
}
}
sub set_options
{
my ($self, $options) = @_;
$self->{'options'} = $options;
}
sub get_options
{
my ($self) = @_;
return $self->{'options'};
}
=head2 validate()
Returns a list of error messages for this field
=cut
sub validate
{
my ($self) = @_;
my $value = $self->get_value();
if ($self->{'mandatory'} && !@$value) {
return ( $self->{'mandmesg'} || $text{'ui_checkmandatory'} );
}
return ( );
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
my @rv;
for(my $i=0; $i<@{$self->{'options'}}; $i++) {
push(@rv, $self->{'name'}."[".$i."]");
}
return @rv;
}
1;

82
Webmin/Columns.pm Normal file
View File

@@ -0,0 +1,82 @@
package Webmin::Columns;
use WebminCore;
=head2 new Webmin::Columns(cols)
Displays some page elements in a multi-column table
=cut
sub new
{
my ($self, $cols) = @_;
if (defined(&Webmin::Theme::Columns::new)) {
return new Webmin::Theme::Columns(@_[1..$#_]);
}
$self = { 'columns' => 2 };
bless($self);
$self->set_columns($cols) if (defined($cols));
return $self;
}
=head2 html()
Returns HTML for the objects, arranged in columns
=cut
sub html
{
my ($self) = @_;
my $rv;
my $n = scalar(@{$self->{'contents'}});
$rv .= "<table width=100% cellpadding=4><tr>\n";
my $h = int($n / $self->{'columns'})+1;
my $i = 0;
my $pc = int(100/$self->{'columns'});
foreach my $c (@{$self->{'contents'}}) {
if ($i%$h == 0) {
$rv .= "<td valign=top width=$pc%>";
}
$rv .= $c->html()."<p>\n";
$i++;
if ($i%$h == 0) {
$rv .= "</td>\n";
}
}
$rv .= "</tr></table>\n";
return $rv;
}
=head2 add(object)
Adds some Webmin:: object to this list
=cut
sub add
{
my ($self, $object) = @_;
push(@{$self->{'contents'}}, $object);
if ($self->{'page'}) {
$object->set_page($self->{'page'});
}
}
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub get_columns
{
my ($self) = @_;
return $self->{'columns'};
}
=head2 set_page(Webmin::Page)
Called when this menu is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
foreach my $c (@{$self->{'contents'}}) {
$c->set_page($page);
}
}
1;

47
Webmin/ConfirmPage.pm Normal file
View File

@@ -0,0 +1,47 @@
package Webmin::ConfirmPage;
use Webmin::Page;
use WebminCore;
@ISA = ( "Webmin::Page" );
=head2 new Webmin::ConfirmPage(subheading, title, message, cgi, &in, [ok-message],
[cancel-message], [help-name])
Create a new page object that asks if the user is sure if he wants to
do something or not.
=cut
sub new
{
if (defined(&Webmin::Theme::ConfirmPage::new)) {
return new Webmin::Theme::ConfirmPage(@_[1..$#_]);
}
my ($self, $subheading, $title, $message, $cgi, $in, $ok, $cancel, $help) = @_;
$self = new Webmin::Page($subheading, $title, $help);
$self->{'in'} = $in;
$self->add_message($message);
my $form = new Webmin::Form($cgi, "get");
$form->set_input($in);
$self->add_form($form);
foreach my $i (keys %$in) {
foreach my $v (split(/\0/, $in->{$i})) {
$form->add_hidden($i, $v);
}
}
$form->add_button(new Webmin::Submit($ok || "OK", "ui_confirm"));
$form->add_button(new Webmin::Submit($cancel || $text{'cancel'}, "ui_cancel"));
bless($self);
return $self;
}
sub get_confirm
{
my ($self) = @_;
return $self->{'in'}->{'ui_confirm'} ? 1 : 0;
}
sub get_cancel
{
my ($self) = @_;
return $self->{'in'}->{'ui_cancel'} ? 1 : 0;
}
1;

96
Webmin/Date.pm Normal file
View File

@@ -0,0 +1,96 @@
package Webmin::Date;
use Webmin::Input;
use Time::Local;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Date(name, time, [disabled])
Create a new field for selecting a date
=cut
sub new
{
if (defined(&Webmin::Theme::Date::new)) {
return new Webmin::Theme::Date(@_[1..$#_]);
}
my ($self, $name, $value, $disabled) = @_;
bless($self = { });
$self->set_name($name);
$self->set_value($value);
$self->set_disabled($disabled) if (defined($disabled));
return $self;
}
=head2 html()
Returns the HTML for the date chooser
=cut
sub html
{
my ($self) = @_;
my $rv;
my @tm = localtime($self->get_value());
my $name = $self->get_name();
$rv .= &ui_date_input($tm[3], $tm[4]+1, $tm[5]+1900,
"day_".$name, "month_".$name, "year_".$name,
$self->get_disabled())." ".
&date_chooser_button("day_".$name, "month_".$name, "year_".$name);
return $rv;
}
=head2 get_value()
Returns the date as a Unix time number (for zero o'clock)
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && defined($in->{"day_".$self->{'name'}})) {
my $rv = $self->to_time($in);
return defined($rv) ? $rv : $self->{'value'};
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return $in->{"ui_value_".$self->{'name'}};
}
else {
return $self->{'value'};
}
}
sub to_time
{
my ($self, $in) = @_;
my $day = $in->{"day_".$self->{'name'}};
return undef if ($day !~ /^\d+$/);
my $month = $in->{"month_".$self->{'name'}}-1;
my $year = $in->{"year_".$self->{'name'}}-1900;
return undef if ($year !~ /^\d+$/);
my $rv = eval { timelocal(0, 0, 0, $day, $month, $year) };
return $@ ? undef : $rv;
}
sub set_validation_func
{
my ($self, $func) = @_;
$self->{'validation_func'} = $func;
}
=head2 validate()
Ensures that the date is valid
=cut
sub validate
{
my ($self) = @_;
my $tm = $self->to_time($self->{'form'}->{'in'});
if (!defined($tm)) {
return ( $text{'ui_edate'} );
}
if ($self->{'validation_func'}) {
my $err = &{$self->{'validation_func'}}($self->get_value(),
$self->{'name'},
$self->{'form'});
return ( $err ) if ($err);
}
return ( );
}
1;

119
Webmin/DynamicBar.pm Normal file
View File

@@ -0,0 +1,119 @@
package Webmin::DynamicBar;
use WebminCore;
=head2 new Webmin::DynamicBar(&start-function, max)
A page element for displaying progress towards some goal, like the download of
a file.
=cut
sub new
{
my ($self, $func, $max) = @_;
$self = { 'func' => $func,
'name' => "dynamic".++$dynamic_count,
'width' => 80,
'max' => $max };
bless($self);
return $self;
}
=head2 set_message(text)
Sets the text describing what we are waiting for
=cut
sub set_message
{
my ($self, $message) = @_;
$self->{'message'} = $message;
}
sub get_message
{
my ($self) = @_;
return $self->{'message'};
}
=head2 html()
Returns the HTML for the text field
=cut
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_message()) {
$rv .= $self->get_message()."<p>\n";
}
$rv .= "<form name=form_$self->{'name'}>";
$rv .= "<input name=bar_$self->{'name'} size=$self->{'width'} disabled=true style='font-family: courier'>";
$rv .= "&nbsp;";
$rv .= "<input name=pc_$self->{'name'} size=3 disabled=true style='font-family: courier'>%";
$rv .= "</form>";
return $rv;
}
=head2 start()
Called by the page to begin the progress
=cut
sub start
{
my ($self) = @_;
&{$self->{'func'}}($self);
}
=head2 update(pos)
Called by the function to update the position of the bar.
=cut
sub update
{
my ($self, $pos) = @_;
my $pc = int(100*$pos/$self->{'max'});
if ($pc != $self->{'lastpc'}) {
my $xn = int($self->{'width'}*$pos/$self->{'max'});
my $xes = "X" x $xn;
print "<script>window.document.forms[\"form_$self->{'name'}\"].pc_$self->{'name'}.value = \"$pc\";</script>\n";
print "<script>window.document.forms[\"form_$self->{'name'}\"].bar_$self->{'name'}.value = \"$xes\";</script>\n";
$self->{'lastpc'} = $pc;
}
}
=head2 set_wait(wait)
If called with a non-zero arg, generation of the page should wait until this
the progress is complete. Otherwise, the page will be generated completely before
the start function is called
=cut
sub set_wait
{
my ($self, $wait) = @_;
$self->{'wait'} = $wait;
}
sub get_wait
{
my ($self) = @_;
return $self->{'wait'};
}
=head2 set_page(Webmin::Page)
Called when this dynamic text box is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
=head2 needs_unbuffered()
Must return 1 if the page needs to be in un-buffered and no-table mode
=cut
sub needs_unbuffered
{
return 0;
}
1;

76
Webmin/DynamicHTML.pm Normal file
View File

@@ -0,0 +1,76 @@
package Webmin::DynamicHTML;
use WebminCore;
=head2 new Webmin::DynamicHTML(&function, &args, [before])
When the page is being rendered, executes the given function and prints any
text that it returns.
=cut
sub new
{
my ($self, $func, $args, $before) = @_;
$self = { 'func' => $func,
'args' => $args,
'before' => $before };
bless($self);
return $self;
}
=head2 set_before(text)
Sets the text describing what we are waiting for
=cut
sub set_before
{
my ($self, $before) = @_;
$self->{'before'} = $before;
}
sub get_before
{
my ($self) = @_;
return $self->{'before'};
}
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_before()) {
$rv .= $self->get_before()."<p>\n";
}
return $rv;
}
=head2 start()
Called by the page to begin the dynamic output.
=cut
sub start
{
my ($self) = @_;
&{$self->{'func'}}($self, @$args);
}
sub get_wait
{
my ($self) = @_;
return 1;
}
=head2 needs_unbuffered()
Must return 1 if the page needs to be in un-buffered and no-table mode
=cut
sub needs_unbuffered
{
return 1;
}
=head2 set_page(Webmin::Page)
Called when this dynamic HTML element is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
1;

123
Webmin/DynamicText.pm Normal file
View File

@@ -0,0 +1,123 @@
# XXX should support non-Javascript mode?
package Webmin::DynamicText;
use WebminCore;
=head2 new Webmin::DynamicText(&start-function, &args)
A page element for displaying text that takes time to generate, such as from
a long-running script. Uses a non-editable text box, updated via Javascript.
The function will be called when it is time to start producing output, with this
object as a parameter. It must call the add_line function on the object for each
new line to be added.
=cut
sub new
{
my ($self, $func, $args) = @_;
$self = { 'func' => $func,
'args' => $args,
'name' => "dynamic".++$dynamic_count,
'rows' => 20,
'cols' => 80 };
bless($self);
return $self;
}
=head2 set_message(text)
Sets the text describing what we are waiting for
=cut
sub set_message
{
my ($self, $message) = @_;
$self->{'message'} = $message;
}
sub get_message
{
my ($self) = @_;
return $self->{'message'};
}
=head2 html()
Returns the HTML for the text box
=cut
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_message()) {
$rv .= $self->get_message()."<p>\n";
}
$rv .= "<form name=form_$self->{'name'}>";
$rv .= "<textarea name=$self->{'name'} rows=$self->{'rows'} cols=$self->{'cols'} wrap=off disabled=true>";
$rv .= "</textarea>\n";
$rv .= "</form>";
return $rv;
}
=head2 start()
Called by the page to begin the dynamic output.
=cut
sub start
{
my ($self) = @_;
&{$self->{'func'}}($self, @$args);
}
=head2 add_line(line)
Called by the function to add a line of text to this output
=cut
sub add_line
{
my ($self, $line) = @_;
$line =~ s/\r|\n//g;
$line = &quote_escape($line);
print "<script>window.document.forms[\"form_$self->{'name'}\"].$self->{'name'}.value += \"$line\"+\"\\n\";</script>\n";
}
=head2 set_wait(wait)
If called with a non-zero arg, generation of the page should wait until this
text box is complete. Otherwise, the page will be generated completely before the
start function is called
=cut
sub set_wait
{
my ($self, $wait) = @_;
$self->{'wait'} = $wait;
}
sub get_wait
{
my ($self) = @_;
return $self->{'wait'};
}
=head2 set_page(Webmin::Page)
Called when this dynamic text box is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
sub set_rows
{
my ($self, $rows) = @_;
$self->{'rows'} = $rows;
}
sub set_cols
{
my ($self, $cols) = @_;
$self->{'cols'} = $cols;
}
=head2 needs_unbuffered()
Must return 1 if the page needs to be in un-buffered and no-table mode
=cut
sub needs_unbuffered
{
return 0;
}
1;

129
Webmin/DynamicWait.pm Normal file
View File

@@ -0,0 +1,129 @@
package Webmin::DynamicWait;
use WebminCore;
=head2 new Webmin::DynamicWait(&start-function, [&args])
A page element indicating that something is happening.
=cut
sub new
{
my ($self, $func, $args) = @_;
$self = { 'func' => $func,
'args' => $args,
'name' => "dynamic".++$dynamic_count,
'width' => 80,
'delay' => 20 };
bless($self);
return $self;
}
=head2 set_message(text)
Sets the text describing what we are waiting for
=cut
sub set_message
{
my ($self, $message) = @_;
$self->{'message'} = $message;
}
sub get_message
{
my ($self) = @_;
return $self->{'message'};
}
=head2 html()
Returns the HTML for the text field used to indicate progress
=cut
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_message()) {
$rv .= $self->get_message()."<p>\n";
}
$rv .= "<form name=form_$self->{'name'}>";
$rv .= "<input name=$self->{'name'} size=$self->{'width'} disabled=true style='font-family: courier'>";
$rv .= "</form>";
return $rv;
}
=head2 start()
Called by the page to begin the progress. Also starts a process to update the
Javascript text box
=cut
sub start
{
my ($self) = @_;
$self->{'pid'} = fork();
if (!$self->{'pid'}) {
my $pos = 0;
while(1) {
select(undef, undef, undef, $self->{'delay'}/1000.0);
my $str = (" " x $pos) . ("x" x 10);
print "<script>window.document.forms[\"form_$self->{'name'}\"].$self->{'name'}.value = \"$str\";</script>\n";
$pos++;
$pos = 0 if ($pos == $self->{'width'});
}
exit;
}
&{$self->{'func'}}($self, @{$self->{'args'}});
}
=head2 stop()
Called back by the function when whatever we were waiting for is done
=cut
sub stop
{
my ($self) = @_;
if ($self->{'pid'}) {
kill('TERM', $self->{'pid'});
}
my $str = (" " x ($self->{'width'}/2 - 2)) . "DONE";
print "<script>window.document.forms[\"form_$self->{'name'}\"].$self->{'name'}.value = \"$str\";</script>\n";
}
=head2 set_wait(wait)
If called with a non-zero arg, generation of the page should wait until this
the progress is complete. Otherwise, the page will be generated completely before
the start function is called
=cut
sub set_wait
{
my ($self, $wait) = @_;
$self->{'wait'} = $wait;
}
sub get_wait
{
my ($self) = @_;
return $self->{'wait'};
}
=head2 set_page(Webmin::Page)
Called when this dynamic text box is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
=head2 needs_unbuffered()
Must return 1 if the page needs to be in un-buffered and no-table mode
=cut
sub needs_unbuffered
{
return 0;
}
1;

20
Webmin/ErrorPage.pm Normal file
View File

@@ -0,0 +1,20 @@
package Webmin::ErrorPage;
use WebminCore;
=head2 new Webmin::ErrorPage(subheading, title, message, [program-output], [help-name])
Create a new page object for showing an error of some kind
=cut
sub new
{
if (defined(&Webmin::Theme::ErrorPage::new)) {
return new Webmin::Theme::ErrorPage(@_[1..$#_]);
}
my ($self, $subheading, $title, $message, $output, $help) = @_;
$self = new Webmin::Page($subheading, $title, $help);
$self->add_message("<b>",$text{'error'}," : ",$message,"</b>");
$self->add_message("<pre>",$output,"</pre>");
return $self;
}
1;

70
Webmin/File.pm Normal file
View File

@@ -0,0 +1,70 @@
package Webmin::File;
use Webmin::Textbox;
use WebminCore;
@ISA = ( "Webmin::Textbox" );
=head2 new Webmin::File(name, value, size, [directory], [disabled])
A text box for selecting a file
=cut
sub new
{
if (defined(&Webmin::Theme::File::new)) {
return new Webmin::Theme::File(@_[1..$#_]);
}
my ($self, $name, $value, $size, $directory, $disabled) = @_;
$self = new Webmin::Textbox($name, $value, $size, $disabled);
bless($self);
$self->set_directory($directory);
return $self;
}
=head2 html()
Returns the HTML for this file input
=cut
sub html
{
my ($self) = @_;
my $rv = Webmin::Textbox::html($self);
my $name = $self->get_name();
my $directory = $self->get_directory();
my $add = 0;
my $chroot = $self->get_chroot();
$rv .= "<input type=button name=${name}_button onClick='ifield = form.$name; chooser = window.open(\"$gconfig{'webprefix'}/chooser.cgi?add=$add&type=$directory&chroot=$chroot&file=\"+escape(ifield.value), \"chooser\", \"toolbar=no,menubar=no,scrollbar=no,width=400,height=300\"); chooser.ifield = ifield; window.ifield = ifield' value=\"...\">\n";
return $rv;
}
sub set_directory
{
my ($self, $directory) = @_;
$self->{'directory'} = $directory;
}
sub get_directory
{
my ($self) = @_;
return $self->{'directory'};
}
sub set_chroot
{
my ($self, $chroot) = @_;
$self->{'chroot'} = $chroot;
}
sub get_chroot
{
my ($self) = @_;
return $self->{'chroot'};
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'}, $self->{'name'}."_button" );
}
1;

405
Webmin/Form.pm Normal file
View File

@@ -0,0 +1,405 @@
package Webmin::Form;
use WebminCore;
=head2 new Webmin::Form(cgi, [method])
Creates a new form, which submits to the given CGI
=cut
sub new
{
if (defined(&Webmin::Theme::Form::new)) {
return new Webmin::Theme::Form(@_[1..$#_]);
}
my ($self, $program, $method) = @_;
$self = { 'method' => 'get',
'name' => "form".++$form_count };
bless($self);
$self->set_program($program);
$self->set_method($method) if ($method);
return $self;
}
=head2 html()
Returns the HTML that makes up this form
=cut
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_align()) {
$rv .= "<div align=".$self->get_align().">\n";
}
$rv .= $self->form_start();
if ($self->get_heading()) {
if (defined(&ui_subheading)) {
$rv .= &ui_subheading($self->get_heading());
}
else {
$rv .= "<h3>".$self->get_heading()."</h3>\n";
}
}
# Add the sections
foreach my $h (@{$self->{'hiddens'}}) {
$rv .= &ui_hidden($h->[0], $h->[1])."\n";
}
foreach my $s (@{$self->{'sections'}}) {
$rv .= $s->html();
}
# Check if we have any inputs that need disabling
my @dis = $self->list_disable_inputs();
if (@dis) {
# Yes .. generate a function for them
$rv .= "<script>\n";
$rv .= "function ui_disable_".$self->{'name'}."(form) {\n";
foreach my $i (@dis) {
foreach my $n ($i->get_input_names()) {
$rv .= " form.".$n.".disabled = (".
$i->get_disable_code().");\n";
}
}
$rv .= "}\n";
$rv .= "</script>\n";
}
# Add the buttons at the end of the form
my @buttonargs;
foreach my $b (@{$self->{'buttons'}}) {
if (ref($b)) {
# An array of inputs
my $ihtml = join(" ", map { $_->html() } @$b);
push(@buttonargs, $ihtml);
}
else {
# A spacer
push(@buttonargs, "");
}
}
$rv .= &ui_form_end(\@buttonargs);
if ($self->get_align()) {
$rv .= "</div>\n";
}
# Call the Javascript disable function
if (@dis) {
$rv .= "<script>\n";
$rv .= "ui_disable_".$self->{'name'}."(window.document.forms[\"$self->{'name'}\"]);\n";
$rv .= "</script>\n";
}
return $rv;
}
sub form_start
{
my ($self) = @_;
return "<form action='$self->{'program'}' ".
($self->{'method'} eq "post" ? "method=post" :
$self->{'method'} eq "form-data" ?
"method=post enctype=multipart/form-data" :
"method=get")." name=$self->{'name'}>\n";
}
=head2 add_section(section)
Adds a Webmin::Section object to this form
=cut
sub add_section
{
my ($self, $section) = @_;
push(@{$self->{'sections'}}, $section);
$section->set_form($self);
}
=head2 get_section(idx)
=cut
sub get_section
{
my ($self, $idx) = @_;
return $self->{'sections'}->[$idx];
}
=head2 add_button(button, [beside, ...])
Adds a Webmin::Submit object to this form, for display at the bottom
=cut
sub add_button
{
my ($self, $button, @beside) = @_;
push(@{$self->{'buttons'}}, [ $button, @beside ]);
}
=head2 add_button_spacer()
Adds a gap between buttons, for grouping
=cut
sub add_button_spacer
{
my ($self, $spacer) = @_;
push(@{$self->{'buttons'}}, $spacer);
}
=head2 add_hidden(name, value)
Adds some hidden input to this form, for passing to the CGI
=cut
sub add_hidden
{
my ($self, $name, $value) = @_;
push(@{$self->{'hiddens'}}, [ $name, $value ]);
}
=head2 validate()
Validates all form inputs, based on the current CGI input hash. Returns a list
of errors, each of which is field name and error message.
=cut
sub validate
{
my ($self) = @_;
my @errs;
foreach my $s (@{$self->{'sections'}}) {
push(@errs, $s->validate($self->{'in'}));
}
return @errs;
}
=head2 validate_redirect(page, [&extra-errors])
Validates the form, and if any errors are found re-directs to the given page
with the errors, so that they can be displayed.
=cut
sub validate_redirect
{
my ($self, $page, $extras) = @_;
if ($self->{'in'}->{'ui_redirecting'}) {
# If this page is displayed as part of a redirect, no need to validate!
return;
}
my @errs = $self->validate();
push(@errs, @$extras);
if (@errs) {
my (@errlist, @vallist);
foreach my $e (@errs) {
push(@errlist, &urlize("ui_error_".$e->[0])."=".
&urlize($e->[1]));
}
foreach my $i ($self->list_inputs()) {
my $v = $i->get_value();
my @vals = ref($v) ? @$v : ( $v );
@vals = ( undef ) if (!@vals);
foreach $v (@vals) {
push(@vallist,
&urlize("ui_value_".$i->get_name())."=".
&urlize($v));
}
}
foreach my $h (@{$self->{'hiddens'}}) {
push(@vallist,
&urlize($h->[0])."=".&urlize($h->[1]));
}
if ($page =~ /\?/) { $page .= "&"; }
else { $page .= "?"; }
&redirect($page.join("&", "ui_redirecting=1", @errlist, @vallist));
exit(0);
}
}
=head2 validate_error(whatfailed)
Validates the form, and if any errors are found displays an error page.
=cut
sub validate_error
{
my ($self, $whatfailed) = @_;
my @errs = $self->validate();
&error_setup($whatfailed);
if (@errs == 1) {
&error($errs[0]->[2] ? "$errs[0]->[2] : $errs[0]->[1]"
: $errs[0]->[1]);
}
elsif (@errs > 1) {
my $msg = $text{'ui_errors'}."<br>";
foreach my $e (@errs) {
$msg .= $e->[2] ? "$e->[2] : $e->[1]<br>\n"
: "$e->[1]<br>\n";
}
&error($msg);
}
}
=head2 field_errors(name)
Returns a list of error messages associated with the field of some name, from
the input passed to set_input
=cut
sub field_errors
{
my ($self, $name) = @_;
my @errs;
my $in = $self->{'in'};
foreach my $i (keys %$in) {
if ($i eq "ui_error_".$name) {
push(@errs, split(/\0/, $in->{$i}));
}
}
return @errs;
}
=head2 set_input(&input)
Passes the form input hash to this form object, for use by the validate
functions and for displaying errors next to fields.
=cut
sub set_input
{
my ($self, $in) = @_;
$self->{'in'} = $in;
}
=head2 get_value(input-name)
Returns the value of the input with the given name.
=cut
sub get_value
{
my ($self, $name) = @_;
foreach my $s (@{$self->{'sections'}}) {
my $rv = $s->get_value($name);
return $rv if (defined($rv));
}
return $self->{'in'}->{$name};
}
=head2 get_input(name)
Returns the input with the given name
=cut
sub get_input
{
my ($self, $name) = @_;
foreach my $i ($self->list_inputs()) {
return $i if ($i->get_name() eq $name);
}
return undef;
}
sub set_program
{
my ($self, $program) = @_;
$self->{'program'} = $program;
}
sub set_method
{
my ($self, $method) = @_;
$self->{'method'} = $method;
}
=head2 list_inputs()
Returns all inputs in all form sections
=cut
sub list_inputs
{
my ($self) = @_;
my @rv;
foreach my $s (@{$self->{'sections'}}) {
push(@rv, $s->list_inputs());
}
return @rv;
}
=head2 list_disable_inputs()
Returns a list of inputs that have disable functions
=cut
sub list_disable_inputs
{
my ($self) = @_;
my @dis;
foreach my $i ($self->list_inputs()) {
push(@dis, $i) if ($i->get_disable_code());
}
return @dis;
}
=head2 set_page(Webmin::Page)
Called when this form is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
=head2 get_changefunc(&input)
Called by some input, to return the Javascript that should be called when this
input changes it's value.
=cut
sub get_changefunc
{
my ($self, $input) = @_;
my @dis = $self->list_disable_inputs();
if (@dis) {
return "ui_disable_".$self->{'name'}."(form)";
}
return undef;
}
=head2 set_heading(text)
Sets the heading to be displayed above the form
=cut
sub set_heading
{
my ($self, $heading) = @_;
$self->{'heading'} = $heading;
}
sub get_heading
{
my ($self) = @_;
return $self->{'heading'};
}
=head2 get_formno()
Returns the index of this form on the page
=cut
sub get_formno
{
my ($self) = @_;
my $n = 0;
foreach my $f (@{$self->{'page'}->{'contents'}}) {
if ($f eq $self) {
return $n;
}
elsif (ref($f) =~ /Form/) {
$n++;
}
}
return undef;
}
=head2 add_onload(code)
Adds some Javascript code for inclusion in the onLoad tag
=cut
sub add_onload
{
my ($self, $code) = @_;
push(@{$self->{'onloads'}}, $code);
}
=head2 add_script(code)
Adds some Javascript code for putting in the <head> section
=cut
sub add_script
{
my ($self, $script) = @_;
push(@{$self->{'scripts'}}, $script);
}
=head2 set_align(align)
Sets the alignment on the page (left, center, right)
=cut
sub set_align
{
my ($self, $align) = @_;
$self->{'align'} = $align;
}
sub get_align
{
my ($self) = @_;
return $self->{'align'};
}
1;

57
Webmin/Group.pm Normal file
View File

@@ -0,0 +1,57 @@
package Webmin::Group;
use Webmin::Textbox;
use WebminCore;
@ISA = ( "Webmin::Textbox" );
=head2 new Webmin::Group(name, value, [multiple], [disabled])
A text box for entering or selecting one or many Unix groupnames
=cut
sub new
{
if (defined(&Webmin::Theme::Group::new)) {
return new Webmin::Theme::Group(@_[1..$#_]);
}
my ($self, $name, $value, $multiple, $disabled) = @_;
$self = new Webmin::Textbox($name, $value, $multiple ? 40 : 15, $disabled);
bless($self);
$self->set_multiple($multiple);
return $self;
}
=head2 html()
Returns the HTML for this group input
=cut
sub html
{
my ($self) = @_;
my $rv = Webmin::Textbox::html($self);
my $name = $self->get_name();
my $multiple = $self->get_multiple();
local $w = $multiple ? 500 : 300;
$rv .= "&nbsp;<input type=button name=${name}_button onClick='ifield = form.$name; chooser = window.open(\"$gconfig{'webprefix'}/group_chooser.cgi?multi=$multiple&group=\"+escape(ifield.value), \"chooser\", \"toolbar=no,menubar=no,scrollbars=yes,width=$w,height=200\"); chooser.ifield = ifield; window.ifield = ifield' value=\"...\">\n";
return $rv;
}
sub set_multiple
{
my ($self, $multiple) = @_;
$self->{'multiple'} = $multiple;
}
sub get_multiple
{
my ($self) = @_;
return $self->{'multiple'};
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'}, $self->{'name'}."_button" );
}
1;

64
Webmin/Icon.pm Normal file
View File

@@ -0,0 +1,64 @@
package Webmin::Icon;
use WebminCore;
=head2 Webmin::Icon(type, [message])
This object generates an icon indicating some status. Possible types are :
ok - OK
critial - A serious problem
major - A relatively serious problem
minor - A small problem
Can be used inside tables and property lists
=cut
sub new
{
if (defined(&Webmin::Theme::Icon::new) && caller() !~ /Webmin::Theme::Icon/) {
return new Webmin::Theme::Icon(@_[1..$#_]);
}
my ($self, $type, $message) = @_;
$self = { };
bless($self);
$self->set_type($type);
$self->set_message($message) if (defined($message));
return $self;
}
=head2 html()
Returns HTML for the icon
=cut
sub html
{
my ($self) = @_;
my $rv;
$rv .= "<img src=/images/".$self->get_type().".gif align=middle>";
if ($self->get_message()) {
$rv .= "&nbsp;".$self->get_message();
}
return $rv;
}
sub set_type
{
my ($self, $type) = @_;
$self->{'type'} = $type;
}
sub get_type
{
my ($self) = @_;
return $self->{'type'};
}
sub set_message
{
my ($self, $message) = @_;
$self->{'message'} = $message;
}
sub get_message
{
my ($self) = @_;
return $self->{'message'};
}
1;

134
Webmin/Input.pm Normal file
View File

@@ -0,0 +1,134 @@
package Webmin::Input;
use WebminCore;
sub set_form
{
my ($self, $form) = @_;
$self->{'form'} = $form;
}
sub set_name
{
my ($self, $name) = @_;
$self->{'name'} = $name;
}
sub get_name
{
my ($self) = @_;
return $self->{'name'};
}
sub set_disabled
{
my ($self, $disabled) = @_;
$self->{'disabled'} = $disabled;
}
sub get_disabled
{
my ($self) = @_;
return $self->{'disabled'};
}
=head2 validate()
No validation is done by default
=cut
sub validate
{
return ( );
}
sub set_value
{
my ($self, $value) = @_;
$self->{'value'} = $value;
}
=head2 get_value()
Returns the current value for this field as entered by the user, the value
set when the form is re-displayed due to an error, or the initial value.
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && (defined($in->{$self->{'name'}}) ||
defined($in->{"ui_exists_".$self->{'name'}}))) {
return $in->{$self->{'name'}};
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return $in->{"ui_value_".$self->{'name'}};
}
else {
return $self->{'value'};
}
}
=head2 set_disable_code(javascript)
Must be provided with a Javascript expression that will return true when this
input should be disabled. May refer to other fields, via the variable 'form'.
ie. form.mode.value = "0"
Will be called every time any field's value changes.
=cut
sub set_disable_code
{
my ($self, $code) = @_;
$self->{'disablecode'} = $code;
}
sub get_disable_code
{
my ($self) = @_;
return $self->{'disablecode'};
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'} );
}
=head2 set_label(text)
Sets HTML to be displayed before this field
=cut
sub set_label
{
my ($self, $label) = @_;
$self->{'label'} = $label;
}
sub get_label
{
my ($self) = @_;
return $self->{'label'};
}
sub set_mandatory
{
my ($self, $mandatory, $mandmesg) = @_;
$self->{'mandatory'} = $mandatory;
$self->{'mandmesg'} = $mandmesg if (defined($mandmesg));
}
sub get_mandatory
{
my ($self) = @_;
return $self->{'mandatory'};
}
=head2 get_errors()
Returns a list of errors associated with this field
=cut
sub get_errors
{
my ($self) = @_;
return $self->{'form'} ? $self->{'form'}->field_errors($self->get_name())
: ( );
}
1;

137
Webmin/InputTable.pm Normal file
View File

@@ -0,0 +1,137 @@
package Webmin::InputTable;
use Webmin::Table;
use WebminCore;
@ISA = ( "Webmin::Table" );
=head2 new Webmin::InputTable(&headings, [width], [name], [heading])
A table containing multiple rows of inputs, each of which is the same
=cut
sub new
{
if (defined(&Webmin::Theme::InputTable::new) &&
caller() !~ /Webmin::Theme::InputTable/) {
return new Webmin::Theme::InputTable(@_[1..$#_]);
}
my $self = defined(&Webmin::Theme::Table::new) ? Webmin::Theme::Table::new(@_)
: Webmin::Table::new(@_);
bless($self);
$self->{'rowcount'} = 0;
return $self;
}
=head2 set_inputs(&inputs)
Sets the objects to be used for each row
=cut
sub set_inputs
{
my ($self, $classes) = @_;
$self->{'classes'} = $classes;
}
=head2 add_values(&values)
Adds a row of inputs, with the given values
=cut
sub add_values
{
my ($self, $values) = @_;
my @row;
for(my $i=0; $i<@$values; $i++) {
my $cls = $self->{'classes'}->[$i];
my $newin = { %$cls };
bless($newin, ref($cls));
$newin->set_value($values->[$i]);
$newin->set_name($newin->get_name()."_".$self->{'rowcount'});
$newin->set_form($self->{'form'}) if ($self->{'form'});
push(@row, $newin);
}
$self->add_row(\@row);
$self->{'rowcount'}++;
}
=head2 get_values(row)
Returns the values of the inputs in the given row
=cut
sub get_values
{
my ($self, $row) = @_;
my @rv;
foreach my $i (@{$self->{'rows'}->[$row]}) {
if (ref($i) && $i->isa("Webmin::Input")) {
push(@rv, $i->get_value());
}
}
return @rv;
}
=head2 list_inputs()
=cut
sub list_inputs
{
my ($self) = @_;
my @rv = Webmin::Table::list_inputs($self);
foreach my $r (@{$self->{'rows'}}) {
foreach my $i (@$r) {
if ($i && ref($i) && $i->isa("Webmin::Input")) {
push(@rv, $i);
}
}
}
return @rv;
}
sub get_rowcount
{
my ($self) = @_;
return $self->{'rowcount'};
}
=head2 validate()
Validates all inputs, and returns a list of error messages
=cut
sub validate
{
my ($self) = @_;
my $seli = $self->{'selectinput'};
my @errs;
if ($seli) {
push(@errs, map { [ $seli->get_name(), $_ ] } $seli->validate());
}
foreach my $i (@{$self->{'inputs'}}) {
foreach my $e ($i->validate()) {
push(@errs, [ $i->get_name(), $e ]);
}
}
my $k = 1;
foreach my $r (@{$self->{'rows'}}) {
my $j = 0;
my $skip;
if (defined($self->{'control'})) {
if ($r->[$self->{'control'}]->get_value() eq "") {
$skip = 1;
}
}
foreach my $i (@$r) {
if ($i && ref($i) && $i->isa("Webmin::Input") && !$skip) {
my $label = &text('ui_rowlabel', $k, $self->{'headings'}->[$j]);
foreach my $e ($i->validate()) {
push(@errs, [ $i->get_name(), $label." ".$e ]);
}
}
$j++;
}
$k++;
}
return @errs;
}
=head2 set_control(column)
Sets the column for which an empty value means no validation should be done
=cut
sub set_control
{
my ($self, $control) = @_;
$self->{'control'} = $control;
}
1;

View File

@@ -0,0 +1,47 @@
package Webmin::JavascriptButton;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::JavascriptButton(label, script, [disabled])
Create a button that runs some Javascript when clicked
=cut
sub new
{
if (defined(&Webmin::Theme::JavascriptButton::new) &&
caller() !~ /Webmin::Theme::JavascriptButton/) {
return new Webmin::Theme::JavascriptButton(@_[1..$#_]);
}
my ($self, $value, $script, $disabled) = @_;
$self = { };
bless($self);
$self->set_value($value);
$self->set_script($script);
$self->set_disabled($disabled) if ($disabled);
return $self;
}
=head2 html()
Returns the HTML for this text input
=cut
sub html
{
my ($self) = @_;
return "<input type=button value=\"".&quote_escape($self->get_value())."\" ".
"onClick=\"".$self->get_script()."\">";
}
sub set_script
{
my ($self, $script) = @_;
$self->{'script'} = $script;
}
sub get_script
{
my ($self) = @_;
return $self->{'script'};
}
1;

314
Webmin/LinkTable.pm Normal file
View File

@@ -0,0 +1,314 @@
package Webmin::LinkTable;
use Webmin::Table;
use WebminCore;
=head2 new Webmin::LinkTable(heading, [columns], [width], [name])
Creates a new table that just displays links, like in the Users and Groups module
=cut
sub new
{
if (defined(&Webmin::Theme::LinkTable::new) &&
caller() !~ /Webmin::Theme::LinkTable/) {
return new Webmin::Theme::LinkTable(@_[1..$#_]);
}
my ($self, $heading, $columns, $width, $name) = @_;
$self = { 'sorter' => \&Webmin::Table::default_sorter,
'columns' => 4,
'sortable' => 1 };
bless($self);
$self->set_heading($heading);
$self->set_name($name) if (defined($name));
$self->set_width($width) if (defined($width));
$self->set_columns($columns) if (defined($columns));
return $self;
}
=head2 add_entry(name, link)
Adds one item to appear in the table
=cut
sub add_entry
{
my ($self, $name, $link) = @_;
push(@{$self->{'entries'}}, [ $name, $link ]);
}
=head2 html()
Returns the HTML for this table.
=cut
sub html
{
my ($self) = @_;
# Prepare the selector
my @srows = @{$self->{'entries'}};
my %selmap;
if (defined($self->{'selectinput'})) {
my $i = 0;
foreach my $r (@srows) {
$selmap{$r} = $self->{'selectinput'}->one_html($i);
$i++;
}
}
# Sort the entries
my $sortdir = $self->get_sortdir();
if (defined($sortdir)) {
my $func = $self->{'sorter'};
@srows = sort { my $so = &$func($a->[0], $b->[0]);
$sortdir ? -$so : $so } @srows;
}
# Build the sorter
my $head;
my $thisurl = $self->{'form'}->{'page'}->get_myurl();
$thisurl .= $thisurl =~ /\?/ ? "&" : "?";
my $name = $self->get_name();
if ($self->get_sortable()) {
$head = "<table cellpadding=0 cellspacing=0 width=100%><tr>";
$head .= "<td><b>".$self->get_heading()."</b></td> <td align=right>";
if (!defined($sortdir)) {
# Not sorting .. show grey button
$head .= "<a href='${thisurl}ui_sortdir_${name}=0'>".
"<img src=/images/nosort.gif border=0></a>";
}
else {
# Sorting .. show button to switch mode
my $notsort = !$sortdir;
$head .= "<a href='${thisurl}ui_sortdir_${name}=$notsort'>".
"<img src=/images/sort.gif border=0></a>";
}
$head .= "</td></tr></table>";
}
else {
$head = $self->get_heading();
}
# Find any errors
my $rv;
if ($self->{'selectinput'}) {
# Get any errors for inputs
my @errs = $self->{'form'}->field_errors(
$self->{'selectinput'}->get_name());
if (@errs) {
foreach my $e (@errs) {
$rv .= "<font color=#ff0000>$e</font><br>\n";
}
}
}
# Create the actual table
$rv .= &ui_table_start($head,
defined($self->{'width'}) ? "width=$self->{'width'}"
: undef, 1);
$rv .= "<td colspan=2><table width=100%>";
my $i = 0;
my $cols = $self->get_columns();
my $pc = 100/$cols;
foreach my $r (@srows) {
$rv .= "<tr>\n" if ($i%$cols == 0);
$rv .= "<td width=$pc%>".$selmap{$r}."<a href='$r->[1]'>".
&html_escape($r->[0])."</a></td>\n";
$rv .= "<tr>\n" if ($i%$cols == $cols-1);
$i++;
}
if ($i%$cols) {
# Finish off row
while($i++%$cols != $cols-1) {
$rv .= "<td width=$pc%></td>\n";
}
$rv .= "</tr>\n";
}
$rv .= "</table></td>";
$rv .= &ui_table_end();
return $rv;
}
=head2 set_heading(text)
Sets the heading text to appear above the table
=cut
sub set_heading
{
my ($self, $heading) = @_;
$self->{'heading'} = $heading;
}
sub get_heading
{
my ($self) = @_;
return $self->{'heading'};
}
sub set_name
{
my ($self, $name) = @_;
$self->{'name'} = $name;
}
=head2 get_name()
Returns the name for indentifying this table in HTML
=cut
sub get_name
{
my ($self) = @_;
if (defined($self->{'name'})) {
return $self->{'name'};
}
elsif ($self->{'form'}) {
my $secs = $self->{'form'}->{'sections'};
for(my $i=0; $i<@$secs; $i++) {
return "table".$i if ($secs->[$i] eq $self);
}
}
return "table";
}
=head2 set_sorter(function)
Sets a function used for sorting fields. Will be called with two values to compare
=cut
sub set_sorter
{
my ($self, $func) = @_;
$self->{'sorter'} = $func;
}
=head2 default_sorter(value1, value2)
=cut
sub default_sorter
{
my ($value1, $value2, $col) = @_;
return lc($value1) cmp lc($value2);
}
=head2 set_sortable(sortable?)
Tells the table if sorting is allowed or not. By default, it is.
=cut
sub set_sortable
{
my ($self, $sortable) = @_;
$self->{'sortable'} = $sortable;
}
sub get_sortable
{
my ($self) = @_;
return $self->{'sortable'};
}
=head2 get_sortdir()
Returns the order to sort in (1 for descending)
=cut
sub get_sortdir
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
my $name = $self->get_name();
if ($in && defined($in->{"ui_sortdir_".$name})) {
return ( $in->{"ui_sortdir_".$name} );
}
else {
return ( $self->{'sortdir'} );
}
}
=head2 set_sortdir(descending?)
Sets the default sort direction, unless overridden by the user.
=cut
sub set_sortcolumn
{
my ($self, $desc) = @_;
$self->{'sortdir'} = $desc;
}
=head2 set_width([number|number%])
Sets the width of this entire table. Can be called with 100%, 500 or undef to use
the minimum possible width.
=cut
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
=head2 set_columns(cols)
Sets the number of columns to display
=cut
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub get_columns
{
my ($self) = @_;
return $self->{'columns'};
}
=head2 set_form(form)
Called by the Webmin::Form object when this table is added to it
=cut
sub set_form
{
my ($self, $form) = @_;
$self->{'form'} = $form;
if ($self->{'selectinput'}) {
$self->{'selectinput'}->set_form($form);
}
}
=head2 set_selector(input)
Takes a Webmin::Checkboxes or Webmin::Radios object, and uses it to add checkboxes
to all the entries
=cut
sub set_selector
{
my ($self, $input) = @_;
$self->{'selectinput'} = $input;
$input->set_form($form);
}
=head2 get_selector()
Returns the UI element used for selecting rows
=cut
sub get_selector
{
my ($self) = @_;
return $self->{'selectinput'};
}
=head2 validate()
Validates the selector input
=cut
sub validate
{
my ($self) = @_;
my $seli = $self->{'selectinput'};
if ($seli) {
return map { [ $seli->get_name(), $_ ] } $seli->validate();
}
return ( );
}
=head2 get_value(input-name)
Returns the value of the input with the given name.
=cut
sub get_value
{
my ($self, $name) = @_;
if ($self->{'selectinput'} && $self->{'selectinput'}->get_name() eq $name) {
return $self->{'selectinput'}->get_value();
}
return undef;
}
=head2 list_inputs()
Returns all inputs in all form sections
=cut
sub list_inputs
{
my ($self) = @_;
return $self->{'selectinput'} ? ( $self->{'selectinput'} ) : ( );
}
1;

86
Webmin/Menu.pm Normal file
View File

@@ -0,0 +1,86 @@
package Webmin::Menu;
use WebminCore;
=head2 new Webmin::Menu(&options, [columns])
Generates a menu of options, typically using icons.
=cut
sub new
{
my ($self, $options, $columns) = @_;
if (defined(&Webmin::Theme::Menu::new)) {
return new Webmin::Theme::Menu(@_[1..$#_]);
}
$self = { 'columns' => 4 };
bless($self);
$self->set_options($options);
$self->set_columns($columns) if (defined($columns));
return $self;
}
=head2 html()
Returns the HTML for the table
=cut
sub html
{
my ($self) = @_;
my (@links, @titles, @icons, @hrefs);
foreach my $o (@{$self->{'options'}}) {
push(@links, $o->{'link'});
if ($o->{'link2'}) {
push(@titles, "$o->{'title'}</a> <a href='$o->{'link2'}'>$o->{'title2'}");
}
else {
push(@titles, $o->{'title'});
}
push(@icons, $o->{'icon'});
push(@hrefs, $o->{'href'});
}
my $rv = &capture_function_output(\&icons_table,
\@links, \@titles, \@icons, $self->get_columns(),
\@hrefs);
return $rv;
}
=head2 add_option(&option)
=cut
sub add_option
{
my ($self, $option) = @_;
push(@{$self->{'options'}}, $option);
}
sub set_options
{
my ($self, $options) = @_;
$self->{'options'} = $options;
}
sub get_options
{
my ($self) = @_;
return $self->{'options'};
}
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub get_columns
{
my ($self) = @_;
return $self->{'columns'};
}
=head2 set_page(Webmin::Page)
Called when this menu is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
1;

40
Webmin/Multiline.pm Normal file
View File

@@ -0,0 +1,40 @@
package Webmin::Multiline;
use Webmin::Textarea;
use WebminCore;
@ISA = ( "Webmin::Textarea" );
=head2 new Webmin::Multiline(name, &lines, rows, cols, [disabled])
Create a new input for entering multiple text entries. By default, just uses
a textbox
=cut
sub new
{
if (defined(&Webmin::Theme::Multiline::new)) {
return new Webmin::Theme::Multiline(@_[1..$#_]);
}
my ($self, $name, $lines, $rows, $cols, $wrap, $disabled) = @_;
$self = new Webmin::Textarea($name, join("\n", @$lines), $rows, $cols, undef, $disabled);
bless($self);
return $self;
}
=head2 set_lines(&lines)
Sets the lines to display
=cut
sub set_lines
{
my ($self, $lines) = @_;
$self->set_value(join("\n", @$lines));
}
=head2 get_lines()
Returns an array ref of lines to display
=cut
sub get_lines
{
my ($self) = @_;
return [ split(/[\r|\n]+/, $self->get_value()) ];
}
1;

120
Webmin/OptTextarea.pm Normal file
View File

@@ -0,0 +1,120 @@
package Webmin::OptTextarea;
use Webmin::Textarea;
use WebminCore;
@ISA = ( "Webmin::Textarea" );
=head2 new Webmin::OptTextarea(name, value, rows, cols, [default-msg], [other-msg])
Create a text area whose value is optional.
=cut
sub new
{
if (defined(&Webmin::Theme::OptTextarea::new)) {
return new Webmin::Theme::OptTextarea(@_[1..$#_]);
}
my ($self, $name, $value, $rows, $cols, $default, $other) = @_;
$self = new Webmin::Textarea($name, $value, $rows, $cols);
bless($self);
$self->set_default($default || $text{'default'});
$self->set_other($other) if ($other);
return $self;
}
=head2 html()
Returns the HTML for this optional text input
=cut
sub html
{
my ($self) = @_;
my $rv;
my $name = $self->get_name();
my $value = $self->get_value();
my $dis = $self->get_disabled();
my $rows = $self->get_rows();
my $columns = $self->get_cols();
my $dis1 = &js_disable_inputs([ $name ], [ ]);
my $dis2 = &js_disable_inputs([ ], [ $name ]);
my $opt1 = $self->get_default();
my $opt2 = $self->get_other();
$rv .= "<input type=radio name=\"".&quote_escape($name."_def")."\" ".
"value=1 ".($value ne '' ? "" : "checked").
($dis ? " disabled=true" : "")." onClick='$dis1'> ".$opt1."\n";
$rv .= "<input type=radio name=\"".&quote_escape($name."_def")."\" ".
"value=0 ".($value ne '' ? "checked" : "").
($dis ? " disabled=true" : "")." onClick='$dis2'> ".$opt2."<br>\n";
$rv .= "<textarea name=\"".&quote_escape($name)."\" ".
($value eq "" || $dis ? " disabled=true" : "").
"rows=$rows columns=$columns>".&html_escape($value)."</textarea>\n";
return $rv;
}
=head2 validate(&inputs)
=cut
sub validate
{
my ($self, $in) = @_;
if (defined($self->get_value())) {
if ($self->get_value() eq "") {
return ( $text{'ui_nothing'} );
}
return Webmin::Textbox::validate($self);
}
return ( );
}
sub set_default
{
my ($self, $default) = @_;
$self->{'default'} = $default;
}
sub get_default
{
my ($self) = @_;
return $self->{'default'};
}
sub set_other
{
my ($self, $other) = @_;
$self->{'other'} = $other;
}
sub get_other
{
my ($self) = @_;
return $self->{'other'};
}
=head2 get_value()
Returns the specified initial value for this field, or the value set when the
form is re-displayed due to an error.
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && (defined($in->{$self->{'name'}}) ||
defined($in->{$self->{'name'}.'_def'}))) {
return $in->{$self->{'name'}.'_def'} ? undef : $in->{$self->{'name'}};
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return $in->{"ui_value_".$self->{'name'}};
}
else {
return $self->{'value'};
}
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'}, $self->{'name'}."_def[0]",
$self->{'name'}."_def[1]" );
}
1;

90
Webmin/OptTextbox.pm Normal file
View File

@@ -0,0 +1,90 @@
package Webmin::OptTextbox;
use Webmin::Textbox;
use WebminCore;
@ISA = ( "Webmin::Textbox" );
=head2 new Webmin::OptTextbox(name, value, size, [default-msg], [other-msg])
Create a text field whose value is optional.
=cut
sub new
{
if (defined(&Webmin::Theme::OptTextbox::new)) {
return new Webmin::Theme::OptTextbox(@_[1..$#_]);
}
my ($self, $name, $value, $size, $default, $other) = @_;
$self = new Webmin::Textbox($name, $value, $size);
bless($self);
$self->set_default($default || $text{'default'});
$self->set_other($other) if ($other);
return $self;
}
=head2 html()
Returns the HTML for this optional text input
=cut
sub html
{
my ($self) = @_;
return &ui_opt_textbox($self->get_name(), $self->get_value(),
$self->{'size'}, $self->{'default'},
$self->{'other'});
}
=head2 validate(&inputs)
=cut
sub validate
{
my ($self, $in) = @_;
if (defined($self->get_value())) {
if ($self->get_value() eq "") {
return ( $text{'ui_nothing'} );
}
return Webmin::Textbox::validate($self);
}
return ( );
}
sub set_default
{
my ($self, $default) = @_;
$self->{'default'} = $default;
}
sub set_other
{
my ($self, $other) = @_;
$self->{'other'} = $other;
}
=head2 get_value()
Returns the specified initial value for this field, or the value set when the
form is re-displayed due to an error.
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && (defined($in->{$self->{'name'}}) ||
defined($in->{$self->{'name'}.'_def'}))) {
return $in->{$self->{'name'}.'_def'} ? undef : $in->{$self->{'name'}};
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return $in->{"ui_value_".$self->{'name'}};
}
else {
return $self->{'value'};
}
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'}, $self->{'name'}."_def[0]",
$self->{'name'}."_def[1]" );
}
1;

426
Webmin/Page.pm Normal file
View File

@@ -0,0 +1,426 @@
package Webmin::Page;
use WebminCore;
use WebminCore;
=head2 new Webmin::Page(subheading, title, [help-name], [show-config],
[no-module-index], [no-webmin-index], [rightside],
[header], [body-tags], [below-text])
Create a new page object, with the given heading and other details
=cut
sub new
{
if (defined(&Webmin::Theme::Page::new) && caller() !~ /Webmin::Theme::Page/) {
return new Webmin::Theme::Page(@_[1..$#_]);
}
my ($self, $subheading, $title, $help, $config, $noindex, $nowebmin, $right,
$header, $body, $below) = @_;
$self = { 'index' => 1, 'webmin' => 1, 'image' => "" };
bless($self);
$self->set_subheading($subheading);
$self->set_title($title);
$self->set_help($help);
$self->set_config($config);
$self->set_index(!$noindex);
$self->set_webmin(!$nowebmin);
$self->set_right($right);
$self->set_header($header);
$self->set_body($body);
$self->set_below($below);
return $self;
}
=head2 print()
Actually outputs this page
=cut
sub print
{
my ($self) = @_;
my $rv;
# Work out if we need buffering/table
foreach my $c (@{$self->{'contents'}}) {
if (ref($c) =~ /Dynamic/) {
$| = 1;
if ($c->needs_unbuffered()) {
$self->{'unbuffered'} = 1;
}
}
}
# Show the page header
my $func = $self->{'unbuffered'} ? \&ui_print_unbuffered_header
: \&ui_print_header;
my $scripts;
foreach my $s (@{$self->{'scripts'}},
(map { @{$_->{'scripts'}} } @{$self->{'contents'}})) {
$scripts .= "<script>\n".$s."\n</script>\n";
}
my $onload;
my @onloads = ( @{$self->{'onloads'}},
map { @{$_->{'onloads'}} } @{$self->{'contents'}} );
if (@onloads) {
$onload = "onLoad='".join(" ", @onloads)."'";
}
my @args = ( $self->{'subheading'}, $self->{'title'}, $self->{'image'},
$self->{'help'}, $self->{'config'}, $self->{'index'} ? undef : 1,
$self->{'webmin'} ? undef : 1, $self->{'right'},
$self->{'header'}.$scripts, $self->{'body'}.$onload,
$self->{'below'} );
while(!defined($args[$#args])) {
pop(@args);
}
if ($self->get_refresh()) {
print "Refresh: ",$self->get_refresh(),"\r\n";
}
&ui_print_header(@args);
# Add the tab top
if ($self->{'tabs'}) {
print $self->{'tabs'}->top_html();
}
# Add any pre-content stuff
print $self->pre_content();
if ($self->{'errormsg'}) {
# Show the error only
print $self->get_errormsg_html();
}
else {
# Generate the forms and other stuff
foreach my $c (@{$self->{'contents'}}) {
if (!ref($c)) {
# Just a message
print "$c<p>\n";
}
else {
# Convert to HTML
eval { print $c->html(); };
if ($@) {
print "<pre>$@</pre>";
}
if (ref($c) =~ /Dynamic/ && $c->get_wait()) {
# Dynamic object .. execute now
$c->start();
}
}
}
# Generate buttons row
if ($self->{'buttons'}) {
print "<hr>\n";
print &ui_buttons_start();
foreach my $b (@{$self->{'buttons'}}) {
print &ui_buttons_row(@$b);
}
print &ui_buttons_end();
}
}
# Add any post-content stuff
print $self->post_content();
# End of the tabs
if ($self->{'tabs'}) {
print $self->{'tabs'}->bottom_html();
}
# Print the footer
my @footerargs;
foreach my $f (@{$self->{'footers'}}) {
push(@footerargs, $f->[0], $f->[1]);
}
&ui_print_footer(@footerargs);
# Start any dynamic objects
foreach my $c (@{$self->{'contents'}}) {
if (ref($c) =~ /Dynamic/ && !$c->get_wait()) {
$c->start();
}
}
}
=head2 add_footer(link, title)
Adds a return link, typically for display at the end of the page.
=cut
sub add_footer
{
my ($self, $link, $title) = @_;
push(@{$self->{'footers'}}, [ $link, $title ]);
}
=head2 get_footer(index)
Returns the link for the numbered footer
=cut
sub get_footer
{
my ($self, $num) = @_;
return $self->{'footers'}->[$num]->[0];
}
=head2 add_message(text, ...)
Adds a text message, to appear at this point on the page
=cut
sub add_message
{
my ($self, @message) = @_;
push(@{$self->{'contents'}}, join("", @message));
}
=head2 add_error(text, [command-output])
Adds a an error message, possible accompanied by the command output
=cut
sub add_error
{
my ($self, $message, $out) = @_;
$message = "<font color=#ff0000>$message</font>";
if ($out) {
$message .= "<pre>$out</pre>";
}
push(@{$self->{'contents'}}, $message);
}
=head2 add_message_after(&object, text, ...)
Adds a message after some existing object
=cut
sub add_message_after
{
my ($self, $object, @message) = @_;
splice(@{$self->{'contents'}}, $self->position_of($object)+1, 0,
join("", @message));
}
=head2 add_error_after(&object, text, [command-output])
Adds an error message after some existing object
=cut
sub add_error_after
{
my ($self, $object, $message, $out) = @_;
$message = "<font color=#ff0000>$message</font>";
if ($out) {
$message .= "<pre>$out</pre>";
}
splice(@{$self->{'contents'}}, $self->position_of($object)+1, 0,
$message);
}
sub position_of
{
my ($self, $object) = @_;
for(my $i=0; $i<@{$self->{'contents'}}; $i++) {
if ($self->{'contents'}->[$i] eq $object) {
return $i;
}
}
print STDERR "Could not find $object in ",join(" ",@{$self->{'contents'}}),"\n";
return scalar(@{$self->{'contents'}});
}
=head2 add_form(Webmin::Form)
Adds a form to be displayed on this page
=cut
sub add_form
{
my ($self, $form) = @_;
push(@{$self->{'contents'}}, $form);
$form->set_page($self);
}
=head2 add_separator()
Adds some kind of separation between parts of this page, like an <hr>
=cut
sub add_separator
{
my ($self, $message) = @_;
push(@{$self->{'contents'}}, "<hr>");
}
=head2 add_button(cgi, label, description, [&hiddens], [before-button],
[after-button])
Adds an action button associated with this page, typically for display at the end
=cut
sub add_button
{
my ($self, $cgi, $label, $desc, $hiddens, $before, $after) = @_;
push(@{$self->{'buttons'}}, [ $cgi, $label, $desc, join(" ", @$hiddens),
$before, $after ]);
}
=head2 add_tabs(Webmin::Tags)
Tells the page to display the given set of tabs at the top
=cut
sub add_tabs
{
my ($self, $tabs) = @_;
$self->{'tabs'} = $tabs;
}
=head2 add_dynamic(Webmin::DynamicText|Webmin::DynamicProgress)
Adds an object that is dynamically generated, such as a text box or progress bar.
=cut
sub add_dynamic
{
my ($self, $dyn) = @_;
push(@{$self->{'contents'}}, $dyn);
$dyn->set_page($self);
}
sub set_subheading
{
my ($self, $subheading) = @_;
$self->{'subheading'} = $subheading;
}
sub set_title
{
my ($self, $title) = @_;
$self->{'title'} = $title;
}
sub set_help
{
my ($self, $help) = @_;
$self->{'help'} = $help;
}
sub set_config
{
my ($self, $config) = @_;
$self->{'config'} = $config;
}
sub set_index
{
my ($self, $index) = @_;
$self->{'index'} = $index;
}
sub set_webmin
{
my ($self, $webmin) = @_;
$self->{'webmin'} = $webmin;
}
sub set_right
{
my ($self, $right) = @_;
$self->{'right'} = $right;
}
sub set_header
{
my ($self, $header) = @_;
$self->{'header'} = $header;
}
sub set_body
{
my ($self, $body) = @_;
$self->{'body'} = $body;
}
sub set_below
{
my ($self, $below) = @_;
$self->{'below'} = $below;
}
sub set_unbuffered
{
my ($self, $unbuffered) = @_;
$self->{'unbuffered'} = $unbuffered;
}
=head2 set_popup(popup?)
If set to 1, then this is a popup window
=cut
sub set_popup
{
my ($self, $popup) = @_;
$self->{'popup'} = $popup;
}
=head2 get_myurl()
Returns the path part of the URL for this page, like /foo/bar.cgi
=cut
sub get_myurl
{
my @args;
if ($ENV{'QUERY_STRING'} && $ENV{'REQUEST_METHOD'} ne 'POST') {
my %in;
&ReadParse(\%in);
foreach my $i (keys %in) {
if ($i !~ /^ui_/) {
foreach my $v (split(/\0/, $in{$i})) {
push(@args, &urlize($i)."=".
&urlize($v));
}
}
}
}
return @args ? $ENV{'SCRIPT_NAME'}."?".join("&", @args)
: $ENV{'SCRIPT_NAME'};
}
=head2 set_refresh(seconds)
Sets the number of seconds between automatic page refreshes
=cut
sub set_refresh
{
my ($self, $refresh) = @_;
$self->{'refresh'} = $refresh;
}
sub get_refresh
{
my ($self) = @_;
return $self->{'refresh'};
}
=head2 add_onload(code)
Adds some Javascript code for inclusion in the onLoad tag
=cut
sub add_onload
{
my ($self, $code) = @_;
push(@{$self->{'onloads'}}, $code);
}
=head2 add_script(code)
Adds some Javascript code for putting in the <head> section
=cut
sub add_script
{
my ($self, $script) = @_;
push(@{$self->{'scripts'}}, $script);
}
sub pre_content
{
my ($self) = @_;
return undef;
}
sub post_content
{
my ($self) = @_;
return undef;
}
=head2 set_errormsg(message)
Sets an error message to be displayed instead of the page contents
=cut
sub set_errormsg
{
my ($self, $errormsg) = @_;
$self->{'errormsg'} = $errormsg;
}
sub get_errormsg_html
{
my ($self) = @_;
return $self->{'errormsg'}."<p>\n";
}
1;

32
Webmin/Password.pm Normal file
View File

@@ -0,0 +1,32 @@
package Webmin::Password;
@ISA = ( "Webmin::Textbox" );
use Webmin::Textbox;
use WebminCore;
=head2 new Webmin::Password(name, value, [size])
Create a new text input field, for a password
=cut
sub new
{
if (defined(&Webmin::Theme::Password::new)) {
return new Webmin::Theme::Password(@_[1..$#_]);
}
my ($self, $name, $value, $size) = @_;
$self = new Webmin::Textbox($name, $value, $size);
bless($self);
return $self;
}
=head2 html()
Returns the HTML for this password input
=cut
sub html
{
my ($self) = @_;
return &ui_password($self->get_name(), $self->get_value(),
$self->{'size'},
$self->{'$disabled'});
}

97
Webmin/PlainText.pm Normal file
View File

@@ -0,0 +1,97 @@
package Webmin::PlainText;
use WebminCore;
=head2 new Webmin::PlainText(text, columns)
Displays a block of plain fixed-width text, within a page or form.
=cut
sub new
{
if (defined(&Webmin::Theme::PlainText::new) &&
caller() !~ /Webmin::Theme::PlainText/) {
return new Webmin::Theme::PlainText(@_[1..$#_]);
}
my ($self, $text, $columns) = @_;
$self = { 'columns' => 80 };
bless($self);
$self->set_text($text);
$self->set_columns($columns) if (defined($columns));
return $self;
}
=head2 html()
=cut
sub html
{
my ($self) = @_;
my $rv;
$rv .= "<table border><tr $cb><td><pre>";
foreach my $l (&wrap_lines($self->get_text(), $self->get_columns())) {
if (length($l) < $self->get_columns()) {
$l .= (" " x $self->get_columns() - length($l));
}
$rv .= &html_escape($l)."\n";
}
if (!$self->get_text()) {
print (" " x $self->get_columns()),"\n";
}
$rv .= "</pre></td></tr></table>\n";
return $rv;
}
sub set_text
{
my ($self, $text) = @_;
$self->{'text'} = $text;
}
sub get_text
{
my ($self) = @_;
return $self->{'text'};
}
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub get_columns
{
my ($self) = @_;
return $self->{'columns'};
}
# wrap_lines(text, width)
# Given a multi-line string, return an array of lines wrapped to
# the given width
sub wrap_lines
{
local @rv;
local $w = $_[1];
foreach $rest (split(/\n/, $_[0])) {
if ($rest =~ /\S/) {
while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) {
push(@rv, $1);
$rest = $2;
}
}
else {
# Empty line .. keep as it is
push(@rv, $rest);
}
}
return @rv;
}
=head2 set_page(Webmin::Page)
Called when this form is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
1;

132
Webmin/Properties.pm Normal file
View File

@@ -0,0 +1,132 @@
package Webmin::Properties;
use WebminCore;
=head2 new Webmin::Properties([heading], [columns], [width])
Creates a read-only properties list
=cut
sub new
{
if (defined(&Webmin::Theme::Properties::new) &&
caller() !~ /Webmin::Theme::Properties/) {
return new Webmin::Theme::Properties(@_[1..$#_]);
}
my ($self, $heading, $columns, $width) = @_;
$self = { 'columns' => 2 };
bless($self);
$self->set_heading($heading) if (defined($heading));
$self->set_columns($columns) if (defined($columns));
$self->set_width($width) if (defined($width));
return $self;
}
=head2 add_row(label, value, ...)
Adds one row to the properties table
=cut
sub add_row
{
my ($self, @row) = @_;
push(@{$self->{'rows'}}, \@row);
}
=head2 set_heading_row(head1, head2, ...)
Adds a row of headings
=cut
sub set_heading_row
{
my ($self, @row) = @_;
$self->{'heading_row'} = \@row;
}
=head2 html()
Returns the HTML for this properties list
=cut
sub html
{
my ($self) = @_;
my $rv;
my $width = $self->get_width();
$rv .= "<table border ".($width ? "width=$width" : "").">\n";
$rv .= "<tr><td><table width=100% cellspacing=0 cellpadding=3>\n";
my $cols = $self->get_columns();
if ($self->get_heading()) {
$rv .= "<tr $tb><td colspan=$cols><b>".
$self->get_heading()."</b></td> </tr>\n";
}
if ($self->{'heading_row'}) {
$rv .= "<tr $tb>\n";
foreach my $r (@{$self->{'heading_row'}}) {
$rv .= "<td><b>$r</b></td>\n";
}
$rv .= "</tr>\n";
}
foreach my $r (@{$self->{'rows'}}) {
$rv .= "<tr $cb>\n";
$rv .= "<td><b>$r->[0]</b></td>\n";
for(my $i=1; $i<@$r || $i<$cols; $i++) {
$rv .= "<td>".(ref($r->[$i]) ? $r->[$i]->html()
: $r->[$i])."</td>\n";
}
$rv .= "</tr>\n";
}
$rv .= "</table></td></tr></table>\n";
return $rv;
}
=head2 set_width([number|number%])
Sets the width of this section. Can be called with 100%, 500, or undef to use
the minimum possible width.
=cut
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
sub get_width
{
my ($self) = @_;
return $self->{'width'};
}
=head2 set_columns(number)
Sets the number of columns in the properties table, including the title column
=cut
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub get_columns
{
my ($self) = @_;
return $self->{'columns'};
}
=head2 set_heading(number)
Sets the heading to appear above the properties list
=cut
sub set_heading
{
my ($self, $heading) = @_;
$self->{'heading'} = $heading;
}
sub get_heading
{
my ($self) = @_;
return $self->{'heading'};
}
=head2 set_page(Webmin::Page)
Called when this form is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
1;

77
Webmin/Radios.pm Normal file
View File

@@ -0,0 +1,77 @@
package Webmin::Radios;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Radios(name, value, &options, [disabled])
Create a list of radio buttons, of which one may be selected
=cut
sub new
{
if (defined(&Webmin::Theme::Radios::new)) {
return new Webmin::Theme::Radios(@_[1..$#_]);
}
my ($self, $name, $value, $options, $disabled) = @_;
$self = { };
bless($self);
$self->set_name($name);
$self->set_value($value);
$self->set_options($options);
$self->set_disabled($disabled);
return $self;
}
=head2 add_option(name, [label])
=cut
sub add_option
{
my ($self, $name, $label) = @_;
push(@{$self->{'options'}}, [ $name, $label ]);
}
=head2 html()
Returns the HTML for all the radio buttons, one after the other
=cut
sub html
{
my ($self) = @_;
my $dis = $self->{'form'}->get_changefunc($self);
my $opts = $self->get_options();
if ($dis) {
foreach my $o (@$opts) {
$o->[2] = "onClick='$dis'";
}
}
return &ui_radio($self->get_name(), $self->get_value(),
$opts, $self->get_disabled());
}
=head2 one_html(number)
Returns the HTML for a single one of the radio buttons
=cut
sub one_html
{
my ($self, $num) = @_;
my $opt = $self->{'options'}->[$num];
my $dis = $self->{'form'}->get_changefunc($self);
return &ui_oneradio($self->get_name(), $opt->[0],
defined($opt->[1]) ? $opt->[1] : $opt->[0],
$self->get_value() eq $opt->[0],
$dis ? "onClick='$dis'" : undef,
$self->get_disabled());
}
sub set_options
{
my ($self, $options) = @_;
$self->{'options'} = $options;
}
sub get_options
{
my ($self) = @_;
return $self->{'options'};
}
1;

20
Webmin/ResultPage.pm Normal file
View File

@@ -0,0 +1,20 @@
package Webmin::ResultPage;
use WebminCore;
=head2 new Webmin::ResultPage(subheading, title, message, [help-name])
Create a new page object for showing some success message.
=cut
sub new
{
if (defined(&Webmin::Theme::ResultPage::new) &&
caller() !~ /Webmin::Theme::ResultPage/) {
return new Webmin::Theme::ResultPage(@_[1..$#_]);
}
my ($self, $subheading, $title, $message, $help) = @_;
$self = new Webmin::Page($subheading, $title, $help);
$self->add_message("<b>$message</b>");
return $self;
}
1;

172
Webmin/Section.pm Normal file
View File

@@ -0,0 +1,172 @@
package Webmin::Section;
use WebminCore;
=head2 new Webmin::Section(header, [columns], [title], [width])
Create a new form section, which has a header and contains some inputs
=cut
sub new
{
if (defined(&Webmin::Theme::Section::new) &&
caller() !~ /Webmin::Theme::Section/) {
return new Webmin::Theme::Section(@_[1..$#_]);
}
my ($self, $header, $columns, $title, $width) = @_;
$self = { 'columns' => 4 };
bless($self);
$self->set_header($header);
$self->set_columns($columns) if (defined($columns));
$self->set_title($title) if (defined($title));
$self->set_width($width) if (defined($width));
return $self;
}
=head2 html()
Returns the HTML for this form section
=cut
sub html
{
my ($self) = @_;
my $rv;
$rv .= &ui_table_start($self->{'header'},
$self->{'width'} ? "width=$self->{'width'}" : undef,
$self->{'columns'});
foreach my $i (@{$self->{'inputs'}}) {
if (is_input($i->[1])) {
my $errs;
my @errs = $self->{'form'}->field_errors($i->[1]->get_name());
if (@errs) {
foreach my $e (@errs) {
$errs .= "<br><font color=#ff0000>$e</font>\n";
}
}
$rv .= &ui_table_row($i->[0], $i->[1]->html().$errs,
$i->[2]);
}
else {
$rv .= &ui_table_row($i->[0],
ref($i->[1]) ? $i->[1]->html() : $i->[1], $i->[2]);
}
}
$rv .= &ui_table_end();
return $rv;
}
=head2 add_input(label, input, [columns])
Adds some Webmin::Input object to this form section
=cut
sub add_input
{
my ($self, $label, $input, $cols) = @_;
push(@{$self->{'inputs'}}, [ $label, $input, $cols ]);
$input->set_form($self->{'form'});
}
=head2 add_row(label, text, [columns])
Adds a non-editable row to this form section
=cut
sub add_row
{
my ($self, $label, $text, $cols) = @_;
push(@{$self->{'inputs'}}, [ $label, $text, $cols ]);
}
=head2 add_separator()
Adds some kind of separator at this point in the section
=cut
sub add_separator
{
my ($self) = @_;
push(@{$self->{'inputs'}}, [ undef, "<hr>", $self->{'columns'} ]);
}
sub set_header
{
my ($self, $header) = @_;
$self->{'header'} = $header;
}
sub set_columns
{
my ($self, $columns) = @_;
$self->{'columns'} = $columns;
}
sub set_title
{
my ($self, $title) = @_;
$self->{'title'} = $title;
}
=head2 set_width([number|number%])
Sets the width of this section. Can be called with 100%, 500, or undef to use
the minimum possible width.
=cut
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
=head2 validate()
Validates all form inputs, based on the given CGI input hash. Returns a list
of errors, each of which is field name, error message and field label.
=cut
sub validate
{
my ($self) = @_;
my @errs;
foreach my $i (@{$self->{'inputs'}}) {
if (is_input($i->[1])) {
foreach my $e ($i->[1]->validate()) {
push(@errs, [ $i->[1]->get_name(), $e, $i->[0] ]);
}
}
}
return @errs;
}
=head2 get_value(input-name)
Returns the value of the input with the given name.
=cut
sub get_value
{
my ($self, $name) = @_;
foreach my $i (@{$self->{'inputs'}}) {
if (is_input($i->[1]) && $i->[1]->get_name() eq $name) {
return $i->[1]->get_value();
}
}
return undef;
}
=head2 set_form(form)
Called by the Webmin::Form object when this section is added to it
=cut
sub set_form
{
my ($self, $form) = @_;
$self->{'form'} = $form;
foreach my $i (@{$self->{'inputs'}}) {
if (is_input($i->[1])) {
$i->[1]->set_form($form);
}
}
}
sub list_inputs
{
my ($self) = @_;
return map { $_->[1] } grep { is_input($_->[1]) } @{$self->{'inputs'}};
}
=head2 is_input(object)
=cut
sub is_input
{
my ($object) = @_;
return ref($object) && ref($object) =~ /::/ &&
$object->isa("Webmin::Input");
}
1;

135
Webmin/Select.pm Normal file
View File

@@ -0,0 +1,135 @@
package Webmin::Select;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Select(name, value|&values, &options, [multiple-size],
[add-missing], [disabled])
Create a menu or multiple-selection field
=cut
sub new
{
if (defined(&Webmin::Theme::Select::new)) {
return new Webmin::Theme::Select(@_[1..$#_]);
}
my ($self, $name, $value, $options, $size, $missing, $disabled) = @_;
$self = { 'size' => 1 };
bless($self);
$self->set_name($name);
$self->set_value($value);
$self->set_options($options);
$self->set_size($size) if (defined($size));
$self->set_missing($missing);
$self->set_disabled($disabled);
return $self;
}
=head2 add_option(name, [label])
=cut
sub add_option
{
my ($self, $name, $label) = @_;
push(@{$self->{'options'}}, [ $name, $label ]);
}
=head2 html()
Returns the HTML for this menu or multi-select input
=cut
sub html
{
my ($self) = @_;
my $dis = $self->{'form'}->get_changefunc($self);
return &ui_select($self->get_name(), $self->get_value(),
$self->get_options(),
$self->get_size() > 1 ? $self->get_size() : undef,
$self->get_size() > 1 ? 1 : 0,
undef,
$self->get_disabled(),
$dis ? "onChange='$dis'" : undef).
($self->get_size() > 1 ?
&ui_hidden("ui_exists_".$self->get_name(), 1) : "");
}
=head2 get_value()
For a multi-select field, returns an array ref of all values. For a menu,
return just the one value.
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && (defined($in->{$self->{'name'}}) ||
defined($in->{"ui_exists_".$self->{'name'}}))) {
if ($self->get_size() > 1) {
return [ split(/\0/, $in->{$self->{'name'}}) ];
}
else {
return $in->{$self->{'name'}};
}
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
if ($self->get_size() > 1) {
return [ split(/\0/, $in->{"ui_value_".$self->{'name'}}) ];
}
else {
return $in->{"ui_value_".$self->{'name'}};
}
}
else {
return $self->{'value'};
}
}
sub set_options
{
my ($self, $options) = @_;
$self->{'options'} = $options;
}
sub set_size
{
my ($self, $size) = @_;
$self->{'size'} = $size;
}
sub set_missing
{
my ($self, $missing) = @_;
$self->{'missing'} = $missing;
}
sub get_options
{
my ($self) = @_;
return $self->{'options'};
}
sub get_size
{
my ($self) = @_;
return $self->{'size'};
}
sub get_missing
{
my ($self) = @_;
return $self->{'missing'};
}
=head2 validate()
Returns a list of error messages for this field
=cut
sub validate
{
my ($self) = @_;
if ($self->{'size'} > 1) {
my $value = $self->get_value();
if ($self->{'mandatory'} && !@$value) {
return ( $self->{'mandatorymsg'} || $text{'ui_mandatory'} );
}
}
return ( );
}
1;

41
Webmin/Submit.pm Normal file
View File

@@ -0,0 +1,41 @@
package Webmin::Submit;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Submit(label, [name], [disabled])
Create a form submit button
=cut
sub new
{
if (defined(&Webmin::Theme::Submit::new) &&
caller() !~ /Webmin::Theme::Submit/) {
return new Webmin::Theme::Submit(@_[1..$#_]);
}
my ($self, $value, $name, $disabled) = @_;
$self = { };
bless($self);
$self->set_value($value);
$self->set_name($name) if ($name);
$self->set_disabled($disabled) if ($disabled);
return $self;
}
=head2 html()
Returns the HTML for this form submit button
=cut
sub html
{
my ($self) = @_;
return &ui_submit($self->get_value(), $self->get_name(),
$self->get_disabled());
}
sub get_value
{
my ($self) = @_;
return $self->{'value'};
}
1;

660
Webmin/Table.pm Normal file
View File

@@ -0,0 +1,660 @@
package Webmin::Table;
use Webmin::JavascriptButton;
use WebminCore;
=head2 new Webmin::Table(&headings, [width], [name], [heading])
Create a multi-column table, with support for sorting, paging and so on
=cut
sub new
{
if (defined(&Webmin::Theme::Table::new) &&
caller() !~ /Webmin::Theme::Table/) {
return new Webmin::Theme::Table(@_[1..$#_]);
}
my ($self, $headings, $width, $name, $heading) = @_;
$self = { 'sorter' => [ map { \&default_sorter } @$headings ] };
bless($self);
$self->set_headings($headings);
$self->set_name($name) if (defined($name));
$self->set_width($width) if (defined($width));
$self->set_heading($heading) if (defined($heading));
$self->set_all_sortable(1);
$self->set_paging(1);
return $self;
}
=head2 add_row(&fields)
Adds a row to the table. Each element in the row can be either an input of some
kind, or a piece of text.
=cut
sub add_row
{
my ($self, $fields) = @_;
push(@{$self->{'rows'}}, $fields);
}
=head2 html()
Returns the HTML for this table. The actual ordering may depend upon sort headers
clicked by the user. The rows to display may be limited by the page size.
=cut
sub html
{
my ($self) = @_;
my @srows = @{$self->{'rows'}};
my $thisurl = $self->{'form'}->{'page'}->get_myurl();
my $name = $self->get_name();
my $rv;
# Add the heading
if ($self->get_heading()) {
$rv .= &ui_subheading($self->get_heading())."\n";
}
my $sm = $self->get_searchmax();
if (defined($sm) && @srows > $sm) {
# Too many rows to show .. add a search form. This will need to close
# the parent form, and then re-open it after the search form, as nested
# forms aren't allowed!
if ($self->get_searchmsg()) {
$rv .= $self->get_searchmsg()."<br>\n";
}
my $form = new Webmin::Form($thisurl, "get");
$form->set_input($self->{'form'}->{'in'});
my $section = new Webmin::Section(undef, 2);
$form->add_section($section);
my $col = new Webmin::Select("ui_searchcol_".$name, undef);
my $i = 0;
foreach my $h (@{$self->get_headings()}) {
if ($self->{'sortable'}->[$i]) {
$col->add_option($i, $h);
}
$i++;
}
$section->add_input($text{'ui_searchcol'}, $col);
my $for = new Webmin::Textbox("ui_searchfor_".$name, undef, 30);
$section->add_input($text{'ui_searchfor'}, $for);
$rv .= $section->html();
my $url = $self->make_url(undef, undef, undef, undef, 1);
my $jsb = new Webmin::JavascriptButton($text{'ui_searchok'},
"window.location = '$url'+'&'+'ui_searchfor_${name}'+'='+escape(form.ui_searchfor_${name}.value)+'&'+'ui_searchcol_${name}'+'='+escape(form.ui_searchcol_${name}.selectedIndex)");
$rv .= $jsb->html();
$rv .= "<br>\n";
# Limit records to current search
if (defined($col->get_value())) {
my $sf = $for->get_value();
@srows = grep { $_->[$col->get_value()] =~ /\Q$sf\E/i } @srows;
}
else {
@srows = ( );
}
}
# Prepare the selector
my $selc = $self->{'selectcolumn'};
my $seli = $self->{'selectinput'};
my %selmap;
if (defined($selc)) {
my $i = 0;
foreach my $r (@srows) {
$selmap{$r,$selc} = $seli->one_html($i);
$i++;
}
}
# Sort the rows
my ($sortcol, $sortdir) = $self->get_sortcolumn();
if (defined($sortcol)) {
my $func = $self->{'sorter'}->[$sortcol];
@srows = sort { my $so = &$func($a->[$sortcol], $b->[$sortcol], $sortcol);
$sortdir ? -$so : $so } @srows;
}
# Build the td attributes
my @tds = map { "valign=top" } @{$self->{'headings'}};
if ($self->{'widths'}) {
my $i = 0;
foreach my $w (@{$self->{'widths'}}) {
$tds[$i++] .= " width=$w";
}
}
if ($self->{'aligns'}) {
my $i = 0;
foreach my $a (@{$self->{'aligns'}}) {
$tds[$i++] .= " align=$a";
}
}
# Find the page we want
my $page = $self->get_pagepos();
my ($start, $end, $origsize);
if ($self->get_paging() && $self->get_pagesize()) {
# Restrict view to rows within some page
$start = $self->get_pagesize()*$page;
$end = $self->get_pagesize()*($page+1) - 1;
if ($start >= @srows) {
# Gone off end!
$start = 0;
$end = $self->get_pagesize()-1;
}
if ($end >= @srows) {
# End is too far
$end = @srows-1;
}
$origsize = scalar(@srows);
@srows = @srows[$start..$end];
}
# Generate the headings, with sorters
$thisurl .= $thisurl =~ /\?/ ? "&" : "?";
my @sheadings;
my $i = 0;
foreach my $h (@{$self->get_headings()}) {
if ($self->{'sortable'}->[$i]) {
# Column can be sorted!
my $hh = "<table cellpadding=0 cellspacing=0 width=100%><tr>";
$hh .= "<td><b>$h</b></td> <td align=right>";
if (!defined($sortcol) || $sortcol != $i) {
# Not sorting on this column .. show grey button
my $url = $self->make_url($i, 0, undef, undef);
$hh .= "<a href='$url'>".
"<img src=/images/nosort.gif border=0></a>";
}
else {
# Sorting .. show button to switch mode
my $notsort = !$sortdir;
my $url = $self->make_url($i, $sortdir ? 0 : 1, undef, undef);
$hh .= "<a href='$url'>".
"<img src=/images/sort.gif border=0></a>";
}
$hh .= "</td></tr></table>";
push(@sheadings, $hh);
}
else {
push(@sheadings, $h);
}
$i++;
}
# Get any errors for inputs
my @errs = map { $_->get_errors() } $self->list_inputs();
if (@errs) {
foreach my $e (@errs) {
$rv .= "<font color=#ff0000>$e</font><br>\n";
}
}
# Build links for top and bottom
my $links;
if (ref($seli) =~ /Checkboxes/) {
# Add select all/none links
my $formno = $self->{'form'}->get_formno();
$links .= &select_all_link($seli->get_name(), $formno,
$text{'ui_selall'})."\n";
$links .= &select_invert_link($seli->get_name(), $formno,
$text{'ui_selinv'})."\n";
$links .= "&nbsp;\n";
}
foreach my $l (@{$self->{'links'}}) {
$links .= "<a href='$l->[0]'>$l->[1]</a>\n";
}
$links .= "<br>" if ($links);
# Build list of inputs for bottom
my $inputs;
foreach my $i (@{$self->{'inputs'}}) {
$inputs .= $i->html()."\n";
}
$inputs .= "<br>" if ($inputs);
# Create the pager
if ($self->get_paging() && $origsize) {
my $lastpage = int(($origsize-1)/$self->get_pagesize());
$rv .= "<center>";
if ($page != 0) {
# Add start and left arrows
my $surl = $self->make_url(undef, undef, undef, 0);
$rv .= "<a href='$surl'><img src=/images/first.gif border=0 align=middle></a>\n";
my $lurl = $self->make_url(undef, undef, undef, $page-1);
$rv .= "<a href='$lurl'><img src=/images/left.gif border=0 align=middle></a>\n";
}
else {
# Start and left are disabled
$rv .= "<img src=/images/first-grey.gif border=0 align=middle>\n";
$rv .= "<img src=/images/left-grey.gif border=0 align=middle>\n";
}
$rv .= &text('ui_paging', $start+1, $end+1, $origsize);
if ($end < $origsize-1) {
# Add right and end arrows
my $rurl = $self->make_url(undef, undef, undef, $page+1);
$rv .= "<a href='$rurl'><img src=/images/right.gif border=0 align=middle></a>\n";
my $eurl = $self->make_url(undef, undef, undef, $lastpage);
$rv .= "<a href='$eurl'><img src=/images/last.gif border=0 align=middle></a>\n";
}
else {
# Right and end are disabled
$rv .= "<img src=/images/right-grey.gif border=0 align=middle>\n";
$rv .= "<img src=/images/last-grey.gif border=0 align=middle>\n";
}
$rv .= "</center>\n";
}
# Create actual table
if (@srows) {
$rv .= $links;
$rv .= &ui_columns_start(\@sheadings, $self->{'width'}, 0, \@tds);
foreach my $r (@srows) {
my @row;
for(my $i=0; $i<@$r || $i<@sheadings; $i++) {
if (ref($r->[$i]) eq "ARRAY") {
my $j = $r->[$i]->[0] &&
$r->[$i]->[0]->isa("Webmin::TableAction")
? "&nbsp;|&nbsp;" : "&nbsp;";
$row[$i] = $selmap{$r,$i}.
join($j, map { ref($_) ? $_->html() : $_ }
@{$r->[$i]});
}
elsif (ref($r->[$i])) {
$row[$i] = $selmap{$r,$i}.$r->[$i]->html();
}
else {
$row[$i] = $selmap{$r,$i}.$r->[$i];
}
}
$rv .= &ui_columns_row(\@row, \@tds);
}
$rv .= &ui_columns_end();
}
elsif ($self->{'emptymsg'}) {
$rv .= $self->{'emptymsg'}."<p>\n";
}
$rv .= $links;
$rv .= $inputs;
return $rv;
}
=head2 set_form(form)
Called by the Webmin::Form object when this table is added to it
=cut
sub set_form
{
my ($self, $form) = @_;
$self->{'form'} = $form;
foreach my $i ($self->list_inputs()) {
$i->set_form($form);
}
}
=head2 set_sorter(function, [column])
Sets a function used for sorting fields. Will be called with two field values to
compare, and a column number.
=cut
sub set_sorter
{
my ($self, $func, $col) = @_;
if (defined($col)) {
$self->{'sorter'}->[$col] = $func;
}
else {
$self->{'sorter'} = [ map { $func } @{$self->{'headings'}} ];
}
}
=head2 default_sorter(value1, value2, col)
=cut
sub default_sorter
{
my ($value1, $value2, $col) = @_;
if (ref($value1) && $value1->isa("Webmin::TableAction")) {
$value1 = $value1->get_value();
$value2 = $value2->get_value();
}
return lc($value1) cmp lc($value2);
}
=head2 numeric_sorter(value1, value2, col)
=cut
sub numeric_sorter
{
my ($value1, $value2, $col) = @_;
return $value1 <=> $value2;
}
=head2 set_sortable(column, sortable?)
Tells the table if some column should allow sorting or not. By default, all are.
=cut
sub set_sortable
{
my ($self, $col, $sortable) = @_;
$self->{'sortable'}->[$col] = $sortable;
}
=head2 set_all_sortable(sortable?)
Enabled or disables sorting for all columns
=cut
sub set_all_sortable
{
my ($self, $sortable) = @_;
$self->{'sortable'} = [ map { $sortable } @{$self->{'headings'}} ];
}
=head2 get_sortcolumn()
Returns the column to sort on and the order (1 for descending), or undef for none
=cut
sub get_sortcolumn
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
my $name = $self->get_name();
if ($in && defined($in->{"ui_sortcolumn_".$name})) {
return ( $in->{"ui_sortcolumn_".$name},
$in->{"ui_sortdir_".$name} );
}
else {
return ( $self->{'sortcolumn'}, $self->{'sortdir'} );
}
}
=head2 set_sortcolumn(num, descending?)
Sets the default column on which sorting will be done, unless overridden by
the user.
=cut
sub set_sortcolumn
{
my ($self, $col, $desc) = @_;
$self->{'sortcolumn'} = $col;
$self->{'sortdir'} = $desc;
}
=head2 get_paging()
Returns 1 if page-by-page display should be used
=cut
sub get_paging
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
my $name = $self->get_name();
if ($in && defined($in->{"ui_paging_".$name})) {
return ( $in->{"ui_paging_".$name} );
}
else {
return ( $self->{'paging'} );
}
}
=head2 set_paging(paging?)
Turns page-by-page display of the table on or off
=cut
sub set_paging
{
my ($self, $paging) = @_;
$self->{'paging'} = $paging;
}
sub set_name
{
my ($self, $name) = @_;
$self->{'name'} = $name;
}
=head2 get_name()
Returns the name for indentifying this table in HTML
=cut
sub get_name
{
my ($self) = @_;
if (defined($self->{'name'})) {
return $self->{'name'};
}
elsif ($self->{'form'}) {
my $secs = $self->{'form'}->{'sections'};
for(my $i=0; $i<@$secs; $i++) {
return "table".$i if ($secs->[$i] eq $self);
}
}
return "table";
}
sub set_headings
{
my ($self, $headings) = @_;
$self->{'headings'} = $headings;
}
sub get_headings
{
my ($self) = @_;
return $self->{'headings'};
}
=head2 set_selector(column, input)
Takes a Webmin::Checkboxes or Webmin::Radios object, and uses it to add checkboxes
in the specified column.
=cut
sub set_selector
{
my ($self, $col, $input) = @_;
$self->{'selectcolumn'} = $col;
$self->{'selectinput'} = $input;
$input->set_form($form);
}
=head2 get_selector()
Returns the UI element used for selecting rows
=cut
sub get_selector
{
my ($self) = @_;
return wantarray ? ( $self->{'selectinput'}, $self->{'selectcolumn'} )
: $self->{'selectinput'};
}
=head2 set_widths(&widths)
Given an array reference of widths (like 50 or 20%), uses them for the columns
in the table.
=cut
sub set_widths
{
my ($self, $widths) = @_;
$self->{'widths'} = $widths;
}
=head2 set_width([number|number%])
Sets the width of this entire table. Can be called with 100%, 500 or undef to use
the minimum possible width.
=cut
sub set_width
{
my ($self, $width) = @_;
$self->{'width'} = $width;
}
=head2 set_aligns(&aligns)
Given an array reference of horizontal alignments (like left or right), uses them
for the columns in the table.
=cut
sub set_aligns
{
my ($self, $aligns) = @_;
$self->{'aligns'} = $aligns;
}
=head2 validate()
Validates all inputs, and returns a list of error messages
=cut
sub validate
{
my ($self) = @_;
my $seli = $self->{'selectinput'};
my @errs;
if ($seli) {
push(@errs, map { [ $seli->get_name(), $_ ] } $seli->validate());
}
foreach my $i ($self->list_inputs()) {
foreach my $e ($i->validate()) {
push(@errs, [ $i->get_name(), $e ]);
}
}
return @errs;
}
=head2 get_value(input-name)
Returns the value of the input with the given name.
=cut
sub get_value
{
my ($self, $name) = @_;
if ($self->{'selectinput'} && $self->{'selectinput'}->get_name() eq $name) {
return $self->{'selectinput'}->get_value();
}
foreach my $i ($self->list_inputs()) {
if ($i->get_name() eq $name) {
return $i->get_value();
}
}
return undef;
}
=head2 list_inputs()
Returns all inputs in all form sections
=cut
sub list_inputs
{
my ($self) = @_;
my @rv = @{$self->{'inputs'}};
push(@rv, $self->{'selectinput'}) if ($self->{'selectinput'});
return @rv;
}
=head2 set_searchmax(num, [message])
Sets the maximum number of table rows to display before showing a search form
=cut
sub set_searchmax
{
my ($self, $searchmax, $searchmsg) = @_;
$self->{'searchmax'} = $searchmax;
$self->{'searchmsg'} = $searchmsg;
}
sub get_searchmax
{
my ($self) = @_;
return $self->{'searchmax'};
}
sub get_searchmsg
{
my ($self) = @_;
return $self->{'searchmsg'};
}
=head2 add_link(link, message)
Adds a link to the table, for example for adding a new entry
=cut
sub add_link
{
my ($self, $link, $msg) = @_;
push(@{$self->{'links'}}, [ $link, $msg ]);
}
=head2 add_input(input)
Adds some input to be displayed at the bottom of the table
=cut
sub add_input
{
my ($self, $input) = @_;
push(@{$self->{'inputs'}}, $input);
$input->set_form($self->{'form'});
}
=head2 set_emptymsg(message)
Sets the message to display when the table is empty
=cut
sub set_emptymsg
{
my ($self, $emptymsg) = @_;
$self->{'emptymsg'} = $emptymsg;
}
=head2 set_heading(text)
Sets the heading text to appear above the table
=cut
sub set_heading
{
my ($self, $heading) = @_;
$self->{'heading'} = $heading;
}
sub get_heading
{
my ($self) = @_;
return $self->{'heading'};
}
=head2 set_pagesize(pagesize)
Sets the size of a page. Set to 0 to turn off completely.
=cut
sub set_pagesize
{
my ($self, $pagesize) = @_;
$self->{'pagesize'} = $pagesize;
}
=head2 get_pagesize()
Returns the size of a page, or 0 if paging is turned off totally
=cut
sub get_pagesize
{
my ($self) = @_;
return $self->{'pagesize'};
}
sub get_pagepos
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
my $name = $self->get_name();
if ($in && defined($in->{"ui_pagepos_".$name})) {
return ( $in->{"ui_pagepos_".$name} );
}
else {
return ( $self->{'pagepos'} );
}
}
=head2 make_url(sortcol, sortdir, paging, page, [no-searchargs], [no-pagearg])
Returns a link to this table's page, with the defaults for the various state
fields overriden by the parameters (where defined)
=cut
sub make_url
{
my ($self, $newsortcol, $newsortdir, $newpaging, $newpagepos,
$nosearch, $nopage) = @_;
my ($sortcol, $sortdir) = $self->get_sortcolumn();
$sortcol = $newsortcol if (defined($newsortcol));
$sortdir = $newsortdir if (defined($newsortdir));
my $paging = $self->get_paging();
$paging = $newpaging if (defined($newpaging));
my $pagepos = $self->get_pagepos();
$pagepos = $newpagepos if (defined($newpagepos));
my $thisurl = $self->{'form'}->{'page'}->get_myurl();
my $name = $self->get_name();
$thisurl .= $thisurl =~ /\?/ ? "&" : "?";
my $in = $self->{'form'}->{'in'};
return "${thisurl}ui_sortcolumn_${name}=$sortcol".
"&ui_sortdir_${name}=$sortdir".
"&ui_paging_${name}=$paging".
($nopage ? "" : "&ui_pagepos_${name}=$pagepos").
($nosearch ? "" : "&ui_searchfor_${name}=".
&urlize($in->{"ui_searchfor_${name}"}).
"&ui_searchcol_${name}=".
&urlize($in->{"ui_searchcol_${name}"}));
}
1;

92
Webmin/TableAction.pm Normal file
View File

@@ -0,0 +1,92 @@
package Webmin::TableAction;
use WebminCore;
=head2 new Webmin::TableAction(cgi, label, &args, disabled)
An object of this class can be added to a table or properties object to create
a link or action button of some kind.
=cut
sub new
{
if (defined(&Webmin::Theme::TableAction::new) &&
caller() !~ /Webmin::Theme::TableAction/) {
return new Webmin::Theme::TableAction(@_[1..$#_]);
}
my ($self, $cgi, $value, $args, $disabled) = @_;
$self = { };
bless($self);
$self->set_value($value);
$self->set_cgi($cgi);
$self->set_args($args) if (defined($args));
$self->set_disabled($disabled) if (defined($disabled));
return $self;
}
sub html
{
my ($self) = @_;
my $rv;
if ($self->get_disabled()) {
$rv .= "<u><i>".$self->get_value()."</i></u>";
}
else {
my $link = $self->get_cgi();
my $i = 0;
foreach my $a (@{$self->get_args()}) {
$link .= ($i++ ? "&" : "?");
$link .= &urlize($a->[0])."=".&urlize($a->[1]);
}
$rv .= "<a href='$link'>".$self->get_value()."</a>";
}
return $rv;
}
sub set_value
{
my ($self, $value) = @_;
$self->{'value'} = $value;
}
sub get_value
{
my ($self) = @_;
return $self->{'value'};
}
sub set_cgi
{
my ($self, $cgi) = @_;
$self->{'cgi'} = $cgi;
}
sub get_cgi
{
my ($self) = @_;
return $self->{'cgi'};
}
sub set_args
{
my ($self, $args) = @_;
$self->{'args'} = $args;
}
sub get_args
{
my ($self) = @_;
return $self->{'args'};
}
sub set_disabled
{
my ($self, $disabled) = @_;
$self->{'disabled'} = $disabled;
}
sub get_disabled
{
my ($self) = @_;
return $self->{'disabled'};
}
1;

142
Webmin/Tabs.pm Normal file
View File

@@ -0,0 +1,142 @@
package Webmin::Tabs;
use WebminCore;
=head2 new Webmin::Tabs([&tabs])
Displayed at the top of a page, to allow selection of various pages
=cut
sub new
{
my ($self, $tabs) = @_;
if (defined(&Webmin::Theme::Tabs::new)) {
return new Webmin::Theme::Tabs(@_[1..$#_]);
}
$self = { 'tabs' => [ ],
'tab' => 0 };
bless($self);
$self->set_tabs($tabs) if (defined($tabs));
return $self;
}
=head2 add_tab(name, link)
=cut
sub add_tab
{
my ($self, $name, $link) = @_;
push(@{$self->{'tabs'}}, [ $name, $link ]);
}
=head2 html()
Returns the HTML for the top of the page
=cut
sub top_html
{
my ($self) = @_;
my $rv;
$rv .= "<table border=0 cellpadding=0 cellspacing=0 width=100% height=20><tr>";
$rv .= "<td valign=bottom>";
$rv .= "<table border=0 cellpadding=0 cellspacing=0 height=20><tr>";
my $i = 0;
my ($high, $low) = ("#cccccc", "#9999ff");
my ($lowlc, $lowrc) = ( "/images/lc1.gif", "/images/rc1.gif" );
my ($highlc, $highrc) = ( "/images/lc2.gif", "/images/rc2.gif" );
foreach my $t (@{$self->get_tabs()}) {
if ($i == $self->get_tab()) {
# This is the selected tab
$rv .= "<td valign=top bgcolor=$high>".
"<img src=$highlc alt=\"\"></td>";
if ($self->get_link()) {
# Link
$rv .= "<td bgcolor=$high>&nbsp;".
"<a href=$t->[1]><b>$t->[0]</b></a>&nbsp;</td>";
}
else {
# Don't link
$rv .= "<td bgcolor=$high>&nbsp;<b>$t->[0]</b>&nbsp;</td>";
}
$rv .= "<td valign=top bgcolor=$high>".
"<img src=$highrc alt=\"\"></td>\n";
}
else {
# Not selected
$rv .= "<td valign=top bgcolor=$low>".
"<img src=$lowlc alt=\"\"></td>";
$rv .= "<td bgcolor=$low>&nbsp;".
"<a href=$t->[1]><b>$t->[0]</b></a>&nbsp;</td>";
$rv .= "<td valign=top bgcolor=$low>".
"<img src=$lowrc alt=\"\"></td>\n";
}
$i++;
if ($self->{'wrap'} && $i%$self->{'wrap'} == 0) {
# New row
$rv .= "</tr><tr>";
}
}
$rv .= "</tr></table></td>\n";
$rv .= "</tr></table>\n";
$rv .= "<table border=1 cellpadding=10 cellspacing=0 width=100%><tr><td>\n";
return $rv;
}
=head2 bottom_html()
Returns the HTML for the bottom of the page
=cut
sub bottom_html
{
my ($self) = @_;
my $rv = "</td></tr></table>\n";
return $rv;
}
=head2 set_tab(number|link)
Sets the tab that is currently highlighted
=cut
sub set_tab
{
my ($self, $tab) = @_;
if ($tab =~ /^\d+$/) {
$self->{'tab'} = $tab;
}
else {
for(my $i=0; $i<@{$self->{'tabs'}}; $i++) {
if ($self->{'tabs'}->[$i]->[1] eq $tab) {
$self->{'tab'} = $i;
}
}
}
}
sub get_tab
{
my ($self) = @_;
return $self->{'tab'};
}
=head2 set_link(link)
If called with a non-zero parameter, even the highlighted tab will be a link
=cut
sub set_link
{
my ($self, $link) = @_;
$self->{'link'} = $link;
}
sub get_link
{
my ($self) = @_;
return $self->{'link'};
}
sub set_tabs
{
my ($self, $tabs) = @_;
$self->{'tabs'} = $tabs;
}
sub get_tabs
{
my ($self) = @_;
return $self->{'tabs'};
}
1;

122
Webmin/Textarea.pm Normal file
View File

@@ -0,0 +1,122 @@
package Webmin::Textarea;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Textarea(name, value, rows, cols, [wrap], [disabled])
Create a new text box, with the given size
=cut
sub new
{
if (defined(&Webmin::Theme::Textarea::new)) {
return new Webmin::Theme::Textarea(@_[1..$#_]);
}
my ($self, $name, $value, $rows, $cols, $wrap, $disabled) = @_;
$self = { };
bless($self);
$self->set_name($name);
$self->set_value($value);
$self->set_rows($rows);
$self->set_cols($cols);
$self->set_disabled($disabled);
return $self;
}
=head2 html()
Returns the HTML for this text area
=cut
sub html
{
my ($self) = @_;
return &ui_textarea($self->get_name(), $self->get_value(),
$self->get_rows(), $self->get_cols(),
$self->get_wrap(), $self->get_disabled());
}
sub set_rows
{
my ($self, $rows) = @_;
$self->{'rows'} = $rows;
}
sub get_rows
{
my ($self) = @_;
return $self->{'rows'};
}
sub set_cols
{
my ($self, $cols) = @_;
$self->{'cols'} = $cols;
}
sub get_cols
{
my ($self) = @_;
return $self->{'cols'};
}
sub set_wrap
{
my ($self, $wrap) = @_;
$self->{'wrap'} = $wrap;
}
sub get_wrap
{
my ($self) = @_;
return $self->{'wrap'};
}
sub set_validation_func
{
my ($self, $func) = @_;
$self->{'validation_func'} = $func;
}
=head2 set_validation_regexp(regexp, message)
=cut
sub set_validation_regexp
{
my ($self, $regexp, $message) = @_;
$self->{'validation_regexp'} = $regexp;
$self->{'validation_message'} = $message;
}
=head2 validate()
Returns a list of error messages for this field
=cut
sub validate
{
my ($self) = @_;
my $value = $self->get_value();
if ($self->{'mandatory'} && $value eq '') {
return ( $self->{'mandmesg'} || $text{'ui_mandatory'} );
}
if ($self->{'validation_func'}) {
my $err = &{$self->{'validation_func'}}($value, $self->{'name'},
$self->{'form'});
return ( $err ) if ($err);
}
if ($self->{'validation_regexp'}) {
if ($value !~ /$self->{'validation_regexp'}/) {
return ( $self->{'validation_message'} );
}
}
return ( );
}
=head2 get_value()
Returns the value, without any \r characters
=cut
sub get_value
{
my ($self) = @_;
my $rv = Webmin::Input::get_value($self);
$rv =~ s/\r//g;
return $rv;
}
1;

80
Webmin/Textbox.pm Normal file
View File

@@ -0,0 +1,80 @@
package Webmin::Textbox;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Textbox(name, value, [size], [disabled])
Create a new text input field
=cut
sub new
{
if (defined(&Webmin::Theme::Textbox::new)) {
return new Webmin::Theme::Textbox(@_[1..$#_]);
}
my ($self, $name, $value, $size, $disabled) = @_;
$self = { 'size' => 30 };
bless($self);
$self->{'name'} = $name;
$self->{'value'} = $value;
$self->{'size'} = $size if ($size);
$self->set_disabled($disabled) if (defined($disabled));
return $self;
}
=head2 html()
Returns the HTML for this text input
=cut
sub html
{
my ($self) = @_;
return &ui_textbox($self->get_name(), $self->get_value(),
$self->{'size'},
$self->{'$disabled'});
}
sub set_size
{
my ($self, $size) = @_;
$self->{'size'} = $size;
}
sub set_validation_func
{
my ($self, $func) = @_;
$self->{'validation_func'} = $func;
}
=head2 set_validation_regexp(regexp, message)
=cut
sub set_validation_regexp
{
my ($self, $regexp, $message) = @_;
$self->{'validation_regexp'} = $regexp;
$self->{'validation_message'} = $message;
}
=head2 validate()
Returns a list of error messages for this field
=cut
sub validate
{
my ($self) = @_;
my $value = $self->get_value();
if ($self->{'mandatory'} && $value eq '') {
return ( $self->{'mandmesg'} || $text{'ui_mandatory'} );
}
if ($self->{'validation_func'}) {
my $err = &{$self->{'validation_func'}}($value, $self->{'name'},
$self->{'form'});
return ( $err ) if ($err);
}
if ($self->{'validation_regexp'}) {
if ($value !~ /$self->{'validation_regexp'}/) {
return ( $self->{'validation_message'} );
}
}
return ( );
}
1;

168
Webmin/Time.pm Normal file
View File

@@ -0,0 +1,168 @@
package Webmin::Time;
use Webmin::Input;
use Time::Local;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Time(name, time, [disabled])
Create a new field for selecting a time
=cut
sub new
{
if (defined(&Webmin::Theme::Time::new)) {
return new Webmin::Theme::Time(@_[1..$#_]);
}
my ($self, $name, $value, $disabled) = @_;
bless($self = { });
$self->set_name($name);
$self->set_value($value);
$self->set_disabled($disabled) if (defined($disabled));
return $self;
}
=head2 html()
Returns the HTML for the time chooser
=cut
sub html
{
my ($self) = @_;
my $rv;
my $val = $self->get_value();
my $hour = ($val/3600) % 24;
my $min = ($val/60) % 60;
my $sec = ($val/1) % 60;
my $name = $self->get_name();
$rv .= &ui_textbox("hour_".$name, pad2($hour), 2,$self->get_disabled()).":".
&ui_textbox("min_".$name, pad2($min), 2, $self->get_disabled()).":".
&ui_textbox("sec_".$name, pad2($sec), 2, $self->get_disabled());
return $rv;
}
sub pad2
{
return $_[0] < 10 ? "0".$_[0] : $_[0];
}
sub set_value
{
my ($self, $value) = @_;
$self->{'value'} = timegm(localtime($value));
}
=head2 get_value()
Returns the date as a Unix time number (for 1st jan 1970)
=cut
sub get_value
{
my ($self) = @_;
my $in = $self->{'form'} ? $self->{'form'}->{'in'} : undef;
if ($in && defined($in->{"hour_".$self->{'name'}})) {
my $rv = $self->to_time($in);
return defined($rv) ? $rv : $self->{'value'};
}
elsif ($in && defined($in->{"ui_value_".$self->{'name'}})) {
return $in->{"ui_value_".$self->{'name'}};
}
else {
return $self->{'value'};
}
}
sub to_time
{
my ($self, $in) = @_;
my $hour = $in->{"hour_".$self->{'name'}};
return undef if ($hour !~ /^\d+$/ || $hour < 0 || $hour > 23);
my $min = $in->{"min_".$self->{'name'}};
return undef if ($min !~ /^\d+$/ || $min < 0 || $min > 59);
my $sec = $in->{"sec_".$self->{'name'}};
return undef if ($sec !~ /^\d+$/ || $sec < 0 || $sec > 59);
return $hour*60*60 + $min*60 + $sec;
}
sub set_validation_func
{
my ($self, $func) = @_;
$self->{'validation_func'} = $func;
}
=head2 validate()
Ensures that the date is valid
=cut
sub validate
{
my ($self) = @_;
my $tm = $self->to_time($self->{'form'}->{'in'});
if (!defined($tm)) {
return ( $text{'ui_etime'} );
}
if ($self->{'validation_func'}) {
my $err = &{$self->{'validation_func'}}($self->get_value(),
$self->{'name'},
$self->{'form'});
return ( $err ) if ($err);
}
return ( );
}
=head2 set_auto(auto?)
If set to 1, the time will be automatically incremented by Javascript
=cut
sub set_auto
{
my ($self, $auto) = @_;
$self->{'auto'} = $auto;
if ($auto) {
# XXX incorrect!!
my $formno = $self->{'form'}->get_formno();
$self->{'form'}->add_onload("F=[0]; timeInit(F); setTimeout(\"timeUpdate(F)\", 5000)");
my $as = $autoscript;
$as =~ s/NAME/$self->{'name'}/g;
$self->{'form'}->add_script($as);
}
}
$autoscript = <<EOF;
function timeInit(F) {
secs = new Array();
mins = new Array();
hours = new Array();
for(i=0; i<F.length; i++){
secs[i] = document.forms[F[i]].sec_NAME;
mins[i] = document.forms[F[i]].min_NAME;
hours[i] = document.forms[F[i]].hour_NAME;
}
}
function timeUpdate(F) {
for(i=0; i<F.length; i++){
s = parseInt(secs[i].value);
s = s ? s : 0;
s = s+5;
if( s>59 ){
s -= 60;
m = parseInt(mins[i].value);
m= m ? m : 0;
m+=1;
if( m>59 ){
m -= 60;
h = parseInt(hours[i].value);
h = h ? h : 0;
h+=1;
if( h>23 ){
h -= 24;
}
hours[i].value = packNum(h);
}
mins[i].value = packNum(m);
}
secs[i].value = packNum(s);
}
setTimeout('timeUpdate(F)', 5000);
}
function packNum(t) {
return (t < 10 ? '0'+t : t);
}
EOF
1;

101
Webmin/TitleList.pm Normal file
View File

@@ -0,0 +1,101 @@
package Webmin::TitleList;
use WebminCore;
=head2 new Webmin::TitleList(title, &links, [alt-text])
Generates a title with a list of links under it
=cut
sub new
{
my ($self, $title, $links, $alt) = @_;
if (defined(&Webmin::Theme::TitleList::new)) {
return new Webmin::Theme::TitleList(@_[1..$#_]);
}
$self = { };
bless($self);
$self->set_title($title);
$self->set_links($links);
$self->set_alt($alt) if (defined($alt));
return $self;
}
=head2 html()
Returns the list
=cut
sub html
{
my ($self) = @_;
my $rv;
if (defined(&ui_subheading)) {
$rv .= &ui_subheading($self->get_title());
}
else {
$rv .= "<h3>".$self->get_title()."</h3>\n";
}
$rv .= "<hr>\n";
foreach my $l (@{$self->get_links()}) {
if ($l->[1]) {
$rv .= "<a href='$l->[1]'>$l->[0]</a><br>\n";
}
else {
$rv .= $l->[0]."<br>\n";
}
}
return $rv;
}
sub set_title
{
my ($self, $title) = @_;
$self->{'title'} = $title;
}
sub get_title
{
my ($self) = @_;
return $self->{'title'};
}
sub set_links
{
my ($self, $links) = @_;
$self->{'links'} = $links;
}
sub get_links
{
my ($self) = @_;
return $self->{'links'};
}
sub set_alt
{
my ($self, $alt) = @_;
$self->{'alt'} = $alt;
}
sub get_alt
{
my ($self) = @_;
return $self->{'alt'};
}
=head2 add_link(name, link)
Adds a link to be displayed in the list
=cut
sub add_link
{
my ($self, $name, $link) = @_;
push(@{$self->{'links'}}, [ $name, $link ]);
}
=head2 set_page(Webmin::Page)
Called when this menu is added to a page
=cut
sub set_page
{
my ($self, $page) = @_;
$self->{'page'} = $page;
}
1;

77
Webmin/Upload.pm Normal file
View File

@@ -0,0 +1,77 @@
package Webmin::Upload;
use Webmin::Input;
use WebminCore;
@ISA = ( "Webmin::Input" );
=head2 new Webmin::Upload(name, [size])
Create a new file upload field
=cut
sub new
{
if (defined(&Webmin::Theme::Upload::new)) {
return new Webmin::Theme::Upload(@_[1..$#_]);
}
my ($self, $name, $size) = @_;
$self = { 'size' => 30 };
bless($self);
$self->{'name'} = $name;
$self->{'size'} = $size if ($size);
return $self;
}
=head2 html()
Returns the HTML for this text input
=cut
sub html
{
my ($self) = @_;
return &ui_upload($self->get_name(), $self->{'size'},
$self->{'$disabled'});
}
sub set_size
{
my ($self, $size) = @_;
$self->{'size'} = $size;
}
sub set_validation_func
{
my ($self, $func) = @_;
$self->{'validation_func'} = $func;
}
=head2 set_validation_regexp(regexp, message)
=cut
sub set_validation_regexp
{
my ($self, $regexp, $message) = @_;
$self->{'validation_regexp'} = $regexp;
$self->{'validation_message'} = $message;
}
=head2 validate()
Returns a list of error messages for this field
=cut
sub validate
{
my ($self) = @_;
my $value = $self->get_value();
if ($self->{'mandatory'} && $value eq '') {
return ( $self->{'mandmesg'} || $text{'ui_mandatory'} );
}
if ($self->{'validation_func'}) {
my $err = &{$self->{'validation_func'}}($value, $self->{'name'},
$self->{'in'});
return ( $err ) if ($err);
}
if ($self->{'validation_regexp'}) {
if ($value !~ /$self->{'validation_regexp'}/) {
return ( $self->{'validation_message'} );
}
}
return ( );
}
1;

57
Webmin/User.pm Normal file
View File

@@ -0,0 +1,57 @@
package Webmin::User;
use Webmin::Textbox;
use WebminCore;
@ISA = ( "Webmin::Textbox" );
=head2 new Webmin::User(name, value, [multiple], [disabled])
A text box for entering or selecting one or many Unix usernames
=cut
sub new
{
if (defined(&Webmin::Theme::User::new)) {
return new Webmin::Theme::User(@_[1..$#_]);
}
my ($self, $name, $value, $multiple, $disabled) = @_;
$self = new Webmin::Textbox($name, $value, $multiple ? 40 : 15, $disabled);
bless($self);
$self->set_multiple($multiple);
return $self;
}
=head2 html()
Returns the HTML for this user input
=cut
sub html
{
my ($self) = @_;
my $rv = Webmin::Textbox::html($self);
my $name = $self->get_name();
my $multiple = $self->get_multiple();
local $w = $multiple ? 500 : 300;
$rv .= "&nbsp;<input type=button name=${name}_button onClick='ifield = form.$name; chooser = window.open(\"$gconfig{'webprefix'}/user_chooser.cgi?multi=$multiple&user=\"+escape(ifield.value), \"chooser\", \"toolbar=no,menubar=no,scrollbars=yes,width=$w,height=200\"); chooser.ifield = ifield; window.ifield = ifield' value=\"...\">\n";
return $rv;
}
sub set_multiple
{
my ($self, $multiple) = @_;
$self->{'multiple'} = $multiple;
}
sub get_multiple
{
my ($self) = @_;
return $self->{'multiple'};
}
=head2 get_input_names()
Returns the actual names of all HTML elements that make up this input
=cut
sub get_input_names
{
my ($self) = @_;
return ( $self->{'name'}, $self->{'name'}."_button" );
}
1;