| 1: | <?php | 
| 2: |  | 
| 3: | class HTMLPurifier_Printer_HTMLDefinition extends HTMLPurifier_Printer | 
| 4: | { | 
| 5: |  | 
| 6: |  | 
| 7: |  | 
| 8: |  | 
| 9: | protected $def; | 
| 10: |  | 
| 11: |  | 
| 12: |  | 
| 13: |  | 
| 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: |  | 
| 36: |  | 
| 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: |  | 
| 55: |  | 
| 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: |  | 
| 101: |  | 
| 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: |  | 
| 120: |  | 
| 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: |  | 
| 181: |  | 
| 182: |  | 
| 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: |  | 
| 258: |  | 
| 259: |  | 
| 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: |  | 
| 276: |  | 
| 277: |  | 
| 278: |  | 
| 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: |  | 
| 292: |  | 
| 293: |  | 
| 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 = <i>" . $this->getClass($obj, 'AttrDef_') . '</i>'; | 
| 304: | } | 
| 305: | return $this->listify($list); | 
| 306: | } | 
| 307: |  | 
| 308: |  | 
| 309: |  | 
| 310: |  | 
| 311: |  | 
| 312: |  | 
| 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: |  | 
| 325: |  |