[static assets] add them to git so we can forget to call "collectstatic" before we just serve

This commit is contained in:
bronsen 2025-03-18 22:57:38 +01:00
parent 003baf931d
commit 77ae66b015
141 changed files with 34703 additions and 0 deletions

View file

@ -0,0 +1,3 @@
#djDebug {
display: none !important;
}

View file

@ -0,0 +1,772 @@
/* Variable definitions */
:root {
/* Font families are the same as in Django admin/css/base.css */
--djdt-font-family-primary: "Segoe UI", system-ui, Roboto, "Helvetica Neue",
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji",
"Segoe UI Symbol", "Noto Color Emoji";
--djdt-font-family-monospace: ui-monospace, Menlo, Monaco, "Cascadia Mono",
"Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace",
"Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New",
monospace, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
}
:root,
#djDebug[data-theme="light"] {
--djdt-font-color: black;
--djdt-background-color: white;
--djdt-panel-content-background-color: #eee;
--djdt-panel-content-table-background-color: var(--djdt-background-color);
--djdt-panel-title-background-color: #ffc;
--djdt-djdt-panel-content-table-strip-background-color: #f5f5f5;
--djdt--highlighted-background-color: lightgrey;
--djdt-toggle-template-background-color: #bbb;
--djdt-sql-font-color: #333;
--djdt-pre-text-color: #555;
--djdt-path-and-locals: #777;
--djdt-stack-span-color: black;
--djdt-template-highlight-color: #333;
--djdt-table-border-color: #ccc;
--djdt-button-border-color: var(--djdt-table-border-color);
--djdt-pre-border-color: var(--djdt-table-border-color);
--djdt-raw-border-color: var(--djdt-table-border-color);
}
@media (prefers-color-scheme: dark) {
:root {
--djdt-font-color: #8393a7;
--djdt-background-color: #1e293bff;
--djdt-panel-content-background-color: #0f1729ff;
--djdt-panel-title-background-color: #242432;
--djdt-djdt-panel-content-table-strip-background-color: #324154ff;
--djdt--highlighted-background-color: #2c2a7dff;
--djdt-toggle-template-background-color: #282755;
--djdt-sql-font-color: var(--djdt-font-color);
--djdt-pre-text-color: var(--djdt-font-color);
--djdt-path-and-locals: #65758cff;
--djdt-stack-span-color: #7c8fa4;
--djdt-template-highlight-color: var(--djdt-stack-span-color);
--djdt-table-border-color: #324154ff;
--djdt-button-border-color: var(--djdt-table-border-color);
--djdt-pre-border-color: var(--djdt-table-border-color);
--djdt-raw-border-color: var(--djdt-table-border-color);
}
}
#djDebug[data-theme="dark"] {
--djdt-font-color: #8393a7;
--djdt-background-color: #1e293bff;
--djdt-panel-content-background-color: #0f1729ff;
--djdt-panel-content-table-background-color: var(--djdt-background-color);
--djdt-panel-title-background-color: #242432;
--djdt-djdt-panel-content-table-strip-background-color: #324154ff;
--djdt--highlighted-background-color: #2c2a7dff;
--djdt-toggle-template-background-color: #282755;
--djdt-sql-font-color: var(--djdt-font-color);
--djdt-pre-text-color: var(--djdt-font-color);
--djdt-path-and-locals: #65758cff;
--djdt-stack-span-color: #7c8fa4;
--djdt-template-highlight-color: var(--djdt-stack-span-color);
--djdt-table-border-color: #324154ff;
--djdt-button-border-color: var(--djdt-table-border-color);
--djdt-pre-border-color: var(--djdt-table-border-color);
--djdt-raw-border-color: var(--djdt-table-border-color);
}
/* Debug Toolbar CSS Reset, adapted from Eric Meyer's CSS Reset */
#djDebug {
color: var(--djdt-font-color);
background: var(--djdt-background-color);
}
#djDebug,
#djDebug div,
#djDebug span,
#djDebug applet,
#djDebug object,
#djDebug iframe,
#djDebug h1,
#djDebug h2,
#djDebug h3,
#djDebug h4,
#djDebug h5,
#djDebug h6,
#djDebug p,
#djDebug blockquote,
#djDebug pre,
#djDebug a,
#djDebug abbr,
#djDebug acronym,
#djDebug address,
#djDebug big,
#djDebug cite,
#djDebug code,
#djDebug del,
#djDebug dfn,
#djDebug em,
#djDebug font,
#djDebug img,
#djDebug ins,
#djDebug kbd,
#djDebug q,
#djDebug s,
#djDebug samp,
#djDebug small,
#djDebug strike,
#djDebug strong,
#djDebug sub,
#djDebug sup,
#djDebug tt,
#djDebug var,
#djDebug b,
#djDebug u,
#djDebug i,
#djDebug center,
#djDebug dl,
#djDebug dt,
#djDebug dd,
#djDebug ol,
#djDebug ul,
#djDebug li,
#djDebug fieldset,
#djDebug form,
#djDebug label,
#djDebug legend,
#djDebug table,
#djDebug caption,
#djDebug tbody,
#djDebug tfoot,
#djDebug thead,
#djDebug tr,
#djDebug th,
#djDebug td,
#djDebug summary,
#djDebug button {
margin: 0;
padding: 0;
min-width: 0;
width: auto;
border: 0;
outline: 0;
font-size: 12px;
line-height: 1.5em;
color: var(--djdt-font-color);
vertical-align: baseline;
background-color: transparent;
font-family: var(--djdt-font-family-primary);
text-align: left;
text-shadow: none;
white-space: normal;
transition: none;
}
#djDebug button {
background-color: #eee;
background-image: linear-gradient(to bottom, #eee, #cccccc);
border: 1px solid var(--djdt-button-border-color);
border-bottom: 1px solid #bbb;
border-radius: 3px;
color: #333;
line-height: 1;
padding: 0 8px;
text-align: center;
text-shadow: 0 1px 0 #eee;
}
#djDebug button:hover {
background-color: #ddd;
background-image: linear-gradient(to bottom, #ddd, #bbb);
border-color: #bbb;
border-bottom-color: #999;
cursor: pointer;
text-shadow: 0 1px 0 #ddd;
}
#djDebug button:active {
border: 1px solid #aaa;
border-bottom: 1px solid #888;
box-shadow:
inset 0 0 5px 2px #aaa,
0 1px 0 0 #eee;
}
#djDebug #djDebugToolbar {
background-color: #111;
width: 220px;
z-index: 100000000;
position: fixed;
top: 0;
bottom: 0;
right: 0;
opacity: 0.9;
overflow-y: auto;
}
#djDebug #djDebugToolbar small {
color: #999;
}
#djDebug #djDebugToolbar ul {
margin: 0;
padding: 0;
list-style: none;
}
#djDebug #djDebugToolbar li {
border-bottom: 1px solid #222;
color: #fff;
display: block;
font-weight: bold;
float: none;
margin: 0;
padding: 0;
position: relative;
width: auto;
}
#djDebug #djDebugToolbar input[type="checkbox"] {
float: right;
margin: 10px;
}
#djDebug #djDebugToolbar li > a,
#djDebug #djDebugToolbar li > div.djdt-contentless {
font-weight: normal;
font-style: normal;
text-decoration: none;
display: block;
font-size: 16px;
padding: 7px 10px 8px 25px;
color: #fff;
}
#djDebug #djDebugToolbar li > div.djdt-disabled {
font-style: italic;
color: #999;
}
#djDebug #djDebugToolbar li a:hover {
color: #111;
background-color: #ffc;
}
#djDebug #djDebugToolbar li.djdt-active {
background: #333;
}
#djDebug #djDebugToolbar li.djdt-active:before {
content: "▶";
font-family: var(--djdt-font-family-primary);
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
color: #eee;
font-size: 150%;
}
#djDebug #djDebugToolbar li.djdt-active a:hover {
color: #b36a60;
background-color: transparent;
}
#djDebug #djDebugToolbar li small {
font-size: 12px;
color: #999;
font-style: normal;
text-decoration: none;
}
#djDebug #djDebugToolbarHandle {
position: fixed;
transform: translateY(-100%) rotate(-90deg);
transform-origin: right bottom;
background-color: #fff;
border: 1px solid #111;
border-bottom: 0;
top: 0;
right: 0;
z-index: 100000000;
opacity: 0.75;
}
#djDebug #djShowToolBarButton {
padding: 0 5px;
border: 4px solid #fff;
border-bottom-width: 0;
color: #fff;
font-size: 22px;
font-weight: bold;
background: #000;
opacity: 0.6;
}
#djDebug #djShowToolBarButton:hover {
background-color: #111;
border-color: #ffe761;
cursor: move;
opacity: 1;
}
#djDebug #djShowToolBarD {
color: #cf9;
font-size: 22px;
}
#djDebug #djShowToolBarJ {
color: #cf9;
font-size: 16px;
}
#djDebug pre,
#djDebug code {
display: block;
font-family: var(--djdt-font-family-monospace);
overflow: auto;
}
#djDebug code {
font-size: 12px;
white-space: pre;
}
#djDebug pre {
white-space: pre-wrap;
color: var(--djdt-pre-text-color);
border: 1px solid var(--djdt-pre-border-color);
border-collapse: collapse;
background-color: var(--djdt-background-color);
padding: 2px 3px;
margin-bottom: 3px;
}
#djDebug .djdt-panelContent {
position: fixed;
margin: 0;
top: 0;
right: 220px;
bottom: 0;
left: 0px;
background-color: var(--djdt-panel-content-background-color);
color: #666;
z-index: 100000000;
}
#djDebug .djdt-panelContent > div {
border-bottom: 1px solid #ddd;
}
#djDebug .djDebugPanelTitle {
position: absolute;
background-color: var(--djdt-panel-title-background-color);
color: #666;
padding-left: 20px;
top: 0;
right: 0;
left: 0;
height: 50px;
}
#djDebug .djDebugPanelTitle code {
display: inline;
font-size: inherit;
}
#djDebug .djDebugPanelContent {
position: absolute;
top: 50px;
right: 0;
bottom: 0;
left: 0;
height: auto;
padding: 5px 0 0 20px;
}
#djDebug .djDebugPanelContent .djdt-loader {
margin: 80px auto;
border: 6px solid white;
border-radius: 50%;
border-top: 6px solid #ffe761;
width: 38px;
height: 38px;
animation: spin 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#djDebug .djDebugPanelContent .djdt-scroll {
height: 100%;
overflow: auto;
display: block;
padding: 0 10px 0 0;
}
#djDebug h3 {
font-size: 24px;
font-weight: normal;
line-height: 50px;
}
#djDebug h4 {
font-size: 20px;
font-weight: bold;
margin-top: 0.8em;
}
#djDebug .djdt-panelContent table {
border: 1px solid var(--djdt-table-border-color);
border-collapse: collapse;
width: 100%;
background-color: var(--djdt-panel-content-table-background-color);
display: table;
margin-top: 0.8em;
overflow: auto;
}
#djDebug .djdt-panelContent tbody > tr:nth-child(odd):not(.djdt-highlighted) {
background-color: var(--djdt-panel-content-table-strip-background-color);
}
#djDebug .djdt-panelContent tbody td,
#djDebug .djdt-panelContent tbody th {
vertical-align: top;
padding: 2px 3px;
}
#djDebug .djdt-panelContent tbody td.djdt-time {
text-align: center;
}
#djDebug .djdt-panelContent thead th {
padding: 1px 6px 1px 3px;
text-align: left;
font-weight: bold;
font-size: 14px;
white-space: nowrap;
}
#djDebug .djdt-panelContent tbody th {
width: 12em;
text-align: right;
color: #666;
padding-right: 0.5em;
}
#djDebug .djTemplateContext {
background-color: var(--djdt-background-color);
}
#djDebug .djdt-panelContent .djDebugClose {
position: absolute;
top: 4px;
right: 15px;
line-height: 16px;
border: 6px solid #ddd;
border-radius: 50%;
background: #fff;
color: #ddd;
font-weight: 900;
font-size: 20px;
height: 36px;
width: 36px;
padding: 0 0 5px;
box-sizing: border-box;
display: grid;
place-items: center;
}
#djDebug .djdt-panelContent .djDebugClose:hover {
background: #c0695d;
}
#djDebug .djdt-panelContent dt,
#djDebug .djdt-panelContent dd {
display: block;
}
#djDebug .djdt-panelContent dt {
margin-top: 0.75em;
}
#djDebug .djdt-panelContent dd {
margin-left: 10px;
}
#djDebug a.toggleTemplate {
padding: 4px;
background-color: var(--djdt-toggle-template-background-color);
border-radius: 3px;
}
#djDebug a.toggleTemplate:hover {
padding: 4px;
background-color: #444;
color: #ffe761;
border-radius: 3px;
}
#djDebug .djDebugCollapsed {
color: var(--djdt-sql-font-color);
}
#djDebug .djDebugUncollapsed {
color: var(--djdt-sql-font-color);
}
#djDebug .djUnselected {
display: none;
}
#djDebug tr.djSelected {
display: table-row;
}
#djDebug .djDebugSql {
overflow-wrap: anywhere;
}
#djDebug .djSQLDetailsDiv tbody th {
text-align: left;
}
#djDebug span.djDebugLineChart {
background-color: #777;
height: 3px;
position: absolute;
bottom: 0;
top: 0;
left: 0;
display: block;
z-index: 1000000001;
}
#djDebug span.djDebugLineChartWarning {
background-color: #900;
}
#djDebug .highlight {
color: var(--djdt-font-color);
}
#djDebug .highlight .err {
color: var(--djdt-font-color);
} /* Error */
/*
Styles for pygments HTMLFormatter
- This should match debug_toolbar/panels/templates/views.py::template_source
- Each line needs to be prefixed with #djDebug .highlight as well.
- The .w definition needs to include:
white-space: pre-wrap
To regenerate:
from pygments.formatters import HtmlFormatter
print(HtmlFormatter(wrapcode=True).get_style_defs())
*/
#djDebug .highlight pre { line-height: 125%; }
#djDebug .highlight td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
#djDebug .highlight span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
#djDebug .highlight td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
#djDebug .highlight span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
#djDebug .highlight .hll { background-color: #ffffcc }
#djDebug .highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
#djDebug .highlight .err { border: 1px solid #FF0000 } /* Error */
#djDebug .highlight .k { color: #008000; font-weight: bold } /* Keyword */
#djDebug .highlight .o { color: #666666 } /* Operator */
#djDebug .highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
#djDebug .highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
#djDebug .highlight .cp { color: #9C6500 } /* Comment.Preproc */
#djDebug .highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
#djDebug .highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
#djDebug .highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
#djDebug .highlight .gd { color: #A00000 } /* Generic.Deleted */
#djDebug .highlight .ge { font-style: italic } /* Generic.Emph */
#djDebug .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
#djDebug .highlight .gr { color: #E40000 } /* Generic.Error */
#djDebug .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
#djDebug .highlight .gi { color: #008400 } /* Generic.Inserted */
#djDebug .highlight .go { color: #717171 } /* Generic.Output */
#djDebug .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
#djDebug .highlight .gs { font-weight: bold } /* Generic.Strong */
#djDebug .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
#djDebug .highlight .gt { color: #0044DD } /* Generic.Traceback */
#djDebug .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
#djDebug .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
#djDebug .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
#djDebug .highlight .kp { color: #008000 } /* Keyword.Pseudo */
#djDebug .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
#djDebug .highlight .kt { color: #B00040 } /* Keyword.Type */
#djDebug .highlight .m { color: #666666 } /* Literal.Number */
#djDebug .highlight .s { color: #BA2121 } /* Literal.String */
#djDebug .highlight .na { color: #687822 } /* Name.Attribute */
#djDebug .highlight .nb { color: #008000 } /* Name.Builtin */
#djDebug .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
#djDebug .highlight .no { color: #880000 } /* Name.Constant */
#djDebug .highlight .nd { color: #AA22FF } /* Name.Decorator */
#djDebug .highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
#djDebug .highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
#djDebug .highlight .nf { color: #0000FF } /* Name.Function */
#djDebug .highlight .nl { color: #767600 } /* Name.Label */
#djDebug .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
#djDebug .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
#djDebug .highlight .nv { color: #19177C } /* Name.Variable */
#djDebug .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
#djDebug .highlight .w { color: #bbbbbb; white-space: pre-wrap } /* Text.Whitespace */
#djDebug .highlight .mb { color: #666666 } /* Literal.Number.Bin */
#djDebug .highlight .mf { color: #666666 } /* Literal.Number.Float */
#djDebug .highlight .mh { color: #666666 } /* Literal.Number.Hex */
#djDebug .highlight .mi { color: #666666 } /* Literal.Number.Integer */
#djDebug .highlight .mo { color: #666666 } /* Literal.Number.Oct */
#djDebug .highlight .sa { color: #BA2121 } /* Literal.String.Affix */
#djDebug .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
#djDebug .highlight .sc { color: #BA2121 } /* Literal.String.Char */
#djDebug .highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
#djDebug .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
#djDebug .highlight .s2 { color: #BA2121 } /* Literal.String.Double */
#djDebug .highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
#djDebug .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
#djDebug .highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
#djDebug .highlight .sx { color: #008000 } /* Literal.String.Other */
#djDebug .highlight .sr { color: #A45A77 } /* Literal.String.Regex */
#djDebug .highlight .s1 { color: #BA2121 } /* Literal.String.Single */
#djDebug .highlight .ss { color: #19177C } /* Literal.String.Symbol */
#djDebug .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
#djDebug .highlight .fm { color: #0000FF } /* Name.Function.Magic */
#djDebug .highlight .vc { color: #19177C } /* Name.Variable.Class */
#djDebug .highlight .vg { color: #19177C } /* Name.Variable.Global */
#djDebug .highlight .vi { color: #19177C } /* Name.Variable.Instance */
#djDebug .highlight .vm { color: #19177C } /* Name.Variable.Magic */
#djDebug .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
#djDebug svg.djDebugLineChart {
width: 100%;
height: 1.5em;
}
#djDebug svg.djDebugLineChartWarning rect {
fill: #900;
}
#djDebug svg.djDebugLineChartInTransaction rect {
fill: #d3ff82;
}
#djDebug svg.djDebugLineChart line {
stroke: #94b24d;
}
#djDebug .djDebugRowWarning .djdt-time {
color: red;
}
#djDebug .djdt-panelContent table .djdt-toggle {
width: 14px;
padding-top: 3px;
}
#djDebug .djdt-panelContent table .djdt-actions {
min-width: 70px;
white-space: nowrap;
}
#djDebug .djdt-color:after {
content: "\00a0";
}
#djDebug .djToggleSwitch {
box-sizing: content-box;
padding: 0;
border: 1px solid #999;
border-radius: 0;
width: 12px;
color: #777;
background: linear-gradient(to bottom, #fff, #dcdcdc);
}
#djDebug .djNoToggleSwitch {
height: 14px;
width: 14px;
display: inline-block;
}
#djDebug .djSQLDetailsDiv {
margin-top: 0.8em;
}
#djDebug .djdt-stack span {
color: var(--djdt-stack-span-color);
font-weight: bold;
}
#djDebug .djdt-stack span.djdt-path,
#djDebug .djdt-stack pre.djdt-locals,
#djDebug .djdt-stack pre.djdt-locals span {
color: var(--djdt-path-and-locals);
font-weight: normal;
}
#djDebug .djdt-stack span.djdt-code {
font-weight: normal;
}
#djDebug .djdt-stack pre.djdt-locals {
margin: 0 27px 27px 27px;
}
#djDebug .djdt-raw {
background-color: #fff;
border: 1px solid var(--djdt-raw-border-color);
margin-top: 0.8em;
padding: 5px;
white-space: pre-wrap;
}
#djDebug .djdt-width-20 {
width: 20%;
}
#djDebug .djdt-width-30 {
width: 30%;
}
#djDebug .djdt-width-60 {
width: 60%;
}
#djDebug .djdt-max-height-100 {
max-height: 100%;
}
#djDebug .djdt-highlighted {
background-color: var(--djdt--highlighted-background-color);
}
#djDebug tr.djdt-highlighted.djdt-profile-row {
background-color: #ffc;
}
#djDebug tr.djdt-highlighted.djdt-profile-row:nth-child(2n + 1) {
background-color: #dd9;
}
@keyframes djdt-flash-new {
from {
background-color: green;
}
to {
background-color: inherit;
}
}
#djDebug .flash-new {
animation: djdt-flash-new 1s;
}
.djdt-hidden {
display: none;
}
#djDebug #djDebugToolbar a#djToggleThemeButton {
display: flex;
align-items: center;
cursor: pointer;
}
#djToggleThemeButton > svg {
margin-left: auto;
}
#djDebug[data-theme="light"] #djToggleThemeButton svg.theme-light,
#djDebug[data-theme="dark"] #djToggleThemeButton svg.theme-dark,
#djDebug[data-theme="auto"] #djToggleThemeButton svg.theme-auto {
display: block;
height: 1rem;
width: 1rem;
}

