3 * DHTML replacement for the standard JavaScript alert window for client-side
8 * Copyright (c) 2005-2007, Mark Wiesemann <wiesemann@php.net>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * * Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * * The names of the authors may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
24 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
31 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 * @package HTML_QuickForm_DHTMLRulesTableless
37 * @author Alexey Borzov <borz_off@cs.msu.su>
38 * @author Adam Daniel <adaniel1@eesus.jnj.com>
39 * @author Bertrand Mansion <bmansion@mamasam.com>
40 * @author Justin Patrin <papercrane@gmail.com>
41 * @author Mark Wiesemann <wiesemann@php.net>
42 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
43 * @version CVS: $Id: PageDHTMLRulesTableless.php,v 1.3 2007/10/24 20:36:11 wiesemann Exp $
44 * @link http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
47 require_once 'HTML/QuickForm/Page.php';
50 * This is a DHTML replacement for the standard JavaScript alert window for
51 * client-side validation of forms built with HTML_QuickForm
54 * @package HTML_QuickForm_DHTMLRulesTableless
55 * @author Alexey Borzov <borz_off@cs.msu.su>
56 * @author Adam Daniel <adaniel1@eesus.jnj.com>
57 * @author Bertrand Mansion <bmansion@mamasam.com>
58 * @author Justin Patrin <papercrane@gmail.com>
59 * @author Mark Wiesemann <wiesemann@php.net>
60 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
61 * @version Release: 0.3.3
62 * @link http://pear.php.net/package/HTML_QuickForm_DHTMLRulesTableless
64 class HTML_QuickForm_PageDHTMLRulesTableless extends HTML_QuickForm_Page
71 function HTML_QuickForm_PageDHTMLRulesTableless($formName, $method = 'post',
72 $target = '', $attributes = null)
74 $this->HTML_QuickForm_Page($formName, $method, '', $target, $attributes);
77 // {{{ getValidationScript()
80 * Returns the client side validation script
82 * The code here was copied from HTML_QuickForm and slightly modified to run rules per-element
85 * @return string Javascript to perform validation, empty string if no 'client' rules were added
87 function getValidationScript()
89 if (empty($this->_rules) || empty($this->_attributes['onsubmit'])) {
93 include_once('HTML/QuickForm/RuleRegistry.php');
94 $registry =& HTML_QuickForm_RuleRegistry::singleton();
105 foreach ($this->_rules as $elementName => $rules) {
106 foreach ($rules as $rule) {
107 if ('client' == $rule['validation']) {
110 $dependent = isset($rule['dependent']) && is_array($rule['dependent']);
111 $rule['message'] = strtr($rule['message'], $js_escape);
113 if (isset($rule['group'])) {
114 $group =& $this->getElement($rule['group']);
115 // No JavaScript validation for frozen elements
116 if ($group->isFrozen()) {
119 $elements =& $group->getElements();
120 foreach (array_keys($elements) as $key) {
121 if ($elementName == $group->getElementName($key)) {
122 $element =& $elements[$key];
126 } elseif ($dependent) {
128 $element[] =& $this->getElement($elementName);
129 foreach ($rule['dependent'] as $idx => $elName) {
130 $element[] =& $this->getElement($elName);
133 $element =& $this->getElement($elementName);
135 // No JavaScript validation for frozen elements
136 if (is_object($element) && $element->isFrozen()) {
138 } elseif (is_array($element)) {
139 foreach (array_keys($element) as $key) {
140 if ($element[$key]->isFrozen()) {
146 $test[$elementName][] = $registry->getValidationScript($element, $elementName, $rule);
151 <script type="text/javascript"><!--//--><![CDATA[//><!--
152 qf_errorHandler = function(element, _qfMsg) {
153 div = element.parentNode;
154 var elementName = element.name.replace(/\[/, "_____");
155 var elementName = elementName.replace(/\]/, "_____");
156 if (_qfMsg != \'\') {
157 span = document.createElement("span");
158 span.className = "error";
159 _qfMsg = _qfMsg.substring(4);
160 span.appendChild(document.createTextNode(_qfMsg));
161 br = document.createElement("br");
163 var errorDiv = document.getElementById(elementName + \'_errorDiv\');
165 errorDiv = document.createElement("div");
166 errorDiv.id = elementName + \'_errorDiv\';
168 if ( div.firstChild.textContent == \'\'
169 || _qfMsg == div.firstChild.textContent
174 while (errorDiv.firstChild) {
175 errorDiv.removeChild(errorDiv.firstChild);
178 errorDiv.insertBefore(br, errorDiv.firstChild);
179 errorDiv.insertBefore(span, errorDiv.firstChild);
181 errorDivInserted = false;
182 for (var i = element.parentNode.childNodes.length - 1; i >= 0; i--) {
184 if (j >= 0 && element.parentNode.childNodes[j].nodeName == "DIV") {
185 element.parentNode.insertBefore(errorDiv, element.parentNode.childNodes[i]);
186 errorDivInserted = true;
190 if (!errorDivInserted) {
191 element.parentNode.insertBefore(errorDiv, element.parentNode.firstChild);
194 if (div.className.substr(div.className.length - 6, 6) != " error"
195 && div.className != "error") {
196 div.className += " error";
201 var errorDiv = document.getElementById(elementName + \'_errorDiv\');
203 errorDiv.parentNode.removeChild(errorDiv);
206 // do not remove the error style from the div tag if there is still an error
208 if (div.firstChild.innerHTML != "") {
212 if (div.className.substr(div.className.length - 6, 6) == " error") {
213 div.className = div.className.substr(0, div.className.length - 6);
214 } else if (div.className == "error") {
222 foreach ($test as $elementName => $jsArr) {
223 // remove group element part of the element name to avoid JS errors
224 $singleElementName = $elementName;
225 $shortNameForJS = str_replace(array('[', ']'), '__', $elementName);
226 $bracketPos = strpos($elementName, '[');
227 if ($bracketPos !== false) {
228 $singleElementName = substr($elementName, 0, $bracketPos);
229 $groupElementName = substr($elementName, $bracketPos + 1, -1);
231 if ($bracketPos === false || !$this->elementExists($singleElementName)) {
232 $groupElementName = $elementName;
233 $singleElementName = $elementName;
235 $id = str_replace('-', '_', $this->_attributes['id']);
237 validate_' . $id . '_' . $shortNameForJS . ' = function(element) {
239 var errFlag = new Array();
242 var frm = element.parentNode;
243 while (frm && frm.nodeName != "FORM") {
244 frm = frm.parentNode;
246 ' . join("\n", $jsArr) . '
247 return qf_errorHandler(element, _qfMsg);
251 $element =& $this->getElement($singleElementName);
252 $elementNameForJS = 'frm.elements[\'' . $elementName . '\']';
253 if ($element->getType() === 'group' && $singleElementName === $elementName) {
254 $elementNameForJS = 'document.getElementById(\'' . $element->_elements[0]->getAttribute('id') . '\')';
257 ret = validate_' . $id . '_' . $shortNameForJS . '('. $elementNameForJS . ') && ret;';
258 if ($element->getType() !== 'group') { // not a group
259 $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
260 $onBlur = $element->getAttribute('onBlur');
261 $onChange = $element->getAttribute('onChange');
262 $element->updateAttributes(array('onBlur' => $onBlur . $valFunc,
263 'onChange' => $onChange . $valFunc));
265 $elements =& $element->getElements();
266 for ($i = 0; $i < count($elements); $i++) {
267 // $groupElementName is a substring of attribute name of the element
268 if (strpos($elements[$i]->getAttribute('name'), $groupElementName) === 0) {
269 $valFunc = 'validate_' . $id . '_' . $shortNameForJS . '(this)';
270 $onBlur = $elements[$i]->getAttribute('onBlur');
271 $onChange = $elements[$i]->getAttribute('onChange');
272 $elements[$i]->updateAttributes(array('onBlur' => $onBlur . $valFunc,
273 'onChange' => $onChange . $valFunc));
279 validate_' . $id . ' = function (frm) {
284 //--><!]]></script>';
286 } // end func getValidationScript
291 $this->getValidationScript();
292 return parent::display();