Skip to content

Commit e766af7

Browse files
committed
Support panel rendered JS event.
This fixes the problem of the Timer Panel not inserting the browser timings section after being loaded via the HistoryPanel. These events could be wired into to better render panels or support a more dynamic toolbar and/or panel.
1 parent f4b5dbf commit e766af7

File tree

6 files changed

+74
-49
lines changed

6 files changed

+74
-49
lines changed

debug_toolbar/panels/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ def scripts(self):
108108
"""
109109
Scripts used by the HTML content of the panel when it's displayed.
110110
111-
When a panel is loaded on the frontend, a JavaScript event will be
112-
dispatched of the format ``djdt.panel.[panel_id]``. The scripts used can
113-
listen for this event to execute functionality on panel load.
111+
When a panel is rendered on the frontend, the ``djdt.panel.render``
112+
JavaScript event will be dispatched. The scripts can listen for
113+
this event to support dynamic functionality.
114114
"""
115115
return []
116116

debug_toolbar/static/debug_toolbar/js/timer.js

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import { $$ } from "./utils.js";
2+
13
function insertBrowserTiming() {
4+
console.log(["inserted"]);
25
const timingOffset = performance.timing.navigationStart,
36
timingEnd = performance.timing.loadEventEnd,
47
totalTime = timingEnd - timingOffset;
@@ -48,20 +51,25 @@ function insertBrowserTiming() {
4851
tbody.appendChild(row);
4952
}
5053

51-
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
52-
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
53-
addRow(tbody, "domainLookupStart", "domainLookupEnd");
54-
addRow(tbody, "connectStart", "connectEnd");
55-
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
56-
addRow(tbody, "responseStart", "responseEnd");
57-
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
58-
addRow(tbody, "domInteractive");
59-
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
60-
addRow(tbody, "loadEventStart", "loadEventEnd");
61-
document
62-
.getElementById("djDebugBrowserTiming")
63-
.classList.remove("djdt-hidden");
54+
const browserTiming = document.getElementById("djDebugBrowserTiming");
55+
// Determine if the browser timing section has already been rendered.
56+
if (browserTiming.classList.contains("djdt-hidden")) {
57+
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
58+
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
59+
addRow(tbody, "domainLookupStart", "domainLookupEnd");
60+
addRow(tbody, "connectStart", "connectEnd");
61+
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
62+
addRow(tbody, "responseStart", "responseEnd");
63+
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
64+
addRow(tbody, "domInteractive");
65+
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
66+
addRow(tbody, "loadEventStart", "loadEventEnd");
67+
browserTiming.classList.remove("djdt-hidden");
68+
}
6469
}
6570

6671
const djDebug = document.getElementById("djDebug");
67-
djDebug.addEventListener("djdt.panel.TimerPanel", insertBrowserTiming, false);
72+
// Insert the browser timing now since it's possible for this
73+
// script to miss the initial panel load event.
74+
insertBrowserTiming();
75+
$$.onPanelRender(djDebug, "TimerPanel", insertBrowserTiming);

debug_toolbar/static/debug_toolbar/js/toolbar.js

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ const djdt = {
2020
if (!this.className) {
2121
return;
2222
}
23-
const current = document.getElementById(this.className);
23+
const panelId = this.className;
24+
const current = document.getElementById(panelId);
2425
if ($$.visible(current)) {
2526
djdt.hide_panels();
2627
} else {
@@ -38,27 +39,24 @@ const djdt = {
3839
djDebug.dataset.renderPanelUrl,
3940
window.location
4041
);
41-
const onLoadEvent = current.dataset.onLoadEvent;
4242
url.searchParams.append("store_id", store_id);
43-
url.searchParams.append("panel_id", this.className);
43+
url.searchParams.append("panel_id", panelId);
4444
ajax(url).then(function (data) {
4545
inner.previousElementSibling.remove(); // Remove AJAX loader
4646
inner.innerHTML = data.content;
47-
if (data.scripts.length > 0) {
48-
let raisedEvent = false;
49-
$$.executeScripts(data.scripts, function () {
50-
// Attempt to raise the event only once.
51-
if (!raisedEvent) {
52-
raisedEvent = true;
53-
djDebug.dispatchEvent(
54-
new Event(onLoadEvent)
55-
);
56-
}
57-
});
58-
} else {
59-
djDebug.dispatchEvent(new Event(onLoadEvent));
60-
}
47+
$$.executeScripts(data.scripts);
48+
djDebug.dispatchEvent(
49+
new CustomEvent("djdt.panel.render", {
50+
detail: { panelId: panelId },
51+
})
52+
);
6153
});
54+
} else {
55+
djDebug.dispatchEvent(
56+
new CustomEvent("djdt.panel.render", {
57+
detail: { panelId: panelId },
58+
})
59+
);
6260
}
6361
}
6462
}

