File indexing completed on 2024-12-22 05:36:20
0001 <?php 0002 0003 /** 0004 * @todo Rewrite to use Interchange objects 0005 */ 0006 class HTMLPurifier_Printer_ConfigForm extends HTMLPurifier_Printer 0007 { 0008 0009 /** 0010 * Printers for specific fields. 0011 * @type HTMLPurifier_Printer[] 0012 */ 0013 protected $fields = array(); 0014 0015 /** 0016 * Documentation URL, can have fragment tagged on end. 0017 * @type string 0018 */ 0019 protected $docURL; 0020 0021 /** 0022 * Name of form element to stuff config in. 0023 * @type string 0024 */ 0025 protected $name; 0026 0027 /** 0028 * Whether or not to compress directive names, clipping them off 0029 * after a certain amount of letters. False to disable or integer letters 0030 * before clipping. 0031 * @type bool 0032 */ 0033 protected $compress = false; 0034 0035 /** 0036 * @param string $name Form element name for directives to be stuffed into 0037 * @param string $doc_url String documentation URL, will have fragment tagged on 0038 * @param bool $compress Integer max length before compressing a directive name, set to false to turn off 0039 */ 0040 public function __construct( 0041 $name, 0042 $doc_url = null, 0043 $compress = false 0044 ) { 0045 parent::__construct(); 0046 $this->docURL = $doc_url; 0047 $this->name = $name; 0048 $this->compress = $compress; 0049 // initialize sub-printers 0050 $this->fields[0] = new HTMLPurifier_Printer_ConfigForm_default(); 0051 $this->fields[HTMLPurifier_VarParser::BOOL] = new HTMLPurifier_Printer_ConfigForm_bool(); 0052 } 0053 0054 /** 0055 * Sets default column and row size for textareas in sub-printers 0056 * @param $cols Integer columns of textarea, null to use default 0057 * @param $rows Integer rows of textarea, null to use default 0058 */ 0059 public function setTextareaDimensions($cols = null, $rows = null) 0060 { 0061 if ($cols) { 0062 $this->fields['default']->cols = $cols; 0063 } 0064 if ($rows) { 0065 $this->fields['default']->rows = $rows; 0066 } 0067 } 0068 0069 /** 0070 * Retrieves styling, in case it is not accessible by webserver 0071 */ 0072 public static function getCSS() 0073 { 0074 return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.css'); 0075 } 0076 0077 /** 0078 * Retrieves JavaScript, in case it is not accessible by webserver 0079 */ 0080 public static function getJavaScript() 0081 { 0082 return file_get_contents(HTMLPURIFIER_PREFIX . '/HTMLPurifier/Printer/ConfigForm.js'); 0083 } 0084 0085 /** 0086 * Returns HTML output for a configuration form 0087 * @param HTMLPurifier_Config|array $config Configuration object of current form state, or an array 0088 * where [0] has an HTML namespace and [1] is being rendered. 0089 * @param array|bool $allowed Optional namespace(s) and directives to restrict form to. 0090 * @param bool $render_controls 0091 * @return string 0092 */ 0093 public function render($config, $allowed = true, $render_controls = true) 0094 { 0095 if (is_array($config) && isset($config[0])) { 0096 $gen_config = $config[0]; 0097 $config = $config[1]; 0098 } else { 0099 $gen_config = $config; 0100 } 0101 0102 $this->config = $config; 0103 $this->genConfig = $gen_config; 0104 $this->prepareGenerator($gen_config); 0105 0106 $allowed = HTMLPurifier_Config::getAllowedDirectivesForForm($allowed, $config->def); 0107 $all = array(); 0108 foreach ($allowed as $key) { 0109 list($ns, $directive) = $key; 0110 $all[$ns][$directive] = $config->get($ns . '.' . $directive); 0111 } 0112 0113 $ret = ''; 0114 $ret .= $this->start('table', array('class' => 'hp-config')); 0115 $ret .= $this->start('thead'); 0116 $ret .= $this->start('tr'); 0117 $ret .= $this->element('th', 'Directive', array('class' => 'hp-directive')); 0118 $ret .= $this->element('th', 'Value', array('class' => 'hp-value')); 0119 $ret .= $this->end('tr'); 0120 $ret .= $this->end('thead'); 0121 foreach ($all as $ns => $directives) { 0122 $ret .= $this->renderNamespace($ns, $directives); 0123 } 0124 if ($render_controls) { 0125 $ret .= $this->start('tbody'); 0126 $ret .= $this->start('tr'); 0127 $ret .= $this->start('td', array('colspan' => 2, 'class' => 'controls')); 0128 $ret .= $this->elementEmpty('input', array('type' => 'submit', 'value' => 'Submit')); 0129 $ret .= '[<a href="?">Reset</a>]'; 0130 $ret .= $this->end('td'); 0131 $ret .= $this->end('tr'); 0132 $ret .= $this->end('tbody'); 0133 } 0134 $ret .= $this->end('table'); 0135 return $ret; 0136 } 0137 0138 /** 0139 * Renders a single namespace 0140 * @param $ns String namespace name 0141 * @param array $directives array of directives to values 0142 * @return string 0143 */ 0144 protected function renderNamespace($ns, $directives) 0145 { 0146 $ret = ''; 0147 $ret .= $this->start('tbody', array('class' => 'namespace')); 0148 $ret .= $this->start('tr'); 0149 $ret .= $this->element('th', $ns, array('colspan' => 2)); 0150 $ret .= $this->end('tr'); 0151 $ret .= $this->end('tbody'); 0152 $ret .= $this->start('tbody'); 0153 foreach ($directives as $directive => $value) { 0154 $ret .= $this->start('tr'); 0155 $ret .= $this->start('th'); 0156 if ($this->docURL) { 0157 $url = str_replace('%s', urlencode("$ns.$directive"), $this->docURL); 0158 $ret .= $this->start('a', array('href' => $url)); 0159 } 0160 $attr = array('for' => "{$this->name}:$ns.$directive"); 0161 0162 // crop directive name if it's too long 0163 if (!$this->compress || (strlen($directive) < $this->compress)) { 0164 $directive_disp = $directive; 0165 } else { 0166 $directive_disp = substr($directive, 0, $this->compress - 2) . '...'; 0167 $attr['title'] = $directive; 0168 } 0169 0170 $ret .= $this->element( 0171 'label', 0172 $directive_disp, 0173 // component printers must create an element with this id 0174 $attr 0175 ); 0176 if ($this->docURL) { 0177 $ret .= $this->end('a'); 0178 } 0179 $ret .= $this->end('th'); 0180 0181 $ret .= $this->start('td'); 0182 $def = $this->config->def->info["$ns.$directive"]; 0183 if (is_int($def)) { 0184 $allow_null = $def < 0; 0185 $type = abs($def); 0186 } else { 0187 $type = $def->type; 0188 $allow_null = isset($def->allow_null); 0189 } 0190 if (!isset($this->fields[$type])) { 0191 $type = 0; 0192 } // default 0193 $type_obj = $this->fields[$type]; 0194 if ($allow_null) { 0195 $type_obj = new HTMLPurifier_Printer_ConfigForm_NullDecorator($type_obj); 0196 } 0197 $ret .= $type_obj->render($ns, $directive, $value, $this->name, array($this->genConfig, $this->config)); 0198 $ret .= $this->end('td'); 0199 $ret .= $this->end('tr'); 0200 } 0201 $ret .= $this->end('tbody'); 0202 return $ret; 0203 } 0204 0205 } 0206 0207 /** 0208 * Printer decorator for directives that accept null 0209 */ 0210 class HTMLPurifier_Printer_ConfigForm_NullDecorator extends HTMLPurifier_Printer 0211 { 0212 /** 0213 * Printer being decorated 0214 * @type HTMLPurifier_Printer 0215 */ 0216 protected $obj; 0217 0218 /** 0219 * @param HTMLPurifier_Printer $obj Printer to decorate 0220 */ 0221 public function __construct($obj) 0222 { 0223 parent::__construct(); 0224 $this->obj = $obj; 0225 } 0226 0227 /** 0228 * @param string $ns 0229 * @param string $directive 0230 * @param string $value 0231 * @param string $name 0232 * @param HTMLPurifier_Config|array $config 0233 * @return string 0234 */ 0235 public function render($ns, $directive, $value, $name, $config) 0236 { 0237 if (is_array($config) && isset($config[0])) { 0238 $gen_config = $config[0]; 0239 $config = $config[1]; 0240 } else { 0241 $gen_config = $config; 0242 } 0243 $this->prepareGenerator($gen_config); 0244 0245 $ret = ''; 0246 $ret .= $this->start('label', array('for' => "$name:Null_$ns.$directive")); 0247 $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); 0248 $ret .= $this->text(' Null/Disabled'); 0249 $ret .= $this->end('label'); 0250 $attr = array( 0251 'type' => 'checkbox', 0252 'value' => '1', 0253 'class' => 'null-toggle', 0254 'name' => "$name" . "[Null_$ns.$directive]", 0255 'id' => "$name:Null_$ns.$directive", 0256 'onclick' => "toggleWriteability('$name:$ns.$directive',checked)" // INLINE JAVASCRIPT!!!! 0257 ); 0258 if ($this->obj instanceof HTMLPurifier_Printer_ConfigForm_bool) { 0259 // modify inline javascript slightly 0260 $attr['onclick'] = 0261 "toggleWriteability('$name:Yes_$ns.$directive',checked);" . 0262 "toggleWriteability('$name:No_$ns.$directive',checked)"; 0263 } 0264 if ($value === null) { 0265 $attr['checked'] = 'checked'; 0266 } 0267 $ret .= $this->elementEmpty('input', $attr); 0268 $ret .= $this->text(' or '); 0269 $ret .= $this->elementEmpty('br'); 0270 $ret .= $this->obj->render($ns, $directive, $value, $name, array($gen_config, $config)); 0271 return $ret; 0272 } 0273 } 0274 0275 /** 0276 * Swiss-army knife configuration form field printer 0277 */ 0278 class HTMLPurifier_Printer_ConfigForm_default extends HTMLPurifier_Printer 0279 { 0280 /** 0281 * @type int 0282 */ 0283 public $cols = 18; 0284 0285 /** 0286 * @type int 0287 */ 0288 public $rows = 5; 0289 0290 /** 0291 * @param string $ns 0292 * @param string $directive 0293 * @param string $value 0294 * @param string $name 0295 * @param HTMLPurifier_Config|array $config 0296 * @return string 0297 */ 0298 public function render($ns, $directive, $value, $name, $config) 0299 { 0300 if (is_array($config) && isset($config[0])) { 0301 $gen_config = $config[0]; 0302 $config = $config[1]; 0303 } else { 0304 $gen_config = $config; 0305 } 0306 $this->prepareGenerator($gen_config); 0307 // this should probably be split up a little 0308 $ret = ''; 0309 $def = $config->def->info["$ns.$directive"]; 0310 if (is_int($def)) { 0311 $type = abs($def); 0312 } else { 0313 $type = $def->type; 0314 } 0315 if (is_array($value)) { 0316 switch ($type) { 0317 case HTMLPurifier_VarParser::LOOKUP: 0318 $array = $value; 0319 $value = array(); 0320 foreach ($array as $val => $b) { 0321 $value[] = $val; 0322 } 0323 //TODO does this need a break? 0324 case HTMLPurifier_VarParser::ALIST: 0325 $value = implode(PHP_EOL, $value); 0326 break; 0327 case HTMLPurifier_VarParser::HASH: 0328 $nvalue = ''; 0329 foreach ($value as $i => $v) { 0330 if (is_array($v)) { 0331 // HACK 0332 $v = implode(";", $v); 0333 } 0334 $nvalue .= "$i:$v" . PHP_EOL; 0335 } 0336 $value = $nvalue; 0337 break; 0338 default: 0339 $value = ''; 0340 } 0341 } 0342 if ($type === HTMLPurifier_VarParser::MIXED) { 0343 return 'Not supported'; 0344 $value = serialize($value); 0345 } 0346 $attr = array( 0347 'name' => "$name" . "[$ns.$directive]", 0348 'id' => "$name:$ns.$directive" 0349 ); 0350 if ($value === null) { 0351 $attr['disabled'] = 'disabled'; 0352 } 0353 if (isset($def->allowed)) { 0354 $ret .= $this->start('select', $attr); 0355 foreach ($def->allowed as $val => $b) { 0356 $attr = array(); 0357 if ($value == $val) { 0358 $attr['selected'] = 'selected'; 0359 } 0360 $ret .= $this->element('option', $val, $attr); 0361 } 0362 $ret .= $this->end('select'); 0363 } elseif ($type === HTMLPurifier_VarParser::TEXT || 0364 $type === HTMLPurifier_VarParser::ITEXT || 0365 $type === HTMLPurifier_VarParser::ALIST || 0366 $type === HTMLPurifier_VarParser::HASH || 0367 $type === HTMLPurifier_VarParser::LOOKUP) { 0368 $attr['cols'] = $this->cols; 0369 $attr['rows'] = $this->rows; 0370 $ret .= $this->start('textarea', $attr); 0371 $ret .= $this->text($value); 0372 $ret .= $this->end('textarea'); 0373 } else { 0374 $attr['value'] = $value; 0375 $attr['type'] = 'text'; 0376 $ret .= $this->elementEmpty('input', $attr); 0377 } 0378 return $ret; 0379 } 0380 } 0381 0382 /** 0383 * Bool form field printer 0384 */ 0385 class HTMLPurifier_Printer_ConfigForm_bool extends HTMLPurifier_Printer 0386 { 0387 /** 0388 * @param string $ns 0389 * @param string $directive 0390 * @param string $value 0391 * @param string $name 0392 * @param HTMLPurifier_Config|array $config 0393 * @return string 0394 */ 0395 public function render($ns, $directive, $value, $name, $config) 0396 { 0397 if (is_array($config) && isset($config[0])) { 0398 $gen_config = $config[0]; 0399 $config = $config[1]; 0400 } else { 0401 $gen_config = $config; 0402 } 0403 $this->prepareGenerator($gen_config); 0404 $ret = ''; 0405 $ret .= $this->start('div', array('id' => "$name:$ns.$directive")); 0406 0407 $ret .= $this->start('label', array('for' => "$name:Yes_$ns.$directive")); 0408 $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); 0409 $ret .= $this->text(' Yes'); 0410 $ret .= $this->end('label'); 0411 0412 $attr = array( 0413 'type' => 'radio', 0414 'name' => "$name" . "[$ns.$directive]", 0415 'id' => "$name:Yes_$ns.$directive", 0416 'value' => '1' 0417 ); 0418 if ($value === true) { 0419 $attr['checked'] = 'checked'; 0420 } 0421 if ($value === null) { 0422 $attr['disabled'] = 'disabled'; 0423 } 0424 $ret .= $this->elementEmpty('input', $attr); 0425 0426 $ret .= $this->start('label', array('for' => "$name:No_$ns.$directive")); 0427 $ret .= $this->element('span', "$ns.$directive:", array('class' => 'verbose')); 0428 $ret .= $this->text(' No'); 0429 $ret .= $this->end('label'); 0430 0431 $attr = array( 0432 'type' => 'radio', 0433 'name' => "$name" . "[$ns.$directive]", 0434 'id' => "$name:No_$ns.$directive", 0435 'value' => '0' 0436 ); 0437 if ($value === false) { 0438 $attr['checked'] = 'checked'; 0439 } 0440 if ($value === null) { 0441 $attr['disabled'] = 'disabled'; 0442 } 0443 $ret .= $this->elementEmpty('input', $attr); 0444 0445 $ret .= $this->end('div'); 0446 0447 return $ret; 0448 } 0449 } 0450 0451 // vim: et sw=4 sts=4