ONO::FW::Apps::ToolBox

package ONO::FW::Apps::ToolBox;
################################################################################
# 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::DB;

use ONO::Lib::Basic;

use ONO::Lib::Code::RandomID;

use ONO::Lib::UI::Check;
use ONO::Lib::UI::Radio;
use ONO::Lib::UI::Select;

###############################################################################
# apps base on website
###############################################################################

sub apps_base {

#: Get the URL base for apps on a specific site.

my $APPSBASE = "elearning/-";

# cron support is still missing here!

if ($ENV{'SERVER_NAME'} =~ /(oli|morzino)/) {

$APPSBASE = "/en/online-exercises/-";
$APPSBASE = "/en/elearning/-";

if ($ENV{'REQUEST_URI'} =~ m~/de/~ || $ENV{'SERVER_NAME'} =~ /\.de$/) {

$APPSBASE = "/de/online-uebungen/-";
$APPSBASE = "/de/elearning/-";

}

if ($ENV{'REQUEST_URI'} =~ m~/fr/~ || $ENV{'SERVER_NAME'} =~ /\.fr$/) {

$APPSBASE = "/fr/exercices-en-ligne/-";
$APPSBASE = "/fr/elearning/-";

}

}

return $APPSBASE;

}

###############################################################################
# info
###############################################################################

sub get_app_name {

my (
$self,
$db,
$community,
$app,
$lang,
) = @_;

#: Get app name.

my $AppName;

foreach my $line (ONO::DB->select($db,"${community}_apps_apps","app = '$app'")) {
my @row = ONO::DB->readcols($line);
my $counter = 4;
foreach my $opt ('en','da','de','es','fi','fr','it','lu','nl','no','pt','sv','ch','jp','ru') {
$counter++;
if ($row[$counter] && ($counter == 5 || $lang eq $opt)) {
$AppName = $row[$counter];
}
}

}

if (!$AppName) {
$AppName = ucfirst $app;
$AppName =~ s~_~ ~g;
}

return $AppName;

}

sub copyright {

#: Get copyright information.

if ($_[3] || $_[4]) {
if (int(rand(100)) == 50 || !ONO::IO->exists("var/community/$_[1]/apps/$_[2]/copyright.txt")) {
ONO::IO->mkpath("var/community/$_[1]/apps/$_[2]");
ONO::IO->store("var/community/$_[1]/apps/$_[2]/copyright.txt","$_[3]:$_[4]:");
}
}

}

sub conf_input_box_open {

#: Configuration input box helper: open

my $BOX = "box_$_[1]";
if ($_[1] =~ /^bg_/) {
$BOX = $_[1];
}

my $CL = &conf_input_splitrow_table_class("",$_[2]);

return qq~<tr>
<td></td>
<td>
<div class="$BOX">
<table class="$CL">
~;

}

sub conf_input_box_close {

#: Configuration input box helper: close

return qq~ </table>
</div>
</td>
</tr>
~;

}

sub conf_input_splitrow_open {

#: Configuration input box helper: split row - open

my $CL = &conf_input_splitrow_table_class("",$_[2]);

return qq~<tr>
<td class="p0" colspan="2">
<table class="wide_table">
<tr class="vtop">
<td class="p0 $_[1]">
<table class="$CL">
~;

}

sub conf_input_splitrow_col {

#: Configuration input box helper: split row - column

my $CL = &conf_input_splitrow_table_class("",$_[2]);

return qq~ </table>
</td>
<td class="p0 $_[1]">
<table class="$CL">
~;
}

sub conf_input_splitrow_row {

#: Configuration input box helper: split row - row

my $CL = &conf_input_splitrow_table_class("",$_[2]);

return qq~ </table>
</td>
</tr>
<tr class="vtop">
<td class="p0 $_[1]">
<table class="$CL">
~;
}

sub conf_input_splitrow_close {

#: Configuration input box helper: split row - close

return qq~ </table>
</td>
</tr>
</table>
</td>
</tr>
~;

}

sub conf_input_splitrow_table_class {

#: Configuration input box helper: split row - get table class

if ($_[1]) {
return $_[1];
} else {
return "default_table";
}

}

sub conf_input {

my (
$self,
$type,
$BLK_ref,
$vars_ref,
$switches,
@data,
) = @_;

#: Configuration input elements.
#:
#: Switches:
#:
#: -C comma option: add prefer comma option (huh?)
#: -d disable (NOT implemented for all types yet!)
#: -h hide (will be shown when clicking a 'more options' button)
#: -H hide alt (custom for ops for example)
#: -i inset, displays name field as part of input item, before input
#: -I use $type instead of random ID, also see -J and $vars{'app_input_custom_row_id'}
#: -j inset after, displays name field as part of input item, after input
#: -J use $data[1] instead of random ID, also see -I and $vars{'app_input_custom_row_id'}
#: -l list manager button (used by selections for example)
#: -L shift left 10
#: -m mix mode (used by langs for example)
#: -M minimize elements (if possible / available)
#: -n name field behind item (not available for all options (yet))
#: -N don't display the name field
#: -O less standard options for this type
#: -p prefer option (used by "selections" for example)
#: -P force zero padding
#: -s apply standard name in field (for types that usually don't use name)
#: -S split to two colums
#: -t transparent
#: -T vtop

my %BLK = %$BLK_ref;
my %vars = %$vars_ref;

my $ID = ONO::Lib::Code::RandomID->make;
if ($switches =~ /I/) {
$ID = $type;
}
if ($switches =~ /J/) {
$ID = $data[1];
}
if ($vars{'app_input_custom_row_id'}) {
$ID = $vars{'app_input_custom_row_id'};
}
my $P0 = qq~ class="p0"~;
my $DEBUG;

my $ADDROW_ICON = qq~<a href="javascript:void(0);" id="app_input_addrow_icon_$ID"
onclick="onojs_tablerow('app_input_addrow_$ID');
onojs_hide('app_input_addrow_icon_$ID');">
<img class="block16" src="/ono/osr/images/icons/ono/32x32/setup.png" alt="">
</a>
~;
my $ADDROW_BUTTON = qq~<a href="javascript:void(0);" id="app_input_addrow_icon_$ID" class="button button_mini"
onclick="onojs_tablerow('app_input_addrow_$ID');
onojs_hide('app_input_addrow_icon_$ID');">
$BLK{'options'}...
</a>
~;

my ($NAME,$CONF,$ADDROW,$CLASS,$TROPTS,%sel,%chk);

### spacer

if ($type eq "spacer") {

# -s smaller

$CLASS = qq~ class="p5"~;
if ($data[0] =~ /s/) {
$CLASS = qq~ class="p2"~;
}

}

### txt / text

if ($type eq "txt" || $type eq "text") {

$NAME = "";

$CONF .= qq~<div class="lh125 col6">$data[0]</div>~;

$data[0] = "";

}

### html

if ($type eq "html") {

$NAME = "";

$CONF .= $data[0];

$data[0] = "";

}

### tip

if ($type eq "tip") {

$NAME = qq~<img class="block32 fr" src="/ono/osr/images/icons/crystal/32x32/ono/help.png" alt="">~;

$CONF .= qq~<div class="lh125 col6">$data[0]</div>~;

$data[0] = "";

}

### lines

if ($type eq "lines") {

$NAME = "";

if (!$vars{"app_input_lines_type"}) {
$vars{"app_input_lines_type"} = "lines";
}

my $HEIGHT;
my ($color1,$color2) = ('green','paper');
my ($hide1,$hide2) = ('',' hide');

if ($vars{"app_input_lines_type"} eq "edulines") {
($color1,$color2) = ('paper','green');
($hide1,$hide2) = (' hide','');
}

for (my $h = 8; $h < 17; $h++) {
my $sel;
if (($h == $vars{'app_input_lines_height'}) || ($h == 10 && !$vars{'app_input_lines_height'})) {
$sel = " selected";
}
$HEIGHT .= qq~<option value="$h"$sel>$h mm</option>~;
}

$CONF .= qq~<input type="hidden" id="app_input_lines_type_id" name="app_input_lines_type" value="$vars{"app_input_lines_type"}">
<table class="default_table">
<tr>
<td class="p0">
<div id="app_input_lines_type_lines" class="box_$color1 p5 fl mr10 mb10 cursorlink noselect" onclick="app_input_lines_type_toggle();">
<div class="block24 bo rel bg_paper" style="width:60px">
<div class="abs bg_black" style="bottom:0px;left:0px;width:100%;height:2px"></div>
<div id="app_input_lines_type_lines_check" class="abs$hide1" style="top:8px;right:4px"><img class="block24" src="/ono/osr/images/icons/crystal/32x32/ono/ok.png" alt=""></div>
</div>
</div>
</td>
<td class="p0">
<div id="app_input_lines_type_edulines" class="box_$color2 p5 fl mr10 mb10 cursorlink noselect" onclick="app_input_lines_type_toggle();">
<div class="block24 bo rel bg_paper" style="width:60px">
<div class="abs bg_black trans50" style="top:8px;left:0px;width:100%;height:1px"></div>
<div class="abs bg_black" style="top:16px;left:0px;width:100%;height:2px"></div>
<div id="app_input_lines_type_edulines_check" class="abs$hide2" style="top:8px;right:4px"><img class="block24" src="/ono/osr/images/icons/crystal/32x32/ono/ok.png" alt=""></div>
</div>
</div>
</td>
<td></td>
<td class="p0">
<div class="select_small mb5"><select name="app_input_lines_height">$HEIGHT</select></div>
</td>
</tr>
</table>
<script>
function app_input_lines_type_toggle() {
if (onojs_getvalue('app_input_lines_type_id') == 'lines') {
onojs_setvalue('app_input_lines_type_id','edulines');
onojs_hide('app_input_lines_type_lines_check');
onojs_block('app_input_lines_type_edulines_check');
onojs_class('app_input_lines_type_lines','box_fabric p5 fl mr10 mb10 cursorlink noselect');
onojs_class('app_input_lines_type_edulines','box_green p5 fl mr10 mb10 cursorlink noselect');
} else {
onojs_setvalue('app_input_lines_type_id','lines');
onojs_block('app_input_lines_type_lines_check');
onojs_hide('app_input_lines_type_edulines_check');
onojs_class('app_input_lines_type_lines','box_green p5 fl mr10 mb10 cursorlink noselect');
onojs_class('app_input_lines_type_edulines','box_fabric p5 fl mr10 mb10 cursorlink noselect');
}
}
</script>
~;

$data[0] = "";

}

### code and title

if ($type eq "codetitle") {

# make sure to disable code + title in the printing options using the -Q switch!

$NAME = $BLK{'code'};

$CONF = qq~<table class="wide_table">
<tr>
<td class="p0 w25"><input type="text" name="app_input_print_options_code" value="$data[1]" class="w80"></td>
<td class="p0">$BLK{'title'}:</td>
<td class="p2"></td>
<td class="p0 w75"><input type="text" name="app_input_print_options_title" value="$data[2]" class="w95"></td>
</tr>
</table>
~;

}

### select tabs / buttons

if ($type eq "tabs") {

$NAME = $data[0];

my @tabs = split(/\;/,$data[2]);

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_$data[1]",
$vars{"app_input_$data[1]_status"},
\@tabs,
"",
"f",
$BLK_ref,
);

}

### checkbox (single - see checks for multiple checkboxes)

