//
// File: hdsGenerate.cpp
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library 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. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#include <fstream>
#include <cmath>
#include <unistd.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include "hzDissemino.h"
using namespace std ;
/*
** Prototypes
*/
const char* Exec2Txt (Exectype eType) ;
/*
** Shorthand for generating HTML
*/
// Google script
static hzString s_Recaptcha = "<script src=\"https://www.google.com/recaptcha/api.js\" async defer></script>\n" ;
// Standard meta tags for generated pages
static hzString s_std_metas =
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>\n"
"<meta http-equiv=\"Expires\" content=\"-1\"/>\n"
"<meta http-equiv=\"Cache-Control\" content=\"no-cache\"/>\n"
"<meta http-equiv=\"Cache-Control\" content=\"no-store\"/>\n"
"<meta http-equiv=\"Pragma\" content=\"no-cache\"/>\n"
"<meta http-equiv=\"Pragma\" content=\"no-store\"/>\n" ;
/*
** Variables
*/
static hzString tagInput = "input" ; // String for HTML tag input
static hzString tagImg = "img" ; // String for HTML tag img
static hzString tagBr = "br" ; // String for HTML tag br
extern hzString _dsmScript_ckEmail ; // Javascript to validate email address
extern hzString _dsmScript_ckUrl ; // Javascript to validate URL
extern hzString _dsmScript_ckExists ; // Javascript to run AJAX check for value already exists
extern hzString _dsmScript_tog ; // Javascript to toggle nav-tree items
extern hzString _dsmScript_loadArticle ; // Javascript to load aricles upon selection from nav-tree
extern hzString _dsmScript_navtree ; // Javascript to display nav-tree
extern hzString _dsmScript_gwp ; // Javascript to obtain window params
extern hzString _hzGlobal_str_TRUE ; // For flowchart decision boxes
extern hzString _hzGlobal_str_FALSE ; // For flowchart decision boxes
extern hzString _hzGlobal_str_START ; // For flowchart START stadium
/*
** Pull down menu driver
*/
void hdsNavbar::Generate (hzChain& Z, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregates into the supplied chain, the HTML nessesary to display the navbar
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsNavbar::Generate") ;
hzList<hzString>::Iter si ; // Subjects iterator
hzPair p ; // NV pair representing page url and page title
hdsInfo* pInfo = 0 ; // Session
//hdsSubject* pSubj ; // Subject
hzString subject ; // Subject
hdsResource* pPage ; // Page within subject
uint32_t x ; // Subhect iterator
uint32_t y ; // Page iterator (within subject)
uint32_t nLo ; // First page of a given subject
uint32_t nHi ; // Last page of a given subject
if (pE)
pInfo = (hdsInfo*) pE->Session() ;
if (m_JS)
{
Z << "<script language=\"javascript\" src=\"/jsc/navbarItems.js\"></script>\n" ;
Z << "<script language=\"javascript\" src=\"/jsc/navbarMenu.js\"></script>\n" ;
return ;
}
Z <<
"\n<table cellspacing='0' cellpadding='0' width='90%' background-color='#000000' border='0'>\n"
"<tr>\n"
"\t<td width='1'> </td><td height='20' valign='center'>\n" ;
// Prepare headings
#if 0
for (x = 0 ; x < m_pApp->m_vecPgSubjects.Count() ; x++)
{
pSubj = m_pApp->m_vecPgSubjects[x] ;
if (!pSubj->pglist.Count())
continue ;
if (pSubj->pglist.Count() <= 1)
Z.Printf("\t<span id='Pdm%d' class='measure'><a href='%s' onmouseover='hideLast()' class='top'>", x, *pSubj->first) ;
else
Z.Printf("\t<span id='Pdm%d' class='measure'><a href=\"#\" class='top' onmouseover='doSub(%d)' onclick='return false'>", x, x) ;
Z.Printf("%s </a></span>\n", *pSubj->subject) ;
}
#endif
for (si = m_pApp->m_lstPgSubjects, x = 0 ; si.Valid() && x < m_pApp->m_lstPgSubjects.Count() ; si++, x++)
{
subject = si.Element() ;
if (m_pApp->m_lstPgSubjects.Count() == 1)
Z.Printf("\t<span id='Pdm%d' class='measure'><a href='%s' onmouseover='hideLast()' class='top'>", x, *subject) ;
else
Z.Printf("\t<span id='Pdm%d' class='measure'><a href=\"#\" class='top' onmouseover='doSub(%d)' onclick='return false'>", x, x) ;
Z.Printf("%s </a></span>\n", *subject) ;
}
Z <<
"\t</td>\n"
"</tr>\n"
"</table>\n" ;
// Prepare lists (sub-menus)
#if 0
for (x = 0 ; x < m_pApp->m_vecPgSubjects.Count() ; x++)
{
Z.Printf("<div id='Sub%d' style='visibility:hidden;position:absolute;width:relative;' onmouseover='IEBum(0,%d)' onmouseout='IEBum(1,%d)'>\n",
x, x, x) ;
Z << "\t<table border='0' background-color='#000000' cellspacing=0 cellpadding=0 width='200'>\n" ;
pSubj = m_pApp->m_vecPgSubjects[x] ;
if (!pSubj->pglist.Count())
continue ;
for (y = 0 ; y < pSubj->pglist.Count() ; y++)
{
pPage = pSubj->pglist[y] ;
if (pPage->m_resAccess == ACCESS_PUBLIC
|| (pPage->m_resAccess == ACCESS_NOBODY && (!pInfo || !(pInfo->m_Access & ACCESS_MASK)))
|| (pInfo && (pInfo->m_Access & ACCESS_ADMIN || (pInfo->m_Access & ACCESS_MASK) == pPage->m_resAccess)))
Z.Printf("\t<tr><td height='13' valign='center'> <a href='%s' id='link' class='top' onmouseover='IEBum(0,%d)'>%s</a></td></tr>\n",
*pPage->m_Url, x, *pPage->m_Title) ;
}
Z << "\t</table>\n</div>\n" ;
}
#endif
for (si = m_pApp->m_lstPgSubjects, x = 0 ; si.Valid() && x < m_pApp->m_lstPgSubjects.Count() ; si++, x++)
{
subject = si.Element() ;
Z.Printf("<div id='Sub%d' style='visibility:hidden;position:absolute;width:relative;' onmouseover='IEBum(0,%d)' onmouseout='IEBum(1,%d)'>\n",
x, x, x) ;
Z << "\t<table border='0' background-color='#000000' cellspacing=0 cellpadding=0 width='200'>\n" ;
nLo = m_pApp->m_mapSubj2Res.First(subject) ;
if (nLo < 0)
continue ;
nHi = m_pApp->m_mapSubj2Res.Last(subject) ;
for (y = nLo ; y <= nHi ; y++)
{
pPage = m_pApp->m_mapSubj2Res.GetObj(y) ;
if (pPage->m_resAccess == ACCESS_PUBLIC
|| (pPage->m_resAccess == ACCESS_NOBODY && (!pInfo || !(pInfo->m_Access & ACCESS_MASK)))
|| (pInfo && (pInfo->m_Access & ACCESS_ADMIN || (pInfo->m_Access & ACCESS_MASK) == pPage->m_resAccess)))
Z.Printf("\t<tr><td height='13' valign='center'> <a href='%s' id='link' class='top' onmouseover='IEBum(0,%d)'>%s</a></td></tr>\n",
*pPage->m_Url, x, *pPage->m_Title) ;
}
Z << "\t</table>\n</div>\n" ;
}
}
/*
** Error message
*/
void hdsApp::_doHead (hzChain& Z, const char* cpPage)
{
// Formulate a standard HTML header (the <head> tag) and agregate it to the supplied chain. The title is set to the supplied value and the header
// contains a link to the application's stylesheet.
//
// Arguments: 1) Z The target chain
// 2) cpPage The page title
//
// Returns: None
_hzfunc("hdsApp::_doHead") ;
Z <<
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>" << cpPage << "</title>\n"
<< s_std_metas <<
"<link rel=\"stylesheet\" href=\"" << m_namCSS << "\">\n"
"</head>\n\n" ;
//"<link rel=\"icon\" href=\"data:;base64,iVBORw0KGgo=\">\n"
}
void hdsApp::_doHeadR (hzChain& Z, const char* cpPage, const char* cpUrl, int nDelay)
{
// Formulate a standard HTML header as with _doHead() but with the addition of a <meta> refresh tag to direct the browser to another URL after a
// stated time interval.
//
// Arguments: 1) Z The target chain
// 2) cpPage The page title
// 3) cpUrl The redirection RL
// 4) nDelay The delay in seconds
//
// Returns: None
_hzfunc("hdsApp::_doHeadR") ;
Z <<
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>" << cpPage << "</title>\n" ;
if (!nDelay)
nDelay = 10 ;
if (cpUrl)
Z.Printf("<meta http-equiv=\"Refresh\" content=\"%d; url='%s'\">\n", nDelay, cpUrl) ;
else
Z.Printf("<meta http-equiv=\"Refresh\" content=\"%d\">\n", nDelay) ;
Z << s_std_metas <<
"<link rel=\"stylesheet\" href=\"" << m_namCSS << "\">\n"
"</head>\n\n" ;
}
// FnGrp: hdsApp::SendErrorPage
//
// Generate HTML to display a system error report. This will name the function in which the error occured and the error message
//
// Returns: None
//
// Func: hdsApp::_xerror (hzHttpEvent*, HttpRC, const char*, const char* ...)
// Func: hdsApp::_xerror (hzHttpEvent*, HttpRC, const char*, hzChain&)
void hdsApp::SendErrorPage (hzHttpEvent* pE, HttpRC rv, const char* func, const char* va_alist ...)
{
// Arguments: 1) pE The current HTTP event
// 2) rv The required HTML return code
// 3) func The function name
// 4) va_alist The error message either as a varargs string
//
// Returns: None
_hzfunc("hdsApp::SendErrorPage(1)") ;
va_list ap1 ; // Variable argument list
hzChain C ; // Output chain
hzChain E ; // Error chain
if (!pE)
{
hzerr(E_ARGUMENT, "No HTTP Event") ;
return ;
}
va_start(ap1, va_alist) ;
E._vainto(va_alist, ap1) ;
_doHead(C, "Error") ;
C << "<body marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" topmargin=\"0\">\n\n" ;
C << "<center><h2>Oops!</h2></center>\n" ;
C << "<table width=\"300\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"fld\">\n" ;
C << "<tr height=\"100\"><td>Function " << func << " Has produced the following error<td></tr>\n" ;
C << "<tr height=\"350\"><td>" << E << "</td></tr>\n" ;
C.Printf("<tr height=\"150\"><td><input type=\"button\" value=\"Go Back\" onclick=\"window.location.href='%s'\"></td></tr>\n", *pE->Referer()) ;
C << "</table>\n\n</body>\n</html>\n" ;
pE->SendRawChain(rv, HMTYPE_TXT_HTML, C, 0, false) ;
}
void hdsApp::SendErrorPage (hzHttpEvent* pE, HttpRC rv, const char* func, hzChain& error)
{
// Arguments: 1) pE The current HTTP event
// 2) rv The required HTML return code
// 3) func The function name
// 4) error The error message as a preformulated chain
//
// Returns: None
_hzfunc("hdsApp::SendErrorPage(1)") ;
hzChain C ; // Output chain
if (!pE)
{
hzerr(E_ARGUMENT, "No HTTP Event") ;
return ;
}
_doHead(C, "Error") ;
C << "<body marginwidth=\"0\" marginheight=\"0\" leftmargin=\"0\" topmargin=\"0\">\n\n" ;
C << "<center><h2>Oops!</h2></center>\n" ;
C << "<table width=\"300\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"fld\">\n" ;
C << "<tr height=\"100\"><td>Function " << func << " Has produced the following error<td></tr>\n" ;
C << "<tr height=\"350\"><td>" << error << "</td></tr>\n" ;
C.Printf("<tr height=\"150\"><td><input type=\"button\" value=\"Go Back\" onclick=\"window.location.href='%s'\"></td></tr>\n", *pE->Referer()) ;
C << "</table>\n\n</body>\n</html>\n" ;
pE->SendRawChain(rv, HMTYPE_TXT_HTML, C, 0, false) ;
}
/*
** Web Component display functions
*/
void hdsButton::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregate to the supplied chain, HTML to manifest a button.
//
// The button can be a link (GET request) OR a form action (POST request). In the link case, button member m_Linkto will give the location. In the form action case, there will
// need to be submission URL which is obtained from the form reference (given in HTTP event variable m_pContextForm).
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsButton::Generate") ;
hdsFormref* pFR ; // Form reference
hzString url ; // URL to use (if form action)
uint32_t x ; // Indent counter
if (m_Line != nLine)
{
C.AddByte(CHAR_NL) ;
for (x = m_Indent ; x ; x--)
C.AddByte(CHAR_TAB) ;
nLine = m_Line ;
}
if (pE->m_pContextForm)
{
pFR = (hdsFormref*) pE->m_pContextForm ;
x = m_pApp->m_FormRef2Url.First(pFR) ;
if (x >= 0)
url = m_pApp->m_FormRef2Url.GetObj(x + m_Resv - 1) ;
}
if (m_Formname)
{
if (url)
C.Printf("<input type=\"submit\" formaction=\"%s\" value=\"%s\">", *url, *m_strContent) ;
else
C.Printf("<input type=\"submit\" value=\"%s\">", *m_strContent) ;
}
else
{
if (pE && m_Linkto[0] == CHAR_PERCENT)
C.Printf("<input type=\"button\" value=\"%s\" onclick=\"window.location.href='%s'\">", *m_strContent, *m_pApp->ConvertText(m_Linkto, pE)) ;
else
C.Printf("<input type=\"button\" value=\"%s\" onclick=\"window.location.href='%s'\">", *m_strContent, *m_Linkto) ;
}
}
void hdsRecap::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregates to the supplied chain (the HTML body), the RECAPTCHA tag responsible for the appearence of the google 'human being' test icon. This
// will contain the public key which must be supplied as an argument to the <project> tag.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsRecap::Generate") ;
if (m_pApp->m_KeyPublic)
C.Printf("<div class=\"g-recaptcha\" data-sitekey=\"%s\"></div>", *m_pApp->m_KeyPublic) ;
else
C << "<div class=\"g-recaptcha\" invalid data-sitekey=\"not supplied\"></div>" ;
}
void hdsDirlist::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Does not in itself produce HTML but the subtags do. The complete set of subtags are called for each member of the list the hdsTable controls.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsDirlist::Generate") ;
hzMapS <hzString,hzDirent> byName ; // Directory entries by name
hzMapM <uint32_t,hzDirent> byDate ; // Directory entries by name
hzVect <hzDirent> dirents ; // List of directories
hzList <hdsCol>::Iter ci ; // Column iterator
hzDirent de ; // Directory entry
hzXDate date ; // Last mod date
hdsCol col ; // Column
hzAtom atom ; // Current value
hdsVE* pVE ; // Visible entitiy
hzString apath ; // Translated path (absolute so includes doc root)
hzString rpath ; // Translated path (relative to doc root)
hzString crit ; // Resolved criteria
uint32_t nDirs ; // Number of directories
uint32_t nFiles ; // Number of files
uint32_t x ; // Table controller
uint32_t y ; // Table controller
// Do the heading
C.AddByte(CHAR_NL) ;
for (x = m_Indent ; x ; x--)
C.AddByte(CHAR_TAB) ;
// Obtain resolved parmeters
rpath = m_pApp->ConvertText(m_Directory, pE) ;
apath = m_pApp->m_Docroot + rpath ;
crit = m_pApp->ConvertText(m_Criteria, pE) ;
// Provide filelist matching the criteria
ReadDir(dirents, *apath, *crit) ;
if (!dirents.Count())
{
// Print the ifnone tags
for (pVE = m_pNone ; pVE ; pVE = pVE->Sibling())
pVE->Generate(C, pE, nLine) ;
}
else
{
// Sort directory entries
for (nDirs = nFiles = x = 0 ; x < dirents.Count() ; x++)
{
de = dirents[x] ;
if (de.IsDir())
nDirs++ ;
else
nFiles++ ;
if (m_Order == 1 || m_Order == 2)
byName.Insert(de.strName(), de) ;
if (m_Order == 3 || m_Order == 4)
byDate.Insert(de.Mtime(), de) ;
}
if (m_Order)
{
// Now place back in array
if (m_Order == 1)
for (x = 0 ; x < dirents.Count() ; x++)
dirents[x] = byName.GetObj(x) ;
if (m_Order == 3)
for (x = 0 ; x < dirents.Count() ; x++)
dirents[x] = byDate.GetObj(x) ;
if (m_Order == 2)
for (y = dirents.Count() - 1, x = 0 ; x < dirents.Count() ; y--, x++)
dirents[x] = byName.GetObj(y) ;
if (m_Order == 4)
for (y = dirents.Count() - 1, x = 0 ; x < dirents.Count() ; y--, x++)
dirents[x] = byDate.GetObj(y) ;
}
// Create HTML table for listing
C.Printf("<table width=\"%d\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"%s\">\n", m_Width, *m_CSS) ;
C.Printf("<tr valign=\"top\" height=\"20\"><td>Listing %d directories and %d files</td></tr>\n", nDirs, nFiles) ;
C.Printf("<tr valign=\"top\" height=\"%d\">\n\t<td>\n", m_Height) ;
C.Printf("\t<table width=\"%d\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"%s\">\n", m_Width, *m_CSS) ;
// Do table headers
C << "\t<tr>\n" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
C.Printf("\t<th width=\"%d\">%s</th>\n", col.m_nSize, *col.m_Title) ;
}
C << "\t</tr>\n" ;
// Do first rows as parent directory
if (pE->m_Resarg)
{
C << "\t<tr>" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
if (col.m_Title == "Mtime")
C << "<td>---</td>" ;
else if (col.m_Title == "Type")
C << "<td>DIR</td>" ;
else if (col.m_Title == "Size")
C << "<td>---</td>" ;
else if (col.m_Title == "Name")
C.Printf("<td><a href=\"%s\">Back to parent dir</a></td>", *m_Directory) ;
else
C << "<td> </td>" ;
}
C << "\t</tr>\n" ;
}
// Do table rows (directories)
for (x = 0 ; x < dirents.Count() ; x++)
{
de = dirents[x] ;
if (!de.IsDir())
continue ;
C << "\t<tr>" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
if (col.m_Title == "Mtime") { date.SetByEpoch(de.Mtime()) ; C.Printf("<td>%s</td>", *date) ; }
else if (col.m_Title == "Type") C << "<td>DIR</td>" ;
else if (col.m_Title == "Size") C.Printf("<td alight=\"right\">%s</td>", FormalNumber(de.Size())) ;
else if (col.m_Title == "Name") C.Printf("<td><a href=\"%s-%s\"> %s</a></td>", *m_Directory, de.txtName(), de.txtName()) ;
else
C << "<td> </td>" ;
}
C << "\t</tr>\n" ;
}
// Do table rows (files)
for (x = 0 ; x < dirents.Count() ; x++)
{
de = dirents[x] ;
if (de.IsDir())
continue ;
C << "\t<tr>" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
if (col.m_Title == "Mtime")
{ date.SetByEpoch(de.Mtime()) ; C.Printf("<td>%s</td>", *date) ; }
else if (col.m_Title == "Type")
C << "<td>File</td>" ;
else if (col.m_Title == "Size")
C.Printf("<td alight=\"right\">%s</td>", FormalNumber(de.Size())) ;
else if (col.m_Title == "Name")
{
if (pE->m_Resarg)
C.Printf("<td><a href=\"/userdir/%s/%s\"> %s</a></td>", *pE->m_Resarg, de.txtName(), de.txtName()) ;
else
C.Printf("<td><a href=\"/userdir/%s\"> %s</a></td>", de.txtName(), de.txtName()) ;
}
else
C << "<td> </td>" ;
}
C << "\t</tr>\n" ;
}
C << "\t</table>\n</table>\n" ;
}
}
void hdsTable::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Does not in itself produce HTML but the subtags do. The complete set of subtags are called for each member of the list the hdsTable controls.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsTable::Generate") ;
hzList<hdsCol>::Iter ci ; // Column iterator
hzVect<uint32_t> items ; // Items drawn from class member (of table) to be listed as rows
hdbObject obj ; // Retrieved data object
hdbIdset srchResult ; // Items selected from applicable repository
hdsCol col ; // Column
hdsVE* pVE ; // For processing subtags
hzAtom atom ; // Current value
hzString value ; // Value in session if set
uint32_t nFound ; // Table controller
uint32_t objId ; // Object id
hzEcode rc ; // Return code from Fetch()
// Do the heading
C.AddByte(CHAR_NL) ;
// Do the select
if (m_Criteria == "all")
nFound = m_pRepos->Count() ;
else
{
m_pRepos->Select(srchResult, *m_Criteria) ;
nFound = srchResult.Count() ;
}
// Display results
if (nFound == 0)
{
// In the event of no objects found, print the ifnone tags
for (pVE = m_pNone ; pVE ; pVE = pVE->Sibling())
pVE->Generate(C, pE, nLine) ;
}
else
{
// Create HTML table for listing
C.Printf("<table width=\"%d\" align=\"center\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"%s\">\n", m_nWidth, *m_CSS) ;
C.Printf("<tr valign=\"top\" height=\"20\"><td>Listing %d objects</td></tr>\n", nFound) ;
C.Printf("<tr valign=\"top\" height=\"%d\">\n\t<td>\n", m_nHeight) ;
C.Printf("\t<table width=\"%d\" align=\"center\" border=\"1\" cellspacing=\"1\" cellpadding=\"1\" class=\"%s\">\n", m_nWidth, *m_CSS) ;
// Do table headers
C << "\t<tr>\n" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
C.Printf("\t<th width=\"%d\">%s</th>\n", col.m_nSize, *col.m_Title) ;
}
C << "\t</tr>\n" ;
// Provide filelist matching the criteria
obj.Init(m_pRepos->Class()) ;
for (objId = 1 ; objId <= nFound ; objId++)
{
// Fetch data object
rc = m_pRepos->Fetch(obj, objId) ;
if (rc != E_OK)
break ;
// Now display object as row
C << "\t<tr>" ;
for (ci = m_Cols ; ci.Valid() ; ci++)
{
col = ci.Element() ;
//m_pRepos->Fetchval(atom, col.m_mbrNo, objId) ;
obj.GetValue(atom, m_pRepos->Class()->GetMember(col.m_mbrNo)) ;
if (atom.IsSet())
value = atom.Str() ;
else
value.Clear() ;
if (col.m_nSize)
C.Printf("<td width=\"%d\">%s</td>", col.m_nSize, *value) ; //atom.Str()) ;
else
C.Printf("<td>%s</td>", *value) ; //atom.Str()) ;
}
C << "</tr>\n" ;
}
C << "</table>\n" ;
}
}
void hdsField::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregates to the supplied chain, HTML code for presenting an input field as part of a form. The resulting field will be unpopulated unless a
// data source is specified as an attribute to <xfield> and only then if that source successfully evaluates.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsField::Generate") ;
hzAtom atom ; // For fetching field value from db
hdbEnum* pSlct ; // Selector
const char* pDictStr ; // String from dictionary string number
hzString value ; // Value in session if set
hzString S ; // Temp string
uint32_t rows ; // Selector rows for radio
uint32_t n ; // Selector items iterator
hzEcode rc ; // Return code
if (pE && m_Source)
{
rc = m_pApp->PcEntConv(atom, m_Source, pE) ;
if (atom.IsSet())
value = atom.Str() ;
}
switch (m_Fldspec.htype)
{
case HTMLTYPE_HIDDEN: // Insert hidden value
C.Printf("<input type=\"hidden\" name=\"%s\" value=\"%s\"/>", *m_Varname, *value) ; //atom.Str()) ;
break ;
case HTMLTYPE_SELECT: // Write out the selector with already selected options marked as selected
pSlct = (hdbEnum*) m_Fldspec.m_pType ;
if (m_flagVE & VE_MULTIPLE)
C.Printf("<select name=\"%s\" multiple>", *m_Varname) ;
else
C.Printf("<select name=\"%s\">", *m_Varname) ;
for (n = 0 ; n < pSlct->Count() ; n++)
{
S = pSlct->GetStr(n) ;
//strNo = pSlct->m_Items[n] ;
//pDictStr = _hzGlobal_setStrings->Xlate(strNo) ;
if (value == pDictStr)
C.Printf("<option selected>%s</option>", *S) ;
else
C.Printf("<option>%s</option>", *S) ;
}
C << "</select>" ;
break ;
case HTMLTYPE_RADIO:
// Write out the selector as a radio button set. The seletor cannot be multiple but the number of colums must be specified. The radio set will appear
// within a <table> in which each column except the last, will contain N items. N is calculated as the total selector population divided by the number
// of columns, then plus one. The last column will contain the remainder. The items will be displayed in the order they appear in the selector but are
// used to fill each column before moving on to the next. The columns are from left to right.
pSlct = (hdbEnum*) m_Fldspec.m_pType ;
rows = (pSlct->Count() / m_Fldspec.nCols) + 1 ;
C << "<table>\n" ;
C << "\t<tr>\n" ;
C << "\t\t<td>\n" ;
for (n = 0 ; n < pSlct->Count() ; n++)
{
S = pSlct->GetStr(n) ;
if (n && (n % rows) == 0)
{
C.Printf("<input type=\"radio\" name=\"%s\" value=\"%d\">%s\n", *m_Varname, n, *S) ;
C << "\t\t<td>\n\t\t</td>\n" ;
continue ;
}
C.Printf("<input type=\"radio\" name=\"%s\" value=\"%d\">%s<br>\n", *m_Varname, n, *S) ;
}
C << "\t\t</td>\n" ;
C << "\t</tr>\n" ;
C << "</table>\n" ;
break ;
case HTMLTYPE_CHECKBOX: if (value)
C.Printf("<input type=\"checkbox\" name=\"%s\" checked>", *m_Varname) ;
else
C.Printf("<input type=\"checkbox\" name=\"%s\">", *m_Varname) ;
break ;
case HTMLTYPE_FILE: C.Printf("<input type=\"file\" name=\"%s\" value=\"%s\">", *m_Varname, *value) ;
break ;
case HTMLTYPE_TEXT:
case HTMLTYPE_TEXTAREA:
if (m_Fldspec.nRows <= 1)
{
if (m_flagVE & VE_UNIQUE)
C.Printf("<input type=\"text\" name=\"%s\" size=\"%d\" maxlength=\"%d\" onchange=\"ckUnique_%s()\"",
*m_Varname, m_Fldspec.nCols, m_Fldspec.nSize, *m_Varname) ;
else
C.Printf("<input type=\"text\" name=\"%s\" size=\"%d\" maxlength=\"%d\"", *m_Varname, m_Fldspec.nCols, m_Fldspec.nSize) ;
if (m_CSS)
C.Printf(" class=\"%s\"", *m_CSS) ;
if (value)
C.Printf(" value=\"%s\"", *value) ;
if (m_flagVE & VE_DISABLED)
C << " disabled" ;
C << "/>" ;
}
else
{
C.Printf("<textarea name=\"%s\" rows=\"%d\" cols=\"%d\" maxlength=\"%d\"", *m_Varname, m_Fldspec.nRows, m_Fldspec.nCols, m_Fldspec.nSize) ;
if (m_CSS)
C.Printf(" class=\"%s\"", *m_CSS) ;
C.AddByte(CHAR_MORE) ;
if (value)
C << value ;
C << "</textarea>" ;
}
break ;
case HTMLTYPE_PASSWORD:
C.Printf("<input type=\"password\" name=\"%s\" size=\"%d\" maxlength=\"%d\"", *m_Varname, m_Fldspec.nCols, m_Fldspec.nSize) ;
if (m_CSS)
C.Printf(" class=\"%s\"", *m_CSS) ;
if (value)
C.Printf(" value=\"%s\"", *value) ;
C << "/>" ;
break ;
default:
C.Printf("Sorry: HTML Unknown type. FldDesc=%s Name=%s Type=%s htype=%d Rows=%d Cols=%d Size=%d",
*m_Fldspec.m_Refname, *m_Varname, m_Fldspec.m_pType->txtType(), m_Fldspec.htype, m_Fldspec.nRows, m_Fldspec.nCols, m_Fldspec.nSize) ;
break ;
}
}
void hdsFormref::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregates to the supplied chain (the HTML body), the HTML code for presenting a form. This will present the whole form so everything from the
// opening <form> tag to the closing </form> antitag.
//
// The HTML for the form is actually vested with the form definition so generating HTML for a form reference is a matter of ....
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsFormref::Generate") ;
hzList<hdsVE*>::Iter ih ; // Html entity iterator
hdsFormdef* pFormdef ; // Actual form referenced
hdsVE* pVE ; // Html entity
hzString url ; // URL from hdsApp map m_FormRef2Url
uint32_t nV ; // Visual entity iterator
uint32_t relLn ; // Relative line
uint32_t x ; // Tab controller
if (m_Line != nLine)
{
C.AddByte(CHAR_NL) ;
for (x = m_Indent ; x ; x--)
C.AddByte(CHAR_TAB) ;
nLine = m_Line ;
}
pFormdef = m_pApp->m_FormDefs[m_Formname] ;
if (!pFormdef)
{
C.Printf("<p>ERROR: NULL FORM DEF</p>\n") ;
return ;
}
if (pFormdef->m_nActions == 1)
{
x = m_pApp->m_FormRef2Url.First(this) ;
url = m_pApp->m_FormRef2Url.GetObj(x) ;
if (m_flagVE & VE_MULTIPART)
C.Printf("<form name=\"%s\" method=\"POST\" action=\"%s\" onsubmit=\"return ck%s()\" enctype=\"multipart/form-data\">\n",
*m_Formname, *url, *m_Formname) ;
else
C.Printf("<form name=\"%s\" method=\"POST\" action=\"%s\" onsubmit=\"return ck%s()\">\n", *m_Formname, *url, *m_Formname) ;
}
else
{
if (m_flagVE & VE_MULTIPART)
C.Printf("<form name=\"%s\" method=\"POST\" enctype=\"multipart/form-data\">\n",
*m_Formname, *url, *url) ;
else
C.Printf("<form name=\"%s\" method=\"POST\">\n", *m_Formname, *url, *url) ;
}
relLn = nLine ;
pE->m_pContextForm = this ;
for (nV = 0 ; nV < pFormdef->m_VEs.Count() ; nV++)
{
pVE = pFormdef->m_VEs[nV] ; pVE->Generate(C, pE, relLn) ;
}
if (nLine != m_Line)
{
C.AddByte(CHAR_NL) ;
for (x = m_Indent ; x ; x--)
C.AddByte(CHAR_TAB) ;
}
C << "</form>\n" ;
}
void hdsPage::WriteValidationJS (void)
{
// This is run once upon startup and applies to each page in which there is one or more forms. It Creates the JavaScript that must be run to pre
// validate form content before submission to the server.
//
// Arguments: None
// Returns: None
_hzfunc("hdsPage::WriteValidationJS") ;
hzList<hdsFormref*>::Iter fi ; // Form iterator
hzChain Z ; // For building page validation script(s)
hdsFormref* pFormref ; // Form in page
hdsFormdef* pFormdef ; // Form in page
hdsField* pFld ; // Field in form
uint32_t n ; // Field iterator
// Check for pre-submission requirements. This is where one or more fields can only be validated by querying the server. For example in a form to
// register a new user, the email address must be new. The 'onchange' event is used to check on the server for the existance of the field class,
// member and value.
_hzGlobal_Dissemino->m_pLog->Log("DOING PAGE %s\n", *m_Title) ;
for (fi = m_xForms ; fi.Valid() ; fi++)
{
pFormref = fi.Element() ;
m_pApp->m_pLog->Log("DOING FORM REF %p\n", pFormref) ;
if (!pFormref)
{ _hzGlobal_Dissemino->m_pLog->Log("ERROR Page %s has a NULL form reference\n", *m_Title) ; continue ; }
//pFormdef = pFormref->m_pFormdef ;
pFormdef = m_pApp->m_FormDefs[pFormref->m_Formname] ;
if (!pFormdef)
{ m_pApp->m_pLog->Log("ERROR Page %s has a NULL form definition\n", *m_Title) ; continue ; }
for (n = 0 ; n < pFormdef->m_vecFlds.Count() ; n++)
{
pFld = pFormdef->m_vecFlds[n] ;
if (!pFld->m_Varname)
continue ;
if (!(pFld->m_flagVE & VE_UNIQUE))
continue ;
if (!pFld->m_pClass || !pFld->m_pMem)
continue ;
Z.Printf("function ckUnique_%s()\n{\n", *pFld->m_Varname) ;
Z.Printf("\tif (ckExists('%s','%s',document.%s.%s.value))\n", pFld->m_pClass->txtType(), pFld->m_pMem->txtName(), *pFormdef->m_Formname, *pFld->m_Varname) ;
Z << "\t{\n" ;
Z.Printf("\t\talert(\"%s already in use\");\n", *pFld->m_Varname) ;
Z.Printf("\t\tdocument.%s.%s.value=\"\";\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
Z.Printf("\t\tdocument.%s.%s.focus();\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
Z << "\t}\n}\n" ;
m_bScriptFlags |= INC_SCRIPT_EXISTS ;
}
// Now do the ordinary format checking validation scripting
Z.Printf("function ck%s()\n{\n", *pFormdef->m_Formname) ;
for (n = 0 ; n < pFormdef->m_vecFlds.Count() ; n++)
{
pFld = pFormdef->m_vecFlds[n] ;
if (!pFld->m_Varname)
continue ;
if (!(pFld->m_flagVE & VE_COMPULSORY))
continue ;
if (pFld->m_Fldspec.m_pType->Basetype() == BASETYPE_ENUM)
Z.Printf("\tif (document.%s.%s.value==\"0\")\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
else
Z.Printf("\tif (document.%s.%s.value==\"\")\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
Z.Printf("\t\t{ alert(\"Please provide your %s\"); document.%s.%s.focus(); return false; }\n", *pFld->m_Varname, *pFormdef->m_Formname, *pFld->m_Varname) ;
if (pFld->m_Fldspec.m_pType->Basetype() == BASETYPE_EMADDR)
{
Z.Printf("\tif (!ckEmaddr(document.%s.%s.value))\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
Z.Printf("\t\t{ document.%s.%s.focus(); return false }\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
m_bScriptFlags |= INC_SCRIPT_CKEMAIL ;
}
if (pFld->m_Fldspec.m_pType->Basetype() == BASETYPE_URL)
{
Z.Printf("\tif (!ckUrl(document.%s.%s.value))\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
Z.Printf("\t\t{ document.%s.%s.focus(); return false }\n", *pFormdef->m_Formname, *pFld->m_Varname) ;
m_bScriptFlags |= INC_SCRIPT_CKURL ;
}
}
if (pFormdef->m_bScriptFlags & INC_SCRIPT_RECAPTCHA)
{
Z.Printf("\tif (grecaptcha.getResponse()==\"\")\n") ;
Z.Printf("\t\t{ alert(\"Please prove you are human!\"); return false; }\n") ;
}
Z.Printf("\tdocument.%s.submit();\n\treturn true\n}\n", *pFormdef->m_Formname) ;
}
m_validateJS = Z ;
}
/*
** Grapics
*/
void hdsGraphic::Draw (hzChain& Z)
{
// Draw shape
_hzfunc("hdsGraphic::Draw") ;
threadLog("ok .. \n") ;
switch (m_eShape)
{
case HDSGRAPH_DIAMOND: Z.Printf("<polygon points=\"%u,%u %u,%u %u,%u %u,%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u\"/>\n",
lftMidptX(), lftMidptY(),
topMidptX(), topMidptY(),
rhtMidptX(), rhtMidptY(),
botMidptX(), botMidptY(),
m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_HEXAGON: Z.Printf("<polygon points=\"%u,%u %u,%u %u,%u %u,%u, %u,%u, %u,%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u\"/>\n",
m_Lft, m_Top + (m_Height/2),
m_Lft + (m_Height/2), m_Top,
m_Rht - (m_Height/2), m_Top,
m_Rht, m_Top + (m_Height/2),
m_Rht - (m_Height/2), m_Bot,
m_Lft + (m_Height/2), m_Bot,
m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_ARROW: Z.Printf("<polygon points=\"%u,%u %u,%u %u,%u %u,%u %u,%u %u,%u %u,%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u\"/>\n",
m_Lft, m_Top + m_Height/3,
topMidptX(), m_Top + m_Height/3,
topMidptX(), m_Top,
rhtMidptX(), rhtMidptY(),
botMidptX(), botMidptY(),
botMidptX(), m_Bot - m_Height/3,
m_Lft, m_Bot - m_Height/3,
m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_RECT: Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u;\"/>\n",
m_Lft, m_Top, m_Width, m_Height, m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_VRECT: break ;
case HDSGRAPH_HRECT: break ;
case HDSGRAPH_RRECT: Z.Printf("<rect x=\"%u\" y=\"%u\" rx=\"%u\" ry=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u;\"/>\n",
m_Lft, m_Top, m_Rad, m_Rad, m_Width, m_Height, m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_STADIUM: Z.Printf("<rect x=\"%u\" y=\"%u\" rx=\"%u\" ry=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u;\"/>\n",
m_Lft, m_Top, m_Height/2, m_Height/2, m_Width, m_Height, m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_CIRCLE: Z.Printf("<circle cx=\"%u\" cy=\"%u\" r=\"%u\" stroke=\"#%06x\" stroke-width=\"%u\" fill=\"#%06x\"/>\n",
m_Lft + (m_Width/2), m_Top + (m_Height/2), m_Rad, m_ColorFill, m_ColorLine, m_Thick) ;
break ;
case HDSGRAPH_LGATE_AND: break ;
case HDSGRAPH_LGATE_OR: break ;
case HDSGRAPH_LGATE_NOT: break ;
case HDSGRAPH_LGATE_NAND: break ;
case HDSGRAPH_LGATE_NOR: break ;
}
}
void _hds_svg_drawTriangle (hzChain& Z, uint32_t aX, uint32_t aY, uint32_t bX, uint32_t bY, uint32_t cX, uint32_t cY, uint32_t color)
{
_hzfunc(__func__) ;
Z.Printf("<polygon points=\"%u,%u %u,%u %u,%u\" style=\"fill:#%06x;\"/>\n", aX, aY, bX, bY, cX, cY, color) ;
}
void _hds_svg_drawLine (hzChain& Z, hdsLine& ln)
{
_hzfunc(__func__) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n",
ln.m_startH, ln.m_startV, ln.m_finalH, ln.m_finalV, ln.m_Color, ln.m_Thick) ;
}
void _hds_svg_drawLine (hzChain& Z, uint32_t aX, uint32_t aY, uint32_t bX, uint32_t bY, uint32_t color, uint32_t width)
{
_hzfunc(__func__) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", aX, aY, bX, bY, color, width) ;
}
void _hds_svg_drawText (hzChain& Z, hzString& text, uint32_t H, uint32_t V, uint32_t color, uint16_t alignCode)
{
// Align code 1 center, 2 right else left
_hzfunc(__func__) ;
if (!text)
return ;
if (alignCode == 1)
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\" dominant-baseline=\"top\" text-anchor=\"middle\">%s</text>\n", H, V, color, *text) ;
else if (alignCode == 2)
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\" dominant-baseline=\"top\" text-anchor=\"end\">%s</text>\n", H, V, color, *text) ;
else
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\" dominant-baseline=\"top\">%s</text>\n", H, V, color, *text) ;
}
void _hds_svg_drawMLText (hzChain& Z, hzString& text, uint32_t X, uint32_t Y, uint32_t color, uint32_t id)
{
// Multi-line Text
_hzfunc(__func__) ;
const char* i ; // Text iterator
Z.Printf("<text fill=\"#%06x\" dominant-baseline=\"top\">\n", color) ;
Z.Printf("\t<tspan x=\"%u\" dy=\"%u\">%d:", X, Y, id) ;
for (i = *text ; *i ; i++)
{
if (*i == CHAR_NL)
{
Y += 20 ;
Z << "\t</tspan>\n" ;
Z.Printf("\t<tspan x=\"%u\" y=\"%u\">", X, Y) ;
continue ;
}
Z.AddByte(*i) ;
}
Z << "\t</tspan>\n" ;
Z << "</text>\n" ;
}
void hdsChartPie::Generate (hzChain& Z, hzHttpEvent* pE, uint32_t& nLine)
{
// Category: HTML Generation
//
// Displays a pie chart by means of the <svg> tag and associated javascript.
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsChartPie::Generate") ;
_pie* pSlice ; // Pie value
double val ; // Current segment value
double sofar ; // Total value of all segments so far processed
double deg ; // Angle from top
double ang ; // Angle in radians
uint32_t X ; // Destination horizontal coord
uint32_t Y ; // Destination vertical coord
uint32_t last_y = 0 ; // y-coord
uint32_t last_x = 0 ; // x-coord
uint32_t n ; // Parts iterator
uint32_t bSmall ; // Short arc indicator
//char buf[200] ;
// Open svg tag
Z.Printf("\n<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"background:#%06x;\">", *m_Id, m_Height, m_Width, m_BgColor) ;
// Draw header and footer if applicable
if (m_Header)
_hds_svg_drawText(Z, m_Header, m_Width/2, 20, m_FgColor, 1) ;
// Work out what percentage of the total, each part represents
last_x = m_ccX ;
last_y = m_ccY - m_Rad ;
sofar = val = 0.0 ;
for (n = 0 ; n < m_nSlices ; n++)
{
pSlice = m_pSlices + n ;
bSmall = pSlice->m_nValue/m_Total >= 0.5 ? 1 : 0 ;
Z << "\t<path d=\"" ;
if ((n+1) == m_nSlices)
{
X = m_ccX ;
Y = m_ccY - m_Rad ;
Z.Printf("M %u %u L %u %u A %u %u 0 %d 1 %u %u Z\" fill=\"#%06x\"/>\n", m_ccX, m_ccY, last_x, last_y, m_Rad, m_Rad, bSmall, X, Y, pSlice->color) ;
}
else
{
sofar += pSlice->m_nValue ;
deg = (360 * sofar)/m_Total ;
ang = (deg * M_PI)/180 ;
X = m_ccX + (m_Rad * sin(ang)) ;
Y = m_ccY - (m_Rad * cos(ang)) ;
Z.Printf("M %u %u L %u %u A %u %u 0 %d 1 %u %u Z\" fill=\"#%06x\"/>\n", m_ccX, m_ccY, last_x, last_y, m_Rad, m_Rad, bSmall, X, Y, pSlice->color) ;
last_x = X ;
last_y = Y ;
}
}
// Write index
X = m_ccX + m_Rad + 40 ;
Y = m_ccY - m_Rad ;
for (n = 0 ; n < m_nSlices ; n++)
{
pSlice = m_pSlices + n ;
Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:1\"/>\n",
X, Y, 12, 12, pSlice->color, m_FgColor, 1) ;
_hds_svg_drawText(Z, pSlice->header, X+15, Y+12, m_FgColor, 0) ;
Y += 20 ;
}
if (m_Footer)
_hds_svg_drawText(Z, m_Footer, m_Width/2, m_Height - 20, m_FgColor, 1) ;
Z << "</svg>\n" ;
}
void hdsChartStd::Generate (hzChain& Z, hzHttpEvent* pE, uint32_t& nLine)
{
// Category: HTML Generation
//
// Displays a chart by placing in the page HTML, a <svg> tag.
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsChartStd::Generate") ;
hzList<_rset*>::Iter ri ; // Dataset iterator
_rset* pSet ; // Dataset
double per_pixel_X ; // For ploting x
double per_pixel_Y ; // For ploting y
double val ; // Current value
double stepSize ; // Axis value per step
uint32_t X ; // Current horizontal coord
uint32_t Y ; // Current vertical coord
uint16_t axisPixelsX ; // Total pixels on V-axis
uint16_t axisPixelsY ; // Total pixels on V-axis
uint32_t n ; // Loop iterator
/*
** Start draw instrutions
*/
Z.Printf("<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"border:1px solid #000000; background:#%06x;\">", *m_Id, m_Height, m_Width, m_BgColor) ;
// Draw header and footer if applicable
if (m_Header)
_hds_svg_drawText(Z, m_Header, m_Width/2, 20, m_FgColor, 1) ;
// Calculate pixels
axisPixelsY = m_nSlotsY * m_nPxSlotY ;
axisPixelsX = m_nSlotsX * m_nPxSlotX ;
per_pixel_Y = (m_nMaxY - m_nMinY)/axisPixelsY ;
per_pixel_X = (m_nMaxX - m_nMinX)/axisPixelsX ;
// Draw vertical and horizontal axis
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:1\"/>\n", m_origX, m_origY - axisPixelsY, m_origX, m_origY, m_FgColor) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:1\"/>\n", m_origX, m_origY, m_origX + axisPixelsX, m_origY, m_FgColor) ;
// Draw out vertical axis heading and markers
X = 20 ;
Y = 30 ;
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%s</text>\n", X, Y, m_FgColor, *m_HdrY) ;
stepSize = (m_nMaxY - m_nMinY)/m_nSlotsY ;
Y = m_origY ;
for (val = m_nMinY ; val <= m_nMaxY ; val += stepSize)
{
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%u</text>\n", X, Y, m_FgColor, (uint32_t) val) ;
Y -= m_nPxSlotY ;
}
// Draw out horizontal axis heading and markers
stepSize = (m_nMaxX - m_nMinX)/m_nSlotsX ;
Y = m_origY + 20 ;
X = m_origX ;
for (val = m_nMinX ; val <= m_nMaxX ; val += stepSize)
{
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%u</text>\n", X, Y, m_FgColor, (uint32_t) val) ;
X += m_nPxSlotX ;
}
// Plot values
for (ri = m_Sets ; ri.Valid() ; ri++)
{
pSet = ri.Element() ;
Z << "<polyline points=\"" ;
X = m_origX + ((m_hVals[0] - m_nMinX)/per_pixel_X) ;
Y = m_origY - ((pSet->m_vVals[0] - m_nMinY)/per_pixel_Y) ;
Z.Printf("%u,%u", X, Y) ;
for (n = 1 ; n <= m_nSlotsX ; n++)
{
X = m_origX + ((m_hVals[n] - m_nMinX)/per_pixel_X) ;
Y = m_origY - ((pSet->m_vVals[n] - m_nMinY)/per_pixel_Y) ;
Z.Printf(" %u,%u", X, Y) ;
}
Z.Printf("\" style=\"fill:none;stroke:#%06x;stroke-width:1\"/>\n", pSet->color) ;
}
// Do the component index if applicable
Y = m_origY + 40 ;
if (m_Sets.Count() > 1)
{
X = m_origX ;
for (ri = m_Sets ; ri.Valid() ; ri++)
{
pSet = ri.Element() ;
Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;\"/>\n", X, Y, 12, 12, pSet->color) ;
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%s</text>\n", X+15, Y+12, m_FgColor, *pSet->header) ;
X += 10 * (pSet->header.Length()) ;
}
Y += 20 ;
}
if (m_Footer)
_hds_svg_drawText(Z, m_Footer, m_Width/2, Y, m_FgColor, 1) ;
Z
<< "Your Browser does not support the HTML5 SVG tag\n"
"</svg>\n" ;
}
void hdsChartBar::Generate (hzChain& Z, hzHttpEvent* pE, uint32_t& nLine)
{
// Category: HTML Generation
//
// Displays a chart by placing in the page HTML, a <svg> tag.
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsChartBar::Generate") ;
hzList<_rset*>::Iter ri ; // Dataset iterator
_rset* pSet ; // Dataset
//double per_pixel_X ; // For ploting x
double per_pixel_Y ; // For ploting y
double stepSize ; // Axis value per step
uint32_t val ; // Current value
uint32_t X ; // Current horizontal coord
uint32_t Y ; // Current vertical coord
uint16_t axisPixelsX ; // Total pixels on X-axis
uint16_t axisPixelsY ; // Total pixels on Y-axis
uint32_t n ; // Loop iterator
/*
** Start draw instrutions
*/
Z.Printf("<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"border:1px solid #000000; background:#%06x;\">", *m_Id, m_Height, m_Width, m_BgColor) ;
// Draw header and footer if applicable
if (m_Header)
_hds_svg_drawText(Z, m_Header, m_Width/2, 20, m_FgColor, 1) ;
// Calculate pixels
axisPixelsX = m_nSlotsX * m_nPxSlotX ;
axisPixelsY = m_nSlotsY * m_nPxSlotY ;
//per_pixel_X = (m_nMaxX - m_nMinX)/axisPixelsX ;
per_pixel_Y = (m_nMaxY - m_nMinY)/axisPixelsY ;
// Draw vertical and horizontal axis
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:1\"/>\n", m_origX, m_origY - axisPixelsY, m_origX, m_origY, m_FgColor) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:1\"/>\n", m_origX, m_origY, m_origX + axisPixelsX, m_origY, m_FgColor) ;
// Draw out vertical axis heading and markers
Y = 30 ;
X = 20 ;
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%s</text>\n", X, Y, m_FgColor, *m_HdrY) ;
stepSize = (m_nMaxY - m_nMinY)/m_nSlotsY ;
Y = m_origY ;
for (val = m_nMinY ; val <= m_nMaxY ; val += stepSize)
{
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%u</text>\n", X, Y, m_FgColor, (uint32_t) val) ;
Y -= m_nPxSlotY ;
}
// Draw out horizontal axis heading and markers
stepSize = (m_nMaxX - m_nMinX)/m_nSlotsX ;
Y = m_origY + 20 ;
X = m_origX ;
for (val = m_nMinX ; val <= m_nMaxX ; val += stepSize)
{
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%u</text>\n", X, Y, m_FgColor, (uint32_t) val) ;
X += m_nPxSlotX ;
}
// Plot values
for (n = 0 ; n <= m_nSlotsX ; n++)
{
Y = m_origY ;
X = m_origX + (n * m_nPxSlotX) + 1 ;
for (ri = m_Sets ; ri.Valid() ; ri++)
{
pSet = ri.Element() ;
val = ((pSet->m_vVals[n] - m_nMinY) * per_pixel_Y) ;
Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;\"/>\n", X, Y - val, (uint32_t)m_nPxSlotX - 1, val, pSet->color) ;
Y -= val ;
}
}
// Do the component index if applicable
Y = m_origY + 40 ;
if (m_Sets.Count() > 1)
{
X = m_origX ;
for (ri = m_Sets ; ri.Valid() ; ri++)
{
pSet = ri.Element() ;
Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;\"/>\n", X, Y, 12, 12, pSet->color) ;
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%s</text>\n", X+15, Y+15, m_FgColor, *pSet->header) ;
X += 10 * (pSet->header.Length()) ;
}
Y += 20 ;
}
if (m_Footer)
_hds_svg_drawText(Z, m_Footer, m_Width/2, Y, m_FgColor, 1) ;
Z
<< "Your Browser does not support the HTML5 SVG tag\n"
"</svg>\n" ;
}
/*
** Diagrams and Flowcharts
*/
static hzString s_fc_conn_TRUE = "Y" ;
static hzString s_fc_conn_FALSE = "N" ;
void _drawFlowConn (hzChain& Z, hdsFlowchart* pFlow, hdsConnector* pConn)
{
// Flowchart support function.
_hzfunc(__func__) ;
hdsGraphic* pG_src ; // Origin shape
hdsGraphic* pG_tgt ; // Target shape
uint32_t color ; // Line color
uint32_t lw ; // Line width
uint16_t sX ; // Connector source X coord
uint16_t sY ; // Connector source Y coord
uint16_t tX ; // Connector target X coord
uint16_t tY ; // Connector target Y coord
uint16_t mY ; // Connector source/target Y midpoint
if (!pFlow)
{ threadLog("FAIL NO FLOWCHART\n") ; return ; }
if (!pConn)
{ threadLog("FAIL NO CONNECTORS\n") ; return ; }
if (!pFlow->m_pShapes)
{ threadLog("FAIL NO SHAPES\n") ; return ; }
if (pConn->m_Origin == pConn->m_Target)
{ threadLog("FAIL SRC=TGT %d\n", pConn->m_Origin) ; return ; }
if (!pConn->m_Target)
{ threadLog("FAIL SRC %d TGT %d\n", pConn->m_Origin, pConn->m_Target) ; return ; }
threadLog("PASS SRC %d TGT %d\n", pConn->m_Origin, pConn->m_Target) ;
color = pFlow->m_ColorLine ;
lw = pFlow->m_nWidthConn ;
pG_src = pFlow->m_pShapes + pConn->m_Origin ;
pG_tgt = pFlow->m_pShapes + pConn->m_Target ;
//threadLog("case x.2\n") ;
if (pG_tgt->rhtMidptY() == pG_src->rhtMidptY())
{
// Target graphic is vertically equal to the source target - Draw line from either the RHS of source to the LHS of target, or vice versa, then triangle arrow head
//threadLog("case A\n") ;
if (pG_tgt->m_Lft > pG_src->m_Rht)
{
threadLog("case a.1\n") ;
sX = pG_src->rhtMidptX() ;
sY = pG_src->rhtMidptY() ;
tX = pG_tgt->lftMidptX() ;
tY = pG_tgt->lftMidptY() ;
_hds_svg_drawLine(Z, sX, sY, tX, tY, color, lw) ;
_hds_svg_drawTriangle(Z, tX-10, tY-4, tX-10, tY+4, tX-6, tY, color) ;
}
else
{
//threadLog("case a.2\n") ;
sX = pG_src->lftMidptX() ;
sY = pG_src->lftMidptY() ;
tX = pG_tgt->rhtMidptX() ;
tY = pG_tgt->rhtMidptY() ;
_hds_svg_drawLine(Z, sX, sY, tX, tY, color, lw) ;
_hds_svg_drawTriangle(Z, tX+10, tY-4, tX+10, tY+4, tX+6, tY, color) ;
}
goto doText ;
}
if (pG_tgt->rhtMidptY() > pG_src->rhtMidptY())
{
// Downwards flow (increasing Y). Draw one or more lines with an overall down direction. Put the triangle toward the target on the last appraoch
//threadLog("case B\n") ;
sX = pG_src->botMidptX() ;
sY = pG_src->botMidptY() ;
tX = pG_tgt->topMidptX() ;
tY = pG_tgt->topMidptY() ;
mY = sY + ((tY-sY)/2) ;
threadLog("case b.1\n") ;
if (sX == tX)
{
//threadLog("case b.2\n") ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, sY, tX, tY, color, lw) ;
}
else
{
// Draw short vertical line (first leg), a horizontal line and then another vertical (last approach)
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, sY, sX, mY, color, lw) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, mY, tX, mY, color, lw) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", tX, mY, tX, tY, color, lw) ;
}
_hds_svg_drawTriangle(Z, tX-4, tY-10, tX+4, tY-10, tX, tY-6, color) ;
goto doText ;
}
// Upwards flow (decreasing Y). Draw one or more lines with an overall up direction. Put the triangle toward the target on the last appraoch
//threadLog("case C\n") ;
sX = pG_src->topMidptX() ;
sY = pG_src->topMidptY() ;
tX = pG_tgt->botMidptX() ;
tY = pG_tgt->botMidptY() ;
mY = sY - ((tY-sY)/2) ;
//threadLog("case c.1\n") ;
if (sX == tX)
{
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, sY, tX, tY, color, lw) ;
}
else
{
// Draw short vertical line (first leg), a horizontal line and then another vertical (last approach)
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, sY, sX, mY, color, lw) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", sX, mY, tX, mY, color, lw) ;
Z.Printf("<line x1=\"%u\" y1=\"%u\" x2=\"%u\" y2=\"%u\" style=\"stroke:#%06x;stroke-width:%u\"/>\n", tX, mY, tX, tY, color, lw) ;
}
_hds_svg_drawTriangle(Z, tX-4, tY+10, tX+4, tY+10, tX, tY+6, color) ;
doText:
if (pConn->m_eType)
{
if (pConn->m_eType & HDS_CONNECTOR_TRUE)
_hds_svg_drawText(Z, s_fc_conn_TRUE, sX, sY, 0xff0000, 1) ;
else
{
if (pConn->m_eType & HDS_CONNECTOR_FALSE)
_hds_svg_drawText(Z, s_fc_conn_FALSE, sX, sY, 0xff0000, 1) ;
}
}
}
void hdsFlowchart::Generate (hzChain& Z, hzHttpEvent* pE, uint32_t& nLine)
{
// Displays a diagram by placing in the page HTML, a <svg> tag.
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsFlowchart::Generate") ;
hdsText TX ; // Current text
hdsGraphic* pG ; // Current shape
hdsConnector* pConn ; // Connector
hzString text ; // For diagnostics
uint32_t n ; // Shapes and connector iterator
threadLog("Shapes %d, Connects %d\n", m_nShapes, m_nConnects) ;
// Use SVG
if (m_nBoundary)
Z.Printf("<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"border:1px solid #000000; background:#%06x;\">\n", *m_Id, m_Height, m_Width, m_BgColor) ;
else
Z.Printf("<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"background:#%06x;\">\n", *m_Id, m_Height, m_Width, m_BgColor) ;
// Draw shapes
for (n = 0 ; n < m_nShapes ; n++)
{
pG = m_pShapes + n ;
if (!pG)
break ;
Z.AddByte(CHAR_TAB) ;
switch (pG->m_eShape)
{
case HDSGRAPH_HEXAGON: Z.Printf("<polygon points=\"%u,%u %u,%u %u,%u %u,%u, %u,%u, %u,%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u\"/>\n",
pG->m_Lft, pG->m_Top + (pG->m_Height/2),
pG->m_Lft + (pG->m_Height/2), pG->m_Top,
pG->m_Rht - (pG->m_Height/2), pG->m_Top,
pG->m_Rht, pG->m_Top + (pG->m_Height/2),
pG->m_Rht - (pG->m_Height/2), pG->m_Bot,
pG->m_Lft + (pG->m_Height/2), pG->m_Bot,
m_ColorTest, m_ColorLine, m_nWidthConn) ;
break ;
case HDSGRAPH_RECT: Z.Printf("<rect x=\"%u\" y=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u;\"/>\n",
pG->m_Lft, pG->m_Top, pG->m_Width, pG->m_Height, m_ColorProc, m_ColorLine, m_nWidthConn) ;
break ;
case HDSGRAPH_STADIUM: Z.Printf("<rect x=\"%u\" y=\"%u\" rx=\"%u\" ry=\"%u\" width=\"%u\" height=\"%u\" style=\"fill:#%06x;stroke:#%06x;stroke-width:%u;\"/>\n",
pG->m_Lft, pG->m_Top, pG->m_Height/2, pG->m_Height/2, pG->m_Width, pG->m_Height, m_ColorTerm, m_ColorLine, m_nWidthConn) ;
break ;
}
if (pG->m_Text)
{
if (pG->m_nLines == 1)
Z.Printf("\t<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%d:%s</text>\n", pG->lftMidptX(), pG->lftMidptY(), pG->m_ColorLine, n, *pG->m_Text) ;
else
_hds_svg_drawMLText(Z, pG->m_Text, pG->m_Lft, pG->m_Top+20, pG->m_ColorLine, n) ;
}
else
{
Z.Printf("\t<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%d: No text</text>\n", pG->lftMidptX(), pG->lftMidptY(), pG->m_ColorLine, n) ;
}
}
// Draw connectors
for (n = 0 ; n < m_nConnects ; n++)
{
pConn = m_pConn + n ;
//if (!pConn)
// break ;
//if (pConn->m_Origin && pConn->m_Target)
//{
//pG = m_pShapes + pConn->m_Origin ;
//pT = m_pShapes + pConn->m_Target ;
_drawFlowConn(Z, this, pConn) ;
//}
}
Z << "</svg>\n" ;
}
void hdsDiagram::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Displays a diagram by placing in the page HTML, a <svg> tag. This has to refer to a JavaScript which must appear earlier in the HTML
//
// Arguments: 1) Z The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsDiagram::Generate") ;
hzList<hdsGraphic>::Iter gI ; // Graphic object iterator
hzList<hdsLine>::Iter lI ; // List iterator for lines
hzList<hdsText>::Iter tI ; // List iterator for texts
hzChain Z ; // This part of chain
hdsText TX ; // Current text
hdsLine LN ; // Current line
hdsGraphic gObj ; // Current graphic object
// Calculate total width and height of svg image
for (gI = m_Shapes ; gI.Valid() ; gI++)
{
gObj = gI.Element() ;
}
// Generate the svg tag
Z.Printf("<svg id=\"%s\" height=\"%d\" width=\"%d\" style=\"border:1px solid #000000; background:#%06x;\">", *m_Id, m_Height, m_Width, m_BgColor) ;
for (gI = m_Shapes ; gI.Valid() ; gI++)
{
gObj = gI.Element() ;
gObj.Draw(Z) ;
}
// Handle lines last as a special case
for (lI = m_Lines ; lI.Valid() ; lI++)
{
LN = lI.Element() ;
_hds_svg_drawLine(Z, LN) ;
}
for (tI = m_Texts ; tI.Valid() ; tI++)
{
TX = tI.Element() ;
Z.Printf("<text x=\"%u\" y=\"%u\" fill=\"#%06x\">%s</text>\n", TX.V(), TX.H(), TX.Color(), TX.Text()) ;
}
Z << "</svg>\n" ;
C << Z ;
//"document.getElementById('articlecontent').addEventListener('DOMCharacterDataModified',paintJob" << m_Id << ");\n"
}
void hdsHtag::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Display the inactive HTML tag as part of page
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsHtag::Generate") ;
hdsVE* pVE ; // For processing subtags
//hzFixPair pa ; // Tag attribute
hzPair pa ; // Tag attribute
hzString S ; // Temp string
uint32_t n ; // Tab counter
int32_t aLo ; // First attribute
int32_t aHi ; // Last attribute
int32_t nA ; // Attribute iterator
hzHtagform tagForm ; // HTML tag type
// Write out newline and tabs if the current tag's line is greater than the supplied line
if (m_Line != nLine)
{
C.AddByte(CHAR_NL) ;
for (n = m_Indent ; n ; n--)
C.AddByte(CHAR_TAB) ;
nLine = m_Line ;
}
// Write out the opening tag
C.AddByte(CHAR_LESS) ;
C << m_Tag ;
if (m_nAttrs)
{
aLo = m_pApp->m_VE_attrs.First(m_VID) ;
if (aLo >= 0)
{
aHi = m_pApp->m_VE_attrs.Last(m_VID) ;
for (nA = aLo ; nA <= aHi ; nA++)
{
pa = m_pApp->m_VE_attrs.GetObj(nA) ;
C.AddByte(CHAR_SPACE) ;
C << *pa.name ;
C.AddByte(CHAR_EQUAL) ;
C.AddByte(CHAR_DQUOTE) ;
if (pE && (m_flagVE & VE_AT_ACTIVE))
C << m_pApp->ConvertText(*pa.value, pE) ;
else
C << *pa.value ;
C.AddByte(CHAR_DQUOTE) ;
}
}
}
C.AddByte(CHAR_MORE) ;
// Now for each subtag, output first the pretext (part of this tag's content) and then call Display on the subtag
for (pVE = Children() ; pVE ; pVE = pVE->Sibling())
{
if (pVE->m_strPretext)
{
S = pVE->m_strPretext ;
if (pE && (pVE->m_flagVE & VE_PT_ACTIVE))
C << m_pApp->ConvertText(S, pE) ;
else
C << S ;
}
pVE->Generate(C, pE, nLine) ;
}
// Now write out the content
if (m_strContent)
{
// if (pLang && m_usiContent)
// S = pLang->m_LangStrings[m_usiContent] ;
// else
S = m_strContent ;
if (pE && m_flagVE & VE_CT_ACTIVE)
C << m_pApp->ConvertText(S, pE) ;
else
C << S ;
}
// Now write the antitag
S = *m_Tag ;
tagForm = TagLookup(S) ;
if (tagForm.rule != HTRULE_SINGLE)
{
if (nLine != m_Line)
{
C.AddByte(CHAR_NL) ;
for (n = m_Indent ; n ; n--)
C.AddByte(CHAR_TAB) ;
nLine = m_Line ;
}
C.AddByte(CHAR_LESS) ;
C.AddByte(CHAR_FWSLASH) ;
C << m_Tag ;
C.AddByte(CHAR_MORE) ;
}
}
void hdsXtag::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// The <x> tag does not itself generate a HTML tag but instead inserts textual content into the parent tag.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsHtag::Generate") ;
hdsVE* pVE ; // For processing subtags
hzString S ; // Temp string
uint32_t n ; // Tab counter
// Write out newline and tabs if the current tag's line is greater than the supplied line
if (m_Line != nLine)
{
C.AddByte(CHAR_NL) ;
for (n = m_Indent ; n ; n--)
C.AddByte(CHAR_TAB) ;
nLine = m_Line ;
}
// Now for each subtag, output first the pretext (part of this tag's content) and then call Display on the subtag
for (pVE = Children() ; pVE ; pVE = pVE->Sibling())
{
if (pVE->m_strPretext)
{
S = pVE->m_strPretext ;
if (pE && (pVE->m_flagVE & VE_PT_ACTIVE))
C << m_pApp->ConvertText(S, pE) ;
else
C << S ;
}
pVE->Generate(C, pE, nLine) ;
}
// Now write out the content
if (m_strContent)
{
S = m_strContent ;
if (pE && m_flagVE & VE_CT_ACTIVE)
C << m_pApp->ConvertText(S, pE) ;
else
C << S ;
}
}
void hdsBlock::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregate to the supplied chain (the HTML body), the set of tags found within this hdsBlock instance. This is the functional equivelent of a
// server side include.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsBlock::Generate") ;
hzList<hdsVE*>::Iter ih ; // Visible entity iterator
hdsVE* pVE ; // Child visible entity
uint32_t relLn ; // Relative line
uint32_t nV ; // Visual entity iterator
m_pApp->m_pLog->Log("BK %p %d %s\n", this, m_VID, *m_Refname) ;
relLn = nLine ;
for (nV = 0 ; nV < m_VEs.Count() ; nV++)
{
pVE = m_VEs[nV] ;
m_pApp->m_pLog->Log("VE %p %d %s\n", pVE, pVE->m_VID, *pVE->m_Tag) ;
pVE->Generate(C, pE, nLine) ;
}
nLine = relLn ;
}
void hdsXdiv::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// On the condition that the user's access matches that of this <xdiv> tag, aggregate to the supplied chain (the HTML body), all child tags. Do
// nothing otherwise.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsXdiv::Generate") ;
hdsVE* pVE ; // Visible entity
hdsInfo* pInfo ; // Client session data
bool bShow ; // Print or not to print
bShow = false ;
pInfo = (hdsInfo*) pE->Session() ;
if (!pInfo)
{
if (m_Access == ACCESS_PUBLIC || m_Access == ACCESS_NOBODY)
bShow = true ;
}
else
{
if (m_Access == ACCESS_PUBLIC || (m_Access == ACCESS_ADMIN && pInfo->m_Access & ACCESS_ADMIN)
|| (pInfo->m_Access & ACCESS_MASK) == m_Access)
bShow = true ;
}
if (bShow)
{
for (pVE = Children() ; pVE ; pVE = pVE->Sibling())
pVE->Generate(C, pE, nLine) ;
}
}
void hdsCond::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// If the flags are 0, then the variable named in m_Tag must be null for the subtags of <xcond> to be executed. Otherwise the named variable must
// exist and be non-null for the subtags to be executed.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 3) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsCond::Generate") ;
//hzFixPair pa ; // Tag attribute
hzPair pa ; // Tag attribute
hdsVE* pVE ; // Subtag pointer
hdsInfo* pInfo ; // User session if applicable
hzString nam ; // The variable value, if applicable
hzString val ; // The variable value, if applicable
int32_t aLo ; // First attribute
int32_t aHi ; // Last attribute
int32_t nA ; // Attribute iterator
bool bPassed ; // True if condition passed
bPassed = true ;
if (pE)
{
if (m_nAttrs)
{
pInfo = (hdsInfo*) pE->Session() ;
if (pInfo)
{
aLo = m_pApp->m_VE_attrs.First(pVE->m_VID) ;
if (aLo >= 0)
{
aHi = m_pApp->m_VE_attrs.Last(pVE->m_VID) ;
for (nA = aLo ; nA <= aHi ; nA++)
{
pa = m_pApp->m_VE_attrs.GetObj(nA) ;
if (*pa.value)
val = m_pApp->ConvertText(*pa.value, pE) ;
nam = *pa.name ;
if ((nam == "isnull" && val) || (nam == "exists" && !val))
{ bPassed = false ; break ; }
}
}
}
}
}
if (bPassed)
{
for (pVE = Children() ; pVE ; pVE = pVE->Sibling())
pVE->Generate(C, pE, nLine) ;
}
}
void hdsPage::Head (hzHttpEvent* pE)
{
// Send only the HTTP header for a page to the browser.
//
// Arguments: 1) pE The HTTP event
//
// Returns: None
_hzfunc("hdsPage::Head") ;
ifstream is ; // Read file stream
hzXDate d ; // Date for header lines
hzChain Z ; // Response for browser is built here
const char* pEnd ; // Filename extension and hence type
hzMimetype type ; // File's HTTP type
HttpRC hrc ; // HTTP return code
hzEcode rc ; // Return code from sending function
// Establish real filename, either cpFilename or index.htm(l)
// Determine the type of file so that the correct header can be
// sent to the browser
pEnd = strrchr(*m_Url, CHAR_PERIOD) ;
if (pEnd)
type = Filename2Mimetype(pEnd) ;
else
type = HMTYPE_TXT_HTML ;
// Send the header
Z.Clear() ;
switch (hrc)
{
case HTTPMSG_OK: Z << "HTTP/1.1 200 OK\r\n" ; break ;
case HTTPMSG_NOTFOUND: Z << "HTTP/1.1 404 Not found\r\n" ; break ;
default:
Z.Printf("HTTP/1.1 %03d\r\n", hrc) ;
} ;
d.SysDateTime() ;
Z.Printf("Date: %s\r\n", d.Txt(FMT_DT_INET)) ;
Z << "Server: HTTP/1.0 (HadronZoo, Linux)\r\n" ;
Z.Printf("Last-Modified: %s\r\n", d.Txt(FMT_DT_INET)) ;
d.altdate(SECOND, 1000) ;
Z.Printf("Expires: %s\r\n", d.Txt(FMT_DT_INET)) ;
Z << "Accept-Ranges: bytes\r\n" ;
if (hrc == HTTPMSG_OK)
Z.Printf("Content-Length: 0\r\n") ;
Z << "Content-Type: " << Mimetype2Txt(type) << "\n\n" ;
pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, Z, 0, false) ;
}
void hdsArtref::Generate (hzChain& C, hzHttpEvent* pE, uint32_t& nLine)
{
// Aggregate to the supplied chain (the HTML body), this article's preformulated value (the tags found within this article)
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
// 4) nLine Line number tracker (controls NL printing)
//
// Returns: None
_hzfunc("hdsArtref::Generate") ;
hzList<hdsVE*>::Iter ih ; // Html entity iterator
hdsInfo* pInfo = 0 ; // Session
//hdsLang* pLang ; // Applicable language
hdsNavtree* pAG = 0 ; // Article group
hdsArticle* pArt = 0 ; // The article
hdsArticleStd* pArtStd = 0 ; // The article as a visible entity container
hdsArticleCIF* pArtCIF = 0 ; // The article as a C-Interface function
hzString S ; // Temp string
if (!this)
Fatal("No instance\n") ;
// Get session if one applies
if (pE)
pInfo = (hdsInfo*) pE->Session() ;
threadLog("info %p\n", pInfo) ;
// Lookup the tree of articles. This could be in the hdsApp map m_ArticleGroups or it could be vested with the session
pAG = m_pApp->m_ArticleGroups[m_Group] ;
if (!pAG)
{
if (pInfo && pInfo->m_pTree)
if (pInfo->m_pTree->m_Groupname == m_Group)
pAG = pInfo->m_pTree ;
}
if (!pAG)
{
C.Printf("SORRY: No such article group (%s)", *m_Group) ;
return ;
}
if (m_Show == 300)
{
// Export tree as script
C << "\n<script language=\"javascript\">\n" ;
pAG->ExportDataScript(C) ;
C.Printf("makeTree('%s');\n", *m_Group) ;
C << "</script>\n" ;
return ;
}
if (m_Article[0] == CHAR_AT)
{
if (!memcmp(*m_Article, "@resarg;/", 9))
{
if (pE && pE->m_Resarg)
pArt = (hdsArticle*) pAG->GetItem(pE->m_Resarg) ;
else
{
S = *m_Article + 9 ;
pArt = (hdsArticle*) pAG->GetItem(S) ;
}
}
}
else
{
pArt = (hdsArticle*) pAG->GetItem(m_Article) ;
threadLog("fetched article %p %s\n", pArt, *m_Article) ;
}
if (!pArt)
{
C.Printf("SORRY: No article with group (%s) and name (%s)", *m_Group, *m_Article) ;
}
else
{
if (m_Show == 100)
{
C << pArt->m_Title ;
}
else if (m_Show == 200)
{
pArtStd = dynamic_cast<hdsArticleStd*>(pArt) ;
if (pArtStd)
{
// pLang = (hdsLang*) pE->m_pContextLang ;
// C << pLang->m_rawItems[pArtStd->m_USL] ;
pArtStd->Display(C, pE) ;
}
else
{
pArtCIF = dynamic_cast<hdsArticleCIF*>(pArt) ;
if (pArtCIF && pE)
pArtCIF->m_pFunc(C, pArtCIF, pE) ;
}
}
else
{
C.Printf("FOUND: article with group (%s) and name (%s) but no show directive", *m_Group, *pArt->m_Title) ;
}
}
}
//void hdsArticleStd::Generate (hzChain& C, hzHttpEvent* pE)
void hdsArticleStd::EvalHtml (hzChain& C)
{
// Generate HTML for an article.
//
// If the applicable article contains active elements and so is itself active, this function will be called to serve the article in response to an AJAX request. Otherwise this
// function is only called to create a fixed HTML value for the article during program initialization.
//
// Note this function is never called by hdsPage::Display() since an hdsArticle cannot be a page component.
//
// Argument: C The HTML output chain
// Returns: None
_hzfunc("hdsArticleStd::Display") ;
hzHttpEvent httpEv ; // Artificial HTTP event
hdsVE* pVE ; // Html entity
uint32_t nV ; // Visual entity iterator
uint32_t relLn ; // Relative line
threadLog("Generating Article %s\n", *m_Title) ;
for (nV = 0 ; nV < m_VEs.Count() ; nV++)
{
pVE = m_VEs[nV] ; pVE->Generate(C, &httpEv, relLn) ;
}
}
void hdsArticleStd::Display (hzChain& C, hzHttpEvent* pE)
{
// Generate HTML for an article.
//
// If the applicable article contains active elements and so is itself active, this function will be called to serve the article in response to an AJAX request. Otherwise this
// function is only called to create a fixed HTML value for the article during program initialization.
//
// Note this function is never called by hdsPage::Display() since an hdsArticle cannot be a page component.
//
// Arguments: 1) C The HTML output chain
// 2) pE The HTTP event being responded to
//
// Returns: None
_hzfunc("hdsArticleStd::Display") ;
hdsVE* pVE ; // Html entity
uint32_t nV ; // Visual entity iterator
uint32_t relLn ; // Relative line
threadLog("Generating Article %s\n", *m_Title) ;
for (nV = 0 ; nV < m_VEs.Count() ; nV++)
{
pVE = m_VEs[nV] ; pVE->Generate(C, pE, relLn) ;
}
}
void hdsPage::EvalHtml (hzChain& C) //, hdsLang* pLang)
{
// Create HTML for a page that is inactive and so can be stored. This will be done once per inactive pager per supported language. Because this is part of the initialization
// process there will not be an actual HTTP event so a blank one is created. This is necessary because the language is carried by the HTTP event m_pContextLang variable.
//
// CHANGE to:-
// Create pro-forma HTML for the page. If the page is active, this HTML will interspersed with percent entities that must be evaluated with each serving.
//
// Arguments: 1) C The HTML output chain
// 2) pLang Current language
//
// Returns: None
_hzfunc("hdsPage::EvalHtml") ;
hzList<hdsVE*>::Iter ih ; // Html entity iterator
hzList<hdsFormref*>::Iter iF ; // Form iterator
hzHttpEvent httpEv ; // Artificial HTTP event
hzChain X ; // For zipping output if applicable
hdsVE* pH ; // Html entity
hdsFormref* pFormref ; // Form reference
hdsFormdef* pFormdef ; // Form definition
uint32_t relLn ; // Relative line
uint32_t nV ; // Visual entity iterator
hzEcode rc ; // Return code
// if (!pLang)
// Fatal("No language supplied\n") ;
// httpEv.m_pContextLang = pLang ;
m_pApp->m_pLog->Log("PAGE %s Script Flags %x\n", *m_Title, m_bScriptFlags) ;
// Construct the output HTML
if (!m_Title)
m_Title = "untitled" ;
C << "<!DOCTYPE html>\n"
"<html>\n"
"<head>\n" ;
C << "<title>" << m_Title << "</title>\n" ;
if (m_Desc)
C.Printf("<meta name=\"description\" content=\"%s\"/>\n", *m_Desc) ;
else
C.Printf("<meta name=\"description\" content=\"%s\"/>\n", *m_Title) ;
if (m_Keys)
C.Printf("<meta name=\"keywords\" content=\"%s\"/>\n", *m_Keys) ;
C << s_std_metas ;
C << "<link rel=\"stylesheet\" href=\"" << m_pApp->m_namCSS << "\"/>\n" ;
if (m_bScriptFlags || m_xForms.Count())
{
if (m_bScriptFlags & INC_SCRIPT_RECAPTCHA)
C << s_Recaptcha ;
C << "<script language=\"javascript\">\n" ;
// If page contains forms then it must include validation javascript in the HTML
if (m_xForms.Count())
{
if (m_bScriptFlags & INC_SCRIPT_CKEMAIL)
C << _dsmScript_ckEmail ;
if (m_bScriptFlags & INC_SCRIPT_CKURL)
C << _dsmScript_ckUrl ;
if (m_bScriptFlags & INC_SCRIPT_EXISTS)
C << _dsmScript_ckExists ;
for (iF = m_xForms ; iF.Valid() ; iF++)
{
pFormref = iF.Element() ;
pFormdef = m_pApp->m_FormDefs[pFormref->m_Formname] ;
C << pFormdef->m_ValJS ;
//C << pFormref->m_pFormdef->m_ValJS ;
}
C << m_validateJS ;
}
C << "</script>\n" ;
}
C << "</head>\n\n" ;
// Construct the <body> tag
C << "<body" ;
if (m_CSS)
C.Printf(" class=\"%s\"", *m_CSS) ;
else
C.Printf(" bgcolor=\"#%06x\" marginwidth=\"%d\" marginheight=\"%d\" leftmargin=\"%d\" topmargin=\"%d\"",
m_BgColor, m_Width, m_Height, m_Width, m_Top) ;
if (m_Onpage) C.Printf(" onpageshow=\"%s\"", *m_Onpage) ;
if (m_Onload) C.Printf(" onload=\"%s\"", *m_Onload) ;
if (m_Resize) C.Printf(" onresize=\"%s\"", *m_Resize) ;
C << ">\n" ;
m_pApp->m_pLog->Log("PAGE %s Script Flags %x\n", *m_Title, m_bScriptFlags) ;
// Now construct the page elements
relLn = m_Line ;
for (nV = 0 ; nV < m_VEs.Count() ; nV++)
{
pH = m_VEs[nV] ; pH->Generate(C, &httpEv, relLn) ;
}
// End page construction
C << "</body>\n</html>\n" ;
m_pApp->m_pLog->Log("PAGE %s Script Flags %x\n", *m_Title, m_bScriptFlags) ;
}
void hdsPage::Display (hzHttpEvent* pE)
{
// Display HTML according to listed entities in the page.
//
// Argument: pE The HTTP event being responded to
//
// Returns: None
_hzfunc("hdsPage::Display") ;
hzList<hdsExec*>::Iter ei ; // Page exec commands iterator
hzList<hdsVE*>::Iter ih ; // Html entity iterator
hzList<hdsFormref*>::Iter iF ; // Form iterator
hzChain C ; // For formulating HTML
hdsExec* pExec ; // Exec function
hdsVE* pVE ; // Html entity
hdsFormref* pFormref ; // Form
hdsFormdef* pFormdef ; // Form definition
uint32_t relLn ; // Relative line
uint32_t nV ; // Visual entity iterator
hzEcode rc ; // Return code
if (!pE) Fatal("No HTTP Event\n") ;
if (!pE->m_pContextLang) Fatal("No Language\n") ;
m_pApp->m_pLog->Log("PAGE %s Script Flags %x\n", *m_Title, m_bScriptFlags) ;
// Run executable commands
for (ei = m_Exec ; ei.Valid() ; ei++)
{
pExec = ei.Element() ;
m_pApp->m_pLog->Log("HAVE EXEC %s\n", Exec2Txt(pExec->m_Command)) ;
rc = pExec->Exec(C, pE) ;
m_pApp->m_pLog->Out(C) ;
C.Clear() ;
}
// Construct the output HTML
if (!m_Title)
m_Title = "untitled" ;
C << "<!DOCTYPE html>\n"
"<html>\n"
"<head>\n" ;
if (pE && pE->m_Resarg)
C.Printf("<title>%s-%s</title>\n", *m_Title, *pE->m_Resarg) ;
else
C << "<title>" << m_Title << "</title>\n" ;
if (m_Desc)
C.Printf("<meta name=\"description\" content=\"%s\"/>\n", *m_Desc) ;
else
C.Printf("<meta name=\"description\" content=\"%s\"/>\n", *m_Title) ;
if (m_Keys)
C.Printf("<meta name=\"keywords\" content=\"%s\"/>\n", *m_Keys) ;
C << s_std_metas ;
C << "<link rel=\"stylesheet\" href=\"" << m_pApp->m_namCSS << "\"/>\n" ;
if (m_bScriptFlags || m_xForms.Count())
{
if (m_bScriptFlags & INC_SCRIPT_RECAPTCHA)
C << s_Recaptcha ;
C << "<script language=\"javascript\">\n" ;
if (m_bScriptFlags & INC_SCRIPT_WINDIM)
C << _dsmScript_gwp ;
if (m_bScriptFlags & INC_SCRIPT_NAVTREE)
{
C << _dsmScript_tog ;
C << _dsmScript_loadArticle ;
C << _dsmScript_navtree ;
}
// If page contains forms then it must include validation javascript in the HTML
if (m_xForms.Count())
{
if (m_bScriptFlags & INC_SCRIPT_CKEMAIL) C << _dsmScript_ckEmail ;
if (m_bScriptFlags & INC_SCRIPT_CKURL) C << _dsmScript_ckUrl ;
if (m_bScriptFlags & INC_SCRIPT_EXISTS) C << _dsmScript_ckExists ;
for (iF = m_xForms ; iF.Valid() ; iF++)
{
pFormref = iF.Element() ;
pFormdef = m_pApp->m_FormDefs[pFormref->m_Formname] ;
C << pFormdef->m_ValJS ;
}
C << m_validateJS ;
}
C << "</script>\n" ;
}
C << "</head>\n\n" ;
// Construct the <body> tag
C << "<body" ;
if (m_CSS)
C.Printf(" class=\"%s\"", *m_CSS) ;
else
C.Printf(" bgcolor=\"#%06x\" marginwidth=\"%d\" marginheight=\"%d\" leftmargin=\"%d\" topmargin=\"%d\"",
m_BgColor, m_Width, m_Height, m_Width, m_Top) ;
if (m_Onpage) C.Printf(" onpageshow=\"%s\"", *m_Onpage) ;
if (m_Onload) C.Printf(" onload=\"%s\"", *m_Onload) ;
if (m_Resize) C.Printf(" onresize=\"%s\"", *m_Resize) ;
C << ">\n" ;
// Now construct the page elements
relLn = m_Line ;
for (nV = 0 ; nV < m_VEs.Count() ; nV++)
{
pVE = m_VEs[nV] ; pVE->Generate(C, pE, relLn) ;
}
// End page construction
C << "</body>\n</html>\n" ;
// Send out page. Note all generated pages are sent out raw, not zipped
rc = pE->SendRawChain(HTTPMSG_OK, HMTYPE_TXT_HTML, C, 0, false) ;
}