CMS: Absatz-Tags aus dem Rich-Text-Editor erscheinen nicht mehr als Text
Der Editor packt eingefügten Text in <p>; Felder wie die FAQ-Antwort gibt die Website als Text aus, die Tags waren sichtbar. Beim Speichern entfernt unwrapParagraphs() die Absätze (ein Absatz ohne <p>, mehrere mit <br><br>, Blockinhalte unverändert). cms_inline() gibt die Felder als bereinigtes Inline-HTML aus – auch schon gespeicherte Texte mit <p> erscheinen sauber, Fett und Hervorhebung werden dargestellt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
07816dce19
commit
451e738c8b
20 changed files with 147 additions and 23 deletions
69
tests/Feature/CmsEditorParagraphsTest.php
Normal file
69
tests/Feature/CmsEditorParagraphsTest.php
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use App\Services\CmsFluxEditorHtmlTransformer;
|
||||
use Database\Seeders\CmsContentSeeder;
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use Livewire\Volt\Volt;
|
||||
|
||||
/**
|
||||
* Der Rich-Text-Editor packt eingefügten Text in <p>; auf der Website erschienen die Tags als
|
||||
* Text, z. B. in der FAQ (12.10.2026).
|
||||
*/
|
||||
it('stores pasted text from the editor without paragraph tags', function (string $editor, string $stored) {
|
||||
expect(CmsFluxEditorHtmlTransformer::unwrapParagraphs($editor))->toBe($stored);
|
||||
})->with([
|
||||
'ein Absatz' => ['<p>Eingefügter Text</p>', 'Eingefügter Text'],
|
||||
'Sonderzeichen' => ['<p>Planung & Montage</p>', 'Planung & Montage'],
|
||||
'fett' => ['<p>Mit <strong>fett</strong></p>', 'Mit <strong>fett</strong>'],
|
||||
'zwei Absätze' => ['<p>Eins</p><p>Zwei</p>', 'Eins<br><br>Zwei'],
|
||||
'leere Absätze' => ['<p>Text</p><p></p><p><br></p>', 'Text'],
|
||||
'Blockinhalt bleibt' => ['<h2>Titel</h2><p>Text</p>', '<h2>Titel</h2><p>Text</p>'],
|
||||
'schon Klartext' => ['Ohne Tags', 'Ohne Tags'],
|
||||
]);
|
||||
|
||||
it('renders cms text inline: plain text escaped, editor html without paragraphs, nothing unsafe', function (string $value, string $html) {
|
||||
expect((string) cms_inline($value))->toBe($html);
|
||||
})->with([
|
||||
['Planung & Montage', 'Planung & Montage'],
|
||||
['<p>Schon gespeichert</p>', 'Schon gespeichert'],
|
||||
['<p>Mit <mark>Hervorhebung</mark></p>', 'Mit <span class="text-secondary">Hervorhebung</span>'],
|
||||
['<p>a</p><p>b</p>', 'a<br><br>b'],
|
||||
['<a href="javascript:alert(1)" onclick="x()">Link</a>', '<a href="#">Link</a>'],
|
||||
['<p><script></p>', ''],
|
||||
]);
|
||||
|
||||
it('saves a pasted faq answer without p tags and shows it cleanly on the page', function () {
|
||||
$this->actingAs(User::factory()->create());
|
||||
$this->seed(CmsContentSeeder::class);
|
||||
$row = CmsContent::query()->where('group', 'faq')->where('key', 'faq')->first();
|
||||
|
||||
$component = Volt::test('admin.cms.content-index')
|
||||
->call('startFieldEdit', $row->id, 'questions');
|
||||
|
||||
$component->set('jsonItems.0.answer', '<p>Neue Antwort aus der Zwischenablage</p>')
|
||||
->call('saveJsonModal');
|
||||
|
||||
expect($row->refresh()->getTranslation('value', 'de')['questions'][0]['answer'])->toBe('Neue Antwort aus der Zwischenablage');
|
||||
|
||||
$page = $this->get('/faq')->assertSuccessful()->getContent();
|
||||
|
||||
expect(substr($page, strpos($page, 'id="faq"')))->toContain('Neue Antwort aus der Zwischenablage')
|
||||
->not->toContain('<p>');
|
||||
});
|
||||
|
||||
it('shows answers that were already stored with p tags without the tags', function () {
|
||||
$this->seed(CmsContentSeeder::class);
|
||||
$row = CmsContent::query()->where('group', 'faq')->where('key', 'faq')->first();
|
||||
$value = $row->getTranslation('value', 'de');
|
||||
$value['questions'][0]['answer'] = '<p>Bereits gespeichert mit Absatz</p>';
|
||||
$row->setTranslation('value', 'de', $value)->save();
|
||||
app(FluxCms\Core\Services\CmsContentService::class)->clearCache('faq');
|
||||
|
||||
$page = $this->get('/faq')->assertSuccessful()->getContent();
|
||||
$section = substr($page, strpos($page, 'id="faq"'));
|
||||
|
||||
expect($section)->toContain('Bereits gespeichert mit Absatz')
|
||||
->not->toContain('<p>')
|
||||
->not->toContain('<p>Bereits');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue