$content$tag>
// If is_null($content), a single tag will be createed (<$tag $paramkey="$paramvalue"/>).
// If a value or key of the $parameter hash is NULL, the key="value" entry will not appear.
// The content and the parameter are not encoded in any way.
function html_tag($tagname, $parameter, $content) {
	$result = "<$tagname";
	foreach($parameter as $key => $value) {
		if (!is_null($value) && !is_null($key))
		$result .= " $key=\"$value\"";
	}
	if (is_null($content)) return $result . '/>';
	return $result . ">$content$tagname>";
}
// Applies the function htmlentities on every value of an array.
function html_escape_array($array, $keystoo = FALSE) {
	$newarray = array();
	foreach($array as $key => $value) {
		if (is_string($value)) $value = htmlspecialchars($value, ENT_COMPAT, 'ISO-8859-1');
		if ($keystoo && is_string($key)) $key = htmlspecialchars($key, ENT_COMPAT, 'ISO-8859-1');
		$newarray[$key] = $value;
	}
	return $newarray;
}
// indents a text
function text_indent($text, $indentchar = "\t") {
	if (strlen($text) == 0) return '';
	$result = $indentchar . str_replace("\n", "\n$indentchar", $text);
	if (substr($result, -2) == "\n$indentchar") $result = substr($result, 0, -strlen($indentchar));
	return $result;
}
// Cuts a text to the specified max length and adds fill char. The cutting is done at word ends.
// If the text is shorter than maxlength, it returns text.
function text_cut($text, $maxlength, $fillchar = ' ...') {
	if (strlen($text) <= $maxlength) return $text;
	$text = wordwrap($text, $maxlength);
	$lines = explode("\n", $text);
	return $lines[0] . $fillchar;
}
// Shortcuts for creating simple things
// ====================================
// Shortcut for html_tag: You can use it in the following ways:
// html_element($tagname);
// html_element($tagname, $content [, $encode]);
// html_element($tagname, $parameter [, $encode]);
// html_element($tagname, $parameter, $content, [, $encode]);
// The optional argument $encode is FALSE by default.
// If $encode is TRUE, the $content _and_ the parameters _and_ the keys of the parameters will be encoded.
function html_element($tagname) {
	list($tagname, $parameter, $content) = html_element_decode(func_get_args());
	return html_tag($tagname, $parameter, $content);
}
// same as html_element but it does not result in
// content
// but
// \n
// \t content\n
// 
function html_ielement($tagname) {
	list($tagname, $parameter, $content) = html_element_decode(func_get_args());
	if (!is_null($content) && !$content == '') {
		$content = "\n" . text_indent($content);
		if (substr($content, -1) != "\n") $content .= "\n";
	}
	return html_tag($tagname, $parameter, $content);
}
// "internal" function to use at html_element and html_ielement
// Brings the arguments in the correct order and does the encoding
function html_element_decode($args) {
	// Parameter
	$tagname = $args[0];
	$encode = FALSE;
	$parameter = array();
	$content = NULL;
	for ($i=1; $i != count($args); ++$i) {
		$arg = $args[$i];
		if (is_bool($arg)) $encode = $arg;
		else if (is_array($arg)) $parameter = $arg;
		else if (is_string($arg)) $content = $arg;
		else die('unknown arguments in html_element');
	}
	// Encoding
	if ($encode) {
		$parameter = html_escape_array($parameter, TRUE);
		if (!is_null($content)) $content = htmlspecialchars($content, ENT_COMPAT, 'ISO-8859-1');
	}
	return array($tagname, $parameter, $content);
}
// Shortcuts for form fields
// =========================
// Helper function for the following form-field-generating functions
function html_input_basic($name, $value, $type, $additionalParameter = array()) {
	$parameter = array('type' => $type, 'name' => $name, 'value' => $value);
	$parameter = array_merge($parameter, $additionalParameter);
	return html_element('input', $parameter, TRUE);
}
// Creates an hidden field
function html_input_hidden($name, $value) {
	return html_input_basic($name, $value, 'hidden');
}
// Creates an input text field
function html_input_text($name, $value=NULL, $length=NULL, $size=NULL) {
	return html_input_basic($name, $value, 'text', array('maxlength' => $length, 'size' => $size));
}
// Creates an input password field
function html_input_password($name, $value=NULL, $length=NULL, $size=NULL) {
	return html_input_basic($name, $value, 'password', array('maxlength' => $length, 'size' => $size));
}
// Creates a submit field
function html_input_submit($name, $value) {
	return html_input_basic($name, $value, 'submit');
}
// Creates a reset field
function html_input_reset($value) {
	return html_input_basic(NULL, $value, 'reset');
}
// Creates a select box field
function html_input_select($name, $value=NULL, $hash, $encode=FALSE, $format=TRUE, $size=1) {
	$options = '';
	foreach($hash as $k => $v) {
		$parameter = array('value' => $k);
		if ($value == $k) $parameter['selected'] = 'selected';
		$options .= html_element('option', $parameter, $v, $encode) . "\n";
	}
	if ($format) $options = "\n" . text_indent($options);
	if ($encode) $name = htmlspecialchars($name, ENT_COMPAT, 'ISO-8859-1');
	return html_element('select', array('name' => $name, 'size' => $size), $options);
}
// Creates a textarea field
function html_textarea($name, $value, $cols, $rows, $encode=FALSE) {
	$parameter = array('name' => $name, 'cols' => $cols, 'rows' => $rows);
	if (is_null($value)) $value = ''; 
	return html_element('textarea', $parameter, $value, $encode);
}
// Creates a string for an img element. You can use the function as follows:
//   html_img($src) // alt=""
//   html_img($src, [$alt,] [$encode,] [$keyvaluearray])
//   html_img($src, [$alt,] [$keyvaluearray,] [$encode])
// keyvaluearray: supply additional attributes. default: array()
// encode: default: FALSE
// alt: default: ''
function html_img($src, $alt='') {
	$encode = FALSE;
	$attributes = array('src' => $src, 'alt' => $alt);
	$args = func_get_args();
	for($i = 2; $i != count($args); ++$i) {
		$arg = $args[$i];
		if (is_bool($arg)) $encode=$arg;
		if (is_array($arg)) $attributes=array_merge($attributes, $arg);
	}
	return html_element('img', $attributes, $encode);
}
// Same as above with additional title. If title is NULL, $title = $alt.
function html_img_title($src, $alt='', $title=NULL) {
	$func_parameter = func_get_args();
	if (is_null($title)) $title = $alt;
	unset($func_parameter[2]);
	$found = FALSE;
	foreach($func_parameter as $k => $v) {
		if (is_array($v)) {
			$func_parameter[$k]['title'] = $title;
			$found = TRUE;
		}
	}
	if (!$found) $func_parameter[] = array('title' => $title);
	return call_user_func_array('html_img', $func_parameter);
}
// DataInfo classes
// ================
// These classes are intended for use with EditForm.
// For all class fields, the value NULL means that a default value should be taken.
class DataInfo {
	var $header;
	var $name; // name for form.
	var $default; // default value for insert
	function DataInfo($name = NULL, $header = NULL, $default = NULL) {
		$this->name = $name;
		$this->header = $header;
		$this->default = $default;
	}
	// virtual...
	// creates the head cell of the table
	function createHtmlTableHeader() {
		if (!is_null($this->header))
			return html_element('span', array('class'=>'th'), $this->header, TRUE);
	}
	// virtual...
	// creates the body cell of the table
	function createHtmlTableBody($value) {
		return html_element('span', array('class'=>'td'), $this->createHtml($value));
	}
	// virtual...
	// creates the body cell of an insert row of the table
	function createHtmlTableInsertBody() {
		return html_element('span', array('class'=>'td'), $this->createInsertHtml());
	}
	// virtual...
	function createHtml($value) {
		return '';
	}
	// virtual...
	function createInsertHtml() {
		return $this->createHtml($this->default);
	}
};
// This shows the text but is not "database sensitive"
class DiReadOnly extends DataInfo {
	function DiReadOnly($header = NULL, $default = NULL) {
		$this->DataInfo(NULL, $header, $default);
	}
	function createHtml($value) {
		return htmlspecialchars($value, ENT_COMPAT, 'ISO-8859-1');
	}
};
class DiHidden extends DataInfo {
	function DiHidden($name, $default = NULL) {
		$this->DataInfo($name, NULL, $default);
	}
	function createHtmlTableBody($value) {
		return $this->createHtml($value);
	}
	function createHtmlTableInsertBody() {
		return $this->createInsertHtml();
	}
	function createHtml($value) {
		return html_input_hidden($this->name, $value);
	}
	function createInsertHtml() {
		if (is_null($this->default)) return '';
		return $this->createHtml($this->default);
	}
};
/*
class DiRawHtml extends DataInfo {
	function createHtml($value) {
		return $value;
	}
};
*/
class DiTextEdit extends DataInfo {
	var $length = NULL;
	var $size = NULL;
	function DiTextEdit($name, $header, $length = NULL, $size = NULL, $default = NULL) {
		$this->DataInfo($name, $header, $default);
		$this->length = $length;
		$this->size = $size;
	}
	function createHtml($value) {
		return html_input_text($this->name, $value, $this->length, $this->size);
	}
	
