/ lib / htmlpurifier / Printer / HTMLDefinition.php
HTMLDefinition.php
  1  <?php
  2  
  3  class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer
  4  {
  5  
  6      /**
  7       * @type HTMLPurifier_HTMLDefinition, for easy access
  8       */
  9      protected $def;
 10  
 11      /**
 12       * @param HTMLPurifier_Config $config
 13       * @return string
 14       */
 15      public function render($config)
 16      {
 17          $ret = '';
 18          $this->config =& $config;
 19  
 20          $this->def = $config->getHTMLDefinition();
 21  
 22          $ret .= $this->start('div', array('class' => 'HTMLPurifier_Printer'));
 23  
 24          $ret .= $this->renderDoctype();
 25          $ret .= $this->renderEnvironment();
 26          $ret .= $this->renderContentSets();
 27          $ret .= $this->renderInfo();
 28  
 29          $ret .= $this->end('div');
 30  
 31          return $ret;
 32      }
 33  
 34      /**
 35       * Renders the Doctype table
 36       * @return string
 37       */
 38      protected function renderDoctype()
 39      {
 40          $doctype = $this->def->doctype;
 41          $ret = '';
 42          $ret .= $this->start('table');
 43          $ret .= $this->element('caption', 'Doctype');
 44          $ret .= $this->row('Name', $doctype->name);
 45          $ret .= $this->row('XML', $doctype->xml ? 'Yes' : 'No');
 46          $ret .= $this->row('Default Modules', implode($doctype->modules, ', '));
 47          $ret .= $this->row('Default Tidy Modules', implode($doctype->tidyModules, ', '));
 48          $ret .= $this->end('table');
 49          return $ret;
 50      }
 51  
 52  
 53      /**
 54       * Renders environment table, which is miscellaneous info
 55       * @return string
 56       */
 57      protected function renderEnvironment()
 58      {
 59          $def = $this->def;
 60  
 61          $ret = '';
 62  
 63          $ret .= $this->start('table');
 64          $ret .= $this->element('caption', 'Environment');
 65  
 66          $ret .= $this->row('Parent of fragment', $def->info_parent);
 67          $ret .= $this->renderChildren($def->info_parent_def->child);
 68          $ret .= $this->row('Block wrap name', $def->info_block_wrapper);
 69  
 70          $ret .= $this->start('tr');
 71          $ret .= $this->element('th', 'Global attributes');
 72          $ret .= $this->element('td', $this->listifyAttr($def->info_global_attr), null, 0);
 73          $ret .= $this->end('tr');
 74  
 75          $ret .= $this->start('tr');
 76          $ret .= $this->element('th', 'Tag transforms');
 77          $list = array();
 78          foreach ($def->info_tag_transform as $old => $new) {
 79              $new = $this->getClass($new, 'TagTransform_');
 80              $list[] = "<$old> with $new";
 81          }
 82          $ret .= $this->element('td', $this->listify($list));
 83          $ret .= $this->end('tr');
 84  
 85          $ret .= $this->start('tr');
 86          $ret .= $this->element('th', 'Pre-AttrTransform');
 87          $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_pre));
 88          $ret .= $this->end('tr');
 89  
 90          $ret .= $this->start('tr');
 91          $ret .= $this->element('th', 'Post-AttrTransform');
 92          $ret .= $this->element('td', $this->listifyObjectList($def->info_attr_transform_post));
 93          $ret .= $this->end('tr');
 94  
 95          $ret .= $this->end('table');
 96          return $ret;
 97      }
 98  
 99      /**
100       * Renders the Content Sets table
101       * @return string
102       */
103      protected function renderContentSets()
104      {
105          $ret = '';
106          $ret .= $this->start('table');
107          $ret .= $this->element('caption', 'Content Sets');
108          foreach ($this->def->info_content_sets as $name => $lookup) {
109              $ret .= $this->heavyHeader($name);
110              $ret .= $this->start('tr');
111              $ret .= $this->element('td', $this->listifyTagLookup($lookup));
112              $ret .= $this->end('tr');
113          }
114          $ret .= $this->end('table');
115          return $ret;
116      }
117  
118      /**
119       * Renders the Elements ($info) table
120       * @return string
121       */
122      protected function renderInfo()
123      {
124          $ret = '';
125          $ret .= $this->start('table');
126          $ret .= $this->element('caption', 'Elements ($info)');
127          ksort($this->def->info);
128          $ret .= $this->heavyHeader('Allowed tags', 2);
129          $ret .= $this->start('tr');
130          $ret .= $this->element('td', $this->listifyTagLookup($this->def->info), array('colspan' => 2));
131          $ret .= $this->end('tr');
132          foreach ($this->def->info as $name => $def) {
133              $ret .= $this->start('tr');
134              $ret .= $this->element('th', "<$name>", array('class' => 'heavy', 'colspan' => 2));
135              $ret .= $this->end('tr');
136              $ret .= $this->start('tr');
137              $ret .= $this->element('th', 'Inline content');
138              $ret .= $this->element('td', $def->descendants_are_inline ? 'Yes' : 'No');
139              $ret .= $this->end('tr');
140              if (!empty($def->excludes)) {
141                  $ret .= $this->start('tr');
142                  $ret .= $this->element('th', 'Excludes');
143                  $ret .= $this->element('td', $this->listifyTagLookup($def->excludes));
144                  $ret .= $this->end('tr');
145              }
146              if (!empty($def->attr_transform_pre)) {
147                  $ret .= $this->start('tr');
148                  $ret .= $this->element('th', 'Pre-AttrTransform');
149                  $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_pre));
150                  $ret .= $this->end('tr');
151              }
152              if (!empty($def->attr_transform_post)) {
153                  $ret .= $this->start('tr');
154                  $ret .= $this->element('th', 'Post-AttrTransform');
155                  $ret .= $this->element('td', $this->listifyObjectList($def->attr_transform_post));
156                  $ret .= $this->end('tr');
157              }
158              if (!empty($def->auto_close)) {
159                  $ret .= $this->start('tr');
160                  $ret .= $this->element('th', 'Auto closed by');
161                  $ret .= $this->element('td', $this->listifyTagLookup($def->auto_close));
162                  $ret .= $this->end('tr');
163              }
164              $ret .= $this->start('tr');
165              $ret .= $this->element('th', 'Allowed attributes');
166              $ret .= $this->element('td', $this->listifyAttr($def->attr), array(), 0);
167              $ret .= $this->end('tr');
168  
169              if (!empty($def->required_attr)) {
170                  $ret .= $this->row('Required attributes', $this->listify($def->required_attr));
171              }
172  
173              $ret .= $this->renderChildren($def->child);
174          }
175          $ret .= $this->end('table');
176          return $ret;
177      }
178  
179      /**
180       * Renders a row describing the allowed children of an element
181       * @param HTMLPurifier_ChildDef $def HTMLPurifier_ChildDef of pertinent element
182       * @return string
183       */
184      protected function renderChildren($def)
185      {
186          $context = new HTMLPurifier_Context();
187          $ret = '';
188          $ret .= $this->start('tr');
189          $elements = array();
190          $attr = array();
191          if (isset($def->elements)) {
192              if ($def->type == 'strictblockquote') {
193                  $def->validateChildren(array(), $this->config, $context);
194              }
195              $elements = $def->elements;
196          }
197          if ($def->type == 'chameleon') {
198              $attr['rowspan'] = 2;
199          } elseif ($def->type == 'empty') {
200              $elements = array();
201          } elseif ($def->type == 'table') {
202              $elements = array_flip(
203                  array(
204                      'col',
205                      'caption',
206                      'colgroup',
207                      'thead',
208                      'tfoot',
209                      'tbody',
210                      'tr'
211                  )
212              );
213          }
214          $ret .= $this->element('th', 'Allowed children', $attr);
215  
216          if ($def->type == 'chameleon') {
217  
218              $ret .= $this->element(
219                  'td',
220                  '<em>Block</em>: ' .
221                  $this->escape($this->listifyTagLookup($def->block->elements)),
222                  null,
223                  0
224              );
225              $ret .= $this->end('tr');
226              $ret .= $this->start('tr');
227              $ret .= $this->element(
228                  'td',
229                  '<em>Inline</em>: ' .
230                  $this->escape($this->listifyTagLookup($def->inline->elements)),
231                  null,
232                  0
233              );
234  
235          } elseif ($def->type == 'custom') {
236  
237              $ret .= $this->element(
238                  'td',
239                  '<em>' . ucfirst($def->type) . '</em>: ' .
240                  $def->dtd_regex
241              );
242  
243          } else {
244              $ret .= $this->element(
245                  'td',
246                  '<em>' . ucfirst($def->type) . '</em>: ' .
247                  $this->escape($this->listifyTagLookup($elements)),
248                  null,
249                  0
250              );
251          }
252          $ret .= $this->end('tr');
253          return $ret;
254      }
255  
256      /**
257       * Listifies a tag lookup table.
258       * @param array $array Tag lookup array in form of array('tagname' => true)
259       * @return string
260       */
261      protected function listifyTagLookup($array)
262      {
263          ksort($array);
264          $list = array();
265          foreach ($array as $name => $discard) {
266              if ($name !== '#PCDATA' && !isset($this->def->info[$name])) {
267                  continue;
268              }
269              $list[] = $name;
270          }
271          return $this->listify($list);
272      }
273  
274      /**
275       * Listifies a list of objects by retrieving class names and internal state
276       * @param array $array List of objects
277       * @return string
278       * @todo Also add information about internal state
279       */
280      protected function listifyObjectList($array)
281      {
282          ksort($array);
283          $list = array();
284          foreach ($array as $obj) {
285              $list[] = $this->getClass($obj, 'AttrTransform_');
286          }
287          return $this->listify($list);
288      }
289  
290      /**
291       * Listifies a hash of attributes to AttrDef classes
292       * @param array $array Array hash in form of array('attrname' => HTMLPurifier_AttrDef)
293       * @return string
294       */
295      protected function listifyAttr($array)
296      {
297          ksort($array);
298          $list = array();
299          foreach ($array as $name => $obj) {
300              if ($obj === false) {
301                  continue;
302              }
303              $list[] = "$name&nbsp;=&nbsp;<i>" . $this->getClass($obj, 'AttrDef_') . '</i>';
304          }
305          return $this->listify($list);
306      }
307  
308      /**
309       * Creates a heavy header row
310       * @param string $text
311       * @param int $num
312       * @return string
313       */
314      protected function heavyHeader($text, $num = 1)
315      {
316          $ret = '';
317          $ret .= $this->start('tr');
318          $ret .= $this->element('th', $text, array('colspan' => $num, 'class' => 'heavy'));
319          $ret .= $this->end('tr');
320          return $ret;
321      }
322  }
323  
324  // vim: et sw=4 sts=4