mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-08-03 12:47:56 +02:00
Release 2.0.0, merged in 1026 to HEAD.
git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/branches/strict@1179 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
@@ -11,30 +11,22 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Bdo';
|
||||
var $elements = array('bdo');
|
||||
var $content_sets = array('Inline' => 'bdo');
|
||||
var $attr_collections = array(
|
||||
'I18N' => array('dir' => false)
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_Bdo() {
|
||||
$dir = new HTMLPurifier_AttrDef_Enum(array('ltr','rtl'), false);
|
||||
$this->attr_collections['I18N']['dir'] = $dir;
|
||||
$this->info['bdo'] = new HTMLPurifier_ElementDef();
|
||||
$this->info['bdo']->attr = array(
|
||||
0 => array('Core', 'Lang'),
|
||||
'dir' => $dir, // required
|
||||
// The Abstract Module specification has the attribute
|
||||
// inclusions wrong for bdo: bdo allows
|
||||
// xml:lang too (and we'll toss in lang for good measure,
|
||||
// though it is not allowed for XHTML 1.1, this will
|
||||
// be managed with a global attribute transform)
|
||||
$bdo =& $this->addElement(
|
||||
'bdo', true, 'Inline', 'Inline', array('Core', 'Lang'),
|
||||
array(
|
||||
'dir' => 'Enum#ltr,rtl', // required
|
||||
// The Abstract Module specification has the attribute
|
||||
// inclusions wrong for bdo: bdo allows Lang
|
||||
)
|
||||
);
|
||||
$this->info['bdo']->content_model = '#PCDATA | Inline';
|
||||
$this->info['bdo']->content_model_type = 'optional';
|
||||
// provides fallback behavior if dir's missing (dir is required)
|
||||
$this->info['bdo']->attr_transform_post['required-dir'] =
|
||||
new HTMLPurifier_AttrTransform_BdoDir();
|
||||
$bdo->attr_transform_post['required-dir'] = new HTMLPurifier_AttrTransform_BdoDir();
|
||||
|
||||
$this->attr_collections['I18N']['dir'] = 'Enum#ltr,rtl';
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
var $name = 'CommonAttributes';
|
||||
@@ -12,9 +14,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
||||
'id' => 'ID',
|
||||
'title' => 'CDATA',
|
||||
),
|
||||
'Lang' => array(
|
||||
'xml:lang' => false, // see constructor
|
||||
),
|
||||
'Lang' => array(),
|
||||
'I18N' => array(
|
||||
0 => array('Lang'), // proprietary, for xml:lang/lang
|
||||
),
|
||||
@@ -22,10 +22,6 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
||||
0 => array('Core', 'I18N')
|
||||
)
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_CommonAttributes() {
|
||||
$this->attr_collections['Lang']['xml:lang'] = new HTMLPurifier_AttrDef_Lang();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@@ -11,28 +11,24 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Edit';
|
||||
var $elements = array('del', 'ins');
|
||||
var $content_sets = array('Inline' => 'del | ins');
|
||||
|
||||
function HTMLPurifier_HTMLModule_Edit() {
|
||||
foreach ($this->elements as $element) {
|
||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$element]->attr = array(
|
||||
0 => array('Common'),
|
||||
'cite' => 'URI',
|
||||
// 'datetime' => 'Datetime' // Datetime not implemented
|
||||
);
|
||||
// Inline context ! Block context (exclamation mark is
|
||||
// separator, see getChildDef for parsing)
|
||||
$this->info[$element]->content_model =
|
||||
'#PCDATA | Inline ! #PCDATA | Flow';
|
||||
// HTML 4.01 specifies that ins/del must not contain block
|
||||
// elements when used in an inline context, chameleon is
|
||||
// a complicated workaround to acheive this effect
|
||||
$this->info[$element]->content_model_type = 'chameleon';
|
||||
}
|
||||
$contents = 'Chameleon: #PCDATA | Inline ! #PCDATA | Flow';
|
||||
$attr = array(
|
||||
'cite' => 'URI',
|
||||
// 'datetime' => 'Datetime', // not implemented
|
||||
);
|
||||
$this->addElement('del', true, 'Inline', $contents, 'Common', $attr);
|
||||
$this->addElement('ins', true, 'Inline', $contents, 'Common', $attr);
|
||||
}
|
||||
|
||||
// HTML 4.01 specifies that ins/del must not contain block
|
||||
// elements when used in an inline context, chameleon is
|
||||
// a complicated workaround to acheive this effect
|
||||
|
||||
// Inline context ! Block context (exclamation mark is
|
||||
// separator, see getChildDef for parsing)
|
||||
|
||||
var $defines_child_def = true;
|
||||
function getChildDef($def) {
|
||||
if ($def->content_model_type != 'chameleon') return false;
|
||||
|
@@ -10,25 +10,22 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Hypertext';
|
||||
var $elements = array('a');
|
||||
var $content_sets = array('Inline' => 'a');
|
||||
|
||||
function HTMLPurifier_HTMLModule_Hypertext() {
|
||||
$this->info['a'] = new HTMLPurifier_ElementDef();
|
||||
$this->info['a']->attr = array(
|
||||
0 => array('Common'),
|
||||
// 'accesskey' => 'Character',
|
||||
// 'charset' => 'Charset',
|
||||
'href' => 'URI',
|
||||
//'hreflang' => 'LanguageCode',
|
||||
'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'),
|
||||
'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'),
|
||||
//'tabindex' => 'Number',
|
||||
//'type' => 'ContentType',
|
||||
$a =& $this->addElement(
|
||||
'a', true, 'Inline', 'Inline', 'Common',
|
||||
array(
|
||||
// 'accesskey' => 'Character',
|
||||
// 'charset' => 'Charset',
|
||||
'href' => 'URI',
|
||||
// 'hreflang' => 'LanguageCode',
|
||||
'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'),
|
||||
'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'),
|
||||
// 'tabindex' => 'Number',
|
||||
// 'type' => 'ContentType',
|
||||
)
|
||||
);
|
||||
$this->info['a']->content_model = '#PCDATA | Inline';
|
||||
$this->info['a']->content_model_type = 'optional';
|
||||
$this->info['a']->excludes = array('a' => true);
|
||||
$a->excludes = array('a' => true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -14,21 +14,21 @@ class HTMLPurifier_HTMLModule_Image extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Image';
|
||||
var $elements = array('img');
|
||||
var $content_sets = array('Inline' => 'img');
|
||||
|
||||
function HTMLPurifier_HTMLModule_Image() {
|
||||
$this->info['img'] = new HTMLPurifier_ElementDef();
|
||||
$this->info['img']->attr = array(
|
||||
0 => array('Common'),
|
||||
'alt' => 'Text',
|
||||
'height' => 'Length',
|
||||
'longdesc' => 'URI',
|
||||
'src' => new HTMLPurifier_AttrDef_URI(true), // embedded
|
||||
'width' => 'Length'
|
||||
$img =& $this->addElement(
|
||||
'img', true, 'Inline', 'Empty', 'Common',
|
||||
array(
|
||||
'alt*' => 'Text',
|
||||
'height' => 'Length',
|
||||
'longdesc' => 'URI',
|
||||
'src*' => new HTMLPurifier_AttrDef_URI(true), // embedded
|
||||
'width' => 'Length'
|
||||
)
|
||||
);
|
||||
$this->info['img']->content_model_type = 'empty';
|
||||
$this->info['img']->attr_transform_post[] =
|
||||
// kind of strange, but splitting things up would be inefficient
|
||||
$img->attr_transform_pre[] =
|
||||
$img->attr_transform_post[] =
|
||||
new HTMLPurifier_AttrTransform_ImgRequired();
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrDef/HTML/Bool.php';
|
||||
|
||||
/**
|
||||
* XHTML 1.1 Legacy module defines elements that were previously
|
||||
* deprecated.
|
||||
@@ -22,36 +24,115 @@ class HTMLPurifier_HTMLModule_Legacy extends HTMLPurifier_HTMLModule
|
||||
// incomplete
|
||||
|
||||
var $name = 'Legacy';
|
||||
var $elements = array('u', 's', 'strike');
|
||||
var $non_standalone_elements = array('li', 'ol', 'address', 'blockquote');
|
||||
|
||||
function HTMLPurifier_HTMLModule_Legacy() {
|
||||
// setup new elements
|
||||
foreach ($this->elements as $name) {
|
||||
$this->info[$name] = new HTMLPurifier_ElementDef();
|
||||
// for u, s, strike, as more elements get added, add
|
||||
// conditionals as necessary
|
||||
$this->info[$name]->content_model = 'Inline | #PCDATA';
|
||||
$this->info[$name]->content_model_type = 'optional';
|
||||
$this->info[$name]->attr[0] = array('Common');
|
||||
}
|
||||
|
||||
$this->addElement('basefont', true, 'Inline', 'Empty', false, array(
|
||||
'color' => 'Color',
|
||||
'face' => 'Text', // extremely broad, we should
|
||||
'size' => 'Text', // tighten it
|
||||
'id' => 'ID'
|
||||
));
|
||||
$this->addElement('center', true, 'Block', 'Flow', 'Common');
|
||||
$this->addElement('dir', true, 'Block', 'Required: li', 'Common', array(
|
||||
'compact' => 'Bool#compact'
|
||||
));
|
||||
$this->addElement('font', true, 'Inline', 'Inline', array('Core', 'I18N'), array(
|
||||
'color' => 'Color',
|
||||
'face' => 'Text', // extremely broad, we should
|
||||
'size' => 'Text', // tighten it
|
||||
));
|
||||
$this->addElement('menu', true, 'Block', 'Required: li', 'Common', array(
|
||||
'compact' => 'Bool#compact'
|
||||
));
|
||||
$this->addElement('s', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('strike', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('u', true, 'Inline', 'Inline', 'Common');
|
||||
|
||||
// setup modifications to old elements
|
||||
foreach ($this->non_standalone_elements as $name) {
|
||||
$this->info[$name] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$name]->standalone = false;
|
||||
|
||||
$align = 'Enum#left,right,center,justify';
|
||||
|
||||
$address =& $this->addBlankElement('address');
|
||||
$address->content_model = 'Inline | #PCDATA | p';
|
||||
$address->content_model_type = 'optional';
|
||||
$address->child = false;
|
||||
|
||||
$blockquote =& $this->addBlankElement('blockquote');
|
||||
$blockquote->content_model = 'Flow | #PCDATA';
|
||||
$blockquote->content_model_type = 'optional';
|
||||
$blockquote->child = false;
|
||||
|
||||
$br =& $this->addBlankElement('br');
|
||||
$br->attr['clear'] = 'Enum#left,all,right,none';
|
||||
|
||||
$caption =& $this->addBlankElement('caption');
|
||||
$caption->attr['align'] = 'Enum#top,bottom,left,right';
|
||||
|
||||
$div =& $this->addBlankElement('div');
|
||||
$div->attr['align'] = $align;
|
||||
|
||||
$dl =& $this->addBlankElement('dl');
|
||||
$dl->attr['compact'] = 'Bool#compact';
|
||||
|
||||
for ($i = 1; $i <= 6; $i++) {
|
||||
$h =& $this->addBlankElement("h$i");
|
||||
$h->attr['align'] = $align;
|
||||
}
|
||||
|
||||
$this->info['li']->attr['value'] = new HTMLPurifier_AttrDef_Integer();
|
||||
$this->info['ol']->attr['start'] = new HTMLPurifier_AttrDef_Integer();
|
||||
$hr =& $this->addBlankElement('hr');
|
||||
$hr->attr['align'] = $align;
|
||||
$hr->attr['noshade'] = 'Bool#noshade';
|
||||
$hr->attr['size'] = 'Pixels';
|
||||
$hr->attr['width'] = 'Length';
|
||||
|
||||
$this->info['address']->content_model = 'Inline | #PCDATA | p';
|
||||
$this->info['address']->content_model_type = 'optional';
|
||||
$this->info['address']->child = false;
|
||||
$img =& $this->addBlankElement('img');
|
||||
$img->attr['align'] = 'Enum#top,middle,bottom,left,right';
|
||||
$img->attr['border'] = 'Pixels';
|
||||
$img->attr['hspace'] = 'Pixels';
|
||||
$img->attr['vspace'] = 'Pixels';
|
||||
|
||||
$this->info['blockquote']->content_model = 'Flow | #PCDATA';
|
||||
$this->info['blockquote']->content_model_type = 'optional';
|
||||
$this->info['blockquote']->child = false;
|
||||
// figure out this integer business
|
||||
|
||||
$li =& $this->addBlankElement('li');
|
||||
$li->attr['value'] = new HTMLPurifier_AttrDef_Integer();
|
||||
$li->attr['type'] = 'Enum#s:1,i,I,a,A,disc,square,circle';
|
||||
|
||||
$ol =& $this->addBlankElement('ol');
|
||||
$ol->attr['compact'] = 'Bool#compact';
|
||||
$ol->attr['start'] = new HTMLPurifier_AttrDef_Integer();
|
||||
$ol->attr['type'] = 'Enum#s:1,i,I,a,A';
|
||||
|
||||
$p =& $this->addBlankElement('p');
|
||||
$p->attr['align'] = $align;
|
||||
|
||||
$pre =& $this->addBlankElement('pre');
|
||||
$pre->attr['width'] = 'Number';
|
||||
|
||||
// script omitted
|
||||
|
||||
$table =& $this->addBlankElement('table');
|
||||
$table->attr['align'] = 'Enum#left,center,right';
|
||||
$table->attr['bgcolor'] = 'Color';
|
||||
|
||||
$tr =& $this->addBlankElement('tr');
|
||||
$tr->attr['bgcolor'] = 'Color';
|
||||
|
||||
$th =& $this->addBlankElement('th');
|
||||
$th->attr['bgcolor'] = 'Color';
|
||||
$th->attr['height'] = 'Length';
|
||||
$th->attr['nowrap'] = 'Bool#nowrap';
|
||||
$th->attr['width'] = 'Length';
|
||||
|
||||
$td =& $this->addBlankElement('td');
|
||||
$td->attr['bgcolor'] = 'Color';
|
||||
$td->attr['height'] = 'Length';
|
||||
$td->attr['nowrap'] = 'Bool#nowrap';
|
||||
$td->attr['width'] = 'Length';
|
||||
|
||||
$ul =& $this->addBlankElement('ul');
|
||||
$ul->attr['compact'] = 'Bool#compact';
|
||||
$ul->attr['type'] = 'Enum#square,disc,circle';
|
||||
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,6 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'List';
|
||||
var $elements = array('dl', 'dt', 'dd', 'ol', 'ul', 'li');
|
||||
|
||||
// According to the abstract schema, the List content set is a fully formed
|
||||
// one or more expr, but it invariably occurs in an optional declaration
|
||||
@@ -19,26 +18,19 @@ class HTMLPurifier_HTMLModule_List extends HTMLPurifier_HTMLModule
|
||||
// Furthermore, the actual XML Schema may disagree. Regardless,
|
||||
// we don't have support for such nested expressions without using
|
||||
// the incredibly inefficient and draconic Custom ChildDef.
|
||||
var $content_sets = array('List' => 'dl | ol | ul', 'Flow' => 'List');
|
||||
|
||||
var $content_sets = array('Flow' => 'List');
|
||||
|
||||
function HTMLPurifier_HTMLModule_List() {
|
||||
foreach ($this->elements as $element) {
|
||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$element]->attr = array(0 => array('Common'));
|
||||
if ($element == 'li' || $element == 'dd') {
|
||||
$this->info[$element]->content_model = '#PCDATA | Flow';
|
||||
$this->info[$element]->content_model_type = 'optional';
|
||||
} elseif ($element == 'ol' || $element == 'ul') {
|
||||
$this->info[$element]->content_model = 'li';
|
||||
$this->info[$element]->content_model_type = 'required';
|
||||
}
|
||||
}
|
||||
$this->info['dt']->content_model = '#PCDATA | Inline';
|
||||
$this->info['dt']->content_model_type = 'optional';
|
||||
$this->info['dl']->content_model = 'dt | dd';
|
||||
$this->info['dl']->content_model_type = 'required';
|
||||
// this could be a LOT more robust
|
||||
$this->info['li']->auto_close = array('li' => true);
|
||||
$this->addElement('ol', true, 'List', 'Required: li', 'Common');
|
||||
$this->addElement('ul', true, 'List', 'Required: li', 'Common');
|
||||
$this->addElement('dl', true, 'List', 'Required: dt | dd', 'Common');
|
||||
|
||||
$li =& $this->addElement('li', true, false, 'Flow', 'Common');
|
||||
$li->auto_close = array('li' => true);
|
||||
|
||||
$this->addElement('dd', true, false, 'Flow', 'Common');
|
||||
$this->addElement('dt', true, false, 'Inline', 'Common');
|
||||
}
|
||||
|
||||
}
|
||||
|
16
library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php
Normal file
16
library/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_NonXMLCommonAttributes extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
var $name = 'NonXMLCommonAttributes';
|
||||
|
||||
var $attr_collections = array(
|
||||
'Lang' => array(
|
||||
'lang' => 'LanguageCode',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
@@ -16,23 +16,16 @@ class HTMLPurifier_HTMLModule_Presentation extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Presentation';
|
||||
var $elements = array('b', 'big', 'hr', 'i', 'small', 'sub', 'sup', 'tt');
|
||||
var $content_sets = array(
|
||||
'Block' => 'hr',
|
||||
'Inline' => 'b | big | i | small | sub | sup | tt'
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_Presentation() {
|
||||
foreach ($this->elements as $element) {
|
||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$element]->attr = array(0 => array('Common'));
|
||||
if ($element == 'hr') {
|
||||
$this->info[$element]->content_model_type = 'empty';
|
||||
} else {
|
||||
$this->info[$element]->content_model = '#PCDATA | Inline';
|
||||
$this->info[$element]->content_model_type = 'optional';
|
||||
}
|
||||
}
|
||||
$this->addElement('b', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('big', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('hr', true, 'Block', 'Empty', 'Common');
|
||||
$this->addElement('i', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('small', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('sub', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('sup', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('tt', true, 'Inline', 'Inline', 'Common');
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -46,8 +46,12 @@ class HTMLPurifier_HTMLModule_Scripting extends HTMLPurifier_HTMLModule
|
||||
// blockquote's custom definition (we would use it but
|
||||
// blockquote's contents are optional while noscript's contents
|
||||
// are required)
|
||||
|
||||
// TODO: convert this to new syntax, main problem is getting
|
||||
// both content sets working
|
||||
foreach ($this->elements as $element) {
|
||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$element]->safe = false;
|
||||
}
|
||||
$this->info['noscript']->attr = array( 0 => array('Common') );
|
||||
$this->info['noscript']->content_model = 'Heading | List | Block';
|
||||
|
@@ -10,75 +10,60 @@ 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(
|
||||
'void', 'above', 'below', 'hsides', 'lhs', 'rhs',
|
||||
'vsides', 'box', 'border'
|
||||
), false);
|
||||
$attr['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(
|
||||
'left', 'center', 'right', 'justify', 'char'
|
||||
), false);
|
||||
$attr['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';
|
||||
|
||||
// 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();
|
||||
$this->addElement('caption', true, false, 'Inline', 'Common');
|
||||
|
||||
$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('table', true, 'Block',
|
||||
new HTMLPurifier_ChildDef_Table(), 'Common',
|
||||
array(
|
||||
'border' => 'Pixels',
|
||||
'cellpadding' => 'Length',
|
||||
'cellspacing' => 'Length',
|
||||
'frame' => 'Enum#void,above,below,hsides,lhs,rhs,vsides,box,border',
|
||||
'rules' => 'Enum#none,groups,rows,cols,all',
|
||||
'summary' => 'Text',
|
||||
'width' => 'Length'
|
||||
)
|
||||
);
|
||||
|
||||
$this->info['tr']->content_model = 'td | th';
|
||||
$this->info['tr']->content_model_type = 'required';
|
||||
// common attributes
|
||||
$cell_align = array(
|
||||
'align' => 'Enum#left,center,right,justify,char',
|
||||
'charoff' => 'Length',
|
||||
'valign' => 'Enum#top,middle,bottom,baseline',
|
||||
);
|
||||
|
||||
$this->info['col']->content_model_type = 'empty';
|
||||
$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['colgroup']->content_model = 'col';
|
||||
$this->info['colgroup']->content_model_type = 'optional';
|
||||
$this->addElement('tr', true, false, 'Required: td | th', 'Common', $cell_align);
|
||||
|
||||
$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';
|
||||
$cell_col = array_merge(
|
||||
array(
|
||||
'span' => 'Number',
|
||||
'width' => 'MultiLength',
|
||||
),
|
||||
$cell_align
|
||||
);
|
||||
$this->addElement('col', true, false, 'Empty', 'Common', $cell_col);
|
||||
$colgroup =& $this->addElement('colgroup', true, false, 'Optional: col', 'Common', $cell_col);
|
||||
$colgroup->auto_close = $this->makeLookup(
|
||||
'thead', 'tbody', 'tfoot', 'tr'
|
||||
);
|
||||
|
||||
$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);
|
||||
|
||||
}
|
||||
|
||||
|
@@ -9,13 +9,12 @@ class HTMLPurifier_HTMLModule_Target extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Target';
|
||||
var $elements = array('a');
|
||||
|
||||
function HTMLPurifier_HTMLModule_Target() {
|
||||
foreach ($this->elements as $e) {
|
||||
$this->info[$e] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$e]->standalone = false;
|
||||
$this->info[$e]->attr = array(
|
||||
$elements = array('a');
|
||||
foreach ($elements as $name) {
|
||||
$e =& $this->addBlankElement($name);
|
||||
$e->attr = array(
|
||||
'target' => new HTMLPurifier_AttrDef_HTML_FrameTarget()
|
||||
);
|
||||
}
|
||||
|
@@ -10,65 +10,60 @@ require_once 'HTMLPurifier/HTMLModule.php';
|
||||
* - Block Structural (div, p)
|
||||
* - Inline Phrasal (abbr, acronym, cite, code, dfn, em, kbd, q, samp, strong, var)
|
||||
* - Inline Structural (br, span)
|
||||
* We have elected not to follow suite, but this may change.
|
||||
* This module, functionally, does not distinguish between these
|
||||
* sub-modules, but the code is internally structured to reflect
|
||||
* these distinctions.
|
||||
*/
|
||||
class HTMLPurifier_HTMLModule_Text extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'Text';
|
||||
|
||||
var $elements = array('abbr', 'acronym', 'address', 'blockquote',
|
||||
'br', 'cite', 'code', 'dfn', 'div', 'em', 'h1', 'h2', 'h3',
|
||||
'h4', 'h5', 'h6', 'kbd', 'p', 'pre', 'q', 'samp', 'span', 'strong',
|
||||
'var');
|
||||
|
||||
var $content_sets = array(
|
||||
'Heading' => 'h1 | h2 | h3 | h4 | h5 | h6',
|
||||
'Block' => 'address | blockquote | div | p | pre',
|
||||
'Inline' => 'abbr | acronym | br | cite | code | dfn | em | kbd | q | samp | span | strong | var',
|
||||
'Flow' => 'Heading | Block | Inline'
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_Text() {
|
||||
foreach ($this->elements as $element) {
|
||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
||||
// attributes
|
||||
if ($element == 'br') {
|
||||
$this->info[$element]->attr = array(0 => array('Core'));
|
||||
} elseif ($element == 'blockquote' || $element == 'q') {
|
||||
$this->info[$element]->attr = array(0 => array('Common'), 'cite' => 'URI');
|
||||
} else {
|
||||
$this->info[$element]->attr = array(0 => array('Common'));
|
||||
}
|
||||
// content models
|
||||
if ($element == 'br') {
|
||||
$this->info[$element]->content_model_type = 'empty';
|
||||
} elseif ($element == 'blockquote') {
|
||||
$this->info[$element]->content_model = 'Heading | Block | List';
|
||||
$this->info[$element]->content_model_type = 'optional';
|
||||
} elseif ($element == 'div') {
|
||||
$this->info[$element]->content_model = '#PCDATA | Flow';
|
||||
$this->info[$element]->content_model_type = 'optional';
|
||||
} else {
|
||||
$this->info[$element]->content_model = '#PCDATA | Inline';
|
||||
$this->info[$element]->content_model_type = 'optional';
|
||||
}
|
||||
}
|
||||
// SGML permits exclusions for all descendants, but this is
|
||||
// not possible with DTDs or XML Schemas. W3C has elected to
|
||||
// use complicated compositions of content_models to simulate
|
||||
// exclusion for children, but we go the simpler, SGML-style
|
||||
// route of flat-out exclusions. Note that the Abstract Module
|
||||
// is blithely unaware of such distinctions.
|
||||
$this->info['pre']->excludes = array_flip(array(
|
||||
'img', 'big', 'small',
|
||||
'object', 'applet', 'font', 'basefont' // generally not allowed
|
||||
));
|
||||
$this->info['p']->auto_close = array_flip(array(
|
||||
|
||||
// Inline Phrasal -------------------------------------------------
|
||||
$this->addElement('abbr', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('acronym', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('cite', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('code', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('dfn', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('em', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('kbd', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('q', true, 'Inline', 'Inline', 'Common', array('cite' => 'URI'));
|
||||
$this->addElement('samp', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('strong', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('var', true, 'Inline', 'Inline', 'Common');
|
||||
|
||||
// Inline Structural ----------------------------------------------
|
||||
$this->addElement('span', true, 'Inline', 'Inline', 'Common');
|
||||
$this->addElement('br', true, 'Inline', 'Empty', 'Core');
|
||||
|
||||
// Block Phrasal --------------------------------------------------
|
||||
$this->addElement('address', true, 'Block', 'Inline', 'Common');
|
||||
$this->addElement('blockquote', true, 'Block', 'Optional: Heading | Block | List', 'Common', array('cite' => 'URI') );
|
||||
$pre =& $this->addElement('pre', true, 'Block', 'Inline', 'Common');
|
||||
$pre->excludes = $this->makeLookup(
|
||||
'img', 'big', 'small', 'object', 'applet', 'font', 'basefont' );
|
||||
$this->addElement('h1', true, 'Heading', 'Inline', 'Common');
|
||||
$this->addElement('h2', true, 'Heading', 'Inline', 'Common');
|
||||
$this->addElement('h3', true, 'Heading', 'Inline', 'Common');
|
||||
$this->addElement('h4', true, 'Heading', 'Inline', 'Common');
|
||||
$this->addElement('h5', true, 'Heading', 'Inline', 'Common');
|
||||
$this->addElement('h6', true, 'Heading', 'Inline', 'Common');
|
||||
|
||||
// Block Structural -----------------------------------------------
|
||||
$p =& $this->addElement('p', true, 'Block', 'Inline', 'Common');
|
||||
// this seems really ad hoc: implementing some general
|
||||
// heuristics would probably be better
|
||||
$p->auto_close = $this->makeLookup(
|
||||
'address', 'blockquote', 'dd', 'dir', 'div', 'dl', 'dt',
|
||||
'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'ol', 'p', 'pre',
|
||||
'table', 'ul'
|
||||
));
|
||||
'table', 'ul' );
|
||||
$this->addElement('div', true, 'Block', 'Flow', 'Common');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
241
library/HTMLPurifier/HTMLModule/Tidy.php
Normal file
241
library/HTMLPurifier/HTMLModule/Tidy.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule.php';
|
||||
|
||||
HTMLPurifier_ConfigSchema::define(
|
||||
'HTML', 'TidyLevel', 'medium', 'string', '
|
||||
<p>General level of cleanliness the Tidy module should enforce.
|
||||
There are four allowed values:</p>
|
||||
<dl>
|
||||
<dt>none</dt>
|
||||
<dd>No extra tidying should be done</dd>
|
||||
<dt>light</dt>
|
||||
<dd>Only fix elements that would be discarded otherwise due to
|
||||
lack of support in doctype</dd>
|
||||
<dt>medium</dt>
|
||||
<dd>Enforce best practices</dd>
|
||||
<dt>heavy</dt>
|
||||
<dd>Transform all deprecated elements and attributes to standards
|
||||
compliant equivalents</dd>
|
||||
</dl>
|
||||
<p>This directive has been available since 2.0.0</p>
|
||||
' );
|
||||
HTMLPurifier_ConfigSchema::defineAllowedValues(
|
||||
'HTML', 'TidyLevel', array('none', 'light', 'medium', 'heavy')
|
||||
);
|
||||
|
||||
HTMLPurifier_ConfigSchema::define(
|
||||
'HTML', 'TidyAdd', array(), 'lookup', '
|
||||
Fixes to add to the default set of Tidy fixes as per your level. This
|
||||
directive has been available since 2.0.0.
|
||||
' );
|
||||
|
||||
HTMLPurifier_ConfigSchema::define(
|
||||
'HTML', 'TidyRemove', array(), 'lookup', '
|
||||
Fixes to remove from the default set of Tidy fixes as per your level. This
|
||||
directive has been available since 2.0.0.
|
||||
' );
|
||||
|
||||
/**
|
||||
* Abstract class for a set of proprietary modules that clean up (tidy)
|
||||
* poorly written HTML.
|
||||
*/
|
||||
class HTMLPurifier_HTMLModule_Tidy extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
/**
|
||||
* List of supported levels. Index zero is a special case "no fixes"
|
||||
* level.
|
||||
*/
|
||||
var $levels = array(0 => 'none', 'light', 'medium', 'heavy');
|
||||
|
||||
/**
|
||||
* Default level to place all fixes in. Disabled by default
|
||||
*/
|
||||
var $defaultLevel = null;
|
||||
|
||||
/**
|
||||
* Lists of fixes used by getFixesForLevel(). Format is:
|
||||
* HTMLModule_Tidy->fixesForLevel[$level] = array('fix-1', 'fix-2');
|
||||
*/
|
||||
var $fixesForLevel = array(
|
||||
'light' => array(),
|
||||
'medium' => array(),
|
||||
'heavy' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Lazy load constructs the module by determining the necessary
|
||||
* fixes to create and then delegating to the populate() function.
|
||||
* @todo Wildcard matching and error reporting when an added or
|
||||
* subtracted fix has no effect.
|
||||
*/
|
||||
function construct($config) {
|
||||
|
||||
// create fixes, initialize fixesForLevel
|
||||
$fixes = $this->makeFixes();
|
||||
$this->makeFixesForLevel($fixes);
|
||||
|
||||
// figure out which fixes to use
|
||||
$level = $config->get('HTML', 'TidyLevel');
|
||||
$fixes_lookup = $this->getFixesForLevel($level);
|
||||
|
||||
// get custom fix declarations: these need namespace processing
|
||||
$add_fixes = $config->get('HTML', 'TidyAdd');
|
||||
$remove_fixes = $config->get('HTML', 'TidyRemove');
|
||||
|
||||
foreach ($fixes as $name => $fix) {
|
||||
// needs to be refactored a little to implement globbing
|
||||
if (
|
||||
isset($remove_fixes[$name]) ||
|
||||
(!isset($add_fixes[$name]) && !isset($fixes_lookup[$name]))
|
||||
) {
|
||||
unset($fixes[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
// populate this module with necessary fixes
|
||||
$this->populate($fixes);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all fixes per a level, returning fixes for that specific
|
||||
* level as well as all levels below it.
|
||||
* @param $level String level identifier, see $levels for valid values
|
||||
* @return Lookup up table of fixes
|
||||
*/
|
||||
function getFixesForLevel($level) {
|
||||
if ($level == $this->levels[0]) {
|
||||
return array();
|
||||
}
|
||||
$activated_levels = array();
|
||||
for ($i = 1, $c = count($this->levels); $i < $c; $i++) {
|
||||
$activated_levels[] = $this->levels[$i];
|
||||
if ($this->levels[$i] == $level) break;
|
||||
}
|
||||
if ($i == $c) {
|
||||
trigger_error(
|
||||
'Tidy level ' . htmlspecialchars($level) . ' not recognized',
|
||||
E_USER_WARNING
|
||||
);
|
||||
return array();
|
||||
}
|
||||
$ret = array();
|
||||
foreach ($activated_levels as $level) {
|
||||
foreach ($this->fixesForLevel[$level] as $fix) {
|
||||
$ret[$fix] = true;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically populates the $fixesForLevel member variable using
|
||||
* the fixes array. It may be custom overloaded, used in conjunction
|
||||
* with $defaultLevel, or not used at all.
|
||||
*/
|
||||
function makeFixesForLevel($fixes) {
|
||||
if (!isset($this->defaultLevel)) return;
|
||||
if (!isset($this->fixesForLevel[$this->defaultLevel])) {
|
||||
trigger_error(
|
||||
'Default level ' . $this->defaultLevel . ' does not exist',
|
||||
E_USER_ERROR
|
||||
);
|
||||
return;
|
||||
}
|
||||
$this->fixesForLevel[$this->defaultLevel] = array_keys($fixes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the module with transforms and other special-case code
|
||||
* based on a list of fixes passed to it
|
||||
* @param $lookup Lookup table of fixes to activate
|
||||
*/
|
||||
function populate($fixes) {
|
||||
foreach ($fixes as $name => $fix) {
|
||||
// determine what the fix is for
|
||||
list($type, $params) = $this->getFixType($name);
|
||||
switch ($type) {
|
||||
case 'attr_transform_pre':
|
||||
case 'attr_transform_post':
|
||||
$attr = $params['attr'];
|
||||
if (isset($params['element'])) {
|
||||
$element = $params['element'];
|
||||
if (empty($this->info[$element])) {
|
||||
$e =& $this->addBlankElement($element);
|
||||
} else {
|
||||
$e =& $this->info[$element];
|
||||
}
|
||||
} else {
|
||||
$type = "info_$type";
|
||||
$e =& $this;
|
||||
}
|
||||
$f =& $e->$type;
|
||||
$f[$attr] = $fix;
|
||||
break;
|
||||
case 'tag_transform':
|
||||
$this->info_tag_transform[$params['element']] = $fix;
|
||||
break;
|
||||
case 'child':
|
||||
case 'content_model_type':
|
||||
$element = $params['element'];
|
||||
if (empty($this->info[$element])) {
|
||||
$e =& $this->addBlankElement($element);
|
||||
} else {
|
||||
$e =& $this->info[$element];
|
||||
}
|
||||
$e->$type = $fix;
|
||||
break;
|
||||
default:
|
||||
trigger_error("Fix type $type not supported", E_USER_ERROR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a fix name and determines what kind of fix it is, as well
|
||||
* as other information defined by the fix
|
||||
* @param $name String name of fix
|
||||
* @return array(string $fix_type, array $fix_parameters)
|
||||
* @note $fix_parameters is type dependant, see populate() for usage
|
||||
* of these parameters
|
||||
*/
|
||||
function getFixType($name) {
|
||||
// parse it
|
||||
$property = $attr = null;
|
||||
if (strpos($name, '#') !== false) list($name, $property) = explode('#', $name);
|
||||
if (strpos($name, '@') !== false) list($name, $attr) = explode('@', $name);
|
||||
|
||||
// figure out the parameters
|
||||
$params = array();
|
||||
if ($name !== '') $params['element'] = $name;
|
||||
if (!is_null($attr)) $params['attr'] = $attr;
|
||||
|
||||
// special case: attribute transform
|
||||
if (!is_null($attr)) {
|
||||
if (is_null($property)) $property = 'pre';
|
||||
$type = 'attr_transform_' . $property;
|
||||
return array($type, $params);
|
||||
}
|
||||
|
||||
// special case: tag transform
|
||||
if (is_null($property)) {
|
||||
return array('tag_transform', $params);
|
||||
}
|
||||
|
||||
return array($property, $params);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines all fixes the module will perform in a compact
|
||||
* associative array of fix name to fix implementation.
|
||||
* @abstract
|
||||
*/
|
||||
function makeFixes() {}
|
||||
|
||||
}
|
||||
|
||||
?>
|
18
library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php
Normal file
18
library/HTMLPurifier/HTMLModule/Tidy/Proprietary.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_Proprietary extends
|
||||
HTMLPurifier_HTMLModule_Tidy
|
||||
{
|
||||
|
||||
var $name = 'Tidy_Proprietary';
|
||||
var $defaultLevel = 'light';
|
||||
|
||||
function makeFixes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
21
library/HTMLPurifier/HTMLModule/Tidy/XHTML.php
Normal file
21
library/HTMLPurifier/HTMLModule/Tidy/XHTML.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Lang.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_XHTML extends
|
||||
HTMLPurifier_HTMLModule_Tidy
|
||||
{
|
||||
|
||||
var $name = 'Tidy_XHTML';
|
||||
var $defaultLevel = 'medium';
|
||||
|
||||
function makeFixes() {
|
||||
$r = array();
|
||||
$r['@lang'] = new HTMLPurifier_AttrTransform_Lang();
|
||||
return $r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
193
library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php
Normal file
193
library/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php
Normal file
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||
|
||||
require_once 'HTMLPurifier/TagTransform/Simple.php';
|
||||
require_once 'HTMLPurifier/TagTransform/Font.php';
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/BgColor.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/BoolToCSS.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Border.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Name.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Length.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/ImgSpace.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4 extends
|
||||
HTMLPurifier_HTMLModule_Tidy
|
||||
{
|
||||
|
||||
function makeFixes() {
|
||||
|
||||
$r = array();
|
||||
|
||||
// == deprecated tag transforms ===================================
|
||||
|
||||
$r['font'] = new HTMLPurifier_TagTransform_Font();
|
||||
$r['menu'] = new HTMLPurifier_TagTransform_Simple('ul');
|
||||
$r['dir'] = new HTMLPurifier_TagTransform_Simple('ul');
|
||||
$r['center'] = new HTMLPurifier_TagTransform_Simple('div', 'text-align:center;');
|
||||
$r['u'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:underline;');
|
||||
$r['s'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:line-through;');
|
||||
$r['strike'] = new HTMLPurifier_TagTransform_Simple('span', 'text-decoration:line-through;');
|
||||
|
||||
// == deprecated attribute transforms =============================
|
||||
|
||||
$r['caption@align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
// we're following IE's behavior, not Firefox's, due
|
||||
// to the fact that no one supports caption-side:right,
|
||||
// W3C included (with CSS 2.1). This is a slightly
|
||||
// unreasonable attribute!
|
||||
'left' => 'text-align:left;',
|
||||
'right' => 'text-align:right;',
|
||||
'top' => 'caption-side:top;',
|
||||
'bottom' => 'caption-side:bottom;' // not supported by IE
|
||||
));
|
||||
|
||||
// @align for img -------------------------------------------------
|
||||
$r['img@align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'float:left;',
|
||||
'right' => 'float:right;',
|
||||
'top' => 'vertical-align:top;',
|
||||
'middle' => 'vertical-align:middle;',
|
||||
'bottom' => 'vertical-align:baseline;',
|
||||
));
|
||||
|
||||
// @align for table -----------------------------------------------
|
||||
$r['table@align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'float:left;',
|
||||
'center' => 'margin-left:auto;margin-right:auto;',
|
||||
'right' => 'float:right;'
|
||||
));
|
||||
|
||||
// @align for hr -----------------------------------------------
|
||||
$r['hr@align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
// we use both text-align and margin because these work
|
||||
// for different browsers (IE and Firefox, respectively)
|
||||
// and the melange makes for a pretty cross-compatible
|
||||
// solution
|
||||
'left' => 'margin-left:0;margin-right:auto;text-align:left;',
|
||||
'center' => 'margin-left:auto;margin-right:auto;text-align:center;',
|
||||
'right' => 'margin-left:auto;margin-right:0;text-align:right;'
|
||||
));
|
||||
|
||||
// @align for h1, h2, h3, h4, h5, h6, p, div ----------------------
|
||||
// {{{
|
||||
$align_lookup = array();
|
||||
$align_values = array('left', 'right', 'center', 'justify');
|
||||
foreach ($align_values as $v) $align_lookup[$v] = "text-align:$v;";
|
||||
// }}}
|
||||
$r['h1@align'] =
|
||||
$r['h2@align'] =
|
||||
$r['h3@align'] =
|
||||
$r['h4@align'] =
|
||||
$r['h5@align'] =
|
||||
$r['h6@align'] =
|
||||
$r['p@align'] =
|
||||
$r['div@align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup);
|
||||
|
||||
// @bgcolor for table, tr, td, th ---------------------------------
|
||||
$r['table@bgcolor'] =
|
||||
$r['td@bgcolor'] =
|
||||
$r['th@bgcolor'] =
|
||||
new HTMLPurifier_AttrTransform_BgColor();
|
||||
|
||||
// @border for img ------------------------------------------------
|
||||
$r['img@border'] = new HTMLPurifier_AttrTransform_Border();
|
||||
|
||||
// @clear for br --------------------------------------------------
|
||||
$r['br@clear'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('clear', array(
|
||||
'left' => 'clear:left;',
|
||||
'right' => 'clear:right;',
|
||||
'all' => 'clear:both;',
|
||||
'none' => 'clear:none;',
|
||||
));
|
||||
|
||||
// @height for td, th ---------------------------------------------
|
||||
$r['td@height'] =
|
||||
$r['th@height'] =
|
||||
new HTMLPurifier_AttrTransform_Length('height');
|
||||
|
||||
// @hspace for img ------------------------------------------------
|
||||
$r['img@hspace'] = new HTMLPurifier_AttrTransform_ImgSpace('hspace');
|
||||
|
||||
// @name for img, a -----------------------------------------------
|
||||
$r['img@name'] =
|
||||
$r['a@name'] = new HTMLPurifier_AttrTransform_Name();
|
||||
|
||||
// @noshade for hr ------------------------------------------------
|
||||
// this transformation is not precise but often good enough.
|
||||
// different browsers use different styles to designate noshade
|
||||
$r['hr@noshade'] =
|
||||
new HTMLPurifier_AttrTransform_BoolToCSS(
|
||||
'noshade',
|
||||
'color:#808080;background-color:#808080;border:0;'
|
||||
);
|
||||
|
||||
// @nowrap for td, th ---------------------------------------------
|
||||
$r['td@nowrap'] =
|
||||
$r['th@nowrap'] =
|
||||
new HTMLPurifier_AttrTransform_BoolToCSS(
|
||||
'nowrap',
|
||||
'white-space:nowrap;'
|
||||
);
|
||||
|
||||
// @size for hr --------------------------------------------------
|
||||
$r['hr@size'] = new HTMLPurifier_AttrTransform_Length('size', 'height');
|
||||
|
||||
// @type for li, ol, ul -------------------------------------------
|
||||
// {{{
|
||||
$ul_types = array(
|
||||
'disc' => 'list-style-type:disc;',
|
||||
'square' => 'list-style-type:square;',
|
||||
'circle' => 'list-style-type:circle;'
|
||||
);
|
||||
$ol_types = array(
|
||||
'1' => 'list-style-type:decimal;',
|
||||
'i' => 'list-style-type:lower-roman;',
|
||||
'I' => 'list-style-type:upper-roman;',
|
||||
'a' => 'list-style-type:lower-alpha;',
|
||||
'A' => 'list-style-type:upper-alpha;'
|
||||
);
|
||||
$li_types = $ul_types + $ol_types;
|
||||
// }}}
|
||||
|
||||
$r['ul@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types);
|
||||
$r['ol@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $ol_types, true);
|
||||
$r['li@type'] = new HTMLPurifier_AttrTransform_EnumToCSS('type', $li_types, true);
|
||||
|
||||
// @vspace for img ------------------------------------------------
|
||||
$r['img@vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace');
|
||||
|
||||
// @width for hr, td, th ------------------------------------------
|
||||
$r['td@width'] =
|
||||
$r['th@width'] =
|
||||
$r['hr@width'] = new HTMLPurifier_AttrTransform_Length('width');
|
||||
|
||||
return $r;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_Transitional extends
|
||||
HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4
|
||||
{
|
||||
var $name = 'Tidy_Transitional';
|
||||
var $defaultLevel = 'heavy';
|
||||
}
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_Strict extends
|
||||
HTMLPurifier_HTMLModule_Tidy_XHTMLAndHTML4
|
||||
{
|
||||
var $name = 'Tidy_Strict';
|
||||
var $defaultLevel = 'light';
|
||||
}
|
||||
|
||||
?>
|
27
library/HTMLPurifier/HTMLModule/Tidy/XHTMLStrict.php
Normal file
27
library/HTMLPurifier/HTMLModule/Tidy/XHTMLStrict.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule/Tidy.php';
|
||||
require_once 'HTMLPurifier/ChildDef/StrictBlockquote.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_Tidy_XHTMLStrict extends
|
||||
HTMLPurifier_HTMLModule_Tidy
|
||||
{
|
||||
|
||||
var $name = 'Tidy_XHTMLStrict';
|
||||
var $defaultLevel = 'light';
|
||||
|
||||
function makeFixes() {
|
||||
$r = array();
|
||||
$r['blockquote#content_model_type'] = 'strictblockquote';
|
||||
return $r;
|
||||
}
|
||||
|
||||
var $defines_child_def = true;
|
||||
function getChildDef($def) {
|
||||
if ($def->content_model_type != 'strictblockquote') return false;
|
||||
return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -1,200 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/ChildDef/StrictBlockquote.php';
|
||||
|
||||
require_once 'HTMLPurifier/TagTransform/Simple.php';
|
||||
require_once 'HTMLPurifier/TagTransform/Center.php';
|
||||
require_once 'HTMLPurifier/TagTransform/Font.php';
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/Lang.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/BgColor.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/BoolToCSS.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Border.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Name.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/Length.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/ImgSpace.php';
|
||||
require_once 'HTMLPurifier/AttrTransform/EnumToCSS.php';
|
||||
|
||||
/**
|
||||
* Proprietary module that transforms deprecated elements into Strict
|
||||
* HTML (see HTML 4.01 and XHTML 1.0) when possible.
|
||||
*/
|
||||
|
||||
class HTMLPurifier_HTMLModule_TransformToStrict extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'TransformToStrict';
|
||||
|
||||
// we're actually modifying these elements, not defining them
|
||||
var $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p',
|
||||
'blockquote', 'table', 'td', 'th', 'tr', 'img', 'a', 'hr', 'br',
|
||||
'caption', 'ul', 'ol', 'li');
|
||||
|
||||
var $info_tag_transform = array(
|
||||
// placeholders, see constructor for definitions
|
||||
'font' => false,
|
||||
'menu' => false,
|
||||
'dir' => false,
|
||||
'center'=> false
|
||||
);
|
||||
|
||||
var $attr_collections = array(
|
||||
'Lang' => array(
|
||||
'lang' => false // placeholder
|
||||
)
|
||||
);
|
||||
|
||||
var $info_attr_transform_post = array(
|
||||
'lang' => false // placeholder
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_TransformToStrict() {
|
||||
|
||||
// behavior with transformations when there's another CSS property
|
||||
// working on it is interesting: the CSS will *always* override
|
||||
// the deprecated attribute, whereas an inline CSS declaration will
|
||||
// override the corresponding declaration in, say, an external
|
||||
// stylesheet. This behavior won't affect most people, but it
|
||||
// does represent an operational difference we CANNOT fix.
|
||||
|
||||
// deprecated tag transforms
|
||||
$this->info_tag_transform['font'] = new HTMLPurifier_TagTransform_Font();
|
||||
$this->info_tag_transform['menu'] = new HTMLPurifier_TagTransform_Simple('ul');
|
||||
$this->info_tag_transform['dir'] = new HTMLPurifier_TagTransform_Simple('ul');
|
||||
$this->info_tag_transform['center'] = new HTMLPurifier_TagTransform_Center();
|
||||
|
||||
foreach ($this->elements as $name) {
|
||||
$this->info[$name] = new HTMLPurifier_ElementDef();
|
||||
$this->info[$name]->standalone = false;
|
||||
}
|
||||
|
||||
// deprecated attribute transforms
|
||||
|
||||
// align battery
|
||||
$align_lookup = array();
|
||||
$align_values = array('left', 'right', 'center', 'justify');
|
||||
foreach ($align_values as $v) $align_lookup[$v] = "text-align:$v;";
|
||||
$this->info['h1']->attr_transform_pre['align'] =
|
||||
$this->info['h2']->attr_transform_pre['align'] =
|
||||
$this->info['h3']->attr_transform_pre['align'] =
|
||||
$this->info['h4']->attr_transform_pre['align'] =
|
||||
$this->info['h5']->attr_transform_pre['align'] =
|
||||
$this->info['h6']->attr_transform_pre['align'] =
|
||||
$this->info['p'] ->attr_transform_pre['align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', $align_lookup);
|
||||
|
||||
// xml:lang <=> lang mirroring, implement in TransformToStrict,
|
||||
// this is overridden in TransformToXHTML11
|
||||
$this->info_attr_transform_post['lang'] = new HTMLPurifier_AttrTransform_Lang();
|
||||
$this->attr_collections['Lang']['lang'] = new HTMLPurifier_AttrDef_Lang();
|
||||
|
||||
// this should not be applied to XHTML 1.0 Transitional, ONLY
|
||||
// XHTML 1.0 Strict. We may need three classes
|
||||
$this->info['blockquote']->content_model_type = 'strictblockquote';
|
||||
$this->info['blockquote']->child = false; // recalculate please!
|
||||
|
||||
$this->info['table']->attr_transform_pre['bgcolor'] =
|
||||
$this->info['tr']->attr_transform_pre['bgcolor'] =
|
||||
$this->info['td']->attr_transform_pre['bgcolor'] =
|
||||
$this->info['th']->attr_transform_pre['bgcolor'] = new HTMLPurifier_AttrTransform_BgColor();
|
||||
|
||||
$this->info['img']->attr_transform_pre['border'] = new HTMLPurifier_AttrTransform_Border();
|
||||
|
||||
$this->info['img']->attr_transform_pre['name'] =
|
||||
$this->info['a']->attr_transform_pre['name'] = new HTMLPurifier_AttrTransform_Name();
|
||||
|
||||
$this->info['td']->attr_transform_pre['width'] =
|
||||
$this->info['th']->attr_transform_pre['width'] =
|
||||
$this->info['hr']->attr_transform_pre['width'] = new HTMLPurifier_AttrTransform_Length('width');
|
||||
|
||||
$this->info['td']->attr_transform_pre['nowrap'] =
|
||||
$this->info['th']->attr_transform_pre['nowrap'] = new HTMLPurifier_AttrTransform_BoolToCSS('nowrap', 'white-space:nowrap;');
|
||||
|
||||
$this->info['td']->attr_transform_pre['height'] =
|
||||
$this->info['th']->attr_transform_pre['height'] = new HTMLPurifier_AttrTransform_Length('height');
|
||||
|
||||
$this->info['img']->attr_transform_pre['hspace'] = new HTMLPurifier_AttrTransform_ImgSpace('hspace');
|
||||
$this->info['img']->attr_transform_pre['vspace'] = new HTMLPurifier_AttrTransform_ImgSpace('vspace');
|
||||
|
||||
$this->info['hr']->attr_transform_pre['size'] = new HTMLPurifier_AttrTransform_Length('size', 'height');
|
||||
|
||||
// this transformation is not precise but often good enough.
|
||||
// different browsers use different styles to designate noshade
|
||||
$this->info['hr']->attr_transform_pre['noshade'] = new HTMLPurifier_AttrTransform_BoolToCSS('noshade', 'color:#808080;background-color:#808080;border: 0;');
|
||||
|
||||
$this->info['br']->attr_transform_pre['clear'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('clear', array(
|
||||
'left' => 'clear:left;',
|
||||
'right' => 'clear:right;',
|
||||
'all' => 'clear:both;',
|
||||
'none' => 'clear:none;',
|
||||
));
|
||||
|
||||
// this is a slightly unreasonable attribute
|
||||
$this->info['caption']->attr_transform_pre['align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
// we're following IE's behavior, not Firefox's, due
|
||||
// to the fact that no one supports caption-side:right,
|
||||
// W3C included (with CSS 2.1)
|
||||
'left' => 'text-align:left;',
|
||||
'right' => 'text-align:right;',
|
||||
'top' => 'caption-side:top;',
|
||||
'bottom' => 'caption-side:bottom;' // not supported by IE
|
||||
));
|
||||
|
||||
$this->info['table']->attr_transform_pre['align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'float:left;',
|
||||
'center' => 'margin-left:auto;margin-right:auto;',
|
||||
'right' => 'float:right;'
|
||||
));
|
||||
|
||||
$this->info['img']->attr_transform_pre['align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'float:left;',
|
||||
'right' => 'float:right;',
|
||||
'top' => 'vertical-align:top;',
|
||||
'middle' => 'vertical-align:middle;',
|
||||
'bottom' => 'vertical-align:baseline;',
|
||||
));
|
||||
|
||||
$this->info['hr']->attr_transform_pre['align'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('align', array(
|
||||
'left' => 'margin-left:0;margin-right:auto;text-align:left;',
|
||||
'center' => 'margin-left:auto;margin-right:auto;text-align:center;',
|
||||
'right' => 'margin-left:auto;margin-right:0;text-align:right;'
|
||||
));
|
||||
|
||||
$ul_types = array(
|
||||
'disc' => 'list-style-type:disc;',
|
||||
'square' => 'list-style-type:square;',
|
||||
'circle' => 'list-style-type:circle;'
|
||||
);
|
||||
$ol_types = array(
|
||||
'1' => 'list-style-type:decimal;',
|
||||
'i' => 'list-style-type:lower-roman;',
|
||||
'I' => 'list-style-type:upper-roman;',
|
||||
'a' => 'list-style-type:lower-alpha;',
|
||||
'A' => 'list-style-type:upper-alpha;'
|
||||
);
|
||||
$li_types = $ul_types + $ol_types;
|
||||
|
||||
$this->info['ul']->attr_transform_pre['type'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('type', $ul_types);
|
||||
$this->info['ol']->attr_transform_pre['type'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('type', $ol_types, true);
|
||||
$this->info['li']->attr_transform_pre['type'] =
|
||||
new HTMLPurifier_AttrTransform_EnumToCSS('type', $li_types, true);
|
||||
|
||||
|
||||
}
|
||||
|
||||
var $defines_child_def = true;
|
||||
function getChildDef($def) {
|
||||
if ($def->content_model_type != 'strictblockquote') return false;
|
||||
return new HTMLPurifier_ChildDef_StrictBlockquote($def->content_model);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/AttrTransform/Lang.php';
|
||||
|
||||
/**
|
||||
* Proprietary module that transforms XHTML 1.0 deprecated aspects into
|
||||
* XHTML 1.1 compliant ones, when possible. For maximum effectiveness,
|
||||
* HTMLPurifier_HTMLModule_TransformToStrict must also be loaded
|
||||
* (otherwise, elements that were deprecated from Transitional to Strict
|
||||
* will not be transformed).
|
||||
*
|
||||
* XHTML 1.1 compliant document are automatically XHTML 1.0 compliant too,
|
||||
* although they may not be as friendly to legacy browsers.
|
||||
*/
|
||||
|
||||
class HTMLPurifier_HTMLModule_TransformToXHTML11 extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
|
||||
var $name = 'TransformToXHTML11';
|
||||
var $attr_collections = array(
|
||||
'Lang' => array(
|
||||
'lang' => false // remove it
|
||||
)
|
||||
);
|
||||
|
||||
var $info_attr_transform_post = array(
|
||||
'lang' => false // remove it
|
||||
);
|
||||
|
||||
function HTMLPurifier_HTMLModule_TransformToXHTML11() {
|
||||
$this->info_attr_transform_pre['lang'] = new HTMLPurifier_AttrTransform_Lang();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
16
library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php
Normal file
16
library/HTMLPurifier/HTMLModule/XMLCommonAttributes.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
require_once 'HTMLPurifier/HTMLModule.php';
|
||||
|
||||
class HTMLPurifier_HTMLModule_XMLCommonAttributes extends HTMLPurifier_HTMLModule
|
||||
{
|
||||
var $name = 'XMLCommonAttributes';
|
||||
|
||||
var $attr_collections = array(
|
||||
'Lang' => array(
|
||||
'xml:lang' => 'LanguageCode',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
Reference in New Issue
Block a user