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