	function createInsertHtml() {
		return $this->createHtml($this->default);
	}	
};
class DiPasswordEdit extends DiTextEdit {
	function createHtml($value) {
		return html_input_password($this->name, 'XXXXXX', $this->length, $this->size);
	}
	
	function createInsertHtml() {
		return html_input_password($this->name, '', $this->length, $this->size);
	}
};
// input: 1D array of arrays with 2 entries.
// the first will be used as key, the second as value.
// Useful to crate hash for DiSelect out of database query result.
function array_to_hash($array) {
	$result = array();
	foreach ($array as $row) {
		$result[$row[0]] = (string) $row[1];
	}
	return $result;
}
class DiSelect extends DataInfo {
	var $hash;
	function DiSelect($name, $heading, $hash) {
		$this->DataInfo($name, $heading);
		$this->hash = $hash;
	}
	function createHtml($value) {
		$hash = html_escape_array($this->hash, TRUE);
		return html_input_select($this->name, $value, $hash, TRUE);
	}
};
class DiBoolEdit extends DataInfo {
	function createHtml($value) {
		$hash = array('' => '---', 't' => _('Yes'), 'f' => _('No'));
		return html_input_select($this->name, $value, $hash);
	}
};
class DiBoolReadOnly extends DataInfo {
	function DiBoolReadOnly($header = NULL, $default = NULL) {
		$this->DataInfo(NULL, $header, $default);
	}
	function createHtml($value) {
		if ($value == 't') return htmlspecialchars(_('Yes'), ENT_COMPAT, 'ISO-8859-1');
		if ($value == 'f') return htmlspecialchars(_('No'), ENT_COMPAT, 'ISO-8859-1');
		return '';
	}
};
// The data are not editable (but are shown) in normal rows.
// Therefore a lookup hash is used.
// In the "insert" row, a combobox is used.
class DiOnlyInputSelect extends DataInfo {
	var $lookupHash; // hash for "normal" lines to lookup.
	var $insertHash; // hash for comboBox for "insert" line.
	
