Add template save event handling and update preview functionality: Implemented afterSave method in Footer, Header, Menu, and Section templates to dispatch a 'template-saved' event for Livewire. Updated template preview components to listen for this event, ensuring previews are refreshed after template modifications. Enhanced viewData method in template forms for better record ID handling.
This commit is contained in:
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,13 +50,11 @@ class FooterTemplateForm
|
||||
|
||||
// Preview Component - placed after editor
|
||||
View::make('components.template-preview')
|
||||
->viewData(function ($record) {
|
||||
return [
|
||||
->viewData([
|
||||
'type' => 'footer',
|
||||
'fieldName' => 'html_content',
|
||||
'recordId' => $record?->id,
|
||||
];
|
||||
})
|
||||
'recordId' => null, // Will be extracted from URL by JavaScript
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('is_active')
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,11 @@ class HeaderTemplateForm
|
||||
|
||||
// Preview Component - placed after editor
|
||||
View::make('components.template-preview')
|
||||
->viewData(function ($record) {
|
||||
return [
|
||||
->viewData([
|
||||
'type' => 'header',
|
||||
'fieldName' => 'html_content',
|
||||
'recordId' => $record?->id,
|
||||
];
|
||||
})
|
||||
'recordId' => null, // Will be extracted from URL by JavaScript
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('is_active')
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,13 +46,11 @@ class MenuTemplateForm
|
||||
|
||||
// Preview Component
|
||||
View::make('components.menu-template-preview')
|
||||
->viewData(function ($record) {
|
||||
return [
|
||||
->viewData([
|
||||
'type' => 'menu',
|
||||
'fieldName' => 'html_content',
|
||||
'recordId' => $record?->id,
|
||||
];
|
||||
})
|
||||
'recordId' => null, // Will be extracted from URL by JavaScript
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('is_active')
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,13 +49,11 @@ class SectionTemplateForm
|
||||
|
||||
// Preview Component - placed after editor
|
||||
View::make('components.template-preview')
|
||||
->viewData(function ($record) {
|
||||
return [
|
||||
->viewData([
|
||||
'type' => 'section',
|
||||
'fieldName' => 'html_content',
|
||||
'recordId' => $record?->id,
|
||||
];
|
||||
})
|
||||
'recordId' => null, // Will be extracted from URL by JavaScript
|
||||
])
|
||||
->columnSpanFull(),
|
||||
|
||||
Toggle::make('is_active')
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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') }}'"
|
||||
>
|
||||
<code class="text-xs font-mono" x-text="'{' + type + '.' + example + '}'"></code>
|
||||
@@ -105,7 +105,7 @@
|
||||
size="sm"
|
||||
color="primary"
|
||||
outlined
|
||||
@click="insertPlaceholder('{{ $fieldName }}', 'menu')"
|
||||
x-on:click="window.insertPlaceholder('{{ $fieldName }}', 'menu')"
|
||||
>
|
||||
<code class="text-xs font-mono">{menu}</code>
|
||||
</x-filament::button>
|
||||
@@ -113,7 +113,7 @@
|
||||
size="sm"
|
||||
color="primary"
|
||||
outlined
|
||||
@click="insertPlaceholder('{{ $fieldName }}', 'staticMenu')"
|
||||
x-on:click="window.insertPlaceholder('{{ $fieldName }}', 'staticMenu')"
|
||||
>
|
||||
<code class="text-xs font-mono">{staticMenu}</code>
|
||||
</x-filament::button>
|
||||
@@ -179,119 +179,128 @@
|
||||
// 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) {
|
||||
try {
|
||||
const container = editor.getContainerDomNode();
|
||||
if (container && container.closest && container.closest('[data-field-name=\'' + fieldName + '\']')) {
|
||||
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;
|
||||
const model = editor.getModel();
|
||||
currentValue = model.getValue();
|
||||
const selection = editor.getSelection();
|
||||
if (selection) {
|
||||
cursorPosition = model.getOffsetAt(selection.getStartPosition());
|
||||
} else {
|
||||
cursorPosition = currentValue.length;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.debug('Monaco Editor container check failed:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// Monaco Editor'ı focus et (önce focus et ki cursor pozisyonu doğru alınsın)
|
||||
monacoEditorInstance.focus();
|
||||
|
||||
// Kısa bir delay ile cursor pozisyonunu al (focus işleminin tamamlanması için)
|
||||
setTimeout(() => {
|
||||
// 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: new window.monaco.Range(
|
||||
model.getPositionAt(cursorPosition).lineNumber,
|
||||
model.getPositionAt(cursorPosition).column,
|
||||
model.getPositionAt(cursorPosition).lineNumber,
|
||||
model.getPositionAt(cursorPosition).column
|
||||
),
|
||||
range: range,
|
||||
text: placeholderText
|
||||
}]);
|
||||
|
||||
// Cursor pozisyonunu güncelle
|
||||
const newPosition = model.getPositionAt(cursorPosition + placeholderText.length);
|
||||
monacoEditorInstance.setPosition(newPosition);
|
||||
// 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 Monaco Editor'ın change event'ini tetikle
|
||||
// Filament CodeEditor otomatik olarak değişiklikleri algılar
|
||||
// Filament form state'ini güncellemek için güncel değeri al
|
||||
const updatedValue = model.getValue();
|
||||
|
||||
// Filament form state'ini güncelle
|
||||
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
|
||||
});
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user