View file

@ -0,0 +1,109 @@
import { $$, ajaxForm, replaceToolbarState } from "./utils.js";
const djDebug = document.getElementById("djDebug");
function difference(setA, setB) {
const _difference = new Set(setA);
for (const elem of setB) {
_difference.delete(elem);
}
return _difference;
}
/**
* Create an array of dataset properties from a NodeList.
*/
function pluckData(nodes, key) {
const data = [];
nodes.forEach(function (obj) {
data.push(obj.dataset[key]);
});
return data;
}
function refreshHistory() {
const formTarget = djDebug.querySelector(".refreshHistory");
const container = document.getElementById("djdtHistoryRequests");
const oldIds = new Set(
pluckData(container.querySelectorAll("tr[data-store-id]"), "storeId")
);
ajaxForm(formTarget)
.then(function (data) {
// Remove existing rows first then re-populate with new data
container
.querySelectorAll("tr[data-store-id]")
.forEach(function (node) {
node.remove();
});
data.requests.forEach(function (request) {
container.innerHTML = request.content + container.innerHTML;
});
})
.then(function () {
const allIds = new Set(
pluckData(
container.querySelectorAll("tr[data-store-id]"),
"storeId"
)
);
const newIds = difference(allIds, oldIds);
const lastRequestId = newIds.values().next().value;
return {
allIds,
newIds,
lastRequestId,
};
})
.then(function (refreshInfo) {
refreshInfo.newIds.forEach(function (newId) {
const row = container.querySelector(
`tr[data-store-id="${newId}"]`
);
row.classList.add("flash-new");
});
setTimeout(() => {
container
.querySelectorAll("tr[data-store-id]")
.forEach((row) => {
row.classList.remove("flash-new");
});
}, 2000);
});
}
function switchHistory(newStoreId) {
const formTarget = djDebug.querySelector(
".switchHistory[data-store-id='" + newStoreId + "']"
);
const tbody = formTarget.closest("tbody");
const highlighted = tbody.querySelector(".djdt-highlighted");
if (highlighted) {
highlighted.classList.remove("djdt-highlighted");
}
formTarget.closest("tr").classList.add("djdt-highlighted");
ajaxForm(formTarget).then(function (data) {
if (Object.keys(data).length === 0) {
const container = document.getElementById("djdtHistoryRequests");
container.querySelector(
'button[data-store-id="' + newStoreId + '"]'
).innerHTML = "Switch [EXPIRED]";
}
replaceToolbarState(newStoreId, data);
});
}
$$.on(djDebug, "click", ".switchHistory", function (event) {
event.preventDefault();
switchHistory(this.dataset.storeId);
});
$$.on(djDebug, "click", ".refreshHistory", function (event) {
event.preventDefault();
refreshHistory();
});
// We don't refresh the whole toolbar each fetch or ajax request,
// so we need to refresh the history when we open the panel
$$.onPanelRender(djDebug, "HistoryPanel", refreshHistory);