	function DiOnlyInputSelect($name, $header, $default, $lookupHash, $insertHash) {
		$this->DataInfo($name, $header, $default);
		$this->lookupHash = $lookupHash;
		$this->insertHash = $insertHash;
	}
	function createHtml($value) {
		$hash = html_escape_array($this->lookupHash, TRUE);
		$hiddenField = html_input_hidden($this->name, $value);
		if (array_key_exists($value, $hash)) return $hiddenField . $hash[$value];
		return $hiddenField . '(' . htmlentities($value, ENT_COMPAT, 'ISO-8859-1') . ')';
	}
	function createInsertHtml() {
		$hash = html_escape_array($this->insertHash, TRUE);
		return html_input_select($this->name, $this->default, $hash, TRUE);
	}
};
class DiTextareaEdit extends DataInfo {
	var $cols = NULL;
	var $rows = NULL;
	function DiTextareaEdit($name, $header, $cols = NULL, $rows = NULL) {
		$this->DataInfo($name, $header);
		$this->cols = $cols;
		$this->rows = $rows;
	}
	function createHtml($value) {
		return html_textarea($this->name, $value, $this->cols, $this->rows, TRUE);
	}
};
// EditForm classes and functions
// ==============================
// creates an array of DataInfo classes suitable for the $dbresult.
// if fieldnamekeys === TRUE, the field names will be taken as keys,
//   else numbers will be taken.
// $header: the names of the header
// $size: the size of the field, if the type has a size.
// $length: the length of the field, if the type has a length. If NULL,
//   the $size will be taken.
// $header, $size, $length can each be:
// * assoziative array (hash): columnname => value
// * normal array: values "from left to right"
// * string functionname to apply to the default values i.e. ucwords.
// The value NULL means that this property is not taken,
// a value TRUE means that the default property is taken.
function html_defaultColumns(
	$dbresult,
	$fieldnamekeys = FALSE,
	$header = NULL,
	$size = NULL,
	$length = NULL
) {
	for ($col = 0; $col != pg_num_fields($dbresult); ++$col) {
		// Name
		$cname = pg_field_name($dbresult, $col);
		// Type
		$ctype = pg_field_type($dbresult, $col);
		// Size
		$dsize = pg_field_size($dbresult, $col);
		$csize = FALSE;
		if (is_string($size)) $csize = $size($dsize);
		elseif (is_array($size) && array_key_exists($cname, $size)) $csize = $size[$cname];
		elseif (is_array($size) && array_key_exists($col, $size)) $csize = $size[$col];
		if ($csize === FALSE) $csize = $dsize;
		if ($csize == -1) $csize = NULL;
		// Length
		$clength = FALSE;
		if (is_string($length)) $clength = $length($csize);
		elseif (is_array($length) && array_key_exists($cname, $length)) $clength = $length[$cname];
		elseif (is_array($length) && array_key_exists($col, $length)) $clength = $length[$col];
		if ($clength === FALSE) $clength = $csize;
		// Header
		$cheader = FALSE;
		if (is_string($header)) $cheader = $header($cname);
		elseif (is_array($header) && array_key_exists($cname, $header)) $cheader = $header[$cname];
		elseif (is_array($header) && array_key_exists($col, $header)) $cheader = $header[$col];
		if ($cheader === FALSE) $cheader = $cname;
		// Create DataInfo class
		$di = NULL;
		if ($ctype == 'bool') $di = new DiBoolEdit($cname, $cheader);
		if (is_null($di)) $di = new DiTextEdit($cname, $cheader, $csize, $clength);
		if ($fieldnamekeys) $columns[$cname] = $di;
		else $columns[] = $di;
	}
	return $columns;
}
function html_createEditForm(
	$action,
	$nextpage, // data to fill in in the field :nextpage (needed by editdb.php)
	$tablename,
	$columns, // 1D Array of EfDataInfo classes
	$data, // Array of rows, that are again arrays of columns
	$insert=TRUE,
	$update=TRUE,
	$delete=TRUE
) {
	if (count($data) == 0 && !$insert) return;
	$action = htmlspecialchars($action, ENT_COMPAT, 'ISO-8859-1');
	// fill in nextpage
	$columns[] = new DiHidden(':nextpage', $nextpage);
	foreach ($data as $rownum => $datarow) {
		$data[$rownum][] = $nextpage;
	}
	
	// fill in tablename
	$columns[] = new DiHidden(':tablename', $tablename);
	foreach ($data as $rownum => $datarow) {
		$data[$rownum][] = $tablename;
	}
	
	// head
	$head = '';
	foreach($columns as $column) {
		$h = $column->createHtmlTableHeader();
		if (strlen($h) > 0) $h .= "\n";
		$head .= $h;
	}
	$head .= html_element('span', array('class'=>'th'), ' ');
	$result = html_ielement('div', array('class'=>'tr_head'), $head) . "\n";
	// update
	$rownr = 0;
	foreach($data as $datarow) {
		$row = '';
		$columnnr = 0;
		foreach ($datarow as $field) {
			$column = $columns[$columnnr];			
			$html = $column->createHtmlTableBody($field);
			if (strlen($html) > 0) $html .= "\n";
			$row .= $html;
			++$columnnr;
		}
		$buttons = '';
		if ($update) $buttons .= html_input_submit(':operation_update', _('update'));
		if ($delete) $buttons .= html_input_submit(':operation_delete', _('delete'));
		$row .= html_element('span', array('class'=>'td'), $buttons);
		$class = ($rownr % 2 == 0) ? 'tr_even' : 'tr_odd';
		$result .= html_ielement('form', array('action' => $action, 'method' => 'post', 'class' => $class), $row) . "\n";
		++$rownr;
	}
	// insert
	if ($insert) {
		$row = '';
		foreach($columns as $column) {
			$html = $column->createHtmlTableInsertBody();
			if (strlen($html) > 0) $html .= "\n";
			$row .= $html;
		}
		$button = html_input_submit(':operation_insert', _('insert')) . "\n";
		$row .= html_element('span', array('class'=>'td'), $button);
		$result .= html_ielement('form', array('action' => $action, 'method' => 'post', 'class' => 'tr_insert'), $row);
		// $result .= html_ielement('div', array('class' => 'tr_insert'), $row);
	}
	return html_ielement('div', array('class'=>'table'), $result);
}
function html_createVEditForm(
	$action,
	$tablename,
	$columns, // 1D Array of EfDataInfo classes
	$data, // Array of rows, that are again arrays of columns
	$insert=TRUE,
	$update=TRUE,
	$delete=TRUE
) {
	// fill in tablename
	$columns[] = new DiHidden(':tablename', $tablename);
	foreach ($data as $rownum => $datarow) {
		$data[$rownum][] = $tablename;
	}
	// Rows
	$rows = '';
	$rownr = 0;
	foreach($data as $row) {
		$coltext = '';
		reset($columns);
		reset($row);
		while($column = current($columns)) {
			$head = $column->createHtmlTableHeader();
			$field = $column->createHtmlTableBody(current($row));
			$text = "$head\n$field";
			if (!is_null($column->header)) $text = html_ielement('tr', $text);
			$coltext .= "$text\n";
			next($columns);
			next($row);
		}
		$buttons = '';
		if ($update) $buttons .= html_input_submit(':operation_update', _('update'));
		if ($delete) $buttons .= html_input_submit(':operation_delete', _('delete'));
		$coltext .= '
| ' . html_element('td', $buttons) . " | 
|---|
\n";
		$coltext = html_ielement('form', array('action' => $action, 'method' => 'post'), $coltext) . "\n";
		$class = ($rownr % 2 == 0) ? 'even' : 'odd';
		$coltext = html_ielement('table', array('class' => $class), $coltext) . "\n";
		$coltext = html_ielement('p', $coltext) . "\n";
		$rows .= $coltext;
		++$rownr;
	}
	// Insert
	if ($insert) {
		$coltext = '';
		reset($columns);
		while($column = current($columns)) {
			$head = $column->createHtmlTableHeader();
			$field = $column->createHtmlTableInsertBody();
			$text = "$head\n$field";
			if (!is_null($column->header)) $text = html_ielement('tr', $text);
			$coltext .= "$text\n";
			next($columns);
		}
		$button = html_input_submit(':operation_insert', _('insert'));
		$coltext .= '| ' . html_element('td', $button) . " | 
|---|
\n";
		$coltext = html_ielement('form', array('action' => $action, 'method' => 'post'), $coltext) . "\n";
		$coltext = html_ielement('table', array('class' => 'insert'), $coltext) . "\n";
		$coltext = html_ielement('p', $coltext) . "\n";
		$rows .= $coltext;
	}
	return $rows;
}
function html_createTable(
	$head, // 1D Array of Head fields
	$data // Array of rows, that are again arrays of columns
) {
	html_escape_array($head);
	$thead = '| ' . implode(' | ', $head) . " | 
|---|
\n";
	$tbody = '';
	$num = 0;
	foreach($data as $row) {
		html_escape_array($row);
		$trow = '' . implode(' | ', $row) . '';
		$tbody .= html_element('tr', array('class' => ($num % 2 == 0 ? 'even' : 'odd')), $trow);
		++$num;
	}
	return html_ielement('table', "$thead$tbody");
}
?> |