debug_toolbar/static/debug_toolbar/js/utils.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,21 @@ const $$ = {
77
}
88
});
99
},
10+
onPanelRender(root, panelId, fn) {
11+
/*
12+
This is a helper function to attach a handler for a `djdt.panel.render`
13+
event of a specific panel.
14+
15+
root: The container element that the listener should be attached to.
16+
panelId: The Id of the panel.
17+
fn: A function to execute when the event is triggered.
18+
*/
19+
root.addEventListener("djdt.panel.render", function (event) {
20+
if (event.detail.panelId === panelId) {
21+
fn.call(event);
22+
}
23+
});
24+
},
1025
show(element) {
1126
element.classList.remove("djdt-hidden");
1227
},
@@ -23,13 +38,12 @@ const $$ = {
2338
visible(element) {
2439
return !element.classList.contains("djdt-hidden");
2540
},
26-
executeScripts(scripts, onLoad) {
41+
executeScripts(scripts) {
2742
scripts.forEach(function (script) {
2843
const el = document.createElement("script");
2944
el.type = "module";
3045
el.src = script;
3146
el.async = true;
32-
el.onload = onLoad;
3347
document.head.appendChild(el);
3448
});
3549
},

debug_toolbar/templates/debug_toolbar/includes/panel_content.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{% load static %}
22

33
{% if panel.has_content and panel.enabled %}
4-
<div id="{{ panel.panel_id }}" class="djdt-panelContent djdt-hidden" data-on-load-event="djdt.panel.{{ panel.panel_id }}">
4+
<div id="{{ panel.panel_id }}" class="djdt-panelContent djdt-hidden">
55
<div class="djDebugPanelTitle">
66
<button type="button" class="djDebugClose">×</button>
77
<h3>{{ panel.title }}</h3>

docs/panels.rst

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,9 @@ URL: https://github.com/danyi1212/django-windowsauth
184184

185185
Path: ``windows_auth.panels.LDAPPanel``
186186

187-
LDAP Operations performed during the request, including timing, request and response messages,
187+
LDAP Operations performed during the request, including timing, request and response messages,
188188
the entries received, write changes list, stack-tracing and error debugging.
189-
This panel also shows connection usage metrics when it is collected.
189+
This panel also shows connection usage metrics when it is collected.
190190
`Check out the docs <https://django-windowsauth.readthedocs.io/en/latest/howto/debug_toolbar.html>`_.
191191

192192
Line Profiler
@@ -406,23 +406,28 @@ common methods available.
406406
Events
407407
^^^^^^
408408

409-
.. js:attribute:: djdt.panel.[panel_id]
409+
.. js:attribute:: djdt.panel.render
410410

411-
``[panel_id]`` is the ``panel_id`` property of the panel's Python class.
412-
413-
This is an event raised when a panel is loaded for the first time. This
414-
will not be raised on every render of the panel as the panel's content
415-
is cached after the first load. This event can be useful when creating
416-
custom scripts to process the HTML further.
411+
This is an event raised when a panel is rendered. It has the property
412+
``detail.panelId`` which identifies which panel has been loaded. This
413+
event can be useful when creating custom scripts to process the HTML
414+
further.
417415

418416
An example of this for the ``CustomPanel`` would be:
419417

420418
.. code-block:: javascript
421419
420+
import { $$ } from "./utils.js";
422421
function addCustomMetrics() {
423422
// Logic to process/add custom metrics here.
423+
424+
// Be sure to cover the case of this function being called twice
425+
// due to file being loaded asynchronously.
424426
}
425-
// The panel events are dispatched on the #djDebug element.
426427
const djDebug = document.getElementById("djDebug");
427-
// When the event djdt.panel.CustomPanel is raised, call AddCustomMetrics
428-
djDebug.addEventListener("djdt.panel.CustomPanel", addCustomMetrics, false);
428+
$$.onPanelRender(djDebug, "CustomPanel", addCustomMetrics);
429+
// Since a panel's scripts are loaded asynchronously, it's possible that
430+
// the above statement would occur after the djdt.panel.render event has
431+
// been raised. To account for that, the rendering function should be
432+
// called here as well.
433+
addCustomMetrics();

0 commit comments

Comments
 (0)