All files / assets/js gfmr-ssr-client.js

0% Statements 0/58
0% Branches 0/32
0% Functions 0/15
0% Lines 0/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177                                                                                                                                                                                                                                                                                                                                                                 
/**
 * WP GFM Renderer - SSR Client
 *
 * Handles client-side complement for Server-Side Rendering
 * - Sends rendered Mermaid SVG to server for caching
 * - Detects and processes SSR-pending elements
 *
 * @package WpGfmRenderer
 * @since 2.0.0
 */
 
/* global wpGfmConfig */
 
(function() {
    'use strict';
 
    // Wait for wpGfmConfig configuration to be available
    if (typeof wpGfmConfig === 'undefined') {
        console.warn('[GFMR SSR] wpGfmConfig configuration not found');
        return;
    }
 
    /**
     * Save Mermaid SVG to server cache
     *
     * @param {string} diagramId - Diagram identifier (content hash)
     * @param {string} theme - Theme identifier
     * @param {string} bgColor - Background color
     * @param {string} svg - SVG content
     */
    function saveMermaidSvgToCache(diagramId, theme, bgColor, svg) {
        // Only send if user is logged in (admin preview scenario)
        // Check if SSR nonce is available (indicates user can cache)
        if (!wpGfmConfig.mermaidSsrNonce) {
            console.log('[GFMR SSR] Skip SVG caching - no nonce available (user likely not logged in)');
            return;
        }
 
        const data = new URLSearchParams({
            action: 'gfmr_save_mermaid_svg',
            nonce: wpGfmConfig.mermaidSsrNonce,
            diagram_id: diagramId,
            theme: theme,
            bg_color: bgColor,
            svg: svg
        });
 
        // Use WordPress AJAX URL if available, fallback to standard path
        const ajaxUrl = wpGfmConfig.ajaxUrl || '/wp-admin/admin-ajax.php';
        fetch(ajaxUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded',
            },
            body: data
        })
        .then(response => response.json())
        .then(result => {
            if (result.success) {
                console.log('[GFMR SSR] Mermaid SVG cached:', diagramId);
            } else {
                console.warn('[GFMR SSR] Failed to cache Mermaid SVG:', result.data?.message);
            }
        })
        .catch(error => {
            console.error('[GFMR SSR] Error caching Mermaid SVG:', error);
        });
    }
 
    /**
     * Process SSR-pending Mermaid diagrams
     *
     * Waits for Mermaid to render, then sends SVG to server
     */
    function processSsrPendingDiagrams() {
        const pendingDiagrams = document.querySelectorAll('.gfmr-mermaid-container[data-ssr="pending"]');
 
        if (pendingDiagrams.length === 0) {
            return;
        }
 
        console.log('[GFMR SSR] Found', pendingDiagrams.length, 'SSR-pending diagrams');
 
        // Set up MutationObserver to detect when Mermaid rendering completes
        pendingDiagrams.forEach(container => {
            const diagramId = container.getAttribute('data-diagram-id');
            const theme = container.getAttribute('data-theme') || 'default';
            const bgColor = container.getAttribute('data-mermaid-bg-color') || 'transparent';
 
            // Create observer to watch for SVG insertion
            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    mutation.addedNodes.forEach((node) => {
                        if (node.nodeName === 'SVG') {
                            // SVG was rendered
                            const svg = node.outerHTML;
 
                            // Send to server for caching
                            saveMermaidSvgToCache(diagramId, theme, bgColor, svg);
 
                            // Mark as processed
                            container.setAttribute('data-ssr', 'cached');
 
                            // Disconnect observer
                            observer.disconnect();
                        }
                    });
                });
            });
 
            // Start observing
            observer.observe(container, {
                childList: true,
                subtree: true
            });
 
            // Set timeout to disconnect observer after 30 seconds
            setTimeout(() => {
                observer.disconnect();
                if (container.getAttribute('data-ssr') === 'pending') {
                    console.warn('[GFMR SSR] Timeout waiting for Mermaid render:', diagramId);
                    container.setAttribute('data-ssr', 'failed');
                }
            }, 30000);
        });
    }
 
    /**
     * Initialize SSR client
     */
    function init() {
        // Wait for DOM to be ready
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', init);
            return;
        }
 
        console.log('[GFMR SSR] Initializing SSR client');
 
        // Process SSR-pending diagrams
        processSsrPendingDiagrams();
 
        // Re-process if new content is dynamically added
        const contentObserver = new MutationObserver((mutations) => {
            let hasNewDiagrams = false;
            mutations.forEach((mutation) => {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === 1) { // Element node
                        if (node.matches && node.matches('.gfmr-mermaid-container[data-ssr="pending"]')) {
                            hasNewDiagrams = true;
                        } else if (node.querySelector) {
                            const pending = node.querySelector('.gfmr-mermaid-container[data-ssr="pending"]');
                            if (pending) {
                                hasNewDiagrams = true;
                            }
                        }
                    }
                });
            });
 
            if (hasNewDiagrams) {
                console.log('[GFMR SSR] Detected new SSR-pending diagrams');
                processSsrPendingDiagrams();
            }
        });
 
        // Observe document body for dynamic content
        contentObserver.observe(document.body, {
            childList: true,
            subtree: true
        });
    }
 
    // Start initialization
    init();
})();