m6web / draftjs-bundle
将 Draft.js 状态渲染为 HTML
Requires
- php: >=5.6
- symfony/framework-bundle: ~2.7|~3.0
- symfony/templating: ~2.8|~3.0
Requires (Dev)
- atoum/atoum: ~2.1
- m6web/coke: ~2.1
- m6web/symfony2-coding-standard: ~3.1
This package is not auto-updated.
Last update: 2020-01-24 16:33:56 UTC
README
DraftjsBundle
此 Symfony 扩展旨在将 Draft.js 状态转换为等效的 PHP 对象模型,并提供必要的工具以渲染 HTML。
安装
此库可以通过 composer 轻松安装
composer require m6web/draftjs-bundle
然后注册此包
# app/AppKernel.php public function registerBundles() { $bundles = array( new M6Web\Bundle\DraftjsBundle\M6WebDraftjsBundle(), ); }
YAML 配置参考
此配置允许您自定义块、内联样式和文本对齐的类名。
m6_web_draftjs: class_names: blocks: # overriding class name of block atomic: 'custom-atomic' default: 'custom-paragraph' list: 'custom-list' heading: 'custom-heading' inline: # define inline styles class name <string>: <string> text_alignment: # define text alignment class name left: 'text-left' center: 'text-center' right: 'text-right'
内联键允许您对内联样式文本的类名进行任何字符串的定制,例如,如果您想定义加粗样式的类名,只需定义以下配置
m6_web_draftjs: class_names: inline: bold: 'u-bold'
对象模型
DraftjsBundle 遵循 Draft.js 对象模型。
ContentState : Represent the document
ContentBlock : Represent a single block
DraftEntity : Represent a Draft.js entity
CharacterMetadata : Represent a character with style and entity
Draft.js 支持
DraftjsBundle 支持以下 Draft.js 块类型,具体如下
- atomic
- unstyled
- paragraph
- unordered-list-item
- ordered-list-item
- header-one
- header-two
- header-three
- header-four
- header-five
- header-six
- blockquote
您可以通过实现自定义渲染器来扩展此列表,如渲染器部分所示
异常
- DraftjsException
ContentStateConverter
将 Draft.js 状态转换为 PHP 模型对象。
m6_web_draftjs.content_state_converter
HtmlBuilder
从 ContentState 对象构建 HTML。
m6_web_draftjs.html_builder
HtmlRenderer
用于将 Draft.js 状态转换为 HTML 的对象。
m6_web_draftjs.html_renderer
渲染器
除了全局 HtmlRenderer 之外,我们还提供了通过添加新渲染器来扩展渲染引擎的可能性。
根据您想要定制的类型,我们区分了三种类型的渲染器:
还有另一种未在此列出的渲染器,即 ContentRenderer,它负责从文本和内联样式渲染块内的 HTML。
您需要做的就是创建一个服务,然后将其标记为预期。
添加自定义块渲染器
首先定义您的服务
# block entity renderers acme_demo.acme_block_renderer: class: Acme\Bundle\DemoBundle\Renderer\Block\AcmeBlockRenderer parent: m6_web_draft_js.abstract_block_renderer calls: - [setBlockClassName, ['block-acme']] tags: - { name: draftjs.block_renderer, alias: draftjs_acme_block_renderer }
为了完全支持我们的渲染引擎,您必须将您的服务标记为 draftjs.block_renderer,并且您必须扩展实现 BlockRendererInterface 接口的 AbstractBlockRenderer。
以 AcmeBlockRenderer 类为例
namespace Acme\Bundle\DemoBundle\Renderer\Block; use M6Web\Bundle\DraftjsBundle\Renderer\Block\AbstractBlockRenderer; use M6Web\Bundle\DraftjsBundle\Model\ContentBlock; class AcmeBlockRenderer extends AbstractBlockRenderer { /** * @param \ArrayIterator $iterator * @param array $entities * * @return string */ public function render(\ArrayIterator &$iterator, array $entities) { // you have acces to the global iterator of ContentBlock // so just get current item by use curent() $contentBlock = $iterator->current(); // if your renderer is handling the current ContentBlock // you must inform the iterator to move to the next entry for next iteration $iterator->next(); // By extending the AbstractBlockRenderer, you can use the ContentRenderer who allow to render inline html $content = $this->contentRenderer->render( $contentBlock->getText(), $contentBlock->getCharacterList(), $entities ); if (!$this->template) { return $content; } // You also have access to the templating engine return $this->templating->render($this->template, [ 'classNames' => $this->buildClassNames($contentBlock), 'content' => $content, ]); } /** * @param string $type * * @return bool */ public function supports($type) { return 'acme' === $type; } /** * @return string */ public function getName() { return 'acme'; } }
添加自定义内联实体渲染器
内联渲染器用于在具有字符串的块内容中显示实体信息。
function createLink() { return DraftEntity.__create('LINK', 'MUTABLE', {uri: 'zombo.com'}); }
首先定义您的服务
acme_demo.link_inline_entity_renderer: class: Acme\Bundle\DemoBundle\Renderer\Inline\LinkInlineEntityRenderer calls: - [setClassName, ['u-link']] tags: - { name: draftjs.inline_entity_renderer, alias: draftjs_link_inline_entity_renderer }
为了完全支持我们的渲染引擎,您必须使用 draftjs.inline_entity_renderer 标签您的服务,并且必须扩展实现 InlineEntityRendererInterface 接口的 AbstractInlineEntityRenderer。
以 LinkInlineEntityRenderer 类为例
namespace Acme\Bundle\DemoBundle\Renderer\Inline; use M6Web\Bundle\DraftjsBundle\Renderer\Inline\AbstractInlineEntityRenderer; use M6Web\Bundle\DraftjsBundle\Renderer\Helper\InlineRendererHelperTrait; use M6Web\Bundle\DraftjsBundle\Model\DraftEntity; class LinkInlineEntityRenderer extends AbstractInlineEntityRenderer { const TAG_NAME = 'a'; use InlineRendererHelperTrait; /** * @param DraftEntity $entity * * @return string */ public function openTag(DraftEntity $entity) { $data = $entity->getData(); $attributes = []; if (isset($data['url'])) { $attributes['href'] = $data['url']; } if (isset($data['target']) && '_self' !== $data['target']) { $attributes['target'] = $data['target']; } if (isset($data['nofollow']) && true === $data['nofollow']) { $attributes['rel'] = 'nofollow'; } if ($this->className) { $attributes['class'] = $this->className; } return $this->openNode(self::TAG_NAME, $attributes); } /** * @return string */ public function closeTag() { return $this->closeNode(self::TAG_NAME); } /** * @param string $type * * @return bool */ public function supports($type) { return 'link' === $type; } /** * @return string */ public function getName() { return 'link'; } }
注意使用了 InlineRendererHelperTrait
添加自定义块实体渲染器
实体块渲染器用于以块的形式显示实体信息。
首先定义您的服务
acme_demo.acme_block_entity_renderer: class: Acme\Bundle\DemoBundle\Renderer\Entity\AcmeBlockEntityRenderer parent: m6_web_draft_js.abstract_block_entity_renderer calls: - [setClassName, ['block-entity-acme']] tags: - { name: draftjs.block_entity_renderer, alias: draftjs_acme_block_entity_renderer }
为了完全支持我们的渲染引擎,您必须使用 draftjs.block_entity_renderer 标签您的服务,并且必须扩展实现 BlockEntityRendererInterface 接口的 AbstractBlockEntityRenderer。
以 LinkInlineEntityRenderer 类为例
namespace Acme\Bundle\DemoBundle\Renderer\Entity; use M6Web\Bundle\DraftjsBundle\Renderer\Entity\AbstractBlockEntityRenderer; use M6Web\Bundle\DraftjsBundle\Model\DraftEntity; class AcmeBlockEntityRenderer extends AbstractBlockEntityRenderer { /** * @param DraftEntity $entity * * @return string */ public function render(DraftEntity $entity) { // generate content from the entity data $content = 'content of your acme block'; return $this->templating->render($this->getTemplate(), [ 'className' => $this->getClassName(), 'content' => $content, ]); } /** * @param string $type * * @return bool */ public function supports($type) { return 'acme' === $type; } /** * @return string */ public function getName() { return 'acme'; } }
辅助工具
内联渲染器辅助工具
trait InlineRendererHelperTrait { /** * @param $tagName * @param array $attributes * * @return string */ protected function openNode($tagName, array $attributes = []) { $strAttributes = $this->buildAttributes($attributes); return sprintf('<%s%s>', $tagName, $strAttributes); } /** * @param $tagName * * @return string */ protected function closeNode($tagName) { return sprintf('</%s>', $tagName); } /** * Convert an array of attributes in string like http_build_query * * @param array $attributes * * @return string */ protected function buildAttributes(array $attributes = []) { $strAttributes = array_map(function ($key) use ($attributes) { return sprintf('%s="%s"', $key, $attributes[$key]); }, array_keys(array_filter($attributes))); if (!$strAttributes) { return ''; } return sprintf(' %s', implode(' ', $strAttributes)); } }
块渲染器辅助工具
trait BlockRendererHelperTrait { /** * Get text alignment from content block data * * @param ContentBlock $contentBlock * * @return null */ protected function getTextAlignment(ContentBlock $contentBlock) { $data = $contentBlock->getData(); if (isset($data['textAlignment'])) { return $data['textAlignment']; } return null; } /** * Build string class names from block and text alignment class names * * @param ContentBlock $contentBlock * * @return string */ protected function buildClassNames(ContentBlock $contentBlock) { $textAlignment = $this->getTextAlignment($contentBlock); $classNames = [ $this->getBlockClassName(), ]; if ($textAlignment) { $classNames[] = $this->getTextAlignmentClassName($textAlignment); } return implode(' ', $classNames); } }