ONO::FW::Apps::Render

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

use ONO::Lib::Parser::Html::BBCode;

use ONO::Lib::Code::RandomID;
use ONO::Lib::DateTime::ToolBox;
use ONO::Lib::Web::Cookie;

use ONO::FW::Apps::ToolBox;

###############################################################################
# render engine
###############################################################################

sub render {

my (
$self,
$WEB,
$background,
$color,
$vars_ref,
$BASE,
$switches,
$JS_ADD,
) = @_;

#: Render an ONO app.
#:
#: Switches:
#:
#: -B disable BBCode parser

my ($HEAD,$INIT);

if ($WEB =~ /^head:web:(.*?)$/) {

$INIT = $1;

(
$self,
$self,
$HEAD,
$WEB,
$background,
$color,
$vars_ref,
) = @_;
}

if ($BASE) {
$WEB =~ s~="/~="$BASE/~g;
$WEB =~ s~='/~='$BASE/~g;
$WEB =~ s~url\('/~url\('$BASE/~g;

$WEB =~ s~="$BASE$BASE/~="$BASE/~g;
$WEB =~ s~='$BASE$BASE/~='$BASE/~g;
}

my %vars = %$vars_ref;

if (!$vars{'app_lang'}) {
$vars{'app_lang'} = "en";
}

my $robot = "noindex,nofollow";
# if ($vars{'portalkey'} || $vars{'output_web'} || $vars{'output_paper'} || $vars{'output_print'}) {
# $robot = "noindex,nofollow";
# }

my $description = "";

my $STYLE;
if ($background =~ /^#/) {
$STYLE .= qq~body {background-color:$background}\n~;
}

if ($WEB =~ s/<bgcolor="(.*?)">//) {
$STYLE .= qq~body {background-color:$1}\n~;
}

if ($WEB =~ s/<bgimage="(.*?)" alt="">//) {
$STYLE .= qq~body {background-image:url('$1');background-repeat:no-repeat;background-position:top center}\n~;
}
if ($WEB =~ s/<bgimage="(.*?)">//) {
$STYLE .= qq~body {background-image:url('$1');background-repeat:no-repeat;background-position:top center}\n~;
}

if ($color =~ /^#/) {
$STYLE .= qq~a {color:$color}\nh1,h2,h3,h4,h5,h6 {color:$color}\n~;
}

my ($ONLOAD,$whilecounter);
while ($WEB =~ s~\<on(.*?)\:(.*?)\:(.*?)\:(.*?)\>~~ && $whilecounter < 16) {
$whilecounter++;
if (($1 eq "load" || $1 eq "click") && $2 eq "focus") {
$ONLOAD .= qq~ on$1="onojs_focus('$4');"~;
}
}
if ($WEB =~ s~\<onload="(.*?)"\>~~) {
$ONLOAD .= qq~ onload="$1;"~;
}

if ($switches !~ /B/) {
$WEB = ONO::Lib::Parser::Html::BBCode->parse($WEB);
}

my $test_frame;

# (un)comment the following line to enable / disable the test frame on development stations

$test_frame = 1;

if (ONO::IO->devstation && $test_frame) {

$WEB = qq~<div class="bo rel" style="max-width:920px;height:480px">$WEB</div>~;

}

if ($INIT) {
$ONLOAD = qq~ onload="$INIT;"~;
}

my $CSSJS = ONO::Render->cssjs($BASE);

if ($JS_ADD) {
foreach my $JS (split(/;/,";$JS_ADD;")) {
if ($JS =~ /[a-z]/) {
$CSSJS .= qq~<script src="$BASE/ono/osr/javascript/$JS"></script>~;
}
}
}

if ($WEB =~ m~\<\! -- GamePlayLoadPhaser --\>~) {
$HEAD .= qq~<script src="$BASE/ono/osr/javascript/phaser/build/phaser.min.js"></script>\n~;
}

if ($WEB =~ m~\<meta(.*?)\>~) {
my $META = $1;
$META =~ s~\&\;~\&~g;
$HEAD .= qq~<meta$META>~;
}

my $COOKIE;

if ($vars{'output_cookie_store'}) {

if ($ENV{'SCRIPT_NAME'} =~ m~/cgi-bin/local/perl/(.*?)/apps/(.*?)\.pl~) {

my $community = $1;
my $app = $2;
my $CDAT;
foreach my $key (sort keys %vars) {
if ($key =~ /^app_(input|info)_/ && $vars{$key} =~ /[A-Za-z0-9]/) {
$CDAT .= "$key=$vars{$key}\n";
}
}

my $ID = ONO::Lib::Web::Cookie->get("ono_app_${app}_settings");
if (length $ID < 32 || length $ID > 48) {
# 48 is required to remove old broken cookies (pre 2023)
$ID = ONO::Lib::Code::RandomID->make(32);
}

ONO::IO->mkpath("var/tmp/cookies/apps");
ONO::IO->store("var/tmp/cookies/apps/$ID.txt",$CDAT);

$COOKIE = ONO::Lib::Web::Cookie->make("ono_app_${app}_settings",$ID,"6m");

if (ONO::IO->devstation) {
$vars{'username'} = "jos";
}

if ($vars{'username'}) {
$CDAT =~ s~\^~\n~g;
my $DIR = "var/community/$community/accounts/data/".ONO::IO->deepdir($vars{'username'})."/$vars{'username'}/apps_settings";
ONO::IO->mkpath($DIR);
ONO::IO->store("$DIR/$app.txt",$CDAT);
}

}
}

print qq~Content-Type: text/html; charset=UTF-8\n$COOKIE\n
<!doctype html>
<html lang="$vars{'app_lang'}">
<head>
<title>App</title>
<meta charset="utf-8">
<meta name="robots" content="$robot">
<meta name="Generator" content="ONO App Engine">
<meta name="description" content="$description">
$CSSJS
<style>
$STYLE
</style>
$HEAD
</head>
<body$ONLOAD>
$WEB
</body>
</html>
~;

}

sub redirect {

#: Redirect instead of rendering.

my $app = $_[1];
my $HTTP = ONO::IO->http();
my $BASE = $_[3];
if (!$HTTP) {
$HTTP = "http";
}

if (!$app) {
$ENV{'SCRIPT_NAME'} =~ m~/cgi-bin/local/perl/(.*?)/apps/(.*?)\.pl~;
$app = $2;
}

my $APPS_BASE = ONO::FW::Apps::ToolBox->apps_base();

my $REFRESH = ONO::IO->refresh("$ENV{'SERVER_NAME'}$BASE/$APPS_BASE/$app/");

print qq~Content-Type: text/html; charset=UTF-8\n\n
<!doctype html>
<html>
<head>
<meta name="robots" content="noindex,nofollow">
$REFRESH
</head>
<body>
<h1>please wait...</h1>
</body>
</html>
~;

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

1;

__END__