]>
Commit | Line | Data |
---|---|---|
d4949327 NL |
1 | <?php\r |
2 | \r | |
3 | /**\r | |
4 | * @todo Rewrite to use Interchange objects\r | |
5 | */\r | |
6 | class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer\r | |
7 | {\r | |
8 | \r | |
9 | /**\r | |
10 | * Printers for specific fields.\r | |
11 | * @type HTMLPurifier_Printer[]\r | |
12 | */\r | |
13 | protected $fields = array();\r | |
14 | \r | |
15 | /**\r | |
16 | * Documentation URL, can have fragment tagged on end.\r | |
17 | * @type string\r | |
18 | */\r | |
19 | protected $docURL;\r | |
20 | \r | |
21 | /**\r | |
22 | * Name of form element to stuff config in.\r | |
23 | * @type string\r | |
24 | */\r | |
25 | protected $name;\r | |
26 | \r | |
27 | /**\r | |
28 | * Whether or not to compress directive names, clipping them off\r | |
29 | * after a certain amount of letters. False to disable or integer letters\r | |
30 | * before clipping.\r | |
31 | * @type bool\r | |
32 | */\r | |
33 | protected $compress = false;\r | |
34 | \r | |
35 | /**\r | |
36 | * @param string $name Form element name for directives to be stuffed into\r | |
37 | * @param string $doc_url String documentation URL, will have fragment tagged on\r | |
38 | * @param bool $compress Integer max length before compressing a directive name, set to false to turn off\r | |
39 | */\r | |
40 | public function __construct(\r | |
41 | $name,\r | |
42 | $doc_url = null,\r | |
43 | $compress = false\r | |
44 | ) {\r | |
45 | parent::__construct();\r | |
46 | $this->docURL = $doc_url;\r | |
47 | $this->name = $name;\r | |
48 | $this->compress = $compress;\r | |
49 | // initialize sub-printers\r | |
50 | $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default();\r | |
51 | $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool();\r | |
52 | }\r | |
53 | \r | |
54 | /**\r | |
55 | * Sets default column and row size for textareas in sub-printers\r | |
56 | * @param $cols Integer columns of textarea, null to use default\r | |
57 | * @param $rows Integer rows of textarea, null to use default\r | |
58 | */\r | |
59 | public function setTextareaDimensions($cols = null, $rows = null)\r | |
60 | {\r | |
61 | if ($cols) {\r | |
62 | $this->fields['default']->cols = $cols;\r | |
63 | }\r | |
64 | if ($rows) {\r | |
65 | $this->fields['default']->rows = $rows;\r | |
66 | }\r | |
67 | }\r | |
68 | \r | |
69 | /**\r | |
70 | * Retrieves styling, in case it is not accessible by webserver\r | |
71 | */\r | |
72 | public static function getCSS()\r | |
73 | {\r | |
74 | return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css');\r | |
75 | }\r | |
76 | \r | |
77 | /**\r | |
78 | * Retrieves JavaScript, in case it is not accessible by webserver\r | |
79 | */\r | |
80 | public static function getJavaScript()\r | |
81 | {\r | |
82 | return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js');\r | |
83 | }\r | |
84 | \r | |
85 | /**\r | |
86 | * Returns HTML output for a configuration form\r | |
87 | * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array\r | |
88 | * where [0] has an HTML namespace and [1] is being rendered.\r | |
89 | * @param array|bool $allowed Optional namespace(s) and directives to restrict form to.\r | |
90 | * @param bool $render_controls\r | |
91 | * @return string\r | |
92 | */\r | |
93 | public function render($config, $allowed = true, $render_controls = true)\r | |
94 | {\r | |
95 | if (is_array($config) && isset($config[0])) {\r | |
96 | $gen_config = $config[0];\r | |
97 | $config = $config[1];\r | |
98 | } else {\r | |
99 | $gen_config = $config;\r | |
100 | }\r | |
101 | \r | |
102 | $this->config = $config;\r | |
103 | $this->genConfig = $gen_config;\r | |
104 | $this->prepareGenerator($gen_config);\r | |
105 | \r | |
106 | $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def);\r | |
107 | $all = array();\r | |
108 | foreach ($allowed as $key) {\r | |
109 | list($ns, $directive) = $key;\r | |
110 | $all[$ns][$directive] = $config->get($ns . '.' . $directive);\r | |
111 | }\r | |
112 | \r | |
113 | $ret = '';\r | |
114 | $ret .= $this->start('table', array('class' => 'hp-config'));\r | |
115 | $ret .= $this->start('thead');\r | |
116 | $ret .= $this->start('tr');\r | |
117 | $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive'));\r | |
118 | $ret .= $this->element('th', 'Value', array('class' => 'hp-value'));\r | |
119 | $ret .= $this->end('tr');\r | |
120 | $ret .= $this->end('thead');\r | |
121 | foreach ($all as $ns => $directives) {\r | |
122 | $ret .= $this->renderNamespace($ns, $directives);\r | |
123 | }\r | |
124 | if ($render_controls) {\r | |
125 | $ret .= $this->start('tbody');\r | |
126 | $ret .= $this->start('tr');\r | |
127 | $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls'));\r | |
128 | $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit'));\r | |
129 | $ret .= '[<a href="?">Reset</a>]';\r | |
130 | $ret .= $this->end('td');\r | |
131 | $ret .= $this->end('tr');\r | |
132 | $ret .= $this->end('tbody');\r | |
133 | }\r | |
134 | $ret .= $this->end('table');\r | |
135 | return $ret;\r | |
136 | }\r | |
137 | \r | |
138 | /**\r | |
139 | * Renders a single namespace\r | |
140 | * @param $ns String namespace name\r | |
141 | * @param array $directives array of directives to values\r | |
142 | * @return string\r | |
143 | */\r | |
144 | protected function renderNamespace($ns, $directives)\r | |
145 | {\r | |
146 | $ret = '';\r | |
147 | $ret .= $this->start('tbody', array('class' => 'namespace'));\r | |
148 | $ret .= $this->start('tr');\r | |
149 | $ret .= $this->element('th', $ns, array('colspan' => 2));\r | |
150 | $ret .= $this->end('tr');\r | |
151 | $ret .= $this->end('tbody');\r | |
152 | $ret .= $this->start('tbody');\r | |
153 | foreach ($directives as $directive => $value) {\r | |
154 | $ret .= $this->start('tr');\r | |
155 | $ret .= $this->start('th');\r | |
156 | if ($this->docURL) {\r | |
157 | $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL);\r | |
158 | $ret .= $this->start('a', array('href' => $url));\r | |
159 | }\r | |
160 | $attr = array('for' => "{$this->name}:$ns.$directive");\r | |
161 | \r | |
162 | // crop directive name if it's too long\r | |
163 | if (!$this->compress || (strlen($directive) < $this->compress)) {\r | |
164 | $directive_disp = $directive;\r | |
165 | } else {\r | |
166 | $directive_disp = substr($directive, 0, $this->compress - 2) . '...';\r | |
167 | $attr['title'] = $directive;\r | |
168 | }\r | |
169 | \r | |
170 | $ret .= $this->element(\r | |
171 | 'label',\r | |
172 | $directive_disp,\r | |
173 | // component printers must create an element with this id\r | |
174 | $attr\r | |
175 | );\r | |
176 | if ($this->docURL) {\r | |
177 | $ret .= $this->end('a');\r | |
178 | }\r | |
179 | $ret .= $this->end('th');\r | |
180 | \r | |
181 | $ret .= $this->start('td');\r | |
182 | $def = $this->config->def->info["$ns.$directive"];\r | |
183 | if (is_int($def)) {\r | |
184 | $allow_null = $def < 0;\r | |
185 | $type = abs($def);\r | |
186 | } else {\r | |
187 | $type = $def->type;\r | |
188 | $allow_null = isset($def->allow_null);\r | |
189 | }\r | |
190 | if (!isset($this->fields[$type])) {\r | |
191 | $type = 0;\r | |
192 | } // default\r | |
193 | $type_obj = $this->fields[$type];\r | |
194 | if ($allow_null) {\r | |
195 | $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj);\r | |
196 | }\r | |
197 | $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config));\r | |
198 | $ret .= $this->end('td');\r | |
199 | $ret .= $this->end('tr');\r | |
200 | }\r | |
201 | $ret .= $this->end('tbody');\r | |
202 | return $ret;\r | |
203 | }\r | |
204 | \r | |
205 | }\r | |
206 | \r | |
207 | /**\r | |
208 | * Printer decorator for directives that accept null\r | |
209 | */\r | |
210 | class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer\r | |
211 | {\r | |
212 | /**\r | |
213 | * Printer being decorated\r | |
214 | * @type HTMLPurifier_Printer\r | |
215 | */\r | |
216 | protected $obj;\r | |
217 | \r | |
218 | /**\r | |
219 | * @param HTMLPurifier_Printer $obj Printer to decorate\r | |
220 | */\r | |
221 | public function __construct($obj)\r | |
222 | {\r | |
223 | parent::__construct();\r | |
224 | $this->obj = $obj;\r | |
225 | }\r | |
226 | \r | |
227 | /**\r | |
228 | * @param string $ns\r | |
229 | * @param string $directive\r | |
230 | * @param string $value\r | |
231 | * @param string $name\r | |
232 | * @param HTMLPurifier_Config|array $config\r | |
233 | * @return string\r | |
234 | */\r | |
235 | public function render($ns, $directive, $value, $name, $config)\r | |
236 | {\r | |
237 | if (is_array($config) && isset($config[0])) {\r | |
238 | $gen_config = $config[0];\r | |
239 | $config = $config[1];\r | |
240 | } else {\r | |
241 | $gen_config = $config;\r | |
242 | }\r | |
243 | $this->prepareGenerator($gen_config);\r | |
244 | \r | |
245 | $ret = '';\r | |
246 | $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive"));\r | |
247 | $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose'));\r | |
248 | $ret .= $this->text(' Null/Disabled');\r | |
249 | $ret .= $this->end('label');\r | |
250 | $attr = array(\r | |
251 | 'type' => 'checkbox',\r | |
252 | 'value' => '1',\r | |
253 | 'class' => 'null-toggle',\r | |
254 | 'name' => "$name" . "[Null_$ns.$directive]",\r | |
255 | 'id' => "$name:Null_$ns.$directive",\r | |
256 | 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!!\r | |
257 | );\r | |
258 | if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) {\r | |
259 | // modify inline javascript slightly\r | |
260 | $attr['onclick'] =\r | |
261 | "toggleWriteability('$name:Yes_$ns.$directive',checked);" .\r | |
262 | "toggleWriteability('$name:No_$ns.$directive',checked)";\r | |
263 | }\r | |
264 | if ($value === null) {\r | |
265 | $attr['checked'] = 'checked';\r | |
266 | }\r | |
267 | $ret .= $this->elementEmpty('input', $attr);\r | |
268 | $ret .= $this->text(' or ');\r | |
269 | $ret .= $this->elementEmpty('br');\r | |
270 | $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config));\r | |
271 | return $ret;\r | |
272 | }\r | |
273 | }\r | |
274 | \r | |
275 | /**\r | |
276 | * Swiss-army knife configuration form field printer\r | |
277 | */\r | |
278 | class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer\r | |
279 | {\r | |
280 | /**\r | |
281 | * @type int\r | |
282 | */\r | |
283 | public $cols = 18;\r | |
284 | \r | |
285 | /**\r | |
286 | * @type int\r | |
287 | */\r | |
288 | public $rows = 5;\r | |
289 | \r | |
290 | /**\r | |
291 | * @param string $ns\r | |
292 | * @param string $directive\r | |
293 | * @param string $value\r | |
294 | * @param string $name\r | |
295 | * @param HTMLPurifier_Config|array $config\r | |
296 | * @return string\r | |
297 | */\r | |
298 | public function render($ns, $directive, $value, $name, $config)\r | |
299 | {\r | |
300 | if (is_array($config) && isset($config[0])) {\r | |
301 | $gen_config = $config[0];\r | |
302 | $config = $config[1];\r | |
303 | } else {\r | |
304 | $gen_config = $config;\r | |
305 | }\r | |
306 | $this->prepareGenerator($gen_config);\r | |
307 | // this should probably be split up a little\r | |
308 | $ret = '';\r | |
309 | $def = $config->def->info["$ns.$directive"];\r | |
310 | if (is_int($def)) {\r | |
311 | $type = abs($def);\r | |
312 | } else {\r | |
313 | $type = $def->type;\r | |
314 | }\r | |
315 | if (is_array($value)) {\r | |
316 | switch ($type) {\r | |
317 | case HTMLPurifier_VarParser::LOOKUP:\r | |
318 | $array = $value;\r | |
319 | $value = array();\r | |
320 | foreach ($array as $val => $b) {\r | |
321 | $value[] = $val;\r | |
322 | }\r | |
323 | //TODO does this need a break?\r | |
324 | case HTMLPurifier_VarParser::ALIST:\r | |
325 | $value = implode(PHP_EOL, $value);\r | |
326 | break;\r | |
327 | case HTMLPurifier_VarParser::HASH:\r | |
328 | $nvalue = '';\r | |
329 | foreach ($value as $i => $v) {\r | |
330 | $nvalue .= "$i:$v" . PHP_EOL;\r | |
331 | }\r | |
332 | $value = $nvalue;\r | |
333 | break;\r | |
334 | default:\r | |
335 | $value = '';\r | |
336 | }\r | |
337 | }\r | |
338 | if ($type === HTMLPurifier_VarParser::MIXED) {\r | |
339 | return 'Not supported';\r | |
340 | $value = serialize($value);\r | |
341 | }\r | |
342 | $attr = array(\r | |
343 | 'name' => "$name" . "[$ns.$directive]",\r | |
344 | 'id' => "$name:$ns.$directive"\r | |
345 | );\r | |
346 | if ($value === null) {\r | |
347 | $attr['disabled'] = 'disabled';\r | |
348 | }\r | |
349 | if (isset($def->allowed)) {\r | |
350 | $ret .= $this->start('select', $attr);\r | |
351 | foreach ($def->allowed as $val => $b) {\r | |
352 | $attr = array();\r | |
353 | if ($value == $val) {\r | |
354 | $attr['selected'] = 'selected';\r | |
355 | }\r | |
356 | $ret .= $this->element('option', $val, $attr);\r | |
357 | }\r | |
358 | $ret .= $this->end('select');\r | |
359 | } elseif ($type === HTMLPurifier_VarParser::TEXT ||\r | |
360 | $type === HTMLPurifier_VarParser::ITEXT ||\r | |
361 | $type === HTMLPurifier_VarParser::ALIST ||\r | |
362 | $type === HTMLPurifier_VarParser::HASH ||\r | |
363 | $type === HTMLPurifier_VarParser::LOOKUP) {\r | |
364 | $attr['cols'] = $this->cols;\r | |
365 | $attr['rows'] = $this->rows;\r | |
366 | $ret .= $this->start('textarea', $attr);\r | |
367 | $ret .= $this->text($value);\r | |
368 | $ret .= $this->end('textarea');\r | |
369 | } else {\r | |
370 | $attr['value'] = $value;\r | |
371 | $attr['type'] = 'text';\r | |
372 | $ret .= $this->elementEmpty('input', $attr);\r | |
373 | }\r | |
374 | return $ret;\r | |
375 | }\r | |
376 | }\r | |
377 | \r | |
378 | /**\r | |
379 | * Bool form field printer\r | |
380 | */\r | |
381 | class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer\r | |
382 | {\r | |
383 | /**\r | |
384 | * @param string $ns\r | |
385 | * @param string $directive\r | |
386 | * @param string $value\r | |
387 | * @param string $name\r | |
388 | * @param HTMLPurifier_Config|array $config\r | |
389 | * @return string\r | |
390 | */\r | |
391 | public function render($ns, $directive, $value, $name, $config)\r | |
392 | {\r | |
393 | if (is_array($config) && isset($config[0])) {\r | |
394 | $gen_config = $config[0];\r | |
395 | $config = $config[1];\r | |
396 | } else {\r | |
397 | $gen_config = $config;\r | |
398 | }\r | |
399 | $this->prepareGenerator($gen_config);\r | |
400 | $ret = '';\r | |
401 | $ret .= $this->start('div', array('id' => "$name:$ns.$directive"));\r | |
402 | \r | |
403 | $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive"));\r | |
404 | $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose'));\r | |
405 | $ret .= $this->text(' Yes');\r | |
406 | $ret .= $this->end('label');\r | |
407 | \r | |
408 | $attr = array(\r | |
409 | 'type' => 'radio',\r | |
410 | 'name' => "$name" . "[$ns.$directive]",\r | |
411 | 'id' => "$name:Yes_$ns.$directive",\r | |
412 | 'value' => '1'\r | |
413 | );\r | |
414 | if ($value === true) {\r | |
415 | $attr['checked'] = 'checked';\r | |
416 | }\r | |
417 | if ($value === null) {\r | |
418 | $attr['disabled'] = 'disabled';\r | |
419 | }\r | |
420 | $ret .= $this->elementEmpty('input', $attr);\r | |
421 | \r | |
422 | $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive"));\r | |
423 | $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose'));\r | |
424 | $ret .= $this->text(' No');\r | |
425 | $ret .= $this->end('label');\r | |
426 | \r | |
427 | $attr = array(\r | |
428 | 'type' => 'radio',\r | |
429 | 'name' => "$name" . "[$ns.$directive]",\r | |
430 | 'id' => "$name:No_$ns.$directive",\r | |
431 | 'value' => '0'\r | |
432 | );\r | |
433 | if ($value === false) {\r | |
434 | $attr['checked'] = 'checked';\r | |
435 | }\r | |
436 | if ($value === null) {\r | |
437 | $attr['disabled'] = 'disabled';\r | |
438 | }\r | |
439 | $ret .= $this->elementEmpty('input', $attr);\r | |
440 | \r | |
441 | $ret .= $this->end('div');\r | |
442 | \r | |
443 | return $ret;\r | |
444 | }\r | |
445 | }\r | |
446 | \r | |
447 | // vim: et sw=4 sts=4\r |