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