mirror of
https://github.com/ezyang/htmlpurifier.git
synced 2025-08-02 04:10:25 +02:00
[1.7.0] Add more convenience functions to HTMLModule, wire Edit and Hypertext to use new functionality
- Added LanguageCode to AttrTypes. We should prefer string representations of attribute definitions. git-svn-id: http://htmlpurifier.org/svnroot/htmlpurifier/trunk@1040 48356398-32a2-884e-a903-53898d9a118a
This commit is contained in:
@@ -32,6 +32,7 @@ class HTMLPurifier_AttrTypes
|
|||||||
$this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels();
|
$this->info['Pixels'] = new HTMLPurifier_AttrDef_HTML_Pixels();
|
||||||
$this->info['Text'] = new HTMLPurifier_AttrDef_Text();
|
$this->info['Text'] = new HTMLPurifier_AttrDef_Text();
|
||||||
$this->info['URI'] = new HTMLPurifier_AttrDef_URI();
|
$this->info['URI'] = new HTMLPurifier_AttrDef_URI();
|
||||||
|
$this->info['LanguageCode'] = new HTMLPurifier_AttrDef_Lang();
|
||||||
|
|
||||||
// number is really a positive integer (one or more digits)
|
// number is really a positive integer (one or more digits)
|
||||||
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
|
$this->info['Number'] = new HTMLPurifier_AttrDef_Integer(false, false, true);
|
||||||
|
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
class HTMLPurifier_HTMLModule
|
class HTMLPurifier_HTMLModule
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// -- Overloadable ----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Short unique string identifier of the module
|
* Short unique string identifier of the module
|
||||||
*/
|
*/
|
||||||
@@ -120,13 +123,15 @@ class HTMLPurifier_HTMLModule
|
|||||||
*/
|
*/
|
||||||
function setup(&$definition) {}
|
function setup(&$definition) {}
|
||||||
|
|
||||||
|
// -- Convenience -----------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function that sets up a new element
|
* Convenience function that sets up a new element
|
||||||
* @param $element Name of element to add
|
* @param $element Name of element to add
|
||||||
* @param $safe Is element safe for untrusted users to use?
|
* @param $safe Is element safe for untrusted users to use?
|
||||||
* @param $type What content set should element be registered to?
|
* @param $type What content set should element be registered to?
|
||||||
* Set as false to skip this step.
|
* Set as false to skip this step.
|
||||||
* @param $content_model Content model definition in form of:
|
* @param $contents Allowed children in form of:
|
||||||
* "$content_model_type: $content_model"
|
* "$content_model_type: $content_model"
|
||||||
* @param $attr_includes What attribute collections to register to
|
* @param $attr_includes What attribute collections to register to
|
||||||
* element?
|
* element?
|
||||||
@@ -134,14 +139,12 @@ class HTMLPurifier_HTMLModule
|
|||||||
* @note See ElementDef for in-depth descriptions of these parameters.
|
* @note See ElementDef for in-depth descriptions of these parameters.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
function addElement($element, $safe, $type, $content_model, $attr_includes, $attr) {
|
function addElement($element, $safe, $type, $contents, $attr_includes, $attr) {
|
||||||
$this->elements[] = $element;
|
$this->elements[] = $element;
|
||||||
// parse content_model
|
// parse content_model
|
||||||
list($content_model_type, $content_model) = explode(':', $content_model);
|
list($content_model_type, $content_model) = $this->parseContents($contents);
|
||||||
$content_model_type = strtolower(trim($content_model_type));
|
|
||||||
$content_model = trim($content_model);
|
|
||||||
// merge in attribute inclusions
|
// merge in attribute inclusions
|
||||||
$attr[0] = $attr_includes;
|
$this->mergeInAttrIncludes($attr, $attr_includes);
|
||||||
// add element to content sets
|
// add element to content sets
|
||||||
if ($type) $this->addElementToContentSet($element, $type);
|
if ($type) $this->addElementToContentSet($element, $type);
|
||||||
// create element
|
// create element
|
||||||
@@ -163,6 +166,41 @@ class HTMLPurifier_HTMLModule
|
|||||||
$this->content_sets[$type] .= $element;
|
$this->content_sets[$type] .= $element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function that transforms single-string contents
|
||||||
|
* into separate content model and content model type
|
||||||
|
* @param $contents Allowed children in form of:
|
||||||
|
* "$content_model_type: $content_model"
|
||||||
|
*/
|
||||||
|
function parseContents($contents) {
|
||||||
|
switch ($contents) {
|
||||||
|
// check for shorthand content model forms
|
||||||
|
case 'Inline':
|
||||||
|
$contents = 'Optional: Inline | #PCDATA';
|
||||||
|
break;
|
||||||
|
case 'Flow':
|
||||||
|
$contents = 'Optional: Flow | #PCDATA';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
list($content_model_type, $content_model) = explode(':', $contents);
|
||||||
|
$content_model_type = strtolower(trim($content_model_type));
|
||||||
|
$content_model = trim($content_model);
|
||||||
|
return array($content_model_type, $content_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience function that merges a list of attribute includes into
|
||||||
|
* an attribute array.
|
||||||
|
* @param $attr Reference to attr array to modify
|
||||||
|
* @param $attr_includes Array of includes / string include to merge in
|
||||||
|
*/
|
||||||
|
function mergeInAttrIncludes(&$attr, $attr_includes) {
|
||||||
|
if (!is_array($attr_includes)) {
|
||||||
|
if (empty($attr_includes)) $attr_includes = array();
|
||||||
|
else $attr_includes = array($attr_includes);
|
||||||
|
}
|
||||||
|
$attr[0] = $attr_includes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
@@ -18,7 +18,7 @@ class HTMLPurifier_HTMLModule_Bdo extends HTMLPurifier_HTMLModule
|
|||||||
function HTMLPurifier_HTMLModule_Bdo() {
|
function HTMLPurifier_HTMLModule_Bdo() {
|
||||||
$dir = new HTMLPurifier_AttrDef_Enum(array('ltr','rtl'), false);
|
$dir = new HTMLPurifier_AttrDef_Enum(array('ltr','rtl'), false);
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'bdo', true, 'Inline', 'Optional: #PCDATA | Inline', array('Core', 'Lang'),
|
'bdo', true, 'Inline', 'Inline', array('Core', 'Lang'),
|
||||||
array(
|
array(
|
||||||
'dir' => $dir, // required
|
'dir' => $dir, // required
|
||||||
// The Abstract Module specification has the attribute
|
// The Abstract Module specification has the attribute
|
||||||
|
@@ -13,7 +13,7 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
|||||||
'title' => 'CDATA',
|
'title' => 'CDATA',
|
||||||
),
|
),
|
||||||
'Lang' => array(
|
'Lang' => array(
|
||||||
'xml:lang' => false, // see constructor
|
'xml:lang' => 'LanguageCode',
|
||||||
),
|
),
|
||||||
'I18N' => array(
|
'I18N' => array(
|
||||||
0 => array('Lang'), // proprietary, for xml:lang/lang
|
0 => array('Lang'), // proprietary, for xml:lang/lang
|
||||||
@@ -22,10 +22,6 @@ class HTMLPurifier_HTMLModule_CommonAttributes extends HTMLPurifier_HTMLModule
|
|||||||
0 => array('Core', 'I18N')
|
0 => array('Core', 'I18N')
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
function HTMLPurifier_HTMLModule_CommonAttributes() {
|
|
||||||
$this->attr_collections['Lang']['xml:lang'] = new HTMLPurifier_AttrDef_Lang();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
@@ -11,28 +11,28 @@ class HTMLPurifier_HTMLModule_Edit extends HTMLPurifier_HTMLModule
|
|||||||
{
|
{
|
||||||
|
|
||||||
var $name = 'Edit';
|
var $name = 'Edit';
|
||||||
var $elements = array('del', 'ins');
|
|
||||||
var $content_sets = array('Inline' => 'del | ins');
|
|
||||||
|
|
||||||
function HTMLPurifier_HTMLModule_Edit() {
|
function HTMLPurifier_HTMLModule_Edit() {
|
||||||
foreach ($this->elements as $element) {
|
$contents = 'Chameleon: #PCDATA | Inline ! #PCDATA | Flow';
|
||||||
$this->info[$element] = new HTMLPurifier_ElementDef();
|
$attr = array(
|
||||||
$this->info[$element]->attr = array(
|
'cite' => 'URI',
|
||||||
0 => array('Common'),
|
// 'datetime' => 'Datetime', // not implemented
|
||||||
'cite' => 'URI',
|
);
|
||||||
// 'datetime' => 'Datetime' // Datetime not implemented
|
$this->addElement(
|
||||||
);
|
'del', true, 'Inline', $contents, 'Common', $attr
|
||||||
// Inline context ! Block context (exclamation mark is
|
);
|
||||||
// separator, see getChildDef for parsing)
|
$this->addElement(
|
||||||
$this->info[$element]->content_model =
|
'ins', true, 'Inline', $contents, 'Common', $attr
|
||||||
'#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';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
var $defines_child_def = true;
|
||||||
function getChildDef($def) {
|
function getChildDef($def) {
|
||||||
if ($def->content_model_type != 'chameleon') return false;
|
if ($def->content_model_type != 'chameleon') return false;
|
||||||
|
@@ -10,24 +10,21 @@ class HTMLPurifier_HTMLModule_Hypertext extends HTMLPurifier_HTMLModule
|
|||||||
{
|
{
|
||||||
|
|
||||||
var $name = 'Hypertext';
|
var $name = 'Hypertext';
|
||||||
var $elements = array('a');
|
|
||||||
var $content_sets = array('Inline' => 'a');
|
|
||||||
|
|
||||||
function HTMLPurifier_HTMLModule_Hypertext() {
|
function HTMLPurifier_HTMLModule_Hypertext() {
|
||||||
$this->info['a'] = new HTMLPurifier_ElementDef();
|
$this->addElement(
|
||||||
$this->info['a']->attr = array(
|
'a', true, 'Inline', 'Inline', 'Common',
|
||||||
0 => array('Common'),
|
array(
|
||||||
// 'accesskey' => 'Character',
|
// 'accesskey' => 'Character',
|
||||||
// 'charset' => 'Charset',
|
// 'charset' => 'Charset',
|
||||||
'href' => 'URI',
|
'href' => 'URI',
|
||||||
//'hreflang' => 'LanguageCode',
|
// 'hreflang' => 'LanguageCode',
|
||||||
'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'),
|
'rel' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rel'),
|
||||||
'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'),
|
'rev' => new HTMLPurifier_AttrDef_HTML_LinkTypes('rev'),
|
||||||
//'tabindex' => 'Number',
|
// 'tabindex' => 'Number',
|
||||||
//'type' => 'ContentType',
|
// 'type' => 'ContentType',
|
||||||
|
)
|
||||||
);
|
);
|
||||||
$this->info['a']->content_model = '#PCDATA | Inline';
|
|
||||||
$this->info['a']->content_model_type = 'optional';
|
|
||||||
$this->info['a']->excludes = array('a' => true);
|
$this->info['a']->excludes = array('a' => true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -45,6 +45,56 @@ class HTMLPurifier_HTMLModuleTest extends UnitTestCase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_parseContents() {
|
||||||
|
|
||||||
|
$module = new HTMLPurifier_HTMLModule();
|
||||||
|
|
||||||
|
// pre-defined templates
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('Inline'),
|
||||||
|
array('optional', 'Inline | #PCDATA')
|
||||||
|
);
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('Flow'),
|
||||||
|
array('optional', 'Flow | #PCDATA')
|
||||||
|
);
|
||||||
|
|
||||||
|
// normalization procedures
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('optional: a'),
|
||||||
|
array('optional', 'a')
|
||||||
|
);
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('OPTIONAL :a'),
|
||||||
|
array('optional', 'a')
|
||||||
|
);
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('Optional: a'),
|
||||||
|
array('optional', 'a')
|
||||||
|
);
|
||||||
|
|
||||||
|
// others
|
||||||
|
$this->assertIdentical(
|
||||||
|
$module->parseContents('Optional: a | b | c'),
|
||||||
|
array('optional', 'a | b | c')
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_mergeInAttrIncludes() {
|
||||||
|
|
||||||
|
$module = new HTMLPurifier_HTMLModule();
|
||||||
|
|
||||||
|
$attr = array();
|
||||||
|
$module->mergeInAttrIncludes($attr, 'Common');
|
||||||
|
$this->assertIdentical($attr, array(0 => array('Common')));
|
||||||
|
|
||||||
|
$attr = array('a' => 'b');
|
||||||
|
$module->mergeInAttrIncludes($attr, array('Common', 'Good'));
|
||||||
|
$this->assertIdentical($attr, array('a' => 'b', 0 => array('Common', 'Good')));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
Reference in New Issue
Block a user