PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/nette-dev/Forms/Renderers/InstantClientScript.php

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