.
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { $$, ajaxForm } from "./utils.js";
|
||||
|
||||
const djDebug = document.getElementById("djDebug");
|
||||
|
||||
$$.on(djDebug, "click", ".switchHistory", function (event) {
|
||||
event.preventDefault();
|
||||
const newStoreId = this.dataset.storeId;
|
||||
const tbody = this.closest("tbody");
|
||||
|
||||
tbody
|
||||
.querySelector(".djdt-highlighted")
|
||||
.classList.remove("djdt-highlighted");
|
||||
this.closest("tr").classList.add("djdt-highlighted");
|
||||
|
||||
ajaxForm(this).then(function (data) {
|
||||
djDebug.setAttribute("data-store-id", newStoreId);
|
||||
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;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
$$.on(djDebug, "click", ".refreshHistory", function (event) {
|
||||
event.preventDefault();
|
||||
const container = document.getElementById("djdtHistoryRequests");
|
||||
ajaxForm(this).then(function (data) {
|
||||
data.requests.forEach(function (request) {
|
||||
if (
|
||||
!container.querySelector('[data-store-id="' + request.id + '"]')
|
||||
) {
|
||||
container.innerHTML = request.content + container.innerHTML;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
document.getElementById("redirect_to").focus();
|
||||
@@ -0,0 +1,59 @@
|
||||
const timingOffset = performance.timing.navigationStart,
|
||||
timingEnd = performance.timing.loadEventEnd,
|
||||
totalTime = timingEnd - timingOffset;
|
||||
function getLeft(stat) {
|
||||
return ((performance.timing[stat] - timingOffset) / totalTime) * 100.0;
|
||||
}
|
||||
function getCSSWidth(stat, endStat) {
|
||||
let width =
|
||||
((performance.timing[endStat] - performance.timing[stat]) / totalTime) *
|
||||
100.0;
|
||||
// Calculate relative percent (same as sql panel logic)
|
||||
width = (100.0 * width) / (100.0 - getLeft(stat));
|
||||
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 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");
|
||||
document.getElementById("djDebugBrowserTiming").classList.remove("djdt-hidden");
|
||||
@@ -0,0 +1,295 @@
|
||||
import { $$, ajax } from "./utils.js";
|
||||
|
||||
function onKeyDown(event) {
|
||||
if (event.keyCode === 27) {
|
||||
djdt.hide_one_level();
|
||||
}
|
||||
}
|
||||
|
||||
const djdt = {
|
||||
handleDragged: false,
|
||||
init() {
|
||||
const djDebug = document.getElementById("djDebug");
|
||||
$$.show(djDebug);
|
||||
$$.on(
|
||||
document.getElementById("djDebugPanelList"),
|
||||
"click",
|
||||
"li a",
|
||||
function (event) {
|
||||
event.preventDefault();
|
||||
if (!this.className) {
|
||||
return;
|
||||
}
|
||||
const current = document.getElementById(this.className);
|
||||
if ($$.visible(current)) {
|
||||
djdt.hide_panels();
|
||||
} else {
|
||||
djdt.hide_panels();
|
||||
|
||||
$$.show(current);
|
||||
this.parentElement.classList.add("djdt-active");
|
||||
|
||||
const inner = current.querySelector(
|
||||
".djDebugPanelContent .djdt-scroll"
|
||||
),
|
||||
store_id = djDebug.dataset.storeId;
|
||||
if (store_id && inner.children.length === 0) {
|
||||
const url = new URL(
|
||||
djDebug.dataset.renderPanelUrl,
|
||||
window.location
|
||||
);
|
||||
url.searchParams.append("store_id", store_id);
|
||||
url.searchParams.append("panel_id", this.className);
|
||||
ajax(url).then(function (data) {
|
||||
inner.previousElementSibling.remove(); // Remove AJAX loader
|
||||
inner.innerHTML = data.content;
|
||||
$$.executeScripts(data.scripts);
|
||||
$$.applyStyles(inner);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
$$.on(djDebug, "click", ".djDebugClose", function () {
|
||||
djdt.hide_one_level();
|
||||
});
|
||||
$$.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 ajax_data = {};
|
||||
|
||||
if (this.tagName === "BUTTON") {
|
||||
const form = this.closest("form");
|
||||
url = this.formAction;
|
||||
ajax_data.method = form.method.toUpperCase();
|
||||
ajax_data.body = new FormData(form);
|
||||
} else if (this.tagName === "A") {
|
||||
url = this.href;
|
||||
}
|
||||
|
||||
ajax(url, ajax_data).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 open_me = this.textContent === toggleOpen;
|
||||
const name = this.dataset.toggleName;
|
||||
const container = document.getElementById(name + "_" + id);
|
||||
container
|
||||
.querySelectorAll(".djDebugCollapsed")
|
||||
.forEach(function (e) {
|
||||
$$.toggle(e, open_me);
|
||||
});
|
||||
container
|
||||
.querySelectorAll(".djDebugUncollapsed")
|
||||
.forEach(function (e) {
|
||||
$$.toggle(e, !open_me);
|
||||
});
|
||||
const self = this;
|
||||
this.closest(".djDebugPanelContent")
|
||||
.querySelectorAll(".djToggleDetails_" + id)
|
||||
.forEach(function (e) {
|
||||
if (open_me) {
|
||||
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;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById("djHideToolBarButton")
|
||||
.addEventListener("click", function (event) {
|
||||
event.preventDefault();
|
||||
djdt.hide_toolbar();
|
||||
});
|
||||
document
|
||||
.getElementById("djShowToolBarButton")
|
||||
.addEventListener("click", function () {
|
||||
if (!djdt.handleDragged) {
|
||||
djdt.show_toolbar();
|
||||
}
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
document
|
||||
.getElementById("djShowToolBarButton")
|
||||
.addEventListener("mousedown", 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;
|
||||
});
|
||||
}
|
||||
});
|
||||
const show =
|
||||
localStorage.getItem("djdt.show") || djDebug.dataset.defaultShow;
|
||||
if (show === "true") {
|
||||
djdt.show_toolbar();
|
||||
} else {
|
||||
djdt.hide_toolbar();
|
||||
}
|
||||
},
|
||||
hide_panels() {
|
||||
const djDebug = document.getElementById("djDebug");
|
||||
$$.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");
|
||||
});
|
||||
},
|
||||
hide_toolbar() {
|
||||
djdt.hide_panels();
|
||||
|
||||
$$.hide(document.getElementById("djDebugToolbar"));
|
||||
|
||||
const handle = document.getElementById("djDebugToolbarHandle");
|
||||
$$.show(handle);
|
||||
// set handle position
|
||||
let handleTop = localStorage.getItem("djdt.top");
|
||||
if (handleTop) {
|
||||
handleTop = Math.min(
|
||||
handleTop,
|
||||
window.innerHeight - handle.offsetHeight
|
||||
);
|
||||
handle.style.top = handleTop + "px";
|
||||
}
|
||||
|
||||
document.removeEventListener("keydown", onKeyDown);
|
||||
|
||||
localStorage.setItem("djdt.show", "false");
|
||||
},
|
||||
hide_one_level() {
|
||||
const win = document.getElementById("djDebugWindow");
|
||||
if ($$.visible(win)) {
|
||||
$$.hide(win);
|
||||
} else {
|
||||
const toolbar = document.getElementById("djDebugToolbar");
|
||||
if (toolbar.querySelector("li.djdt-active")) {
|
||||
djdt.hide_panels();
|
||||
} else {
|
||||
djdt.hide_toolbar();
|
||||
}
|
||||
}
|
||||
},
|
||||
show_toolbar() {
|
||||
document.addEventListener("keydown", onKeyDown);
|
||||
$$.hide(document.getElementById("djDebugToolbarHandle"));
|
||||
$$.show(document.getElementById("djDebugToolbar"));
|
||||
localStorage.setItem("djdt.show", "true");
|
||||
},
|
||||
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.show_toolbar,
|
||||
hide_toolbar: djdt.hide_toolbar,
|
||||
init: djdt.init,
|
||||
close: djdt.hide_one_level,
|
||||
cookie: djdt.cookie,
|
||||
};
|
||||
|
||||
if (document.readyState !== "loading") {
|
||||
djdt.init();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", djdt.init);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
const timingOffset = performance.timing.navigationStart,
|
||||
timingEnd = performance.timing.loadEventEnd,
|
||||
totalTime = timingEnd - timingOffset;
|
||||
function getLeft(stat) {
|
||||
return ((performance.timing[stat] - timingOffset) / (totalTime)) * 100.0;
|
||||
}
|
||||
function getCSSWidth(stat, endStat) {
|
||||
let width = ((performance.timing[endStat] - performance.timing[stat]) / (totalTime)) * 100.0;
|
||||
// Calculate relative percent (same as sql panel logic)
|
||||
width = 100.0 * width / (100.0 - getLeft(stat));
|
||||
return (width < 1) ? "2px" : width + "%";
|
||||
}
|
||||
function addRow(stat, endStat) {
|
||||
const row = document.createElement('tr');
|
||||
if (endStat) {
|
||||
// Render a start through end bar
|
||||
row.innerHTML = '<td>' + stat.replace('Start', '') + '</td>' +
|
||||
'<td class="djdt-timeline"><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 class="djdt-timeline"><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));
|
||||
document.querySelector('#djDebugBrowserTimingTableBody').appendChild(row);
|
||||
}
|
||||
|
||||
// This is a reasonably complete and ordered set of timing periods (2 params) and events (1 param)
|
||||
addRow('domainLookupStart', 'domainLookupEnd');
|
||||
addRow('connectStart', 'connectEnd');
|
||||
addRow('requestStart', 'responseEnd'); // There is no requestEnd
|
||||
addRow('responseStart', 'responseEnd');
|
||||
addRow('domLoading', 'domComplete'); // Spans the events below
|
||||
addRow('domInteractive');
|
||||
addRow('domContentLoadedEventStart', 'domContentLoadedEventEnd');
|
||||
addRow('loadEventStart', 'loadEventEnd');
|
||||
document.querySelector('#djDebugBrowserTiming').classList.remove('djdt-hidden');
|
||||
@@ -0,0 +1,92 @@
|
||||
const $$ = {
|
||||
on(root, eventName, selector, fn) {
|
||||
root.addEventListener(eventName, function (event) {
|
||||
const target = event.target.closest(selector);
|
||||
if (root.contains(target)) {
|
||||
fn.call(target, 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();
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
export { $$, ajax, ajaxForm };
|
||||
Reference in New Issue
Block a user