if ($type eq "check" || $type eq "checkinv") {

# data -> 0 is the displayed name (optional), 1 is the name/id, 2 is selected, 3 is the label

# data[1] is the checkbox ID, custom switches can be transmitted to OnOff->switch using "ID:switches"

# -B make bracketed text smaller
# -d disabled
# -M mini
# -o toggle ops (add/sub/mul/div) on
# -O toggle ops (add/sub/mul/div) on/off
# -S inSert
# -R Right insert

$NAME = $data[0];

my ($img_switches,$JS1,$JS2);

if ($data[1] =~ s~:(.*?)$~~) {
$img_switches = $1;
}
if ($switches =~ /d/) {
$img_switches .= "d";
}
if ($switches =~ /M/) {
$img_switches .= "m";
}
if ($switches =~ /o/) {
$JS1 = "onojs_block('ono_fwapps_input_ops');";
$img_switches .= "sJ";
}
if ($switches =~ /O/) {
$JS1 = "onojs_block('ono_fwapps_input_ops');";
$JS2 = "onojs_hide('ono_fwapps_input_ops');";
$img_switches .= "sJ";
}
if ($type eq "checkinv") {
$img_switches .= "i";
}

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_$data[1]",$data[2],$img_switches,"",$JS1,$JS2);

if ($data[3] !~ /onclick/) {
$data[3] =~ s~\((.*?)\)~<span class="small col9">\($1\)</span>~;
}

$data[3] =~ s~\<~###_OP_###~g;
$data[3] =~ s~\>~###_CL_###~g;
$data[3] =~ s~\-\>~→~g;

if ($vars{'app_conf_check_text_class'}) {
$data[3] = qq~<span class='$vars{'app_conf_check_text_class'}'>$data[3]</span>~;
}

if ($switches =~ /S/) {

$NAME = qq~<div class="fr">$SWITCH</div>~;
$CONF .= $data[3];

} else {

my ($SW,$ICON);

if ($switches =~ /R/) {
$SW = " ml30";
}

if ($vars{'app_conf_check_show_icon'}) {

my $size = 32;
if ($vars{'app_conf_check_icon_size'}) {
$size = $vars{'app_conf_check_icon_size'};
}

$ICON = $data[1];
$ICON =~ s~^(.*?)_~~;
$ICON =~ s~^lang_trainer_~~;
$ICON = qq~<img class="block$size radius5" src="/images/apps/${ICON}_32.png" alt="icon">~;
if ($vars{'app_conf_check_icon_js'} ne "" && $switches !~ /d/) {
$ICON = qq~<div class="cursorlink" onclick="$vars{'app_conf_check_icon_js'}">$ICON</div>~;
}

$ICON = qq~<td class="p0"><div class="block$size bg_black p1 radius5 mr5">$ICON</div></td>~;
}

if ($data[3] =~ m~###_CL_###verbs_(.*?)###_OP_###~) {
my $la = substr($1,0,2);
$la =~ s~ge~de~;
my $TABLE = qq~<table class="default_table">
<tr>
<td><img class="flag" src="/ono/osr/images/flags/languages/$la.png" style="width:24px;height:18px" alt="$la"></td>
<td>$BLK{'Verbs'}</td>
</tr>
</table>
~;
$data[3] =~ s~###_CL_###verbs_(.*?)###_OP_###~###_CL_###$TABLE###_OP_###~;
}

$CONF .= qq~<table class="wide_table$SW"><tr>$ICON<td class="p0">$SWITCH</td><td></td><td class="p0 w100 lh100">$data[3]</td></tr></table>~;

}

$CONF =~ s~###_OP_###~\<~g;
$CONF =~ s~###_CL_###~\>~g;

}

### checkboxes (data -> 0 is the displayed name, 1 is the name/id, all following are options...)

if ($type eq "checks") {

# options -> id:selected:display_name

# selected: 0 = no, 1 = yes, X = no_disabled

my $num = @data;
$NAME = $data[0];

$CONF .= qq~<table class="default_table">~;

for (my $i = 2; $i < $num; $i++) {

my @dp = split(/:/,$data[$i]);
$dp[2] =~ s~\-\>~→~g;
$dp[2] =~ s~\((.*?)\)~<span class="col9">\($1\)</span>~g;

my $OFF;
if ($dp[1] eq "X") {
$dp[1] = 0;
$OFF = qq~ class="trans30"~;
}

# $dp[3] switches: g = grey, -i = insert, -m = mini, s = small

my ($switch_switches,$font_class);

if ($dp[3] =~ /g/) {
$font_class .= " col9";
}
if ($dp[3] =~ /m/) {
$switch_switches .= "m";
}
if ($dp[3] =~ /s/) {
$font_class .= " small";
}

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_$data[1]_$dp[0]",$dp[1],$switch_switches);

if ($dp[3] =~ /i/) {

$CONF .= qq~ <tr$OFF>
<td></td>
<td></td>
<td class="p0">
<table class="default_table">
<tr><td class="p0">$SWITCH</td><td></td><td class="p0$font_class">$dp[2]</td></tr>
</table>
</td>
</tr>
~;

} else {

$CONF .= qq~ <tr$OFF>
<td class="p0">$SWITCH</td>
<td></td>
<td class="p0$font_class">$dp[2]</td>
</tr>
~;

}

}

$CONF .= qq~</table>~;

}

if ($type eq "checknum") {

# data -> 0 is the displayed name (optional), 1 is the name/id, 2 is selected, 3 is max num, 4 is selected num

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_$data[1]",$data[2],"r");

$NAME = $SWITCH;

my $SEL;
for (my $s = 1; $s < $data[3]+1; $s++) {
$SEL .= qq~<option value="$s">$s</option>~;
}

$CONF .= qq~<table class="default_table"><tr><td class="p0 small"><div class="select"><select name="app_input_$data[1]_num">$SEL</select></div></td><td class="pad5_2"></td><td class="p0">$data[0]</td></tr></table>~;

}

if ($type eq "select") {

# 0 the data
# 1 name
# 2 selected
# 3 onchange code
# 4 input_name
# 5 switches

$NAME = $data[1];

$data[0] =~ s~ ~ ~g;

my $leftmode;
if ($data[0] !~ /=/) {
$leftmode = 1;
}

if ($data[4]) {
$data[4] = "_$data[4]";
}

my ($OPTS,$ONCHANGE,$SELCLASS);

foreach my $opt (split(/;/,$data[0])) {
my $sel;
if ($opt eq "-") {
$OPTS .= qq~<option value="">----</option>~;
} else {
if ($opt =~ /=/) {
my @op = split(/=/,$opt);
if (($op[0] =~ /[0-9]/ && $op[0] !~ /[A-Za-z]/ && $data[2] == $op[0]) || ($op[0] =~ /[A-Za-z]/ && $data[2] eq $op[0])) {
$sel = " selected";
}
$OPTS .= qq~<option value="$op[0]"$sel>$op[1]</option>~;
} else {
if (($opt =~ /[0-9]/ && $opt !~ /[A-Za-z]/ && $data[2] == $opt) || ($opt =~ /[A-Za-z]/ && $data[2] eq $opt)) {
$sel = " selected";
}
$OPTS .= qq~<option value="$opt"$sel>$opt</option>~;
}
}
}



if ($data[3]) {
$ONCHANGE = qq~ onchange="$data[3]"~;
}

if ($switches =~ /M/) {
$SELCLASS = qq~ class="button_mini"~;
}

$CONF .= qq~<div class="select"><select name="app_input_select$data[4]"$ONCHANGE$SELCLASS>$OPTS</select></div>~;

if ($leftmode) {
$NAME = qq~<div class="fr">$CONF</div>~;
$CONF = $data[1];
$CONF =~ s~\((.*?)\)~<span class="small col9">\($1\)</span>~;
}

}

if ($type eq "selnum") {

# $data[2] offers switches:
#
# -d default option on top (empty value)
# -D disable the select menu
# -e empty option on top
# -n name using data_4
# -N name label on the right (also see -o)
# -o shift -N label to the right
# -p print unique number of copies (special mode, replacing the default field on the print page, used by worksheet maker)
# -P same as -p, but use alternative input name (required by worksheet maker)
# -q use 'paragraphs' instead of 'number'
# -r use 'results' instead of 'number'
# -R reverse (not implemented yet)
# -s smaller width (100px), can be combined with -S (50px)
# -S smaller width (75px), can be combined with -s (50px)
# -z use data_4 for zero value (display only)
# -Z separator behind zero option

$NAME = $BLK{'number'};
if ($data[2] =~ /q/) {
$NAME = $BLK{'paragraphs'};
}
if ($data[2] =~ /r/) {
$NAME = $BLK{'results'};
}
if ($data[2] =~ /n/ && $data[4]) {
$NAME = $data[4];
}

my ($CLASS,$STYLE,$dis);

if ($data[2] =~ /D/) {
$dis = " disabled";
}

if ($data[2] =~ /s/) {
$STYLE = "width:100px";
}
if ($data[2] =~ /S/) {
$STYLE = "width:75px";
}
if ($data[2] =~ /s/ && $data[2] =~ /S/) {
$STYLE = "width:50px";
}

my $NUM;
if ($data[2] =~ /d/) {
$NUM .= qq~<option value="">$BLK{'default'}</option><option value="">----</option>~;
}
if ($data[2] =~ /e/) {
$NUM .= qq~<option value=""></option><option value="">----</option>~;
}
for (my $i = $data[0]; $i < $data[1]+1; $i++) {
my $sel;
if (($data[2] =~ /(p|P)/ && $i == $vars{'app_input_print_options_unique_copies_alt'}) || ($data[3] && $i == $data[3])) {
$sel = " selected";
}
my $iname = $i;
if (!$i && $data[2] =~ /z/) {
$iname = $data[4];
}
$NUM .= qq~<option value="$i"$sel>$iname</option>~;
if (!$i && $data[2] =~ /Z/) {
$NUM .= qq~<option value="0">----</option>~;
}
}

my $selname = "app_input_number";
if ($data[5]) {
$selname = $data[5];
}
if ($data[2] =~ /(p|P)/) {
$NAME = $BLK{'pages'};
$CLASS = " w50px";
$selname = "app_input_print_options_unique_copies";
if ($data[2] =~ /P/) {
$selname = "app_input_print_options_unique_copies_alt";
}
}

$CONF .= qq~<div class="select$CLASS" style="$STYLE"><select name="$selname"$dis>$NUM</select></div>~;

if ($data[2] =~ /N/) {
if ($data[2] =~ /o/) {
$NAME = " $NAME";
}
$CONF = qq~<table class="default_table">
<tr>
<td class="p0">$CONF</td>
<td class="p2"></td>
<td class="p0">$NAME</td>
</tr>
</table>
~;
$NAME = "";
}

}

### range (numbers from x to y, using input fields - also see "rangesel" as an alternative)

