Commit version 24.12.13800
This commit is contained in:
291
libs/Nette/Tracy/Bar/assets/bar.css
Normal file
291
libs/Nette/Tracy/Bar/assets/bar.css
Normal file
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* This file is part of the Tracy (https://tracy.nette.org)
|
||||
*/
|
||||
|
||||
/* common styles */
|
||||
#tracy-debug {
|
||||
display: none;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
body#tracy-debug { /* in popup window */
|
||||
display: block;
|
||||
}
|
||||
|
||||
#tracy-debug:not(body) {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
#tracy-debug a {
|
||||
color: #125EAE;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#tracy-debug a:hover,
|
||||
#tracy-debug a:focus {
|
||||
background-color: #125EAE;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#tracy-debug h2,
|
||||
#tracy-debug h3,
|
||||
#tracy-debug p {
|
||||
margin: .4em 0;
|
||||
}
|
||||
|
||||
#tracy-debug table {
|
||||
background: #FDF5CE;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#tracy-debug tr:nth-child(2n) td {
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
#tracy-debug td,
|
||||
#tracy-debug th {
|
||||
border: 1px solid #E6DFBF;
|
||||
padding: 2px 5px;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#tracy-debug th {
|
||||
background: #F4F3F1;
|
||||
color: #655E5E;
|
||||
font-size: 90%;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#tracy-debug pre,
|
||||
#tracy-debug code {
|
||||
font: 9pt/1.5 Consolas, monospace;
|
||||
}
|
||||
|
||||
#tracy-debug table .tracy-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#tracy-debug svg {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-dump {
|
||||
margin: 0;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
|
||||
/* bar */
|
||||
#tracy-debug-bar {
|
||||
font: normal normal 13px/1.55 Tahoma, sans-serif;
|
||||
color: #333;
|
||||
border: 1px solid #c9c9c9;
|
||||
background: #EDEAE0 url('data:image/png;base64,R0lGODlhAQAUALMAAOzq4e/t5e7s4/Dt5vDu5e3r4vDu5uvp4O/t5AAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAABABQAAAQM0EgySEAYi1LA+UcEADs=') top;
|
||||
background-size: 1em;
|
||||
position: fixed;
|
||||
|
||||
min-width: 50px;
|
||||
white-space: nowrap;
|
||||
|
||||
z-index: 30000;
|
||||
opacity: .9;
|
||||
transition: opacity 0.2s;
|
||||
will-change: opacity, top, left;
|
||||
|
||||
border-radius: 3px;
|
||||
box-shadow: 1px 1px 10px rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
#tracy-debug-bar:hover {
|
||||
opacity: 1;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
|
||||
#tracy-debug-bar .tracy-row {
|
||||
list-style: none none;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#tracy-debug-bar .tracy-row:not(:first-child) {
|
||||
background: #d5d2c6;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
#tracy-debug-bar .tracy-row[data-tracy-group="ajax"] {
|
||||
animation: tracy-row-flash .2s ease;
|
||||
}
|
||||
|
||||
@keyframes tracy-row-flash {
|
||||
0% {
|
||||
background: #c9c0a0;
|
||||
}
|
||||
}
|
||||
|
||||
#tracy-debug-bar .tracy-row:not(:first-child) li:first-child {
|
||||
width: 4.1em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#tracy-debug-bar img {
|
||||
vertical-align: bottom;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
#tracy-debug-bar svg {
|
||||
vertical-align: bottom;
|
||||
width: 1.23em;
|
||||
height: 1.55em;
|
||||
}
|
||||
|
||||
#tracy-debug-bar .tracy-label {
|
||||
margin-left: .2em;
|
||||
}
|
||||
|
||||
#tracy-debug-bar li > a,
|
||||
#tracy-debug-bar li > span {
|
||||
color: #000;
|
||||
display: block;
|
||||
padding: 0 .4em;
|
||||
}
|
||||
|
||||
#tracy-debug-bar li > a:hover {
|
||||
color: black;
|
||||
background: #c3c1b8;
|
||||
}
|
||||
|
||||
#tracy-debug-bar li:first-child {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
#tracy-debug-logo svg {
|
||||
width: 3.4em;
|
||||
margin: 0 .2em 0 .5em;
|
||||
}
|
||||
|
||||
|
||||
/* panels */
|
||||
#tracy-debug .tracy-panel {
|
||||
display: none;
|
||||
font: normal normal 12px/1.5 sans-serif;
|
||||
background: white;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
body#tracy-debug .tracy-panel { /* in popup window */
|
||||
display: block;
|
||||
}
|
||||
|
||||
#tracy-debug h1 {
|
||||
font: normal normal 23px/1.4 Tahoma, sans-serif;
|
||||
color: #575753;
|
||||
margin: -5px -5px 5px;
|
||||
padding: 0 5px 0 5px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-inner {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-panel .tracy-icons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-panel-ajax h1::after,
|
||||
#tracy-debug .tracy-panel-redirect h1::after {
|
||||
content: 'ajax';
|
||||
float: right;
|
||||
font-size: 65%;
|
||||
margin: 0 .3em;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-panel-redirect h1::after {
|
||||
content: 'redirect';
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-peek,
|
||||
#tracy-debug .tracy-mode-float {
|
||||
position: fixed;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
min-width: 200px;
|
||||
min-height: 80px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 1px 1px 20px rgba(102, 102, 102, 0.36);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-peek,
|
||||
#tracy-debug .tracy-mode-float:not(.tracy-panel-resized) {
|
||||
max-width: 700px;
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
@media (max-height: 555px) {
|
||||
#tracy-debug .tracy-mode-peek,
|
||||
#tracy-debug .tracy-mode-float:not(.tracy-panel-resized) {
|
||||
max-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-peek h1 {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-float {
|
||||
display: flex;
|
||||
opacity: .95;
|
||||
transition: opacity 0.2s;
|
||||
will-change: opacity, top, left;
|
||||
overflow: auto;
|
||||
resize: both;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-focused {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-float h1 {
|
||||
cursor: move;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-float .tracy-icons {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 5px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-mode-window {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-icons a {
|
||||
color: #575753;
|
||||
}
|
||||
|
||||
#tracy-debug .tracy-icons a:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
#tracy-debug .tracy-inner-container {
|
||||
min-width: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
@media print {
|
||||
#tracy-debug * {
|
||||
display: none;
|
||||
}
|
||||
}
|
685
libs/Nette/Tracy/Bar/assets/bar.js
Normal file
685
libs/Nette/Tracy/Bar/assets/bar.js
Normal file
@ -0,0 +1,685 @@
|
||||
/**
|
||||
* This file is part of the Tracy (https://tracy.nette.org)
|
||||
*/
|
||||
|
||||
let nonce = document.currentScript.getAttribute('nonce') || document.currentScript.nonce,
|
||||
requestId = document.currentScript.dataset.id,
|
||||
ajaxCounter = 1,
|
||||
baseUrl = location.href.split('#')[0];
|
||||
|
||||
baseUrl += (baseUrl.indexOf('?') < 0 ? '?' : '&');
|
||||
|
||||
let defaults = {
|
||||
PanelZIndex: 20000,
|
||||
MaxAjaxRows: 3,
|
||||
AutoRefresh: true,
|
||||
};
|
||||
|
||||
function getOption(key)
|
||||
{
|
||||
let global = window['Tracy' + key];
|
||||
return global === undefined ? defaults[key] : global;
|
||||
}
|
||||
|
||||
class Panel
|
||||
{
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
this.elem = document.getElementById(this.id);
|
||||
this.elem.Tracy = this.elem.Tracy || {};
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
let elem = this.elem;
|
||||
|
||||
this.init = function() {};
|
||||
elem.innerHTML = elem.dataset.tracyContent;
|
||||
Tracy.Dumper.init(Debug.layer);
|
||||
evalScripts(elem);
|
||||
|
||||
draggable(elem, {
|
||||
handles: elem.querySelectorAll('h1'),
|
||||
start: () => {
|
||||
if (!this.is(Panel.FLOAT)) {
|
||||
this.toFloat();
|
||||
}
|
||||
this.focus();
|
||||
this.peekPosition = false;
|
||||
}
|
||||
});
|
||||
|
||||
elem.addEventListener('mousedown', () => {
|
||||
this.focus();
|
||||
});
|
||||
|
||||
elem.addEventListener('mouseenter', () => {
|
||||
clearTimeout(elem.Tracy.displayTimeout);
|
||||
});
|
||||
|
||||
elem.addEventListener('mouseleave', () => {
|
||||
this.blur();
|
||||
});
|
||||
|
||||
elem.addEventListener('mousemove', (e) => {
|
||||
if (e.buttons && !this.is(Panel.RESIZED) && (elem.style.width || elem.style.height)) {
|
||||
elem.classList.add(Panel.RESIZED);
|
||||
}
|
||||
});
|
||||
|
||||
elem.addEventListener('tracy-toggle', () => {
|
||||
this.reposition();
|
||||
});
|
||||
|
||||
elem.querySelectorAll('.tracy-icons a').forEach((link) => {
|
||||
link.addEventListener('click', (e) => {
|
||||
if (link.dataset.tracyAction === 'close') {
|
||||
this.toPeek();
|
||||
} else if (link.dataset.tracyAction === 'window') {
|
||||
this.toWindow();
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
});
|
||||
|
||||
if (this.is('tracy-panel-persist')) {
|
||||
Tracy.Toggle.persist(elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
is(mode) {
|
||||
return this.elem.classList.contains(mode);
|
||||
}
|
||||
|
||||
|
||||
focus() {
|
||||
let elem = this.elem;
|
||||
if (this.is(Panel.WINDOW)) {
|
||||
elem.Tracy.window.focus();
|
||||
|
||||
} else if (!this.is(Panel.FOCUSED)) {
|
||||
for (let id in Debug.panels) {
|
||||
Debug.panels[id].elem.classList.remove(Panel.FOCUSED);
|
||||
}
|
||||
elem.classList.add(Panel.FOCUSED);
|
||||
elem.style.zIndex = getOption('PanelZIndex') + Panel.zIndexCounter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
blur() {
|
||||
let elem = this.elem;
|
||||
if (this.is(Panel.PEEK)) {
|
||||
clearTimeout(elem.Tracy.displayTimeout);
|
||||
elem.Tracy.displayTimeout = setTimeout(() => {
|
||||
elem.classList.remove(Panel.FOCUSED);
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
toFloat() {
|
||||
this.elem.classList.remove(Panel.WINDOW);
|
||||
this.elem.classList.remove(Panel.PEEK);
|
||||
this.elem.classList.add(Panel.FLOAT);
|
||||
this.elem.classList.remove(Panel.RESIZED);
|
||||
this.reposition();
|
||||
}
|
||||
|
||||
|
||||
toPeek() {
|
||||
this.elem.classList.remove(Panel.WINDOW);
|
||||
this.elem.classList.remove(Panel.FLOAT);
|
||||
this.elem.classList.remove(Panel.FOCUSED);
|
||||
this.elem.classList.add(Panel.PEEK);
|
||||
this.elem.style.width = '';
|
||||
this.elem.style.height = '';
|
||||
this.elem.classList.remove(Panel.RESIZED);
|
||||
}
|
||||
|
||||
|
||||
toWindow() {
|
||||
let offset = getOffset(this.elem);
|
||||
offset.left += typeof window.screenLeft === 'number' ? window.screenLeft : (window.screenX + 10);
|
||||
offset.top += typeof window.screenTop === 'number' ? window.screenTop : (window.screenY + 50);
|
||||
|
||||
let win = window.open('', this.id.replace(/-/g, '_'), 'left=' + offset.left + ',top=' + offset.top
|
||||
+ ',width=' + this.elem.offsetWidth + ',height=' + this.elem.offsetHeight + ',resizable=yes,scrollbars=yes');
|
||||
if (!win) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let doc = win.document;
|
||||
doc.write('<!DOCTYPE html><meta charset="utf-8">'
|
||||
+ '<script src="' + (baseUrl.replace(/&/g, '&').replace(/"/g, '"')) + '_tracy_bar=js&XDEBUG_SESSION_STOP=1" onload="Tracy.Dumper.init()" async></script>'
|
||||
+ '<body id="tracy-debug">'
|
||||
);
|
||||
|
||||
let meta = this.elem.parentElement.lastElementChild;
|
||||
doc.body.innerHTML = '<tracy-div itemscope>'
|
||||
+ '<div class="tracy-panel tracy-mode-window" id="' + this.elem.id + '">' + this.elem.dataset.tracyContent + '</div>'
|
||||
+ meta.outerHTML
|
||||
+ '</tracy-div>';
|
||||
evalScripts(doc.body);
|
||||
if (this.elem.querySelector('h1')) {
|
||||
doc.title = this.elem.querySelector('h1').textContent;
|
||||
}
|
||||
|
||||
win.addEventListener('beforeunload', () => {
|
||||
this.toPeek();
|
||||
win.close(); // forces closing, can be invoked by F5
|
||||
});
|
||||
|
||||
doc.addEventListener('keyup', (e) => {
|
||||
if (e.keyCode === 27 && !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey) {
|
||||
win.close();
|
||||
}
|
||||
});
|
||||
|
||||
this.elem.classList.remove(Panel.FLOAT);
|
||||
this.elem.classList.remove(Panel.PEEK);
|
||||
this.elem.classList.remove(Panel.FOCUSED);
|
||||
this.elem.classList.remove(Panel.RESIZED);
|
||||
this.elem.classList.add(Panel.WINDOW);
|
||||
this.elem.Tracy.window = win;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
reposition(deltaX, deltaY) {
|
||||
let pos = getPosition(this.elem);
|
||||
if (pos.width) { // is visible?
|
||||
setPosition(this.elem, {left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0)});
|
||||
if (this.is(Panel.RESIZED)) {
|
||||
let size = getWindowSize();
|
||||
this.elem.style.width = Math.min(size.width, pos.width) + 'px';
|
||||
this.elem.style.height = Math.min(size.height, pos.height) + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
savePosition() {
|
||||
let key = this.id.split(':')[0]; // remove :requestId part
|
||||
let pos = getPosition(this.elem);
|
||||
if (this.is(Panel.WINDOW)) {
|
||||
localStorage.setItem(key, JSON.stringify({window: true}));
|
||||
} else if (pos.width) { // is visible?
|
||||
localStorage.setItem(key, JSON.stringify({right: pos.right, bottom: pos.bottom, width: pos.width, height: pos.height, zIndex: this.elem.style.zIndex - getOption('PanelZIndex'), resized: this.is(Panel.RESIZED)}));
|
||||
} else {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restorePosition() {
|
||||
let key = this.id.split(':')[0];
|
||||
let pos = JSON.parse(localStorage.getItem(key));
|
||||
if (!pos) {
|
||||
this.elem.classList.add(Panel.PEEK);
|
||||
} else if (pos.window) {
|
||||
this.init();
|
||||
this.toWindow() || this.toFloat();
|
||||
} else if (this.elem.dataset.tracyContent) {
|
||||
this.init();
|
||||
this.toFloat();
|
||||
if (pos.resized) {
|
||||
this.elem.classList.add(Panel.RESIZED);
|
||||
this.elem.style.width = pos.width + 'px';
|
||||
this.elem.style.height = pos.height + 'px';
|
||||
}
|
||||
setPosition(this.elem, pos);
|
||||
this.elem.style.zIndex = getOption('PanelZIndex') + (pos.zIndex || 1);
|
||||
Panel.zIndexCounter = Math.max(Panel.zIndexCounter, (pos.zIndex || 1)) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Panel.PEEK = 'tracy-mode-peek';
|
||||
Panel.FLOAT = 'tracy-mode-float';
|
||||
Panel.WINDOW = 'tracy-mode-window';
|
||||
Panel.FOCUSED = 'tracy-focused';
|
||||
Panel.RESIZED = 'tracy-panel-resized';
|
||||
Panel.zIndexCounter = 1;
|
||||
|
||||
|
||||
class Bar
|
||||
{
|
||||
init() {
|
||||
this.id = 'tracy-debug-bar';
|
||||
this.elem = document.getElementById(this.id);
|
||||
|
||||
draggable(this.elem, {
|
||||
handles: this.elem.querySelectorAll('li:first-child'),
|
||||
draggedClass: 'tracy-dragged',
|
||||
stop: () => {
|
||||
this.savePosition();
|
||||
}
|
||||
});
|
||||
|
||||
this.elem.addEventListener('mousedown', (e) => {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
this.initTabs(this.elem);
|
||||
this.restorePosition();
|
||||
|
||||
(new MutationObserver(() => {
|
||||
this.restorePosition();
|
||||
})).observe(this.elem, {childList: true, characterData: true, subtree: true});
|
||||
}
|
||||
|
||||
|
||||
initTabs(elem) {
|
||||
elem.querySelectorAll('a').forEach((link) => {
|
||||
link.addEventListener('click', (e) => {
|
||||
if (link.dataset.tracyAction === 'close') {
|
||||
this.close();
|
||||
|
||||
} else if (link.rel) {
|
||||
let panel = Debug.panels[link.rel];
|
||||
panel.init();
|
||||
|
||||
if (e.shiftKey) {
|
||||
panel.toFloat();
|
||||
panel.toWindow();
|
||||
|
||||
} else if (panel.is(Panel.FLOAT)) {
|
||||
panel.toPeek();
|
||||
|
||||
} else {
|
||||
panel.toFloat();
|
||||
if (panel.peekPosition) {
|
||||
panel.reposition(-Math.round(Math.random() * 100) - 20, (Math.round(Math.random() * 100) + 20) * (this.isAtTop() ? 1 : -1));
|
||||
panel.peekPosition = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
});
|
||||
|
||||
link.addEventListener('mouseenter', (e) => {
|
||||
if (e.buttons || !link.rel || elem.classList.contains('tracy-dragged')) {
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(this.displayTimeout);
|
||||
this.displayTimeout = setTimeout(() => {
|
||||
let panel = Debug.panels[link.rel];
|
||||
panel.focus();
|
||||
|
||||
if (panel.is(Panel.PEEK)) {
|
||||
panel.init();
|
||||
|
||||
let pos = getPosition(panel.elem);
|
||||
setPosition(panel.elem, {
|
||||
left: getOffset(link).left + getPosition(link).width + 4 - pos.width,
|
||||
top: this.isAtTop()
|
||||
? getOffset(this.elem).top + getPosition(this.elem).height + 4
|
||||
: getOffset(this.elem).top - pos.height - 4
|
||||
});
|
||||
panel.peekPosition = true;
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
|
||||
link.addEventListener('mouseleave', () => {
|
||||
clearTimeout(this.displayTimeout);
|
||||
|
||||
if (link.rel && !elem.classList.contains('tracy-dragged')) {
|
||||
Debug.panels[link.rel].blur();
|
||||
}
|
||||
});
|
||||
});
|
||||
this.autoHideLabels();
|
||||
}
|
||||
|
||||
|
||||
autoHideLabels() {
|
||||
let width = getWindowSize().width;
|
||||
this.elem.querySelectorAll('.tracy-row').forEach((row) => {
|
||||
let i, labels = row.querySelectorAll('.tracy-label');
|
||||
for (i = 0; i < labels.length && row.clientWidth < width; i++) {
|
||||
labels.item(i).hidden = false;
|
||||
}
|
||||
for (i = labels.length - 1; i >= 0 && row.clientWidth >= width; i--) {
|
||||
labels.item(i).hidden = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
close() {
|
||||
document.getElementById('tracy-debug').style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
reposition(deltaX, deltaY) {
|
||||
let pos = getPosition(this.elem);
|
||||
if (pos.width) { // is visible?
|
||||
setPosition(this.elem, {left: pos.left + (deltaX || 0), top: pos.top + (deltaY || 0)});
|
||||
this.savePosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
savePosition() {
|
||||
let pos = getPosition(this.elem);
|
||||
if (pos.width) { // is visible?
|
||||
localStorage.setItem(this.id, JSON.stringify(this.isAtTop() ? {right: pos.right, top: pos.top} : {right: pos.right, bottom: pos.bottom}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restorePosition() {
|
||||
let pos = JSON.parse(localStorage.getItem(this.id));
|
||||
setPosition(this.elem, pos || {right: 0, bottom: 0});
|
||||
this.savePosition();
|
||||
}
|
||||
|
||||
|
||||
isAtTop() {
|
||||
let pos = getPosition(this.elem);
|
||||
return pos.top < 100 && pos.bottom > pos.top;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Debug
|
||||
{
|
||||
static init(content) {
|
||||
Debug.bar = new Bar;
|
||||
Debug.panels = {};
|
||||
Debug.layer = document.createElement('tracy-div');
|
||||
Debug.layer.setAttribute('id', 'tracy-debug');
|
||||
Debug.layer.innerHTML = content;
|
||||
(document.body || document.documentElement).appendChild(Debug.layer);
|
||||
evalScripts(Debug.layer);
|
||||
Debug.layer.style.display = 'block';
|
||||
Debug.bar.init();
|
||||
|
||||
Debug.layer.querySelectorAll('.tracy-panel').forEach((panel) => {
|
||||
Debug.panels[panel.id] = new Panel(panel.id);
|
||||
Debug.panels[panel.id].restorePosition();
|
||||
});
|
||||
|
||||
Debug.captureWindow();
|
||||
Debug.captureAjax();
|
||||
|
||||
Tracy.TableSort.init();
|
||||
}
|
||||
|
||||
|
||||
static loadAjax(content) {
|
||||
let rows = Debug.bar.elem.querySelectorAll('.tracy-row[data-tracy-group=ajax]');
|
||||
rows = Array.from(rows).reverse();
|
||||
let max = getOption('MaxAjaxRows');
|
||||
rows.forEach((row) => {
|
||||
if (--max > 0) {
|
||||
return;
|
||||
}
|
||||
row.querySelectorAll('a[rel]').forEach((tab) => {
|
||||
let panel = Debug.panels[tab.rel];
|
||||
if (panel.is(Panel.PEEK)) {
|
||||
delete Debug.panels[tab.rel];
|
||||
panel.elem.remove();
|
||||
}
|
||||
});
|
||||
row.remove();
|
||||
});
|
||||
|
||||
if (rows[0]) { // update content in first-row panels
|
||||
rows[0].querySelectorAll('a[rel]').forEach((tab) => {
|
||||
Debug.panels[tab.rel].savePosition();
|
||||
Debug.panels[tab.rel].toPeek();
|
||||
});
|
||||
}
|
||||
|
||||
Debug.layer.insertAdjacentHTML('beforeend', content.panels);
|
||||
evalScripts(Debug.layer);
|
||||
Debug.bar.elem.insertAdjacentHTML('beforeend', content.bar);
|
||||
let ajaxBar = Debug.bar.elem.querySelector('.tracy-row:last-child');
|
||||
|
||||
Debug.layer.querySelectorAll('.tracy-panel').forEach((panel) => {
|
||||
if (!Debug.panels[panel.id]) {
|
||||
Debug.panels[panel.id] = new Panel(panel.id);
|
||||
Debug.panels[panel.id].restorePosition();
|
||||
}
|
||||
});
|
||||
|
||||
Debug.bar.initTabs(ajaxBar);
|
||||
}
|
||||
|
||||
|
||||
static captureWindow() {
|
||||
let size = getWindowSize();
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
let newSize = getWindowSize();
|
||||
|
||||
Debug.bar.reposition(newSize.width - size.width, newSize.height - size.height);
|
||||
Debug.bar.autoHideLabels();
|
||||
|
||||
for (let id in Debug.panels) {
|
||||
Debug.panels[id].reposition(newSize.width - size.width, newSize.height - size.height);
|
||||
}
|
||||
|
||||
size = newSize;
|
||||
});
|
||||
|
||||
window.addEventListener('unload', () => {
|
||||
for (let id in Debug.panels) {
|
||||
Debug.panels[id].savePosition();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static captureAjax() {
|
||||
if (!requestId) {
|
||||
return;
|
||||
}
|
||||
let oldOpen = XMLHttpRequest.prototype.open;
|
||||
|
||||
XMLHttpRequest.prototype.open = function() {
|
||||
oldOpen.apply(this, arguments);
|
||||
|
||||
if (getOption('AutoRefresh') && new URL(arguments[1], location.origin).host === location.host) {
|
||||
let reqId = Tracy.getAjaxHeader();
|
||||
this.setRequestHeader('X-Tracy-Ajax', reqId);
|
||||
this.addEventListener('load', function() {
|
||||
if (this.getAllResponseHeaders().match(/^X-Tracy-Ajax: 1/mi)) {
|
||||
Debug.loadScript(baseUrl + '_tracy_bar=content-ajax.' + reqId + '&XDEBUG_SESSION_STOP=1&v=' + Math.random());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let oldFetch = window.fetch;
|
||||
window.fetch = function(request, options) {
|
||||
request = request instanceof Request ? request : new Request(request, options || {});
|
||||
let reqId = request.headers.get('X-Tracy-Ajax');
|
||||
|
||||
if (getOption('AutoRefresh') && !reqId && new URL(request.url, location.origin).host === location.host) {
|
||||
reqId = Tracy.getAjaxHeader();
|
||||
request.headers.set('X-Tracy-Ajax', reqId);
|
||||
}
|
||||
|
||||
return oldFetch(request).then((response) => {
|
||||
if (response instanceof Response && response.headers.has('X-Tracy-Ajax') && response.headers.get('X-Tracy-Ajax')[0] === '1') {
|
||||
Debug.loadScript(baseUrl + '_tracy_bar=content-ajax.' + reqId + '&XDEBUG_SESSION_STOP=1&v=' + Math.random());
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
static loadScript(url) {
|
||||
if (Debug.scriptElem) {
|
||||
Debug.scriptElem.remove();
|
||||
}
|
||||
Debug.scriptElem = document.createElement('script');
|
||||
Debug.scriptElem.src = url;
|
||||
Debug.scriptElem.setAttribute('nonce', nonce);
|
||||
(document.body || document.documentElement).appendChild(Debug.scriptElem);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function evalScripts(elem) {
|
||||
elem.querySelectorAll('script').forEach((script) => {
|
||||
if ((!script.hasAttribute('type') || script.type === 'text/javascript' || script.type === 'application/javascript') && !script.tracyEvaluated) {
|
||||
let document = script.ownerDocument;
|
||||
let dolly = document.createElement('script');
|
||||
dolly.textContent = script.textContent;
|
||||
dolly.setAttribute('nonce', nonce);
|
||||
(document.body || document.documentElement).appendChild(dolly);
|
||||
script.tracyEvaluated = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let dragging;
|
||||
|
||||
function draggable(elem, options) {
|
||||
let dE = document.documentElement, started, deltaX, deltaY, clientX, clientY;
|
||||
options = options || {};
|
||||
|
||||
let redraw = function () {
|
||||
if (dragging) {
|
||||
setPosition(elem, {left: clientX + deltaX, top: clientY + deltaY});
|
||||
requestAnimationFrame(redraw);
|
||||
}
|
||||
};
|
||||
|
||||
let onMove = function(e) {
|
||||
if (e.buttons === 0) {
|
||||
return onEnd(e);
|
||||
}
|
||||
if (!started) {
|
||||
if (options.draggedClass) {
|
||||
elem.classList.add(options.draggedClass);
|
||||
}
|
||||
if (options.start) {
|
||||
options.start(e, elem);
|
||||
}
|
||||
started = true;
|
||||
}
|
||||
|
||||
clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
return false;
|
||||
};
|
||||
|
||||
let onEnd = function(e) {
|
||||
if (started) {
|
||||
if (options.draggedClass) {
|
||||
elem.classList.remove(options.draggedClass);
|
||||
}
|
||||
if (options.stop) {
|
||||
options.stop(e, elem);
|
||||
}
|
||||
}
|
||||
dragging = null;
|
||||
dE.removeEventListener('mousemove', onMove);
|
||||
dE.removeEventListener('mouseup', onEnd);
|
||||
dE.removeEventListener('touchmove', onMove);
|
||||
dE.removeEventListener('touchend', onEnd);
|
||||
return false;
|
||||
};
|
||||
|
||||
let onStart = function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (dragging) { // missed mouseup out of window?
|
||||
return onEnd(e);
|
||||
}
|
||||
|
||||
let pos = getPosition(elem);
|
||||
clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
||||
clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
||||
deltaX = pos.left - clientX;
|
||||
deltaY = pos.top - clientY;
|
||||
dragging = true;
|
||||
started = false;
|
||||
dE.addEventListener('mousemove', onMove);
|
||||
dE.addEventListener('mouseup', onEnd);
|
||||
dE.addEventListener('touchmove', onMove);
|
||||
dE.addEventListener('touchend', onEnd);
|
||||
requestAnimationFrame(redraw);
|
||||
if (options.start) {
|
||||
options.start(e, elem);
|
||||
}
|
||||
};
|
||||
|
||||
options.handles.forEach((handle) => {
|
||||
handle.addEventListener('mousedown', onStart);
|
||||
handle.addEventListener('touchstart', onStart);
|
||||
|
||||
handle.addEventListener('click', (e) => {
|
||||
if (started) {
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// returns total offset for element
|
||||
function getOffset(elem) {
|
||||
let res = {left: elem.offsetLeft, top: elem.offsetTop};
|
||||
while (elem = elem.offsetParent) { // eslint-disable-line no-cond-assign
|
||||
res.left += elem.offsetLeft; res.top += elem.offsetTop;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
function getWindowSize() {
|
||||
return {
|
||||
width: document.documentElement.clientWidth,
|
||||
height: document.compatMode === 'BackCompat' ? window.innerHeight : document.documentElement.clientHeight
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// move to new position
|
||||
function setPosition(elem, coords) {
|
||||
let win = getWindowSize();
|
||||
if (typeof coords.right !== 'undefined') {
|
||||
coords.left = win.width - elem.offsetWidth - coords.right;
|
||||
}
|
||||
if (typeof coords.bottom !== 'undefined') {
|
||||
coords.top = win.height - elem.offsetHeight - coords.bottom;
|
||||
}
|
||||
elem.style.left = Math.max(0, Math.min(coords.left, win.width - elem.offsetWidth)) + 'px';
|
||||
elem.style.top = Math.max(0, Math.min(coords.top, win.height - elem.offsetHeight)) + 'px';
|
||||
}
|
||||
|
||||
|
||||
// returns current position
|
||||
function getPosition(elem) {
|
||||
let win = getWindowSize();
|
||||
return {
|
||||
left: elem.offsetLeft,
|
||||
top: elem.offsetTop,
|
||||
right: win.width - elem.offsetWidth - elem.offsetLeft,
|
||||
bottom: win.height - elem.offsetHeight - elem.offsetTop,
|
||||
width: elem.offsetWidth,
|
||||
height: elem.offsetHeight
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
let Tracy = window.Tracy = window.Tracy || {};
|
||||
Tracy.DebugPanel = Panel;
|
||||
Tracy.DebugBar = Bar;
|
||||
Tracy.Debug = Debug;
|
||||
Tracy.getAjaxHeader = () => requestId + '_' + ajaxCounter++;
|
31
libs/Nette/Tracy/Bar/assets/bar.phtml
Normal file
31
libs/Nette/Tracy/Bar/assets/bar.phtml
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tracy;
|
||||
|
||||
/**
|
||||
* @var string $type
|
||||
* @var \stdClass[] $panels
|
||||
*/
|
||||
?>
|
||||
|
||||
<ul class="tracy-row" data-tracy-group="<?= Helpers::escapeHtml($type) ?>">
|
||||
<?php if ($type === 'main'): ?>
|
||||
<li id="tracy-debug-logo" title="Tracy Debugger <?= Debugger::VERSION, " \nhttps://tracy.nette.org" ?>">
|
||||
<svg viewBox="0 -10 1561 333"><path fill="#585755" d="m176 327h-57v-269h-119v-57h291v57h-115v269zm208-191h114c50 0 47-78 0-78h-114v78zm106-135c17 0 33 2 46 7 75 30 75 144 1 175-13 6-29 8-47 8h-27l132 74v68l-211-128v122h-57v-326h163zm300 57c-5 0-9 3-11 9l-56 156h135l-55-155c-2-7-6-10-13-10zm-86 222l-17 47h-61l102-285c20-56 107-56 126 0l102 285h-61l-17-47h-174zm410 47c-98 0-148-55-148-163v-2c0-107 50-161 149-161h118v57h-133c-26 0-45 8-58 25-12 17-19 44-19 81 0 71 26 106 77 106h133v57h-119zm270-145l-121-181h68l81 130 81-130h68l-121 178v148h-56v-145z"/></svg>
|
||||
</li>
|
||||
<?php endif; if ($type === 'redirect'): ?>
|
||||
<li><span title="Previous request before redirect">redirect</span></li>
|
||||
<?php endif; if ($type === 'ajax'): ?>
|
||||
<li>AJAX</li>
|
||||
<?php endif ?>
|
||||
|
||||
<?php foreach ($panels as $panel): if ($panel->tab) { ?>
|
||||
<li><?php if ($panel->panel): ?><a href="#" rel="tracy-debug-panel-<?= $panel->id ?>"><?= trim($panel->tab) ?></a><?php else: echo '<span>', trim($panel->tab), '</span>'; endif ?></li>
|
||||
<?php } endforeach ?>
|
||||
|
||||
<?php if ($type === 'main'): ?>
|
||||
<li><a href="#" data-tracy-action="close" title="close debug bar">×</a></li>
|
||||
<?php endif ?>
|
||||
</ul>
|
30
libs/Nette/Tracy/Bar/assets/loader.phtml
Normal file
30
libs/Nette/Tracy/Bar/assets/loader.phtml
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tracy;
|
||||
|
||||
/**
|
||||
* @var ?string $nonce
|
||||
* @var bool $async
|
||||
* @var string $requestId
|
||||
*/
|
||||
|
||||
$baseUrl = $_SERVER['REQUEST_URI'] ?? '';
|
||||
$baseUrl .= strpos($baseUrl, '?') === false ? '?' : '&';
|
||||
$nonceAttr = $nonce ? ' nonce="' . Helpers::escapeHtml($nonce) . '"' : '';
|
||||
$asyncAttr = $async ? ' async' : '';
|
||||
?>
|
||||
<?php if (empty($content)): ?>
|
||||
<script src="<?= Helpers::escapeHtml($baseUrl) ?>_tracy_bar=<?= urlencode("content.$requestId") ?>&XDEBUG_SESSION_STOP=1" data-id="<?= Helpers::escapeHtml($requestId) ?>"<?= $asyncAttr, $nonceAttr ?>></script>
|
||||
<?php else: ?>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Tracy Debug Bar -->
|
||||
<script src="<?= Helpers::escapeHtml($baseUrl) ?>_tracy_bar=js&v=<?= urlencode(Debugger::VERSION) ?>&XDEBUG_SESSION_STOP=1" data-id="<?= Helpers::escapeHtml($requestId) ?>"<?= $nonceAttr ?>></script>
|
||||
<script<?= $nonceAttr ?>>
|
||||
Tracy.Debug.init(<?= str_replace(['<!--', '</s'], ['<\!--', '<\/s'], json_encode($content, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE)) ?>);
|
||||
</script>
|
||||
<?php endif ?>
|
30
libs/Nette/Tracy/Bar/assets/panels.phtml
Normal file
30
libs/Nette/Tracy/Bar/assets/panels.phtml
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Tracy;
|
||||
|
||||
use Tracy\Helpers;
|
||||
|
||||
/**
|
||||
* @var string $type
|
||||
* @var \stdClass[] $panels
|
||||
*/
|
||||
|
||||
$icons = '
|
||||
<div class="tracy-icons">
|
||||
<a href="#" data-tracy-action="window" title="open in window">¤</a>
|
||||
<a href="#" data-tracy-action="close" title="close window">×</a>
|
||||
</div>
|
||||
';
|
||||
|
||||
echo '<div itemscope>';
|
||||
|
||||
foreach ($panels as $panel) {
|
||||
$content = $panel->panel ? ($panel->panel . "\n" . $icons) : '';
|
||||
$class = 'tracy-panel ' . ($type === 'ajax' ? '' : 'tracy-panel-persist') . ' tracy-panel-' . $type; ?>
|
||||
<div class="<?= $class ?>" id="tracy-debug-panel-<?= $panel->id ?>" data-tracy-content='<?= str_replace(['&', "'"], ['&', '''], $content) ?>'></div><?php
|
||||
}
|
||||
|
||||
echo '<meta itemprop=tracy-snapshot content=', Dumper::formatSnapshotAttribute(Dumper::$liveSnapshot), '>';
|
||||
echo '</div>';
|
Reference in New Issue
Block a user