HTMLDefinition.php 9.6 KB

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