Location: PHPKode > scripts > B-Forms > b-forms/layout.inc
<?
/* -------------------------------------------------------------

    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 "&nbsp;";
               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 "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ".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 "&nbsp;" 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;
   }
}


?>
Return current item: B-Forms