View file

@ -0,0 +1 @@
document.getElementById("redirect_to").focus();

View file

@ -0,0 +1,88 @@
import { $$ } from "./utils.js";
function insertBrowserTiming() {
const timingOffset = performance.timing.navigationStart,
timingEnd = performance.timing.loadEventEnd,
totalTime = timingEnd - timingOffset;
function getLeft(stat) {
if (totalTime !== 0) {
return (
((performance.timing[stat] - timingOffset) / totalTime) * 100.0
);
} else {
return 0;
}
}
function getCSSWidth(stat, endStat) {
let width = 0;
if (totalTime !== 0) {
width =
((performance.timing[endStat] - performance.timing[stat]) /
totalTime) *
100.0;
}
const denominator = 100.0 - getLeft(stat);
if (denominator !== 0) {
// Calculate relative percent (same as sql panel logic)
width = (100.0 * width) / denominator;
} else {
width = 0;
}
return width < 1 ? "2px" : width + "%";
}
function addRow(tbody, stat, endStat) {
const row = document.createElement("tr");
if (endStat) {
// Render a start through end bar
row.innerHTML =
"<td>" +
stat.replace("Start", "") +
"</td>" +
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
"<td>" +
(performance.timing[stat] - timingOffset) +
" (+" +
(performance.timing[endStat] - performance.timing[stat]) +
")</td>";
row.querySelector("rect").setAttribute(
"width",
getCSSWidth(stat, endStat)
);
} else {
// Render a point in time
row.innerHTML =
"<td>" +
stat +
"</td>" +
'<td><svg class="djDebugLineChart" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 100 5" preserveAspectRatio="none"><rect y="0" height="5" fill="#ccc" /></svg></td>' +
"<td>" +
(performance.timing[stat] - timingOffset) +
"</td>";
row.querySelector("rect").setAttribute("width", 2);
}
row.querySelector("rect").setAttribute("x", getLeft(stat));
tbody.appendChild(row);
}
const browserTiming = document.getElementById("djDebugBrowserTiming");
// Determine if the browser timing section has already been rendered.
if (browserTiming.classList.contains("djdt-hidden")) {
const tbody = document.getElementById("djDebugBrowserTimingTableBody");
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
addRow(tbody, "domainLookupStart", "domainLookupEnd");
addRow(tbody, "connectStart", "connectEnd");
addRow(tbody, "requestStart", "responseEnd"); // There is no requestEnd
addRow(tbody, "responseStart", "responseEnd");
addRow(tbody, "domLoading", "domComplete"); // Spans the events below
addRow(tbody, "domInteractive");
addRow(tbody, "domContentLoadedEventStart", "domContentLoadedEventEnd");
addRow(tbody, "loadEventStart", "loadEventEnd");
browserTiming.classList.remove("djdt-hidden");
}
}
const djDebug = document.getElementById("djDebug");
// Insert the browser timing now since it's possible for this
// script to miss the initial panel load event.
insertBrowserTiming();
$$.onPanelRender(djDebug, "TimerPanel", insertBrowserTiming);

