Source for file InstantClientScript.php

Documentation is available at InstantClientScript.php

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