ueberdosis / tiptap-php
一个用于处理 Tiptap 输出的 PHP 包
Requires
- php: ^7.4|^8.0
- scrivo/highlight.php: ^9.18
- spatie/shiki-php: ^2.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.5
- pestphp/pest: ^1.21
- phpunit/phpunit: ^9.5
- vimeo/psalm: ^4.3
README
一个用于处理 Tiptap 内容的 PHP 包。您可以转换 Tiptap 兼容的 JSON 到 HTML,反之亦然,清理您的内容,或者只是修改它。
安装
您可以通过 composer 安装此包
composer require ueberdosis/tiptap-php
使用方法
该 PHP 包模仿了 JavaScript 包的大部分功能。如果您熟悉 Tiptap,PHP 语法将非常熟悉。
将 Tiptap HTML 转换为 JSON
让我们从一个 HTML 片段开始,将其转换为具有 Tiptap 兼容结构的 PHP 数组
(new \Tiptap\Editor) ->setContent('<p>Example Text</p>') ->getDocument(); // Returns: // ['type' => 'doc', 'content' => …]
您也可以在 PHP 中获取 JSON 字符串。
(new \Tiptap\Editor) ->setContent('<p>Example Text</p>') ->getJSON(); // Returns: // {"type": "doc", "content": …}
将 Tiptap JSON 转换为 HTML
反之亦然。只需传递一个 JSON 字符串或 PHP 数组以生成 HTML。
(new \Tiptap\Editor) ->setContent([ 'type' => 'doc', 'content' => [ [ 'type' => 'paragraph', 'content' => [ [ 'type' => 'text', 'text' => 'Example Text', ], ] ] ], ]) ->getHTML(); // Returns: // <h1>Example Text</h1>
这并不完全符合 ProseMirror 架构。一些功能也得到支持,例如在 CodeBlock
中不允许标记。
如果您需要更好的架构支持,请创建一个包含您缺失功能的 issue。
使用 highlight.php 为代码块提供语法高亮(需要 Node.js)
默认的 CodeBlock
扩展不会为您的代码块添加语法高亮。但是,如果您想为代码块添加语法高亮,有一个特殊的 CodeBlockHighlight
扩展。
替换默认的一个是这样工作的
(new \Tiptap\Editor([ 'extensions' => [ new \Tiptap\Extensions\StarterKit([ 'codeBlock' => false, ]), new \Tiptap\Nodes\CodeBlockHighlight(), ], ])) ->setContent('<pre><code><?php phpinfo()</code></pre>') ->getHTML(); // Returns: // <pre><code class="hljs php"><span class="hljs-meta"><?php</span> phpinfo()</code></pre>
这仍然是未样式的。您需要 加载一个 CSS 文件 以添加颜色到输出,例如这样
<link rel="stylesheet" href="//unpkg.com/@highlightjs/[email protected]/styles/default.min.css">
Boom,语法高亮!顺便说一句,这是由惊人的 scrivo/highlight.php 驱动的。
使用 Shiki 为代码块提供语法高亮(需要 Node.js)
还有一个使用 Shiki 的替代语法高亮器。Shiki 是一个美丽的语法高亮器,由许多代码编辑器使用的相同语言引擎提供支持。与 CodeBlockHighlight
扩展的主要区别是,1) 您必须安装 shiki
npm 包,2) Shiki 代码高亮通过注入内联样式来实现,因此不需要引入外部 CSS 文件,3) 您可以使用大多数 VS Code 主题来突出显示您的代码。
要使用 Shiki 扩展,首先安装 npm 包
npm install shiki
然后按照下面的示例进行操作
(new \Tiptap\Editor([ 'extensions' => [ new \Tiptap\Extensions\StarterKit([ 'codeBlock' => false, ]), new \Tiptap\Nodes\CodeBlockShiki, ], ])) ->setContent('<pre><code><?php phpinfo()</code></pre>') ->getHTML();
要配置主题或代码块的默认语言,请将附加配置传递给构造函数,如下所示
(new \Tiptap\Editor([ 'extensions' => [ new \Tiptap\Extensions\StarterKit([ 'codeBlock' => false, ]), new \Tiptap\Nodes\CodeBlockShiki([ 'theme' => 'github-dark', // default: nord, see https://github.com/shikijs/shiki/blob/main/docs/themes.md 'defaultLanguage' => 'php' // default: html, see https://github.com/shikijs/shiki/blob/main/docs/languages.md 'guessLanguage' => true // default: true, if the language isn’t passed, it tries to guess the language with highlight.php ]), ], ])) ->setContent('<pre><code><?php phpinfo()</code></pre>') ->getHTML();
在内部,Shiki 扩展使用 Spatie 的 Shiki PHP,因此请参阅文档以获取更多详细信息和注意事项。
将内容转换为纯文本
内容也可以转换为纯文本,例如将其放入搜索索引中。
(new \Tiptap\Editor) ->setContent('<h1>Heading</h1><p>Paragraph</p>') ->getText(); // Returns: // "Heading // // Paragraph"
在块之间可以配置什么。
(new \Tiptap\Editor) ->setContent('<h1>Heading</h1><p>Paragraph</p>') ->getText([ 'blockSeparator' => "\n", ]); // Returns: // "Heading // Paragraph"
清理内容
PHP 包的一个很好的用途是清理(或“清理”)内容。您可以使用 sanitize()
方法完成此操作。它支持 JSON 字符串、PHP 数组和 HTML。
它将返回与输入格式相同的格式。
(new \Tiptap\Editor) ->sanitize('<p>Example Text<script>alert("HACKED!")</script></p>'); // Returns: // '<p>Example Text</p>'
修改内容
使用descendants()
方法,您可以递归地遍历所有节点,就像您从JavaScript包中习惯的那样。但在PHP中,您甚至可以修改节点以更新属性等。
警告:您需要将
&
添加到参数中。这会保持对原始项目的引用,并允许您修改原始项目,而不是仅仅修改一个副本。
$editor->descendants(function (&$node) { if ($node->type !== 'heading') { return; } $node->attrs->level = 1; });
配置
将配置传递给编辑器的构造函数。可配置的内容不多,但至少您可以传递初始内容和加载特定扩展。
new \Tiptap\Editor([ 'content' => '<p>Example Text</p>', 'extensions' => [ new \Tiptap\Extensions\StarterKit, ], ])
默认情况下将加载StarterKit
。如果您只想使用它,则无需设置。
扩展
默认情况下将加载StarterKit
,但您也可以传递一个自定义的扩展数组。
new \Tiptap\Editor([ 'extensions' => [ new \Tiptap\Extensions\StarterKit, new \Tiptap\Marks\Link, ], ])
配置扩展
某些扩展可以进行配置。只需将一个数组传递给构造函数即可。我们旨在支持与JavaScript包相同的配置。
new \Tiptap\Editor([ 'extensions' => [ // … new \Tiptap\Nodes\Heading([ 'levels' => [1, 2, 3], ]), ], ])
您也可以通过配置传递自定义HTML属性。
new \Tiptap\Editor([ 'extensions' => [ // … new \Tiptap\Nodes\Heading([ 'HTMLAttributes' => [ 'class' => 'my-custom-class', ], ]), ], ])
对于StarterKit
,虽然略有不同,但工作方式与您从JavaScript包中习惯的那样相同。
new \Tiptap\Editor([ 'extensions' => [ new Tiptap\Extensions\StarterKit([ 'codeBlock' => false, 'heading' => [ 'HTMLAttributes' => [ 'class' => 'my-custom-class', ], ] ]), ], ])
扩展现有扩展
如果您需要更改支持扩展的细微细节,则可以简单地扩展一个扩展。
<?php class CustomBold extends \Tiptap\Marks\Bold { public function renderHTML($mark) { // Renders <b> instead of <strong> return ['b', 0] } } new \Tiptap\Editor([ 'extensions' => [ new Paragraph, new Text, new CustomBold, ], ])
自定义扩展
您甚至可以构建自定义扩展。如果您习惯了JavaScript API,您会惊讶地发现PHP中也有很多这样的功能。🤯以下是一个简单的示例。
请务必查阅此存储库中的扩展,以了解有关PHP扩展API的更多信息。
<?php use Tiptap\Core\Node; class CustomNode extends Node { public static $name = 'customNode'; public static $priority = 100; public function addOptions() { return [ 'HTMLAttributes' => [], ]; } public function parseHTML() { return [ [ 'tag' => 'my-custom-tag[data-id]', ], [ 'tag' => 'my-custom-tag', 'getAttrs' => function ($DOMNode) { return ! \Tiptap\Utils\InlineStyle::hasAttribute($DOMNode, [ 'background-color' => '#000000', ]) ? null : false; }, ], [ 'style' => 'background-color', 'getAttrs' => function ($value) { return (bool) preg_match('/^(black)$/', $value) ? null : false; }, ], ]; } public function renderHTML($node) { return ['my-custom-tag', ['class' => 'foobar'], 0] } }
扩展优先级
扩展将按降序优先级进行评估。默认情况下,所有节点、标记和扩展都具有100
的优先级值。
当创建节点扩展以匹配可能被其他节点匹配的标记时,应定义优先级。例如,TaskItem节点具有比ListItem节点更高的评估优先级。
测试
composer test
您可以使用nodemon(npm install -g nodemon
)安装测试套件,并监视文件更改以保持其运行。
composer test-watch
贡献
有关详细信息,请参阅CONTRIBUTING。
安全漏洞
请参阅我们的安全策略,了解如何报告安全漏洞。
致谢
许可
MIT许可(MIT)。有关更多信息,请参阅许可文件。