View file

@ -0,0 +1,392 @@
import { $$, ajax, debounce, replaceToolbarState } from "./utils.js";
function onKeyDown(event) {
if (event.keyCode === 27) {
djdt.hideOneLevel();
}
}
function getDebugElement() {
// Fetch the debug element from the DOM.
// This is used to avoid writing the element's id
// everywhere the element is being selected. A fixed reference
// to the element should be avoided because the entire DOM could
// be reloaded such as via HTMX boosting.
return document.getElementById("djDebug");
}
const djdt = {
handleDragged: false,
needUpdateOnFetch: false,
init() {
const djDebug = getDebugElement();
djdt.needUpdateOnFetch = djDebug.dataset.updateOnFetch === "True";
$$.on(djDebug, "click", "#djDebugPanelList li a", function (event) {
event.preventDefault();
if (!this.className) {
return;
}
const panelId = this.className;
const current = document.getElementById(panelId);
if ($$.visible(current)) {
djdt.hidePanels();
} else {
djdt.hidePanels();
$$.show(current);
this.parentElement.classList.add("djdt-active");
const inner = current.querySelector(
".djDebugPanelContent .djdt-scroll"
),
storeId = djDebug.dataset.storeId;
if (storeId && inner.children.length === 0) {
const url = new URL(
djDebug.dataset.renderPanelUrl,
window.location
);
url.searchParams.append("store_id", storeId);
url.searchParams.append("panel_id", panelId);
ajax(url).then(function (data) {
inner.previousElementSibling.remove(); // Remove AJAX loader
inner.innerHTML = data.content;
$$.executeScripts(data.scripts);
$$.applyStyles(inner);
djDebug.dispatchEvent(
new CustomEvent("djdt.panel.render", {
detail: { panelId: panelId },
})
);
});
} else {
djDebug.dispatchEvent(
new CustomEvent("djdt.panel.render", {
detail: { panelId: panelId },
})
);
}
}
});
$$.on(djDebug, "click", ".djDebugClose", function () {
djdt.hideOneLevel();
});
$$.on(
djDebug,
"click",
".djDebugPanelButton input[type=checkbox]",
function () {
djdt.cookie.set(
this.dataset.cookie,
this.checked ? "on" : "off",
{
path: "/",
expires: 10,
}
);
}
);
// Used by the SQL and template panels
$$.on(djDebug, "click", ".remoteCall", function (event) {
event.preventDefault();
let url;
const ajaxData = {};
if (this.tagName === "BUTTON") {
const form = this.closest("form");
url = this.formAction;
ajaxData.method = form.method.toUpperCase();
ajaxData.body = new FormData(form);
} else if (this.tagName === "A") {
url = this.href;
}
ajax(url, ajaxData).then(function (data) {
const win = document.getElementById("djDebugWindow");
win.innerHTML = data.content;
$$.show(win);
});
});
// Used by the cache, profiling and SQL panels
$$.on(djDebug, "click", ".djToggleSwitch", function () {
const id = this.dataset.toggleId;
const toggleOpen = "+";
const toggleClose = "-";
const openMe = this.textContent === toggleOpen;
const name = this.dataset.toggleName;
const container = document.getElementById(name + "_" + id);
container
.querySelectorAll(".djDebugCollapsed")
.forEach(function (e) {
$$.toggle(e, openMe);
});
container
.querySelectorAll(".djDebugUncollapsed")
.forEach(function (e) {
$$.toggle(e, !openMe);
});
const self = this;
this.closest(".djDebugPanelContent")
.querySelectorAll(".djToggleDetails_" + id)
.forEach(function (e) {
if (openMe) {
e.classList.add("djSelected");
e.classList.remove("djUnselected");
self.textContent = toggleClose;
} else {
e.classList.remove("djSelected");
e.classList.add("djUnselected");
self.textContent = toggleOpen;
}
const switch_ = e.querySelector(".djToggleSwitch");
if (switch_) {
switch_.textContent = self.textContent;
}
});
});
$$.on(djDebug, "click", "#djHideToolBarButton", function (event) {
event.preventDefault();
djdt.hideToolbar();
});
$$.on(djDebug, "click", "#djShowToolBarButton", function () {
if (!djdt.handleDragged) {
djdt.showToolbar();
}
});
let startPageY, baseY;
const handle = document.getElementById("djDebugToolbarHandle");
function onHandleMove(event) {
// Chrome can send spurious mousemove events, so don't do anything unless the
// cursor really moved. Otherwise, it will be impossible to expand the toolbar
// due to djdt.handleDragged being set to true.
if (djdt.handleDragged || event.pageY !== startPageY) {
let top = baseY + event.pageY;
if (top < 0) {
top = 0;
} else if (top + handle.offsetHeight > window.innerHeight) {
top = window.innerHeight - handle.offsetHeight;
}
handle.style.top = top + "px";
djdt.handleDragged = true;
}
}
$$.on(djDebug, "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) {
event.preventDefault();
localStorage.setItem("djdt.top", handle.offsetTop);
requestAnimationFrame(function () {
djdt.handleDragged = false;
});
djdt.ensureHandleVisibility();
}
},
{ once: true }
);
});
// Make sure the debug element is rendered at least once.
// showToolbar 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") {
djdt.showToolbar();
} else {
djdt.hideToolbar();
}
if (djDebug.dataset.sidebarUrl !== undefined) {
djdt.updateOnAjax();
}
// Updates the theme using user settings
const userTheme = localStorage.getItem("djdt.user-theme");
if (userTheme !== null) {
djDebug.setAttribute("data-theme", userTheme);
}
// Adds the listener to the Theme Toggle Button
$$.on(djDebug, "click", "#djToggleThemeButton", function () {
switch (djDebug.getAttribute("data-theme")) {
case "auto":
djDebug.setAttribute("data-theme", "light");
localStorage.setItem("djdt.user-theme", "light");
break;
case "light":
djDebug.setAttribute("data-theme", "dark");
localStorage.setItem("djdt.user-theme", "dark");
break;
default: /* dark is the default */
djDebug.setAttribute("data-theme", "auto");
localStorage.setItem("djdt.user-theme", "auto");
break;
}
});
},
hidePanels() {
const djDebug = getDebugElement();
$$.hide(document.getElementById("djDebugWindow"));
djDebug.querySelectorAll(".djdt-panelContent").forEach(function (e) {
$$.hide(e);
});
document.querySelectorAll("#djDebugToolbar li").forEach(function (e) {
e.classList.remove("djdt-active");
});
},
ensureHandleVisibility() {
const handle = document.getElementById("djDebugToolbarHandle");
// set handle position
const handleTop = Math.min(
localStorage.getItem("djdt.top") || 265,
window.innerHeight - handle.offsetWidth
);
handle.style.top = handleTop + "px";
},
hideToolbar() {
djdt.hidePanels();
$$.hide(document.getElementById("djDebugToolbar"));
const handle = document.getElementById("djDebugToolbarHandle");
$$.show(handle);
djdt.ensureHandleVisibility();
window.addEventListener("resize", djdt.ensureHandleVisibility);
document.removeEventListener("keydown", onKeyDown);
localStorage.setItem("djdt.show", "false");
},
hideOneLevel() {
const win = document.getElementById("djDebugWindow");
if ($$.visible(win)) {
$$.hide(win);
} else {
const toolbar = document.getElementById("djDebugToolbar");
if (toolbar.querySelector("li.djdt-active")) {
djdt.hidePanels();
} else {
djdt.hideToolbar();
}
}
},
showToolbar() {
document.addEventListener("keydown", onKeyDown);
$$.show(document.getElementById("djDebug"));
$$.hide(document.getElementById("djDebugToolbarHandle"));
$$.show(document.getElementById("djDebugToolbar"));
localStorage.setItem("djdt.show", "true");
window.removeEventListener("resize", djdt.ensureHandleVisibility);
},
updateOnAjax() {
const sidebarUrl =
document.getElementById("djDebug").dataset.sidebarUrl;
const slowjax = debounce(ajax, 200);
function handleAjaxResponse(storeId) {
storeId = encodeURIComponent(storeId);
const dest = `${sidebarUrl}?store_id=${storeId}`;
slowjax(dest).then(function (data) {
if (djdt.needUpdateOnFetch) {
replaceToolbarState(storeId, data);
}
});
}
// Patch XHR / traditional AJAX requests
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
this.addEventListener("load", function () {
// Chromium emits a "Refused to get unsafe header" uncatchable warning
// when the header can't be fetched. While it doesn't impede execution
// it's worrisome to developers.
if (
this.getAllResponseHeaders().indexOf("djdt-store-id") >= 0
) {
handleAjaxResponse(this.getResponseHeader("djdt-store-id"));
}
});
origOpen.apply(this, arguments);
};
const origFetch = window.fetch;
window.fetch = function () {
const promise = origFetch.apply(this, arguments);
promise.then(function (response) {
if (response.headers.get("djdt-store-id") !== null) {
handleAjaxResponse(response.headers.get("djdt-store-id"));
}
// Don't resolve the response via .json(). Instead
// continue to return it to allow the caller to consume as needed.
return response;
});
return promise;
};
},
cookie: {
get(key) {
if (!document.cookie.includes(key)) {
return null;
}
const cookieArray = document.cookie.split("; "),
cookies = {};
cookieArray.forEach(function (e) {
const parts = e.split("=");
cookies[parts[0]] = parts[1];
});
return cookies[key];
},
set(key, value, options) {
options = options || {};
if (typeof options.expires === "number") {
const days = options.expires,
t = (options.expires = new Date());
t.setDate(t.getDate() + days);
}
document.cookie = [
encodeURIComponent(key) + "=" + String(value),
options.expires
? "; expires=" + options.expires.toUTCString()
: "",
options.path ? "; path=" + options.path : "",
options.domain ? "; domain=" + options.domain : "",
options.secure ? "; secure" : "",
"samesite" in options
? "; samesite=" + options.samesite
: "; samesite=lax",
].join("");
return value;
},
},
};
window.djdt = {
show_toolbar: djdt.showToolbar,
hide_toolbar: djdt.hideToolbar,
init: djdt.init,
close: djdt.hideOneLevel,
cookie: djdt.cookie,
};
if (document.readyState !== "loading") {
djdt.init();
} else {
document.addEventListener("DOMContentLoaded", djdt.init);
}

