From c43a91ded5182adee2287e15cc8172b9c273ef5f Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Fri, 21 Oct 2022 12:13:11 -0700 Subject: [PATCH 1/6] Support rerendering the toolbar on HTMX boosted pages. This reworks the JavaScript integration to put most event handlers on document.body. This means we'll have slightly slower performance, but it's easier to handle re-rendering the toolbar when the DOM has been replaced. --- .../static/debug_toolbar/js/timer.js | 1 - .../static/debug_toolbar/js/toolbar.js | 64 +++++++++++-------- .../static/debug_toolbar/js/utils.js | 1 + docs/changes.rst | 5 ++ docs/installation.rst | 21 ++++++ docs/panels.rst | 5 +- example/templates/htmx/boost.html | 27 ++++++++ example/urls.py | 1 + 8 files changed, 96 insertions(+), 29 deletions(-) create mode 100644 example/templates/htmx/boost.html diff --git a/debug_toolbar/static/debug_toolbar/js/timer.js b/debug_toolbar/static/debug_toolbar/js/timer.js index 70d3fe5a2..bb777ee10 100644 --- a/debug_toolbar/static/debug_toolbar/js/timer.js +++ b/debug_toolbar/static/debug_toolbar/js/timer.js @@ -1,7 +1,6 @@ import { $$ } from "./utils.js"; function insertBrowserTiming() { - console.log(["inserted"]); const timingOffset = performance.timing.navigationStart, timingEnd = performance.timing.loadEventEnd, totalTime = timingEnd - timingOffset; diff --git a/debug_toolbar/static/debug_toolbar/js/toolbar.js b/debug_toolbar/static/debug_toolbar/js/toolbar.js index 7864603c8..c782168ff 100644 --- a/debug_toolbar/static/debug_toolbar/js/toolbar.js +++ b/debug_toolbar/static/debug_toolbar/js/toolbar.js @@ -9,12 +9,10 @@ function onKeyDown(event) { const djdt = { handleDragged: false, init() { - const djDebug = document.getElementById("djDebug"); - $$.show(djDebug); $$.on( - document.getElementById("djDebugPanelList"), + document.body, "click", - "li a", + "#djDebugPanelList li a", function (event) { event.preventDefault(); if (!this.className) { @@ -30,6 +28,7 @@ const djdt = { $$.show(current); this.parentElement.classList.add("djdt-active"); + const djDebug = djdt.get_debug_element(); const inner = current.querySelector( ".djDebugPanelContent .djdt-scroll" ), @@ -62,13 +61,13 @@ const djdt = { } } ); - $$.on(djDebug, "click", ".djDebugClose", function () { + $$.on(document.body, "click", "#djDebug .djDebugClose", function () { djdt.hide_one_level(); }); $$.on( - djDebug, + document.body, "click", - ".djDebugPanelButton input[type=checkbox]", + "#djDebug .djDebugPanelButton input[type=checkbox]", function () { djdt.cookie.set( this.dataset.cookie, @@ -82,7 +81,7 @@ const djdt = { ); // Used by the SQL and template panels - $$.on(djDebug, "click", ".remoteCall", function (event) { + $$.on(document.body, "click", "#djDebug .remoteCall", function (event) { event.preventDefault(); let url; @@ -105,7 +104,7 @@ const djdt = { }); // Used by the cache, profiling and SQL panels - $$.on(djDebug, "click", ".djToggleSwitch", function () { + $$.on(document.body, "click", "#djDebug .djToggleSwitch", function () { const id = this.dataset.toggleId; const toggleOpen = "+"; const toggleClose = "-"; @@ -142,19 +141,16 @@ const djdt = { }); }); - document - .getElementById("djHideToolBarButton") - .addEventListener("click", function (event) { - event.preventDefault(); - djdt.hide_toolbar(); - }); - document - .getElementById("djShowToolBarButton") - .addEventListener("click", function () { - if (!djdt.handleDragged) { - djdt.show_toolbar(); - } - }); + $$.on(document.body, "click", "#djHideToolBarButton", function (event) { + event.preventDefault(); + djdt.hide_toolbar(); + }); + + $$.on(document.body, "click", "#djShowToolBarButton", function () { + if (!djdt.handleDragged) { + djdt.show_toolbar(); + } + }); let startPageY, baseY; const handle = document.getElementById("djDebugToolbarHandle"); function onHandleMove(event) { @@ -174,14 +170,18 @@ const djdt = { djdt.handleDragged = true; } } - document - .getElementById("djShowToolBarButton") - .addEventListener("mousedown", function (event) { + $$.on( + document.body, + "mousedown", + "#djShowToolBarButton", + function (event) { event.preventDefault(); startPageY = event.pageY; baseY = handle.offsetTop - startPageY; document.addEventListener("mousemove", onHandleMove); - }); + } + ); + document.addEventListener("mouseup", function (event) { document.removeEventListener("mousemove", onHandleMove); if (djdt.handleDragged) { @@ -193,6 +193,11 @@ const djdt = { djdt.ensure_handle_visibility(); } }); + const djDebug = djdt.get_debug_element(); + // Make sure the debug element is rendered at least once. + // show_toolbar will continue to show it in the future if the + // entire DOM is reloaded. + $$.show(djDebug); const show = localStorage.getItem("djdt.show") || djDebug.dataset.defaultShow; if (show === "true") { @@ -205,7 +210,7 @@ const djdt = { } }, hide_panels() { - const djDebug = document.getElementById("djDebug"); + const djDebug = djdt.get_debug_element(); $$.hide(document.getElementById("djDebugWindow")); djDebug.querySelectorAll(".djdt-panelContent").forEach(function (e) { $$.hide(e); @@ -251,6 +256,7 @@ const djdt = { }, show_toolbar() { document.addEventListener("keydown", onKeyDown); + $$.show(document.getElementById("djDebug")); $$.hide(document.getElementById("djDebugToolbarHandle")); $$.show(document.getElementById("djDebugToolbar")); localStorage.setItem("djdt.show", "true"); @@ -340,6 +346,9 @@ const djdt = { return value; }, }, + get_debug_element: function () { + return document.getElementById("djDebug"); + }, }; window.djdt = { show_toolbar: djdt.show_toolbar, @@ -347,6 +356,7 @@ window.djdt = { init: djdt.init, close: djdt.hide_one_level, cookie: djdt.cookie, + get_debug_element: djdt.get_debug_element, }; if (document.readyState !== "loading") { diff --git a/debug_toolbar/static/debug_toolbar/js/utils.js b/debug_toolbar/static/debug_toolbar/js/utils.js index 72c767fb6..447c367c2 100644 --- a/debug_toolbar/static/debug_toolbar/js/utils.js +++ b/debug_toolbar/static/debug_toolbar/js/utils.js @@ -1,5 +1,6 @@ const $$ = { on(root, eventName, selector, fn) { + root.removeEventListener(eventName, fn); root.addEventListener(eventName, function (event) { const target = event.target.closest(selector); if (root.contains(target)) { diff --git a/docs/changes.rst b/docs/changes.rst index 6f74c04b9..5ca3a17a9 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -5,6 +5,11 @@ Pending ------- * Auto-update History panel for JavaScript ``fetch`` requests. +* Support `HTMX boosting `__ and + re-rendering the toolbar after the DOM has been replaced. This reworks + the JavaScript integration to put most event handlers on document.body. + This means we'll have slightly slower performance, but it's easier + to handle re-rendering the toolbar when the DOM has been replaced. 3.7.0 (2022-09-25) diff --git a/docs/installation.rst b/docs/installation.rst index d343849e4..cc67e3ea2 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -199,3 +199,24 @@ The Debug Toolbar currently doesn't support Django Channels or async projects. If you are using Django channels are having issues getting panels to load, please review the documentation for the configuration option :ref:`RENDER_PANELS `. + + +HTMX +^^^^ + +If you're using `HTMX`_ to `boost a page`_ you will need to add the following +event handler to your code: + +.. code-block:: javascript + + if (typeof htmx !== "undefined") { + htmx.on("htmx:afterSettle", function(detail) { + if (detail.target instanceof HTMLBodyElement) { + djdt.show_toolbar(); + } + }); + } + + +.. _HTMX: https://htmx.org/ +.. _boost a page: https://htmx.org/docs/#boosting diff --git a/docs/panels.rst b/docs/panels.rst index 09891f2e5..21abb5903 100644 --- a/docs/panels.rst +++ b/docs/panels.rst @@ -427,7 +427,10 @@ common methods available. .. js:function:: djdt.show_toolbar - Shows the toolbar. + Shows the toolbar. This can be used to rerender the toolbar when reloading the + entire DOM. For example, then using `HTMX's boosting`_. + +.. _HTMX's boosting: https://htmx.org/docs/#boosting Events ^^^^^^ diff --git a/example/templates/htmx/boost.html b/example/templates/htmx/boost.html new file mode 100644 index 000000000..9ccb8213c --- /dev/null +++ b/example/templates/htmx/boost.html @@ -0,0 +1,27 @@ +{% load cache %} + + + + + Index of Tests + + + +

Index of Tests

+ +

Django Admin

+ + + diff --git a/example/urls.py b/example/urls.py index 1bef284f0..d609035df 100644 --- a/example/urls.py +++ b/example/urls.py @@ -9,6 +9,7 @@ path("jquery/", TemplateView.as_view(template_name="jquery/index.html")), path("mootools/", TemplateView.as_view(template_name="mootools/index.html")), path("prototype/", TemplateView.as_view(template_name="prototype/index.html")), + path("htmx/boost/", TemplateView.as_view(template_name="htmx/boost.html")), path("admin/", admin.site.urls), path("ajax/increment", increment, name="ajax_increment"), path("__debug__/", include("debug_toolbar.urls")), From d2c50c7a1a0e168af0ac074589ce6cf6305dc374 Mon Sep 17 00:00:00 2001 From: Tim Schilling Date: Sat, 22 Oct 2022 17:17:20 -0500 Subject: [PATCH 2/6] Improve docs' JavaScript usage and links for django std lib docs. --- docs/installation.rst | 27 ++++++++++++++++++++------- example/templates/htmx/boost.html | 4 ++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index cc67e3ea2..31be9fe77 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -209,14 +209,27 @@ event handler to your code: .. code-block:: javascript - if (typeof htmx !== "undefined") { - htmx.on("htmx:afterSettle", function(detail) { - if (detail.target instanceof HTMLBodyElement) { - djdt.show_toolbar(); - } - }); - } + {% if debug %} + if (typeof window.htmx !== "undefined") { + htmx.on("htmx:afterSettle", function(detail) { + if ( + typeof window.djdt !== "undefined" + && detail.target instanceof HTMLBodyElement + ) { + djdt.show_toolbar(); + } + }); + } + {% endif %} + + +The use of ``{% if debug %}``` requires +`django.template.context_processors.debug`_ be included in the +``'context_processors'`` option of the `TEMPLATES`_ setting. Django's +default configuration includes this context processor. .. _HTMX: https://htmx.org/ .. _boost a page: https://htmx.org/docs/#boosting +.. _django.template.context_processors.debug: https://docs.djangoproject.com/en/4.1/ref/templates/api/#django-template-context-processors-debug +.. _TEMPLATES: https://docs.djangoproject.com/en/4.1/ref/settings/#std-setting-TEMPLATES diff --git a/example/templates/htmx/boost.html b/example/templates/htmx/boost.html index 9ccb8213c..f6c2c9749 100644 --- a/example/templates/htmx/boost.html +++ b/example/templates/htmx/boost.html @@ -15,9 +15,9 @@

Index of Tests

Django Admin