fix(ckeditor): prevent null value from being converted to string 'null' on validation returns
This commit is contained in:
parent
f84a1a7b8c
commit
52588ae999
11 changed files with 71 additions and 15 deletions
|
|
@ -26,7 +26,7 @@ import {
|
|||
useAttrs,
|
||||
} from "vue";
|
||||
|
||||
import { builtinPlugins, frTranslations } from "@modules/ckeditor";
|
||||
import { builtinPlugins, frTranslations, normalizeEditorText } from "@modules/ckeditor";
|
||||
import { uniqueId } from "@modules/uniqueid";
|
||||
|
||||
import "ckeditor5/ckeditor5.css";
|
||||
|
|
@ -70,7 +70,7 @@ const props = defineProps({
|
|||
// * DATA
|
||||
const id = ref<string>(props.id);
|
||||
const name = ref<string>(props.name);
|
||||
const text = ref<string>(props.dbtext);
|
||||
const text = ref<string>(normalizeEditorText(props.dbtext));
|
||||
const required = ref<boolean>(props.required);
|
||||
|
||||
/** Counter parameters. */
|
||||
|
|
@ -102,8 +102,8 @@ onMounted(() => {
|
|||
data = JSON.parse(json);
|
||||
if (!isUsedWithProps.value) {
|
||||
if (data.id) id.value = String(data.id);
|
||||
name.value = String(data.name);
|
||||
text.value = String(data.text);
|
||||
if (data.name) name.value = String(data.name);
|
||||
text.value = normalizeEditorText(data.text);
|
||||
if (data.required) required.value = Boolean(data.required);
|
||||
void makeSuperBuild();
|
||||
}
|
||||
|
|
@ -320,13 +320,14 @@ function onExternalSetData(event: Event): void {
|
|||
return;
|
||||
}
|
||||
|
||||
text.value = payload;
|
||||
const cleanText = normalizeEditorText(payload);
|
||||
text.value = cleanText;
|
||||
if (hiddenInput.value) {
|
||||
hiddenInput.value.value = payload;
|
||||
hiddenInput.value.value = cleanText;
|
||||
}
|
||||
|
||||
if (editorInstance.value) {
|
||||
editorInstance.value.setData(payload);
|
||||
editorInstance.value.setData(cleanText);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
6
resources/ts/modules/ckeditor-utils.ts
Normal file
6
resources/ts/modules/ckeditor-utils.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export function normalizeEditorText(value: unknown): string {
|
||||
if (value === null || value === undefined || value === "null" || value === "undefined") {
|
||||
return "";
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
33
resources/ts/modules/ckeditor.test.ts
Normal file
33
resources/ts/modules/ckeditor.test.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { normalizeEditorText } from "./ckeditor-utils";
|
||||
|
||||
describe("normalizeEditorText", () => {
|
||||
it("converts null and undefined to empty string", () => {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(normalizeEditorText(null)).toBe("");
|
||||
expect(normalizeEditorText(undefined)).toBe("");
|
||||
});
|
||||
|
||||
it("converts string 'null' and 'undefined' to empty string", () => {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(normalizeEditorText("null")).toBe("");
|
||||
expect(normalizeEditorText("undefined")).toBe("");
|
||||
});
|
||||
|
||||
it("preserves valid empty string", () => {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(normalizeEditorText("")).toBe("");
|
||||
});
|
||||
|
||||
it("preserves HTML and text content", () => {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(normalizeEditorText("<p>Hello world</p>")).toBe("<p>Hello world</p>");
|
||||
expect(normalizeEditorText("Some regular text")).toBe("Some regular text");
|
||||
});
|
||||
|
||||
it("converts numbers to string", () => {
|
||||
// GIVEN / WHEN / THEN
|
||||
expect(normalizeEditorText(123)).toBe("123");
|
||||
});
|
||||
});
|
||||
|
|
@ -166,4 +166,5 @@ const builtinPlugins: Array<PluginConstructor | typeof SpecialCharactersEmoji> =
|
|||
|
||||
export { ClassicEditor } from "ckeditor5";
|
||||
export { builtinPlugins, frTranslations };
|
||||
export { normalizeEditorText } from "./ckeditor-utils";
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
'id' => 'answer-text',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'answer',
|
||||
'text' => old('answer', $faq->answer ?? ''),
|
||||
'text' => old('answer', $faq->answer ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editor)'></div>
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@
|
|||
'id' => 'page-content',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'content',
|
||||
'text' => old('content', $page->content ?? ''),
|
||||
'text' => old('content', $page->content ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editor)'></div>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
'id' => 'inco-ingredients',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'ingredients',
|
||||
'text' => old('ingredients', $inco->ingredients ?? ''),
|
||||
'text' => old('ingredients', $inco->ingredients ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editorIngredients)'></div>
|
||||
|
|
@ -81,7 +81,7 @@
|
|||
'id' => 'inco-preparation',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'preparation',
|
||||
'text' => old('preparation', $inco->preparation ?? ''),
|
||||
'text' => old('preparation', $inco->preparation ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editorPrep)'></div>
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
'id' => 'inco-selling-argument',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'selling_argument',
|
||||
'text' => old('selling_argument', $inco->selling_argument ?? ''),
|
||||
'text' => old('selling_argument', $inco->selling_argument ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editorSelling)'></div>
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@
|
|||
'id' => 'product-description',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'description',
|
||||
'text' => old('description', $product->description ?? ''),
|
||||
'text' => old('description', $product->description ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editor)'></div>
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
'id' => 'range-description',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'description',
|
||||
'text' => old('description', $range->description ?? ''),
|
||||
'text' => old('description', $range->description ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editor)'></div>
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
'id' => 'slide-text',
|
||||
'csrf' => csrf_token(),
|
||||
'name' => 'text',
|
||||
'text' => old('text', $slide->text ?? ''),
|
||||
'text' => old('text', $slide->text ?? '') ?? '',
|
||||
];
|
||||
@endphp
|
||||
<div class="ck-editor" data-json='@json($editor)'></div>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,21 @@ describe('ProductsController', function () {
|
|||
expect($response->status())->toBe(200);
|
||||
});
|
||||
|
||||
it('renders empty string instead of null for ckeditor text when old input is null', function () {
|
||||
// GIVEN
|
||||
/** @var \Tests\TestCase $this */
|
||||
session()->put('_old_input', ['description' => null]);
|
||||
|
||||
// WHEN
|
||||
$response = $this->get('/bo/products/create');
|
||||
|
||||
// THEN
|
||||
$response->assertOk();
|
||||
$content = $response->getContent();
|
||||
expect($content)->not->toContain('"text":null')
|
||||
->and($content)->toContain('"text":""');
|
||||
});
|
||||
|
||||
it('can store a product', function () {
|
||||
// GIVEN
|
||||
$range = new Range();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue