diff --git a/app/Livewire/Posts/PostFormComponent.php b/app/Livewire/Posts/PostFormComponent.php index 9288485e..043a91bd 100644 --- a/app/Livewire/Posts/PostFormComponent.php +++ b/app/Livewire/Posts/PostFormComponent.php @@ -5,14 +5,13 @@ namespace App\Livewire\Posts; use App\Dtos\PostDto; -use App\Enums\LivewireEventEnum; use App\Enums\PostStateEnum; use App\Http\Requests\Post\StorePostRequest; use App\Services\PostService; use App\Traits\LoggingTrait; use App\Traits\SubsiteTrait; use Illuminate\Contracts\View\View; -use Livewire\Attributes\On; +use Livewire\Attributes\Locked; use Livewire\Component; final class PostFormComponent extends Component @@ -24,7 +23,11 @@ final class PostFormComponent extends Component public string $body = ''; public string $more_inside = ''; public string $tags = ''; + + #[Locked] public int $subsiteId = 0; + + #[Locked] public int $userId = 0; private PostService $postService; @@ -49,17 +52,6 @@ public function render(): View return view('livewire.posts.post-form-component'); } - #[On(LivewireEventEnum::EditorUpdated->value)] - public function saveEditorContent($editorId, $content): void - { - if ($editorId === 'post-body') { - $this->body = $content; - } - if ($editorId === 'more-inside') { - $this->more_inside = $content; - } - } - public function store(): void { $this->validate(); diff --git a/app/Livewire/Wysiwyg/WysiwygComponent.php b/app/Livewire/Wysiwyg/WysiwygComponent.php index 8d9b5807..0d1ba8fb 100644 --- a/app/Livewire/Wysiwyg/WysiwygComponent.php +++ b/app/Livewire/Wysiwyg/WysiwygComponent.php @@ -6,13 +6,22 @@ use App\Enums\LivewireEventEnum; use Illuminate\Contracts\View\View; +use Livewire\Attributes\Locked; +use Livewire\Attributes\Modelable; use Livewire\Component; final class WysiwygComponent extends Component { + #[Modelable] public string $content = ''; + + #[Locked] public string $editorId; + + #[Locked] public string $label; + + #[Locked] public string $name; public function mount(string $editorId, string $content = '', string $label = '', string $name = ''): void diff --git a/app/Services/PostService.php b/app/Services/PostService.php index 85690f94..8d2869ee 100644 --- a/app/Services/PostService.php +++ b/app/Services/PostService.php @@ -34,7 +34,6 @@ public function store(PostDto $dto): ?Post 'more_inside' => $this->purifierService->clean($dto->more_inside), 'user_id' => $dto->user_id, 'subsite_id' => $dto->subsite_id, - 'state' => $dto->state, 'published_at' => $dto->published_at, 'is_published' => $dto->is_published, ]; diff --git a/resources/js/wysiwyg.js b/resources/js/wysiwyg.js index 0defe637..479aaea4 100644 --- a/resources/js/wysiwyg.js +++ b/resources/js/wysiwyg.js @@ -4,34 +4,76 @@ const cleanupKey = Symbol('cleanup'); // Set up a single textarea with CKEditor async function initializeEditor(textarea, component) { try { - const editorConfig = JSON.parse(document.querySelector('meta[name="ckeditor-config"]')?.content || 'null') || {} + let globalEditorConfig = null; + try { + globalEditorConfig = JSON.parse(document.querySelector('meta[name="ckeditor-config"]')?.content || 'null'); + } catch (e) { + // Ignore + console.debug('Unable to parse CKEditor config from meta tag', e); + } + + let localEditorConfig = null; + try { + localEditorConfig = JSON.parse(textarea.dataset.editorConfig || 'null'); + } catch (e) { + // Ignore + console.debug('Unable to parse CKEditor config from textarea data-editor-config', e); + } + + const editorConfig = { + ...(globalEditorConfig || {}), + ...(localEditorConfig || {}), + toolbar: { + items: [ + 'bold', 'italic', 'link', + 'bulletedList', 'numberedList', 'blockQuote', '|', + 'heading', 'insertTable', 'mediaEmbed', '|', + 'undo', 'redo' + ], + // Collapse into three dots menu when the toolbar is full. + shouldNotGroupWhenFull: false + } + } + const editor = await ClassicEditor.create(textarea, editorConfig); const editorId = textarea.dataset.editorId; - // Listen for changes to the editor content and update the component's content property - editor.model.document.on('change:data', () => { - component.$wire.$set('content', editor.getData()); + // Listen for changes to the editor content and update the component's content property. + const sync = () => { + const content = editor.getData(); + textarea.value = content; + component.$wire.$set('content', content, false); + }; + + editor.model.document.on('change:data', sync); + + // Also sync when the editor loses focus. + editor.ui.focusTracker.on('change:isFocused', ( _event, _name, isFocused ) => { + if (!isFocused) sync(); }); // Reset the editor content when we receive a notification from the backend. - const onEditorClear = (event) => { + const clearEditor = (event) => { if (event.detail.editorId === editorId) { editor.setData(''); + textarea.value = ''; } }; - document.addEventListener('editor:clear', onEditorClear); + document.addEventListener('editor:clear', clearEditor); // Update the component's content property when the force sync event is received - const onForceSync = () => { - component.$wire.$set('content', editor.getData()); + const syncAndFlush = () => { + const content = editor.getData(); + textarea.value = content; + component.$wire.$set('content', content); }; - document.addEventListener('livewire:force-sync', onForceSync); + document.addEventListener('livewire:force-sync', syncAndFlush); textarea[cleanupKey] = () => { - document.removeEventListener('editor:clear', onEditorClear); - document.removeEventListener('livewire:force-sync', onForceSync); + document.removeEventListener('editor:clear', clearEditor); + document.removeEventListener('livewire:force-sync', syncAndFlush); editor.destroy().catch(e => console.error('Error destroying editor', e)); }; } catch (error) { diff --git a/resources/sass/modules/_forms.scss b/resources/sass/modules/_forms.scss index 836d6b17..9890da9d 100644 --- a/resources/sass/modules/_forms.scss +++ b/resources/sass/modules/_forms.scss @@ -157,6 +157,9 @@ fieldset { border: none; position: relative; margin: 0; + // Reset min-inline-size to unset - Chrome sets it to min-content, which + // prevents CKEditor from responding to the screen width correctly. + min-inline-size: unset; padding: 0; } diff --git a/resources/views/livewire/comments/comment-form-component.blade.php b/resources/views/livewire/comments/comment-form-component.blade.php index 33603023..6dafaecf 100644 --- a/resources/views/livewire/comments/comment-form-component.blade.php +++ b/resources/views/livewire/comments/comment-form-component.blade.php @@ -19,7 +19,7 @@ + wire:model="body" />
@if($isEditing === true || $isReplying === true) diff --git a/resources/views/livewire/posts/post-form-component.blade.php b/resources/views/livewire/posts/post-form-component.blade.php index f4c38811..62c8ed03 100644 --- a/resources/views/livewire/posts/post-form-component.blade.php +++ b/resources/views/livewire/posts/post-form-component.blade.php @@ -11,6 +11,7 @@
@@ -18,6 +19,7 @@
{{ $content }} + data-editor-config="{{ json_encode($editorConfig) }}" + wire:model.lazy="content">{!! $content !!}