/** * Block Editor Auto-Sync * * Automatically syncs blocks from BlockEditorComponent to ContentFormComponent * when blocks are added, removed, updated, or reordered. */ export class BlockEditorSync { constructor(blockEditorElement, contentFormComponentId) { this.blockEditorElement = blockEditorElement; this.contentFormComponentId = contentFormComponentId; this.syncDebounceTimer = null; this.SYNC_DEBOUNCE_MS = 500; // Debounce sync calls by 500ms this.init(); } init() { // Listen for LiveComponent update events this.blockEditorElement.addEventListener('livecomponent:updated', (e) => { this.handleBlockEditorUpdate(e); }); // Also listen for custom block events document.addEventListener('livecomponent:event', (e) => { const eventData = e.detail; if (eventData && eventData.component_id) { const blockEditorId = this.blockEditorElement.dataset.liveComponent; if (eventData.component_id === blockEditorId) { // Check if it's a block-related event if (eventData.event_name && ( eventData.event_name.includes('block:') || eventData.event_name.includes('blocks:') )) { this.scheduleSync(); } } } }); } /** * Handle BlockEditorComponent update */ handleBlockEditorUpdate(e) { // Debounce sync to avoid too many requests this.scheduleSync(); } /** * Schedule sync with debouncing */ scheduleSync() { if (this.syncDebounceTimer) { clearTimeout(this.syncDebounceTimer); } this.syncDebounceTimer = setTimeout(() => { this.syncBlocks(); }, this.SYNC_DEBOUNCE_MS); } /** * Sync blocks from BlockEditorComponent to ContentFormComponent */ async syncBlocks() { if (!this.contentFormComponentId) { console.warn('BlockEditorSync: No content form component ID'); return; } // Find ContentFormComponent element const contentFormElement = document.querySelector( `[data-live-component="${this.contentFormComponentId}"]` ); if (!contentFormElement) { console.warn('BlockEditorSync: ContentFormComponent not found'); return; } // Get LiveComponent instance const liveComponent = window.LiveComponents?.getComponent?.(this.contentFormComponentId); if (!liveComponent) { console.warn('BlockEditorSync: LiveComponent instance not found'); return; } // Call syncBlocksFromBlockEditor action on ContentFormComponent try { await liveComponent.action('syncBlocksFromBlockEditor'); } catch (error) { console.error('BlockEditorSync: Failed to sync blocks', error); } } /** * Initialize all block editor syncs on the page */ static initializeAll() { const instances = []; // Find all BlockEditorComponents const blockEditorElements = document.querySelectorAll( '[data-live-component^="admin-block-editor:"]' ); blockEditorElements.forEach(blockEditorElement => { // Find parent ContentFormComponent const contentFormElement = blockEditorElement.closest( '[data-live-component^="admin-content-form:"]' ); if (contentFormElement) { const contentFormComponentId = contentFormElement.dataset.liveComponent; instances.push(new BlockEditorSync(blockEditorElement, contentFormComponentId)); } }); return instances; } } // Auto-initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { BlockEditorSync.initializeAll(); }); } else { BlockEditorSync.initializeAll(); } // Re-initialize when LiveComponents are loaded dynamically document.addEventListener('livecomponent:loaded', () => { BlockEditorSync.initializeAll(); });