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