Skip to content

Commit bf1546b

Browse files
committed
hide trix related fields and remove it before save
1 parent 2f1c001 commit bf1546b

File tree

8 files changed

+4901
-1
lines changed

8 files changed

+4901
-1
lines changed

package-lock.json

Lines changed: 4652 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/css/fields.css

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* Hide Trix caption field for RichEditor when hideCaptions is enabled */
2+
3+
/* Target the specific figcaption with attachment__caption class */
4+
[data-hide-captions="true"] figcaption.attachment__caption {
5+
display: none !important;
6+
}
7+
8+
/* Target figcaption with data-trix-placeholder attribute */
9+
[data-hide-captions="true"] figcaption[data-trix-placeholder] {
10+
display: none !important;
11+
}
12+
13+
/* Target any figcaption within the editor area */
14+
[data-hide-captions="true"] .trix-content figcaption,
15+
[data-hide-captions="true"] .trix-editor figcaption,
16+
[data-hide-captions="true"] .fi-fo-rich-editor figcaption {
17+
display: none !important;
18+
}
19+
20+
/* Target Filament's rich editor container */
21+
[data-hide-captions="true"] .fi-fo-rich-editor .trix-content figcaption,
22+
[data-hide-captions="true"] .fi-fo-rich-editor .trix-editor figcaption {
23+
display: none !important;
24+
}
25+
26+
/* More specific targeting for the attachment caption */
27+
[data-hide-captions="true"] .trix-content figure figcaption.attachment__caption,
28+
[data-hide-captions="true"] .trix-editor figure figcaption.attachment__caption {
29+
display: none !important;
30+
}
31+
32+
/* Hide the caption input field that appears when uploading images */
33+
[data-hide-captions="true"] .trix-content figcaption input,
34+
[data-hide-captions="true"] .trix-content figcaption textarea {
35+
display: none !important;
36+
}
37+
38+
/* Alternative selectors for different Trix versions */
39+
[data-hide-captions="true"] .trix-content .attachment__caption,
40+
[data-hide-captions="true"] .trix-content .attachment__name,
41+
[data-hide-captions="true"] .trix-content .attachment__size {
42+
display: none !important;
43+
}
44+
45+
/* Hide caption fields in the editor */
46+
[data-hide-captions="true"] .trix-content [data-trix-content-type] figcaption {
47+
display: none !important;
48+
}
49+
50+
/* Hide any caption-related elements */
51+
[data-hide-captions="true"] .trix-content .caption,
52+
[data-hide-captions="true"] .trix-content .image-caption {
53+
display: none !important;
54+
}
55+
56+
/* Global targeting for any figcaption when hideCaptions is enabled */
57+
[data-hide-captions="true"] figcaption {
58+
display: none !important;
59+
}

resources/css/index.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
@import '../../vendor/filament/filament/resources/css/theme.css';
2+
@import './fields.css';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace Backstage\Fields\Concerns;
4+
5+
use Backstage\Fields\Services\ContentCleaningService;
6+
7+
trait HasContentCleaning
8+
{
9+
/**
10+
* Boot the trait and add model events
11+
*/
12+
protected static function bootHasContentCleaning()
13+
{
14+
static::saving(function ($model) {
15+
$model->cleanRichEditorFields();
16+
});
17+
}
18+
19+
/**
20+
* Clean RichEditor fields automatically
21+
*/
22+
protected function cleanRichEditorFields(): void
23+
{
24+
$richEditorFields = $this->getRichEditorFields();
25+
26+
foreach ($richEditorFields as $field) {
27+
if (isset($this->attributes[$field]) && !empty($this->attributes[$field])) {
28+
$this->attributes[$field] = ContentCleaningService::cleanRichEditorContent($this->attributes[$field]);
29+
}
30+
}
31+
}
32+
33+
/**
34+
* Get the list of RichEditor fields to clean
35+
* Override this method in your model to specify which fields should be cleaned
36+
*/
37+
protected function getRichEditorFields(): array
38+
{
39+
// Default implementation - override in your model
40+
return [];
41+
}
42+
43+
/**
44+
* Clean a specific field manually
45+
*/
46+
public function cleanField(string $fieldName): void
47+
{
48+
if (isset($this->attributes[$fieldName]) && !empty($this->attributes[$fieldName])) {
49+
$this->attributes[$fieldName] = ContentCleaningService::cleanRichEditorContent($this->attributes[$fieldName]);
50+
}
51+
}
52+
53+
/**
54+
* Clean content with custom options
55+
*/
56+
public function cleanFieldWithOptions(string $fieldName, array $options = []): void
57+
{
58+
if (isset($this->attributes[$fieldName]) && !empty($this->attributes[$fieldName])) {
59+
$this->attributes[$fieldName] = ContentCleaningService::cleanHtmlContent($this->attributes[$fieldName], $options);
60+
}
61+
}
62+
}

