Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?php/*** Definition for tables. The general idea is to extract out all of the* essential bits, and then reconstruct it later.** This is a bit confusing, because the DTDs and the W3C* validators seem to disagree on the appropriate definition. The* DTD claims:** (CAPTION?, (COL*|COLGROUP*), THEAD?, TFOOT?, TBODY+)** But actually, the HTML4 spec then has this to say:** The TBODY start tag is always required except when the table* contains only one table body and no table head or foot sections.* The TBODY end tag may always be safely omitted.** So the DTD is kind of wrong. The validator is, unfortunately, kind* of on crack.** The definition changed again in XHTML1.1; and in my opinion, this* formulation makes the most sense.** caption?, ( col* | colgroup* ), (( thead?, tfoot?, tbody+ ) | ( tr+ ))** Essentially, we have two modes: thead/tfoot/tbody mode, and tr mode.* If we encounter a thead, tfoot or tbody, we are placed in the former* mode, and we *must* wrap any stray tr segments with a tbody. But if* we don't run into any of them, just have tr tags is OK.*/class HTMLPurifier_ChildDef_Table extends HTMLPurifier_ChildDef{/*** @type bool*/public $allow_empty = false;/*** @type string*/public $type = 'table';/*** @type array*/public $elements = array('tr' => true,'tbody' => true,'thead' => true,'tfoot' => true,'caption' => true,'colgroup' => true,'col' => true);public function __construct(){}/*** @param array $children* @param HTMLPurifier_Config $config* @param HTMLPurifier_Context $context* @return array*/public function validateChildren($children, $config, $context){if (empty($children)) {return false;}// only one of these elements is allowed in a table$caption = false;$thead = false;$tfoot = false;// whitespace$initial_ws = array();$after_caption_ws = array();$after_thead_ws = array();$after_tfoot_ws = array();// as many of these as you want$cols = array();$content = array();$tbody_mode = false; // if true, then we need to wrap any stray// <tr>s with a <tbody>.$ws_accum =& $initial_ws;foreach ($children as $node) {if ($node instanceof HTMLPurifier_Node_Comment) {$ws_accum[] = $node;continue;}switch ($node->name) {case 'tbody':$tbody_mode = true;// fall throughcase 'tr':$content[] = $node;$ws_accum =& $content;break;case 'caption':// there can only be one caption!if ($caption !== false) break;$caption = $node;$ws_accum =& $after_caption_ws;break;case 'thead':$tbody_mode = true;// XXX This breaks rendering properties with// Firefox, which never floats a <thead> to// the top. Ever. (Our scheme will float the// first <thead> to the top.) So maybe// <thead>s that are not first should be// turned into <tbody>? Very tricky, indeed.if ($thead === false) {$thead = $node;$ws_accum =& $after_thead_ws;} else {// Oops, there's a second one! What// should we do? Current behavior is to// transmutate the first and last entries into// tbody tags, and then put into content.// Maybe a better idea is to *attach// it* to the existing thead or tfoot?// We don't do this, because Firefox// doesn't float an extra tfoot to the// bottom like it does for the first one.$node->name = 'tbody';$content[] = $node;$ws_accum =& $content;}break;case 'tfoot':// see above for some aveats$tbody_mode = true;if ($tfoot === false) {$tfoot = $node;$ws_accum =& $after_tfoot_ws;} else {$node->name = 'tbody';$content[] = $node;$ws_accum =& $content;}break;case 'colgroup':case 'col':$cols[] = $node;$ws_accum =& $cols;break;case '#PCDATA':// How is whitespace handled? We treat is as sticky to// the *end* of the previous element. So all of the// nonsense we have worked on is to keep things// together.if (!empty($node->is_whitespace)) {$ws_accum[] = $node;}break;}}if (empty($content) && $thead === false && $tfoot === false) {return false;}$ret = $initial_ws;if ($caption !== false) {$ret[] = $caption;$ret = array_merge($ret, $after_caption_ws);}if ($cols !== false) {$ret = array_merge($ret, $cols);}if ($thead !== false) {$ret[] = $thead;$ret = array_merge($ret, $after_thead_ws);}if ($tfoot !== false) {$ret[] = $tfoot;$ret = array_merge($ret, $after_tfoot_ws);}if ($tbody_mode) {// we have to shuffle tr into tbody$current_tr_tbody = null;foreach($content as $node) {switch ($node->name) {case 'tbody':$current_tr_tbody = null;$ret[] = $node;break;case 'tr':if ($current_tr_tbody === null) {$current_tr_tbody = new HTMLPurifier_Node_Element('tbody');$ret[] = $current_tr_tbody;}$current_tr_tbody->children[] = $node;break;case '#PCDATA'://assert($node->is_whitespace);if ($current_tr_tbody === null) {$ret[] = $node;} else {$current_tr_tbody->children[] = $node;}break;}}} else {$ret = array_merge($ret, $content);}return $ret;}}// vim: et sw=4 sts=4