if ($type eq "range") {

$NAME = $BLK{'numbers'};
$CLASS = $P0;

# 0 default from
# 1 default to
# 2 max to
# 3 switches
# 4 opts (adds select)

# -D hide default values
# -h hide from
# -H hide to
# -f allow fixed numbers as alternative
# -F like -F, fixed is default (not implemented yet)
# -m min from (=1)
# -M max to (not implemented yet)
# -u replace "-" by "up to"
# -x fixed from (not implemented yet)
# -X fixed to (not implemented yet)
# -z zero from (not implemented yet)
# -Z zero to (not implemented yet)

if (!$vars{'app_input_range_from'}) {
$vars{'app_input_range_from'} = $data[0];
}
if (!$vars{'app_input_range_to'}) {
$vars{'app_input_range_to'} = $data[1];
}
if ($data[2] && $vars{'app_input_range_to'} > $data[2]) {
$vars{'app_input_range_to'} = $data[2];
}
if ($vars{'app_input_range_from'} > $vars{'app_input_range_to'}) {
$vars{'app_input_range_to'} = $vars{'app_input_range_from'};
}

if ($switches =~ /O/) {
$ADDROW_ICON = "";
}

my $max = 9999999;
if ($data[2]) {
$max = $data[2];
}
my $maxlength = length $max;
my $TO = "–";
my @HIDE;

if ($data[3] =~ /m/) {
$vars{'app_input_range_from'} = 1;
}
if ($data[3] =~ /h/) {
$HIDE[0] = qq~ class="hide"~;
}
if ($data[3] =~ /u/) {
$TO = $BLK{'up_to'};
}
if ($data[3] =~ /H/) {
$HIDE[2] = qq~ class="hide"~;
}
if ($data[3] =~ /D/) {
$HIDE[3] = qq~ class="hide"~;
}
# if ($data[3] !~ /f/) {
# $HIDE[5] = qq~ class="hide"~;
# }

# my $txt = "add manually";
# $txt = "manuell eingeben";

my @TDS = (
qq~<td$HIDE[0]>
<input type="number" id="app_input_range_from_id" name="app_input_range_from" value="$vars{'app_input_range_from'}"
size="$maxlength" maxlength="$maxlength" min="-$max" max="$max" step="1" class="w98 center"
onclick="this.select();" onkeyup="app_input_range_check('from');">
</td>
~,
qq~<td$HIDE[1]>$TO</td>~,
qq~<td$HIDE[2]>
<input type="number" id="app_input_range_to_id" name="app_input_range_to" value="$vars{'app_input_range_to'}"
size="$maxlength" maxlength="$maxlength" min="-$max" max="$max" step="1" class="w98 center"
onclick="this.select();" onkeyup="app_input_range_check('to');">
</td>
~,
qq~<td$HIDE[3]>$ADDROW_ICON</td>~,
);

# qq~~,
# qq~<td$HIDE[5]><a href="" class="button_yellow button_small">$txt</a></td>~,


if ($data[4]) {

my $OPTS;
foreach my $opt (split(/;/,";$data[4];")) {
if ($opt =~ m~^(.*?)=(.*?)$~) {
my $sel;
if ($1 eq $vars{'app_input_range_opts'}) {
$sel = " selected";
}
$OPTS .= qq~<option value="$1"$sel>$2</option>~;
}
if ($opt eq "-") {
$OPTS .= qq~<option value="">----</option>~;
}
}

$TDS[4] = qq~<td>,</td><td><div class="select" style="width:150px"><select name="app_input_range_opts">$OPTS</select></div></td>~;
}

my $RANGE = qq~<table class="default_table"><tr>$TDS[0]$TDS[1]$TDS[2]$TDS[3]$TDS[4]$TDS[5]</tr></table>~;

if ($data[3] =~ /(f|F)/) {

$switches .= "T";

$NAME = qq~<div class="mt2">$NAME:</div>~;

my @opts = ("default","list");

if (!$vars{'app_input_range_mode'}) {
$vars{'app_input_range_mode'} = "default";
if ($data[3] =~ /F/) {
$vars{'app_input_range_mode'} = "list";
}
}

if (!$vars{'app_input_range_list'}) {
$vars{'app_input_range_list'} = "5,10,15,20";
}

my @RADIO = ONO::Lib::UI::Radio->buttons("app_input_range_mode",\@opts,$vars{'app_input_range_mode'});

$RANGE = qq~<table class="default_table">
<tr>
<td class="">$RADIO[1]</td>
<td class="p0">$RANGE</td>
</tr>
<tr>
<td class="">$RADIO[2]</td>
<td class=""><input type="text" name="app_input_range_list" value="$vars{'app_input_range_list'}" class="w100" placeholder="$BLK{'comma_separated_list'}"></td>
</tr>
</table>
$RADIO[0]
~;

}

$CONF .= qq~$RANGE
<script>
function app_input_range_check(id) {
var val = onojs_getvalue('app_input_range_'+id+'_id');
val = val.substring(0,8);
onojs_setvalue('app_input_range_'+id+'_id',val);
}
</script>
~;

my @opts = ('1:10','1:20','1:100','50:500','100:1000');
if ($vars{'app_input_range_defaults'} =~ /;/) {
@opts = split(/;/,$vars{'app_input_range_defaults'});
}

foreach my $opt (@opts) {

my @op = split(/:/,$opt);

if (!$data[2] || $op[1] < $data[2]+1) {

$ADDROW .= qq~<a href="javascript:void(0);"
onclick="document.getElementById('app_input_range_from_id').value='$op[0]';document.getElementById('app_input_range_to_id').value='$op[1]';";
class="button_yellow button_mini mb5">$op[0]..$op[1]</a>~;

}

}

}

### rangesel (numbers from x to y, using pulldown menu - also see "range" as an alternative)

if ($type eq "rangesel") {

$NAME = $BLK{'numbers'};
$CLASS = $P0;

# 0 default from
# 1 default to
# 2 max to
# 3 alt name
# 4 post name
# 5 alt html name

my ($SEL1,$SEL2,$POST);

if ($data[3]) {
$NAME = $data[3];
}
if ($data[4]) {
$POST = qq~<td>$data[4]</td>~;
}

for (my $i = 0; $i < $data[2]+1; $i++) {
if ($i < $data[2]) {
my $sel;
if ($i == $data[0]) {
$sel = " selected";
}
$SEL1 .= qq~<option value="$i"$sel>$i</option>~;
}
if ($i) {
my $sel;
if ($i == $data[1]) {
$sel = " selected";
}
$SEL2 .= qq~<option value="$i"$sel>$i</option>~;
}
}

my $RANGE = "range";
if ($data[5]) {
$RANGE = $data[5];
}

$CONF .= qq~<table class="default_table">
<tr>
<td><div class="select"><select name="app_input_${RANGE}_from">$SEL1</select></div></td>
<td>–</td>
<td><div class="select"><select name="app_input_${RANGE}_to">$SEL2</select></div></td>
$POST
</tr>
</table>
~;

}

### number

if ($type eq "number") {

$NAME = $data[0];
if (!$NAME) {
$NAME = $BLK{'number'};
}
$CLASS = $P0;

if ($switches =~ /O/) {
$ADDROW_ICON = "";
}

# 0 name
# 1 id
# 2 min
# 3 max
# 4 default
# 5 additional text info

if (!$vars{"app_input_$data[1]"}) {
$vars{"app_input_$data[1]"} = $data[4];
if (!$vars{"app_input_$data[1]"}) {
$vars{"app_input_$data[1]"} = $data[3];
}
}

my $maxlength = length $data[3];
if ($data[5]) {
$data[5] = qq~<td class="col9">$data[5]</td>~;
}

$CONF .= qq~<table class="default_table">
<tr>
<td>
<input type="number" id="app_input_$data[1]_id" name="app_input_$data[1]" value="$vars{"app_input_$data[1]"}"
size="7" maxlength="$maxlength" min="$data[2]" max="$data[3]" step="1" class="center"
onclick="this.select();" onkeyup="app_input_number_check_$data[1]();" style="width:75px">
</td>
<td>$ADDROW_ICON</td>
$data[5]
</tr>
</table>
<script>
function app_input_number_check_$data[1]() {
var val = onojs_getvalue('app_input_$data[1]_id');
val = val.substring(0,$maxlength);
onojs_setvalue('app_input_$data[1]_id',val);
}
</script>
~;

my @opts = (10,20,50,100,500,1000);
if ($vars{'app_input_number_defaults'} =~ /;/) {
@opts = split(/;/,$vars{'app_input_number_defaults'});
}

foreach my $opt (@opts) {

if (!$data[3] || $opt < $data[3]+1) {

$ADDROW .= qq~<a href="javascript:void(0);"
onclick="document.getElementById('app_input_$data[1]_id').value='$opt';document.getElementById('app_input_$data[1]_id').value='$opt';";
class="button_yellow button_mini mb5">$opt</a>~;

}

}

}

### mulrows

if ($type eq "mulrows") {

# data 1 = min
# data 2 = max
# data 3 = def_max_select
# data 4 = switches / opts
# data 5 = name (optional)
# data 6 = alt_id_base

# -b buttons (all,1-5,5-10,none)
# -B bigger than 10 option (limit data 2/3 to 10 then...)
# -m multiplier instead of name
# -p padding 1px (default = 2px)
# -P padding 0px (default = 2px)
# -s split mode if more than 10

if ($data[5]) {
$NAME = $data[5];
}

my $ID_BASE = "app_input_mulrow";
if ($data[6]) {
$ID_BASE = $data[6];
}

if ($data[4] =~ /m/) {
my $MUL = qq~<option value="2:5:10">2,5,10</option><option value="1:2:5:10">----</option>~;
for (my $m = 1; $m < 1001; $m++) {
if ($m < 11 || $m == 15 || ($m < 101 && $m%10 == 0) || $m%100 == 0) {
my $sel;
if ($vars{"${ID_BASE}_main"} eq "0-$m" || ($vars{"${ID_BASE}_main"} eq "" && $m == 10)) {
$sel = " selected";
}
$MUL .= qq~<option value="0-$m"$sel>0 - $m</option>~;
}
}
$NAME = qq~<div class="select_small" style="width:70px"><select id="${ID_BASE}_main_id" name="${ID_BASE}_main">$MUL</select></div>~;
}

my $PAD1 = "2px 2px 0px 2px";
my $PAD2 = "0px 2px 2px 2px";
if ($data[4] =~ /p/) {
$PAD1 = "1px 1px 0px 1px";
$PAD2 = "0px 1px 1px 1px";
}
if ($data[4] =~ /P/) {
$PAD1 = "0px";
$PAD2 = "0px";
}

my ($SW1,$SW2,$SW3,$SW4,$MORE,$BIG1,$BIG2,$mul_found,$counter);

for (my $i = $data[1]; $i < $data[2]; $i++) {
if ($vars{"${ID_BASE}_$i"}) {
$mul_found++;
}
}

for (my $i = $data[1]; $i < $data[2]+1; $i++) {
if (!$mul_found && $i < $data[3]+1) {
$vars{"${ID_BASE}_$i"}++;
}
$counter++;
my $SW = ONO::Lib::UI::Check->switch("${ID_BASE}_$i",$vars{"${ID_BASE}_$i"},"cmv");
if ($counter > 10 && $data[4] =~ /s/) {
$SW3 .= qq~<td style="padding:$PAD1">$SW</td>~;
$SW4 .= qq~<td class="center" style="padding:$PAD2">$i</td>~;
} else {
$SW1 .= qq~<td style="padding:$PAD1">$SW</td>~;
$SW2 .= qq~<td class="center" style="padding:$PAD2">$i</td>~;
}
}

if ($counter > 10 && $data[4] =~ /s/) {
$MORE = qq~<tr>$SW3</tr><tr>$SW4</tr>~;
}

if ($data[4] =~ /B/) {
my $SWITCH = ONO::Lib::UI::Check->switch("app_input_op_muldiv_bigger_10",$vars{'app_input_op_muldiv_bigger_10'},"mv");
$BIG1 = qq~<td></td><td class="p0"><div class="mt2 mr2">$SWITCH</div></td>~;
$BIG2 = qq~<td></td><td class="p0 col9">11+</td>~;
}

my $MULBOX = qq~<table class="default_table"><tr>$SW1$BIG1</tr><tr>$SW2$BIG2</tr>$MORE</table>~;

if ($data[4] =~ /b/) {

$MULBOX .= qq~<div class="ml10 mt5">
<div class="inline w100">
<a href="javascript:void(0);" onclick="conf_mulrows_sel('none');" class="button button_left button_micro">$BLK{'none'}</a>
<a href="javascript:void(0);" onclick="conf_mulrows_sel('1-5');" class="button button_middle button_micro">1..5</a>
<a href="javascript:void(0);" onclick="conf_mulrows_sel('1-10');" class="button button_middle button_micro">1..10</a>
<a href="javascript:void(0);" onclick="conf_mulrows_sel('all');" class="button button_right button_micro">$BLK{'all'}</a>
</div>
</div>
<script>
function conf_mulrows_sel(opt) {
for (i = 1;i < 21;i++){
onojs_ui_switch_off('${ID_BASE}_'+i,'0');
}
if (opt != 'none') {
var end = 20;if (opt == '1-10') {end=10};if (opt == '1-5') {end=5};
for (i = 1;i < end+1;i++){
onojs_ui_switch_on('${ID_BASE}_'+i,'1');
}
}
}
</script>
~;
}

if ($data[4] =~ /m/) {

$MULBOX = qq~<table class="default_table"><tr class="vtop"><td>×</td><td>$MULBOX</td></tr></table>~;

}

$CONF .= $MULBOX;

}

