diff --git a/library/HTMLPurifier/ElementDef.php b/library/HTMLPurifier/ElementDef.php index 30c80cd4..eb6ff271 100644 --- a/library/HTMLPurifier/ElementDef.php +++ b/library/HTMLPurifier/ElementDef.php @@ -93,7 +93,7 @@ class HTMLPurifier_ElementDef var $safe = false; /** - * Factory constructor for creating new standalone element defs + * Low-level factory constructor for creating new standalone element defs * @static */ function create($safe, $content_model, $content_model_type, $attr) { diff --git a/library/HTMLPurifier/HTMLModule.php b/library/HTMLPurifier/HTMLModule.php index a4d4af73..c6de7670 100644 --- a/library/HTMLPurifier/HTMLModule.php +++ b/library/HTMLPurifier/HTMLModule.php @@ -151,6 +151,8 @@ class HTMLPurifier_HTMLModule $this->info[$element] = HTMLPurifier_ElementDef::create( $safe, $content_model, $content_model_type, $attr ); + // literal object $contents means direct child manipulation + if (!is_string($contents)) $this->info[$element]->child = $contents; } /** @@ -171,8 +173,12 @@ class HTMLPurifier_HTMLModule * into separate content model and content model type * @param $contents Allowed children in form of: * "$content_model_type: $content_model" + * @note If contents is an object, an array of two nulls will be + * returned, and the callee needs to take the original $contents + * and use it directly. */ function parseContents($contents) { + if (!is_string($contents)) return array(null, null); // defer switch ($contents) { // check for shorthand content model forms case 'Empty': diff --git a/library/HTMLPurifier/HTMLModule/Tables.php b/library/HTMLPurifier/HTMLModule/Tables.php index 003ff624..732f6bcb 100644 --- a/library/HTMLPurifier/HTMLModule/Tables.php +++ b/library/HTMLPurifier/HTMLModule/Tables.php @@ -10,75 +10,66 @@ class HTMLPurifier_HTMLModule_Tables extends HTMLPurifier_HTMLModule { var $name = 'Tables'; - var $elements = array('caption', 'table', 'td', 'th', 'tr', 'col', - 'colgroup', 'tbody', 'thead', 'tfoot'); - var $content_sets = array('Block' => 'table'); function HTMLPurifier_HTMLModule_Tables() { - foreach ($this->elements as $e) { - $this->info[$e] = new HTMLPurifier_ElementDef(); - $this->info[$e]->attr = array(0 => array('Common')); - $attr =& $this->info[$e]->attr; - if ($e == 'caption') continue; - if ($e == 'table'){ - $attr['border'] = 'Pixels'; - $attr['cellpadding'] = 'Length'; - $attr['cellspacing'] = 'Length'; - $attr['frame'] = new HTMLPurifier_AttrDef_Enum(array( + + $this->addElement('table', true, 'Block', + new HTMLPurifier_ChildDef_Table(), 'Common', + array( + 'border' => 'Pixels', + 'cellpadding' => 'Length', + 'cellspacing' => 'Length', + 'frame' => new HTMLPurifier_AttrDef_Enum(array( 'void', 'above', 'below', 'hsides', 'lhs', 'rhs', 'vsides', 'box', 'border' - ), false); - $attr['rules'] = new HTMLPurifier_AttrDef_Enum(array( + ), false), + 'rules' => new HTMLPurifier_AttrDef_Enum(array( 'none', 'groups', 'rows', 'cols', 'all' - ), false); - $attr['summary'] = 'Text'; - $attr['width'] = 'Length'; - continue; - } - if ($e == 'col' || $e == 'colgroup') { - $attr['span'] = 'Number'; - $attr['width'] = 'MultiLength'; - } - if ($e == 'td' || $e == 'th') { - $attr['abbr'] = 'Text'; - $attr['colspan'] = 'Number'; - $attr['rowspan'] = 'Number'; - } - $attr['align'] = new HTMLPurifier_AttrDef_Enum(array( + ), false), + 'summary' => 'Text', + 'width' => 'Length' + ) + ); + + $this->addElement('caption', true, false, 'Inline', 'Common'); + + // common attributes + $cell_align = array( + 'align' => new HTMLPurifier_AttrDef_Enum(array( 'left', 'center', 'right', 'justify', 'char' - ), false); - $attr['valign'] = new HTMLPurifier_AttrDef_Enum(array( + ), false), + 'valign' => new HTMLPurifier_AttrDef_Enum(array( 'top', 'middle', 'bottom', 'baseline' - ), false); - $attr['charoff'] = 'Length'; - } - $this->info['caption']->content_model = '#PCDATA | Inline'; - $this->info['caption']->content_model_type = 'optional'; + ), false), + 'charoff' => 'Length', + ); - // Is done directly because it doesn't leverage substitution - // mechanisms. True model is: - // 'caption?, ( col* | colgroup* ), (( thead?, tfoot?, tbody+ ) | ( tr+ ))' - $this->info['table']->child = new HTMLPurifier_ChildDef_Table(); + $cell_t = array_merge( + array( + 'abbr' => 'Text', + 'colspan' => 'Number', + 'rowspan' => 'Number', + ), + $cell_align + ); + $this->addElement('td', true, false, 'Flow', 'Common', $cell_t); + $this->addElement('th', true, false, 'Flow', 'Common', $cell_t); - $this->info['td']->content_model = - $this->info['th']->content_model = '#PCDATA | Flow'; - $this->info['td']->content_model_type = - $this->info['th']->content_model_type = 'optional'; + $this->addElement('tr', true, false, 'Required: td | th', 'Common', $cell_align); - $this->info['tr']->content_model = 'td | th'; - $this->info['tr']->content_model_type = 'required'; + $cell_col = array_merge( + array( + 'span' => 'Number', + 'width' => 'MultiLength', + ), + $cell_align + ); + $this->addElement('col', true, false, 'Empty', 'Common', $cell_col); + $this->addElement('colgroup', true, false, 'Optional: col', 'Common', $cell_col); - $this->info['col']->content_model_type = 'empty'; - - $this->info['colgroup']->content_model = 'col'; - $this->info['colgroup']->content_model_type = 'optional'; - - $this->info['tbody']->content_model = - $this->info['thead']->content_model = - $this->info['tfoot']->content_model = 'tr'; - $this->info['tbody']->content_model_type = - $this->info['thead']->content_model_type = - $this->info['tfoot']->content_model_type = 'required'; + $this->addElement('tbody', true, false, 'Required: tr', 'Common', $cell_align); + $this->addElement('thead', true, false, 'Required: tr', 'Common', $cell_align); + $this->addElement('tfoot', true, false, 'Required: tr', 'Common', $cell_align); } diff --git a/tests/HTMLPurifier/HTMLModuleTest.php b/tests/HTMLPurifier/HTMLModuleTest.php index 7f584a48..3803a715 100644 --- a/tests/HTMLPurifier/HTMLModuleTest.php +++ b/tests/HTMLPurifier/HTMLModuleTest.php @@ -83,6 +83,13 @@ class HTMLPurifier_HTMLModuleTest extends UnitTestCase array('optional', 'a | b | c') ); + // object pass-through + generate_mock_once('HTMLPurifier_AttrDef'); + $this->assertIdentical( + $module->parseContents(new HTMLPurifier_AttrDefMock()), + array(null, null) + ); + } function test_mergeInAttrIncludes() {