fixed creation
This commit is contained in:
@@ -14,29 +14,49 @@
|
||||
<div {{ $attributes->whereDoesntStartWith('wire:model')->merge(['class' => 'space-y-2']) }}
|
||||
@if ($model) data-helpdesk-editor-model="{{ $model }}" @endif
|
||||
x-on:helpdesk-editor-reset.window="if ($event.detail.model === model) clear()"
|
||||
x-on:helpdesk-editor-sync.window="if ($event.detail.model === model) sync()" x-data="{
|
||||
x-on:helpdesk-editor-sync.window="if ($event.detail.model === model) syncToLivewire()"
|
||||
x-data="{
|
||||
model: @js($model),
|
||||
value: @js($initialValue),
|
||||
sync() {
|
||||
submitHandler: null,
|
||||
readEditor() {
|
||||
this.value = this.$refs.editor.innerHTML;
|
||||
|
||||
return this.value;
|
||||
},
|
||||
syncToHiddenInput() {
|
||||
this.readEditor();
|
||||
},
|
||||
syncToLivewire(live = false) {
|
||||
this.readEditor();
|
||||
|
||||
if (this.model) {
|
||||
this.$wire.set(this.model, this.value);
|
||||
this.$wire.set(this.model, this.value, live);
|
||||
}
|
||||
},
|
||||
command(action, value = null) {
|
||||
this.$refs.editor.focus();
|
||||
document.execCommand(action, false, value);
|
||||
this.sync();
|
||||
this.syncToHiddenInput();
|
||||
},
|
||||
clear() {
|
||||
this.value = '';
|
||||
this.$refs.editor.innerHTML = '';
|
||||
|
||||
if (this.model) {
|
||||
this.$wire.set(this.model, '');
|
||||
this.$wire.set(this.model, '', false);
|
||||
}
|
||||
},
|
||||
init() {
|
||||
this.$refs.editor.innerHTML = this.value || '';
|
||||
|
||||
this.submitHandler = () => this.syncToLivewire(false);
|
||||
this.$root.closest('form')?.addEventListener('submit', this.submitHandler, { capture: true });
|
||||
},
|
||||
destroy() {
|
||||
if (this.submitHandler) {
|
||||
this.$root.closest('form')?.removeEventListener('submit', this.submitHandler, { capture: true });
|
||||
}
|
||||
}
|
||||
}">
|
||||
<label class="block text-sm font-medium text-zinc-700 dark:text-zinc-200">{{ $label }}</label>
|
||||
@@ -66,16 +86,15 @@
|
||||
class="rounded-lg px-2 py-1 text-sm hover:bg-zinc-200 dark:hover:bg-zinc-800">Clear</button>
|
||||
</div>
|
||||
|
||||
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" autocapitalize="sentences" autocorrect="on" autocomplete="on" inputmode="text"
|
||||
<div x-ref="editor" contenteditable="true" spellcheck="true" lang="en-GB" autocapitalize="sentences" autocorrect="on" autocomplete="off" inputmode="text"
|
||||
@if ($editorDusk) data-dusk="{{ $editorDusk }}" dusk="{{ $editorDusk }}" @endif
|
||||
x-on:input.debounce.150ms="sync" x-on:keyup="sync" x-on:paste="$nextTick(() => sync())" x-on:blur="sync"
|
||||
class="prose prose-sm min-h-[{{ (int) $rows * 28 }}px] max-w-none bg-white p-4 text-sm text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
|
||||
x-on:paste="$nextTick(() => syncToHiddenInput())" x-on:blur="syncToHiddenInput()"
|
||||
class="helpdesk-rich-editor prose prose-sm min-h-[{{ (int) $rows * 28 }}px] max-w-none bg-white p-4 text-sm text-zinc-900 outline-none dark:prose-invert dark:bg-zinc-950 dark:text-zinc-100"
|
||||
data-placeholder="{{ $placeholder }}"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<p class="text-xs font-semibold text-zinc-500 dark:text-zinc-400">
|
||||
Browser spellcheck is enabled for this rich editor. Use your browser or operating-system spelling menu for suggestions.
|
||||
Browser spellcheck is enabled for this rich editor. Misspelled words are checked by the browser/operating system while typing.
|
||||
</p>
|
||||
|
||||
@if ($model)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'Raise a new support request with priority, product/service, project, category, team and full details.',
|
||||
])
|
||||
|
||||
<form wire:submit.prevent="save" enctype="multipart/form-data" class="helpdesk-ticket-form space-y-6">
|
||||
<form wire:submit.prevent="save" x-on:submit.capture="$dispatch('helpdesk-editor-sync', { model: 'body' })" enctype="multipart/form-data" class="helpdesk-ticket-form space-y-6">
|
||||
<div class="overflow-hidden rounded-2xl border border-zinc-700 bg-zinc-900 shadow-sm">
|
||||
<div class="border-b border-zinc-700 bg-zinc-800/80 px-6 py-4">
|
||||
<h2 class="text-lg font-semibold text-zinc-100">Ticket details</h2>
|
||||
|
||||
@@ -9,23 +9,35 @@ use Tests\TestCase;
|
||||
final class TicketCreateEditorSyncFilesTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* The ticket create editor must bind the details body through Livewire
|
||||
* without eager live validation while the user is typing.
|
||||
* The ticket create editor must not send Livewire requests while typing.
|
||||
* Eager key/input sync causes disabled submit states, random content
|
||||
* replacement, and prevents native spellcheck from settling.
|
||||
*/
|
||||
public function test_ticket_create_editor_pushes_details_body_to_livewire_before_validation(): void
|
||||
public function test_ticket_create_editor_does_not_sync_livewire_on_keypress_or_input(): void
|
||||
{
|
||||
$editor = file_get_contents(base_path('Modules/Helpdesk/Resources/views/components/html-editor.blade.php'));
|
||||
|
||||
$this->assertIsString($editor);
|
||||
$this->assertStringNotContainsString('x-on:input', $editor);
|
||||
$this->assertStringNotContainsString('x-on:keyup', $editor);
|
||||
$this->assertStringContainsString('contenteditable="true"', $editor);
|
||||
$this->assertStringContainsString('spellcheck="true"', $editor);
|
||||
$this->assertStringContainsString('this.$wire.set(this.model, this.value, live)', $editor);
|
||||
$this->assertStringContainsString('syncToLivewire(false)', $editor);
|
||||
}
|
||||
|
||||
/**
|
||||
* The create form must push the rich editor body to the Livewire property
|
||||
* during submit capture, before the save action validates the body field.
|
||||
*/
|
||||
public function test_ticket_create_form_syncs_body_before_submit_validation(): void
|
||||
{
|
||||
$view = file_get_contents(base_path('Modules/Helpdesk/Resources/views/livewire/ticket-create.blade.php'));
|
||||
|
||||
$this->assertIsString($view);
|
||||
$this->assertStringContainsString('wire:model="body"', $view);
|
||||
$this->assertStringContainsString('x-on:submit.capture', $view);
|
||||
$this->assertStringContainsString('helpdesk-editor-sync', $view);
|
||||
$this->assertStringNotContainsString('wire:model.live="body"', $view);
|
||||
$this->assertStringContainsString('submit', $view);
|
||||
$this->assertTrue(
|
||||
str_contains($view, 'Livewire')
|
||||
|| str_contains($view, '$wire')
|
||||
|| str_contains($view, '@this')
|
||||
|| str_contains($view, 'wire:model="body"'),
|
||||
'Ticket create editor must keep the body field synchronised with Livewire before validation.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,3 +228,11 @@
|
||||
- Mirrored manual time-log entries into helpdesk_ticket_time_logs when the timer history table is present so the ticket detail modal stays current.
|
||||
- Updated TicketTimeLogTest to use authorised Helpdesk fixture users and lookup data instead of ad-hoc users that fail the ticket update policy.
|
||||
- Kept the pricing-free dashboard test baseline and preserved append-only changelog history.
|
||||
|
||||
- version: 1.9.52
|
||||
date: 2026-06-24
|
||||
changes:
|
||||
- Fixed ticket create rich editor Livewire synchronisation so typing no longer fires keypress/input requests.
|
||||
- Restored native browser spellcheck on the contenteditable editor by allowing typed text to remain stable in the DOM.
|
||||
- Added submit-capture body synchronisation before validation so tickets can be created reliably.
|
||||
- Added regression assertions for editor spellcheck, keypress sync prevention, and submit-time body sync.
|
||||
|
||||
@@ -22,5 +22,5 @@
|
||||
"Modules\\Helpdesk\\Providers\\HelpdeskServiceProvider"
|
||||
],
|
||||
"files": [],
|
||||
"version": "1.9.50"
|
||||
"version": "1.9.52"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user