### num system (dec, roman, hex)

if ($type eq "numsys") {

$NAME = "system";

my @tabs = ("dec:dark:$BLK{'decimals'}","roman:dark:$BLK{'romans'}","hex:dark:$BLK{'hexadecimal'}");

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_numsys",
$vars{'app_input_numsys_status'},
\@tabs,
"",
"f",
$BLK_ref,
);

}

### operations (add, sub, mul, div)

if ($type eq "ops") {

$NAME = ""; #$BLK{'operations'};
$CLASS = $P0;

# -a,s,m,d operators
# -A,S,M,D operators selected
#
# -r mul: rows selectable (combinable with -t)
# -R mul: intelligent auto select
#
# -t allow to overrun mul/div ten-limit
# -T -t selected by default (not implemented yet)
#
# -H hide by default
# -i insert
#
# -j mt2 (can be combined with -J)
# -J mt5 (can be combined with -j)
#
# -P if possible message, in combination with -t

my $HIDE;
if ($data[0] =~ /H/) {
$HIDE = "hide";
}

$CONF .= qq~<div id="ono_fwapps_input_ops" class="$HIDE">~;

if ($data[0] =~ /i/) {
$CONF .= qq~<div class="ml30">~;
}

$CONF .= qq~<table class="default_table"><tr>~;

my $hide_muldiv_bigger = "hide";

foreach my $opt (

"a\^A\^add\^+",
"s\^S\^sub\^−",
"m\^M\^mul\^×",
"d\^D\^div\^÷",

) {

my @op = split(/\^/,$opt);

if ($data[0] =~ /$op[0]/) {

my $sel;

if ($vars{"app_input_op_$op[2]"} > 0) {
$sel++;
}
if (!$vars{'output_selected'} && !$vars{"app_input_op_add"} && !$vars{"app_input_op_sub"} && !$vars{"app_input_op_mul"} && !$vars{"app_input_op_div"} && $data[0] =~ /$op[1]/) {
$sel++;
}
if (($op[0] eq "m" || $op[0] eq "d") && $sel) {
$hide_muldiv_bigger = "";
}

$CONF .= ONO::Lib::UI::Check->switch("app_input_op_$op[2]",$sel,"J",$op[3],"ops_check();","ops_check();",);

}

}

$CONF .= qq~</tr></table>~;

$CONF .= qq~<script>
function ops_check() {
if (onojs_getvalue('app_input_op_mul_id') == '1' || onojs_getvalue('app_input_op_div_id') == '1') {onojs_block('muldiv_bigger')} else {onojs_hide('muldiv_bigger')}
}
</script>
~;

if ($data[0] =~ /(r|t)/ && $data[0] =~ /(m|d)/) {

my $txt = "also mul/div numbers bigger than 10";
if ($vars{'app_lang'} eq "de") {
$txt = "auch Mul/Div Zahlen größer als 10";
}
if ($vars{'app_lang'} eq "lu") {
$txt = "och Mul/Div Zuele méi grouss wéi 10";
}
if ($vars{'app_lang'} eq "fr") {
$txt = "aussi nombres mul/div plus grands que 10";
}
if ($data[0] =~ /P/) {
$txt .= qq~ <span class="col9">($BLK{'if_possible'})</span>~;
}

my $sel;
if ($vars{'app_input_op_muldiv_bigger_10'} || ($data[0] =~ /T/ && !$vars{'output_paper'} && !$vars{'output_web'})) {
$sel++;
}

if ($data[0] =~ /r/) {

my ($MUL,$SW1,$SW2,$mul_found);

for (my $m = 5; $m < 1001; $m++) {
if ($m < 11 || $m == 15 || ($m < 101 && $m%10 == 0) || $m%100 == 0) {
my $sel;
if ($vars{'app_input_mulrow_main'} eq "0-$m" || ($vars{'app_input_mulrow_main'} eq "" && $m == 10)) {
$sel = " selected";
}
$MUL .= qq~<option value="0-$m"$sel>0 - $m</option>~;
}
}

my $max_preselect = 5;
if ($vars{'app_input_range_to'} > 90) {
$max_preselect = 10;
}

for (my $i = 1; $i < 11; $i++) {
if ($vars{"app_input_mulrow_$i"}) {
$mul_found++;
}
}

for (my $i = 1; $i < 11; $i++) {
if (!$mul_found && $i < $max_preselect+1) {
$vars{"app_input_mulrow_$i"}++;
}
my $SW = ONO::Lib::UI::Check->switch("app_input_mulrow_$i",$vars{"app_input_mulrow_$i"},"mvy");
$SW1 .= qq~<td style="padding:2px 2px 0px 2px">$SW</td>~;
$SW2 .= qq~<td class="center" style="padding:0px 2px 0px 2px">$i</td>~;
}

my ($BIG1,$BIG2);
if ($data[0] =~ /t/) {
my $SWITCH = ONO::Lib::UI::Check->switch("app_input_op_muldiv_bigger_10",$sel,"mvy");
$BIG1 = qq~<td></td><td class="p0"><div class="mt2 mr2">$SWITCH</div></td>~;
$BIG2 = qq~<td></td><td class="p0 col9">11+</td>~;
}

$CONF .= qq~<div id="muldiv_bigger" class="$hide_muldiv_bigger">
<div class="inline w100">
<table class="default_table mt5">
<tr class="vtop">
<td class="p0"><div class="select_small" style="width:60px"><select id="app_input_mulrow_main_id" name="app_input_mulrow_main">$MUL</select></div></td>
<td class="pad5_0">×</td>
<td class="p0"><table class="default_table"><tr>$SW1$BIG1</tr><tr>$SW2$BIG2</tr></table></td>
</tr>
</table>
</div>
</div>
~;

} else {

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_op_muldiv_bigger_10",$sel,"m");

$CONF .= qq~<div id="muldiv_bigger" class="$hide_muldiv_bigger">
<div class="inline w100">
<table class="default_table ml10">
<tr class="vtop"><td><div class="mt2">$SWITCH</div></td><td class="small"><div class="lh125">$txt</div></td></tr></table>
</div>
</div>
~;

}

}

if ($data[0] =~ /i/) {
$CONF .= qq~</div>~;
}

$CONF .= qq~</div>~;

if ($data[0] =~ /j/) {
$CONF = qq~<div class="mt2">$CONF</div>~;
}
if ($data[0] =~ /J/) {
$CONF = qq~<div class="mt5">$CONF</div>~;
}

}

### digits

if ($type eq "digits" || $type eq "digitsdual") {

$NAME = $BLK{'digits'};
# $CLASS = $P0;

my @tabs = ("0:dark:$BLK{'random'}","1:dark:1","2:dark:2","3:dark:3","4:dark:4");

if ($type eq "digitsdual") {

my @SEL;

for (my $i = 0; $i < 2; $i++) {
foreach my $tab (@tabs) {
my @tp = split(/:/,$tab);
my $sel;
if ($i == 0 && $vars{'app_input_digits_status'} == $tp[0]) {
$sel = " selected";
}
if ($i == 1 && $vars{'app_input_digits_status_alt'} == $tp[0]) {
$sel = " selected";
}
$SEL[$i] .= qq~<option value="$tp[0]"$sel>$tp[2]</option>~;
}
}

$CONF .= qq~<table class="default_table">
<tr>
<td class="p0"><div class="select_mini mr5"><select name="app_input_digits_status">$SEL[0]</select></div></td>
<td class="p0">/</td>
<td class="p0"><div class="select_mini ml5 mr5"><select name="app_input_digits_status_alt">$SEL[1]</select></div></td>
<td class="p0 small col9">($BLK{'if_possible'})</td>
</tr>
</table>
~;

}

if ($type eq "digits") {

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_digits",
$vars{'app_input_digits_status'},
\@tabs,
"",
"f",
$BLK_ref,
);

}

}

### comma

if ($type eq "comma" || $type eq "commadual") {

# -C prefer comma (huh?)

if (!$data[3]) {
$NAME = $BLK{'comma'};
}

my @tabs = ("no:dark:$BLK{'no'}","1:dark:1 $BLK{'digit'}","2:dark:2 $BLK{'digits'}","3:dark:3 $BLK{'digits'}","rand:dark:$BLK{'random'}");

if ($type eq "commadual") {

my @SEL;

for (my $i = 0; $i < 2; $i++) {
foreach my $tab (@tabs) {
my @tp = split(/:/,$tab);
my $sel;
if ($i == 0 && $vars{'app_input_comma_status'} eq $tp[0]) {
$sel = " selected";
}
if ($i == 1 && $vars{'app_input_comma_status_alt'} eq $tp[0]) {
$sel = " selected";
}
$SEL[$i] .= qq~<option value="$tp[0]"$sel>$tp[2]</option>~;
}
}

$CONF .= qq~<table class="default_table">
<tr>
<td class="p0"><div class="select_mini mr5"><select name="app_input_comma_status">$SEL[0]</select></div></td>
<td class="p0">/</td>
<td class="p0"><div class="select_mini ml5 mr5"><select name="app_input_comma_status_alt">$SEL[1]</select></div></td>
<td class="p0 small col9">($BLK{'if_possible'})</td>
</tr>
</table>
~;

}

if ($type eq "comma") {

my $sel = $vars{'app_input_comma_status'};
if ($vars{'app_input_comma_rand'}) {
$sel = "rand";
}

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_comma",
$sel,
\@tabs,
"",
"f",
$BLK_ref,
"",
$data[3]
);

}

}

### tens barrier

if ($type eq "tensbarrier") {

# -S selected by default

my $sel;

if ($vars{'app_input_tens_barrier'} || ($data[0] =~ /S/ && !$vars{'output_selected'} && !$vars{'exercise_editor'})) {
$sel++;
}
if ($vars{'app_input_tens_barrier'} eq "0") {
$sel = 0;
}

$NAME = ONO::Lib::UI::Check->switch("app_input_tens_barrier",$sel,"r");
$CONF .= qq~$BLK{'tens_barrier'} <span class="col9 small">(+ & -)</span>~;

}

### negative numbers

if ($type eq "negative") {

my $sel;

if ($vars{'app_input_negative'}) {
$sel++;
}

$NAME = ONO::Lib::UI::Check->switch("app_input_negative",$sel,"r");
$CONF .= qq~$BLK{'negative_numbers'}~;

}

if ($type eq "negativemix") {

my $SEL;

foreach my $opt ("pos:positive_numbers","neg:negative_numbers","mix:mix") {
my @op = split(/:/,$opt);
my $sel;
if ($vars{'app_input_posneg'} eq $op[0]) {
$sel = " selected";
}
$SEL .= qq~<option value="$op[0]"$sel>$BLK{$op[1]}</option>~;

}
$CONF .= qq~<div class="select select_small w150px"><select name="app_input_posneg">$SEL</select></div>~;

}

### also integers, and negative numbers

