(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 += '
';
/* ── 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 += '
';
} 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 += '| Widget ▲ | ';
html += 'Init Time ▼ | ';
html += 'DOM Nodes ▲ | ';
html += 'Element ID | ';
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 += '' + esc(displayName) + '';
if (jw.elId) html += '⌖';
html += ' | ';
html += '' + jw.ms.toFixed(2) + 'ms | ';
html += '' + jwNodes + ' | ';
html += '' + esc(jw.elId || '—') + ' | ';
html += '
';
}
html += '
';
} 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 += '| Handle ▲ | ';
html += 'Type ▲ | ';
html += 'Transfer ▼ | ';
html += 'Original ▲ | ';
html += 'Load Time ▲ | ';
html += 'Status ▲ | ';
html += 'Source ▲ | ';
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 += '';
// Handle + path tooltip
html += '| ';
html += '' + esc(ar.handle) + '';
if (ar.src) html += ' ' + shortenSrc(ar.src) + ' ';
if (ar.ver) html += 'v' + esc(ar.ver) + '';
html += ' | ';
// Type
html += '' + ar.type + ' | ';
// Transfer size
if (ar.hasPerf) {
var saved = ar.decoded > 0 && ar.transfer < ar.decoded ? Math.round((1 - ar.transfer / ar.decoded) * 100) : 0;
html += '' + fmt(ar.transfer) + '';
if (saved > 0) html += ' -' + saved + '%';
html += ' | ';
} else {
html += '— | ';
}
// Original (decoded) size
if (ar.hasPerf && ar.decoded > 0) {
html += '' + fmt(ar.decoded) + ' | ';
} else {
html += '— | ';
}
// Load time
if (ar.hasPerf && ar.duration >= 0) {
html += '' + ar.duration + 'ms | ';
} else {
html += '— | ';
}
// Cache status
if (ar.hasPerf) {
if (ar.cached) {
html += 'Cached | ';
} else {
html += 'Network';
if (ar.protocol) html += ' ' + esc(ar.protocol) + '';
html += ' | ';
}
} else {
html += 'Inline | ';
}
// Source
if (ar.source === 'ep') {
html += 'EP | ';
} else if (ar.source === 'elementor') {
html += 'Elementor | ';
} else {
html += 'Other | ';
}
html += '
';
}
html += '
';
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);
});
}
})();