1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Forms;
9:
10: use Nette;
11: use Nette\Utils\Html;
12: use Nette\Utils\Strings;
13:
14:
15: 16: 17:
18: class Helpers
19: {
20: use Nette\StaticClass;
21:
22: private static $unsafeNames = [
23: 'attributes', 'children', 'elements', 'focus', 'length', 'reset', 'style', 'submit', 'onsubmit', 'form',
24: 'presenter', 'action',
25: ];
26:
27:
28: 29: 30: 31: 32: 33: 34: 35:
36: public static function (array $data, $htmlName, $type)
37: {
38: $name = explode('[', str_replace(['[]', ']', '.'], ['', '', '_'], $htmlName));
39: $data = Nette\Utils\Arrays::get($data, $name, null);
40: $itype = $type & ~Form::DATA_KEYS;
41:
42: if (substr($htmlName, -2) === '[]') {
43: if (!is_array($data)) {
44: return [];
45: }
46: foreach ($data as $k => $v) {
47: $data[$k] = $v = static::sanitize($itype, $v);
48: if ($v === null) {
49: unset($data[$k]);
50: }
51: }
52: if ($type & Form::DATA_KEYS) {
53: return $data;
54: }
55: return array_values($data);
56: } else {
57: return static::sanitize($itype, $data);
58: }
59: }
60:
61:
62: private static function sanitize($type, $value)
63: {
64: if ($type === Form::DATA_TEXT) {
65: return is_scalar($value) ? Strings::normalizeNewLines($value) : null;
66:
67: } elseif ($type === Form::DATA_LINE) {
68: return is_scalar($value) ? Strings::trim(strtr((string) $value, "\r\n", ' ')) : null;
69:
70: } elseif ($type === Form::DATA_FILE) {
71: return $value instanceof Nette\Http\FileUpload ? $value : null;
72:
73: } else {
74: throw new Nette\InvalidArgumentException('Unknown data type');
75: }
76: }
77:
78:
79: 80: 81: 82:
83: public static function generateHtmlName($id)
84: {
85: $name = str_replace(Nette\ComponentModel\IComponent::NAME_SEPARATOR, '][', $id, $count);
86: if ($count) {
87: $name = substr_replace($name, '', strpos($name, ']'), 1) . ']';
88: }
89: if (is_numeric($name) || in_array($name, self::$unsafeNames, true)) {
90: $name = '_' . $name;
91: }
92: return $name;
93: }
94:
95:
96: 97: 98:
99: public static function exportRules(Rules $rules)
100: {
101: $payload = [];
102: foreach ($rules as $rule) {
103: if (!is_string($op = $rule->validator)) {
104: if (!Nette\Utils\Callback::isStatic($op)) {
105: continue;
106: }
107: $op = Nette\Utils\Callback::toString($op);
108: }
109: if ($rule->branch) {
110: $item = [
111: 'op' => ($rule->isNegative ? '~' : '') . $op,
112: 'rules' => static::exportRules($rule->branch),
113: 'control' => $rule->control->getHtmlName(),
114: ];
115: if ($rule->branch->getToggles()) {
116: $item['toggle'] = $rule->branch->getToggles();
117: } elseif (!$item['rules']) {
118: continue;
119: }
120: } else {
121: $item = ['op' => ($rule->isNegative ? '~' : '') . $op, 'msg' => Validator::formatMessage($rule, false)];
122: }
123:
124: if (is_array($rule->arg)) {
125: $item['arg'] = [];
126: foreach ($rule->arg as $key => $value) {
127: $item['arg'][$key] = $value instanceof IControl ? ['control' => $value->getHtmlName()] : $value;
128: }
129: } elseif ($rule->arg !== null) {
130: $item['arg'] = $rule->arg instanceof IControl ? ['control' => $rule->arg->getHtmlName()] : $rule->arg;
131: }
132:
133: $payload[] = $item;
134: }
135: if ($payload && $rules->isOptional()) {
136: array_unshift($payload, ['op' => 'optional']);
137: }
138: return $payload;
139: }
140:
141:
142: 143: 144:
145: public static function createInputList(array $items, array $inputAttrs = null, array $labelAttrs = null, $wrapper = null)
146: {
147: list($inputAttrs, $inputTag) = self::prepareAttrs($inputAttrs, 'input');
148: list($labelAttrs, $labelTag) = self::prepareAttrs($labelAttrs, 'label');
149: $res = '';
150: $input = Html::el();
151: $label = Html::el();
152: list($wrapper, $wrapperEnd) = $wrapper instanceof Html ? [$wrapper->startTag(), $wrapper->endTag()] : [(string) $wrapper, ''];
153:
154: foreach ($items as $value => $caption) {
155: foreach ($inputAttrs as $k => $v) {
156: $input->attrs[$k] = isset($v[$value]) ? $v[$value] : null;
157: }
158: foreach ($labelAttrs as $k => $v) {
159: $label->attrs[$k] = isset($v[$value]) ? $v[$value] : null;
160: }
161: $input->value = $value;
162: $res .= ($res === '' && $wrapperEnd === '' ? '' : $wrapper)
163: . $labelTag . $label->attributes() . '>'
164: . $inputTag . $input->attributes() . (Html::$xhtml ? ' />' : '>')
165: . ($caption instanceof Nette\Utils\IHtmlString ? $caption : htmlspecialchars($caption, ENT_NOQUOTES, 'UTF-8'))
166: . '</label>'
167: . $wrapperEnd;
168: }
169: return $res;
170: }
171:
172:
173: 174: 175:
176: public static function createSelectBox(array $items, array $optionAttrs = null, $selected = null)
177: {
178: if ($selected !== null) {
179: $optionAttrs['selected?'] = $selected;
180: }
181: list($optionAttrs, $optionTag) = self::prepareAttrs($optionAttrs, 'option');
182: $option = Html::el();
183: $res = $tmp = '';
184: foreach ($items as $group => $subitems) {
185: if (is_array($subitems)) {
186: $res .= Html::el('optgroup')->label($group)->startTag();
187: $tmp = '</optgroup>';
188: } else {
189: $subitems = [$group => $subitems];
190: }
191: foreach ($subitems as $value => $caption) {
192: $option->value = $value;
193: foreach ($optionAttrs as $k => $v) {
194: $option->attrs[$k] = isset($v[$value]) ? $v[$value] : null;
195: }
196: if ($caption instanceof Html) {
197: $caption = clone $caption;
198: $res .= $caption->setName('option')->addAttributes($option->attrs);
199: } else {
200: $res .= $optionTag . $option->attributes() . '>'
201: . htmlspecialchars((string) $caption, ENT_NOQUOTES, 'UTF-8')
202: . '</option>';
203: }
204: if ($selected === $value) {
205: unset($optionAttrs['selected'], $option->attrs['selected']);
206: }
207: }
208: $res .= $tmp;
209: $tmp = '';
210: }
211: return Html::el('select')->setHtml($res);
212: }
213:
214:
215: private static function prepareAttrs($attrs, $name)
216: {
217: $dynamic = [];
218: foreach ((array) $attrs as $k => $v) {
219: $p = str_split($k, strlen($k) - 1);
220: if ($p[1] === '?' || $p[1] === ':') {
221: unset($attrs[$k], $attrs[$p[0]]);
222: if ($p[1] === '?') {
223: $dynamic[$p[0]] = array_fill_keys((array) $v, true);
224: } elseif (is_array($v) && $v) {
225: $dynamic[$p[0]] = $v;
226: } else {
227: $attrs[$p[0]] = $v;
228: }
229: }
230: }
231: return [$dynamic, '<' . $name . Html::el(null, $attrs)->attributes()];
232: }
233: }
234: