3  * Replacement for the default renderer of HTML_QuickForm that uses only XHTML
 
   4  * and CSS but no table tags, and generates fully valid XHTML output
 
  10  * Copyright (c) 2005-2007, Mark Wiesemann <wiesemann@php.net>
 
  11  * All rights reserved.
 
  13  * Redistribution and use in source and binary forms, with or without
 
  14  * modification, are permitted provided that the following conditions
 
  17  *    * Redistributions of source code must retain the above copyright
 
  18  *      notice, this list of conditions and the following disclaimer.
 
  19  *    * Redistributions in binary form must reproduce the above copyright
 
  20  *      notice, this list of conditions and the following disclaimer in the
 
  21  *      documentation and/or other materials provided with the distribution.
 
  22  *    * The names of the authors may not be used to endorse or promote products
 
  23  *      derived from this software without specific prior written permission.
 
  25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 
  26  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
  27  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
  28  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
  29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
  30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
  31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
  32  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
  33  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 
  34  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 
  35  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
  38  * @package    HTML_QuickForm_Renderer_Tableless
 
  39  * @author     Alexey Borzov <borz_off@cs.msu.su>
 
  40  * @author     Adam Daniel <adaniel1@eesus.jnj.com>
 
  41  * @author     Bertrand Mansion <bmansion@mamasam.com>
 
  42  * @author     Mark Wiesemann <wiesemann@php.net>
 
  43  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
 
  44  * @version    CVS: $Id: Tableless.php 271939 2008-12-26 20:22:30Z wiesemann $
 
  45  * @link       http://pear.php.net/package/HTML_QuickForm_Renderer_Tableless
 
  48 require_once 'HTML/QuickForm/Renderer/Default.php';
 
  51  * Replacement for the default renderer of HTML_QuickForm that uses only XHTML
 
  52  * and CSS but no table tags, and generates fully valid XHTML output
 
  54  * You need to specify a stylesheet like the one that you find in
 
  55  * data/stylesheet.css to make this work.
 
  58  * @package    HTML_QuickForm_Renderer_Tableless
 
  59  * @author     Alexey Borzov <borz_off@cs.msu.su>
 
  60  * @author     Adam Daniel <adaniel1@eesus.jnj.com>
 
  61  * @author     Bertrand Mansion <bmansion@mamasam.com>
 
  62  * @author     Mark Wiesemann <wiesemann@php.net>
 
  63  * @license    http://www.opensource.org/licenses/bsd-license.php New BSD License
 
  64  * @version    Release: 0.6.2
 
  65  * @link       http://pear.php.net/package/HTML_QuickForm_Renderer_Tableless
 
  67 class HTML_QuickForm_Renderer_Tableless extends HTML_QuickForm_Renderer_Default
 
  70     * Header Template string
 
  74     var $_headerTemplate = "\n\t\t<legend>{header}</legend>\n\t\t<ol>";
 
  77     * Element template string
 
  81     var $_elementTemplate =
 
  82         "\n\t\t\t<li><label class=\"element\"><!-- BEGIN required --><span class=\"required\">*</span><!-- END required -->{label}</label><div class=\"element<!-- BEGIN error --> error<!-- END error -->\"><!-- BEGIN error --><span class=\"error\">{error}</span><br /><!-- END error -->{element}</div></li>";
 
  85     * Form template string
 
  90         "\n<form{attributes}>\n\t<div style=\"display: none;\">\n{hidden}\t</div>\n{content}\n</form>";
 
  93     * Template used when opening a fieldset
 
  97     var $_openFieldsetTemplate = "\n\t<fieldset{id}{attributes}>";
 
 100     * Template used when opening a hidden fieldset
 
 101     * (i.e. a fieldset that is opened when there is no header element)
 
 105     var $_openHiddenFieldsetTemplate = "\n\t<fieldset class=\"hidden{class}\">\n\t\t<ol>";
 
 108     * Template used when closing a fieldset
 
 112     var $_closeFieldsetTemplate = "\n\t\t</ol>\n\t</fieldset>";
 
 115     * Required Note template string
 
 119     var $_requiredNoteTemplate =
 
 120         "\n\t\t\t<li class=\"reqnote\"><label class=\"element\"> </label>{requiredNote}</li>";
 
 123     * How many fieldsets are open
 
 127    var $_fieldsetsOpen = 0;
 
 130     * Array of element names that indicate the end of a fieldset
 
 131     * (a new one will be opened when the next header element occurs)
 
 135     var $_stopFieldsetElements = array();
 
 138     * Name of the currently active group
 
 142     var $_currentGroupName = '';
 
 149     function HTML_QuickForm_Renderer_Tableless()
 
 151         $this->HTML_QuickForm_Renderer_Default();
 
 155     * Called when visiting a header element
 
 157     * @param    object     An HTML_QuickForm_header element being visited
 
 161     function renderHeader(&$header)
 
 163         $name = $header->getName();
 
 164         $id = empty($name) ? '' : ' id="' . $name . '"';
 
 165         if (!empty($name) && isset($this->_templates[$name])) {
 
 166             $header_html = str_replace('{header}', $header->toHtml(), $this->_templates[$name]);
 
 168             $header_html = str_replace('{header}', $header->toHtml(), $this->_headerTemplate);
 
 170         $attributes = $header->getAttributes();
 
 172         if (is_array($attributes)) {
 
 173             $charset = HTML_Common::charset();
 
 174             foreach ($attributes as $key => $value) {
 
 175                 if ($key == 'name') {
 
 178                 $strAttr .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT, $charset) . '"';
 
 181         if ($this->_fieldsetsOpen > 0) {
 
 182             $this->_html .= $this->_closeFieldsetTemplate;
 
 183             $this->_fieldsetsOpen--;
 
 185         $openFieldsetTemplate = str_replace('{id}', $id, $this->_openFieldsetTemplate);
 
 186         $openFieldsetTemplate = str_replace('{attributes}',
 
 188                                             $openFieldsetTemplate);
 
 189         $this->_html .= $openFieldsetTemplate . $header_html;
 
 190         $this->_fieldsetsOpen++;
 
 191     } // end func renderHeader
 
 194     * Renders an element Html
 
 195     * Called when visiting an element
 
 197     * @param object     An HTML_QuickForm_element object being visited
 
 198     * @param bool       Whether an element is required
 
 199     * @param string     An error message associated with an element
 
 203     function renderElement(&$element, $required, $error)
 
 205         $this->_handleStopFieldsetElements($element->getName());
 
 206         if (!$this->_inGroup) {
 
 207             $html = $this->_prepareTemplate($element->getName(), $element->getLabel(), $required, $error);
 
 208             // the following lines (until the "elseif") were changed / added
 
 209             // compared to the default renderer
 
 210             $element_html = $element->toHtml();
 
 211             if (!is_null($element->getAttribute('id'))) {
 
 212                 $id = $element->getAttribute('id');
 
 214                 $id = $element->getName();
 
 216             if ($element->getType() != 'static' && !empty($id)) {
 
 217                 $html = str_replace('<label', '<label for="' . $id . '"', $html);
 
 218                 $element_html = preg_replace(preg_quote('#name="' . $id . '#'),
 
 219                                              'id="' . $id . '" name="' . $id,
 
 223             $this->_html .= str_replace('{element}', $element_html, $html);
 
 224         } elseif (!empty($this->_groupElementTemplate)) {
 
 225             $html = str_replace('{label}', $element->getLabel(), $this->_groupElementTemplate);
 
 227                 $html = str_replace('<!-- BEGIN required -->', '', $html);
 
 228                 $html = str_replace('<!-- END required -->', '', $html);
 
 230                 $html = preg_replace("/([ \t\n\r]*)?<!-- BEGIN required -->(\s|\S)*<!-- END required -->([ \t\n\r]*)?/i", '', $html);
 
 232             $this->_groupElements[] = str_replace('{element}', $element->toHtml(), $html);
 
 235             $element_html = $element->toHtml();
 
 236             // add "id" attribute to first element of the group
 
 237             if (count($this->_groupElements) === 0) {
 
 238                 if (!is_null($element->getAttribute('id'))) {
 
 239                     $id = $element->getAttribute('id');
 
 241                     $id = $element->getName();
 
 243                 $groupId = $this->_currentGroupName;
 
 244                 if ($element->getType() != 'static' && !empty($id)) {
 
 245                     $element_html = preg_replace(preg_quote('#name="' . $id . '#'),
 
 246                                                  'id="' . $groupId . '" name="' . $id,
 
 251             $this->_groupElements[] = $element_html;
 
 253     } // end func renderElement
 
 256     * Renders an hidden element
 
 257     * Called when visiting a hidden element
 
 259     * @param object     An HTML_QuickForm_hidden object being visited
 
 263     function renderHidden(&$element)
 
 265         if (!is_null($element->getAttribute('id'))) {
 
 266             $id = $element->getAttribute('id');
 
 268             $id = $element->getName();
 
 270         $html = $element->toHtml();
 
 272             $html = str_replace('name="' . $id,
 
 273                                 'id="' . $id . '" name="' . $id,
 
 276         $this->_hiddenHtml .= $html . "\n";
 
 277     } // end func renderHidden
 
 280     * Called when visiting a group, before processing any group elements
 
 282     * @param object     An HTML_QuickForm_group object being visited
 
 283     * @param bool       Whether a group is required
 
 284     * @param string     An error message associated with a group
 
 288     function startGroup(&$group, $required, $error)
 
 290         $this->_handleStopFieldsetElements($group->getName());
 
 291         $name = $group->getName();
 
 292         $this->_groupTemplate        = $this->_prepareTemplate($name, $group->getLabel(), $required, $error);
 
 293         $this->_groupTemplate        = str_replace('<label', '<label for="' . $name . '"', $this->_groupTemplate);
 
 294         $this->_groupElementTemplate = empty($this->_groupTemplates[$name])? '': $this->_groupTemplates[$name];
 
 295         $this->_groupWrap            = empty($this->_groupWraps[$name])? '': $this->_groupWraps[$name];
 
 296         $this->_groupElements        = array();
 
 297         $this->_inGroup              = true;
 
 298         $this->_currentGroupName     = $name;
 
 299     } // end func startGroup
 
 302     * Called when visiting a group, after processing all group elements
 
 304     * @param    object      An HTML_QuickForm_group object being visited
 
 308     function finishGroup(&$group)
 
 310         $separator = $group->_separator;
 
 311         if (is_array($separator)) {
 
 312             $count = count($separator);
 
 314             for ($i = 0; $i < count($this->_groupElements); $i++) {
 
 315                 $html .= (0 == $i? '': $separator[($i - 1) % $count]) . $this->_groupElements[$i];
 
 318             if (is_null($separator)) {
 
 319                 $separator = ' ';
 
 321             $html = implode((string)$separator, $this->_groupElements);
 
 323         if (!empty($this->_groupWrap)) {
 
 324             $html = str_replace('{content}', $html, $this->_groupWrap);
 
 326         if (!is_null($group->getAttribute('id'))) {
 
 327             $id = $group->getAttribute('id');
 
 329             $id = $group->getName();
 
 331         $groupTemplate = $this->_groupTemplate;
 
 333         $this->_html   .= str_replace('{element}', $html, $groupTemplate);
 
 334         $this->_inGroup = false;
 
 335     } // end func finishGroup
 
 338     * Called when visiting a form, before processing any form elements
 
 340     * @param    object      An HTML_QuickForm object being visited
 
 344     function startForm(&$form)
 
 346         $this->_fieldsetsOpen = 0;
 
 347         parent::startForm($form);
 
 348     } // end func startForm
 
 351     * Called when visiting a form, after processing all form elements
 
 352     * Adds required note, form attributes, validation javascript and form content.
 
 354     * @param    object      An HTML_QuickForm object being visited
 
 358     function finishForm(&$form)
 
 360         // add a required note, if one is needed
 
 361         if (!empty($form->_required) && !$form->_freezeAll) {
 
 362             $requiredNote = $form->getRequiredNote();
 
 363             // replace default required note by DOM/XHTML optimized note
 
 364             if ($requiredNote == '<span style="font-size:80%; color:#ff0000;">*</span><span style="font-size:80%;"> denotes required field</span>') {
 
 365                 $requiredNote = '<span class="required">*</span> denotes required field';
 
 367             $this->_html .= str_replace('{requiredNote}', $requiredNote, $this->_requiredNoteTemplate);
 
 369         // close the open fieldset
 
 370         if ($this->_fieldsetsOpen > 0) {
 
 371             $this->_html .= $this->_closeFieldsetTemplate;
 
 372             $this->_fieldsetsOpen--;
 
 374         // add form attributes and content
 
 375         $html = str_replace('{attributes}', $form->getAttributes(true), $this->_formTemplate);
 
 376         if (strpos($this->_formTemplate, '{hidden}')) {
 
 377             $html = str_replace('{hidden}', $this->_hiddenHtml, $html);
 
 379             $this->_html .= $this->_hiddenHtml;
 
 381         $this->_hiddenHtml = '';
 
 382         $this->_html = str_replace('{content}', $this->_html, $html);
 
 383         $this->_html = str_replace('></label>', '> </label>', $this->_html);
 
 384         // add a validation script
 
 385         if ('' != ($script = $form->getValidationScript())) {
 
 386             $this->_html = $script . "\n" . $this->_html;
 
 388     } // end func finishForm
 
 391      * Sets the template used when opening a fieldset
 
 393      * @param       string      The HTML used when opening a fieldset
 
 397     function setOpenFieldsetTemplate($html)
 
 399         $this->_openFieldsetTemplate = $html;
 
 400     } // end func setOpenFieldsetTemplate
 
 403      * Sets the template used when opening a hidden fieldset
 
 404      * (i.e. a fieldset that is opened when there is no header element)
 
 406      * @param       string      The HTML used when opening a hidden fieldset
 
 410     function setOpenHiddenFieldsetTemplate($html)
 
 412         $this->_openHiddenFieldsetTemplate = $html;
 
 413     } // end func setOpenHiddenFieldsetTemplate
 
 416      * Sets the template used when closing a fieldset
 
 418      * @param       string      The HTML used when closing a fieldset
 
 422     function setCloseFieldsetTemplate($html)
 
 424         $this->_closeFieldsetTemplate = $html;
 
 425     } // end func setCloseFieldsetTemplate
 
 428      * Adds one or more element names that indicate the end of a fieldset
 
 429      * (a new one will be opened when a the next header element occurs)
 
 431      * @param       mixed      Element name(s) (as array or string)
 
 432      * @param       string     (optional) Class name for the fieldset(s)
 
 436     function addStopFieldsetElements($element, $class = '')
 
 438         if (is_array($element)) {
 
 440             foreach ($element as $name) {
 
 441                 $elements[$name] = $class;
 
 443             $this->_stopFieldsetElements = array_merge($this->_stopFieldsetElements,
 
 446             $this->_stopFieldsetElements[$element] = $class;
 
 448     } // end func addStopFieldsetElements
 
 451      * Handle element/group names that indicate the end of a group
 
 453      * @param string     The name of the element or group
 
 457     function _handleStopFieldsetElements($element)
 
 459         // if the element/group name indicates the end of a fieldset, close
 
 461         if (   array_key_exists($element, $this->_stopFieldsetElements)
 
 462             && $this->_fieldsetsOpen > 0
 
 464             $this->_html .= $this->_closeFieldsetTemplate;
 
 465             $this->_fieldsetsOpen--;
 
 467         // if no fieldset was opened, we need to open a hidden one here to get
 
 469         if ($this->_fieldsetsOpen === 0) {
 
 471             if (   array_key_exists($element, $this->_stopFieldsetElements)
 
 472                 && $this->_stopFieldsetElements[$element] != ''
 
 474                 $replace = ' ' . $this->_stopFieldsetElements[$element];
 
 476             $this->_html .= str_replace('{class}', $replace,
 
 477                                         $this->_openHiddenFieldsetTemplate);
 
 478             $this->_fieldsetsOpen++;
 
 480     } // end func _handleStopFieldsetElements
 
 483      * Sets element template
 
 485      * @param   string    The HTML surrounding an element
 
 486      * @param   mixed     (optional) Name(s) of the element to apply template
 
 487      *                    for (either single element name as string or multiple
 
 488      *                    element names as an array)
 
 492     function setElementTemplate($html, $element = null)
 
 494         if (is_null($element)) {
 
 495             $this->_elementTemplate = $html;
 
 496         } elseif (is_array($element)) {
 
 497             foreach ($element as $name) {
 
 498                 $this->_templates[$name] = $html;
 
 501             $this->_templates[$element] = $html;
 
 503     } // end func setElementTemplate
 
 505 } // end class HTML_QuickForm_Renderer_Default