From 1da16a54d63eba4b7e5a19b83eb5af9d6eaf274a Mon Sep 17 00:00:00 2001 From: DevSoftTech Server Date: Sat, 6 Jun 2026 12:51:21 +0530 Subject: [PATCH] Fix CKEditor initialization issues in discharge template editor Fixed the error: Uncaught TypeError: can't access property 'getElementsByTag', b is null Root Cause: - CKEditor was not properly destroyed before reinitialization - No error handling for editor state transitions - Missing timing delays for DOM readiness when loaded via AJAX - Inconsistent checking for CKEditor availability Improvements: 1. Safe destroy pattern - wrap destroy() in try-catch to handle state issues 2. Added typeof check for CKEDITOR instead of window.CKEDITOR 3. Added 100ms setTimeout delay before CKEDITOR.replace() to ensure cleanup 4. Added 150ms delay for initial editor load (especially for AJAX loads) 5. Wrapped all setData() calls in try-catch with textarea fallback 6. Added console warnings for debugging instead of silent failures 7. Check document.readyState before initialization 8. Re-initialize editor check after AJAX template load 9. Added element existence validation before replace() Changes follow the working pattern from: - app/Views/PathLab_Report/ultrasound_report_edit.php (safeReplace pattern) - app/Views/diagnosis/lab_final_report_editor.php (typeof checks) This ensures the editor works properly when: - Page loads normally - Page loads via AJAX (load_form_div) - User switches between templates using Edit button - User cancels edit and resets form Tested scenarios: - Initial page load - Edit template -> load data -> CKEditor shows content - Cancel -> CKEditor resets - Multiple edit/cancel cycles --- .../Setting/Template/discharge_templates.php | 109 +++++++++++++----- 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/app/Views/Setting/Template/discharge_templates.php b/app/Views/Setting/Template/discharge_templates.php index 1d4b40c..d4ed4a5 100644 --- a/app/Views/Setting/Template/discharge_templates.php +++ b/app/Views/Setting/Template/discharge_templates.php @@ -325,12 +325,21 @@ $status = (int) ($edit['status'] ?? 1); fieldTemplateCss.value = ''; } - if (window.CKEDITOR && CKEDITOR.instances[editorFieldId]) { - CKEDITOR.instances[editorFieldId].setData(initialTemplateHtml || '{{CONTENT}}'); + var defaultHtml = initialTemplateHtml || '{{CONTENT}}'; + if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) { + try { + CKEDITOR.instances[editorFieldId].setData(defaultHtml); + } catch (e) { + console.warn('CKEditor setData failed in reset:', e); + var templateHtmlEl = document.getElementById(editorFieldId); + if (templateHtmlEl) { + templateHtmlEl.value = defaultHtml; + } + } } else { var templateHtmlEl = document.getElementById(editorFieldId); if (templateHtmlEl) { - templateHtmlEl.value = initialTemplateHtml || '{{CONTENT}}'; + templateHtmlEl.value = defaultHtml; } } @@ -393,8 +402,16 @@ $status = (int) ($edit['status'] ?? 1); } var html = String(row.template_html || '{{CONTENT}}'); - if (window.CKEDITOR && CKEDITOR.instances[editorFieldId]) { - CKEDITOR.instances[editorFieldId].setData(html); + if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) { + try { + CKEDITOR.instances[editorFieldId].setData(html); + } catch (e) { + console.warn('CKEditor setData failed in setForm:', e); + var templateHtmlEl = document.getElementById(editorFieldId); + if (templateHtmlEl) { + templateHtmlEl.value = html; + } + } } else { var templateHtmlEl = document.getElementById(editorFieldId); if (templateHtmlEl) { @@ -427,33 +444,50 @@ $status = (int) ($edit['status'] ?? 1); } function initTemplateEditor() { - if (!window.CKEDITOR) { + if (typeof CKEDITOR === 'undefined') { + console.warn('CKEditor not loaded'); + return; + } + + var editorEl = document.getElementById(editorFieldId); + if (!editorEl) { + console.warn('Editor textarea not found:', editorFieldId); return; } CKEDITOR.config.versionCheck = false; CKEDITOR.config.removePlugins = ''; - if (CKEDITOR.instances[editorFieldId]) { - CKEDITOR.instances[editorFieldId].destroy(true); + // Safe destroy - wrap in try-catch to handle any state issues + if (CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) { + try { + CKEDITOR.instances[editorFieldId].destroy(true); + } catch (e) { + console.warn('CKEditor destroy failed for', editorFieldId, '- This is usually safe to ignore', e); + } } - if (document.getElementById(editorFieldId)) { - CKEDITOR.replace(editorFieldId, { - height: 360, - toolbar: [ - { name: 'document', items: ['Source'] }, - { name: 'clipboard', items: ['Undo', 'Redo'] }, - { name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'RemoveFormat'] }, - { name: 'paragraph', items: ['NumberedList', 'BulletedList', 'Outdent', 'Indent', 'Blockquote'] }, - { name: 'links', items: ['Link', 'Unlink'] }, - { name: 'insert', items: ['Table', 'HorizontalRule', 'SpecialChar'] }, - { name: 'styles', items: ['Format', 'Font', 'FontSize'] }, - { name: 'colors', items: ['TextColor', 'BGColor'] }, - { name: 'tools', items: ['Maximize'] } - ] - }); - } + // Small delay to ensure DOM is ready and cleanup is complete + setTimeout(function() { + try { + CKEDITOR.replace(editorFieldId, { + height: 360, + toolbar: [ + { name: 'document', items: ['Source'] }, + { name: 'clipboard', items: ['Undo', 'Redo'] }, + { name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'RemoveFormat'] }, + { name: 'paragraph', items: ['NumberedList', 'BulletedList', 'Outdent', 'Indent', 'Blockquote'] }, + { name: 'links', items: ['Link', 'Unlink'] }, + { name: 'insert', items: ['Table', 'HorizontalRule', 'SpecialChar'] }, + { name: 'styles', items: ['Format', 'Font', 'FontSize'] }, + { name: 'colors', items: ['TextColor', 'BGColor'] }, + { name: 'tools', items: ['Maximize'] } + ] + }); + } catch (e) { + console.error('CKEditor replace failed:', e); + } + }, 100); } function toggleCustomSizeFields() { @@ -468,16 +502,29 @@ $status = (int) ($edit['status'] ?? 1); } function syncTemplateEditor() { - if (!window.CKEDITOR) { + if (typeof CKEDITOR === 'undefined') { return; } - if (CKEDITOR.instances[editorFieldId]) { - CKEDITOR.instances[editorFieldId].updateElement(); + if (CKEDITOR.instances && CKEDITOR.instances[editorFieldId]) { + try { + CKEDITOR.instances[editorFieldId].updateElement(); + } catch (e) { + console.warn('CKEditor updateElement failed:', e); + } } } - initTemplateEditor(); + // Initialize editor after a short delay to ensure DOM is ready + // This is especially important when loaded via AJAX + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + setTimeout(initTemplateEditor, 150); + }); + } else { + setTimeout(initTemplateEditor, 150); + } + toggleCustomSizeFields(); if (pageSizeEl) { @@ -545,6 +592,12 @@ $status = (int) ($edit['status'] ?? 1); } setFormFromTemplateRow(data.row); + + // Reinitialize editor after data is loaded to ensure proper state + if (typeof CKEDITOR !== 'undefined' && CKEDITOR.instances && !CKEDITOR.instances[editorFieldId]) { + setTimeout(initTemplateEditor, 200); + } + if (fieldTemplateName) { fieldTemplateName.focus(); }