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