if ($type eq "intneg") {

my ($sel1,$sel2);

if ($vars{'app_input_integers'}) {
$sel1++;
}
if ($vars{'app_input_negative'}) {
$sel2++;
}

my $txt = "also integers";
if ($vars{'app_lang'} eq "de") {
$txt = "auch ganze Zahlen";
}
if ($vars{'app_lang'} eq "lu") {
$txt = "och ganz Zuelen";
}
if ($vars{'app_lang'} eq "fr") {
$txt = "nombres entiers";
}

$NAME = ONO::Lib::UI::Check->switch("app_input_integers",$sel1,"r");
$CONF .= qq~<table class="default_table">
<tr>
<td>$txt,</td>
<td>~;

$CONF .= ONO::Lib::UI::Check->switch("app_input_negative",$sel2,"r");
$CONF .= qq~ </td>
<td>$BLK{'negative_numbers'}</td>
</tr>
</table>
~;

}

### round up

if ($type eq "roundup" || $type eq "roundupdual") {

$NAME = $BLK{'round_up'};

my @tabs = ("no:dark:$BLK{'no'}","10:dark:10","100:dark:100");

if ($type eq "roundupdual") {

my @SEL;

for (my $i = 0; $i < 2; $i++) {
foreach my $tab (@tabs) {
my @tp = split(/:/,$tab);
my $sel;
if ($i == 0 && $vars{'app_input_roundup_status'} eq $tp[0]) {
$sel = " selected";
}
if ($i == 1 && $vars{'app_input_roundup_status_alt'} eq $tp[0]) {
$sel = " selected";
}
$SEL[$i] .= qq~<option value="$tp[0]"$sel>$tp[2]</option>~;
}
}

$CONF .= qq~<table class="default_table">
<tr>
<td class="p0"><div class="select_mini mr5"><select name="app_input_roundup_status">$SEL[0]</select></div></td>
<td class="p0">/</td>
<td class="p0"><div class="select_mini ml5 mr5"><select name="app_input_roundup_status_alt">$SEL[1]</select></div></td>
<td class="p0 small col9">($BLK{'if_possible'})</td>
</tr>
</table>
~;

}

if ($type eq "roundup") {

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_roundup",
$vars{'app_input_roundup_status'},
\@tabs,
"",
"f",
$BLK_ref,
);

}

}

### mixed or progressive

if ($type eq "mixprog") {

$NAME = $BLK{'difficulty'};

my @tabs = ("mixed:dark:$BLK{'mixed'}","progressive:dark:$BLK{'progressive'}");

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_mixprog",
$vars{'app_input_mixprog_status'},
\@tabs,
"",
"f",
$BLK_ref,
);

}

### difficulty

if ($type eq "difficulty") {

$NAME = $BLK{'difficulty'};

my @tabs = ("1:green:-","2:yellow:0","3:red:+");
if ($data[0] == 4) {
@tabs = ("1:green:-","2:yellow:0","3:orange:+","4:red:++");
}
if ($data[0] == 5) {
@tabs = ("1:green:--","2:green:-","3:yellow:0","4:orange:+","5:red:++");
}
if (!$vars{'app_input_difficulty_status'}) {
$vars{'app_input_difficulty_status'} = 2;
if ($data[0] == 5) {
$vars{'app_input_difficulty_status'} = 3;
}
}

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_difficulty",
$vars{'app_input_difficulty_status'},
\@tabs,
"",
"f",
$BLK_ref,
);
}

### level

if ($type eq "level") {

$NAME = $BLK{'level'};

# 0 min
# 1 max
# 2 selected

my @tabs;

for (my $i = $data[0]; $i < $data[1]+1; $i++) {
my $color = "yellow";
if ($i == $data[0]) {
$color = "green";
}
if ($i > $data[1]/1.5) {
$color = "orange";
}
if ($i == $data[1]) {
$color = "red";
}
@tabs = (@tabs,"$i:$color:$i");
}

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_level",
$data[2],
\@tabs,
"",
"f",
$BLK_ref,
);

}

### result hints

if ($type eq "resulthints" && ($vars{'output_paper'} || $data[1] =~ /a/)) {

# -S selected by default
#
# data 1 : -a always display (override output_paper)
# -i add "if possible"

my $sel;

if ($vars{'app_input_result_hints'}) {
$sel++;
}
if ($data[0] =~ /S/) {
$sel++;
}

my $IF;
if ($data[1] =~ /i/) {
$IF = ", $BLK{'if_possible'}";
}

my $txt = qq~allow self-correction <span class="small col9">(print results$IF)</span>~;
if ($vars{'app_lang'} eq "de") {
$txt = qq~Autokorrektur erlauben <span class="small col9">(Resultate drucken$IF)</span>~;
}
if ($vars{'app_lang'} eq "lu") {
$txt = qq~Autokorrektur erlaben <span class="small col9">(Resultater drécken$IF)</span>~;
}
if ($vars{'app_lang'} eq "de") {
$txt = qq~autocorrection <span class="small col9">(résultats visibles$IF)</span>~;
}

$NAME = ONO::Lib::UI::Check->switch("app_input_result_hints",$sel,"r");
$CONF .= $txt;

}


### verbs

if ($type eq "verbs") {

$NAME = $BLK{'verbs'};
my $TO;
if ($data[2] eq "en") {
$TO = "to ";
}

my ($VERBS,$GROUPS,$VERBLIST,$VERBADD,$hide_add,$hide_add_button,$hide_print_button,$hide_add_max,$verb_count);

# add a single verb

if ($vars{'output_add_verb'} =~ /^(.*?):(.*?)$/) {

$vars{"app_input_use_verb_$1"}++;
$vars{"app_info_use_verb_$1"} = $2;

}

# add a verb group

foreach my $key (keys %vars) {
if ($key =~ /^output_add_group_(.*?)$/) {
$VERBLIST .= qq~$1:$vars{"output_add_group_$1"};~;
$vars{'output_add_group'}++;
}
}

# add a custom group

if ($vars{'output_add_custom'} =~ /^(.*?):(.*?)$/) {

$vars{"app_input_use_verb_$1"}++;
$vars{"app_info_use_verb_$1"} = $2;

}

# build verb list

foreach my $key (sort keys %vars) {
if ($key =~ /^app_input_use_verb_(.*?)$/ && $vars{$key}) {
my $verb = $1;
if ($vars{"app_info_use_verb_$verb"}) {
$VERBLIST .= qq~$verb:$vars{"app_info_use_verb_$verb"};~;
}
}
}

# use default verbs if no verbs have been selected AND if not reloaded AND if this is not a programmed exercise

if ($VERBLIST !~ /[a-z]/ && !$vars{'output_web'} && !$vars{'output_paper'} && !$vars{'output_add'} && !$vars{'exercise'}) {
$VERBLIST = $data[0];
}

foreach my $verb (split(/;/,";$VERBLIST;")) {
if ($verb =~ /:/) {

$verb_count++;

my @vp = split(/:/,$verb);
my $NAME = $vp[1];
if ($data[2] eq "en") {
$NAME = qq~<span class="col9">to</span> $vp[1]~;
}
my $vp1js = $vp[1];
$vp1js =~ s~[^A-Za-z0-9]~~g;

if ($vp[0] =~ /^(custom|group)_/) {
$GROUPS .= qq~<a id="app_input_verbs_verbbutton_$vp[0]" href="javascript:void(0);"
onclick="onojs_setvalue('app_input_use_verb_$vp[0]_id','0');onojs_hide('app_input_verbs_verbbutton_$vp[0]');"
class="button_dark button_mini mb5">
<table class="default_table">
<tr>
<td class="p0">$vp[1]</td>
<td></td>
<td class="p0">
<div class="rel" style="top:-1px">
<img class="block trans80" src="/ono/osr/images/icons/ono/32x32/delete.png" style="width:12px;height:12px" alt="">
</div>
</td>
</tr>
</table>
</a>
<input type="hidden" id="app_input_use_verb_$vp[0]_id" name="app_input_use_verb_$vp[0]" value="1">
<input type="hidden" name="app_info_use_verb_$vp[0]" value="$vp[1]">
~;
} else {
$VERBS .= qq~<a id="app_input_verbs_verbbutton_$vp[0]" href="javascript:void(0);" onclick="app_input_verbs_js_verbbox('$vp[0]','$vp1js');"
class="button button_mini mb5">
<table class="default_table">
<tr>
<td class="p0">$NAME</td>
<td></td>
<td class="p0">
<div class="rel" style="top:-1px">
<img class="block trans80" src="/ono/osr/images/icons/ono/32x32/delete.png" style="width:12px;height:12px" alt="">
</div>
</td>
</tr>
</table>
</a>
<input type="hidden" id="app_input_use_verb_$vp[0]_id" name="app_input_use_verb_$vp[0]" value="1">
<input type="hidden" name="app_info_use_verb_$vp[0]" value="$vp[1]">
~;
}

}
}

if ($verb_count < 12) {
$hide_add_max = " hide";
} else {
$hide_add_button = " hide";
}

if ($vars{'output_add'} && !$vars{'output_add_verb'} && !$vars{'output_add_group'}) {
$VERBADD = $data[1];
} else {
$hide_add = " hide";
}

if ($vars{'output_print_verbs'}) {
$hide_print_button = " hide";
}

$data[1] = "";

# <input type="submit" name="output_print_verbs" value="$BLK{'print_verb'}" class="button button_mini mb5$hide_print_button">

$CONF = qq~<div class="rel inline w100">
$VERBS
$GROUPS
<div id="app_input_verbs_add_button" class="fl $hide_add_button">
<input type="submit" name="output_add" value="$BLK{'add'}..." class="button_green button_mini ml10 mb5">
</div>
<div id="app_input_verbs_add_max" class="ml10 col9 small fl$hide_add_max">(max. 12)</div>
<div id="app_input_verbs_verbbox_add" class="box_black abs w100$hide_add" style="top:-32px;left:-32px;z-index:99">
<a href="javascript:void(0);" onclick="onojs_hide('app_input_verbs_verbbox_add');">
<img src="/ono/osr/images/icons/crystal/32x32/ono/close.png" class="close" alt="">
</a>
<h4 class="cole">$BLK{'Add'}</h4>
<div class="box_paper" style="padding-bottom:0px">
<div class="inline w100">$VERBADD</div>
</div>
</div>
<div id="app_input_verbs_verbbox" class="box_fabric pad12_2 radius5 abs w50 hide" style="top:5px;left:5px;z-index:99">
<a href="javascript:void(0);" onclick="onojs_hide('app_input_verbs_verbbox');">
<img src="/ono/osr/images/icons/crystal/32x32/ono/close.png" class="close" alt="">
</a>
<h4 class="col6">$BLK{'Verb'} '$TO<span id="app_input_verbs_verbbox_title" class="bold">$BLK{'please_wait'}...</span>'</h4>
<div class="box_paper">
<div class="inline w100">
<a href="javascript:void(0);" onclick="app_input_verbs_js_verb_remove();" class="button_red">$BLK{'remove'}</a>
</div>
</div>
<input type="hidden" id="app_input_verbs_verbbox_verb_id" name="app_input_verbs_verbbox_verb" value="">
</div>
</div>
<script>
function app_input_verbs_js_verbbox(verb,real) {
onojs_block('app_input_verbs_verbbox');
onojs_sethtml('app_input_verbs_verbbox_title',real);
onojs_setvalue('app_input_verbs_verbbox_verb_id',verb);
}
function app_input_verbs_js_verb_remove(verb) {
var verb = onojs_getvalue('app_input_verbs_verbbox_verb_id');
onojs_setvalue('app_input_use_verb_'+verb+'_id','0');
onojs_hide('app_input_verbs_verbbutton_'+verb);
onojs_hide('app_input_verbs_verbbox');
onojs_hide('app_input_verbs_add_max');
onojs_block('app_input_verbs_add_button');
}
</script>
~;

# this is required to make programmed exercises work:

if ($vars{'exercise'} && $vars{'exercise_id'}) {
foreach my $key (keys %vars) {
if ($key =~ /app_input_use_verb_/) {
$CONF .= qq~<input type="hidden" name="$key" value="$vars{$key}">~;
}
}
}

}

