1 package SL::Template::Plugin::L;
3 use base qw( Template::Plugin );
5 use List::MoreUtils qw(apply);
6 use List::Util qw(max);
7 use Scalar::Util qw(blessed);
13 { # This will give you an id for identifying html tags and such.
14 # It's guaranteed to be unique unless you exceed 10 mio calls per request.
15 # Do not use these id's to store information across requests.
16 my $_id_sequence = int rand 1e7;
18 return "id_" . ( $_id_sequence = ($_id_sequence + 1) % 1e7 );
22 my %_valueless_attributes = map { $_ => 1 } qw(
23 checked compact declare defer disabled ismap multiple noresize noshade nowrap
29 return $::locale->quote_special_chars('HTML', $string);
34 $string =~ s/(\"|\'|\\)/\\$1/g;
39 return (@_ && (ref($_[0]) eq 'HASH')) ? %{ $_[0] } : @_;
43 my ($class, $context, @args) = @_;
51 die 'not an accessor' if @_ > 1;
52 return $_[0]->{CONTEXT};
56 my ($method, @args) = @_;
58 my $presenter = $::request->presenter;
60 return '' unless $presenter->can($method);
62 splice @args, -1, 1, %{ $args[-1] } if @args && (ref($args[-1]) eq 'HASH');
64 $presenter->$method(@args);
71 $name =~ s/[^\w_]/_/g;
78 my ($self, @slurp) = @_;
79 my %options = _hashify(@slurp);
82 while (my ($name, $value) = each %options) {
84 next if $_valueless_attributes{$name} && !$value;
85 $value = '' if !defined($value);
86 push @result, $_valueless_attributes{$name} ? _H($name) : _H($name) . '="' . _H($value) . '"';
89 return @result ? ' ' . join(' ', @result) : '';
93 my ($self, $tag, $content, @slurp) = @_;
94 my $attributes = $self->attributes(@slurp);
96 return "<${tag}${attributes}>" unless defined($content);
97 return "<${tag}${attributes}>${content}</${tag}>";
101 my ($self, @slurp) = @_;
102 my %options = _hashify(@slurp);
104 $options{alt} ||= '';
106 return $self->html_tag('img', undef, %options);
112 my $collection = shift;
113 my %attributes = _hashify(@_);
115 $attributes{id} ||= $self->name_to_id($name);
117 my $value_key = delete($attributes{value_key}) || 'id';
118 my $title_key = delete($attributes{title_key}) || $value_key;
119 my $default_key = delete($attributes{default_key}) || 'selected';
122 my $value_title_sub = delete($attributes{value_title_sub});
124 my $value_sub = delete($attributes{value_sub});
125 my $title_sub = delete($attributes{title_sub});
126 my $default_sub = delete($attributes{default_sub});
128 my $with_empty = delete($attributes{with_empty});
129 my $empty_title = delete($attributes{empty_title});
131 my $with_optgroups = delete($attributes{with_optgroups});
135 if ( ref($attributes{default}) eq 'ARRAY' ) {
137 foreach my $entry (@{$attributes{default}}) {
138 $selected{$entry} = 1;
140 } elsif ( defined($attributes{default}) ) {
141 $selected{$attributes{default}} = 1;
144 delete($attributes{default});
148 push @all_options, [undef, $empty_title || ''] if $with_empty;
150 my $normalize_entry = sub {
151 my ($type, $entry, $sub, $key) = @_;
153 return $sub->($entry) if $sub;
155 my $ref = ref($entry);
158 return $entry if $type eq 'value' || $type eq 'title';
162 if ( $ref eq 'ARRAY' ) {
163 return $entry->[ $type eq 'value' ? 0 : $type eq 'title' ? 1 : 2 ];
166 return $entry->{$key} if $ref eq 'HASH';
167 return $entry->$key if $type ne 'default' || $entry->can($key);
171 my $list_to_code = sub {
172 my ($sub_collection) = @_;
175 foreach my $entry ( @{ $sub_collection } ) {
179 if ( $value_title_sub ) {
180 ($value, $title) = @{ $value_title_sub->($entry) };
183 $value = $normalize_entry->('value', $entry, $value_sub, $value_key);
184 $title = $normalize_entry->('title', $entry, $title_sub, $title_key);
187 my $default = $normalize_entry->('default', $entry, $default_sub, $default_key);
189 push(@options, [$value, $title, $default]);
192 foreach my $entry (@options) {
193 $entry->[2] = 1 if $selected{$entry->[0]};
196 return join '', map { $self->html_tag('option', _H($_->[1]), value => $_->[0], selected => $_->[2]) } @options;
201 if (!$with_optgroups) {
202 $code = $list_to_code->($collection);
205 $code = join '', map {
206 my ($optgroup_title, $sub_collection) = @{ $_ };
207 $self->html_tag('optgroup', $list_to_code->($sub_collection), label => $optgroup_title)
211 return $self->html_tag('select', $code, %attributes, name => $name);
215 my ($self, $name, $content, @slurp) = @_;
216 my %attributes = _hashify(@slurp);
218 $attributes{id} ||= $self->name_to_id($name);
219 $attributes{rows} *= 1; # required by standard
220 $attributes{cols} *= 1; # required by standard
221 $content = $content ? _H($content) : '';
223 return $self->html_tag('textarea', $content, %attributes, name => $name);
227 my ($self, $name, @slurp) = @_;
228 my %attributes = _hashify(@slurp);
230 $attributes{id} ||= $self->name_to_id($name);
231 $attributes{value} = 1 unless defined $attributes{value};
232 my $label = delete $attributes{label};
233 my $checkall = delete $attributes{checkall};
235 if ($attributes{checked}) {
236 $attributes{checked} = 'checked';
238 delete $attributes{checked};
241 my $code = $self->html_tag('input', undef, %attributes, name => $name, type => 'checkbox');
242 $code .= $self->html_tag('label', $label, for => $attributes{id}) if $label;
243 $code .= $self->javascript(qq|\$('#$attributes{id}').checkall('$checkall');|) if $checkall;
248 sub radio_button_tag {
251 my %attributes = _hashify(@_);
253 $attributes{value} = 1 unless defined $attributes{value};
254 $attributes{id} ||= $self->name_to_id($name . "_" . $attributes{value});
255 my $label = delete $attributes{label};
257 if ($attributes{checked}) {
258 $attributes{checked} = 'checked';
260 delete $attributes{checked};
263 my $code = $self->html_tag('input', undef, %attributes, name => $name, type => 'radio');
264 $code .= $self->html_tag('label', $label, for => $attributes{id}) if $label;
270 my ($self, $name, $value, @slurp) = @_;
271 my %attributes = _hashify(@slurp);
273 $attributes{id} ||= $self->name_to_id($name);
274 $attributes{type} ||= 'text';
276 return $self->html_tag('input', undef, %attributes, name => $name, value => $value);
280 my ($self, $name, $value, @slurp) = @_;
281 return $self->input_tag($name, $value, _hashify(@slurp), type => 'hidden');
285 my ($self, $content, @slurp) = @_;
286 return $self->html_tag('div', $content, @slurp);
290 my ($self, $content, @slurp) = @_;
291 return $self->html_tag('ul', $content, @slurp);
295 my ($self, $content, @slurp) = @_;
296 return $self->html_tag('li', $content, @slurp);
300 my ($self, $href, $content, @slurp) = @_;
301 my %params = _hashify(@slurp);
305 return $self->html_tag('a', $content, %params, href => $href);
309 my ($self, $name, $value, @slurp) = @_;
310 my %attributes = _hashify(@slurp);
312 if ( $attributes{confirm} ) {
313 $attributes{onclick} = 'return confirm("'. _J(delete($attributes{confirm})) .'");';
316 return $self->input_tag($name, $value, %attributes, type => 'submit', class => 'submit');
320 my ($self, $onclick, $value, @slurp) = @_;
321 my %attributes = _hashify(@slurp);
323 $attributes{id} ||= $self->name_to_id($attributes{name}) if $attributes{name};
324 $attributes{type} ||= 'button';
326 return $self->html_tag('input', undef, %attributes, value => $value, onclick => $onclick);
330 my ($self, $name, $value) = splice @_, 0, 3;
331 my %attributes = _hashify(@_);
333 return $self->select_tag($name, [ [ 1 => $::locale->text('Yes') ], [ 0 => $::locale->text('No') ] ], default => $value ? 1 : 0, %attributes);
337 my ($self, $data) = @_;
338 return $self->html_tag('script', $data, type => 'text/javascript');
345 foreach my $file (@_) {
346 $file .= '.css' unless $file =~ m/\.css$/;
347 $file = "css/${file}" unless $file =~ m|/|;
349 $code .= qq|<link rel="stylesheet" href="${file}" type="text/css" media="screen" />|;
355 my $date_tag_id_idx = 0;
357 my ($self, $name, $value, @slurp) = @_;
359 my %params = _hashify(@slurp);
360 my $id = $self->name_to_id($name) . _tag_id();
361 my @onchange = $params{onchange} ? (onChange => delete $params{onchange}) : ();
362 my @class = $params{no_cal} || $params{readonly} ? () : (class => 'datepicker');
364 return $self->input_tag(
365 $name, blessed($value) ? $value->to_lxoffice : $value,
368 onblur => "check_right_date_format(this);",
374 sub customer_picker {
375 my ($self, $name, $value, %params) = @_;
376 my $name_e = _H($name);
378 $::request->{layout}->add_javascripts('autocomplete_customer.js');
380 $self->hidden_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => 'customer_autocomplete') .
381 $self->input_tag("$name_e\_name", (ref $value && $value->can('name')) ? $value->name : '', %params);
384 # simple version with select_tag
385 sub vendor_selector {
386 my ($self, $name, $value, %params) = @_;
388 my $actual_vendor_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"}) ? $::form->{"$name"}->id : $::form->{"$name"}) :
389 (ref $value && $value->can('id')) ? $value->id : '';
391 return $self->select_tag($name, SL::DB::Manager::Vendor->get_all(),
392 default => $actual_vendor_id,
393 title_sub => sub { $_[0]->vendornumber . " : " . $_[0]->name },
399 # simple version with select_tag
401 my ($self, $name, $value, %params) = @_;
403 my $actual_part_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"})? $::form->{"$name"}->id : $::form->{"$name"}) :
404 (ref $value && $value->can('id')) ? $value->id : '';
406 return $self->select_tag($name, SL::DB::Manager::Part->get_all(),
407 default => $actual_part_id,
408 title_sub => sub { $_[0]->partnumber . " : " . $_[0]->description },
418 foreach my $file (@_) {
419 $file .= '.js' unless $file =~ m/\.js$/;
420 $file = "js/${file}" unless $file =~ m|/|;
422 $code .= qq|<script type="text/javascript" src="${file}"></script>|;
429 my ($self, $tabs, @slurp) = @_;
430 my %params = _hashify(@slurp);
431 my $id = $params{id} || 'tab_' . _tag_id();
433 $params{selected} *= 1;
435 die 'L.tabbed needs an arrayred of tabs for first argument'
436 unless ref $tabs eq 'ARRAY';
438 my (@header, @blocks);
439 for my $i (0..$#$tabs) {
440 my $tab = $tabs->[$i];
444 my $tab_id = "__tab_id_$i";
445 push @header, $self->li_tag($self->link('#' . $tab_id, $tab->{name}));
446 push @blocks, $self->div_tag($tab->{data}, id => $tab_id);
449 return '' unless @header;
451 my $ul = $self->ul_tag(join('', @header), id => $id);
452 return $self->div_tag(join('', $ul, @blocks), class => 'tabwidget');
456 my ($self, $name, $src, @slurp) = @_;
457 my %params = _hashify(@slurp);
459 $params{method} ||= 'process';
461 return () if defined $params{if} && !$params{if};
464 if ($params{method} eq 'raw') {
466 } elsif ($params{method} eq 'process') {
467 $data = $self->_context->process($src, %{ $params{args} || {} });
469 die "unknown tag method '$params{method}'";
472 return () unless $data;
474 return +{ name => $name, data => $data };
478 my ($self, $name, $value, @slurp) = @_;
479 my %attributes = _hashify(@slurp);
482 my $min = delete $attributes{min_rows} || 1;
484 if (exists $attributes{cols}) {
485 $cols = delete $attributes{cols};
486 $rows = $::form->numtextrows($value, $cols);
488 $rows = delete $attributes{rows} || 1;
492 ? $self->textarea_tag($name, $value, %attributes, rows => max($rows, $min), ($cols ? (cols => $cols) : ()))
493 : $self->input_tag($name, $value, %attributes, ($cols ? (size => $cols) : ()));
496 sub multiselect2side {
497 my ($self, $id, @slurp) = @_;
498 my %params = _hashify(@slurp);
500 $params{labelsx} = "\"" . _J($params{labelsx} || $::locale->text('Available')) . "\"";
501 $params{labeldx} = "\"" . _J($params{labeldx} || $::locale->text('Selected')) . "\"";
502 $params{moveOptions} = 'false';
504 my $vars = join(', ', map { "${_}: " . $params{$_} } keys %params);
506 <script type="text/javascript">
507 \$().ready(function() {
508 \$('#${id}').multiselect2side({ ${vars} });
516 sub sortable_element {
517 my ($self, $selector, @slurp) = @_;
518 my %params = _hashify(@slurp);
520 my %attributes = ( distance => 5,
521 helper => <<'JAVASCRIPT' );
522 function(event, ui) {
523 ui.children().each(function() {
524 $(this).width($(this).width());
532 if ($params{url} && $params{with}) {
533 my $as = $params{as} || $params{with};
534 my $filter = ".filter(function(idx) { return this.substr(0, " . length($params{with}) . ") == '$params{with}'; })";
535 $filter .= ".map(function(idx, str) { return str.replace('$params{with}_', ''); })";
537 $stop_event = <<JAVASCRIPT;
538 \$.post('$params{url}', { '${as}[]': \$(\$('${selector}').sortable('toArray'))${filter}.toArray() });
542 if (!$params{dont_recolor}) {
543 $stop_event .= <<JAVASCRIPT;
544 \$('${selector}>*:odd').removeClass('listrow1').removeClass('listrow0').addClass('listrow0');
545 \$('${selector}>*:even').removeClass('listrow1').removeClass('listrow0').addClass('listrow1');
550 $attributes{stop} = <<JAVASCRIPT;
551 function(event, ui) {
558 $params{handle} = '.dragdrop' unless exists $params{handle};
559 $attributes{handle} = "'$params{handle}'" if $params{handle};
561 my $attr_str = join(', ', map { "${_}: $attributes{$_}" } keys %attributes);
563 my $code = <<JAVASCRIPT;
564 <script type="text/javascript">
566 \$( "${selector}" ).sortable({ ${attr_str} })
574 sub online_help_tag {
575 my ($self, $tag, @slurp) = @_;
576 my %params = _hashify(@slurp);
577 my $cc = $::myconfig{countrycode};
578 my $file = "doc/online/$cc/$tag.html";
579 my $text = $params{text} || $::locale->text('Help');
581 die 'malformed help tag' unless $tag =~ /^[a-zA-Z0-9_]+$/;
582 return unless -f $file;
583 return $self->html_tag('a', $text, href => $file, class => 'jqModal')
588 require Data::Dumper;
589 return '<pre>' . Data::Dumper::Dumper(@_) . '</pre>';
594 return _call_presenter('truncate', @_);
597 sub sortable_table_header {
598 my ($self, $by, @slurp) = @_;
599 my %params = _hashify(@slurp);
601 my $controller = $self->{CONTEXT}->stash->get('SELF');
602 my $sort_spec = $controller->get_sort_spec;
603 my $by_spec = $sort_spec->{$by};
604 my %current_sort_params = $controller->get_current_sort_params;
605 my ($image, $new_dir) = ('', $current_sort_params{dir});
606 my $title = delete($params{title}) || $::locale->text($by_spec->{title});
608 if ($current_sort_params{by} eq $by) {
609 my $current_dir = $current_sort_params{dir} ? 'up' : 'down';
610 $image = '<img border="0" src="image/' . $current_dir . '.png">';
611 $new_dir = 1 - ($current_sort_params{dir} || 0);
614 $params{ $sort_spec->{FORM_PARAMS}->[0] } = $by;
615 $params{ $sort_spec->{FORM_PARAMS}->[1] } = ($new_dir ? '1' : '0');
617 return '<a href="' . $controller->get_callback(%params) . '">' . _H($title) . $image . '</a>';
620 sub paginate_controls {
623 my $controller = $self->{CONTEXT}->stash->get('SELF');
624 my $paginate_spec = $controller->get_paginate_spec;
625 my %paginate_params = $controller->get_current_paginate_params;
627 my %template_params = (
628 pages => \%paginate_params,
630 my %url_params = _hashify(@_);
631 $url_params{ $paginate_spec->{FORM_PARAMS}->[0] } = delete $url_params{page};
632 $url_params{ $paginate_spec->{FORM_PARAMS}->[1] } = delete $url_params{per_page} if exists $url_params{per_page};
634 return $controller->get_callback(%url_params);
638 return SL::Presenter->get->render('common/paginate', %template_params);
643 return _call_presenter('simple_format', @_);
652 SL::Templates::Plugin::L -- Layouting / tag generation
656 Usage from a template:
660 [% L.select_tag('direction', [ [ 'left', 'To the left' ], [ 'right', 'To the right', 1 ] ]) %]
662 [% L.select_tag('direction', [ { direction => 'left', display => 'To the left' },
663 { direction => 'right', display => 'To the right' } ],
664 value_key => 'direction', title_key => 'display', default => 'right')) %]
666 [% L.select_tag('direction', [ { direction => 'left', display => 'To the left' },
667 { direction => 'right', display => 'To the right', selected => 1 } ],
668 value_key => 'direction', title_key => 'display')) %]
672 A module modeled a bit after Rails' ActionView helpers. Several small
673 functions that create HTML tags from various kinds of data sources.
677 =head2 LOW-LEVEL FUNCTIONS
681 =item C<name_to_id $name>
683 Converts a name to a HTML id by replacing various characters.
685 =item C<attributes %items>
687 Creates a string from all elements in C<%items> suitable for usage as
688 HTML tag attributes. Keys and values are HTML escaped even though keys
689 must not contain non-ASCII characters for browsers to accept them.
691 =item C<html_tag $tag_name, $content_string, %attributes>
693 Creates an opening and closing HTML tag for C<$tag_name> and puts
694 C<$content_string> between the two. If C<$content_string> is undefined
695 or empty then only a E<lt>tag/E<gt> tag will be created. Attributes
696 are key/value pairs added to the opening tag.
698 C<$content_string> is not HTML escaped.
702 =head2 HIGH-LEVEL FUNCTIONS
706 =item C<select_tag $name, \@collection, %attributes>
708 Creates a HTML 'select' tag named C<$name> with the contents of one
709 'E<lt>optionE<gt>' tag for each element in C<\@collection> and with arbitrary
710 HTML attributes from C<%attributes>. The value
711 to use and the title to display are extracted from the elements in
712 C<\@collection>. Each element can be one of four things:
716 =item 1. An array reference with at least two elements. The first element is
717 the value, the second element is its title. The third element is optional and and should contain a boolean.
718 If it is true, than the element will be used as default.
720 =item 2. A scalar. The scalar is both the value and the title.
722 =item 3. A hash reference. In this case C<%attributes> must contain
723 I<value_key>, I<title_key> and may contain I<default_key> keys that name the keys in the element to use
724 for the value, title and default respectively.
726 =item 4. A blessed reference. In this case C<%attributes> must contain
727 I<value_key>, I<title_key> and may contain I<default_key> keys that name functions called on the blessed
728 reference whose return values are used as the value, title and default
733 For cases 3 and 4 C<$attributes{value_key}> defaults to C<id>,
734 C<$attributes{title_key}> defaults to C<$attributes{value_key}>
735 and C<$attributes{default_key}> defaults to C<selected>.
737 In addition to pure keys/method you can also provide coderefs as I<value_sub>
738 and/or I<title_sub> and/or I<default_sub>. If present, these take precedence over keys or methods,
739 and are called with the element as first argument. It must return the value, title or default.
741 Lastly a joint coderef I<value_title_sub> may be provided, which in turn takes
742 precedence over the C<value_sub> and C<title_sub> subs. It will only be called once for each
743 element and must return a list of value and title.
745 If the option C<with_empty> is set then an empty element (value
746 C<undef>) will be used as the first element. The title to display for
747 this element can be set with the option C<empty_title> and defaults to
750 The option C<default> can be either a scalar or an array reference
751 containing the values of the options which should be set to be
754 The tag's C<id> defaults to C<name_to_id($name)>.
756 If the option C<with_optgroups> is set then this function expects
757 C<\@collection> to be one level deeper. The upper-most level is
758 translated into a HTML C<optgroup> tag. So the structure becomes:
762 =item 1. Array of array references. Each element in the
763 C<\@collection> is converted into an optgroup.
765 =item 2. The optgroup's C<label> attribute will be set to the the
766 first element in the array element. The second array element is then
767 converted to a list of C<option> tags like it is described above.
771 Example for use of optgroups:
773 # First in a controller:
775 [ t8("First optgroup with two items"),
776 [ { id => 42, name => "item one" },
777 { id => 54, name => "second item" },
778 { id => 23, name => "and the third one" },
780 [ t8("Another optgroup, with a lot of items from Rose"),
781 SL::DB::Manager::Customer->get_all_sorted ],
784 # Later in the template:
785 [% L.select_tag('the_selection', COLLECTION, with_optgroups=1, title_key='name') %]
787 =item C<yes_no_tag $name, $value, %attributes>
789 Creates a HTML 'select' tag with the two entries C<yes> and C<no> by
790 calling L<select_tag>. C<$value> determines
791 which entry is selected. The C<%attributes> are passed through to
794 =item C<input_tag $name, $value, %attributes>
796 Creates a HTML 'input type=text' tag named C<$name> with the value
797 C<$value> and with arbitrary HTML attributes from C<%attributes>. The
798 tag's C<id> defaults to C<name_to_id($name)>.
800 =item C<hidden_tag $name, $value, %attributes>
802 Creates a HTML 'input type=hidden' tag named C<$name> with the value
803 C<$value> and with arbitrary HTML attributes from C<%attributes>. The
804 tag's C<id> defaults to C<name_to_id($name)>.
806 =item C<submit_tag $name, $value, %attributes>
808 Creates a HTML 'input type=submit class=submit' tag named C<$name> with the
809 value C<$value> and with arbitrary HTML attributes from C<%attributes>. The
810 tag's C<id> defaults to C<name_to_id($name)>.
812 If C<$attributes{confirm}> is set then a JavaScript popup dialog will
813 be added via the C<onclick> handler asking the question given with
814 C<$attributes{confirm}>. If request is only submitted if the user
815 clicks the dialog's ok/yes button.
817 =item C<textarea_tag $name, $value, %attributes>
819 Creates a HTML 'textarea' tag named C<$name> with the content
820 C<$value> and with arbitrary HTML attributes from C<%attributes>. The
821 tag's C<id> defaults to C<name_to_id($name)>.
823 =item C<checkbox_tag $name, %attributes>
825 Creates a HTML 'input type=checkbox' tag named C<$name> with arbitrary
826 HTML attributes from C<%attributes>. The tag's C<id> defaults to
827 C<name_to_id($name)>. The tag's C<value> defaults to C<1>.
829 If C<%attributes> contains a key C<label> then a HTML 'label' tag is
830 created with said C<label>. No attribute named C<label> is created in
833 If C<%attributes> contains a key C<checkall> then the value is taken as a
834 JQuery selector and clicking this checkbox will also toggle all checkboxes
835 matching the selector.
837 =item C<date_tag $name, $value, %attributes>
839 Creates a date input field, with an attached javascript that will open a
842 =item C<radio_button_tag $name, %attributes>
844 Creates a HTML 'input type=radio' tag named C<$name> with arbitrary
845 HTML attributes from C<%attributes>. The tag's C<value> defaults to
846 C<1>. The tag's C<id> defaults to C<name_to_id($name . "_" . $value)>.
848 If C<%attributes> contains a key C<label> then a HTML 'label' tag is
849 created with said C<label>. No attribute named C<label> is created in
852 =item C<javascript_tag $file1, $file2, $file3...>
854 Creates a HTML 'E<lt>script type="text/javascript" src="..."E<gt>'
855 tag for each file name parameter passed. Each file name will be
856 postfixed with '.js' if it isn't already and prefixed with 'js/' if it
857 doesn't contain a slash.
859 =item C<stylesheet_tag $file1, $file2, $file3...>
861 Creates a HTML 'E<lt>link rel="text/stylesheet" href="..."E<gt>' tag
862 for each file name parameter passed. Each file name will be postfixed
863 with '.css' if it isn't already and prefixed with 'css/' if it doesn't
866 =item C<tabbed \@tab, %attributes>
868 Will create a tabbed area. The tabs should be created with the helper function
872 L.tab(LxERP.t8('Basic Data'), 'part/_main_tab.html'),
873 L.tab(LxERP.t8('Custom Variables'), 'part/_cvar_tab.html', if => SELF.display_cvar_tab),
876 =item C<areainput_tag $name, $content, %PARAMS>
878 Creates a generic input tag or textarea tag, depending on content size. The
879 amount of desired rows must be either given with the C<rows> parameter or can
880 be computed from the value and the C<cols> paramter, Accepted parameters
881 include C<min_rows> for rendering a minimum of rows if a textarea is displayed.
883 You can force input by setting rows to 1, and you can force textarea by setting
886 =item C<multiselect2side $id, %params>
888 Creates a JavaScript snippet calling the jQuery function
889 C<multiselect2side> on the select control with the ID C<$id>. The
890 select itself is not created. C<%params> can contain the following
897 The label of the list of available options. Defaults to the
898 translation of 'Available'.
902 The label of the list of selected options. Defaults to the
903 translation of 'Selected'.
907 =item C<sortable_element $selector, %params>
909 Makes the children of the DOM element C<$selector> (a jQuery selector)
910 sortable with the I<jQuery UI Selectable> library. The children can be
911 dragged & dropped around. After dropping an element an URL can be
912 postet to with the element IDs of the sorted children.
914 If this is used then the JavaScript file C<js/jquery-ui.js> must be
915 included manually as well as it isn't loaded via C<$::form-gt;header>.
917 C<%params> can contain the following entries:
923 The URL to POST an AJAX request to after a dragged element has been
924 dropped. The AJAX request's return value is ignored. If given then
925 C<$params{with}> must be given as well.
929 A string that is interpreted as the prefix of the children's ID. Upon
930 POSTing the result each child whose ID starts with C<$params{with}> is
931 considered. The prefix and the following "_" is removed from the
932 ID. The remaining parts of the IDs of those children are posted as a
933 single array parameter. The array parameter's name is either
934 C<$params{as}> or, missing that, C<$params{with}>.
938 Sets the POST parameter name for AJAX request after dropping an
939 element (see C<$params{with}>).
943 An optional jQuery selector specifying which part of the child element
944 is dragable. If the parameter is not given then it defaults to
945 C<.dragdrop> matching DOM elements with the class C<dragdrop>. If the
946 parameter is set and empty then the whole child element is dragable,
947 and clicks through to underlying elements like inputs or links might
950 =item C<dont_recolor>
952 If trueish then the children will not be recolored. The default is to
953 recolor the children by setting the class C<listrow0> on odd and
954 C<listrow1> on even entries.
960 <script type="text/javascript" src="js/jquery-ui.js"></script>
962 <table id="thing_list">
964 <tr><td>This</td><td>That</td></tr>
967 <tr id="thingy_2"><td>stuff</td><td>more stuff</td></tr>
968 <tr id="thingy_15"><td>stuff</td><td>more stuff</td></tr>
969 <tr id="thingy_6"><td>stuff</td><td>more stuff</td></tr>
973 [% L.sortable_element('#thing_list tbody',
974 url => 'controller.pl?action=SystemThings/reorder',
977 recolor_rows => 1) %]
979 After dropping e.g. the third element at the top of the list a POST
980 request would be made to the C<reorder> action of the C<SystemThings>
981 controller with a single parameter called C<thing_ids> -- an array
982 containing the values C<[ 6, 2, 15 ]>.
986 Dumps the Argument using L<Data::Dumper> into a E<lt>preE<gt> block.
988 =item C<sortable_table_header $by, %params>
990 Create a link and image suitable for placement in a table
991 header. C<$by> must be an index set up by the controller with
992 L<SL::Controller::Helper::make_sorted>.
994 The optional parameter C<$params{title}> can override the column title
995 displayed to the user. Otherwise the column title from the
996 controller's sort spec is used.
998 The other parameters in C<%params> are passed unmodified to the
999 underlying call to L<SL::Controller::Base::url_for>.
1001 See the documentation of L<SL::Controller::Helper::Sorted> for an
1002 overview and further usage instructions.
1004 =item C<paginate_controls>
1006 Create a set of links used to paginate a list view.
1008 See the documentation of L<SL::Controller::Helper::Paginated> for an
1009 overview and further usage instructions.
1013 =head2 CONVERSION FUNCTIONS
1017 =item C<tab, description, target, %PARAMS>
1019 Creates a tab for C<tabbed>. The description will be used as displayed name.
1020 The target should be a block or template that can be processed. C<tab> supports
1021 a C<method> parameter, which can override the process method to apply target.
1022 C<method => 'raw'> will just include the given text as is. I was too lazy to
1023 implement C<include> properly.
1025 Also an C<if> attribute is supported, so that tabs can be suppressed based on
1026 some occasion. In this case the supplied block won't even get processed, and
1027 the resulting tab will get ignored by C<tabbed>:
1029 L.tab('Awesome tab wih much info', '_much_info.html', if => SELF.wants_all)
1031 =item C<truncate $text, [%params]>
1033 See L<SL::Presenter::Text/truncate>.
1035 =item C<simple_format $text>
1037 See L<SL::Presenter::Text/simple_format>.
1041 =head1 MODULE AUTHORS
1043 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
1045 L<http://linet-services.de>