diff --git a/app/Filament/Admin/Resources/FooterTemplates/Pages/EditFooterTemplate.php b/app/Filament/Admin/Resources/FooterTemplates/Pages/EditFooterTemplate.php index 9194f15..bdc8049 100644 --- a/app/Filament/Admin/Resources/FooterTemplates/Pages/EditFooterTemplate.php +++ b/app/Filament/Admin/Resources/FooterTemplates/Pages/EditFooterTemplate.php @@ -52,4 +52,11 @@ class EditFooterTemplate extends EditRecord return $data; } + + protected function afterSave(): void + { + // Kaydetme sonrası preview'ı güncelle + // Livewire event dispatch et + $this->dispatch('template-saved'); + } } diff --git a/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php b/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php index fe9a753..87e61bf 100644 --- a/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php +++ b/app/Filament/Admin/Resources/FooterTemplates/Schemas/FooterTemplateForm.php @@ -50,13 +50,11 @@ class FooterTemplateForm // Preview Component - placed after editor View::make('components.template-preview') - ->viewData(function ($record) { - return [ - 'type' => 'footer', - 'fieldName' => 'html_content', - 'recordId' => $record?->id, - ]; - }) + ->viewData([ + 'type' => 'footer', + 'fieldName' => 'html_content', + 'recordId' => null, // Will be extracted from URL by JavaScript + ]) ->columnSpanFull(), Toggle::make('is_active') diff --git a/app/Filament/Admin/Resources/HeaderTemplates/Pages/EditHeaderTemplate.php b/app/Filament/Admin/Resources/HeaderTemplates/Pages/EditHeaderTemplate.php index a345243..fa6b6d5 100644 --- a/app/Filament/Admin/Resources/HeaderTemplates/Pages/EditHeaderTemplate.php +++ b/app/Filament/Admin/Resources/HeaderTemplates/Pages/EditHeaderTemplate.php @@ -52,4 +52,11 @@ class EditHeaderTemplate extends EditRecord return $data; } + + protected function afterSave(): void + { + // Kaydetme sonrası preview'ı güncelle + // Livewire event dispatch et (JavaScript tarafında Livewire.on() ile dinlenecek) + $this->dispatch('template-saved'); + } } diff --git a/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php b/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php index 2519047..c697942 100644 --- a/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php +++ b/app/Filament/Admin/Resources/HeaderTemplates/Schemas/HeaderTemplateForm.php @@ -49,13 +49,11 @@ class HeaderTemplateForm // Preview Component - placed after editor View::make('components.template-preview') - ->viewData(function ($record) { - return [ - 'type' => 'header', - 'fieldName' => 'html_content', - 'recordId' => $record?->id, - ]; - }) + ->viewData([ + 'type' => 'header', + 'fieldName' => 'html_content', + 'recordId' => null, // Will be extracted from URL by JavaScript + ]) ->columnSpanFull(), Toggle::make('is_active') diff --git a/app/Filament/Admin/Resources/MenuTemplates/Pages/EditMenuTemplate.php b/app/Filament/Admin/Resources/MenuTemplates/Pages/EditMenuTemplate.php index ad843a3..554bce9 100644 --- a/app/Filament/Admin/Resources/MenuTemplates/Pages/EditMenuTemplate.php +++ b/app/Filament/Admin/Resources/MenuTemplates/Pages/EditMenuTemplate.php @@ -28,4 +28,11 @@ class EditMenuTemplate extends EditRecord RestoreAction::make(), ]; } + + protected function afterSave(): void + { + // Kaydetme sonrası preview'ı güncelle + // Livewire event dispatch et + $this->dispatch('template-saved'); + } } diff --git a/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php b/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php index a7bca8b..c9c6424 100644 --- a/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php +++ b/app/Filament/Admin/Resources/MenuTemplates/Schemas/MenuTemplateForm.php @@ -46,13 +46,11 @@ class MenuTemplateForm // Preview Component View::make('components.menu-template-preview') - ->viewData(function ($record) { - return [ - 'type' => 'menu', - 'fieldName' => 'html_content', - 'recordId' => $record?->id, - ]; - }) + ->viewData([ + 'type' => 'menu', + 'fieldName' => 'html_content', + 'recordId' => null, // Will be extracted from URL by JavaScript + ]) ->columnSpanFull(), Toggle::make('is_active') diff --git a/app/Filament/Admin/Resources/SectionTemplates/Pages/EditSectionTemplate.php b/app/Filament/Admin/Resources/SectionTemplates/Pages/EditSectionTemplate.php index 5cd61e4..d48b122 100644 --- a/app/Filament/Admin/Resources/SectionTemplates/Pages/EditSectionTemplate.php +++ b/app/Filament/Admin/Resources/SectionTemplates/Pages/EditSectionTemplate.php @@ -52,4 +52,11 @@ class EditSectionTemplate extends EditRecord return $data; } + + protected function afterSave(): void + { + // Kaydetme sonrası preview'ı güncelle + // Livewire event dispatch et + $this->dispatch('template-saved'); + } } diff --git a/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php b/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php index e2f0d2f..1d98fce 100644 --- a/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php +++ b/app/Filament/Admin/Resources/SectionTemplates/Schemas/SectionTemplateForm.php @@ -49,13 +49,11 @@ class SectionTemplateForm // Preview Component - placed after editor View::make('components.template-preview') - ->viewData(function ($record) { - return [ - 'type' => 'section', - 'fieldName' => 'html_content', - 'recordId' => $record?->id, - ]; - }) + ->viewData([ + 'type' => 'section', + 'fieldName' => 'html_content', + 'recordId' => null, // Will be extracted from URL by JavaScript + ]) ->columnSpanFull(), Toggle::make('is_active') diff --git a/resources/views/components/menu-template-preview.blade.php b/resources/views/components/menu-template-preview.blade.php index 98774ae..694e3a5 100644 --- a/resources/views/components/menu-template-preview.blade.php +++ b/resources/views/components/menu-template-preview.blade.php @@ -116,6 +116,27 @@ function templatePreview(previewUrl, type, fieldName, recordIdFromView = null) { } catch (e) { console.log('[Preview] Could not get ID from Livewire'); } + + // Livewire event listener ekle (Livewire 3.x için) + if (window.Livewire) { + document.addEventListener('livewire:init', () => { + Livewire.on('template-saved', () => { + this.updatePreview(); + }); + }); + + // Eğer Livewire zaten yüklendiyse direkt dinle + if (window.Livewire.hook) { + Livewire.on('template-saved', () => { + this.updatePreview(); + }); + } + } + + // Window event listener ekle (alternatif - Livewire event'lerini de yakalar) + window.addEventListener('template-saved', () => { + this.updatePreview(); + }); }, async updatePreview() { diff --git a/resources/views/components/placeholder-picker.blade.php b/resources/views/components/placeholder-picker.blade.php index 02230ba..f25b84a 100644 --- a/resources/views/components/placeholder-picker.blade.php +++ b/resources/views/components/placeholder-picker.blade.php @@ -85,7 +85,7 @@ size="sm" color="gray" outlined - @click="insertPlaceholder('{{ $fieldName }}', type + '.' + example)" + x-on:click="window.insertPlaceholder('{{ $fieldName }}', type + '.' + example)" x-bind:tooltip="'{{ __('placeholder-picker.click_to_insert') }}'" > @@ -105,7 +105,7 @@ size="sm" color="primary" outlined - @click="insertPlaceholder('{{ $fieldName }}', 'menu')" + x-on:click="window.insertPlaceholder('{{ $fieldName }}', 'menu')" > {menu} @@ -113,7 +113,7 @@ size="sm" color="primary" outlined - @click="insertPlaceholder('{{ $fieldName }}', 'staticMenu')" + x-on:click="window.insertPlaceholder('{{ $fieldName }}', 'staticMenu')" > {staticMenu} @@ -179,25 +179,37 @@ // Monaco Editor instance'ını bul const editorContainer = document.querySelector('[data-field-name=\'' + fieldName + '\']'); let monacoEditorInstance = null; - let currentValue = ''; - let cursorPosition = null; - // Monaco Editor'dan cursor pozisyonunu al - if (editorContainer && window.monaco) { + // Monaco Editor instance'ını bul + if (editorContainer && window.monaco && window.monaco.editor) { + // Tüm Monaco Editor instance'larını kontrol et const editorInstances = window.monaco.editor.getEditors(); for (let editor of editorInstances) { - const container = editor.getContainerDomNode(); - if (container && container.closest && container.closest('[data-field-name=\'' + fieldName + '\']')) { - monacoEditorInstance = editor; - const model = editor.getModel(); - currentValue = model.getValue(); - const selection = editor.getSelection(); - if (selection) { - cursorPosition = model.getOffsetAt(selection.getStartPosition()); - } else { - cursorPosition = currentValue.length; + try { + const container = editor.getContainerDomNode(); + if (container) { + // Container'ın parent'larını kontrol et + let parent = container; + while (parent && parent !== document.body) { + if (parent.hasAttribute && parent.hasAttribute('data-field-name') && + parent.getAttribute('data-field-name') === fieldName) { + monacoEditorInstance = editor; + break; + } + parent = parent.parentElement; + } + + // Veya closest metodunu kullan + if (!monacoEditorInstance && container.closest) { + const closest = container.closest('[data-field-name=\'' + fieldName + '\']'); + if (closest) { + monacoEditorInstance = editor; + break; + } + } } - break; + } catch (e) { + console.debug('Monaco Editor container check failed:', e); } } } @@ -205,93 +217,90 @@ // Monaco Editor varsa, doğrudan onu kullan if (monacoEditorInstance) { const model = monacoEditorInstance.getModel(); - const newValue = currentValue.slice(0, cursorPosition) + placeholderText + currentValue.slice(cursorPosition); + const currentValue = model.getValue(); - // Monaco Editor'da değeri güncelle - monacoEditorInstance.executeEdits('placeholder-insert', [{ - range: new window.monaco.Range( - model.getPositionAt(cursorPosition).lineNumber, - model.getPositionAt(cursorPosition).column, - model.getPositionAt(cursorPosition).lineNumber, - model.getPositionAt(cursorPosition).column - ), - text: placeholderText - }]); - - // Cursor pozisyonunu güncelle - const newPosition = model.getPositionAt(cursorPosition + placeholderText.length); - monacoEditorInstance.setPosition(newPosition); + // Monaco Editor'ı focus et (önce focus et ki cursor pozisyonu doğru alınsın) monacoEditorInstance.focus(); - // Filament form state'ini güncellemek için Monaco Editor'ın change event'ini tetikle - // Filament CodeEditor otomatik olarak değişiklikleri algılar + // Kısa bir delay ile cursor pozisyonunu al (focus işleminin tamamlanması için) setTimeout(() => { - // Monaco Editor model değişikliğini tetikle - // Bu, Filament'in CodeEditor component'inin otomatik olarak algılamasını sağlar - if (monacoEditorInstance) { - // Model'in değerini tekrar set et (zaten set ettik ama event'i tetiklemek için) - const model = monacoEditorInstance.getModel(); - - // Monaco Editor'ın onDidChangeContent event'ini manuel tetikle - // Filament CodeEditor bu event'i dinliyor ve form state'ini güncelliyor - model.onDidChangeContent(() => { - // Bu event zaten tetiklenmiş olacak, sadece emin olmak için - }); - + // Cursor pozisyonunu al (selection varsa onu kullan, yoksa cursor pozisyonunu) + let selection = monacoEditorInstance.getSelection(); + let cursorPosition; + + if (selection && !selection.isEmpty()) { + // Seçili metin varsa, başlangıç pozisyonunu kullan + cursorPosition = model.getOffsetAt(selection.getStartPosition()); + } else { + // Seçim yoksa cursor pozisyonunu kullan + const position = monacoEditorInstance.getPosition(); + if (position) { + cursorPosition = model.getOffsetAt(position); + } else { + // Cursor pozisyonu alınamazsa sona ekle + cursorPosition = currentValue.length; + } + } + + // Placeholder'ı cursor pozisyonuna ekle + const position = model.getPositionAt(cursorPosition); + const range = new window.monaco.Range( + position.lineNumber, + position.column, + position.lineNumber, + position.column + ); + + // Edit işlemini yap + monacoEditorInstance.executeEdits('placeholder-insert', [{ + range: range, + text: placeholderText + }]); + + // Cursor pozisyonunu güncelle (placeholder'ın sonuna) + const newCursorPosition = model.getPositionAt(cursorPosition + placeholderText.length); + monacoEditorInstance.setPosition(newCursorPosition); + + // Focus'u koru + monacoEditorInstance.focus(); + + // Filament form state'ini güncellemek için güncel değeri al + const updatedValue = model.getValue(); + + // Filament form state'ini güncelle + setTimeout(() => { // Hidden input'u bul ve güncelle (eğer varsa) const hiddenInput = editorContainer.querySelector('input[type=\'hidden\']'); if (hiddenInput) { - hiddenInput.value = newValue; + hiddenInput.value = updatedValue; hiddenInput.dispatchEvent(new Event('input', { bubbles: true })); hiddenInput.dispatchEvent(new Event('change', { bubbles: true })); } // Filament form'unu bul ve güncelle - // Form component'ini bulmak için editor container'ın parent'larını kontrol et - let formComponent = null; const formWireElement = editorContainer.closest('form [wire\\:id], [wire\\:id][wire\\:key*="form"]'); if (formWireElement && window.Livewire) { const wireId = formWireElement.getAttribute('wire:id'); const component = window.Livewire.find(wireId); - // Component'in form component'i olup olmadığını kontrol et - // Sadece field path'lerini kontrol et, 'data' property'sine direkt erişme if (component && component.get) { const fieldPath = 'data.' + fieldName; try { - // Field path'i kontrol et if (component.get(fieldPath) !== undefined) { - formComponent = component; + component.set(fieldPath, updatedValue); } else if (component.get('data.html_content') !== undefined) { - formComponent = component; + component.set('data.html_content', updatedValue); } else if (component.get('html_content') !== undefined) { - formComponent = component; + component.set('html_content', updatedValue); } } catch (e) { - // Property kontrolü sırasında hata alırsak, component'i kullanma + console.debug('Livewire form state update skipped:', e.message); } } } - - // Sadece form component'i bulunduysa güncelle - if (formComponent) { - try { - const fieldPath = 'data.' + fieldName; - if (formComponent.get(fieldPath) !== undefined) { - formComponent.set(fieldPath, newValue); - } else if (formComponent.get('data.html_content') !== undefined) { - formComponent.set('data.html_content', newValue); - } else if (formComponent.get('html_content') !== undefined) { - formComponent.set('html_content', newValue); - } - } catch (e) { - // Hata durumunda sadece console'a yaz, Monaco Editor zaten güncellenmiş - console.debug('Livewire form state update skipped:', e.message); - } - } - } - }, 150); + }, 100); + }, 50); return; } diff --git a/resources/views/components/template-preview.blade.php b/resources/views/components/template-preview.blade.php index 98774ae..694e3a5 100644 --- a/resources/views/components/template-preview.blade.php +++ b/resources/views/components/template-preview.blade.php @@ -116,6 +116,27 @@ function templatePreview(previewUrl, type, fieldName, recordIdFromView = null) { } catch (e) { console.log('[Preview] Could not get ID from Livewire'); } + + // Livewire event listener ekle (Livewire 3.x için) + if (window.Livewire) { + document.addEventListener('livewire:init', () => { + Livewire.on('template-saved', () => { + this.updatePreview(); + }); + }); + + // Eğer Livewire zaten yüklendiyse direkt dinle + if (window.Livewire.hook) { + Livewire.on('template-saved', () => { + this.updatePreview(); + }); + } + } + + // Window event listener ekle (alternatif - Livewire event'lerini de yakalar) + window.addEventListener('template-saved', () => { + this.updatePreview(); + }); }, async updatePreview() {