src/Fields/RichEditor.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
use Backstage\Enums\ToolbarButton;
66
use Backstage\Fields\Contracts\FieldContract;
7+
<<<<<<< Updated upstream
78
use Backstage\Fields\Models\Field;
89
use Filament\Forms;
10+
=======
11+
use Backstage\Fields\Services\ContentCleaningService;
12+
>>>>>>> Stashed changes
913
use Filament\Forms\Components\RichEditor as Input;
1014

1115
class RichEditor extends Base implements FieldContract
@@ -17,6 +21,8 @@ public static function getDefaultConfig(): array
1721
'disableGrammarly' => false,
1822
'toolbarButtons' => ['attachFiles', 'blockquote', 'bold', 'bulletList', 'codeBlock', 'h2', 'h3', 'italic', 'link', 'orderedList', 'redo', 'strike', 'underline', 'undo'],
1923
'disableToolbarButtons' => [],
24+
'autoCleanContent' => true,
25+
'preserveCustomCaptions' => false,
2026
];
2127
}
2228

@@ -29,6 +35,19 @@ public static function make(string $name, ?Field $field = null): Input
2935
->disableGrammarly($field->config['disableGrammarly'] ?? self::getDefaultConfig()['disableGrammarly'])
3036
->disableToolbarButtons($field->config['disableToolbarButtons'] ?? self::getDefaultConfig()['disableToolbarButtons']);
3137

38+
// Add content processing to automatically clean HTML
39+
$autoCleanContent = $field->config['autoCleanContent'] ?? self::getDefaultConfig()['autoCleanContent'];
40+
41+
if ($autoCleanContent) {
42+
$input->afterStateUpdated(function ($state) use ($field) {
43+
$options = [
44+
'preserveCustomCaptions' => $field->config['preserveCustomCaptions'] ?? self::getDefaultConfig()['preserveCustomCaptions'],
45+
];
46+
47+
return ContentCleaningService::cleanHtmlContent($state, $options);
48+
});
49+
}
50+
3251
return $input;
3352
}
3453

@@ -57,6 +76,16 @@ public function getForm(): array
5776
->multiple()
5877
->options(ToolbarButton::array())
5978
->columnSpanFull(),
79+
Toggle::make('config.autoCleanContent')
80+
->label(__('Auto-clean content'))
81+
->helperText(__('Automatically remove figcaption and unwrap images from links'))
82+
->default(true)
83+
->columnSpanFull(),
84+
Toggle::make('config.preserveCustomCaptions')
85+
->label(__('Preserve custom captions'))
86+
->helperText(__('Only remove default captions, keep custom ones'))
87+
->default(false)
88+
->columnSpanFull(),
6089
]),
6190
]),
6291
])->columnSpanFull(),

