Skip to content

Commit

Permalink
Merge pull request #59 from tonysm/tm/attachment-html-content
Browse files Browse the repository at this point in the history
HTML Content Attachments
  • Loading branch information
tonysm authored Oct 14, 2024
2 parents bc9b0b4 + 8096a0f commit 3cd2b3d
Show file tree
Hide file tree
Showing 13 changed files with 75 additions and 87 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
<figure class="attachment attachment--content">
{!! trim($content->renderTrixContentAttachment($options)) !!}
</figure>
1 change: 0 additions & 1 deletion resources/views/contents/_horizontal_rule.blade.php

This file was deleted.

2 changes: 1 addition & 1 deletion src/AttachableFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static function fromNode(DOMElement $node): Attachables\AttachableContrac
return $attachable;
}

return new Attachables\MissingAttachable();
return new Attachables\MissingAttachable;
}

private static function attachableFromSgid(string $sgid)
Expand Down
57 changes: 24 additions & 33 deletions src/Attachables/ContentAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,77 +3,68 @@
namespace Tonysm\RichTextLaravel\Attachables;

use DOMElement;
use Illuminate\Support\Str;
use Tonysm\RichTextLaravel\Content;

class ContentAttachment implements AttachableContract
{
const NAME_PATTERN = '/vnd\.richtextlaravel\.(.+)\.html/';
private Content $contentInstance;

public static $validNames = ['horizontal-rule'];
private string $renderedHtml;

public static function fromNode(DOMElement $node): ?static
{
if (! $node->hasAttribute('content-type')) {
if (! $node->hasAttribute('content-type') || ! $node->hasAttribute('content')) {
return null;
}

if (! preg_match(static::NAME_PATTERN, $node->getAttribute('content-type'), $matches)) {
return null;
}

$name = $matches[1];
$contentType = $node->getAttribute('content-type');
$content = trim($node->getAttribute('content'));

if (! $name || ! static::validName($name)) {
return null;
if (str_contains($contentType, 'html') && ! empty($content)) {
return new static($contentType, $content);
}

return new static($name);
}

private static function validName(string $name): bool
{
return in_array($name, static::$validNames);
}

public function __construct(public $name)
{
}
public function __construct(
public string $contentType,
public string $content,
) {}

public function toRichTextAttributes(array $attributes): array
{
return [
'content' => $this->renderTrixContentAttachment(),
'contentType' => $this->contentType,
'content' => $this->content,
];
}

public function equalsToAttachable(AttachableContract $attachable): bool
{
return $attachable instanceof static
&& $attachable->name === $this->name;
&& $attachable->contentType === $this->contentType
&& $attachable->content === $this->content;
}

public function richTextAsPlainText(): string
{
if ($this->name === 'horizontal-rule') {
return '';
}

return ' ';
return $this->contentInstance()->fragment->source->textContent;
}

public function richTextRender(array $options = []): string
{
return view('rich-text-laravel::contents._content', [
return view('rich-text-laravel::attachables._content', [
'content' => $this,
'options' => $options,
])->render();
}

public function renderTrixContentAttachment(array $options = []): string
{
return view('rich-text-laravel::contents._'.Str::of($this->name)->studly()->snake('_'), [
'content' => $this,
'options' => $options,
])->render();
return $this->renderedHtml ??= $this->contentInstance()->fragment->toHtml();
}

private function contentInstance(): Content
{
return $this->contentInstance ??= new Content($this->content);
}
}
6 changes: 2 additions & 4 deletions src/Attachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Attachment

public static $SELECTOR = '//rich-text-attachment';

const ATTRIBUTES = ['sgid', 'content-type', 'url', 'href', 'filename', 'filesize', 'width', 'height', 'previewable', 'presentation', 'caption'];
const ATTRIBUTES = ['sgid', 'content-type', 'url', 'href', 'filename', 'filesize', 'width', 'height', 'previewable', 'presentation', 'caption', 'content'];

private $cachedAttributes;

Expand Down Expand Up @@ -79,9 +79,7 @@ private static function processAttributes(array $attributes): array
->all();
}

public function __construct(public DOMElement $node, public AttachableContract $attachable)
{
}
public function __construct(public DOMElement $node, public AttachableContract $attachable) {}

public function withFullAttributes(): static
{
Expand Down
4 changes: 1 addition & 3 deletions src/AttachmentGallery.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ public static function selector(): string
);
}

public function __construct(public DOMElement $node)
{
}
public function __construct(public DOMElement $node) {}

public function attachments(): Collection
{
Expand Down
2 changes: 1 addition & 1 deletion src/Commands/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,6 @@ protected static function updateNodePackages(callable $callback, $dev = true)

private function phpBinary()
{
return (new PhpExecutableFinder())->find(false) ?: 'php';
return (new PhpExecutableFinder)->find(false) ?: 'php';
}
}
4 changes: 1 addition & 3 deletions src/Fragment.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,7 @@ public static function fromHtml(?string $html = null): self
return HtmlConversion::fragmentForHtml($html);
}

public function __construct(public DOMDocument $source)
{
}
public function __construct(public DOMDocument $source) {}

public function findAll(string $selector): Collection
{
Expand Down
7 changes: 3 additions & 4 deletions src/TrixAttachment.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use DOMElement;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class TrixAttachment
Expand Down Expand Up @@ -56,9 +57,7 @@ private static function typeCast(string $key, $value)
};
}

public function __construct(public DOMElement $node)
{
}
public function __construct(public DOMElement $node) {}