View file

@ -0,0 +1,142 @@
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)) {
fn.call(target, event);
}
});
},
onPanelRender(root, panelId, fn) {
/*
This is a helper function to attach a handler for a `djdt.panel.render`
event of a specific panel.
root: The container element that the listener should be attached to.
panelId: The Id of the panel.
fn: A function to execute when the event is triggered.
*/
root.addEventListener("djdt.panel.render", function (event) {
if (event.detail.panelId === panelId) {
fn.call(event);
}
});
},
show(element) {
element.classList.remove("djdt-hidden");
},
hide(element) {
element.classList.add("djdt-hidden");
},
toggle(element, value) {
if (value) {
$$.show(element);
} else {
$$.hide(element);
}
},
visible(element) {
return !element.classList.contains("djdt-hidden");
},
executeScripts(scripts) {
scripts.forEach(function (script) {
const el = document.createElement("script");
el.type = "module";
el.src = script;
el.async = true;
document.head.appendChild(el);
});
},
applyStyles(container) {
/*
* Given a container element, apply styles set via data-djdt-styles attribute.
* The format is data-djdt-styles="styleName1:value;styleName2:value2"
* The style names should use the CSSStyleDeclaration camel cased names.
*/
container
.querySelectorAll("[data-djdt-styles]")
.forEach(function (element) {
const styles = element.dataset.djdtStyles || "";
styles.split(";").forEach(function (styleText) {
const styleKeyPair = styleText.split(":");
if (styleKeyPair.length === 2) {
const name = styleKeyPair[0].trim();
const value = styleKeyPair[1].trim();
element.style[name] = value;
}
});
});
},
};
function ajax(url, init) {
init = Object.assign({ credentials: "same-origin" }, init);
return fetch(url, init)
.then(function (response) {
if (response.ok) {
return response.json().catch(function(error){
return Promise.reject(
new Error("The response is a invalid Json object : " + error)
);
});
}
return Promise.reject(
new Error(response.status + ": " + response.statusText)
);
})
.catch(function (error) {
const win = document.getElementById("djDebugWindow");
win.innerHTML =
'<div class="djDebugPanelTitle"><button type="button" class="djDebugClose">»</button><h3>' +
error.message +
"</h3></div>";
$$.show(win);
throw error;
});
}
function ajaxForm(element) {
const form = element.closest("form");
const url = new URL(form.action);
const formData = new FormData(form);
for (const [name, value] of formData.entries()) {
url.searchParams.append(name, value);
}
const ajaxData = {
method: form.method.toUpperCase(),
};
return ajax(url, ajaxData);
}
function replaceToolbarState(newStoreId, data) {
const djDebug = document.getElementById("djDebug");
djDebug.setAttribute("data-store-id", newStoreId);
// Check if response is empty, it could be due to an expired storeId.
Object.keys(data).forEach(function (panelId) {
const panel = document.getElementById(panelId);
if (panel) {
panel.outerHTML = data[panelId].content;
document.getElementById("djdt-" + panelId).outerHTML =
data[panelId].button;
}
});
}
function debounce(func, delay) {
let timer = null;
let resolves = [];
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
const result = func(...args);
resolves.forEach((r) => r(result));
resolves = [];
}, delay);
return new Promise((r) => resolves.push(r));
};
}
export { $$, ajax, ajaxForm, replaceToolbarState, debounce };