11 |
11 |
html_tag input_tag hidden_tag javascript man_days_tag name_to_id select_tag
|
12 |
12 |
checkbox_tag button_tag submit_tag ajax_submit_tag input_number_tag
|
13 |
13 |
stringify_attributes textarea_tag link_tag date_tag
|
14 |
|
div_tag radio_button_tag img_tag);
|
|
14 |
div_tag radio_button_tag img_tag multi_level_select_tag);
|
15 |
15 |
our %EXPORT_TAGS = (ALL => \@EXPORT_OK);
|
16 |
16 |
|
17 |
17 |
use Carp;
|
... | ... | |
244 |
244 |
return $select_html;
|
245 |
245 |
}
|
246 |
246 |
|
|
247 |
sub multi_level_select_tag {
|
|
248 |
my ($name, $collection, $levels, %attributes) = @_;
|
|
249 |
|
|
250 |
_set_id_attribute(\%attributes, $name);
|
|
251 |
my $id = $attributes{id};
|
|
252 |
|
|
253 |
$collection = [] if defined($collection) && !ref($collection) && ($collection eq '');
|
|
254 |
|
|
255 |
my $surround_tag = delete(%attributes{surround_tag});
|
|
256 |
|
|
257 |
my $multi_level_select_tag = "";
|
|
258 |
my %level_keys = ();
|
|
259 |
|
|
260 |
my $base_attributes = delete($attributes{"level_1"}) || {};
|
|
261 |
|
|
262 |
my $base_name = delete($base_attributes->{name});
|
|
263 |
my $base_value_key = $base_attributes->{value_key} || 'id';
|
|
264 |
my $base_title_key = $base_attributes->{title_key} || $base_value_key;
|
|
265 |
my $base_default = $base_attributes->{default};
|
|
266 |
my $base_default_key = $base_attributes->{default_key};
|
|
267 |
|
|
268 |
$level_keys{1} = {
|
|
269 |
"value" => $base_value_key,
|
|
270 |
"title" => $base_title_key,
|
|
271 |
};
|
|
272 |
$base_attributes->{id} = $id . "_level_1";
|
|
273 |
$base_attributes->{onchange} = $id . "_on_chanche_level_1(this)";
|
|
274 |
my $current_select = select_tag(
|
|
275 |
$base_name,
|
|
276 |
$collection,
|
|
277 |
%{$base_attributes}
|
|
278 |
);
|
|
279 |
if ($surround_tag) {
|
|
280 |
$multi_level_select_tag .= html_tag($surround_tag, $current_select);
|
|
281 |
} else {
|
|
282 |
$multi_level_select_tag .= $current_select;
|
|
283 |
}
|
|
284 |
|
|
285 |
my $last_object;
|
|
286 |
if ($base_default) {
|
|
287 |
($last_object) = grep { $_->{$base_value_key} eq $base_default } @{$collection};
|
|
288 |
} elsif ($base_default_key) {
|
|
289 |
($last_object) = grep { $_->{$base_default_key} } @{$collection};
|
|
290 |
} else {
|
|
291 |
$last_object = $collection->[0];
|
|
292 |
}
|
|
293 |
foreach my $level (2 .. $levels) {
|
|
294 |
my $current_attributes = delete($attributes{"level_$level"}) || {};
|
|
295 |
|
|
296 |
my $current_name = delete($current_attributes->{name});
|
|
297 |
my $current_value_key = $current_attributes->{value_key} || 'id';
|
|
298 |
my $current_title_key = $current_attributes->{title_key} || $current_value_key;
|
|
299 |
my $current_default = $current_attributes->{default};
|
|
300 |
my $current_default_key = $current_attributes->{default_key};
|
|
301 |
my $current_object_key = delete($current_attributes->{object_key});
|
|
302 |
die "need object_key in level_$level in multi_level_select_tag" unless $current_object_key;
|
|
303 |
|
|
304 |
$level_keys{$level} = {
|
|
305 |
"value" => $current_value_key,
|
|
306 |
"title" => $current_title_key,
|
|
307 |
"object" => $current_object_key,
|
|
308 |
};
|
|
309 |
|
|
310 |
$current_attributes->{id} = $id . "_level_$level";
|
|
311 |
$current_attributes->{onchange} = $id . "_on_chanche_level_${level}(this)" unless $level eq $levels;
|
|
312 |
my $current_collection = $last_object->{$current_object_key};
|
|
313 |
my $current_select = select_tag(
|
|
314 |
$current_name,
|
|
315 |
$current_collection,
|
|
316 |
%{$current_attributes}
|
|
317 |
);
|
|
318 |
if ($surround_tag) {
|
|
319 |
$multi_level_select_tag .= html_tag($surround_tag, $current_select);
|
|
320 |
} else {
|
|
321 |
$multi_level_select_tag .= $current_select;
|
|
322 |
}
|
|
323 |
|
|
324 |
if ($current_default) {
|
|
325 |
($last_object) = grep { $_->{$current_value_key} eq $current_default } @{$current_collection};
|
|
326 |
} elsif ($current_default_key) {
|
|
327 |
($last_object) = grep { $_->{$current_default_key} } @{$current_collection};
|
|
328 |
} else {
|
|
329 |
$last_object = $current_collection->[0];
|
|
330 |
}
|
|
331 |
}
|
|
332 |
|
|
333 |
my $code = "";
|
|
334 |
|
|
335 |
if ($levels > 1) {
|
|
336 |
my $js_option_string = ""; # js hash map (level->value->{[value: 1, title: 'foo'], ...})
|
|
337 |
|
|
338 |
my @current_collections = @{$collection};
|
|
339 |
my @next_collections = ();
|
|
340 |
foreach my $level (1 .. ($levels - 1)) {
|
|
341 |
$js_option_string .= "'${level}': {";
|
|
342 |
foreach my $option (@current_collections) {
|
|
343 |
$js_option_string .= "'" . $option->{$level_keys{$level}{value}} . "': [";
|
|
344 |
map { $js_option_string .= "{ value: '" . $_->{$level_keys{$level + 1}{value}}
|
|
345 |
. "', title: '" . $_->{$level_keys{$level + 1}{title}}
|
|
346 |
. "'}," } @{$option->{$level_keys{$level + 1}{object}}};
|
|
347 |
$js_option_string .= "],";
|
|
348 |
push @next_collections, @{$option->{$level_keys{$level + 1}{object}}};
|
|
349 |
}
|
|
350 |
$js_option_string .= "},";
|
|
351 |
@current_collections = @next_collections;
|
|
352 |
@next_collections = ();
|
|
353 |
}
|
|
354 |
|
|
355 |
$code .= javascript( qq|
|
|
356 |
var ${id}_options = {
|
|
357 |
$js_option_string
|
|
358 |
};
|
|
359 |
|);
|
|
360 |
foreach my $level (1 .. ($levels - 1)) {
|
|
361 |
my $next_level = $level + 1;
|
|
362 |
$code .= javascript( qq|
|
|
363 |
function ${id}_on_chanche_level_${level}(select_${level}) {
|
|
364 |
var value = select_${level}.value;
|
|
365 |
for (var i = ${next_level}; i < $levels + 1; i++) {
|
|
366 |
var id = '${id}_level_' + i;
|
|
367 |
var select_i = document.getElementById(id);
|
|
368 |
while (select_i.options.length) {
|
|
369 |
select_i.options.remove(0);
|
|
370 |
}
|
|
371 |
select_i.disabled = true;
|
|
372 |
}
|
|
373 |
var id_${next_level} = '${id}_level_${next_level}';
|
|
374 |
var select_${next_level} = document.getElementById(id_${next_level});
|
|
375 |
for (var i=0; i < ${id}_options[${level}][value].length; i++) {
|
|
376 |
var option = new Option(${id}_options[${level}][value][i].title, ${id}_options[${level}][value][i].value)
|
|
377 |
select_${next_level}.options.add(option);
|
|
378 |
}
|
|
379 |
select_${next_level}.disabled = false;
|
|
380 |
select_${next_level}.selectedIndex = -1;
|
|
381 |
}
|
|
382 |
|);
|
|
383 |
}
|
|
384 |
}
|
|
385 |
|
|
386 |
return $multi_level_select_tag . $code;
|
|
387 |
}
|
|
388 |
|
247 |
389 |
sub checkbox_tag {
|
248 |
390 |
my ($name, %attributes) = @_;
|
249 |
391 |
|
... | ... | |
706 |
848 |
# Later in the template:
|
707 |
849 |
[% L.select_tag('the_selection', COLLECTION, with_optgroups=1, title_key='name') %]
|
708 |
850 |
|
|
851 |
=item C<multi_level_select_tag $name, \@collection, $levels, %attributes>
|
|
852 |
|
|
853 |
Creates multiple HTML 'select' tags, one for each level. Each tag ist created
|
|
854 |
with C<select_tag>.
|
|
855 |
|
|
856 |
The parameters for C<select_tag> are created from the values stored in the
|
|
857 |
corrosponding level attributes. The attributes for each level are in
|
|
858 |
C<%attributes{level_i}>, starting with 1.
|
|
859 |
|
|
860 |
The following are used directly from each level:
|
|
861 |
|
|
862 |
=over 12
|
|
863 |
|
|
864 |
=item I<name> is deleted from level attributes.
|
|
865 |
The I<name> is used for the for the name of the 'select' tag.
|
|
866 |
|
|
867 |
=item I<object_key> is deleted from level attriutes.
|
|
868 |
The I<object_key> is used to get the level objects for the current level
|
|
869 |
from the object of the previous level, this is intended for the use of RSDB object.
|
|
870 |
Each level attributes musst contain I<object_key>, except level_1.
|
|
871 |
|
|
872 |
=item I<id> is overridden.
|
|
873 |
The I<id> is set to a specific value for use in JavaScript.
|
|
874 |
|
|
875 |
=item I<value_key> names the key for the value of level object. Defaults to
|
|
876 |
C<id>.
|
|
877 |
|
|
878 |
=item I<title_key> names the key for the titel of level object. Defaults to
|
|
879 |
C<$attributes{value_key}>.
|
|
880 |
|
|
881 |
=item I<default> is used to find the default level object.
|
|
882 |
|
|
883 |
=tiem I<default_key> names the key for the default feld of level object. Is
|
|
884 |
ignored if I<default> is set.
|
|
885 |
|
|
886 |
=back
|
|
887 |
|
|
888 |
|
|
889 |
<\@collection> is used for the level object of level 1. The objects of the next
|
|
890 |
level are taken from the previous level via the <object_key>. On each level the
|
|
891 |
objects must be a hash reference or a blessed reference.
|
|
892 |
|
|
893 |
A I<surround_tag> can be specified, which generates a C<html_tag> with the
|
|
894 |
corrosponding tag around evey C<select_tag>.
|
|
895 |
|
|
896 |
Example:
|
|
897 |
|
|
898 |
# First in a controller:
|
|
899 |
my @collection = (
|
|
900 |
{ 'description' => 'foo_1', 'id' => '1',
|
|
901 |
'key_1' => [
|
|
902 |
{ 'id' => 3, 'description' => "bar_1",
|
|
903 |
'key_2' => [
|
|
904 |
{ 'id' => 1, 'value' => "foobar_1", },
|
|
905 |
{ 'id' => 2, 'value' => "foobar_2", },
|
|
906 |
], },
|
|
907 |
{ 'id' => 4, 'description' => "bar_2",
|
|
908 |
'key_2' => [], },
|
|
909 |
], },
|
|
910 |
{ 'description' => 'foo_2', 'id' => '2',
|
|
911 |
'key_1' => [
|
|
912 |
{ 'id' => 1, 'description' => "bar_1",
|
|
913 |
'key_2' => [
|
|
914 |
{ 'id' => 3, 'value' => "foobar_3", },
|
|
915 |
{ 'id' => 4, 'value' => "foobar_4", },
|
|
916 |
], },
|
|
917 |
{ 'id' => 2, 'description' => "bar_2",
|
|
918 |
'stock' => [
|
|
919 |
{ 'id' => 5, 'value' => "test_5", },
|
|
920 |
], },
|
|
921 |
], },
|
|
922 |
);
|
|
923 |
|
|
924 |
# Later in the template (in a table):
|
|
925 |
[% L.multi_level_select_tag("multi_select_foo_bar_foobar", COLLECTION, 3,
|
|
926 |
surround_tag="td",
|
|
927 |
level_1={
|
|
928 |
name="foo.id",
|
|
929 |
value_key="id",
|
|
930 |
title_key="description",
|
|
931 |
default="2",
|
|
932 |
},
|
|
933 |
level_2={
|
|
934 |
object_key="key_1",
|
|
935 |
name="bar.id",
|
|
936 |
value_key="id",
|
|
937 |
title_key="description",
|
|
938 |
default="1",
|
|
939 |
},
|
|
940 |
level_3={
|
|
941 |
object_key="key_2",
|
|
942 |
name="foobar.id",
|
|
943 |
value_key="id",
|
|
944 |
title_key="value",
|
|
945 |
default="4",
|
|
946 |
},
|
|
947 |
) %]
|
|
948 |
|
709 |
949 |
=back
|
710 |
950 |
|
711 |
951 |
=head1 BUGS
|
multi_level_select_tag hinzugefüht