+ $code .= qq|<link rel="stylesheet" href="${file}" type="text/css" media="screen" />|;
+ }
+
+ return $code;
+}
+
+my $date_tag_id_idx = 0;
+sub date_tag {
+ my ($self, $name, $value, %params) = _hashify(3, @_);
+
+ _set_id_attribute(\%params, $name);
+ my @onchange = $params{onchange} ? (onChange => delete $params{onchange}) : ();
+ my @classes = $params{no_cal} || $params{readonly} ? () : ('datepicker');
+ push @classes, delete($params{class}) if $params{class};
+ my %class = @classes ? (class => join(' ', @classes)) : ();
+
+ return $self->input_tag(
+ $name, blessed($value) ? $value->to_lxoffice : $value,
+ size => 11,
+ onblur => "check_right_date_format(this);",
+ %params,
+ %class, @onchange,
+ );
+}
+
+sub customer_picker {
+ my ($self, $name, $value, %params) = @_;
+ my $name_e = _H($name);
+
+ $::request->{layout}->add_javascripts('autocomplete_customer.js');
+
+ $self->hidden_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => 'customer_autocomplete') .
+ $self->input_tag("$name_e\_name", (ref $value && $value->can('name')) ? $value->name : '', %params);
+}
+
+# simple version with select_tag
+sub vendor_selector {
+ my ($self, $name, $value, %params) = @_;
+
+ my $actual_vendor_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"}) ? $::form->{"$name"}->id : $::form->{"$name"}) :
+ (ref $value && $value->can('id')) ? $value->id : '';
+
+ return $self->select_tag($name, SL::DB::Manager::Vendor->get_all(),
+ default => $actual_vendor_id,
+ title_sub => sub { $_[0]->vendornumber . " : " . $_[0]->name },
+ 'with_empty' => 1,
+ %params);
+}
+
+
+# simple version with select_tag
+sub part_selector {
+ my ($self, $name, $value, %params) = @_;
+
+ my $actual_part_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"})? $::form->{"$name"}->id : $::form->{"$name"}) :
+ (ref $value && $value->can('id')) ? $value->id : '';
+
+ return $self->select_tag($name, SL::DB::Manager::Part->get_all(),
+ default => $actual_part_id,
+ title_sub => sub { $_[0]->partnumber . " : " . $_[0]->description },
+ with_empty => 1,
+ %params);
+}
+
+
+sub javascript_tag {
+ my $self = shift;
+ my $code = '';
+
+ foreach my $file (@_) {
+ $file .= '.js' unless $file =~ m/\.js$/;
+ $file = "js/${file}" unless $file =~ m|/|;
+
+ $code .= qq|<script type="text/javascript" src="${file}"></script>|;
+ }
+
+ return $code;
+}
+
+sub tabbed {
+ my ($self, $tabs, %params) = _hashify(2, @_);
+ my $id = $params{id} || 'tab_' . _tag_id();
+
+ $params{selected} *= 1;
+
+ die 'L.tabbed needs an arrayred of tabs for first argument'
+ unless ref $tabs eq 'ARRAY';
+
+ my (@header, @blocks);
+ for my $i (0..$#$tabs) {
+ my $tab = $tabs->[$i];
+
+ next if $tab eq '';
+
+ my $tab_id = "__tab_id_$i";
+ push @header, $self->li_tag($self->link('#' . $tab_id, $tab->{name}));
+ push @blocks, $self->div_tag($tab->{data}, id => $tab_id);
+ }
+
+ return '' unless @header;
+
+ my $ul = $self->ul_tag(join('', @header), id => $id);
+ return $self->div_tag(join('', $ul, @blocks), class => 'tabwidget');
+}
+
+sub tab {
+ my ($self, $name, $src, %params) = _hashify(3, @_);
+
+ $params{method} ||= 'process';
+
+ return () if defined $params{if} && !$params{if};
+
+ my $data;
+ if ($params{method} eq 'raw') {
+ $data = $src;
+ } elsif ($params{method} eq 'process') {
+ $data = $self->_context->process($src, %{ $params{args} || {} });
+ } else {
+ die "unknown tag method '$params{method}'";
+ }
+
+ return () unless $data;
+
+ return +{ name => $name, data => $data };
+}
+
+sub areainput_tag {
+ my ($self, $name, $value, %attributes) = _hashify(3, @_);
+
+ my ($rows, $cols);
+ my $min = delete $attributes{min_rows} || 1;
+
+ if (exists $attributes{cols}) {
+ $cols = delete $attributes{cols};
+ $rows = $::form->numtextrows($value, $cols);
+ } else {
+ $rows = delete $attributes{rows} || 1;
+ }
+
+ return $rows > 1
+ ? $self->textarea_tag($name, $value, %attributes, rows => max($rows, $min), ($cols ? (cols => $cols) : ()))
+ : $self->input_tag($name, $value, %attributes, ($cols ? (size => $cols) : ()));
+}
+
+sub multiselect2side {
+ my ($self, $id, %params) = _hashify(2, @_);
+
+ $params{labelsx} = "\"" . _J($params{labelsx} || $::locale->text('Available')) . "\"";
+ $params{labeldx} = "\"" . _J($params{labeldx} || $::locale->text('Selected')) . "\"";
+ $params{moveOptions} = 'false';
+
+ my $vars = join(', ', map { "${_}: " . $params{$_} } keys %params);
+ my $code = <<EOCODE;
+<script type="text/javascript">
+ \$().ready(function() {
+ \$('#${id}').multiselect2side({ ${vars} });
+ });
+</script>
+EOCODE
+
+ return $code;
+}
+
+sub sortable_element {
+ my ($self, $selector, %params) = _hashify(2, @_);
+
+ my %attributes = ( distance => 5,
+ helper => <<'JAVASCRIPT' );
+ function(event, ui) {
+ ui.children().each(function() {
+ $(this).width($(this).width());
+ });
+ return ui;