### persons

if ($type eq "persons") {

$NAME = ""; #$BLK{'operations'};
$CLASS = $P0;

my $none_selected;
if (!"$vars{'app_input_person_1'}$vars{'app_input_person_2'}$vars{'app_input_person_3'}$vars{'app_input_person_4'}$vars{'app_input_person_5'}$vars{'app_input_person_6'}") {
$none_selected++;
}

$CONF .= qq~<table class="default_table"><tr>~;
my $new_data_zero_1;
my $new_data_zero_2;

$data[1] =~ s~\((s|p)\)~~g;
$data[1] =~ s~\:(.*?)\;~\;~g;
my @persons = split(/;/,$data[1]);

foreach my $opt (

"1\^A\^$persons[0]",
"2\^B\^$persons[1]",
"3\^C\^$persons[2]",
"4\^D\^$persons[3]",
"5\^E\^$persons[4]",
"6\^F\^$persons[5]",

) {

my @op = split(/\^/,$opt);

if ($data[0] =~ /$op[0]/) {

my $sel;

if ($vars{"app_input_person_$op[0]"} > 0) {
$sel++;
}
if (!$vars{'output_selected'} && $none_selected && $data[0] =~ /$op[1]/) {
$sel++;
}
if ($none_selected) {
$sel++;
}

$new_data_zero_1 .= $op[0];
if ($sel) {
$new_data_zero_2 .= $op[1];
}

# new switch -S: adjust size by content + center content

$CONF .= ONO::Lib::UI::Check->switch("app_input_person_$op[0]",$sel,"S",$op[2]);

}

}

$CONF .= qq~</tr></table>~;

$data[0] = "$new_data_zero_1-$new_data_zero_2";

}

### tenses

if ($type eq "tenses") {

$NAME = ""; #$BLK{'tenses'};
$CLASS = $P0;

my $tenses_ref = $data[0];
my $tenses_switches = $data[4];

# -M lang mix mode

my $TENSE_ID = "app_input_tense_use";

if ($tenses_switches =~ /M/) {
$TENSE_ID = "app_input_lang_mix_$data[5]_tense_use";
}

if ($tenses_ref) {

my @tenses = @$tenses_ref;
my $num = @tenses;

my ($JS_ALL,$JS_NONE,@JS_ALT);

$CONF = qq~<table class="wide_table">~;

for (my $i = 0; $i < 6; $i++) {

my @tp1 = split(/:/,$tenses[$i]);
my @tp2 = split(/:/,$tenses[$i+6]);

if ($tp1[2] =~ /[a-z]/) {
$tp1[1] = qq~<div class="rel" onmouseover="onojs_block('app_input_tenses_hint_1_$i');" onmouseout="onojs_hide('app_input_tenses_hint_1_$i');">
$tp1[1]<div id="app_input_tenses_hint_1_$i" class="box_paper p0 abs small col9 hide" style="top:16px;left:16px;z-index:99"> ($tp1[2]) </div>
</div>
~;
}
if ($tp2[2] =~ /[a-z]/) {
$tp2[1] = qq~<div class="rel" onmouseover="onojs_block('app_input_tenses_hint_2_$i');" onmouseout="onojs_hide('app_input_tenses_hint_2_$i');">
$tp2[1]<div id="app_input_tenses_hint_2_$i" class="box_paper p0 abs small col9 hide" style="top:16px;left:16px;z-index:99"> ($tp2[2]) </div>
</div>
~;
}

my ($SWITCH1,$SWITCH2,$W50);

if ($tp1[0]) {
$SWITCH1 = ONO::Lib::UI::Check->switch("${TENSE_ID}_$tp1[0]",$vars{"${TENSE_ID}_$tp1[0]"},"ms");
$JS_ALL .= qq~ono_ui_switch_${TENSE_ID}_$tp1[0]_on();~;
$JS_NONE .= qq~ono_ui_switch_${TENSE_ID}_$tp1[0]_off();~;
}
if ($tp2[0]) {
$SWITCH2 = ONO::Lib::UI::Check->switch("${TENSE_ID}_$tp2[0]",$vars{"${TENSE_ID}_$tp2[0]"},"ms");
$JS_ALL .= qq~ono_ui_switch_${TENSE_ID}_$tp2[0]_on();~;
$JS_NONE .= qq~ono_ui_switch_${TENSE_ID}_$tp2[0]_off();~;
}

if ($tp1[0]) {

if ($tenses_switches =~ /M/) {

$tp1[1] =~ s~Imperfekt~Imp.~;
$tp1[1] =~ s~Indicatif~Ind.~;
$tp1[1] =~ s~composé~comp.~;
$tp1[1] =~ s~continuous~cont.~;
$tp1[1] =~ s~perfect~perf.~;
$tp2[1] =~ s~perfect~perf.~;
$tp2[1] =~ s~Participe~Part.~;

} else {

$W50 = "w50";

}

if ($num > 6) {

$CONF .= qq~ <tr>
<td>$SWITCH1</td>
<td class="$W50" style="padding:1px 5px 1px 5px">$tp1[1]</td>
<td>$SWITCH2</td>
<td class="$W50" style="padding:1px 5px 1px 5px">$tp2[1]</td>
</tr>
~;

} else {

$CONF .= qq~ <tr>
<td>$SWITCH1</td>
<td class="w100" style="padding:1px 5px 1px 5px">$tp1[1]</td>
</tr>
~;

}
}
}

$CONF .= qq~</table>~;

if ($tenses_switches !~ /M/) {

$CONF .= qq~<div id="app_input_tenses_buttons" class="p2 trans50"
onmouseover="onojs_class('app_input_tenses_buttons','p2')" onmouseout="onojs_class('app_input_tenses_buttons','p2 trans50')">
<div class="inline w100">
<a href="javascript:void(0);" onclick="app_input_tenses_js_all();" class="button_green button_mini mb5">$BLK{'all'}</a>
<a href="javascript:void(0);" onclick="app_input_tenses_js_none();" class="button_orange button_mini mb5">$BLK{'none'}</a>
~;

for (my $i = 1; $i < 4; $i++) {
if ($data[$i]) {
my $opts = $data[$i];
$CONF .= qq~<a href="javascript:void(0);" onclick="app_input_tenses_js_alt_$i();" class="button button_mini mb5">$vars{"app_conf_input_tense_$i"}</a>~;
foreach my $opt (@$opts) {
$JS_ALT[$i] .= qq~ono_ui_switch_${TENSE_ID}_${opt}_on();~;
}
}
}

$CONF .= qq~ </div>
</div>
<script>
function app_input_tenses_js_all() {$JS_ALL}
function app_input_tenses_js_none() {$JS_NONE}
function app_input_tenses_js_alt_1() {$JS_NONE;$JS_ALT[1]}
function app_input_tenses_js_alt_2() {$JS_NONE;$JS_ALT[2]}
function app_input_tenses_js_alt_3() {$JS_NONE;$JS_ALT[3]}
</script>
~;

}

}

}

### writing lines

if ($type eq "writelines") {

$NAME = $BLK{'lines'};
if ($switches !~ /i/) {
$CLASS = $P0;
}

if (!$data[0]) {
$data[0] = "writelines";
}

$CONF = qq~<table class="default_table">
<tr>
<td>
~;

my @displays = (
qq~<div class="p6 bb"></div>~,
qq~<div class="p6 bo"></div>~,
qq~<table class="default_table bo"><tr class="bb"><td class="p3 br"></td><td class="p3 br"></td><td class="p3 br"></td></tr><tr><td class="p3 br"></td><td class="p3 br"></td><td class="p3 br"></td></tr></table>~,
qq~<div class="bo"><div class="p2 bb"></div><div class="p2 bb"></div><div class="p2 bt"></div></div>~,
);

my @tabs = (
qq~std:dark:<div class="p2 wi24 hi16">$displays[0]</div>~,
qq~box:dark:<div class="p2 wi24 hi16">$displays[1]</div>~,
qq~grid:dark:<div class="p2 wi24 hi16">$displays[2]</div>~,
qq~kid:dark:<div class="p2 wi24 hi16">$displays[3]</div>~,
);

$CONF .= ONO::Lib::UI::Select->buttons(
"app_input_$data[0]",
$vars{"app_input_$data[0]_status"},
\@tabs,
"",
"fp",
$BLK_ref,
);

my $SIZE;
for (my $i = 5; $i < 19; $i++) {
$SIZE .= qq~<option value="$i">$i mm</option>~;
}

$CONF .= qq~ </td>
<td><div class="select"><select name="app_input_$data[0]_size"><option value="">$BLK{'default'}</option><option value="">-----</option>$SIZE</select></div></td>
</tr>
</table>
~;

}

### lang(s)

if ($type eq "lang") {

$type = "langs";

}

if ($type eq "langsel") {

my $SWITCH = ONO::Lib::UI::Check->switch(
"app_input_lang_use_$data[0]",
$vars{"app_input_lang_use_$data[0]"},
"Js","",
qq~onojs_class('app_input_lang_use_$data[0]_flag','');onojs_class('app_input_lang_use_$data[0]_name','');~,
qq~onojs_class('app_input_lang_use_$data[0]_flag','trans50');onojs_class('app_input_lang_use_$data[0]_name','trans50');~,
);
my $TRANS;
if (!$vars{"app_input_lang_use_$data[0]"}) {
$TRANS = "trans50";
}

$NAME = "";
$CONF = qq~<table class="default_table cursorlink">
<tr>
<td>$SWITCH</td>
<td onclick="ono_ui_switch_app_input_lang_use_$data[0]_toggle();">
<div id="app_input_lang_use_$data[0]_flag" class="$TRANS">
<img class="flag" src="/ono/osr/images/flags/languages/$data[0].png" style="width:24px;height:18px" alt="$data[0]">
<div>
</td>
<td onclick="ono_ui_switch_app_input_lang_use_$data[0]_toggle();">
<div id="app_input_lang_use_$data[0]_name" class="$TRANS">$BLK{$data[0]}</div>
</td>
</tr>
</table>
~;

}

