Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 401 and 402] [Versions 401 and 403]

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