<?
/* -------------------------------------------------------------
B-Forms / Layout
An object-oriented library to manage web-forms in PHP.
An extention to automatically generate form layouts.
Copyright (C) 2004 Alexei Peterkin, hide@address.com
This 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 2.1 of the License, or (at your
option) any later version.
This 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 this library; if not, write to
the Free Software Foundation, Inc., 59 Temple Place, Suite
330, Boston, MA 02111-1307 USA
-------------------------------------------------------------- */
require_once("b-forms.inc");
/**
* The config class for {@link BaseLayout}.
*/
class BaseLayoutConfig {
/**#@+
* @access public
* @var string
*/
/**
* Opens the whole block layout.
*/
var $layout_open = "<table>\n";
/**
* Closes the whole block layout.
*/
var $layout_close = "</table>\n";
/**
* Opens a new line for a property
*/
var $property_open = "<tr>\n";
/**
* Closes the line for a property.
*/
var $property_close = "</tr>\n";
/**
* Opening HTML before the property label
*/
var $label_open = "<td class=\"formlabel\">";
/**
* Closing HTML after the property label
*/
var $label_close = ":</td>\n";
/**
* Opening HTML before the property input tag
*/
var $field_open = "<td class=\"formfield\">";
/**
* Closing HTML after the property input tag
*/
var $field_close = "</td>\n";
/**
* {@link Separator} will be generates like this.
*/
var $separator = "<tr><td colspan=\"2\" class=\"separator\"></td></tr>\n";
/**
* Opening HTML before {@link SectionHeader}.
*/
var $header_open = "<tr><td colspan=\"2\" class=\"sectionheader\">\n";
/**
* Closing HTML after {@link SectionHeader}.
*/
var $header_close = "</td></tr>\n";
/**
* Opening HTML before the bottom line with all the buttons
*/
var $controls_open = "<tr><td colspan=\"2\" class=\"formcontrols\">\n";
/**
* Opening HTML after the bottom line with all the buttons
*/
var $controls_close = "</td></tr>\n";
/**
* Opening HTML before a form-wide space, where another block
* will be inserted.
*/
var $subblock_open = "<tr><td colspan=\"2\" class=\"inline\">\n";
/**
* Closing HTML after a form-wide space, where another block
* has been inserted.
*/
var $subblock_close = "</td></tr>\n";
/**#@-*/
}
/**
* {@link BaseLayout} should generate the complete block.
*
* @access public
*/
define('BL_FULL', 3);
/**
* {@link BaseLayout} should generate only data entry properties (no controls).
*
* @access public
*/
define('BL_DATA', 1);
/**
* {@link BaseLayout} should generate only controls
*
* @access public
*/
define('BL_CONTROLS', 2);
/**
* The standard layout for single-row blocks.
*
* Looks like a two column table, where the first column is the labels, and
* the second column is the fields.
* All the buttons are at the bottom.
*
* For options, see {@link BL_FULL}, {@link BL_DATA}, {@link BL_CONTROLS}.
*/
class BaseLayout {
/**
* An instance of {@link BaseLayoutConfig} class or its descendant.
*
* @access private
* @var BaseLayoutConfig
*/
var $config;
/**
* Rendering options.
*
* See {@link BL_FULL}, {@link BL_DATA}, {@link BL_CONTROLS}.
*
* @access private
* @var int
*/
var $options;
/**
* @access public
* @param BaseLayoutConfig an instance of a descendant of BaseLayoutConfig. If you do not
* provide a value, an instance of BaseLayoutConfig will be created
* automatically.
* @param int options, see {@link BL_FULL}, {@link BL_DATA}, {@link BL_CONTROLS}.
*/
function BaseLayout($config = null, $options = BL_FULL) {
if ($config) {
$this->config = $config;
}
else {
$this->config = new BaseLayoutConfig();
}
$this->options = $options;
}
/**#@+
* @access private
*/
/**
* Open the block layout
*/
function open_layout() {
echo $this->config->layout_open;
}
/**
* Close the block layout
*/
function close_layout() {
echo $this->config->layout_close;
}
/**
* Open a space for generating inner block.
*/
function open_subblock() {
echo $this->config->subblock_open;
}
/**
* Close a space for generating inner block.
*/
function close_subblock() {
echo $this->config->subblock_close;
}
/**
* Generate a new line, provided label, then open property input tag space.
*
* @param string the label to be generated
*/
function open_pseudo_property($label) {
echo $this->config->property_open;
echo $this->config->label_open;
echo $label;
echo $this->config->label_close;
echo $this->config->field_open;
}
/**
* Close property input tag space, including end of line.
*/
function close_pseudo_property() {
echo $this->config->field_close;
echo $this->config->property_close;
}
/**
* Generate separator.
*/
function show_separator() {
echo $this->config->separator;
}
/**
* Open header element
*/
function open_header() {
echo $this->config->header_open;
}
/**
* Close header element
*/
function close_header() {
echo $this->config->header_close;
}
/**#@-*/
/**
* Generate the block.
*
* The <var>$options</var> parameter overrides the one specified
* in the constructor. If omitted, the value from the constructor
* will be used.
*
* @access public
* @param string the name of the block
* @param int see {@link BL_FULL}, {@link BL_DATA}, {@link BL_CONTROLS}.
*/
function show_block($block, $options = null) {
global $_form;
if ($options == null)
$options = $this->options;
if ($options == BL_FULL)
$this->open_layout();
if (($options & BL_DATA) > 0) {
foreach ($_form->$block->_properties as $name => $property) {
if ($_form->$block->_properties[$name]->is_control) continue;
if (!$_form->$block->_properties[$name]->is_visible()) continue;
if ($_form->$block->_properties[$name]->layout_needs_label()) {
echo $this->config->property_open;
echo $this->config->label_open;
label($block, $name);
echo $this->config->label_close;
echo $this->config->field_open;
field($block, $name);
echo $this->config->field_close;
echo $this->config->property_close;
}
else {
field($block, $name);
}
}
}
if (($options & BL_CONTROLS) > 0) {
$first = TRUE;
foreach ($_form->$block->_properties as $name => $property) {
if ($_form->$block->_properties[$name]->is_control &&
$_form->$block->_properties[$name]->is_visible()) {
if ($first) {
echo $this->config->separator;
echo $this->config->controls_open;
$first = FALSE;
}
field($block, $name);
}
}
if (!$first)
echo $this->config->controls_close;
}
if ($options == BL_FULL)
echo $this->close_layout();
}
}
/**
* The config class for {@link TableLayout}.
*/
class TableLayoutConfig {
/**#@+
* @access public
* @var string
*/
/**
* Opens the whole block layout.
*/
var $layout_open = "<table>\n";
/**
* Closes the whole block layout.
*/
var $layout_close = "</table>\n";
/**
* Opens the row of column labels.
*/
var $header_open = "<tr>\n";
/**
* Closes the row of column labels.
*/
var $header_close = "</tr>\n";
/**
* Opens a data record.
*/
var $record_open = "<tr>\n";
/**
* Closes a data record.
*/
var $record_close = "</tr>\n";
/**
* Opens a column label.
*/
var $label_open = "<td class=\"formheaderlabel\">";
/**
* Closes a column label.
*/
var $label_close = "</td>\n";
/**
* Opens a column for data.
*/
var $field_open = "<td class=\"formfield\">";
/**
* Closes a column for data.
*/
var $field_close = "</td>\n";
/**
* Opens a column for a control.
*/
var $control_open = "<td class=\"formrowcontrols\">";
/**
* Closes a column for a control.
*/
var $control_close = "</td>\n";
/**#@-*/
}
/**
* The standard layout for multi-row blocks.
*
* Looks like a table with labels at the top row, and a row
* for each record in the block.
*/
class TableLayout {
/**
* An instance of {@link TableLayoutConfig} class or its descendant.
*
* @access private
* @var TableLayoutConfig
*/
var $config;
/**
* Indicates whether the column headers should be generated.
*
* @access private
* @var bool
*/
var $show_labels;
/**
* @access public
* @param bool specifies whether the column headers (with field labels) should
* be generated, by default TRUE.
* @param TableLayoutConfig an instance of TableLayoutConfig or a descendant, by
* default an instance of TableLayoutConfig will be automatically
* created.
*/
function TableLayout($show_labels = TRUE, $config = null) {
if ($config) {
$this->config = $config;
}
else {
$this->config = new TableLayoutConfig();
}
$this->show_labels = $show_labels;
}
/**
* Generate the block.
*
* The <var>$show_labels</var> parameter overrides the one specified
* in the constructor. If omitted, the value from the constructor
* will be used.
*
* @access public
* @param string the name of the block
* @param bool specifies whether the column headers (with field labels) should
* be generated, by default TRUE.
*/
function show_block($block, $show_labels = null) {
global $_form;
if ($show_labels == null)
$show_labels = $this->show_labels;
echo $this->config->layout_open;
// Generate the label row
if ($show_labels) {
echo $this->config->header_open;
foreach ($_form->$block->_properties as $name => $property) {
if ($_form->$block->_properties[$name]->is_visible()) {
echo $this->config->label_open;
if ($_form->$block->_properties[$name]->is_control)
echo " ";
else
label($block, $name);
echo $this->config->label_close;
}
}
echo $this->config->header_close;
}
// Generate the rows
for ($i=0; $i<$_form->$block->get_record_count(); $i++) {
if (($_form->$block->is_record_deleted($i)) > 0)
continue;
echo $this->config->record_open;
foreach ($_form->$block->_properties as $name => $property) {
if ($_form->$block->_properties[$name]->is_visible()) {
if ($_form->$block->_properties[$name]->is_control) {
echo $this->config->control_open;
field($block, $name, $i);
echo $this->config->control_close;
}
else {
echo $this->config->field_open;
field($block, $name, $i);
echo $this->config->field_close;
}
}
}
echo $this->config->record_close;
}
echo $this->config->layout_close;
}
}
/**
* Tells the template that it should open the block of rows.
*
* @access public
*/
define('TL_START', -100);
/**
* Tells the template that it should close the block of rows.
*
* @access public
*/
define('TL_END', -200);
/**
* Another layout for multi-row blocks.
*
* Each row is generated by programmer supplied template.
* A template is a function that takes one parameter - $rownum. And then generates
* a row with this number. The function is called with two special row nubmers
* {@link TL_START} and {@link TL_END} respectively before and after all actual rows.
*/
class TemplateLayout {
/**
* The name of the template function
*
* @access private
* @var string
*/
var $template;
/**
* @access public
* @param string the name of the template function.
*/
function TemplateLayout($template) {
$this->template = $template;
}
/**
* Generate the block.
*
* @access public
* @param string the name of the block
*/
function show_block($block) {
global $_form;
$first = TRUE;
// Generate the rows
for ($i=0; $i<$_form->$block->get_record_count(); $i++) {
if (($_form->$block->is_record_deleted($i)) > 0)
continue;
if ($first) {
call_user_func($this->template, TL_START);
$first = FALSE;
}
call_user_func($this->template, $i);
}
if (!$first)
call_user_func($this->template, TL_END);
}
}
/**
* A dummy property serving as layout control.
*/
class LayoutElement extends Property {
/**
* Determines whether a label is needed for this field.
*
* @access private
* @returns bool
*/
function layout_needs_label() {
if ($this->display->no_label)
return FALSE;
if (!$this->label)
return FALSE;
return TRUE;
}
/**
* Prints out the property definition and data
*
* This is a service method, part of the {@link Block::printblock()} debug call.
*
* This implementation prints the class of the property and the class of the
* display.
*
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function printproperty($rownum = -1) {
echo " ".get_class($this).
" as ".get_class($this->display)."<br/>";
}
/**#@+
* This implementation overrides the default implementation to do nothing
* or return empty value.
*
* @access private
*/
/**
* @returns bool
*/
function needs_validation() {
return FALSE;
}
/**
* @returns Display
*/
function get_default_display() {
return null;
}
/**
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function set_default_value($rownum = -1) {
}
/**
* @param mixed the new value
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function set_value($value, $rownum = -1) {
}
/**
* @returns string
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function get_value($rownum = -1) {
return "";
}
/**
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function form_read($rownum = -1) {
}
/**
* @param array array of values returned by SQL SELECT
* @param int first not yet used value in the array
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function sql_read($row, &$count, $rownum=-1) { // Do nothing
}
/**
* @returns bool
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function validate($rownum = -1) {
return TRUE;
}
/**
* @returns string
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function get_sql_name() { // Return empty
return "";
}
/**
* @returns string
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function get_form_name($rownum = -1) { // Return empty
return "";
}
/**
* @returns string
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function get_sql_value($rownum = -1) { // Return empty
return "";
}
/**
* @returns string
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function get_form_value($rownum = -1) { // Return empty
return "";
}
/**
* @param array a reference to array, that contains name=>value pairs
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function auto_store(&$attributes, $rownum = -1) { // Do nothing
}
/**
* @param array a reference to array, that contains name=>value pairs
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function auto_restore(&$attributes, $rownum = -1) { // Do nothing
}
/**#@-*/
/**
* @access public
* @param string optional, label for the layout element.
*/
function LayoutElement($label = "") {
if (!isset($GLOBALS['_dummy_count']))
$GLOBALS['_dummy_count'] = 0;
parent::Property('_dummy_'.(++$GLOBALS['_dummy_count']), $label, '', FALSE);
}
}
/**
* Empty space bewteen rows.
*
* This display is designated for {@link LayoutElement} property.
* Only works with {@link BaseLayout}.
*/
class Separator extends Display {
/**
* A reference to the layout used to render the parent block.
*
* @access private
* @var BaseLayout
*/
var $layout;
/**
* @access public
* @param BaseLayout a reference to layout that will be used to render the block.
*/
function Separator(&$layout) {
$this->layout = &$layout;
$this->no_label = TRUE;
}
/**
* Renders the separator
*
* @access private
* @param Property the property to be displayed
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function show($property, $rownum = -1) {
$this->layout->show_separator();
}
/**
* Indicates read-only properties.
*
* This implementation returns TRUE.
*
* @returns bool
* @access private
*/
function is_readonly() {
return TRUE;
}
}
/**
* A form section header whithin the layout.
*
* This display is designated for {@link LayoutElement} property.
* Only works with {@link BaseLayout}.
*/
class SectionHeader extends Display {
/**
* A reference to the layout used to render the parent block.
*
* @access private
* @var BaseLayout
*/
var $layout;
/**
* @access public
* @param BaseLayout a reference to layout that will be used to render the block.
*/
function SectionHeader(&$layout) {
$this->layout = &$layout;
$this->no_label = TRUE;
}
/**
* Renders the header
*
* @access private
* @param Property the property to be displayed
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function show($property, $rownum = -1) {
$this->layout->open_header();
echo $property->label;
$this->layout->close_header();
}
/**
* Indicates read-only properties.
*
* This implementation returns TRUE.
*
* @returns bool
* @access private
*/
function is_readonly() {
return TRUE;
}
}
/**
* A placeholder for another block, usually multi-row.
*
* If the corresponding {@link LayoutElement} has a label, the label
* will be displayed in front of the block, as if the block was just an field.
*
* If the corresponding {@link LayoutElement} does not have a label, the inner block
* will take up the whole width, including space reserved for labels.
*
* If you want a label-less inline block, but aligned in the same column with
* normal properties, use " " for the label.
*
* This display is designated for {@link LayoutElement} property.
* Only works with {@link BaseLayout}.
*/
class InlineBlock extends Display {
/**
* A reference to the layout used to render the parent block.
*
* @access private
* @var BaseLayout
*/
var $layout;
/**
* The name of the block to be inlined.
*
* @access private
* @var string
*/
var $block;
/**
* A reference to the layout that will be used to render the inlined block.
*
* @access private
* @var TableLayout
*/
var $block_layout;
/**
* @access public
* @param BaseLayout a reference to layout for the outer block.
* @param string the name of the inner block
* @param TableLayout a reference to layout for the inner block.
*/
function InlineBlock(&$layout, $block, &$block_layout) {
$this->layout = &$layout;
$this->block = $block;
$this->block_layout = &$block_layout;
}
/**
* Renders the inline block.
*
* @access private
* @param Property the property to be displayed
* @param int the record number for which the property is to be displayed. If -1 or
* omitted, it is a single-row block.
*/
function show($property, $rownum = -1) {
if ($property->label == "")
$this->layout->open_subblock();
$this->block_layout->show_block($this->block);
if ($property->label == "")
$this->layout->close_subblock();
}
/**
* Indicates read-only properties.
*
* This implementation returns TRUE.
*
* @returns bool
* @access private
*/
function is_readonly() {
return TRUE;
}
}
?>