if ($type eq "langs") {

# -s "language" as name

# -m allow mix (en/de -> de/en, disabled by default)
# -M allow mix (en/de -> de/en, enabled by default) -- not implemented yet

$NAME = "";
$CLASS = $P0;

if ($switches =~ /s/) {
$NAME = $BLK{'language'};
}

$CONF = qq~<table class="default_table">
<tr>
~;

my $lang_counter;

foreach my $dat (@data) {

if ($dat eq ">") {

# padding 4px is required to avoid img flag to jump

$CONF .= qq~ <td class="pad5_2">
<div style="padding:4px">
<a href="javascript:void(0);" onclick="app_input_langs_toggle();">
<img class="block16" src="/ono/osr/images/arrows/nuvola/black/nav_next.png" alt="">
</a>
</div>
</td>
~;

}

if ($dat =~ m~^(.*?);(.*)$~) {

$lang_counter++;

my $default = $1;
my $OPT;

foreach my $opt (split(/:/,$2)) {
if ($opt) {
if ($opt eq "img") {
$OPT .= qq~<tr class="bb"><td></td><td></td></tr><tr><td></td><td></td></tr>
<tr class="row cursorlink" onclick="app_input_langs_select('$lang_counter','img');">
<td class="pad5_2">
<a href="javascript:void(0);" onclick="app_input_langs_select('$lang_counter','img');">
<img class="block24" src="/ono/osr/images/icons/crystal/32x32/filesystems/image.png" alt="">
</a>
</td>
<td>
<a href="javascript:void(0);" onclick="app_input_langs_select('$lang_counter','img');" class="col3">$BLK{'Images'}</a>
</td>
</tr>
~;
} else {
my $Opt = ucfirst $opt;
$OPT .= qq~<tr class="row cursorlink" onclick="app_input_langs_select('$lang_counter','$opt');">
<td class="pad5_2">
<a href="javascript:void(0);" onclick="app_input_langs_select('$lang_counter','$opt');">
<img class="flag_large" src="/ono/osr/images/flags/languages/$opt.png" alt="">
</a>
</td>
<td>
<a href="javascript:void(0);" onclick="app_input_langs_select('$lang_counter','$opt');" class="col3">$BLK{$Opt}</a>
</td>
</tr>
~;
}
}
}

my $DEF = qq~<img id="app_input_langs_lang_${lang_counter}_flag" class="flag_large" src="/ono/osr/images/flags/languages/$default.png" alt="">~;
if ($default eq "img") {
$DEF = qq~<img id="app_input_langs_lang_${lang_counter}_flag" class="block24" src="/ono/osr/images/icons/crystal/32x32/filesystems/image.png" alt="">~;
}

$CONF .= qq~ <td>
<div class="rel" onmouseover="onojs_block('app_input_langs_select_$lang_counter');"
onmouseout="onojs_hide('app_input_langs_select_$lang_counter');">
<div>$DEF</div>
<div id="app_input_langs_select_$lang_counter" class="abs hide" style="top:24px;left:5px;z-index:99">
<div class="box_paper">
<table class="default_table">$OPT</table>
</div>
<img class="block16 abs" src="/ono/osr/images/arrows/nuvola/white32shadow/nav_up.png" style="top:-15px;left:5px" alt="">
</div>
</div>
<input type="hidden" id="app_input_langs_lang_${lang_counter}_id" name="app_input_langs_lang_$lang_counter" value="$default">
</td>
~;

}
}

if ($switches =~ /m/) {

my $SWITCH = ONO::Lib::UI::Check->switch("app_input_langs_mix",$vars{'app_input_langs_mix'},"m");
$CONF .= qq~ <td class="pad10_2"></td><td>$SWITCH</td><td class="small">$BLK{'mix'}</td>~;

}

if ($switches =~ /p/) {

$sel{"prefer_$vars{'app_input_langs_prefer'}"} = " selected";

$CONF .= qq~ <td class="pad10_2"></td>
<td class="small">
<div class="select"><select name="app_input_langs_prefer" class="button_mini">
<option value="">$BLK{'prefer'}...</option>
<option value="">----</option>
<option value="">$BLK{'everything'}</option>
<option value="nouns"$sel{"prefer_nouns"}>$BLK{'nouns'}</option>
<option value="verbs"$sel{"prefer_verbs"}>$BLK{'verbs'}</option>
</select></div>
</td>
~;

}

$CONF .= qq~ </tr>
</table>
<script>
function app_input_langs_select(id,lang) {
onojs_hide('app_input_langs_select_'+id);
onojs_setvalue('app_input_langs_lang_'+id+'_id',lang);
if (lang == 'img') {
onojs_setsrc('app_input_langs_lang_'+id+'_flag','$vars{'software_base'}/ono/osr/images/icons/crystal/32x32/filesystems/image.png');
onojs_class('app_input_langs_lang_'+id+'_flag','block24');
} else {
onojs_setsrc('app_input_langs_lang_'+id+'_flag','$vars{'software_base'}/ono/osr/images/flags/languages/'+lang+'.png');
onojs_class('app_input_langs_lang_'+id+'_flag','flag_large');
}
}
function app_input_langs_toggle() {
var one = onojs_getvalue('app_input_langs_lang_1_id');
if (one == 'img') {
// you can't move img to position 2
} else {
var two = onojs_getvalue('app_input_langs_lang_2_id');
app_input_langs_select('1',two);
app_input_langs_select('2',one);
}
}
</script>
~;

}

### selections

if ($type eq "selections") {

# -l add list management button

# data:
#
# 0 name
# 1 default lessons
# 2 all lessons
# 3 add / custom / etc...
# 4 max categories allowed (default = 12)

$NAME = $data[0];

my $max_cats = 12;
if ($data[4]) {
$max_cats = $data[4];
}

my ($BASIC,$GROUPS,$SELLIST,$SELADD,$hide_add,$hide_add_button,$hide_print_button,$hide_add_max,$sel_count);

# add a single item

# if ($vars{'output_add_item'} =~ /^(.*?):(.*?)$/) {
#
# $vars{"app_input_use_item_$1"}++;
# $vars{"app_info_use_item_$1"} = $2;
#
# }

# add a group

foreach my $key (keys %vars) {
if ($key =~ /^output_add_group_(.*?)$/) {
my $group = $1;
if (";$SELLIST" !~ /;$group:/ && !$vars{"app_input_use_group_$group"}) {
$SELLIST .= qq~$group:$vars{"output_add_group_$group"};~;
}
$vars{'output_add_group'}++;
}
}

# add a custom group

if ($vars{'output_add_custom'} =~ /^(.*?):(.*?)$/) {
my ($id1,$id2) = ($1,$2);
if (";$SELLIST" !~ /;$id1:/ && !$vars{"app_input_use_custom_$id1"} && !$vars{"app_info_use_group_$id1"}) {
$vars{"app_input_use_custom_$id1"}++;
$vars{"app_info_use_custom_$id1"} = $id2;
$SELLIST .= qq~$id1:$id2;~;
}
}

# build list

foreach my $key (sort keys %vars) {
if ($key =~ /^app_input_use_group_(.*?)$/ && $vars{$key}) {
my $group = $1;
if ($vars{"app_info_use_group_$group"}) {
$SELLIST .= qq~$group:$vars{"app_info_use_group_$group"};~;
}
}
}

# use default list if no lists have been selected AND if not reloaded AND if this is not a programmed exercise

if ($SELLIST !~ /[a-z]/ && !$vars{'output_web'} && !$vars{'output_paper'} && !$vars{'output_add'} && !$vars{'exercise'} && !$vars{'exercise_id'}) {
$SELLIST = $data[1];
}

foreach my $group (split(/;/,";$SELLIST;")) {
if ($group =~ /:/) {

$sel_count++;

my @vp = split(/:/,$group);
my $NAME = $vp[1];
my $vp1js = $vp[1];
$vp1js =~ s~[^A-Za-z0-9]~~g;

if ($vp[0] =~ /^(custom|group)_/) {
$GROUPS .= qq~<a id="app_input_groups_groupbutton_$vp[0]" href="javascript:void(0);"
onclick="onojs_setvalue('app_input_use_group_$vp[0]_id','0');onojs_hide('app_input_groups_groupbutton_$vp[0]');"
class="button_dark button_mini mb5">$vp[1] <span class="col9">[<span class="lightred">−</span>]</span></a>
<input type="hidden" id="app_input_use_group_$vp[0]_id" name="app_input_use_group_$vp[0]" value="1">
<input type="hidden" name="app_info_use_group_$vp[0]" value="$vp[1]">
~;
} else {
$BASIC .= qq~<a id="app_input_groups_groupbutton_$vp[0]" href="javascript:void(0);" onclick="app_input_groups_js_groupbox('$vp[0]','$vp1js');"
class="button button_mini mb5">
<table class="default_table">
<tr>
<td class="p0">$NAME</td>
<td></td>
<td class="p0">
<div class="rel" style="top:-1px">
<img class="block trans80" src="/ono/osr/images/icons/ono/32x32/delete.png" style="width:12px;height:12px" alt="">
</div>
</td>
</tr>
</table>
</a>
<input type="hidden" id="app_input_use_group_$vp[0]_id" name="app_input_use_group_$vp[0]" value="1">
<input type="hidden" name="app_info_use_group_$vp[0]" value="$vp[1]">
~;
}

}
}

if ($sel_count < $max_cats) {
$hide_add_max = " hide";
} else {
$hide_add_button = " hide";
}

if ($vars{'output_add'} && !$vars{'output_add_group'}) {
my @BUTTONS;
foreach my $add (split(/;/,$data[2])) {
my @ap = split(/:/,$add);
if ($ap[0]) {
$ap[1] =~ s~\ +$~~;
my $sort = ONO::Lib::Basic->sortstring($ap[1]);
@BUTTONS = (@BUTTONS,qq~<!-- $sort --><input type="submit" name="output_add_group_$ap[0]" value="$ap[1]" class="button_green button_small mb10">~)
}
}
foreach my $ADD (sort @BUTTONS) {
$SELADD .= $ADD;
}

} else {
$hide_add = " hide";
}

if ($vars{'output_print_groups'}) {
$hide_print_button = " hide";
}

# custom: add teacher's virclass lists

my $community = ONO::IO->community();
my $db = ONO::DB->connect($community);
my ($MANAGE_LISTS,$CUSTOM) = &get_custom_lists("",$db,$community,$vars{'username'},"vocs,words");

my $TITLE;
if ($switches =~ /l/) {

my @txt = (
"Teachers may create their own custom vocabulary lists in their Virtual Classrooms.",
"You need to be logged in to use this feature.",
"Manage your own vocabulary lists:",
"You are not listed as a teacher in any classrooms.",
);

if ($vars{'app_lang'} eq "de") {
@txt = (
"Lehrer können ihre eigenen benutzerdefinierten Vokabellisten in ihren Virtuellen Klassen erstellen.",
"Du musst angemeldet sein, um diese Funktion nutzen zu können.",
"Meine Vokabellisten verwalten:",
"Du bist in keinem Klassenzimmer als Lehrer aufgeführt.",
);
}

if ($vars{'app_lang'} eq "lu") {
@txt = (
"Enseignante kënnen hir eege personnaliséiert Vokabellëschten an hire Virtuelle Klassen erstellen.",
"Du muss ageloggt sinn fir dës Funktioun ze benotzen.",
"Meng Vokabellëschte geréieren:",
"Du bass net als Enseignant an engem Klassesäll opgelëscht.",
);
}

if ($vars{'app_lang'} eq "fr") {
@txt = (
"Les enseignants peuvent créer leurs propres listes de vocables personnalisées dans leurs salles de classe virtuelles.",
"Vous devez être connecté pour utiliser cette fonctionnalité.",
"Gérer mes listes de vocables:",
"Vous n'êtes enrégistré comme enseignant dans aucune salle de classe.",
);
}

my $MANAGE = qq~<div class="lightred mb5">$txt[1]</div>
<div class="inline w100"><a href="javascript:void(0);" onclick="onojs_hide('apps_manage_lists');" class="button_yellow">$BLK{'close'}</a></div>
~;

if ($vars{'username'}) {
$MANAGE = qq~<div>$txt[2]</div>
<div class="block" style="max-height:200px;overflow-y:scroll">
<div class="inline">$MANAGE_LISTS</div>
</div>
~;
if (!$MANAGE_LISTS) {
$MANAGE = qq~<div class="lightred mb5">$txt[3]</div>
<div class="inline w100"><a href="javascript:void(0);" onclick="onojs_hide('apps_manage_lists');" class="button_yellow">$BLK{'close'}</a></div>
~;
}
}

$TITLE .= qq~<div class="fr">
<a href="javascript:void(0);" onclick="onojs_block('apps_manage_lists');" class="button_yellow button_small mt10">$BLK{'manage_lists'}</a>
</div>
<div id="apps_manage_lists" class="box_yellow w100 abs hide" style="top:30px;left:10px">
<a href="javascript:void(0);" onclick="onojs_hide('apps_manage_lists');"><img class="close" alt="close button"></a>
<h4 class="yellow">$BLK{'Manage_lists'}</h4>
<div class="box_paper">
<div class="mb5">$txt[0]</div>
$MANAGE
</div>
</div>
~;
}
if ($data[3] =~ s~^(.*)::~~) {
$TITLE .= qq~<div class="mt10 mb5">$1:</div>~;
}

foreach my $opt (split(/;/,";$data[3];")) {
if ($opt eq "-") {
$CUSTOM .= qq~<option value="">----</option>~;
} else {
my @op = split(/:/,$opt);
if ($op[0] && $op[1]) {
$CUSTOM .= qq~<option value="$op[0]:$op[1]">$op[1]</option>~;
}
}
}

$SELADD .= qq~<div class="inline w100 mb10 bt" style="padding-top:5px">
$TITLE
<table class="default_table">
<tr>
<td class="p0"><div class="select"><select name="output_add_custom"><option value="">$BLK{'select'}...</option><option value="">----</option>$CUSTOM</select></div></td>
<td></td>
<td class="p0">$BLK{'submit_add_2_small'}</td>
</tr>
</table>
</div>
~;


# <input type="submit" name="output_print_groups" value="$BLK{'print'}" class="button_yellow button_mini mb5$hide_print_button">

$CONF = qq~<div class="rel inline w100">
$BASIC
$GROUPS
<div id="app_input_groups_remove_button" class="fl trans30"
onmouseover="onojs_class('app_input_groups_remove_button','fl'); "onmouseout="onojs_class('app_input_groups_remove_button','fl trans30');">
<a href="javascript:void(0);" onclick="onojs_block('app_input_groups_remove_box');">
<img class="block20 mb10 ml5" src="/ono/osr/images/icons/ono/32x32/delete.png" alt="">
</a>
</div>
<div id="app_input_groups_remove_box" class="box_fabric abs hide" style="top:-10px;left:75px;z-index:999">
<a href="javascript:void(0);" onclick="onojs_hide('app_input_groups_remove_box');"><img class="close" alt="close button"></a>
<div class="large bold col6 mb10">$BLK{'Remove'}</div>
<div class="box_paper">
<div class="inline">
<a href="javascript:void(0);" onclick="app_input_groups_js_group_remove_all();onojs_hide('app_input_groups_remove_box');"
class="button_red">$BLK{'remove_all'}</a>
</div>
</div>
</div>
<div id="app_input_groups_add_button" class="fl $hide_add_button mb5">
<input type="submit" name="output_add" value="$BLK{'add'}..." class="button_green button_mini ml10 mb5">
</div>
<div id="app_input_groups_add_max" class="ml10 col9 small fl$hide_add_max">(max. $max_cats)</div>
<div id="app_input_groups_groupbox_add" class="box_black abs w100$hide_add" style="top:-72px;left:-32px;z-index:99;min-width:460px">
<a href="javascript:void(0);" onclick="onojs_hide('app_input_groups_groupbox_add');">
<img src="/ono/osr/images/icons/crystal/32x32/ono/close.png" class="close" alt="">
</a>
<h4 class="cole">$BLK{'Add'}</h4>
<div class="box_paper" style="padding-bottom:0px">
<div class="inline w100">$SELADD</div>
</div>
</div>
<div id="app_input_groups_groupbox" class="box_fabric pad12_2 radius5 abs w50 hide" style="top:5px;left:5px;z-index:99">
<a href="javascript:void(0);" onclick="onojs_hide('app_input_groups_groupbox');">
<img src="/ono/osr/images/icons/crystal/32x32/ono/close.png" class="close" alt="">
</a>
<h4 class="col6">$BLK{'group'} '<span id="app_input_groups_groupbox_title" class="bold">$BLK{'please_wait'}...</span>'</h4>
<div class="box_paper">
<div class="inline w100">
<a href="javascript:void(0);" onclick="app_input_groups_js_group_remove();" class="button_red">$BLK{'remove'}</a>
</div>
</div>
<input type="hidden" id="app_input_groups_groupbox_group_id" name="app_input_groups_groupbox_group" value="">
</div>
</div>
<script>
function app_input_groups_js_groupbox(group,real) {
onojs_block('app_input_groups_groupbox');
onojs_sethtml('app_input_groups_groupbox_title',real);
onojs_setvalue('app_input_groups_groupbox_group_id',group);
}
function app_input_groups_js_group_remove(group) {
var group = onojs_getvalue('app_input_groups_groupbox_group_id');
onojs_setvalue('app_input_use_group_'+group+'_id','0');
onojs_hide('app_input_groups_groupbutton_'+group);
onojs_hide('app_input_groups_groupbox');
onojs_hide('app_input_groups_add_max');
onojs_block('app_input_groups_add_button');
}
function app_input_groups_js_group_remove_all() {
for (i = 1;i < 99;i++){
onojs_setvalue('app_input_use_group_'+i+'_id','0');
onojs_hide('app_input_groups_groupbutton_'+i);
}
}

</script>
~;

# this is required to make programmed exercises work:

if ($vars{'exercise'} && $vars{'exercise_id'}) {
foreach my $key (keys %vars) {
if ($key =~ /app_input_use_group_/) {
$CONF .= qq~<input type="hidden" name="$key" value="$vars{$key}">~;
}
}
}

}

