Fix rich editor image preview URLs
This commit is contained in:
@@ -207,7 +207,7 @@ class ManageGuidePages extends Page
|
||||
$page = $this->getRecord()->pages()->findOrFail($arguments['id']);
|
||||
$form->fill([
|
||||
'title' => $page->title,
|
||||
'content' => $page->content,
|
||||
'content' => $page->normalized_content,
|
||||
'options' => $page->options ?? [],
|
||||
]);
|
||||
})
|
||||
@@ -267,6 +267,8 @@ class ManageGuidePages extends Page
|
||||
->fileAttachmentsDisk('public')
|
||||
->fileAttachmentsDirectory('guide-pages')
|
||||
->fileAttachmentsVisibility('public')
|
||||
->getUploadedAttachmentUrlUsing(fn (string $file): string => GuidePage::uploadedAttachmentUrl($file))
|
||||
->dehydrateStateUsing(fn (?string $state): string => GuidePage::normalizeRichTextContent($state))
|
||||
->columnSpanFull(),
|
||||
|
||||
Forms\Components\TagsInput::make('options')
|
||||
|
||||
@@ -30,6 +30,35 @@ class GuidePage extends Model
|
||||
return route('guides.pages.show', $this->id);
|
||||
}
|
||||
|
||||
public function getNormalizedContentAttribute(): string
|
||||
{
|
||||
return static::normalizeRichTextContent($this->content);
|
||||
}
|
||||
|
||||
public static function normalizeRichTextContent(?string $content): string
|
||||
{
|
||||
if (blank($content)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$content = preg_replace_callback(
|
||||
'~(?:https?:)?//[^"\'\s<>()]+(?<path>/storage/guide-pages/[^"\'\s<>()]*)~i',
|
||||
static fn (array $matches): string => $matches['path'],
|
||||
$content,
|
||||
) ?? $content;
|
||||
|
||||
return preg_replace(
|
||||
'~(?<=["\'])storage/guide-pages/~i',
|
||||
'/storage/guide-pages/',
|
||||
$content,
|
||||
) ?? $content;
|
||||
}
|
||||
|
||||
public static function uploadedAttachmentUrl(string $path): string
|
||||
{
|
||||
return '/storage/'.ltrim($path, '/');
|
||||
}
|
||||
|
||||
public function guide()
|
||||
{
|
||||
return $this->belongsTo(Guide::class);
|
||||
@@ -62,5 +91,4 @@ class GuidePage extends Model
|
||||
{
|
||||
return ! $this->incomingEdges()->exists();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<body>
|
||||
<article>
|
||||
<h1>{{ $page->title }}</h1>
|
||||
{!! $page->content !!}
|
||||
{!! $page->normalized_content !!}
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
40
tests/Unit/GuidePageContentTest.php
Normal file
40
tests/Unit/GuidePageContentTest.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
use App\Models\GuidePage;
|
||||
|
||||
it('normalizes uploaded guide image urls for rendering', function () {
|
||||
$page = new GuidePage([
|
||||
'content' => <<<'HTML'
|
||||
<figure data-trix-attachment='{"url":"http://localhost:8000/storage/guide-pages/example.png?signature=abc"}'>
|
||||
<img src="http://localhost:8000/storage/guide-pages/example.png?signature=abc">
|
||||
</figure>
|
||||
HTML,
|
||||
]);
|
||||
|
||||
expect($page->normalized_content)
|
||||
->toContain('/storage/guide-pages/example.png?signature=abc')
|
||||
->not->toContain('http://localhost:8000/storage/guide-pages/example.png?signature=abc');
|
||||
});
|
||||
|
||||
it('adds a leading slash to relative guide image urls', function () {
|
||||
$page = new GuidePage([
|
||||
'content' => '<img src="storage/guide-pages/example.png">',
|
||||
]);
|
||||
|
||||
expect($page->normalized_content)
|
||||
->toBe('<img src="/storage/guide-pages/example.png">');
|
||||
});
|
||||
|
||||
it('keeps external image urls unchanged', function () {
|
||||
$page = new GuidePage([
|
||||
'content' => '<img src="https://example.com/images/example.png">',
|
||||
]);
|
||||
|
||||
expect($page->normalized_content)
|
||||
->toBe('<img src="https://example.com/images/example.png">');
|
||||
});
|
||||
|
||||
it('builds root relative upload urls for new attachments', function () {
|
||||
expect(GuidePage::uploadedAttachmentUrl('guide-pages/example.png'))
|
||||
->toBe('/storage/guide-pages/example.png');
|
||||
});
|
||||
Reference in New Issue
Block a user