package ONO::Lib::UI::Select;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::IO;
use ONO::Lib::Code::RandomID;
use ONO::Lib::UI::Check;
sub boxes {
my (
$self,
$ID,
$boxes_ref,
$vars_ref,
$width,
$height,
$switches,
) = @_;
#: Selection boxes.
my %vars = %$vars_ref;
if (!$width) {
$width = 100;
}
if (!$height) {
$height = 25;
}
my $HIGH = "black";
my $BOXES;
foreach my $box (@$boxes_ref) {
my @bp = split(/:/,$box);
my ($COLOR,$TRANS) = ("fabric","trans20");
if ($vars{"${ID}_$bp[0]"}) {
($COLOR,$TRANS) = ($HIGH,"");
}
my ($TXT,$IMG,$HINT,$OVER);
if ($bp[1]) {
$TXT = qq~<div class="abs" style="left:7px;bottom:2px">$bp[1]</div>~;
}
if ($bp[2]) {
$IMG = qq~<img class="abs" src="$bp[2]" style="top:0px;left:0px;" alt="select">~;
}
if ($bp[3]) {
$HINT = qq~<div id="${ID}_$bp[0]_hint" class="hide"><div class="abs box_paper pad10_2" style="left:7px;bottom:2px">$bp[3]</div></div>~;
$OVER = qq~ onmouseover="onojs_block('${ID}_$bp[0]_hint');" onmouseout="onojs_hide('${ID}_$bp[0]_hint');"~;
}
$BOXES .= qq~<div class="fl mr5 cursorlink" onclick="onojs_ui_select_toggle('$ID','$bp[0]','$HIGH');"$OVER>
<div id="${ID}_$bp[0]_div" class="box_$COLOR box_yellow_hover rel" style="width:${width}px;height:${height}px;overflow:hidden">
<div id="${ID}_$bp[0]_trans" class="$TRANS">
$IMG
<div class="abs" style="right:2px;bottom:0px"><img class="block32" src="/ono/osr/images/icons/crystal/32x32/ono/ok.png" alt="selected"></div>
</div>
$TXT
$HINT
</div>
</div>
<input type="hidden" id="${ID}_$bp[0]_id" name="${ID}_$bp[0]" value="$vars{"${ID}_$bp[0]"}">
~;
}
return qq~<div class="inline w100">$BOXES</div>~;
}
sub checkboxes {
my (
$self,
$name,
$title,
$checked,
$chks_ref,
$switches,
) = @_;
#: Selection checkboxes.
#:
#: flag:text:img
#: flag can be inverted ($checked = not checked) by adding an '*' to this flag
#:
#: -d disabled
my $CHK;
my @chks = @$chks_ref;
my $CHECKED = 0;
if ($checked) {
$CHECKED = length $checked;
}
my $ID = "onojs_ui_select_".ONO::Lib::Code::RandomID->make;
foreach my $ch (@chks) {
if ($ch eq "-") {
$CHK .= qq~<tr><td class="bb"></td><td class="bb"></td><td class="p2 bb"></td><td class="p2 bb"></td><td class="p2 bb"></td></tr><tr><td></td><td></td><td></td><td></td><td class="p2"></td></tr>~;
} else {
my @cp = split(/:/,$ch);
my ($IMG,$chk,$invert,$chk_switches);
if ($cp[0] =~ s~\*~~g) {
$invert++;
}
if ($cp[2]) {
$IMG = qq~<img class="block16" src="$cp[2]" alt="">~;
}
if (($checked =~ /$cp[0]/ && !$invert) || ($checked !~ /$cp[0]/ && $invert)) {
$chk .= " checked";
}
if ($switches =~ /d/) {
$chk_switches .= "d";
if (($checked =~ /$cp[0]/ && !$invert) || ($checked !~ /$cp[0]/ && $invert)) {
$chk = 1;
} else {
$chk = 0;
}
}
my $CHECKBOX = ONO::Lib::UI::Check->switch("${name}$cp[0]",$chk,"bcCm$chk_switches");
$CHK .= qq~<tr>
<td>$CHECKBOX</td>
<td></td>
<td class="p0">$IMG</td>
<td></td>
<td class="nowrap">$cp[1]</td>
<tr>
~;
}
}
return qq~<div class="rel fl" style="xz-index:999" onmouseover = "onojs_block('${ID}_chks');" onmouseout = "onojs_hide('${ID}_chks');">
<div class="block16 bg_fabric bo radius5 center small bold lh125" style="width:14px">$CHECKED</div>
<div id="${ID}_chks" class="abs hide bg_paper bo p5 radius5 small" style="top:0px;z-index:999">
<table class="default_table">
$CHK
</table>
</div>
</div>
~;
}
sub select {
my (
$self,
$name,
$title,
$default,
$sels_ref,
$switches,
) = @_;
#: Select.
#:
#: -i icon instead of icon and text (requires image in every @sels entry)
my @sels = @$sels_ref;
my $ID = "onojs_ui_select_".ONO::Lib::Code::RandomID->make;
my ($DEF,$SEL);
foreach my $sel (@sels) {
my @sp = split(/:/,$sel);
my $CLASS;
if ($sp[0] eq $default) {
$CLASS = " bg_green";
my $IMG;
if ($sp[2]) {
$IMG = qq~<img id="${ID}_defimg" class="block16 mr5" src="$sp[2]" alt="">~;
}
$DEF = qq~<div class="bg_paper bo pad5_2 radius5 small fl">
<table class="default_table">
<tr>
<td>$IMG</td>
<td><div id="${ID}_deftit">$sp[1]</div></td>
</tr>
</table>
</div>
~;
if ($switches =~ /i/) {
$DEF = qq~<div class="bg_paper bo radius5 block16">$IMG</div>~;
}
}
my $IMG;
if ($sp[2]) {
$IMG = qq~<img class="block16 mr5" src="$sp[2]" alt="">~;
}
$SEL .= qq~<tr class="row$CLASS" style="cursor:pointer" onclick="onojs_ui_select_script('$ID','$sp[0]','$sp[1]','$sp[2]');">
<td class="pad5_2"></td>
<td class="p0">$IMG</td>
<td>$sp[1]</td>
<td class="pad5_2"></td>
</tr>
~;
}
if (!$default) {
$DEF = qq~<img class="block10" src="/ono/osr/images/arrows/nuvola/black/nav_down.png" style="margin:3px" alt="">~;
my $CLASS = " block16";
if ($title) {
$DEF = qq~<table class="default_table"><tr><td>$DEF</td><td>$title</td></tr></table>~;
$CLASS = " fl";
}
$DEF = qq~<div id="${ID}_def" class="bg_paper bo radius16 pad10_2 $CLASS" style="background-color: #fff;background-image: linear-gradient(to top, #dddddd, #eeeeee 50%);"
onmouseover = "onojs_class('${ID}_def','bg_yellow bo radius16 pad10_2$CLASS');" onmouseout = "onojs_class('${ID}_def','bg_paper bo radius16 pad10_2$CLASS');">
$DEF
</div>
~;
}
return qq~<div class="rel fl" onmouseover = "onojs_block('${ID}_sels');" onmouseout = "onojs_hide('${ID}_sels');">
<div>$DEF</div>
<div id="${ID}_sels" class="abs hide bg_paper bo p5 radius5 small" style="top:0px;z-index:999">
<table class="default_table">
$SEL
</table>
</div>
<input type="hidden" id="${ID}_name" name="$name" value="$default">
</div>
~;
}
sub script {
#: Obsolete, only here for backwards compatibility, returns nothing.
return "";
}
sub select_country {
my (
$self,
$id,
$opts,
$selected,
$switches,
$lang,
$BLK_ref,
) = @_;
#: Select country from list.
#:
#: -n replace select... by none if $selected
#: -s select...
#: -S omit select
#: -q quick select at top of list
my %BLK = %$BLK_ref;
my ($SEL,$sel_used,$display);
if ($switches =~ /q/) {
$display++;
}
foreach my $country (ONO::IO->list("ono/osr/resources/geo/countries.txt")) {
my @cp = split(/\,/,$country);
if ($display) {
my $sel;
if ($cp[0] eq $selected && !$sel_used) {
$sel = " selected";
$sel_used++;
}
$SEL .= qq~<option value="$cp[0]"$sel>$cp[1]</option>~;
}
if ($cp[0] eq "--") {
$display++;
}
}
if ($switches =~ /s/) {
my $MSG = "$BLK{'select'}...";
if ($switches =~ /n/ && $selected) {
$MSG = $BLK{'none'};
}
$SEL = qq~<option value="">$MSG</option><option value="">----</option>$SEL~;
}
if ($switches =~ /S/) {
return $SEL;
} else {
return qq~<div class="select"><select name="$id">$SEL</select></div>~;
}
}
sub select_edu_branch {
my (
$self,
$id,
$opts_unused,
$selected,
$switches,
$lang,
$BLK_ref,
) = @_;
#: Select education branch from list.
my %BLK = %$BLK_ref;
my $BRA;
foreach my $opt (
"math:$BLK{'Math'}",
"-",
"lang:$BLK{'Languages'}",
"-",
"sci:$BLK{'Science'}",
) {
if ($opt eq "-") {
$BRA .= qq~<option value="">----</option>~;
} else {
my @op = split(/:/,$opt);
my $sel;
if ($op[0] eq $selected) {
$sel = " selected";
}
$BRA .= qq~<option value="$op[0]"$sel>$op[1]</option>~;
}
}
return qq~<div class="select"><select name="$id"><option value="">$BLK{'none'}</option><option value="">----</option>$BRA</select></div>~
}
sub select_language {
my (
$self,
$id,
$opts_unused,
$selected,
$switches,
$lang,
$BLK_ref,
) = @_;
#: Select language from list.
#:
#: -n replace select... by none if $selected
#: -s select...
#: -S omit select
#: -q quick select at top of list
my %BLK = %$BLK_ref;
my ($SEL,$PRE,@langs,%used);
foreach my $language (ONO::IO->list("ono/osr/resources/geo/languages.txt")) {
my @lp = split(/\^/,$language);
if ($lp[1] && $lp[1] !~ /^(lu|ch)$/ && !$used{$lp[1]} && $lp[2]) {
$used{$lp[1]}++;
$lp[1] =~ s~ja~jp~;
$lp[1] =~ s~lb~lu~;
$lp[1] =~ s~zh~ch~;
@langs = (@langs,"$lp[2]^$lp[1]^$lp[2]^");
}
}
foreach my $language (sort @langs) {
my @lp = split(/\^/,$language);
my $sel;
if ($lp[1] eq $selected) {
$sel = " selected";
}
$lp[2] =~ s~(,|;| \()(.*)$~~;
if ($switches =~ /q/ && $lp[1] =~ /^(en|de|fr|nl|lu|es|it|pt|da|fi|no|sv|ch|jp|ru)$/) {
$PRE .= qq~<option value="$lp[1]"$sel>$lp[2]</option>~;
if ($sel) {
$sel = "";
}
}
$SEL .= qq~<option value="$lp[1]"$sel>$lp[2]</option>~;
}
if ($PRE) {
$PRE .= qq~<option value="$selected">----</option>~;
}
if ($switches =~ /s/) {
my $MSG = "$BLK{'select'}...";
if ($switches =~ /n/ && $selected) {
$MSG = $BLK{'none'};
}
$PRE = qq~<option value="">$MSG</option><option value="">----</option>$PRE~;
}
if ($switches =~ /S/) {
return "$PRE$SEL";
} else {
return qq~<div class="select"><select name="$id">$PRE$SEL</select></div>~;
}
}
sub langsel {
my (
$self,
$id,
$langs_ref,
$selected,
$switches,
) = @_;
#: Select language.
#:
#: -c center
#: -i include an input field
#: -S no script code (required when using Ajax)
my @langs = @$langs_ref;
my $num = @langs;
my ($LANG,$SCRIPT,$INPUT,$CLASS,$counter,$first,$last,$middle);
foreach my $lang (@langs) {
$counter++;
my $button = "middle";
if ($counter == 1) {
$button = "left";
$first = $lang;
if (!$selected) {
$selected = $lang;
}
}
if ($counter == $num) {
$button = "right";
$last = $lang;
}
if ($counter > 1 && $counter < $num) {
$middle .= "'$lang',";
}
my $sel;
if ($lang eq $selected) {
$sel = "_green";
}
$LANG .= qq~<td class="p0 nowrap">
<a id="${id}_button_$lang" href="javascript:void(0);" onclick="${id}_script('$lang');" class="button$sel button_$button" style="padding:5px">
<img class="inline" src="/ono/osr/images/flags/languages/$lang.png" style="width:20px;height:15px" alt="">
</a>
</td>
~;
}
$middle =~ s~\,$~~;
if ($switches =~ /c/) {
$CLASS .= " auto";
}
if ($switches =~ /i/) {
$INPUT = qq~<input type="hidden" id="${id}_id" name="${id}" value="$selected">~;
}
if ($switches !~ /S/) {
$SCRIPT = qq~<script>
function ${id}_script(lang) {
document.getElementById('${id}_id').value=lang;
onojs_class('${id}_button_$first','button button_left');
onojs_class('${id}_button_$last','button button_right');
if (lang == '$first') {onojs_class('${id}_button_$first','button_green button_left')}
if (lang == '$last') {onojs_class('${id}_button_$last','button_green button_right')}
var a = [$middle];
for (index = 0; index < a.length; ++index) {
onojs_class('${id}_button_'+a[index],'button button_middle');
if (lang == a[index]) {onojs_class('${id}_button_'+a[index],'button_green button_middle')}
}
}
</script>
~;
}
return qq~<table class="default_table$CLASS">
<tr>
$LANG
</tr>
</table>
$INPUT
$SCRIPT
~;
}
sub select_reload {
#: Select and reload.
my (
$self,
$script_url,
$opts_ref,
$selected,
$label,
) = @_;
my $ID = ONO::Lib::Code::RandomID->make;
my ($LABEL,$OPTS);
if ($label) {
$LABEL = qq~<option value="$selected">$label: $selected</option><option value="$selected">----</option>~;
}
foreach my $opt (@$opts_ref) {
my @op = split(/:/,$opt);
$OPTS .= qq~ <option value="$op[0]">$op[1]</option>~;
}
my $JS = "window.location='$script_url'+document.getElementById('pulldown_${ID}_id').options[selectedIndex].value;";
return qq~<div class="select"><select id="pulldown_${ID}_id" name="pulldown_$ID" onchange="$JS">$LABEL$OPTS</select></div>~;
}
###############################################################################
# tabs
###############################################################################
sub buttons {
my (
$self,
$id,
$selected,
$tabs_ref,
$script_url,
$switches,
$BLK_ref,
$setup_ref,
$title,
) = @_;
#: Select buttons - note that this is NOT Ajax compatible !
#:
#: tab format is "id:color:name"
#:
#: -c center
#: -b bigger buttons (small size, as mini is default, combine with -B for big, also see -X)
#: -B bigger buttons (normal size, as mini is default, combine with -b for big, also see -X)
#: -d display only (not clickable)
#: -f select first if none selected
#: -l left
#: -L use link instead of JS ($script_url required)
#: -p padding 2/5 px
#: -r right
#: -s display save button on change
#: -W force white color on button text
#: -X X-large (also see -b and -B)
my @tabs = @$tabs_ref;
my $num = @tabs;
my (%BLK,%setup,$counter);
if ($switches =~ /s/ && $BLK_ref) {
%BLK = %$BLK_ref;
}
if ($setup_ref) {
%setup = %$setup_ref;
}
my ($TABS,$DISABLE,$ENABLE,$SCRIPT,$STYLE);
my $BUTSIZE = "_mini";
if ($switches =~ /(b|B)/) {
$BUTSIZE = "";
if ($switches =~ /b/) {
$BUTSIZE = "_small";
if ($switches =~ /B/) {
$BUTSIZE = "_large";
}
}
}
if ($switches =~ /X/) {
$BUTSIZE = "_big";
}
if ($switches =~ /p/) {
$STYLE .= "padding:2px 5px 2px 5px;";
}
foreach my $tab (@tabs) {
$counter++;
my @tp = split(/:/,$tab);
my ($COLOR,$COLOR3,$ONCLICK);
if ($switches =~ /f/ && $selected eq "") {
$selected = $tp[0];
}
if ($tp[0] eq $selected && $tp[1]) {
$COLOR = "_$tp[1]";
}
if ($tp[1]) {
$COLOR3 = "_$tp[1]";
}
my $CLASS = "button$COLOR button$BUTSIZE button_middle fl";
my $CLASS2 = "button button$BUTSIZE button_middle fl";
my $CLASS3 = "button$COLOR3 button$BUTSIZE button_middle fl";
if ($counter == 1) {
$CLASS = "button$COLOR button$BUTSIZE button_left fl";
$CLASS2 = "button button$BUTSIZE button_left fl";
$CLASS3 = "button$COLOR3 button$BUTSIZE button_left fl";
}
if ($counter == $num) {
$CLASS = "button$COLOR button$BUTSIZE button_right fl";
$CLASS2 = "button button$BUTSIZE button_right fl";
$CLASS3 = "button$COLOR3 button$BUTSIZE button_right fl";
}
my $STYLE2;
if ($switches =~ /W/ && $COLOR) {
$STYLE2 .= "color:#eeeeee;";
}
if ($setup{"button_$tp[0]_script"}) {
$ONCLICK .= $setup{"button_$tp[0]_script"};
}
my $HREF = qq~href="javascript:void(0);" onclick="gui_onoff_$id('$tp[0]');$ONCLICK"~;
if ($switches =~ /L/) {
$HREF = qq~href="$script_url$tp[0]"~;
}
if ($switches =~ /d/) {
$TABS .= qq~<span class="$CLASS" style="$STYLE$STYLE2">$tp[2]</span>~;
} else {
$TABS .= qq~<a id="${id}_button_$tp[0]" $HREF class="$CLASS" style="$STYLE$STYLE2">$tp[2]</a>~;
}
$DISABLE .= qq~onojs_class('${id}_button_$tp[0]','$CLASS2');\n~;
$ENABLE .= qq~if (status == '$tp[0]') {onojs_class('${id}_button_$tp[0]','$CLASS3');}\n~;
}
if ($switches =~ /s/) {
$TABS .= qq~<input id="${id}_button_save" type="submit" name="save_onoff" value="$BLK{'save'}" class="button_green button$BUTSIZE ml5 fl hide">~;
$ENABLE .= qq~onojs_block('${id}_button_save');\n~;
}
if ($switches !~ /(d|L)/) {
$SCRIPT .= qq~<input type="hidden" id="${id}_button_id" name="${id}_status" value="$selected">
<script>
function gui_onoff_$id(status) {
$DISABLE
$ENABLE
document.getElementById('${id}_button_id').value=status;
}
</script>
~;
}
if ($switches =~ /(l|c|r)/) {
my $CLASS = "fl";
if ($switches =~ /c/) {
$CLASS = "auto";
}
if ($switches =~ /r/) {
$CLASS = "fr";
}
$TABS = qq~<div class="$CLASS">$TABS</div>~;
}
if ($title) {
if ($title =~ /:/) {
$TABS = qq~<table class="default_table"><tr><td class="p0">$title </td><td class="p0">$TABS</td></tr></table>~;
} else {
$TABS = qq~<table class="default_table"><tr><td class="p0">$TABS</td><td class="pad10_2">$title</td></tr></table>~;
}
}
return qq~$TABS$SCRIPT~;
}
###############################################################################
# end of script
###############################################################################
1;
__END__