### custom

if ($type eq "custom") {

$NAME = $data[0];
$CONF .= $data[1];

if ($switches =~ /P/) {
$CLASS = $P0;
}

}

### more options

if ($type eq "moreopts" && !$vars{'app_input_moreopts'}) {

# -b black (dark) button
# -m margin left (10px)

my ($class,$color);
if ($data[0] =~ /m/) {
$class .= " ml10";
}
if ($data[0] =~ /b/) {
$color = "_dark";
}

$CONF .= qq~<a href="javascript:void(0);" id="app_input_moreopts_js_button" onclick="app_input_moreopts_js();"
class="button$color button_mini$class">$BLK{'more_options'}...</a>
<input type="hidden" id="app_input_moreopts_input" name="app_input_moreopts" value="">
<script>
function app_input_moreopts_js() {
onojs_hide('app_input_moreopts_js_button');
document.getElementById('app_input_moreopts_input').value='1';
var elements = document.getElementsByName('app_input_optional_tr');
for (var count = 0; count < elements.length; count++){elements[count].style.display = 'table-row';}
}
</script>
~;

}

### done

if ($NAME && $NAME !~ /\</ && $switches !~ /j/) {
$NAME =~ s~ ~ ~g;
$NAME = "$NAME:";
}

if ($switches =~ /i/) {
$CONF = qq~<table class="default_table"><tr><td class="p0">$NAME</td><td class="pad10_0">$CONF</td></tr></table>~;
$NAME = "";
}

if ($switches =~ /j/) {
$CONF = qq~<table class="default_table"><tr><td class="p0">$CONF</td><td class="pad5_0">$NAME</td></tr></table>~;
$NAME = "";
}

if ($switches =~ /N/) {
$NAME = "";
}

if ($ADDROW) {
$ADDROW = qq~<tr id="app_input_addrow_$ID" class="hide">
<td></td>
<td class="bl bb br p5">
<div class="rel">
<a href="javascript:void(0);"
onclick="onojs_hide('app_input_addrow_$ID');
onojs_block('app_input_addrow_icon_$ID');">
<img class="block20 abs" src="/ono/osr/images/icons/crystal/32x32/ono/close.png" style="right:-15px;top:-15px" alt="">
</a>
$ADDROW
</div>
</td>
</tr>
~;
}

my $TROPCLASS;

if ($type =~ /^(checks|tip|selections|verbs|tenses|mulrows)$/ || ($type eq "comma" && $switches =~ /C/) || $switches =~ /T/) {
$TROPCLASS = " vtop";
}

if ($switches =~ /t/) {
$TROPCLASS .= " trans50";
}

if ($switches =~ /h/ && !$vars{'app_input_moreopts'} && !$vars{'exercise_editor'}) {
$TROPTS = qq~ name="app_input_optional_tr" class="hide$TROPCLASS"~;
}
if ($vars{'exercise'} && !$vars{'exercise_editor'}) {
$TROPTS = qq~ class="hide$TROPCLASS"~;
}
if ($TROPCLASS && !$TROPTS) {
$TROPTS = qq~ class="$TROPCLASS"~;
}

if ($type ne "custom" && !$vars{'app_disable_storage_type'}) {
$CONF .= qq~<input type="hidden" name="app_storage_type_$type" value="1:$data[0]:$data[1]:$data[2]:$data[3]:">~;
}
if ($switches =~ /L/) {
$CONF = qq~<div class="ml10">$CONF</div>~;
}

if ($DEBUG && ONO::IO->devstation) {
$ADDROW .= qq~<tr><td>debug:</td><td>$DEBUG</td></tr>~;
}

return qq~<tr id="ono_fwapps_input_row_$ID"$TROPTS><td class="tar">$NAME</td><td$CLASS>$CONF</td></tr>$ADDROW~;

}

sub get_custom_lists {

my (
$self,
$db,
$community,
$user,
$type,
$langs,
) = @_;

#: Get custom lists defined by users.

my ($MANAGE_LISTS,$CUSTOM,$LANGS,%used);

if ($user) {

# max 2 different types allowed for the moment

my $TYPE = "type = '$type'";
if ($type =~ /^(.*?)\,(.*?)$/) {
$TYPE = "(type = '$1' OR type = '$2')";
}
if ($langs) {
$LANGS = " AND langs = '$langs'";
}

my $found;
my $userdir = "media/users/".ONO::IO->deepdir($user)."/$user/documents/lists/lists";

foreach my $line2 (ONO::DB->select($db,"${community}_school_apps_configs","virclass = '0' AND owner = '$user' AND $TYPE$LANGS")) {
my @row2 = ONO::DB->readcols($line2);
$found++;
$row2[7] =~ s~^$userdir~~;
$row2[7] =~ s~/~ \> ~g;
my $NAME = ONO::Lib::Basic->shortstring("$user > $row2[7] > $row2[6]");
$NAME =~ s~\> \>~\>~g;
$CUSTOM .= qq~<option value="custom_$row2[1]:$row2[6]">$NAME</option>~;
}
if ($found) {
$CUSTOM .= qq~<option value="">----</option>~;
}

foreach my $line (ONO::DB->select($db,"${community}_school_virclass_relationships","username = '$user'")) {
my @row = ONO::DB->readcols($line);
if (!$used{$row[2]}) {
$used{$row[2]}++;
my $name = ONO::DB->get($db,"fullname","${community}_school_virclass","id = '$row[2]'");
if ($name) {
my $found;
$MANAGE_LISTS .= qq~<a href="/bin/virclass/?virclass=$row[2]&mode=lists" class="button_green button_small mt5" target="_parent">$name</a>~;
foreach my $line2 (ONO::DB->select($db,"${community}_school_apps_configs","virclass = '$row[2]' AND $TYPE$LANGS")) {
my @row2 = ONO::DB->readcols($line2);
$found++;
$row2[7] =~ s~^media/virclass/$row[2]/class/lists/lists/~~;
$row2[7] =~ s~/~ \> ~g;
my $NAME = ONO::Lib::Basic->shortstring("$name > $row2[7] > $row2[6]");
$NAME =~ s~\> \>~\>~g;
$CUSTOM .= qq~<option value="custom_$row2[1]:$row2[6]">$NAME</option>~;
}
if ($found) {
$CUSTOM .= qq~<option value="">----</option>~;
}
}
}
}
}

return ($MANAGE_LISTS,$CUSTOM);

}

sub fix_broken_app_link {

#: This is a dirty fix that will correct broken app IDs for older e-learning apps on the Morzino/Oli platform

my $app = $_[1];

$app =~ s~^(remember)$~memorize_words~;

return $app;

}

###############################################################################
# end of script
###############################################################################

1;

__END__