@@ -29,104 +29,107 @@ public static function getDefaultConfig(): array
2929
3030 public static function make (string $ name , ?Field $ field = null ): Input
3131 {
32- /**
33- * @var Input $input
34- */
35- $ input = self ::applyDefaultSettings (Input::make ($ name ), $ field );
36-
37- $ input = $ input ->label ($ field ->name ?? null )
38- ->toolbarButtons ([$ field ->config ['toolbarButtons ' ] ?? self ::getDefaultConfig ()['toolbarButtons ' ]])
39- ->disableToolbarButtons ($ field ->config ['disableToolbarButtons ' ] ?? self ::getDefaultConfig ()['disableToolbarButtons ' ])
32+ $ input = self ::createBaseInput ($ name , $ field );
33+ $ input = self ::configureToolbarButtons ($ input , $ field );
34+ $ input = self ::configureStateHandling ($ input , $ name );
35+ $ input = self ::configureCaptions ($ input , $ field );
36+
37+ return $ input ;
38+ }
39+
40+ private static function createBaseInput (string $ name , ?Field $ field ): Input
41+ {
42+ return self ::applyDefaultSettings (Input::make ($ name ), $ field )
43+ ->label ($ field ->name ?? null )
4044 ->default (null )
4145 ->placeholder ('' )
4246 ->statePath ($ name )
4347 ->live ()
4448 ->json (false )
4549 ->beforeStateDehydrated (function () {})
46- ->saveRelationshipsUsing (function () {})
47- ->formatStateUsing (function ($ state ) {
48- if (empty ($ state )) {
49- return null ;
50- }
51-
52- if (is_string ($ state )) {
53- $ decoded = json_decode ($ state , true );
54- if (json_last_error () === JSON_ERROR_NONE && is_array ($ decoded )) {
55- return $ decoded ;
56- }
57-
58- return $ state ;
59- }
60-
61- if (is_array ($ state )) {
62- if (isset ($ state [0 ]) && is_array ($ state [0 ]) && isset ($ state [0 ]['type ' ]) && $ state [0 ]['type ' ] === 'doc ' ) {
63- $ state = $ state [0 ];
64- }
65-
66- if (isset ($ state ['content ' ]) && is_array ($ state ['content ' ])) {
67- $ content = $ state ['content ' ];
68- if (count ($ content ) > 0 && is_array ($ content [0 ]) && empty ($ content [0 ])) {
69- $ state ['content ' ] = [];
70- }
71- }
72-
73- if (! isset ($ state ['type ' ]) || $ state ['type ' ] !== 'doc ' ) {
74- return null ;
75- }
76-
77- if (! isset ($ state ['content ' ]) || ! is_array ($ state ['content ' ])) {
78- $ state ['content ' ] = [];
79- }
80-
81- return $ state ;
82- }
83-
84- return null ;
85- })
86-
87- ->dehydrateStateUsing (function ($ state ) {
88- if (empty ($ state )) {
89- return null ;
90- }
91-
92- if (is_string ($ state )) {
93- return $ state ;
94- }
95-
96- if (is_array ($ state )) {
97- if (isset ($ state [0 ]) && is_array ($ state [0 ]) && isset ($ state [0 ]['type ' ]) && $ state [0 ]['type ' ] === 'doc ' ) {
98- $ state = $ state [0 ];
99- }
100-
101- if (isset ($ state ['content ' ]) && is_array ($ state ['content ' ])) {
102- $ content = $ state ['content ' ];
103- if (count ($ content ) > 0 && is_array ($ content [0 ]) && empty ($ content [0 ])) {
104- $ state ['content ' ] = [];
105- }
106- }
107-
108- if (! isset ($ state ['type ' ]) || $ state ['type ' ] !== 'doc ' ) {
109- return null ;
110- }
111-
112- if (! isset ($ state ['content ' ]) || ! is_array ($ state ['content ' ])) {
113- $ state ['content ' ] = [];
114- }
115-
116- return $ state ;
117- }
118-
119- return null ;
120- });
50+ ->saveRelationshipsUsing (function () {});
51+ }
52+
53+ private static function configureToolbarButtons (Input $ input , ?Field $ field ): Input
54+ {
55+ $ config = self ::getDefaultConfig ();
56+
57+ return $ input
58+ ->toolbarButtons ([$ field ->config ['toolbarButtons ' ] ?? $ config ['toolbarButtons ' ]])
59+ ->disableToolbarButtons ($ field ->config ['disableToolbarButtons ' ] ?? $ config ['disableToolbarButtons ' ]);
60+ }
12161
62+ private static function configureStateHandling (Input $ input , string $ name ): Input
63+ {
64+ return $ input ->formatStateUsing (function ($ state ) {
65+ return self ::formatRichEditorState ($ state );
66+ });
67+ }
68+
69+ private static function configureCaptions (Input $ input , ?Field $ field ): Input
70+ {
12271 $ hideCaptions = $ field ->config ['hideCaptions ' ] ?? self ::getDefaultConfig ()['hideCaptions ' ];
72+
12373 if ($ hideCaptions ) {
12474 $ input ->extraAttributes (['data-hide-captions ' => 'true ' ]);
12575 }
12676
12777 return $ input ;
12878 }
12979
80+ private static function formatRichEditorState ($ state )
81+ {
82+ if (empty ($ state )) {
83+ return null ;
84+ }
85+
86+ // If it's already a string (HTML), return it as is
87+ if (is_string ($ state )) {
88+ return $ state ;
89+ }
90+
91+ // If it's an array (JSON format), handle it
92+ if (is_array ($ state )) {
93+ return self ::formatJsonState ($ state );
94+ }
95+
96+ return null ;
97+ }
98+
99+ private static function formatJsonState (array $ state ): ?array
100+ {
101+ // Handle nested doc structure
102+ if (isset ($ state [0 ]) && is_array ($ state [0 ]) && isset ($ state [0 ]['type ' ]) && $ state [0 ]['type ' ] === 'doc ' ) {
103+ $ state = $ state [0 ];
104+ }
105+
106+ // Clean up empty content arrays
107+ if (isset ($ state ['content ' ]) && is_array ($ state ['content ' ])) {
108+ $ state = self ::cleanContentArray ($ state );
109+ }
110+
111+ // Validate doc structure
112+ if (! isset ($ state ['type ' ]) || $ state ['type ' ] !== 'doc ' ) {
113+ return null ;
114+ }
115+
116+ if (! isset ($ state ['content ' ]) || ! is_array ($ state ['content ' ])) {
117+ $ state ['content ' ] = [];
118+ }
119+
120+ return $ state ;
121+ }
122+
123+ private static function cleanContentArray (array $ state ): array
124+ {
125+ $ content = $ state ['content ' ];
126+ if (count ($ content ) > 0 && is_array ($ content [0 ]) && empty ($ content [0 ])) {
127+ $ state ['content ' ] = [];
128+ }
129+
130+ return $ state ;
131+ }
132+
130133 public static function cleanRichEditorState ($ state , array $ options = [])
131134 {
132135 if (empty ($ state )) {
@@ -142,45 +145,75 @@ public static function mutateBeforeSaveCallback($record, $field, array $data): a
142145 {
143146 $ data = self ::ensureRichEditorDataFormat ($ record , $ field , $ data );
144147
145- $ autoCleanContent = $ field ->config ['autoCleanContent ' ] ?? self ::getDefaultConfig ()['autoCleanContent ' ];
146-
147- if ($ autoCleanContent ) {
148- $ options = [
149- 'preserveCustomCaptions ' => $ field ->config ['preserveCustomCaptions ' ] ?? self ::getDefaultConfig ()['preserveCustomCaptions ' ],
150- ];
151-
152- // Handle different data structures from different callers
153- if (isset ($ data ['values ' ][$ field ->ulid ])) {
154- // Called from ContentResource
155- $ data ['values ' ][$ field ->ulid ] = self ::cleanRichEditorState ($ data ['values ' ][$ field ->ulid ], $ options );
156- } elseif (isset ($ data [$ record ->valueColumn ][$ field ->ulid ])) {
157- // Called from CanMapDynamicFields trait
158- $ data [$ record ->valueColumn ][$ field ->ulid ] = self ::cleanRichEditorState ($ data [$ record ->valueColumn ][$ field ->ulid ], $ options );
159- }
148+ if (self ::shouldAutoCleanContent ($ field )) {
149+ $ data = self ::applyContentCleaning ($ record , $ field , $ data );
160150 }
161151
162152 return $ data ;
163153 }
164154
165- private static function ensureRichEditorDataFormat ($ record , $ field , array $ data ): array
155+ private static function shouldAutoCleanContent ($ field ): bool
156+ {
157+ return $ field ->config ['autoCleanContent ' ] ?? self ::getDefaultConfig ()['autoCleanContent ' ];
158+ }
159+
160+ private static function applyContentCleaning ($ record , $ field , array $ data ): array
166161 {
162+ $ options = self ::getCleaningOptions ($ field );
163+
167164 if (isset ($ data ['values ' ][$ field ->ulid ])) {
168- $ value = $ data ['values ' ][$ field ->ulid ];
169- if (empty ($ value )) {
170- $ data ['values ' ][$ field ->ulid ] = '' ;
171- }
165+ // Called from ContentResource
166+ $ data ['values ' ][$ field ->ulid ] = self ::cleanRichEditorState ($ data ['values ' ][$ field ->ulid ], $ options );
172167 } elseif (isset ($ data [$ record ->valueColumn ][$ field ->ulid ])) {
173- $ value = $ data [$ record ->valueColumn ][$ field ->ulid ];
174- if (empty ($ value )) {
175- $ data [$ record ->valueColumn ][$ field ->ulid ] = '' ;
176- }
168+ // Called from CanMapDynamicFields trait
169+ $ data [$ record ->valueColumn ][$ field ->ulid ] = self ::cleanRichEditorState ($ data [$ record ->valueColumn ][$ field ->ulid ], $ options );
170+ }
171+
172+ return $ data ;
173+ }
174+
175+ private static function getCleaningOptions ($ field ): array
176+ {
177+ return [
178+ 'preserveCustomCaptions ' => $ field ->config ['preserveCustomCaptions ' ] ?? self ::getDefaultConfig ()['preserveCustomCaptions ' ],
179+ ];
180+ }
181+
182+ private static function ensureRichEditorDataFormat ($ record , $ field , array $ data ): array
183+ {
184+ $ data = self ::normalizeContentResourceValue ($ data , $ field );
185+ $ data = self ::normalizeDynamicFieldValue ($ record , $ data , $ field );
186+
187+ return $ data ;
188+ }
189+
190+ private static function normalizeContentResourceValue (array $ data , $ field ): array
191+ {
192+ if (isset ($ data ['values ' ][$ field ->ulid ]) && empty ($ data ['values ' ][$ field ->ulid ])) {
193+ $ data ['values ' ][$ field ->ulid ] = '' ;
194+ }
195+
196+ return $ data ;
197+ }
198+
199+ private static function normalizeDynamicFieldValue ($ record , array $ data , $ field ): array
200+ {
201+ if (isset ($ data [$ record ->valueColumn ][$ field ->ulid ]) && empty ($ data [$ record ->valueColumn ][$ field ->ulid ])) {
202+ $ data [$ record ->valueColumn ][$ field ->ulid ] = '' ;
177203 }
178204
179205 return $ data ;
180206 }
181207
182208 public static function mutateFormDataCallback ($ record , $ field , array $ data ): array
183209 {
210+ // Get the raw value from the database without JSON decoding
211+ $ rawValue = $ record ->values ()->where ('field_ulid ' , $ field ->ulid )->first ()?->value;
212+
213+ if ($ rawValue !== null ) {
214+ $ data [$ record ->valueColumn ][$ field ->ulid ] = $ rawValue ;
215+ }
216+
184217 return $ data ;
185218 }
186219
0 commit comments