Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • Button
  • Checkbox
  • ConventionalRenderer
  • FileUpload
  • Form
  • FormContainer
  • FormControl
  • FormGroup
  • HiddenField
  • ImageButton
  • InstantClientScript
  • MultiSelectBox
  • RadioList
  • Rule
  • Rules
  • SelectBox
  • SubmitButton
  • TextArea
  • TextBase
  • TextInput

Interfaces

  • IFormControl
  • IFormRenderer
  • INamingContainer
  • ISubmitterControl
  • Overview
  • Namespace
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Forms;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18: /**
 19:  * Instant validation JavaScript generator.
 20:  *
 21:  * @author     David Grudl
 22:  */
 23: final class InstantClientScript extends Nette\Object
 24: {
 25:     /** @var array */
 26:     private $validateScripts;
 27: 
 28:     /** @var string */
 29:     private $toggleScript;
 30: 
 31:     /** @var bool */
 32:     private $central;
 33: 
 34:     /** @var Form */
 35:     private $form;
 36: 
 37: 
 38: 
 39:     public function __construct(Form $form)
 40:     {
 41:         $this->form = $form;
 42:     }
 43: 
 44: 
 45: 
 46:     public function enable()
 47:     {
 48:         $this->validateScripts = array();
 49:         $this->toggleScript = '';
 50:         $this->central = TRUE;
 51: 
 52:         foreach ($this->form->getControls() as $control) {
 53:             $script = $this->getValidateScript($control->getRules());
 54:             if ($script) {
 55:                 $this->validateScripts[$control->getHtmlName()] = $script;
 56:             }
 57:             $this->toggleScript .= $this->getToggleScript($control->getRules());
 58: 
 59:             if ($control instanceof ISubmitterControl && $control->getValidationScope() !== TRUE) {
 60:                 $this->central = FALSE;
 61:             }
 62:         }
 63: 
 64:         if ($this->validateScripts || $this->toggleScript) {
 65:             if ($this->central) {
 66:                 $this->form->getElementPrototype()->onsubmit("return nette.validateForm(this)", TRUE);
 67: 
 68:             } else {
 69:                 foreach ($this->form->getComponents(TRUE, 'Nette\Forms\ISubmitterControl') as $control) {
 70:                     if ($control->getValidationScope()) {
 71:                         $control->getControlPrototype()->onclick("return nette.validateForm(this)", TRUE);
 72:                     }
 73:                 }
 74:             }
 75:         }
 76:     }
 77: 
 78: 
 79: 
 80:     /**
 81:      * Generates the client side validation script.
 82:      * @return string
 83:      */
 84:     public function renderClientScript()
 85:     {
 86:         if (!$this->validateScripts && !$this->toggleScript) {
 87:             return;
 88:         }
 89: 
 90:         $formName = json_encode((string) $this->form->getElementPrototype()->id);
 91:         ob_start();
 92:         require __DIR__ . '/InstantClientScript.phtml';
 93:         return ob_get_clean();
 94:     }
 95: 
 96: 
 97: 
 98:     private function getValidateScript(Rules $rules)
 99:     {
100:         $res = '';
101:         foreach ($rules as $rule) {
102:             if (!is_string($rule->operation)) continue;
103: 
104:             if (strcasecmp($rule->operation, 'Nette\\Forms\\InstantClientScript::javascript') === 0) {
105:                 $res .= "$rule->arg\n";
106:                 continue;
107:             }
108: 
109:             $script = $this->getClientScript($rule->control, $rule->operation, $rule->arg);
110:             if (!$script) continue;
111: 
112:             if ($rule->type === Rule::VALIDATOR && !empty($rule->message)) {
113:                 $message = Rules::formatMessage($rule, FALSE);
114:                 $res .= "$script\n"
115:                     . "if (" . ($rule->isNegative ? '' : '!') . "res) "
116:                     . "return " . json_encode((string) $message) . (strpos($message, '%value') === FALSE ? '' : ".replace('%value', val);\n") . ";\n";
117: 
118:             } elseif ($rule->type === Rule::CONDITION) {
119:                 $innerScript = $this->getValidateScript($rule->subRules);
120:                 if ($innerScript) {
121:                     $res .= "$script\nif (" . ($rule->isNegative ? '!' : '') . "res) {\n" . Nette\String::indent($innerScript) . "}\n";
122:                     if ($rule->control instanceof ISubmitterControl) {
123:                         $this->central = FALSE;
124:                     }
125:                 }
126:             }
127:         }
128:         return $res;
129:     }
130: 
131: 
132: 
133:     private function getToggleScript(Rules $rules, $cond = NULL)
134:     {
135:         $s = '';
136:         foreach ($rules->getToggles() as $id => $visible) {
137:             $s .= "visible = true; {$cond}\n"
138:                 . "nette.toggle(" . json_encode((string) $id) . ", " . ($visible ? '' : '!') . "visible);\n";
139:         }
140:         $formName = json_encode((string) $this->form->getElementPrototype()->id);
141:         foreach ($rules as $rule) {
142:             if ($rule->type === Rule::CONDITION && is_string($rule->operation)) {
143:                 $script = $this->getClientScript($rule->control, $rule->operation, $rule->arg);
144:                 if ($script) {
145:                     $res = $this->getToggleScript($rule->subRules, $cond . "$script visible = visible && " . ($rule->isNegative ? '!' : '') . "res;\n");
146:                     if ($res) {
147:                         $el = $rule->control->getControlPrototype();
148:                         if ($el->getName() === 'select') {
149:                             $el->onchange("nette.forms[$formName].toggle(this)", TRUE);
150:                         } else {
151:                             $el->onclick("nette.forms[$formName].toggle(this)", TRUE);
152:                             //$el->onkeyup("nette.forms[$formName].toggle(this)", TRUE);
153:                         }
154:                         $s .= $res;
155:                     }
156:                 }
157:             }
158:         }
159:         return $s;
160:     }
161: 
162: 
163: 
164:     private function getClientScript(IFormControl $control, $operation, $arg)
165:     {
166:         $operation = strtolower($operation);
167:         $elem = 'form[' . json_encode($control->getHtmlName()) . ']';
168: 
169:         switch (TRUE) {
170:         case $control instanceof HiddenField || $control->isDisabled():
171:             return NULL;
172: 
173:         case $operation === ':filled' && $control instanceof RadioList:
174:             return "res = (val = nette.getValue($elem)) !== null;";
175: 
176:         case $operation === ':submitted' && $control instanceof SubmitButton:
177:             return "res = sender && sender.name==" . json_encode($control->getHtmlName()) . ";";
178: 
179:         case $operation === ':equal' && $control instanceof MultiSelectBox:
180:             $tmp = array();
181:             foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
182:                 $tmp[] = "options[i].value==" . json_encode((string) $item);
183:             }
184:             $first = $control->isFirstSkipped() ? 1 : 0;
185:             return "var options = $elem.options; res = false;\n"
186:                 . "for (var i=$first, len=options.length; i<len; i++)\n\t"
187:                 . "if (options[i].selected && (" . implode(' || ', $tmp) . ")) { res = true; break; }";
188: 
189:         case $operation === ':filled' && $control instanceof SelectBox:
190:             return "res = $elem.selectedIndex >= " . ($control->isFirstSkipped() ? 1 : 0) . ";";
191: 
192:         case $operation === ':filled' && $control instanceof TextBase:
193:             return "val = nette.getValue($elem); res = val!='' && val!=" . json_encode((string) $control->getEmptyValue()) . ";";
194: 
195:         case $operation === ':minlength' && $control instanceof TextBase:
196:             return "res = (val = nette.getValue($elem)).length>=" . (int) $arg . ";";
197: 
198:         case $operation === ':maxlength' && $control instanceof TextBase:
199:             return "res = (val = nette.getValue($elem)).length<=" . (int) $arg . ";";
200: 
201:         case $operation === ':length' && $control instanceof TextBase:
202:             if (!is_array($arg)) {
203:                 $arg = array($arg, $arg);
204:             }
205:             return "val = nette.getValue($elem); res = " . ($arg[0] === NULL ? "true" : "val.length>=" . (int) $arg[0]) . " && "
206:                 . ($arg[1] === NULL ? "true" : "val.length<=" . (int) $arg[1]) . ";";
207: 
208:         case $operation === ':email' && $control instanceof TextBase:
209:             return 'res = /^[^@\s]+@[^@\s]+\.[a-z]{2,10}$/i.test(val = nette.getValue('.$elem.'));';
210: 
211:         case $operation === ':url' && $control instanceof TextBase:
212:             return 'res = /^.+\.[a-z]{2,6}(\\/.*)?$/i.test(val = nette.getValue('.$elem.'));';
213: 
214:         case $operation === ':regexp' && $control instanceof TextBase:
215:             if (!preg_match('#^(/.*/)([imu]*)$#', $arg, $matches)) {
216:                 return NULL; // regular expression must be JavaScript compatible
217:             }
218:             $arg = $matches[1] . str_replace('u', '', $matches[2]);
219:             return "res = $arg.test(val = nette.getValue($elem));";
220: 
221:         case $operation === ':integer' && $control instanceof TextBase:
222:             return "res = /^-?[0-9]+$/.test(val = nette.getValue($elem));";
223: 
224:         case $operation === ':float' && $control instanceof TextBase:
225:             return "res = /^-?[0-9]*[.,]?[0-9]+$/.test(val = nette.getValue($elem));";
226: 
227:         case $operation === ':range' && $control instanceof TextBase:
228:             return "val = nette.getValue($elem); res = " . ($arg[0] === NULL ? "true" : "parseFloat(val)>=" . json_encode((float) $arg[0])) . " && "
229:                 . ($arg[1] === NULL ? "true" : "parseFloat(val)<=" . json_encode((float) $arg[1])) . ";";
230: 
231:         case $operation === ':filled' && $control instanceof FormControl:
232:             return "res = (val = nette.getValue($elem)) != '';";
233: 
234:         case $operation === ':valid' && $control instanceof FormControl:
235:             return "res = !this[" . json_encode($control->getHtmlName()) . "](sender);";
236: 
237:         case $operation === ':equal' && $control instanceof FormControl:
238:             if ($control instanceof Checkbox) $arg = (bool) $arg;
239:             $tmp = array();
240:             foreach ((is_array($arg) ? $arg : array($arg)) as $item) {
241:                 if ($item instanceof IFormControl) { // compare with another form control?
242:                     $tmp[] = "val==nette.getValue(form[" . json_encode($item->getHtmlName()) . "])";
243:                 } else {
244:                     $tmp[] = "val==" . json_encode($item);
245:                 }
246:             }
247:             return "val = nette.getValue($elem); res = (" . implode(' || ', $tmp) . ");";
248:         }
249:     }
250: 
251: 
252: 
253:     public static function javascript()
254:     {
255:         return TRUE;
256:     }
257: 
258: }
259: 
Nette Framework 0.9.7 API documentation generated by ApiGen 2.3.0