public function attributes(): array
{
Expand Down Expand Up @@ -93,7 +92,7 @@ private function readJsonAttribute(string $key): array
$data = json_decode($value ?: '[]', true);

if (json_last_error() !== JSON_ERROR_NONE) {
logger(sprintf(
Log::notice(sprintf(
'[%s] Couldnt parse JSON %s from NODE %s',
static::class,
$value,
Expand Down
53 changes: 23 additions & 30 deletions tests/ContentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Tonysm\RichTextLaravel\Tests;

use Illuminate\Support\Facades\Log;
use Tonysm\RichTextLaravel\Attachables\ContentAttachment;
use Tonysm\RichTextLaravel\Attachables\MissingAttachable;
use Tonysm\RichTextLaravel\Attachables\RemoteImage;
use Tonysm\RichTextLaravel\Attachment;
Expand Down Expand Up @@ -208,6 +210,8 @@ public function converts_trix_formatetd_attachments_with_custom_tag_name()
/** @test */
public function ignores_trix_formatteed_attachments_with_bad_json()
{
Log::shouldReceive('notice')->once();

$html = <<<'HTML'
<div data-trix-attachment='{"sgid": "pure garbate...}'></div>
HTML;
Expand Down Expand Up @@ -505,44 +509,28 @@ public function renders_file_attachments()
}

/** @test */
public function renders_horizontal_rules_as_content_attachment()
public function renders_html_content_attachment()
{
$content = $this->fromHtml(<<<'HTML'
<div>
<figure
data-trix-attachment='{"contentType": "vnd.richtextlaravel.horizontal-rule.html", "content": "<hr>"}'
>
<hr>
</figure>
</div>
HTML);
$attachment = $this->attachmentFromHtml('<rich-text-attachment content-type="text/html" content="abc"></rich-text-attachment>');
$attachable = $attachment->attachable;

$this->assertEquals(<<<'HTML'
<div>
<hr>
$this->assertInstanceOf(ContentAttachment::class, $attachable);
$this->assertEquals('text/html', $attachable->contentType);
$this->assertEquals('abc', $attachable->content);

</div>
HTML, $content->renderWithAttachments());
$trixAttachment = $attachment->toTrixAttachment();
$this->assertEquals('text/html', $trixAttachment->attributes()['contentType']);
$this->assertEquals('abc', $trixAttachment->attributes()['content']);
}

/** @test */
public function renders_horizontal_rules_for_trix()
public function renders_content_attachment()
{
$content = $this->fromHtml(<<<'HTML'
<div>
<figure
data-trix-attachment='{"contentType": "vnd.richtextlaravel.horizontal-rule.html", "content": "<hr>"}'
>
<hr>
</figure>
</div>
HTML);
$attachment = $this->attachmentFromHtml('<rich-text-attachment content-type="text/html" content="&lt;p&gt;abc&lt;/p&gt;"></rich-text-attachment>');
/** @var ContentAttachment $attachable */
$attachable = $attachment->attachable;

$this->assertEquals(<<<'HTML'
<div>
<figure data-trix-attachment='{"contentType":"vnd.richtextlaravel.horizontal-rule.html","content":"&lt;hr&gt;\n"}'></figure>
</div>
HTML, $content->toTrixHtml());
$this->assertEquals('<p>abc</p>', $attachable->renderTrixContentAttachment());
}

/** @test */
Expand Down Expand Up @@ -584,6 +572,11 @@ private function fromHtml(string $html): Content
{
return tap(new Content($html), fn (Content $content) => $this->assertNotEmpty($content->toHtml()));
}

private function attachmentFromHtml(string $html): Attachment
{
return $this->fromHtml($html)->attachments()->first();
}
}

class UserWithCustomRenderContent extends User
Expand Down
17 changes: 14 additions & 3 deletions tests/PlainTextConversionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,25 @@ public function handles_deeply_nested()
}

/** @test */
public function converts_horizontal_rule_to_plain_text()
public function converts_html_content()
{
$this->assertConvertedTo(
"Hello\n\n\n\nWorld",
"Hello\n\n\n\nWorld",
trim(<<<'HTML'
<div>Hello</div>
<br>
<figure data-trix-attachment='{"contentType": "vnd.richtextlaravel.horizontal-rule.html", "content": "<hr>"}'></figure>
<figure data-trix-attachment='{"contentType": "text/html", "content": "<hr>"}'></figure>
<br>
<div>World</div>
HTML)
);

$this->assertConvertedTo(
"Hello\n\n\nhello\nWorld",
trim(<<<'HTML'
<div>Hello</div>
<br>
<figure data-trix-attachment='{"contentType": "text/html", "content": "<p>hello</p>"}'></figure>
<br>
<div>World</div>
HTML)
Expand Down
4 changes: 2 additions & 2 deletions workbench/app/Html/SanitizerFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ private static function configFor($config = null): HtmlSanitizerConfig

private static function defaultConfig(): HtmlSanitizerConfig
{
return (new HtmlSanitizerConfig())
return (new HtmlSanitizerConfig)
->allowSafeElements()
->allowAttribute('class', '*');
}

private static function minimalConfig(): HtmlSanitizerConfig
{
return (new HtmlSanitizerConfig())
return (new HtmlSanitizerConfig)
->allowElement('br')
->allowElement('div')
->allowElement('p')
Expand Down
3 changes: 1 addition & 2 deletions workbench/app/Models/Opengraph/OpengraphEmbed.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ public function __construct(
public $url,
public $filename,
public $description,
) {
}
) {}

public function toRichTextAttributes(array $attributes): array
{
Expand Down

0 comments on commit 3cd2b3d

Please sign in to comment.