src/FieldsServiceProvider.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ protected function getAssets(): array
107107
{
108108
return [
109109
// AlpineComponent::make('fields', __DIR__ . '/../resources/dist/components/fields.js'),
110-
// Css::make('fields-styles', __DIR__ . '/../resources/dist/fields.css'),
110+
Css::make('fields-styles', __DIR__ . '/../resources/css/fields.css'),
111111
// Js::make('fields-scripts', __DIR__ . '/../resources/dist/fields.js'),
112112
];
113113
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
namespace Backstage\Fields\Services;
4+
5+
class ContentCleaningService
6+
{
7+
/**
8+
* Clean HTML content by removing figcaption elements and unwrapping img tags from anchor links
9+
*/
10+
public static function cleanRichEditorContent(?string $content): ?string
11+
{
12+
if (empty($content)) {
13+
return $content;
14+
}
15+
16+
// Remove figcaption elements completely
17+
$content = preg_replace('/<figcaption[^>]*>.*?<\/figcaption>/is', '', $content);
18+
19+
// Unwrap img tags from anchor links, keeping only the img tag
20+
$content = preg_replace('/<a[^>]*>(<img[^>]*>).*?<\/a>/is', '$1', $content);
21+
22+
// Clean up any empty figure tags that might be left
23+
$content = preg_replace('/<figure[^>]*>\s*<\/figure>/is', '', $content);
24+
25+
// Clean up any empty figure tags that only contain img
26+
$content = preg_replace('/<figure[^>]*>(<img[^>]*>)<\/figure>/is', '$1', $content);
27+
28+
return $content;
29+
}
30+
31+
/**
32+
* Clean HTML content with more specific options
33+
*/
34+
public static function cleanHtmlContent(?string $content, array $options = []): ?string
35+
{
36+
if (empty($content)) {
37+
return $content;
38+
}
39+
40+
$defaultOptions = [
41+
'removeFigcaption' => true,
42+
'unwrapImages' => true,
43+
'removeEmptyFigures' => true,
44+
'preserveCustomCaptions' => false, // If true, only remove default captions
45+
];
46+
47+
$options = array_merge($defaultOptions, $options);
48+
49+
if ($options['removeFigcaption']) {
50+
if ($options['preserveCustomCaptions']) {
51+
// Only remove figcaption if it contains default content (filename and size)
52+
$content = preg_replace('/<figcaption[^>]*>\s*<span[^>]*class="[^"]*attachment__name[^"]*"[^>]*>.*?<\/span>\s*<span[^>]*class="[^"]*attachment__size[^"]*"[^>]*>.*?<\/span>\s*<\/figcaption>/is', '', $content);
53+
} else {
54+
// Remove all figcaption elements
55+
$content = preg_replace('/<figcaption[^>]*>.*?<\/figcaption>/is', '', $content);
56+
}
57+
}
58+
59+
if ($options['unwrapImages']) {
60+
// Unwrap img tags from anchor links, keeping only the img tag
61+
$content = preg_replace('/<a[^>]*>(<img[^>]*>).*?<\/a>/is', '$1', $content);
62+
}
63+
64+
if ($options['removeEmptyFigures']) {
65+
// Clean up any empty figure tags that might be left
66+
$content = preg_replace('/<figure[^>]*>\s*<\/figure>/is', '', $content);
67+
68+
// Clean up any figure tags that only contain img
69+
$content = preg_replace('/<figure[^>]*>(<img[^>]*>)<\/figure>/is', '$1', $content);
70+
}
71+
72+
return $content;
73+
}
74+
}

src/helpers.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
use Backstage\Fields\Services\ContentCleaningService;
4+
5+
if (!function_exists('clean_rich_editor_content')) {
6+
/**
7+
* Clean RichEditor content by removing figcaption and unwrapping images from links
8+
*/
9+
function clean_rich_editor_content(?string $content): ?string
10+
{
11+
return ContentCleaningService::cleanRichEditorContent($content);
12+
}
13+
}
14+
15+
if (!function_exists('clean_html_content')) {
16+
/**
17+
* Clean HTML content with custom options
18+
*/
19+
function clean_html_content(?string $content, array $options = []): ?string
20+
{
21+
return ContentCleaningService::cleanHtmlContent($content, $options);
22+
}
23+
}

0 commit comments

Comments
 (0)