Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom html tags and attributes #68

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 95 additions & 4 deletions EditorJS/BlockHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,18 +243,108 @@ private function getPurifier($allowedTags)

$sanitizer->set('HTML.Allowed', $allowedTags);

/**
* Define custom HTML Definition for mark tool
*/
if ($def = $sanitizer->maybeGetRawHTMLDefinition()) {
$def->addElement('mark', 'Inline', 'Inline', 'Common');
// modify the raw HTML definition
$this->addCustomHTMLDefinitions($def);
}

$purifier = new \HTMLPurifier($sanitizer);

return $purifier;
}

/**
* TODO
*/
private function addCustomHTMLDefinitions($def)
{
if($this->rules->customTags){

// default to be added
$def->addElement('mark', 'Inline', 'Inline', 'Common');

foreach($this->rules->customTags as $tag => $tagData){
/**
* Convenience function that sets up a new element
* @param string $element Name of element to add
* @param string|bool $type What content set should element be registered to?
* Set as false to skip this step.
* @param string|\HTMLPurifier_ChildDef $contents Allowed children in form of:
* "$content_model_type: $content_model"
* @param array|string $attr_includes What attribute collections to register to
* element?
* @param array $attr What unique attributes does the element define?
* @see HTMLPurifier_ElementDef:: for in-depth descriptions of these parameters.
* @return \HTMLPurifier_ElementDef Created element definition object, so you
* can set advanced parameters
*/

/**
* "customTags": {
* "tagName1": {
* "type": "string",
* "contents": "string", (Empty, Inline, Flow)
* "collection": "Common",
* "attributes": {
* "attrName1": "attrType",
* "attrName2": { "type": "Enum", "options": "item1,item2,item3" | ["item","item","item"] }
* "attrName2": { "type": "Number", "options": [bool, bool, bool] }
* }
* }
* }
*/
$def->addElement(
$tag,
$tagData['type'] ?: 'Inline',
$tagData['contents'] ?: 'Inline',
$tagData['collection'] ?: 'Common'
);

// custom attributes
foreach($tagData['attributes'] as $attrName => $attrData){

/**
* [{ name: '', attr: '', type: ''| {} }]
* Adds a custom attribute to a pre-existing element
* @note This is strictly convenience, and does not have a corresponding
* method in HTMLPurifier_HTMLModule
* @param string $element_name Element name to add attribute to
* @param string $attr_name Name of attribute
* @param mixed $def Attribute definition, can be string or object, see
* HTMLPurifier_AttrTypes for details \HTMLPurifier\HTMLPurifier_AttrTypes
*/
if(is_string($attrData)){
// no config options given for attribute type (default)
// Not implemented: in case # is present, the user might have defined it according to HTMLPurifier docs: i.e. Enum#_blank,_self,_target,_top
$def->addAttribute($tag, $attrName, $attrData);
}
elseif(isset($attrData['type'])){
/**
* note the types are case sensitive!
* @see \HTMLPurifier_AttrTypes::class for options
*/
if($attrData['type'] == 'Enum'){
if(is_string($attrData['options'])){
// we assume that the options are comma separated
$options = explode(',', $attrData['options']);
} else{
$options = $attrData['options'];
}
$def->addAttribute($tag, $attrName, $attrData['type'], new \HTMLPurifier_AttrDef_Enum( $options ) );
}
if($attrData['type'] == 'Number'){
$def->addAttribute($tag, $attrName, $attrData['type'], new \HTMLPurifier_AttrDef_Integer(
$attrData['options'][0] ?: true, // negative
$attrData['options'][1] ?: true, // zero
$attrData['options'][2] ?: true // positive
));
}
}
}
}
}
}

/**
* Initialize HTML Purifier with default settings
*/
Expand All @@ -266,6 +356,7 @@ private function getDefaultPurifier()
$sanitizer->set('URI.AllowedSchemes', ['http' => true, 'https' => true, 'mailto' => true, 'tel' => true]);
$sanitizer->set('AutoFormat.RemoveEmpty', true);
$sanitizer->set('HTML.DefinitionID', 'html5-definitions');
$sanitizer->set('HTML.DefinitionRev', time());

$cacheDirectory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'purifier';
if (!is_dir($cacheDirectory)) {
Expand Down
15 changes: 15 additions & 0 deletions EditorJS/ConfigLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
class ConfigLoader
{
public $tools = [];

public $customTags = [];

/**
* ConfigLoader constructor
Expand All @@ -26,6 +28,7 @@ public function __construct($configuration)

$config = json_decode($configuration, true);
$this->loadTools($config);
$this->loadCustomTags($config);
}

/**
Expand Down Expand Up @@ -61,4 +64,16 @@ private function loadTool($data)
{
return $data;
}

/**
* Load custom HTML tags from configuration
*/
private function loadCustomTags($config)
{
if (!isset($config['customTags'])) {
throw new EditorJSException('Custom HTML tags not found in configuration');
}

$this->customTags = $config['customTags'];
}
}
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,43 @@ Another configuration example: [/tests/samples/test-config.json](/tests/samples/

If you connect a new Tool on the frontend-side, then you should create a configuration rule for that Tool to validate it on server-side.

# Custom Tags and Attributes

Sometimes you want to use tags or tag attributes for your tools that are not by default supported by [HTMLPurifier](https://github.com/ezyang/htmlpurifier). For example, by default HTMLPurifier filters out the `<mark>` tag, so we added support to this by default.
You can add additional tags through the config:

```json
{
'tools': {
//
},
'customTags':{

}
}
```

## Setting custom tags

```json
'customTags': {
'tagName1': {
'type': 'string',
'contents': 'string', (Empty, Inline, Flow)
'collection': 'Common',
'attributes': {
'attrName1': 'attrType',
'attrName2': { 'type': 'Enum', 'options': 'item1,item2,item3' | ['item','item','item'] }
'attrName3': { 'type': 'Number', 'options': [bool, bool, bool] }
}
}
}
```

...

## Repository
<a href="https://github.com/codex-editor/editorjs-php/">https://github.com/codex-editor/editorjs-php/</a>
<a href='https://github.com/codex-editor/editorjs-php/'>https://github.com/codex-editor/editorjs-php/</a>


## About CodeX
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
}
],
"require": {
"php": ">=5.6",
"php": ">=7.0",
"ezyang/htmlpurifier": "^4.8"
},
"require-dev": {
"phpunit/phpunit": "5.4.*",
"phpunit/phpunit": ">=5.4",
"friendsofphp/php-cs-fixer": "^2.13"
},
"autoload": {
Expand Down
Loading