| 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: | |