­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ (function () { 'use strict'; if (typeof epDebugData === 'undefined') return; var D = epDebugData; /* ── Helpers ──────────────────────────────────────────── */ function fmt(bytes) { if (bytes === 0) return '0 B'; var k = 1024, sizes = ['B', 'KB', 'MB', 'GB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; } function perfClass(ms, ok, bad) { if (ms >= bad) return 'epd-perf-bad'; if (ms >= ok) return 'epd-perf-ok'; return 'epd-perf-good'; } function esc(str) { var d = document.createElement('div'); d.textContent = str; return d.innerHTML; } function getResourceDetails() { var entries = {}; if (window.performance && performance.getEntriesByType) { var res = performance.getEntriesByType('resource'); for (var i = 0; i < res.length; i++) { var r = res[i]; var cached = r.transferSize === 0 && r.decodedBodySize > 0; entries[r.name] = { transferSize: r.transferSize || 0, decodedSize: r.decodedBodySize || 0, encodedSize: r.encodedBodySize || 0, duration: Math.round(r.duration), cached: cached, protocol: r.nextHopProtocol || '', }; } } return entries; } function getPageTiming() { var t = {}; if (window.performance && performance.timing) { var pt = performance.timing; t.domReady = pt.domContentLoadedEventEnd - pt.navigationStart; t.windowLoad = pt.loadEventEnd > 0 ? pt.loadEventEnd - pt.navigationStart : null; t.ttfb = pt.responseStart - pt.navigationStart; t.domInteractive = pt.domInteractive - pt.navigationStart; } if (window.performance && performance.getEntriesByType) { var paint = performance.getEntriesByType('paint'); for (var i = 0; i < paint.length; i++) { if (paint[i].name === 'first-contentful-paint') { t.fcp = Math.round(paint[i].startTime); } } } t.domNodes = document.querySelectorAll('*').length; return t; } function scanDOMWidgets() { var widgets = []; var els = document.querySelectorAll('.elementor-widget[data-widget_type]'); for (var i = 0; i < els.length; i++) { var el = els[i]; var fullType = el.getAttribute('data-widget_type') || ''; var elId = el.getAttribute('data-id') || ''; if (!fullType) continue; var parts = fullType.split('.'); var name = parts[0]; var nodes = el.querySelectorAll('*').length; var htmlBytes = 0; try { htmlBytes = el.outerHTML.length * 2; } catch (e) {} widgets.push({ name: name, skin: parts[1] || 'default', id: elId, isEP: name.indexOf('bdt-') === 0 || name.indexOf('ep-') === 0, nodes: nodes, htmlSize: htmlBytes }); } return widgets; } function findJsEntryById(elementId) { var jsData = window.epDebugJS; if (!jsData || !jsData.widgets || !jsData.widgets.length) return null; for (var i = 0; i < jsData.widgets.length; i++) { if (jsData.widgets[i].elId === elementId) return jsData.widgets[i]; } return null; } /* ── Widget Inspect ──────────────────────────────────── */ function inspectWidget(elementId) { var el = document.querySelector('[data-id="' + elementId + '"]'); if (!el) return; el.classList.remove('epd-inspect-highlight'); if (el._epdTimer) clearTimeout(el._epdTimer); el.scrollIntoView({ behavior: 'smooth', block: 'center' }); requestAnimationFrame(function () { requestAnimationFrame(function () { el.classList.add('epd-inspect-highlight'); el._epdTimer = setTimeout(function () { el.classList.remove('epd-inspect-highlight'); }, 2500); }); }); } /* ── Build Panel HTML ────────────────────────────────── */ function buildPanel() { var timing = getPageTiming(); var resDetails = getResourceDetails(); var jsData = window.epDebugJS || { widgets: [], pageStart: 0 }; var domWidgets = scanDOMWidgets(); var isEditorPreview = D.widgets.count === 0 && domWidgets.length > 0; var phpLookup = {}; for (var pi = 0; pi < D.widgets.items.length; pi++) { phpLookup[D.widgets.items[pi].id] = D.widgets.items[pi]; } var effectiveWidgetCount = Math.max(domWidgets.length, D.widgets.count); var memPct = D.page.memory_limit > 0 ? Math.round((D.page.memory_usage / D.page.memory_limit) * 100) : 0; var html = ''; html += '
'; // Header html += '
'; html += 'Element Pack Debug'; html += '
'; html += 'PHP: ' + D.page.total_time + 'ms'; html += 'Mem: ' + fmt(D.page.memory_usage) + ''; html += 'Queries: ' + D.page.db_queries_total + ''; html += 'Widgets: ' + effectiveWidgetCount + ''; if (timing.fcp) { html += 'FCP: ' + timing.fcp + 'ms'; } html += '
'; html += ''; html += '
'; // Tabs html += '
'; html += '
Overview
'; html += '
Widgets ' + effectiveWidgetCount + '
'; html += '
JS Timing ' + jsData.widgets.length + '
'; html += '
Assets ' + (D.assets.scripts_total + D.assets.styles_total) + '
'; html += '
Environment
'; html += '
'; html += '
'; /* ── Overview Tab ───────────────────────────────────── */ html += '
'; html += '
'; html += '
'; html += '
PHP Generation
'; html += '
' + D.page.total_time + 'ms
'; html += '
Widget render: ' + (isEditorPreview ? 'client-side' : D.widgets.total_render_time + 'ms') + '
'; html += '
'; html += '
'; html += '
Memory Usage
'; html += '
' + fmt(D.page.memory_usage) + '
'; html += '
Peak: ' + fmt(D.page.memory_peak) + ' / Limit: ' + esc(D.page.memory_limit_raw) + '
'; html += '
'; html += '
'; html += '
'; html += '
Database Queries
'; html += '
' + D.page.db_queries_total + '
'; html += '
EP widget queries: ' + D.widgets.total_queries + '
'; html += '
'; html += '
'; html += '
Widgets on Page
'; html += '
' + effectiveWidgetCount + '
'; var epDomCount = 0; for (var ci = 0; ci < domWidgets.length; ci++) { if (domWidgets[ci].isEP) epDomCount++; } if (D.widgets.count > 0 && domWidgets.length > D.widgets.count) { html += '
' + D.widgets.count + ' PHP-profiled / ' + (domWidgets.length - D.widgets.count) + ' cached — ' + epDomCount + ' EP
'; } else if (isEditorPreview) { html += '
' + epDomCount + ' Element Pack / ' + (domWidgets.length - epDomCount) + ' other (DOM scan)
'; } else { html += '
Total memory delta: ' + fmt(D.widgets.total_memory) + '
'; } html += '
'; html += '
'; html += '
Browser Timing
'; html += '
'; if (timing.domReady) html += '' + timing.domReady + 'ms'; html += '
'; html += '
'; if (timing.ttfb) html += 'TTFB: ' + timing.ttfb + 'ms | '; if (timing.fcp) html += 'FCP: ' + timing.fcp + 'ms | '; html += 'DOM nodes: ' + timing.domNodes; html += '
'; html += '
'; html += '
'; html += '
Loaded Assets
'; html += '
' + D.assets.scripts_total + ' JS / ' + D.assets.styles_total + ' CSS
'; html += '
EP: ' + D.assets.ep_scripts.length + ' scripts, ' + D.assets.ep_styles.length + ' styles
'; html += '
'; html += '
'; // grid html += '
'; // pane /* ── Widgets Tab ────────────────────────────────────── */ html += '
'; if (domWidgets.length > 0) { var widgetRows = domWidgets.slice().sort(function (a, b) { var pa = phpLookup[a.id], pb = phpLookup[b.id]; var ma = pa ? pa.memory_delta : -1, mb = pb ? pb.memory_delta : -1; return mb - ma; }); var phpProfiled = 0; for (var pc = 0; pc < domWidgets.length; pc++) { if (phpLookup[domWidgets[pc].id]) phpProfiled++; } var unprofiled = domWidgets.length - phpProfiled; html += '
'; if (isEditorPreview) { html += 'ⓘ Editor preview — click a widget name to scroll & highlight it on the page.'; } else if (unprofiled > 0) { html += 'ⓘ ' + phpProfiled + ' widgets PHP-profiled, ' + unprofiled + ' served from cache (no PHP metrics). Click a name to scroll & highlight.'; } else { html += 'ⓘ Click a widget name to scroll & highlight it on the page. Click a row to expand query details.'; } html += '
'; html += '
'; html += ''; html += ''; html += ''; if (!isEditorPreview) { html += ''; html += ''; html += ''; html += ''; } else { html += ''; } html += ''; html += ''; html += ''; html += ''; var colSpan = isEditorPreview ? 6 : 8; for (var wi = 0; wi < widgetRows.length; wi++) { var dw = widgetRows[wi]; var php = phpLookup[dw.id] || null; var jsEntry = findJsEntryById(dw.id); var nodeCount = dw.nodes || 0; var htmlSize = dw.htmlSize || 0; var renderT = php ? php.render_time : -1; var memD = php ? php.memory_delta : -1; var memP = php ? (php.memory_peak || 0) : -1; var dbQ = php ? php.db_queries : -1; html += ''; html += ''; html += ''; if (!isEditorPreview) { // Render time if (php) { html += ''; } else { html += ''; } // Memory delta if (php) { html += ''; } else { html += ''; } // Peak if (php) { html += ''; } else { html += ''; } // Queries if (php) { html += ''; } else { html += ''; } } else { // JS Init (editor) if (jsEntry) { html += ''; } else { html += ''; } } // DOM Memory (always) html += ''; // Nodes (always) html += ''; // Source html += ''; html += ''; // Query detail row (PHP frontend only) if (php && php.queries && php.queries.length > 0) { var phpIdx = D.widgets.items.indexOf(php); html += ''; } } html += '
Widget Render Memory Δ Peak Queries JS Init DOM Mem Nodes Src
' + php.render_time + 'mscached' + fmt(php.memory_delta) + '' + fmt(memP) + '' + (php.db_queries > 0 ? '' + php.db_queries + '' : '0') + '' + jsEntry.ms.toFixed(2) + 'ms' + fmt(htmlSize) + '' + nodeCount + '' + (dw.isEP ? 'EP' : 'Core') + '
'; } else { html += '

No widgets detected on this page.

'; } html += '
'; /* ── JS Timing Tab ──────────────────────────────────── */ html += '
'; html += '
'; if (timing.domReady) { html += '
DOM Ready
' + timing.domReady + 'ms
'; } if (timing.windowLoad) { html += '
Window Load
' + timing.windowLoad + 'ms
'; } if (timing.fcp) { html += '
First Contentful Paint
' + timing.fcp + 'ms
'; } if (timing.domInteractive) { html += '
DOM Interactive
' + timing.domInteractive + 'ms
'; } html += '
DOM Nodes
' + timing.domNodes + '
'; if (performance.memory) { html += '
JS Heap
' + fmt(performance.memory.usedJSHeapSize) + ' / ' + fmt(performance.memory.jsHeapSizeLimit) + '
'; } html += '
'; if (jsData.widgets.length > 0) { var jsSorted = jsData.widgets.slice().sort(function (a, b) { return b.ms - a.ms; }); html += '

Widget JS Init Times

'; html += '
'; html += ''; html += ''; html += ''; html += ''; html += ''; for (var j = 0; j < jsSorted.length; j++) { var jw = jsSorted[j]; var displayName = jw.widgetType || jw.tag.replace('frontend/element_ready/', ''); var jwNodes = jw.nodes || 0; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; } html += '
Widget Init Time DOM Nodes Element ID
'; html += '' + esc(displayName) + ''; if (jw.elId) html += ''; html += '' + jw.ms.toFixed(2) + 'ms' + jwNodes + '' + esc(jw.elId || '—') + '
'; } else { html += '

No widget JS init timing captured.

'; } html += '
'; /* ── Assets Tab ─────────────────────────────────────── */ html += '
'; var allAssets = []; var totalTransfer = 0, totalDecoded = 0, cacheHits = 0, networkLoads = 0; function pushAssets(list, type) { for (var ai = 0; ai < list.length; ai++) { var a = list[ai]; var r = findResource(a.src, resDetails); var row = { handle: a.handle, src: a.src || '', ver: a.ver || '', deps: a.deps || 0, type: type, source: a.source || 'other', inFooter: a.in_footer || false, transfer: r ? r.transferSize : -1, decoded: r ? r.decodedSize : -1, encoded: r ? r.encodedSize : -1, duration: r ? r.duration : -1, cached: r ? r.cached : false, protocol: r ? r.protocol : '', hasPerf: !!r, }; if (row.hasPerf) { totalTransfer += row.transfer; totalDecoded += row.decoded; if (row.cached) cacheHits++; else networkLoads++; } allAssets.push(row); } } pushAssets(D.assets.scripts_detail || [], 'JS'); pushAssets(D.assets.styles_detail || [], 'CSS'); var epAssets = 0, elAssets = 0; for (var ac = 0; ac < allAssets.length; ac++) { if (allAssets[ac].source === 'ep') epAssets++; else if (allAssets[ac].source === 'elementor') elAssets++; } // Summary cards html += '
'; html += '
Total Assets
'; html += '
' + D.assets.scripts_total + ' JS / ' + D.assets.styles_total + ' CSS
'; html += '
EP: ' + epAssets + ' | Elementor: ' + elAssets + ' | Other: ' + (allAssets.length - epAssets - elAssets) + '
'; html += '
Network Transfer
'; html += '
' + fmt(totalTransfer) + '
'; html += '
Decoded: ' + fmt(totalDecoded); if (totalDecoded > 0 && totalTransfer > 0 && totalTransfer < totalDecoded) { html += ' (saved ' + Math.round((1 - totalTransfer / totalDecoded) * 100) + '% via compression)'; } html += '
'; html += '
Cache Performance
'; var totalMeasured = cacheHits + networkLoads; html += '
' + cacheHits + ' cached / ' + networkLoads + ' network
'; if (totalMeasured > 0) { var cachePct = Math.round(cacheHits / totalMeasured * 100); html += '
'; } html += '
'; html += '
'; // Assets table html += '
'; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; var assetsSorted = allAssets.slice().sort(function (a, b) { return b.transfer - a.transfer; }); for (var at = 0; at < assetsSorted.length; at++) { var ar = assetsSorted[at]; var statusVal = ar.cached ? 0 : (ar.hasPerf ? 1 : 2); var sourceVal = ar.source === 'ep' ? 0 : (ar.source === 'elementor' ? 1 : 2); html += ''; if (ar.src) html += '
' + shortenSrc(ar.src) + '
'; if (ar.ver) html += 'v' + esc(ar.ver) + ''; html += ''; // Type html += ''; // Transfer size if (ar.hasPerf) { var saved = ar.decoded > 0 && ar.transfer < ar.decoded ? Math.round((1 - ar.transfer / ar.decoded) * 100) : 0; html += ''; } else { html += ''; } // Original (decoded) size if (ar.hasPerf && ar.decoded > 0) { html += ''; } else { html += ''; } // Load time if (ar.hasPerf && ar.duration >= 0) { html += ''; } else { html += ''; } // Cache status if (ar.hasPerf) { if (ar.cached) { html += ''; } else { html += ''; } } else { html += ''; } // Source if (ar.source === 'ep') { html += ''; } else if (ar.source === 'elementor') { html += ''; } else { html += ''; } html += ''; } html += '
Handle Type Transfer Original Load Time Status Source
' + ar.type + '' + fmt(ar.transfer) + ''; if (saved > 0) html += ' -' + saved + '%'; html += '' + fmt(ar.decoded) + '' + ar.duration + 'msCachedNetwork'; if (ar.protocol) html += ' ' + esc(ar.protocol) + ''; html += 'InlineEPElementorOther
'; html += '
'; /* ── Environment Tab ────────────────────────────────── */ html += '
'; html += '
'; var envRows = [ ['PHP Version', D.page.php_version], ['WordPress Version', D.page.wp_version], ['Elementor Version', D.page.elementor_version], ['Element Pack Version', D.page.ep_version], ['PHP Memory Limit', D.page.memory_limit_raw], ['Max Execution Time', D.server.max_execution_time + 's'], ['PHP SAPI', D.server.php_sapi], ['OPcache', D.server.opcache_enabled ? 'Enabled' : 'Disabled', D.server.opcache_enabled], ['Object Cache', D.server.object_cache ? 'Enabled' : 'Disabled', D.server.object_cache], ['Asset Optimization', D.page.asset_optimization ? 'Enabled' : 'Disabled', D.page.asset_optimization], ['SAVEQUERIES', D.page.savequeries ? 'Enabled' : 'Disabled', D.page.savequeries], ['User Agent', navigator.userAgent], ['Screen', window.screen.width + 'x' + window.screen.height + ' @' + window.devicePixelRatio + 'x'], ['Viewport', window.innerWidth + 'x' + window.innerHeight], ]; for (var e = 0; e < envRows.length; e++) { var cls = ''; if (envRows[e].length === 3) cls = envRows[e][2] ? ' epd-on' : ' epd-off'; html += '
' + esc(envRows[e][0]) + '
'; html += '
' + esc(envRows[e][1]) + '
'; } html += '
'; html += '
'; // content return html; } function findResource(src, resMap) { if (!src) return null; var srcNorm = src.replace(/^https?:/, ''); for (var url in resMap) { if (url.indexOf(srcNorm) !== -1 || srcNorm.indexOf(url.replace(/^https?:/, '')) !== -1) { return resMap[url]; } } return null; } function shortenSrc(src) { if (!src) return ''; var idx = src.indexOf('/wp-content/'); if (idx > -1) return '...' + src.substring(idx); return src; } /* ── Initialize ──────────────────────────────────────── */ function init() { var toggle = document.createElement('button'); toggle.id = 'ep-debug-toggle'; toggle.innerHTML = '🐛'; toggle.title = 'Element Pack Debug Panel'; document.body.appendChild(toggle); var panel = document.createElement('div'); panel.id = 'ep-debug-panel'; document.body.appendChild(panel); window.epDebugPanel = { toggle: function () { var isOpen = panel.classList.contains('open'); if (isOpen) { panel.classList.remove('open'); toggle.classList.remove('active'); } else { panel.innerHTML = buildPanel(); bindEvents(panel, toggle); panel.classList.add('open'); toggle.classList.add('active'); } }, }; toggle.addEventListener('click', function () { window.epDebugPanel.toggle(); }); } function bindTableSort(table, panel) { var headers = table.querySelectorAll('th[data-sort]'); for (var h = 0; h < headers.length; h++) { headers[h].addEventListener('click', function () { var sortKey = this.getAttribute('data-sort'); var tbody = table.querySelector('tbody'); var rows = Array.prototype.slice.call(tbody.querySelectorAll('tr[data-sortable]')); var isDesc = this.classList.contains('sorted') && this.querySelector('.epd-sort-arrow').innerHTML === '\u25BC'; var allH = table.querySelectorAll('th[data-sort]'); for (var x = 0; x < allH.length; x++) allH[x].classList.remove('sorted'); this.classList.add('sorted'); this.querySelector('.epd-sort-arrow').innerHTML = isDesc ? '\u25B2' : '\u25BC'; rows.sort(function (a, b) { var va = a.getAttribute('data-sort-' + sortKey) || ''; var vb = b.getAttribute('data-sort-' + sortKey) || ''; var na = parseFloat(va); var nb = parseFloat(vb); if (!isNaN(na) && !isNaN(nb)) { return isDesc ? na - nb : nb - na; } return isDesc ? va.localeCompare(vb) : vb.localeCompare(va); }); while (tbody.firstChild) tbody.removeChild(tbody.firstChild); for (var r = 0; r < rows.length; r++) { tbody.appendChild(rows[r]); var idx = rows[r].getAttribute('data-widget-idx'); if (idx !== null) { var detailRow = panel.querySelector('[data-detail-for="' + idx + '"]'); if (detailRow) tbody.appendChild(detailRow); } } }); } } function bindEvents(panel, toggle) { // Close button panel.querySelector('.epd-close').addEventListener('click', function () { panel.classList.remove('open'); toggle.classList.remove('active'); }); // Tab switching var tabs = panel.querySelectorAll('.epd-tab'); var panes = panel.querySelectorAll('.epd-tab-pane'); for (var t = 0; t < tabs.length; t++) { tabs[t].addEventListener('click', function () { var tabName = this.getAttribute('data-tab'); for (var i = 0; i < tabs.length; i++) tabs[i].classList.remove('active'); for (var j = 0; j < panes.length; j++) panes[j].classList.remove('active'); this.classList.add('active'); panel.querySelector('[data-pane="' + tabName + '"]').classList.add('active'); }); } // Inspect: click on widget name or inspect button → scroll to & highlight var inspectBtns = panel.querySelectorAll('.epd-inspect-btn'); for (var ib = 0; ib < inspectBtns.length; ib++) { inspectBtns[ib].addEventListener('click', function (e) { e.stopPropagation(); var row = this.closest('tr[data-inspect-id]'); if (row) inspectWidget(row.getAttribute('data-inspect-id')); }); } var inspectNames = panel.querySelectorAll('tr[data-inspect-id] .epd-widget-name'); for (var wn = 0; wn < inspectNames.length; wn++) { inspectNames[wn].style.cursor = 'pointer'; inspectNames[wn].addEventListener('click', function (e) { e.stopPropagation(); var row = this.closest('tr[data-inspect-id]'); if (row) inspectWidget(row.getAttribute('data-inspect-id')); }); } // Sortable tables (Widgets tab + JS Timing tab) var sortTables = panel.querySelectorAll('.epd-sortable-table'); for (var st = 0; st < sortTables.length; st++) { bindTableSort(sortTables[st], panel); } // Click row to expand query details (PHP frontend Widgets tab) var wTable = panel.querySelector('#epd-widgets-table'); if (wTable) { wTable.addEventListener('click', function (e) { if (e.target.closest('.epd-inspect-btn') || e.target.closest('.epd-widget-name')) return; var row = e.target.closest('tr[data-widget-idx]'); if (!row) return; var idx = row.getAttribute('data-widget-idx'); var detail = panel.querySelector('[data-detail-for="' + idx + '"]'); if (detail) { detail.style.display = detail.style.display === 'none' ? '' : 'none'; } }); } // Resize handle var resize = panel.querySelector('.epd-resize'); if (resize) { var startY, startH; resize.addEventListener('mousedown', function (e) { startY = e.clientY; startH = panel.offsetHeight; document.addEventListener('mousemove', onResize); document.addEventListener('mouseup', stopResize); e.preventDefault(); }); function onResize(e) { var newH = startH + (startY - e.clientY); panel.style.height = Math.max(200, Math.min(window.innerHeight - 40, newH)) + 'px'; } function stopResize() { document.removeEventListener('mousemove', onResize); document.removeEventListener('mouseup', stopResize); } } // Keyboard shortcut document.addEventListener('keydown', function (e) { if (e.ctrlKey && e.shiftKey && e.key === 'D') { e.preventDefault(); window.epDebugPanel.toggle(); } }); } /* ── Boot ────────────────────────────────────────────── */ if (document.readyState === 'complete' || document.readyState === 'interactive') { setTimeout(init, 0); } else { window.addEventListener('DOMContentLoaded', function () { setTimeout(init, 100); }); } })();