package ONO::Lib::UI::Form;
################################################################################
# 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;
###############################################################################
# search
###############################################################################
sub search {
my (
$self,
$name,
$value,
$placeholder,
$width,
$color,
$switches,
$js_function,
$maxlength,
) = @_;
#: Search field.
#:
#: -a auto - same as -c center, required for backward compatibility
#: -b mb5
#: -B disable button (doesn't get transparent though, nice for Ajax)
#: -B mb10
#: -c center
#: -f full size (larger)
#: -F focus (see -M for mobile disable)
#: -i extend id by _id (required in most cases when using JS)
#: -k use onkeyup instead of onkeypress
#: -l left (default, currently not parsed)
#: -m mini (smaller)
#: -M mobile focus disable
#: -r right
#: -R Responsive
#: -S prevent $js_function script code from being added (required for Ajax)
my $BASE = ONO::IO->base();
my $EXT_ID;
$value = ONO::IO->inputfilter($value);
my ($WIDTH2,$WIDTH3,$MORE,$ONCLICK,$ONKEYPRESS,$MAX,$BDIS,$hide_resp);
if ($color) {
$color = "_$color";
} else {
$color = "_green";
}
my ($class,$style,$style2);
if ($switches =~ /m/) {
$style .= "height:12px";
}
if ($switches =~ /f/) {
$style2 .= ";height:28px";
}
if ($switches =~ /(a|c)/) {
$class .= " auto";
}
if ($switches =~ /r/) {
$class .= " fr";
}
if ($switches =~ /b/) {
$class .= " mb5";
}
if ($switches =~ /B/) {
$class .= " mb10";
}
if ($switches =~ /B/) {
$BDIS = " disabled";
}
if ($switches =~ /i/) {
$EXT_ID = "_id";
}
my $ID = ONO::Lib::Code::RandomID->make();
my $TABLE = "default";
my $WIDTH = "width:${width}px";
if ($maxlength) {
$MAX = qq~ maxlength="$maxlength"~;
}
if ($js_function) {
$ONCLICK = qq~ onclick="$js_function"~;
$ONKEYPRESS = qq~ onkeypress="keypress_$name(event);"~;
if ($switches =~ /k/) {
$ONKEYPRESS = qq~ onkeyup="keypress_$name(event);"~;
}
if ($switches !~ /S/) {
$MORE .= qq~<script>function keypress_$name(e){if(e.keyCode === 13){e.preventDefault();$js_function;}}</script>~;
}
}
# only 100% currently supported
if ($width =~ /\%/) {
$TABLE = "wide";
$WIDTH = "width:100%";
}
if ($switches =~ /F/) {
if ($switches =~ /M/) {
if (ONO::IO->device("mobile") || ONO::IO->device("mac")) {
$MORE .= qq~<script>if (navigator.maxTouchPoints < 1) {onojs_focus('$name')}</script>~;
} else {
$MORE .= qq~<script>onojs_focus('$name');</script>~;
}
} else {
$MORE .= qq~<script>onojs_focus('$name');</script>~;
}
}
if ($switches =~ /R/) {
$hide_resp .= " hide800";
$MORE .= qq~<div id="ono_ui_search_resp_$ID" class="p2 hide block800">
<a href="javascript:void(0);" onclick="onojs_hide('ono_ui_search_resp_$ID');onojs_block('ono_ui_search_$ID');" class="button_green" style="padding:4px 10px 4px 10px">
<img class="inline" src="$BASE/ono/osr/images/actions/white_trans75/search.png" alt="search button">
</a>
</div>
~;
}
if ($width eq "100%") {
$WIDTH2 = " w100";
} else {
$WIDTH3 = $WIDTH;
}
return qq~<div id="ono_ui_search_$ID" class="$hide_resp">
<table class="${TABLE}_table$class">
<tr>
<td class="p0" style="$WIDTH">
<input type="text" id="$name$EXT_ID" name="$name" value="$value" placeholder="$placeholder..." class="query$WIDTH2" style="$WIDTH3$style$style2"$ONKEYPRESS$MAX>
</td>
<td class="p0" style="position:relative">
<input type="image" src="$BASE/ono/osr/images/actions/white_trans75/search.png" class="button$color button_right" style="$style;z-index:1" alt="search button"$ONCLICK$BDIS>
</td>
</tr>
</table>
</div>
$MORE
~;
}
###############################################################################
# save
###############################################################################
sub save {
my (
$self,
$name,
$value,
$placeholder,
$width,
$BLK_ref,
$switches,
$alt_id,
) = @_;
#: Save field (text input plus button).
#:
#: -a auto
#: -p padding left 5px
#: -u add an upload button
my %BLK = %$BLK_ref;
my ($CLASS,$UPLOAD);
if (!$width) {
$width = 100;
}
my $pl = 0;
if ($switches =~ /p/) {
$pl = 5;
}
if ($switches =~ /a/) {
$CLASS .= " auto";
}
my $BUTTON = "button_right";
if ($switches =~ /u/) {
$BUTTON = "button_middle";
$UPLOAD = qq~<td class="p0 nowrap"><a href="javascript:void(0);" onclick="onojs_block('$alt_id');" class="button_green button_right">$BLK{'upload'} / $BLK{'select'}</a></td>~;
}
return qq~<table class="default_table w$width rel$CLASS">
<tr>
<td class="p0 w100">
<input type="text" id="$name" name="$name" value="$value" placeholder="$placeholder..."
class="query w100" style="height:19px;border-right:0px solid #ffffff">
</td>
<td class="p0"><input type="submit" name="$BLK{'save'}" value="$BLK{'save'}" class="button_green $BUTTON"></td>
$UPLOAD
</tr>
</table>
~;
}
###############################################################################
# textarea
###############################################################################
sub textarea {
my (
$self,
$name,
$text,
$height,
$maxlength,
$placeholder,
$switches,
$rows,
) = @_;
#: Textarea.
#:
#: -B replace HTML breaks by carriage returns
#: -c count remaining chars (only if maxlegth defined)
#: -C clean text that doesn't contain any letters or numbers
#: -H help - only use this if links can be parsed, currently only works with -c option
#: -i line height 125%
#: -I line height 150%
#: -l count lines in textarea
#: -L larger content / font
#: -N disable name split feature
#: -p pop up to height (also see -P -q -Q)
#: -P always pop up if there is text
#: -q double initial popup size (can be combined with -Q)
#: -Q triple initial popup size (can be combined with -q)
#: -s string (input type text) instead of textarea, ignores height
#: -t top margin 2 (can be combined with -T)
#: -T top margin 5 (can be combined with -t)
#: -u count UP instead of counting down
#: -w wider (95 -> 98)
#: -W wider (95 -> 100)
#:
#: Note that using "cCpP" as switches may be a good idea in most cases
#:
#: Note that "$rows" will actually limit the maximum number of rows that can be entered,
#: this feature requires $ID to be in "id:name" format
my ($ID,$ID_USE,$STYLE,$ONCLICK,$ONKEY,$COUNT,$LINES,$MAX,$HELP);
if ($name =~ /^(.*?):(.*?)$/ && $switches !~ /N/) {
$ID = $1;
$name = $2;
}
if ($switches =~ /C/ && $text !~ /[A-Za-z0-9]/) {
$text = "";
}
my $width = 95;
if ($switches =~ /w/) {
$width = 98;
}
if ($switches =~ /W/) {
$width = 100;
}
if (!$height) {
$height = "h50";
}
if ($height =~ /[0-9]/ && $height !~ /[A-Za-z]/) {
$STYLE = "height:${height}px;";
}
if ($maxlength) {
$COUNT = $maxlength - length $text;
if ($switches =~ /u/) {
$COUNT = length $text;
}
$MAX = qq~ maxlength="$maxlength"~;
}
if ($placeholder) {
$placeholder = qq~ placeholder="$placeholder"~;
}
if ($switches =~ /P/ && $text =~ /[A-Za-z0-9]/) {
$switches =~ s~p~~g;
}
if ($switches =~ /p/) {
if (!$ID) {
$ID = "form_textarea_".(10000+int(rand(9999)));
}
$ONCLICK .= qq~document.getElementById('$ID').style.height='${height}px';~;
$ONKEY .= qq~document.getElementById('$ID').style.height='${height}px';~;
$height = "";
$STYLE = "height:18px;";
if ($switches =~ /q/) {
$STYLE = "height:36px;";
}
if ($switches =~ /Q/) {
$STYLE = "height:54px;";
if ($switches =~ /q/) {
$STYLE = "height:90px;";
}
}
}
if ($switches =~ /i/) {
$STYLE .= "line-height:125%;";
}
if ($switches =~ /I/) {
$STYLE .= "line-height:150%;";
}
if ($switches =~ /c/) {
if (!$ID) {
$ID = "form_textarea_".(10000+int(rand(9999)));
}
$ONKEY = "onojs_text_char_count_max('$ID','${ID}_charcount','$maxlength');";
if ($switches =~ /u/) {
$ONKEY = "onojs_text_char_count('$ID','${ID}_charcount');";
}
}
if ($rows) {
$ONKEY .= "onojs_text_area_maxrows('$ID',$rows);";
}
if ($switches =~ /l/) {
my @tp = split(/\n/,$text);
my $lines = @tp;
$LINES = qq~<div id="${ID}_linecount" class="box_fabric pad5_2 col9 radius10 xsmall lh125 fr">$lines</div>~;
$ONKEY .= "onojs_text_line_count('$ID','${ID}_linecount');";
}
if ($ONCLICK) {
$ONCLICK = qq~ onclick="$ONCLICK"~;
}
if ($ONKEY) {
$ONKEY = qq~ onKeyUp="$ONKEY" onKeyDown="$ONKEY"~;
}
if ($STYLE) {
$STYLE = qq~ style="$STYLE"~;
}
if ($ID) {
$ID_USE = qq~ id="$ID"~;
}
$text =~ s~\[\[~###OPEN###~g;
$text =~ s~\]\]~###CLOSE###~g;
$text =~ s~\[~##OPEN##~g;
$text =~ s~\]~##CLOSE##~g;
if ($switches =~ /B/) {
$text =~ s~\<br\>~\n~gi;
}
$text = ONO::IO->htmlencode($text);
my $AREA = qq~<textarea$ID_USE name="$name" class="w$width $height"$MAX$placeholder$STYLE$ONCLICK$ONKEY>$text</textarea>~;
if ($switches =~ /s/) {
$AREA = qq~<input $ID_USE type="text" name="$name" value="$text" class="w95"$MAX$placeholder$STYLE$ONCLICK$ONKEY>~;
}
if ($switches =~ /t/) {
$AREA = qq~<div class="mt2">$AREA</div>~;
}
if ($switches =~ /T/) {
$AREA = qq~<div class="mt5">$AREA</div>~;
}
if ($switches =~ /L/) {
$AREA = qq~<div class="large">$AREA</div>~;
}
if ($switches =~ /c/) {
if ($switches =~ /H/) {
$HELP = qq~<div class="box_yellow pad5_2 col9 radius10 xsmall lh125 fr mr5" onmouseover="onojs_inline('${ID}_help');" onmouseout="onojs_hide('${ID}_help');">
<div class="fr bold">?</div>
<div id="${ID}_help" class="hide fl lh125">
<table class="default_table">
<tr>
<td class="p0 tar">Link: </td>
<td class="p0">###OPEN###www.example.com###CLOSE###</td>
</tr>
<tr>
<td class="p0 tar nowrap">E-mail: </td>
<td class="p0">###OPEN###you\@example.com###CLOSE###</td>
</tr>
</table>
</div>
</div>
~;
}
$AREA = qq~<div class="rel">
<div class="abs" style="top:-8px;right:5px">
$LINES
<div id="${ID}_charcount" class="box_fabric pad5_2 col9 radius10 xsmall lh125 fr"
onmouseover="onojs_inline('${ID}_charcount_info');" onmouseout="onojs_hide('${ID}_charcount_info');">
$COUNT <span id="${ID}_charcount_info" class="hide">(max. $maxlength)</span>
</div>
$HELP
</div>
$AREA
</div>
~;
}
return $AREA;
}
sub renumber {
my (
$self,
$BLK_ref,
$vars_ref,
) = @_;
#: Renumbering form.
my %BLK = %$BLK_ref;
my %vars = %$vars_ref;
my $REN = qq~<table class="wide_table">
<tr>
<td class="tar">$BLK{'start'}:</td>
<td><input type="text" name="renumber_start" value="$vars{'renumber_start'}" placeholder="1" style="max-width:200px"></td>
</tr>
<tr>
<td class="tar">$BLK{'step'}:</td>
<td><input type="text" name="renumber_step" value="$vars{'renumber_step'}" placeholder="1"></td>
</tr>
<tr>
<td></td>
<td class="w100"><input type="submit" name="submit_renumber" value="$BLK{'renumber'}" class="button_green"></td>
</tr>
</table>
~;
return $REN;
}
###############################################################################
# end of script
###############################################################################
1;
__END__